Dans l'article précédent, nous avons mis en œuvre une stratégie de couverture simple ensemble, et puis nous allons apprendre comment améliorer la stratégie. Il n'y a pas beaucoup de modifications dans la stratégie, mais les détails des modifications nécessitent une attention particulière.
A->B
etB->A
, ainsi que les lignes de déclenchement horizontales, nous pouvons utiliser directement lechart plot library
; l'avantage est la simplicité et la facilité d'utilisation.template library
together.Ensuite, réalisons ces idées de conception une par une.
Prenez Binance spot bot comme exemple. Pour passer au mode de marge au comptant, utiliser le codeexchanges[i].IO
, importez le paramètretrade_normal
de passer à la marge isolée et d'importertrade_super_margin
pour passer à la marge croisée, qui n'est pas prise en charge dans le backtest.
Dans la préparation au début de lamain
fonction, ajouter:
// switch the margin mode
for (var i = 0 ; i < exchanges.length ; i++) { // traverse and detect all exchange objects added
if (exchanges[i].GetName() == "Binance" && marginType != 0) { // if the exchange object represented by the current index i is Binance Spot, and the parameter marginType on the strategy interface is not selected as the "common spot" option, execute the switch
if (marginType == 1) {
Log(exchanges[i].GetName(), "set to isolated margin")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "set to cross margin")
exchanges[i].IO("trade_super_margin")
}
}
}
La stratégie ici n'ajoute que le code pour changer le mode de marge au comptant de Binance Spot, donc le réglage du commutateur dans les paramètres de stratégie ne fonctionne que pour Binance Spot.
L'utilisation des modèles de traçage encapsulés est très simple.chart plot Library
Vous pouvez le rechercher directement sur la plateforme Square of FMZ.
Ou vous pouvez directement cliquer sur le lien:https://www.fmz.com/strategy/27293pour passer à la page de copie du modèle.
Cliquez sur le bouton et vous pouvez facilement copier le modèle dans votre propre bibliothèque de stratégie.
Ensuite, sur la page d'édition de stratégie, vous pouvez vérifier la bibliothèque de modèle à utiliser dans la colonne de modèle. Enregistrer la stratégie après la vérification, et la stratégie utilisera ce modèle. Ceci est juste une brève description de l'utilisation de la bibliothèque de modèle. Puisque la stratégie a déjà fait référence à ce modèle, il n'est pas nécessaire de répéter l'opération. Lorsque vous copiez le code de stratégie dans Square, vous pouvez voir quechart plot Library
a été référencé dans la barre de modèle de la page d'édition de stratégie.
Ici, nous apprenons principalement à utiliser les fonctions duchart plot library
pour comploter.
Nous prévoyons de tracer les écarts deA->B
etB->A
Nous devons tracer deux courbes (actuellement, les spreads de A à B et de B à A), et deux lignes horizontales (lignes de déclenchement des spreads), comme indiqué sur la figure ci-dessus.
Parce que nous voulons concevoir une haie à un seul côté, les lignes de déclenchement deA->B
etB->A
Nous ne pouvons pas utiliser la conception de l'article précédent.
Dans l'article précédent:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Il n' y a qu' une seule propagation activée.targetDiffPrice
Je suis désolée.
Par conséquent, ici nous devons modifier le code, et nous devons modifier les paramètres d'abord.
modifier le code:
var targetDiffPriceA2B = hedgeDiffPriceA2B
var targetDiffPriceB2A = hedgeDiffPriceB2A
if (diffAsPercentage) {
targetDiffPriceA2B = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageA2B
targetDiffPriceB2A = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageB2A
}
Ainsi, la ligne de déclenchement de la propagation a changé de la précédentetargetDiffPrice
à deux, à savoirtargetDiffPriceA2B
ettargetDiffPriceB2A
Je suis désolée.
Ensuite, vous pouvez utiliser la fonction de traçage de graphiques de la bibliothèque de graphiques pour dessiner les données sur le graphique.
// plot
$.PlotHLine(targetDiffPriceA2B, "A->B") // the first parameter of the function is the value of the horizontal line in the Y-axis direction, and the second parameter is the display text
$.PlotHLine(targetDiffPriceB2A, "B->A")
Lorsque la stratégie est exécutée, le graphique sera affiché comme ceci.
Ensuite, tracez la courbe des écarts en temps réel; afin d'éviter de trop tracer, placez le code qui trace les courbes des écarts en temps réel dans la détection du solde. s
if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
nowAccs = _C(updateAccs, exchanges)
var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
cancelAll()
if (isBalance) {
lastKeepBalanceTS = ts
if (isTrade) {
var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
isTrade = false
}
}
$.PlotLine("A2B", depthA.Bids[0].Price - depthB.Asks[0].Price) // plot real-time spread curves
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // the first parameter is the curve name, and the second parameter is the curve value at the current moment, that is, the value in the Y-axis direction at the current moment
}
Le code de traçage n'a besoin que de 4 lignes pour permettre la stratégie avec un affichage de graphique pendant l'exécution.
Comme mentionné ci-dessus, le nombre de lignes de déclenchement du spread a été modifié en deux, qui contrôlent respectivement le déclencheur de la couverture deA->B
etB->A
De cette façon, l'algorithme du prix de commande précédent ne peut pas être utilisé, et la méthode d'addition du prix de glissement au prix du marché est utilisée à la place.
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A->B market condition satisfied
var priceSell = depthA.Bids[0].Price - slidePrice
var priceBuy = depthB.Asks[0].Price + slidePrice
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance * 0.8 / priceSell > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance * 0.8 / priceSell, maxHedgeAmount)
Log("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // prompt message
hedge(exB, exA, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPriceB2A && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B->A market condition satisfied
var priceBuy = depthA.Asks[0].Price + slidePrice
var priceSell = depthB.Bids[0].Price - slidePrice
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance * 0.8 / priceBuy > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance * 0.8 / priceBuy, maxHedgeAmount)
Log("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) // prompt message
hedge(exA, exB, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Comme les prix d'achat et de vente sont divisés en deux parties de données, leshedge
La fonction doit également être modifiée.
function hedge(buyEx, sellEx, priceBuy, priceSell, amount) {
var buyRoutine = buyEx.Go("Buy", priceBuy, amount)
var sellRoutine = sellEx.Go("Sell", priceSell, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
Il y a aussi quelques ajustements mineurs basés sur ces modifications, qui ne seront pas décrits ici.
Ajouter de l'interaction à la stratégie, de sorte que la stratégie puisse modifier la ligne de déclenchement de la propagation en temps réel. La conception de l'interaction de stratégie est également très simple. Premièrement, ajoutez des commandes interactives à la stratégie sur la page de modification de stratégie.
Il y avait deux commandes ajoutées, l'une appelée A2B et l'autre appelée B2A. Après avoir entré une valeur dans la zone d'entrée de contrôle, cliquez sur le bouton à droite de la zone d'entrée. Une commande sera envoyée à la stratégie immédiatement, par exemple: entrer la valeur123
dans la zone d'entrée, cliquez surA2B
le bouton, et une commande sera envoyée à la stratégie immédiatement.
A2B:123
Concevoir un code de détection et de traitement interactif dans le code de stratégie.
// interaction
var cmd = GetCommand() // every time when the loop is operated here, it will detect whether an interactive command is sent; if no, return null string
if (cmd) { // interactive command detected, such as A2B:123
Log("received command:", cmd)
var arr = cmd.split(":") // split out the interactive control name and the value in the input box; arr[0] means A2B, and arr[1] means 123
if (arr[0] == "A2B") { // judge whether the triggered interactive control is A2B
Log("modify parameterA2B,", diffAsPercentage ? "parameter of spread ratio:" : "parameter of spread:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // modify the spread trigger line
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // modify the spread trigger line
}
} else if (arr[0] == "B2A") { // detected the triggered control is B2A
Log("modify parameterB2A,", diffAsPercentage ? "parameter of spread ratio:" : "parameter of spread:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageA2B = parseFloat(arr[1])
} else {
hedgeDiffPriceB2A = parseFloat(arr[1])
}
}
}
Rendre l'affichage des données de la barre d'état plus réglementé et plus facile à observer.
var tbl = {
"type" : "table",
"title" : "data",
"cols" : ["platform", "Currency", "frozenCurrrency", "quoteCurrency", "frozenQuoteCurrency", "triggerSpread", "currentSpread"],
"rows" : [],
}
tbl.rows.push(["A:" + exA.GetName(), nowAccs[0].Stocks, nowAccs[0].FrozenStocks, nowAccs[0].Balance, nowAccs[0].FrozenBalance, "A->B:" + targetDiffPriceA2B, "A->B:" + (depthA.Bids[0].Price - depthB.Asks[0].Price)])
tbl.rows.push(["B:" + exB.GetName(), nowAccs[1].Stocks, nowAccs[1].FrozenStocks, nowAccs[1].Balance, nowAccs[1].FrozenBalance, "B->A:" + targetDiffPriceB2A, "B->A:" + (depthB.Bids[0].Price - depthA.Asks[0].Price)])
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
Le backtest n'est qu'un test de la stratégie, en tant que fonction de détection préliminaire. De nombreux bugs peuvent en fait être testés au stade du backtest. Il n'est pas nécessaire de se soucier trop des résultats du backtest. Finalement, la stratégie doit encore être testée dans l'environnement réel avec de vrais bots.
Le code source de la stratégie:https://www.fmz.com/strategy/302834