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 cette stratégie. Les changements de stratégie ne sont pas importants, mais les détails des changements nécessitent une attention particulière.
A exchange -> B exchange
, B exchange -> A exchange
, et de tracer la ligne horizontale qui déclenche la propagation.line drawing class library
L'avantage est qu'il est facile à utiliser, ici nous apprenons également à utiliser letemplate class library
fonction de la FMZ.Ensuite, mettons en œuvre ces conceptions une par une.
Prenez Binance spot vrai bot comme un exemple, passer à la place mode de levier, utiliser le codeexchanges[i].IO
, entrez le paramètretrade_normal
pour passer à l'effet de levier position par position et entréetrade_super_margin
Pour passer à la position de levier, le backtesting n'est pas pris en charge.
Ajouter à la phase de préparation au début de lamain
fonction:
// Switch leverage mode
for (var i = 0 ; i < exchanges.length ; i++) { // Traverse and detect all added exchange objects
if (exchanges[i].GetName() == "Binance" && marginType != 0) { //If the exchange object represented by the current i-index is Binance spot, and the parameter marginType of the strategy interface is not the option of "common currency", execute the switch operation
if (marginType == 1) {
Log(exchanges[i].GetName(), "Set to leveraged position-by-position")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "Set to leveraged full position")
exchanges[i].IO("trade_super_margin")
}
}
}
La stratégie ici n'ajoute que le code pour changer le mode d'effet de levier de pièce à pièce de Binance spot, de sorte que le réglage du commutateur sur les paramètres de la stratégie n'est valable que pour Binance spot.
Il est très facile d'utiliser le modèle de dessin déjà enveloppé.Line Drawing Library
Il peut être obtenu en effectuant une recherche directement sur la plateforme de stratégie FMZ.
Ou cliquez directement sur le lien:https://www.fmz.com/strategy/27293pour accéder à la page de copie de ce modèle.
Cliquez sur le bouton pour copier cette bibliothèque de classe de modèle dans votre propre bibliothèque de stratégie.
Ensuite, vous pouvez vérifier la bibliothèque de classe de modèle à utiliser dans la colonne de modèle sur la page d'édition de stratégie. Enregistrer la stratégie après la vérification, et la stratégie se référera à ce modèle. Ceci est juste une brève description de l'utilisation de la bibliothèque de classe de modèle. Cette stratégie a déjà fait référence à ce modèle, il n'y a donc pas besoin de répéter l'opération. Lorsque vous copiez cette stratégie dans le carré de stratégie, vous pouvez voir queLine Drawing Library
a fait l'objet d'une référence dans la barre de modèle de la page d'édition de stratégie.
Nous apprendrons principalement à utiliser les fonctions de laLine Drawing Library
pour dessiner un graphique.
Nous avons l'intention de dessiner la propagation deA->B
, la diffusion deB->A
, et la ligne de déclenchement de l'écart. nous devons dessiner deux courbes (actuel A à B, B à A écart), deux lignes horizontales (ligne de déclenchement de l'écart), comme indiqué dans la figure ci-dessus.
Parce que nous voulons concevoir une couverture unilatérale, les lignes de déclenchement deA->B
etB->A
Nous ne pouvons pas utiliser le dessin 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' un seul déclencheurtargetDiffPrice
Je suis désolée.
Donc ici nous devons transformer le code, transformer les paramètres d'abord.
Puis modifiez 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
}
De cette façon, la différence ligne de déclenchement a changé de la précédentetargetDiffPrice
À deux.targetDiffPriceA2B
, targetDiffPriceB2A
Je suis désolée.
L'étape suivante consiste à dessiner ces données sur le graphique en utilisant la fonction de ligne de dessin de la bibliothèque de dessin de ligne.
// drawing
$.PlotHLine(targetDiffPriceA2B, "A->B") // The first parameter of this 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")
Quand la stratégie est en cours d'exécution, il y a un graphique comme celui-ci.
Ensuite, tracez la courbe de propagation en temps réel, pour éviter de sur-tracer la ligne.
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) // Draw real-time spread curves
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // The first parameter is the name of the curve, and the second parameter is the value of the curve at the current moment, that is, the value in the Y-axis direction at the current moment
}
De cette façon, le code de dessin est de seulement 4 lignes, ce qui permet à la stratégie d'avoir un graphique affiché au moment de l'exécution.
Comme mentionné ci-dessus, la ligne de déclenchement du spread a été modifiée en deux, contrôlant 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 d'entrée au prix de 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 conditions are met
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("trigger A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // Tips
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 conditions are met
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("trigger B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) //Tips
hedge(exA, exB, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Comme les prix d'achat et de vente sont séparés en deux données, la fonction de couverturehedge
Il faut aussi modifier.
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 changements, qui ne seront pas répétés ici.
Ajouter une 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 contrôles d'interaction à la stratégie sur la page de modification de stratégie.
Ajout de deux commandes, 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 instruction sera envoyée à la stratégie immédiatement, par exemple: entrez la valeur123
dans la zone d'entrée, cliquez surA2B
Une instruction sera immédiatement envoyée à la stratégie.
A2B:123
Concevoir un code de détection et de traitement interactif dans le code de stratégie.
// interact
var cmd = GetCommand() // Every time the loop is executed here, it checks whether there is an interactive command, and returns to an empty string if not.
if (cmd) { // An interactive command was detected, such as A2B:123
Log("command received:", cmd)
var arr = cmd.split(":") // Split out the interactive control name and the value in the input box, arr[0] is A2B, arr[1] is 123
if (arr[0] == "A2B") { // Determine whether the triggered interactive control is A2B
Log("Modify the parameters of A2B, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // Modify the trigger spread line
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // Modify the trigger spread line
}
} else if (arr[0] == "B2A") { // Triggered control detected is B2A
Log("Modify the parameters of B2A, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", 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 organisé et facile à observer.
var tbl = {
"type" : "table",
"title" : "data",
"cols" : ["exchange", "coin", "freeze coin", "denominated currency", "freeze denominated currency", "trigger spread", "current spread"],
"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 backtesting n'est qu'une stratégie de test, une fonction de détection préliminaire, et de nombreux bugs peuvent être testés au stade du backtesting en fait.
Le code source de la stratégie:https://www.fmz.com/strategy/302834