
Im vorherigen Artikel haben wir eine einfache Absicherungsstrategie implementiert. Als Nächstes erfahren wir, wie man diese Strategie erweitert. Die Strategieänderungen werden nicht groß sein, aber die Einzelheiten der Änderungen erfordern Aufmerksamkeit. Die Definitionen einiger Teile im Code haben sich gegenüber früher geändert und müssen verstanden werden.
A交易所->B交易所,B交易所->A交易所Zeichnen Sie die horizontale Linie, die die Ausbreitung auslöst. Wir verwenden direkt画线类库Der Vorteil ist, dass es einfach und leicht zu bedienen ist. Hier erfahren Sie auch, wie Sie FMZ verwenden模版类库Funktion.Als nächstes implementieren wir diese Designs nacheinander.
Am Beispiel des Binance Spothandels wechseln Sie mit dem Code in den Spot Leverage-Modusexchanges[i].IO, Parameter übergebentrade_normalWechseln Sie zu Leveraged Position-by-Position und geben Sie intrade_super_marginWechseln Sie zur gehebelten Vollposition, Backtesting wird nicht unterstützt. Dies wird nur im realen Handel verwendet.
existierenmainFügen Sie am Anfang der Funktion folgende Vorbereitungsphase hinzu:
// 切换杠杆模式
for (var i = 0 ; i < exchanges.length ; i++) { // 遍历检测所有添加的交易所对象
if (exchanges[i].GetName() == "Binance" && marginType != 0) { // 如果当前i索引代表的交易所对象是币安现货,并且策略界面参数marginType选择的不是「普通币币」选项,执行切换
if (marginType == 1) {
Log(exchanges[i].GetName(), "设置为杠杆逐仓")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "设置为杠杆全仓")
exchanges[i].IO("trade_super_margin")
}
}
}
Die Strategie hier fügt lediglich den Code zum Umschalten des Coin-to-Coin-Hebelmodus für Binance Spot hinzu, sodass der in den Strategieparametern festgelegte Schalter nur für Binance Spot gültig ist.
Die Verwendung der mitgelieferten Zeichenvorlagen ist ganz einfach. Die von uns verwendete Vorlage heißt画线类库. Suchen und beziehen können Sie es direkt auf der FMZ-Plattform StrategiePlatz.

Oder klicken Sie direkt auf den Link: https://www.fmz.com/strategy/27293, um zur Kopierseite dieser Vorlage zu springen.

Klicken Sie auf die Schaltfläche, um diese Vorlagenbibliothek in Ihre eigene Strategiebibliothek zu kopieren.

Anschließend können Sie auf der Seite zur Richtlinienbearbeitung in der Vorlagenspalte die benötigte Vorlagenbibliothek überprüfen. Nachdem Sie das Kontrollkästchen aktiviert und die Richtlinie gespeichert haben, verweist diese Richtlinie auf diese Vorlage. Hier erklären wir nur kurz die Verwendung der Vorlagenbibliothek. Diese Strategie hat bereits auf diese Vorlage verwiesen, sodass der Vorgang nicht wiederholt werden muss. Nachdem Sie diese Strategie im Strategy Square kopiert haben, können Sie sie in der Vorlagenspalte der Strategiebearbeitungsseite sehen.画线类库Bereits zitiert.
Wir lernen vor allem den Umgang mit画线类库Funktion zum Zeichnen des Diagramms.

Wir planenA->BDer Preisunterschied,B->ADie Preisdifferenz und die Preisdifferenz-Auslöselinie werden eingezeichnet. Sie müssen zwei Kurven (die aktuelle Preisdifferenz von A nach B und von B nach A) und zwei horizontale Linien (Auslöselinien der Preisdifferenz) zeichnen, wie in der Abbildung oben dargestellt.
Weil wir eine einseitige Absicherung entwerfen müssen,A->BUndB->ADie Auslöseleitung ist unterschiedlich. Das Design im vorherigen Artikel kann nicht verwendet werden.
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 einen Trigger-SpreadtargetDiffPrice。
Hier müssen wir also den Code ändern, zuerst die Parameter ändern.

