Récemment, il y a beaucoup de stratégies de type Martingale discutées dans le groupe officiel de FMZ, et il n'y a pas beaucoup de stratégies de type Martingale de contrats de crypto-monnaie sur notre plate-forme. Par conséquent, j'ai profité de l'occasion pour concevoir une stratégie de type Martingale de futures de crypto-monnaie simple. Pourquoi est-elle appelée stratégie de type Martingale? Parce que le risque potentiel de la stratégie de Martingale n'est en effet pas petit, il n'est pas nécessaire de concevoir selon la stratégie de Martingale. Cependant, ce type de stratégies comporte encore de nombreux risques, et les paramètres de la stratégie de type Martingale sont étroitement liés aux risques, et les risques ne doivent pas être ignorés.
Dans cet article, nous expliquons principalement et apprenons de la conception des stratégies de type Martingale.
L'équité totale est souvent utilisée lors de la conception d'une stratégie à terme de crypto-monnaie, car nous voulons calculer les bénéfices, en particulier lorsque nous devons calculer les bénéfices flottants.exchange.GetAccount()
En fait, la plupart des plateformes de contrats à terme de crypto-monnaie fournissent les données du capital total, mais cette propriété n'est pas uniformément regroupée sur FMZ.
Par conséquent, nous concevons séparément des fonctions pour obtenir les données selon différentes plateformes:
// OKEX V5 obtains the total equity
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("Fail to obtain the total equity of the account!")
return null
}
}
return totalEquity
}
// Binance Ftures
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("Fail to obtain the total equity!")
return null
}
}
return totalEquity
}
LetotalEquity
dans le code est la valeur totale dont nous avons besoin. puis nous écrivons une fonction comme l'entrée d'invocation, et appeler la fonction correspondante selon le nom de la plate-forme.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "Do not support the platform"
}
}
Avant de concevoir la fonction principale et la logique principale, nous devons également concevoir quelques fonctions auxiliaires pour la préparation.
Annuler toutes les commandes en attente
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
Sleep(500)
}
}
On pense que cette fonction est familière à ceux qui lisent souvent le code de l'exemple de stratégie sur le carré de stratégie FMZ, et de nombreuses stratégies ont utilisé la conception similaire.
L'opération consistant à placer des ordres à terme
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
Il existe quatre directions pour le trading de contrats à terme: position ouverte longue (openLong), position ouverte courte (openShort), position longue fermée (coverLong) et position fermée courte (coverShort). Par conséquent, nous avons conçu quatre fonctions d'ordre pour correspondre à ces opérations.
Nous avons aussi conçu une fonction appelée:trade
pour gérer l'opération lorsquedirection (distance)
, order price (price)
etorder amount (amount)
sont spécifiées.
Les appels à la fonction des positions longues ouvertes (openLong), des positions courtes ouvertes (openShort), des positions longues fermées (coverLong) et des positions courtes fermées (coverShort) sont finalement complétés par letrade
La fonction, c'est-à-dire, selon la direction, le prix et le montant spécifiés, placer des ordres dans les plateformes à terme.
L'idée de la stratégie est très simple; prendre le prix actuel comme la ligne de base, et à une certaine distance au-dessus et en dessous de la ligne de base pour placer des ordres de vente (short) et des ordres d'achat (long).
Travaux initiaux Pour que nous voulons des commandes en attente, nous avons besoin de deux variables pour enregistrer l'ID de commande.
var buyOrderId = null
var sellOrderId = null
Ensuite, l'option d'utiliser le bot simulé OKEX_V5 est conçue dans les paramètres de l'interface de stratégie, donc un certain traitement doit être effectué dans le code:
var exName = exchange.GetName()
// switch to OKEX V5 simulated bot
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
L'option de réinitialisation de toutes les informations est également conçue dans les paramètres de stratégie, donc un certain traitement doit être effectué dans le code:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("Reset all data", "#FF0000")
}
Nous n'exécutons que des contrats perpétuels, donc ici nous l'écrivons dans une boucle infinie, et nous le définissons uniquement sur le contrat perpétuel.
exchange.SetContractType("swap")
En outre, nous devons considérer les problèmes de précision du prix de l'ordre et du montant de l'ordre. Si la précision n'est pas réglée correctement, elle sera perdue pendant le processus de calcul de la stratégie. Si les données ont un grand nombre de décimales, il est facile de faire rejeter l'ordre par l'interface de la plateforme.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("set percision", pricePrecision, amountPrecision)
La simple fonction de récupération de données dans la conception
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "Fail to obtain the initial equity"
}
} else {
totalEq = recoverTotalEq
}
}
Si vous voulez spécifier le capital total initial du compte lors de l'exécution de la stratégie, vous pouvez définir le paramètretotalEq
. Si ce paramètre est réglé sur -1, la stratégie lira les données de capital total stockées. S'il n'y a pas de données de capital total stockées, le capital total actuellement lu est utilisé comme capital total initial dans la stratégie en cours d'exécution. Plus tard, si le capital total augmente, cela signifie qu'il a gagné un profit; si le capital total diminue, cela signifie qu'il y a une perte. Si les données de capital total sont lues, utilisez les données pour continuer à fonctionner.
La logique principale Après le travail initial, nous sommes finalement arrivés à la partie logique principale de la stratégie.
while (1) { // the main logic of the strategy is designed as an infinite loop
var ticker = _C(exchange.GetTicker) // read the current market information first, in which we mainly use the latest trading price
var pos = _C(exchange.GetPosition) // read the current position data
if (pos.length > 1) { // judge the position data; due to the strategy logic, it is unlikely to have long and short positions at the same time, so if there are long and short positions at the same time, an error will be thrown
Log(pos)
throw "concurrently with long and short positions" // raise an error, and stop the strategy
}
// according to the status
if (pos.length == 0) { // according to the position status, make different operations; if pos.length == 0, it means currently no position
// when there is no position yet, calculate the equity
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "Current total equity:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // pend buy order of open long position
sellOrderId = openShort(ticker.Last + targetProfit, amount) // pend sell order of open short position
} else if (pos[0].Type == PD_LONG) { // there are long positions; pending position and amount are
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // there are short positions; pending position and amount are different
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // if opending orders of one side fails, cancel all pending orders and try again
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // finish pending the order, and start to monitor the order
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // both buy order and sell order are detected to be executed
cancelAll()
break
} else if (!isFindBuyId) { // a buy order execution is detected
Log("buy order executed")
cancelAll()
break
} else if (!isFindSellId) { // a sell order execution is detected
Log("sell order executed")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
Toute la logique et la conception sont alors complètement expliquées.
Laissez la stratégie traverser les cotations du marché le 19 mai 2021.
Comme nous pouvons le voir, la stratégie similaire à la stratégie de Martingale comporte encore certains risques.
Adresse stratégique:https://www.fmz.com/strategy/294957
La stratégie est principalement utilisée pour l'étude, alors n'utilisez pas la stratégie dans un vrai bot!