[TOC] Je vous en prie.
Ce tutoriel contient des connaissances de base de l'écriture de stratégie, y compris l'introduction de l'API, backtest, graphiques et plus encore. Après avoir appris ce tutoriel de base, les utilisateurs seront en mesure d'utiliser l'API de base de manière compétente et d'écrire une stratégie de bot stable. Avant d'apprendre le tutoriel, vous devez apprendre à utiliserCommencez avec la plateforme FMZ Quant.
Le tutoriel de l'ancienne version:FMZ Quant (FMZ.COM) Manuel de rédaction de stratégie 2.0 (Tutoriel); il y a beaucoup d'index de postes dans le tutoriel, qui sont recommandés à lire.
Le programme trading consiste à utiliser des programmes pour se connecter à des plateformes via une API afin d'obtenir des achats et des ventes automatiques ou d'autres fonctions selon l'intention de conception.
À l'heure actuelle, il existe deux protocoles d'interface principaux pour les plateformes de crypto-monnaie: REST et Websocket. Chaque fois que le protocole REST obtient des données, il doit être consulté une fois. Prenons l'API de la plate-forme simulée
{"data:{"buy":"11351.73","high":"11595.77","last":"11351.85","low":"11118.45","open":"11358.74","quoteVol":"95995607137.00903936","sell":"11356.02","time":1565593489318,"vol":"3552.5153"}}
De cette façon, vous pouvez voir que le trading suivant les dernières cotations du marché de la paire de trading BTC_USDT, changera à chaque fois qu'il est actualisé;
La plateforme de trading FMZ Quant encapsule l'interface REST de chaque plateforme, et utilise une façon unifiée d'appeler et un format de données unifié, rendant la rédaction de stratégie plus simple et plus générale.
La plupart des parties du document de l'API de la plateforme FMZ utilisent JavaScript comme exemple, mais en raison de l'encapsulation, il n'y a presque aucune différence entre les différents langages, et vous n'avez qu'à faire attention aux problèmes de syntaxe.
Comme Python a des versions différentes, il peut être spécifié au début du programme, comme:#!Python2
et#!Python3
. Notez que JavaScript a récemment mis à jour sa syntaxe ES6, et ceux qui sont intéressés peuvent en apprendre davantage. Les codes Python et Javascript avec les mêmes fonctions sont montrés ci-dessous. On peut voir qu'il n'y a que des différences de syntaxe, donc le document API ne donne que des exemples de Javascript, et ce tutoriel tiendra également compte des cas d'utilisation spéciaux de Python.
#python code
def main():
while True:
Log(exchange.GetAccount().Balance)
Sleep(2000)
#the corresponding Js code
function main(){
while(true){
Log(exchange.GetAccount().Balance)
Sleep(2000)
}
}
La plateforme FMZ Quant fournit les
Le programme de stratégie est le même qu'un programme normal, qui est exécuté dans des ordres de code. La partie spéciale est qu'il doit y avoir une fonction
D'autres fonctions comportant des actions spéciales sont présentées comme suit:
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
while(true){
onTick()
Sleep(6000)
}
}
Dans l'exemple précédent, s'il y a une erreur dans l'accès au réseau, la stratégie peut s'arrêter directement. Si vous voulez une stratégie similaire au redémarrage automatique et qui ne s'arrêtera pas, vous pouvez utiliser la boucle principale tolérante aux erreurs dans la stratégie du bot (n'utilisez pas
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//write the strategy logic here, and it will be called ever 6 seconds
}
function main(){
try{
while(true){
onTick()
Sleep(6000)
}
}catch(err){
Log(err)
}
}
Lorsque vous appelez une API liée à une plateforme, vous devez spécifier la plateforme et la paire de trading.exchange
pour représenter cet objet.exchange.GetTicker()
La valeur de l'indice de change obtenu est le ticker de marché de cette paire de change.
La plate-forme FMZ Quant prend en charge l'ajout simultané de plusieurs objets exchanges
les représentent, à savoirexchanges[0]
etexchanges[1]
...et ainsi de suite, selon l'ordre d'addition lorsque le bot est créé.BTC_USDT
, l'ancienne
Il est évident que si nous opérons beaucoup de paires de trading, cette méthode sera très gênante.exchange.SetCurrency("BTC_USDT")
; alors, la paire de négociation liée àexchange
devientBTC_USDT
, qui restera valable jusqu'à la prochaine demande de changement de paire de négociation.Notez que le backtest prend en charge la commutation des paires de trading récemmentVous trouverez ci-dessous un exemple concret:
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT"]
var buyValue = 1000
function main(){
for(var i=0;i<symbols.length;i++){
exchange.SetCurrency(symbols[i])
var ticker = exchange.GetTicker()
var amount = _N(buyValue/ticker.Sell, 3)
exchange.Buy(ticker.Sell, amount)
Sleep(1000)
}
}
Comme mentionné dans l'exemple précédent, l'interface de marché est généralement une interface publique, accessible à tous. Les interfaces de marché courantes sont: GetTicker, GetDepth, GetRecords et GetTrades. La cote de marché est la base de la stratégie pour faire des jugements commerciaux. Plus tard, je vais les présenter une par une. Il est préférable de les essayer dans le
Chaque interface comporte généralement unInfo
le champ, qui représente la chaîne de données d'origine renvoyée par la plateforme, et qui peut être utilisé pour compléter des informations supplémentaires.JSON.parse()
, alors que Python utilise la bibliothèque json.Time
Le champ indique l'horodatage de la demande, qui peut être utilisé pour juger du retard.
Lorsque vous utilisez n'importe quelle API dans le bot, l'accès peut échouer et retournernull
, et Python retourneNone
. À ce moment, les données en cours d'utilisation signalent une erreur et provoquent l'arrêt du bot, donc la tolérance à l'erreur est très importante. Ce tutoriel présentera la tolérance à l'erreur spécialement.
GetTicker est probablement l'interface la plus couramment utilisée. Vous pouvez trouver le prix exécuté la dernière fois, le prix buy1 et le prix sell1, et le dernier volume de trading. Avant de passer un ordre, le prix exécuté peut être déterminé en fonction des informations du ticker.{"Info:{}, "High":5226.69, "Low":5086.37,"Sell":5210.63, "Buy":5208.5, "Last":5208.51, "Volume":1703.1245, "OpenInterest":0, "Time":1554884195976}
.
function main() {
var ticker = exchange.GetTicker()
Log(ticker) //return ticker in the debugging tool, and you can see the specific result
Log('Last time executed price:',ticker.Last, 'Buy1 price:', ticker.Buy)
}
GetDepth permet d'obtenir des informations approfondies sur les ordres en attente. Bien que GetTicker inclut les prix d'achat 1 et de vente 1, si vous souhaitez interroger des ordres en attente plus profonds, vous pouvez utiliser cette interface, pour généralement vérifier 200 ordres en attente. Les prix de choc peuvent être calculés à l'aide de cette interface. Ci-dessous un résultat de retour réel. Parmi eux,
{
"Info":null,
"Asks":[
{"Price":5866.38,"Amount":0.068644},
{"Price":5866.39,"Amount":0.263985},
......
]
"Bids":[
{"Price":5865.13,"Amount":0.001898},
{"Price":5865,"Amount":0.085575},
......
],
"Time":1530241857399
}
Exemple d'utilisation de GetDepth pour les demandes et les offres:
function main() {
var depth = exchange.GetDepth()
Log('Buy 1 price:', depth.Bids[0].Price, 'Sell 1 price:', depth.Asks[0].Price)
}
GetRecords est l'une des interfaces les plus couramment utilisées, peut retourner des informations de prix dans une longue période à la fois, ce qui est la base du calcul de divers indicateurs. Si la période de la ligne K n'est pas spécifiée, cela signifie utiliser la période par défaut lors de l'ajout d'un bot. La longueur de la ligne K ne peut pas être spécifiée et continuera d'augmenter avec le temps. Le nombre maximum est de 2000, et dans le premier appel, le nombre est d'environ 200 (différentes plateformes renvoient des numéros différents). La dernière ligne K est la dernière ligne K, de sorte que les données changeront à mesure que les cotations du marché changent; la première ligne K est la plus ancienne des données.
exchange.SetMaxBarLen(Len)
peut définir le nombre de K-lines acquises pour la première fois (prouvé par certaines plateformes) et le nombre maximal de K-lines.Par exemple:exchange.SetMaxBarLen(500)
.
GetRecords peut spécifier des périodes telles que PERIOD_M1: 1 minute, PERIOD_M5: 5 minutes, PERIOD_M15: 15 minutes, PERIOD_M30: 30 minutes, PERIOD_H1: 1 heure et PERIOD_D1: 1 jour.exchange.GetRecords(PERIOD_M1)
. Après la mise à niveau du dernier docker, il prendra en charge la personnalisation des périodes, qui passe simplement le deuxième chiffre de la période comme paramètre. La personnalisation au niveau des minutes sera synthétisée selon la ligne K de 1 minute, la ligne K inférieure à 1 minute sera synthétisée via GetTrades ((), et les contrats à terme sur matières premières seront synthétisés selon tick.Notez qu'il y a aussi d'autres variables majuscules commePERIOD_M1
dans le tutoriel. Ce sont les variables globales par défaut de FMZ. Si vous êtes intéressé, vous pouvez
Exemple de données renvoyées:
[
{"Time":1526616000000,"Open":7995,"High":8067.65,"Low":7986.6,"Close":8027.22,"Volume":9444676.27669432},
{"Time":1526619600000,"Open":8019.03,"High":8049.99,"Low":7982.78,"Close":8027,"Volume":5354251.80804935},
{"Time":1526623200000,"Open":8027.01,"High":8036.41,"Low":7955.24,"Close":7955.39,"Volume":6659842.42025361},
......
]
Exemple de ligne K itérée:
function main(){
var close = []
var records = exchange.GetRecords(PERIOD_H1)
Log('total bars: ', records.length)
for(var i=0;i<records.length;i++){
close.push(records[i].Close)
}
return close
}
GetTrades obtient les données de trading dans une certaine plage de temps (pas vos propres données de trading), ce qui n'est pas pris en charge par certaines plateformes.
Ces interfaces sont liées au compte, de sorte qu'elles ne peuvent pas être obtenues directement. Pour les obtenir, vous devez utiliser API-KEY pour signer. Après le traitement automatique unifié en arrière-plan de la plate-forme FMZ, vous pouvez les utiliser directement.
GetAccount pour obtenir les informations du compte. En tant que l'une des interfaces les plus couramment utilisées, il est nécessaire de l'appeler avant de passer une commande, pour éviter un solde insuffisant.{"Stocks":0.38594816,"FrozenStocks":0,"Balance":542.858308,"FrozenBalance":0,"Info":{}}
Lorsque BTC_USDT
,
Notez que le résultat de retour est le résultat de la paire de négociation spécifiée et que les informations sur les autres devises du compte de négociation se trouvent dans le champ
Un bot qui imprime constamment la valeur totale de la paire de négociation en cours:
function main(){
while(true){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
var price = ticker.Buy
var stocks = account.Stocks + account.FrozenStocks
var balance = account.Balance + account.FrozenBalance
var value = stocks*price + balance
Log('Account value is: ', value)
LogProfit(value)
Sleep(3000)//sleep 3000ms(3s), A loop must has a sleep, or the rate-limit of the exchange will be exceed
//when run in debug tool, add a break here
}
}
Les méthodes d'invocation incluentexchange.Buy(Price, Amount)
etexchange.Buy(Price, Amount, Msg)
, dans lequel null
sera renvoyé si la commande est infructueuse, qui est utilisée pour interroger l'état de la commande.
Si vous voulez passer un ordre d'achat au prix du marché, exchange.Buy(-1, 0.5)
; si la paire de négociation estETH_BTC
, ce qui signifie que vous achetez 0,5 BTC d'ETH au prix du marché.
Certaines plateformes ont des exigences de précision pour le prix et le montant, qui peuvent être contrôlés avec la fonction de précision_N()
Pour les contrats à terme,
Exemple d'achat une fois atteint le prix correspondant:
function main(){
while(true){
var ticker = exchange.GetTicker()
var price = ticker.Sell
if(price >= 7000){
exchange.Buy(_N(price+5,2), 1, 'BTC-USDT')
break
}
Sleep(3000)//Sleep 3000ms
}
Log('done')
}
Les paramètres de l'ordre de marché ont des significations différentes.exchange.Sell(-1, 0.2)
, c'est-à-dire vendre 0,2 ETH au prix du marché.
GetOrder obtient les informations de commande basées sur l'identifiant de commande.exchange.GetOrder(OrderId)
, Type
et la valeur réelle de la commandeStatus
Les variables sont des nombres, qui représentent des significations différentes, mais ne sont pas propices à la mémoire.Status
la valeur d'une commande inachevée est 0, ce qui équivaut àORDER_STATE_PENDING
. Toutes ces constantes globales peuvent être vues dans le document... Retour du résultat:
{
"Id":125723661, //Order id
"Amount":0.01, //Order ammount
"Price":7000, //Order price
"DealAmount":0, //Executed amount
"AvgPrice":0, //executed average price
"Status":0, //0: not completely executed; 1: executed; 2: canceled
"Type":1,//Order type; 0: buy order; 1: sell order
"ContractType":"",//contract type, used in futures trading
"Info":{} //the platform returns the raw information
}
}
Une stratégie visant à acheter une certaine quantité de monnaie:
function main(){
while(true){
var amount = exchange.GetAccount().Stocks
var ticker = exchange.GetTicker()
var id = null
if(5-amount>0.01){
id = exchange.Buy(ticker.Sell, Math.min(5-amount,0.2))
}else{
Log('Job completed')
return //return the main function, bot will stop
}
Sleep(3000) //Sleep 3000ms
if(id){
var status = exchange.GetOrder(id).Status
if(status == 0){ //Here you can aslo use "status == ORDER_STATE_PENDING" to judge
exchange.CancelOrder(id)
}
}
}
}
GetOrder obtient la liste de tous les ordres inachevés de la paire de négociation en cours. S'il n'y a pas d'ordre inachevé, renvoie un tableau vide. Le résultat spécifique de la liste d'ordres, tel que
Exemple d'annulation de tous les ordres de la paire de négociation en cours:
function CancelAll(){
var orders = exchange.GetOrders()
for(var i=0;i<orders.length;i++){
exchange.CancelOrder(orders[i].Id) // cancel order by orderID
}
}
function main(){
CancelAll()
while(true){
//do something
Sleep(10000)
}
}
Selon l'identifiant de commande, annuler la commande.exchange.CancelOrder(OrderId)
. Si l'annulation est réussie, retournez
Pour la crypto-monnaie, le trading à terme est différent du trading au comptant. Les fonctions ci-dessus du trading au comptant s'appliquent également au trading à terme, et le trading à terme unique a ses propres fonctions. Avant de mener le trading de programme de futures de crypto-monnaie, vous devez être familier avec les opérations manuelles sur le site Web et comprendre les concepts de base, tels que l'ouverture, la fermeture, le croisement, l'isolement, le levier, le profit et la perte rapprochés, le revenu flottant, la marge et d'autres concepts, ainsi que les formules de calcul correspondantes. Les tutoriels correspondants peuvent être trouvés sur diverses plateformes à terme, et vous devez les apprendre par vous-même.
Les contrats perpétuels sont similaires aux contrats à terme, mais la différence est qu'il n'existe pas de concept de détention de positions longues et courtes en même temps.
Si la plateforme prend en charge à la fois les contrats à terme et les contrats à découvert, tels que les contrats à découvert d'OKEX et Huobi, vous devez sélectionner
La première étape dans le trading de contrats à terme est de définir le contrat à négocier. En prenant les contrats à terme OKEX à titre d'exemple, sélectionnez une paire de trading BTC lors de la création d'un bot ou de backtesting, et vous devez également définir le contrat hebdomadaire, la semaine prochaine ou trimestriel dans le code.invalid contract type
. Contrairement aux paires de négociation au comptant, les contrats à terme utilisent souvent une devise de négociation telle que BTC comme marge. L'ajout de BTC à une paire de négociation représente généralement une paire de négociation BTC_USD qui utilise BTC comme marge. S'il existe un contrat à terme avec USDT comme marge, un bot doit être créé pour ajouter la paire de négociation BTC_USDT. Par exemple, les contrats perpétuels comme Binance OKEX Futures, avec des contrats à crypto-marge et à USDT.Après avoir défini la paire de négociation, vous devez également définir le type de contrat spécifique, tel que perpétuel, hebdomadaire, la semaine prochaine, etc. Après avoir défini le contrat, vous pouvez effectuer des opérations telles que l'obtention de devis sur le marché, l'achat et la vente.
Binance, OKEX, HuobiDM, etc. ont à la fois des contrats cryptographiques et des contrats USDT, qui doivent être distingués lors de l'ajout d'un bot et de la définition d'un contrat.
//OKEX Futures
exchange.SetContractType("swap") // set to perpetual contract
exchange.SetContractType("this_week") // set to weekly contract
exchange.SetContractType("next_week") // set to next week contract
exchange.SetContractType("quarter") // set to quarterly contract
//HuobiDM
exchange.SetContractType("this_week") // set to weekly contract
exchange.SetContractType("next_week") // set to next week contract
exchange.SetContractType("quarter") // set to quarterly contract
exchange.SetContractType("swap") // set to perpetual contract
//Binance Futures
exchange.SetContractType("swap") // set to perpetual contract, and notice that crypto-margined and USDT-margined contracts are all in the perpetual contract
exchange.SetContractType("quarter") // set to quarterly contract
exchange.SetContractType("next_quarter") // set to next quarter contract
//BitMEX
exchange.SetContractType("XBTUSD") // set to perpetual contract
exchange.SetContractType("XBTM19") // the contract settled at a specific time; for more details, please log in BitMEX to check each contract code
//GateIO
exchange.SetContractType("swap") // set to perpetual contract, and do not set the default as swap perpetual contract
//Deribit
exchange.SetContractType("BTC-27APR18") // the contract settled at a specific time; for more details, please log in Deribit to check out
Pour obtenir la liste actuelle des informations de position, les contrats à terme OKEX (OKCOIN) peuvent passer dans un paramètre pour spécifier le type de contrat à obtenir.[]
Il y a beaucoup d'informations spécifiques, qui doivent être analysées en combinaison avec la paire de trading.
Type de données | Nom de la variable | Définition |
---|---|---|
objet | Les informations | la structure brute renvoyée par la plateforme |
Numéro | Niveau de marge | taille de l'effet de levier; OKCoin est 10 ou 20, et la position croisée des contrats à terme OK renvoie 10 (fixé), pour l'API brute ne prend pas en charge |
Numéro | Montant | montant de la position; OKCoin indique la quantité du contrat (entier sur 1) |
Numéro | Nombre congelé | montant de la position gelée |
Numéro | Le prix | prix moyen de la position |
Numéro | Marge | marge congelée |
Numéro | Résultats | les contrats à terme sur matières premières: le profit et la perte de la position marquée sur le marché; crypto-monnaie: unité de crypto-monnaie: BTC/LTC, unité traditionnelle de contrats à terme: RMB (note: dans le cas d'une position croisée de contrats à terme OKCoin, il fait référence au profit et à la perte réalisés, et non au profit et à la perte de la position. Dans la position isolée, il fait référence au profit et à la perte de la position.) |
const | Le type | PD_LONG est la position longue (CTP utilise |
une chaîne | Type de contrat | les contrats à terme sur matières premières sont des codes de contrat, et les actions sont |
function main(){
exchange.SetContractType("this_week");
var position = exchange.GetPosition();
if(position.length>0){ //especially pay attention to judging the length of position before call, or an error will occur
Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type,"ContractType:", position[0].ContractType)
}
}
Tout d'abord, vous devez définir la taille du levier; méthode d'invocation:exchange.SetMarginLevel(10)
, où exchange.SetDirection(Direction)
, qui correspond aux positions ouvertes et fermées.Contrairement aux contrats à terme, si un contrat perpétuel ne contient pas les concepts de long et de court en même temps, c'est-à-dire qu'une seule position n'est pas autorisée.buy
etsell
Si elle prend en charge les positions bidirectionnelles, vous devezclosebuy
, closesell
.Les relations spécifiques:
Opération | Paramètres de direction | Fonction de mise en place de l'ordre |
---|---|---|
Position longue ouverte | Je suis en train de changer de direction | Je suis en train d' acheter. |
Fermer une position longue | Je suis en train de changer de direction. | Je suis en train d' échanger. |
Position courte ouverte | Je suis en train de changer de direction | Je suis en train d' échanger. |
Fermer une position courte | Je suis en train d'écrire une lettre. | Je suis en train d' acheter. |
Enfin, il y a le code spécifique pour les positions ouvertes et fermées. Le montant des ordres passés varie d'une plate-forme à l'autre. Par exemple, les contrats à terme Huobi sont basés sur le nombre de contrats, et un contrat est de 100 dollars américains.
function main(){
exchange.SetContractType("this_week") // for example, set OKEX futures to weekly contract
price = exchange.GetTicker().Last
exchange.SetMarginLevel(10) // set to 10 times of leverage
exchange.SetDirection("buy") // set the order type as buy long
exchange.Buy(price+10, 20) // set contract quantity as 20 orders
pos = exchange.GetPosition()
Log(pos)
Log(exchange.GetOrders()) // check out if there is any unfinished order
exchange.SetDirection("closebuy"); // if it is a perpetual contract, directly set exchange.SetDirection("sell")
exchange.Sell(price-10, 20)
}
Donnez un exemple de stratégie spécifique de positions de fermeture complète comme suit:
function main(){
while(true){
var pos = exchange.GetPosition()
var ticker = exchange.GetTicekr()
if(!ticker){
Log('not able to obtain ticker')
return
}
if(!pos || pos.length == 0 ){
Log('no position')
return
}
for(var i=0;i<pos.length;i++){
if(pos[i].Type == PD_LONG){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closebuy')
exchange.Sell(ticker.Buy, pos[i].Amount - pos[i].FrozenAmount)
}
if(pos[i].Type == PD_SHORT){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closesell')
exchange.Buy(ticker.Sell, pos[i].Amount - pos[i].FrozenAmount)
}
}
var orders = exchange.Getorders()
Sleep(500)
for(var j=0;j<orders.length;j++){
if(orders[i].Status == ORDER_STATE_PENDING){
exchange.CancelOrder(orders[i].Id)
}
}
}
}
Le trading d'effet de levier de crypto-monnaie doit passer au compte d'effet de levier dans le code, et les autres parties sont les mêmes que le trading au comptant.
Utilisationexchange.IO("trade_margin") pour passer au mode compte d'effet de levier; la passation d'un ordre et l'obtention d'actifs de compte accéderont à l'interface de la plateforme d'effet de levier. Utilisationexchange.IO("trade_normal") pour revenir au mode de compte ordinaire.
Plateformes prises en charge:
Les contrats à terme sur matières premières et les contrats à terme sur crypto-monnaie sont très différents. Tout d'abord, le temps de négociation des contrats à terme sur matières premières est très court, mais la crypto-monnaie est négociée pendant 24 heures; le protocole des contrats à terme sur matières premières n'est pas une API REST couramment utilisée; la fréquence de négociation et le montant de la commande en attente des contrats à terme sur matières premières premières sont limités, mais ceux des contrats à terme sur crypto-monnaie sont très lâches, etc. Par conséquent, de nombreux points nécessitent une attention particulière lors de la négociation des contrats à terme sur matières premières premières, et il est recommandé à ceux qui ont une riche expérience des opérations manuelles.https://www.fmz.com/bbs-topic/325Pour ajouter les sociétés à terme sur matières premières:https://www.fmz.com/bbs-topic/371
Les contrats à terme sur matières premières ont mis en place une supervision transparente en juin 2019; pour les programmes individuels, les utilisateurs individuels doivent ouvrir un compte pour demander un code d'autorisation pour les courtiers à terme (le modèle d'information d'application spécifique peut être envoyé au groupe WeChat ou au groupe QQ), ce qui prend généralement 4 à 5 jours; les procédures sont assez compliquées.https://www.fmz.com/bbs-topic/3860. Si votre courtier à terme n'est plus sur la liste, vous pouvez uniquement postuler vous-même, ou ouvrir un nouveau compte d'un courtier pris en charge, ce qui prend généralement 2 jours. FMZ a des relations de coopération approfondies avec certains fournisseurs de services; par exemple, Guotai Junan Hongyuan Futures a acheté la version institutionnelle de la plate-forme FMZ, qui peut être utilisée par ses utilisateurs, et les utilisateurs deviennent automatiquement un VIP lors de l'ouverture d'un compte, et les frais de service sont minimisés.https://www.fmz.com/bbs-topic/506.
En raison des avantages de la structure de la plate-forme FMZ Quant, les utilisateurs peuvent également ajouter plusieurs comptes de courtier à terme et mettre en œuvre certaines fonctions que les autres logiciels de trading de futures de produits de base ne peuvent pas compléter, telles que la synthèse de ticks à haute fréquence; vous pouvez vous référer à:https://www.fmz.com/bbs-topic/1184
Tout d'abord, comme il ne s'agit pas d'un trading 24h et qu'il nécessite une opération de connexion, il est nécessaire de juger de l'état du lien avant de négocier.exchange.IO("status")
esttrue
, ce qui indique une connexion réussie à la plateforme. Si l'API est appelée lorsque la connexion n'est pas réussie, _C(exchange.SetContractType,"MA888")
, ce qui assurera une connexion réussie.
Les codes d'acquisition et de négociation des cotations de marché des contrats à terme sur matières premières sont les mêmes que ceux des contrats à terme sur crypto-monnaie.
function main(){
_C(exchange.SetContractType,"MA888") //If you do not log in successfully, you cannot subscribe to the contract, so better to try again
while(true){
if(exchange.IO("status")){
var ticker = exchange.GetTicker()
Log("MA888 ticker:", ticker)
LogStatus(_D(), "Already connected with CTP !")//_D obtain event
} else {
LogStatus(_D(), "Not connected with CTP !")
Sleep(1000)
}
}
}
Il est recommandé d'utiliser la bibliothèque de contrats à terme sur matières premières pour le trading (qui sera décrite plus loin), le code sera très simple à ce stade, et il n'est pas nécessaire de traiter avec des détails fastidieux.https://www.fmz.com/strategy/57029
function main() {
// Use the CTA strategy framework of commodity futures library
$.CTA(Symbols, function(st) {
var r = st.records
var mp = st.position.amount
var symbol = st.symbol
/*
"r" represents K-line, "mp" indicates the position amount of the current variety; positive number means long position, negative number means short position, and 0 means no position; "symbol" is the variety name
if the return value is n:
n = 0 : full close positions (no matter now they are long or short)
n > 0 : if right now long positions are held, add n long positions; if now they are short positions, close n short posiitons; if n is over the position amount right now, reverse to open long positions
n < 0 : if right now short positions are held, add n short positions; if now they are long positions, close n long posiitons; if -n is over the position amount right now, reverse to open short positions
*/
if (r.length < SlowPeriod) {
return
}
var cross = _Cross(TA.EMA(r, FastPeriod), TA.EMA(r, SlowPeriod));
if (mp <= 0 && cross > ConfirmPeriod) {
Log(symbol, "Golden Cross Period", cross, "the moment position", mp);
return Lots * (mp < 0 ? 2 : 1)
} else if (mp >= 0 && cross < -ConfirmPeriod) {
Log(symbol, "Death Cross Period", cross, "the moment position", mp);
return -Lots * (mp > 0 ? 2 : 1)
}
});
}
Les contrats à terme sur matières premières utilisent le protocole CTP, et toutes les cotations du marché et les exécutions d'ordres ne seront notifiées qu'après les changements, tandis que les requêtes concernant les ordres, les comptes et les positions sont des requêtes actives.GetTicker
, GetDepth
etGetRecords
, tous doivent avoir des données mises en cache pour obtenir les dernières données. S'il n'y a pas de données, il attend jusqu'à ce qu'il y ait des données, il n'est donc pas nécessaire que la stratégie utilise
Si vous voulez obtenir des données à chaque fois que vous obtenez les cotations du marché, même si ce sont des données anciennes, vous pouvez passer au mode de mise à jour immédiate des cotations du marchéexchange.IO("mode", 0)
. À ce stade, la stratégie ne peut pas être écrite comme étant basée sur des événements, et un événement exchange.IO("mode", 1)
pour revenir au mode cache par défaut.
Lors de l'exploitation d'un seul contrat, utilisez le mode par défaut. Cependant, s'il y a plusieurs contrats, il est possible que l'un des contrats ne met pas à jour les devis du marché, ce qui entraîne un blocage de l'interface pour obtenir les devis du marché, et les mises à jour des devis des autres contrats ne peuvent pas non plus être obtenues. Pour résoudre ce problème, le mode de mise à jour immédiate peut être utilisé, mais il est gênant d'écrire des stratégies à haute fréquence.exchange.IO("wait")
Si plusieurs objets d'échange sont ajoutés, ce qui est rare dans les contrats à terme sur matières premières, vous pouvez utiliserexchange.IO("wait_any")
, et l'indice
Poussée des changements de tick du marché:{Event:"tick", Index: platform index (in the order of the platforms added in the bot), Nano: event of nanosecond-level time, Symbol: contract name}
Commande de poussée:{Event:"order", Index:Exchange index, Nano:Event of nanosecond-level time, Order:Order information (same as GetOrder)}
À ce stade, la structure de la stratégie peut être écrite comme suit:
function on_tick(symbol){
Log("symbol update")
exchange.SetContractType(symbol)
Log(exchange.GetTicker())
}
function on_order(order){
Log("order update", order)
}
function main(){
while(true){
if(exchange.IO("status")){ //Judge the link status
exchange.IO("mode", 0)
_C(exchange.SetContractType, "MA888")//Subscribe to MA; only the subscription request for the first time is ture, and the later ones are program switches, which do not consume time
_C(exchange.SetContractType, "rb888")//Subscribe to rb
while(true){
var e = exchange.IO("wait")
if(e){
if(e.event == "tick"){
on_tick(e.Symbol)
}else if(e.event == "order"){
on_order(e.Order)
}
}
}
}else{
Sleep(10*1000)
}
}
}
Notez également la différence entre les futures de matières premières et les plateformes de crypto-monnaie. Par exemple,
exchange.IO("instruments"): il renvoie la liste de tous les contrats de la plateforme {nom du contrat: détails} sous forme de dictionnaire, et ne prend en charge que les robots.exchange.IO("produits"): il renvoie la liste de tous les éléments de la plateforme {nom du contrat: détails} sous forme de dictionnaire, et ne prend en charge que les robots.exchange.IO("abonné"): il renvoie les cotations de marché souscrites sur la plateforme sous forme de dictionnaire, et ne prend en charge que les robots.
LeContractType
Les contrats à terme traditionnels des CTP se réfèrent à l'identifiant du contrat, qui est sensible à la casse et à la majuscule.exchange.SetContractType("au1506")
. Une fois le contrat défini avec succès, il renverra les informations détaillées du contrat, telles que le montant minimum d'achat, les frais de service, le délai de livraison, etc. Lors de l'abonnement à plusieurs contrats, seule la première fois qu'une demande d'abonnement est effectivement envoyée, et puis la paire de négociation est simplement basculée au niveau du code, ce qui ne prend pas de temps. Le principal contrat continu est le code 888, tel que MA888, le contrat de taux continu est 000, tel que MA000; 888 et 000 sont des contrats virtuels qui ne prennent en charge que le backtest, et les vrais robots ne prennent en charge que les cotations du marché.Cependant, Mylanguage peut exploiter le contrat principal, et le programme changera automatiquement de positions, c'est-à-dire qu'il fermera les positions non principales et ouvrira de nouvelles positions sur les positions principales.
Une connexion non réussie ne permet pas de définir des contrats, mais reviendra immédiatement, vous pouvez donc réessayer par
La SetDirection
peut obtenir quatre paramètres:buy, closebuy, sell, closesell
Les contrats à terme sur matières premières ont plusclosebuy_today
etclosesell_today
, indiquant la clôture des positions courantes; le défaut estclosebuy/ closesell
, indiquant la clôture des positions d'hier; seules les variétés de la Bourse de Shanghai sont divisées en clôture d'aujourd'hui et clôture d'hier, ce qui peut affecter les frais de service, il est donc nécessaire de donner la priorité à la clôture des positions d'hier. Pour les contrats à terme traditionnels CTP, vous pouvez définir le deuxième paramètre comme
Opération | Paramètres de direction | Fonction de mise en place de l'ordre |
---|---|---|
Position longue ouverte | Je suis en train de changer de direction | Je suis en train d' acheter. |
Fermer une position longue | Je suis en train de changer de direction. | Je suis en train d' échanger. |
Position courte ouverte | Je suis en train de changer de direction | Je suis en train d' échanger. |
Fermer une position courte | Je suis en train d'écrire une lettre. | Je suis en train d' acheter. |
L'exemple suivant est une fonction de position de clôture spécifique. Notez que cet exemple est trop simple. Vous devriez également considérer si elle est dans le temps de négociation, comment réessayer l'ordre en attente si elle n'est pas complètement remplie, quel est le volume maximal de l'ordre, si la fréquence est trop élevée, et si elle est coulissante prix ou prix du marché et ainsi de suite.Il s'agit d'une bibliothèque de plates-formes suggérées pour l'ouverture et la fermeture de positions dans de vrais robots:https://www.fmz.com/strategy/12961Il y a une introduction spécifique dans la section bibliothèque, et il est également recommandé d'étudier les codes sources de la bibliothèque.
function Cover(contractType, amount, slide) {
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType != contractType) {
continue;
}
var depth = _C(e.GetDepth);
if (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) {
exchange.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");
exchange.Sell(depth.Bids[0]-slide, amount, contractType, positions[i].Type == PD_LONG ? "Close today" : "Close yesterday", 'Bid', depth.Bids[0]);
} else {
exchange.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
exchange.Buy(depth.Asks[0]+slide, amount, contractType, positions[i].Type == PD_SHORT ? "Close today" : "Close yesterday", 'Ask', depth.Asks[0]);
}
}
}
Les contrats à terme sur matières premières prennent en charge des types d'ordres personnalisés (support pour les robots, mais pas pour les backtests), qui sont spécifiés par un suffixe, joint à
exchange.SetDirection("buy_ioc");
exchange.SetDirection("sell_gtd-20170111")
Suffixes spécifiques:
Par défaut, les interfaces ouvertes dans les courtiers à terme sur matières premières sont toutes des interfaces CTP. Si nécessaire, elles peuvent être remplacées par des interfaces Esunny. Grâce à l'encapsulation de FMZ, la méthode d'invocation est la même.
Les types de commandes personnalisées sont les suivants:
Lorsque vous enregistrez un enregistrement de journal sur l'interface du bot, et ajoutez le caractère Log('Push to WeChat@')
.
La couleur du journal peut également être personnalisée, commeLog('this is a log in red font #ff0000')
.
#ff0000
est l'hexadecimal de la couleur RVB, indiquant que tous les fichiers journaux sont stockés dans la base de données SqLit du bot dans le répertoire où se trouve le docker, qui peut être téléchargé et ouvert avec un logiciel de base de données, ou peut être utilisé pour copier une sauvegarde et restaurer (le nom de la base de données et l'identifiant du bot sont les mêmes).
Il enregistre les profits et dessine la courbe de profit sur l'interface du bot, qui peut être conservée après le redémarrage du bot.LogProfit(1000)
. Notez que le paramètre deLogProfit
n'est pas nécessairement le profit, et il peut être n'importe quel nombre et doit être rempli par vous-même.
Si l'état du bot, puisque le journal sera sauvegardé en premier et actualisé en permanence, a besoin de l'information uniquement pour l'affichage et non pour l'enregistrement, vous pouvez utiliser leLogStatus
Les paramètres deLogStatus
sont des chaînes, qui peuvent également être utilisées pour représenter les informations du tableau.
Un exemple de tableau d'affichage de la position réelle du bot:
var table = {type: 'table', title: 'position information', cols: ['Column1', 'Column2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]};
LogStatus('`' + JSON.stringify(table) + '`'); // After serialization, JSON will be added the character "'" on both sides, which is regarded as a comlpex messag format (now supporting tables)
LogStatus('The first line information\n`' + JSON.stringify(table) + '`\nthe third line information'); // the table information can be displayed in multiple lines
LogStatus('`' + JSON.stringify([table, table]) + '`'); // Multiple tables are supported to be displayed at the same time, which will be displayed in one group by TAB
LogStatus('`' + JSON.stringify(tab1) + '`\n' + '`' + JSON.stringify(tab2) + '`\n