Ändern Sie dann 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
}
Auf diese Weise ändert sich die Preisdifferenz-Triggerlinie von der vorherigentargetDiffPriceAus Eins wurden ZweitargetDiffPriceA2B、targetDiffPriceB2A。
Als Nächstes können Sie die Linienzeichnungsfunktion der Linienzeichnungsbibliothek verwenden, um diese Daten in das Diagramm zu zeichnen.
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
Wenn die Strategie ausgeführt wird, wird ein Diagramm wie dieses angezeigt.

Zeichnen Sie als Nächstes die Echtzeit-Spread-Kurve, um ein Überzeichnen zu vermeiden. Fügen Sie den Code zum Zeichnen von Kurven mit Echtzeit-Preisdifferenzdaten in die Saldenprüfung ein.
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) // 画实时差价曲线
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // 第一个参数是曲线名称,第二个参数是曲线当前时刻的值,即当前时刻Y轴方向上的值
}
Auf diese Weise kann die Strategie mit nur 4 Zeilen Zeichencode während der Ausführung ein Diagramm anzeigen.
Wie oben erwähnt, wurde die Preisdifferenz-Triggerlinie in zwei umgewandelt, die kontrollierenA->BDer Hedge-TriggerB->ADie Absicherung wird ausgelöst. Auf diese Weise kann der vorherige Orderpreisalgorithmus nicht verwendet werden, stattdessen wird die Methode Marktpreis plus Slippage verwendet.
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B 盘口条件满足
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("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // 提示信息
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 盘口条件满足
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("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) // 提示信息
hedge(exA, exB, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Da die Kauf- und Verkaufspreise in zwei Daten aufgeteilt werden, ist die Hedging-FunktionhedgeEs muss auch geändert werden.
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()
}
Aufgrund dieser Änderungen gibt es auch einige kleinere Anpassungen, auf die ich hier nicht näher eingehen werde. Einzelheiten können Sie im Code nachlesen.
Fügen Sie der Strategie Interaktivität hinzu, sodass die Strategie die Spread-Triggerlinie in Echtzeit ändern kann. Dies ist eine Designanforderung für eine halbautomatische Strategie, die hier auch als Lehrdemonstration umgesetzt wird. Das Design der Strategieinteraktion ist ebenfalls sehr einfach. Fügen Sie der Strategie zunächst auf der Strategiebearbeitungsseite interaktive Steuerelemente hinzu.

Es werden zwei Steuerelemente hinzugefügt, eines mit der Bezeichnung A2B und das andere mit der Bezeichnung B2A. Nachdem Sie einen Wert in das Steuereingabefeld eingegeben haben, klicken Sie auf die Schaltfläche auf der rechten Seite des Eingabefelds. Es wird sofort eine Anweisung an die Strategie gesendet, zum Beispiel: Geben Sie einen Wert in das Eingabefeld ein123aufA2BÜber diese Schaltfläche werden sofort Anweisungen an die Strategie gesendet.
A2B:123
Entwerfen Sie Code zur Interaktionserkennung und -verarbeitung im Strategiecode.
// 交互
var cmd = GetCommand() // 每次循环执行到这里时,都检测有没有交互指令过来,没有则返回空字符串
if (cmd) { // 检测到有交互指令,例如:A2B:123
Log("接收到命令:", cmd)
var arr = cmd.split(":") // 拆分出交互控件名称和输入框中的值,arr[0]就是A2B,arr[1]就是123
if (arr[0] == "A2B") { // 判断触发的交互控件是不是A2B
Log("修改A2B的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // 修改触发差价线
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // 修改触发差价线
}
} else if (arr[0] == "B2A") { // 检测到触发的控件是B2A
Log("修改B2A的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageA2B = parseFloat(arr[1])
} else {
hedgeDiffPriceB2A = parseFloat(arr[1])
}
}
}
Sorgen Sie für eine übersichtlichere Organisation der Statusleistendaten und für eine einfachere Anzeige.
var tbl = {
"type" : "table",
"title" : "数据",
"cols" : ["交易所", "币", "冻结币", "计价币", "冻结计价币", "触发差价", "当前差价"],
"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) + "`")

Backtesting ist nur ein Test der Strategie und eine vorläufige Erkennung von Funktionen. Viele Fehler können tatsächlich während der Backtesting-Phase ausgetestet werden. Den Backtest-Ergebnissen muss nicht allzu viel Aufmerksamkeit geschenkt werden. Die endgültige Strategie muss noch in einer realen Umgebung getestet werden.


Strategie-Quellcode: https://www.fmz.com/strategy/302834