Im vorherigen Artikel haben wir gemeinsam eine einfache Absicherungsstrategie implementiert, und dann werden wir lernen, wie wir die Strategie aktualisieren können. Es gibt nicht viele Änderungen in der Strategie, aber die Einzelheiten der Änderungen erfordern Aufmerksamkeit.
A->B
undB->A
, sowie die horizontalen Spread-Trigger-Linien, können wir direktchart plot library
Hier erfahren wir auch, wie wir die Funktion von FMZ verwenden.template library
together.Als nächstes werden wir diese Designideen einzeln umsetzen.
Nehmen Sie Binance Spot-Bot als Beispiel.exchanges[i].IO
, den Parameter importierentrade_normal
Umschaltung auf isolierte Marge und Einfuhrtrade_super_margin
Das kann nur in Bots verwendet werden.
In der Vorbereitung zu Beginn dermain
Funktion, hinzufügen:
// 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")
}
}
}
Die Strategie hier fügt nur den Code zum Umschalten des Spot-Margin-Modus von Binance Spot hinzu, so dass die Umschalt-Einstellung in den Strategieparametern nur für Binance Spot funktioniert.
Die Verwendung der eingekapselten Plotting-Vorlagen ist sehr einfach.chart plot Library
Sie können es direkt auf der Plattform des FMZ-Platzes suchen.
Oder Sie klicken direkt auf den Link:https://www.fmz.com/strategy/27293um auf die Kopieseite der Vorlage zu springen.
Klicken Sie auf die Schaltfläche und Sie können die Vorlage einfach in Ihre eigene Strategiebibliothek kopieren.
Dann können Sie auf der Strategiebearbeitungsseite die Template-Bibliothek überprüfen, die in der Template-Spalte verwendet werden soll. Speichern Sie die Strategie, nachdem Sie sie überprüft haben, und die Strategie wird diese Template verwenden. Dies ist nur eine kurze Beschreibung der Verwendung der Template-Bibliothek. Da die Strategie bereits auf diese Vorlage verwiesen hat, ist es nicht notwendig, den Vorgang zu wiederholen. Wenn Sie den Strategiecode in Square kopieren, können Sie sehen, dasschart plot Library
wurde in der Vorlageleiste der Strategiebearbeitungsseite verwiesen.
Hier lernen wir hauptsächlich, wie man die Funktionen derchart plot library
- Ich habe einen Plan.
Wir planen, die Ausbreitung vonA->B
undB->A
Wir müssen zwei Kurven (derzeit die Spreads von A nach B und B nach A) und zwei horizontale Linien (Spread-Trigger-Linien) zeichnen, wie in der obigen Abbildung gezeigt.
Weil wir eine einseitige Hecke entwerfen wollen, die Auslöserlinien vonA->B
undB->A
Wir können nicht den Entwurf im vorherigen Artikel verwenden.
Im vorherigen Artikel:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Es gibt nur eine ausgelöste VerbreitungtargetDiffPrice
- Ich weiß.
Daher müssen wir hier den Code ändern, und wir müssen zuerst die Parameter ändern.
Dann ändern Sie den 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
}
Somit hat sich die Spread-Trigger-Linie von der vorherigen geänderttargetDiffPrice
auf zwei, nämlichtargetDiffPriceA2B
undtargetDiffPriceB2A
- Ich weiß.
Als nächstes können Sie die Diagramm-Plotting-Funktion der Diagramm-Plot-Bibliothek verwenden, um die Daten auf dem Diagramm zu zeichnen.
// 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")
Wenn die Strategie ausgeführt wird, wird das Diagramm wie folgt angezeigt.
Als nächstes zeichnen Sie die Echtzeit-Spread-Kurve; um eine Überziehung zu vermeiden, legen Sie den Code, der die Echtzeit-Spread-Kurven zeichnet, in die Bilanzdetektion ein. 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
}
Der Plotting-Code benötigt nur 4 Zeilen, um die Strategie mit einer Diagrammdarstellung während des Laufens zu ermöglichen.
Wie bereits erwähnt, wurde die Anzahl der Spread-Trigger-Linien in zwei geändert, die jeweils den Hedge-Trigger vonA->B
undB->A
Auf diese Weise kann der vorherige Bestellpreis-Algorithmus nicht verwendet werden und stattdessen wird die Methode der Hinzufügung des Slide-Preises zum Marktpreis verwendet.
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
}
}
Da Kauf- und Verkaufspreise in zwei Datenbestände aufgeteilt sind, werden diehedge
Wir müssen die Funktion auch modifizieren.
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()
}
Es gibt auch einige kleinere Anpassungen, die auf diesen Änderungen basieren, die hier nicht beschrieben werden.
Das ist auch die Konstruktionsanforderung einer halbautomatischen Strategie, die auch hier als Lehrdemonstration implementiert wird. Das Strategie-Interaktionsdesign ist ebenfalls sehr einfach.
Es wurden zwei Steuerelemente hinzugefügt, eine mit dem Namen A2B und die andere mit dem Namen B2A. Nachdem Sie einen Wert in das Steuereingabefeld eingegeben haben, klicken Sie auf die Schaltfläche rechts vom Eingabefeld. Ein Befehl wird sofort an die Strategie gesendet, zum Beispiel:123
in der Eingabebox klicken Sie aufA2B
Schaltfläche, und ein Befehl wird sofort an die Strategie gesendet.
A2B:123
Entwerfen von interaktiven Erkennungs- und Verarbeitungskoden im Strategiecode.
// 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])
}
}
}
Die Anzeige der Statusleiste ist besser geregelt und leicht zu beobachten.
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) + "`")
Der Backtest ist nur ein Test der Strategie, als eine vorläufige Erkennungsfunktion. Viele Bugs können tatsächlich in der Backtest-Phase getestet werden. Es ist nicht notwendig, sich zu sehr um die Backtest-Ergebnisse zu kümmern. Schließlich muss die Strategie immer noch in der realen Umgebung mit echten Bots getestet werden.
Strategie-Quellcode:https://www.fmz.com/strategy/302834