Die Ressourcen sind geladen. Beförderung...

Design einer Strategie zur Sicherung von Kryptowährungen (1)

Schriftsteller:Die Erfinder quantifizieren - Kleine Träume, Erstellt: 2021-07-19 17:38:24, Aktualisiert: 2023-09-20 10:35:16

img

Design einer Strategie zur Sicherung von Kryptowährungen (1)

Für Anfänger, die Strategien entwerfen, ist eine Hedging-Strategie eine sehr gute Praktikerstrategie. Dieser Beitrag umfasst eine einfache, aber praktische digitale Währungs-Hardware-Hedging-Strategie, die es den Anfängern erlaubt, etwas Design-Erfahrung zu sammeln.

Konzipieren von Funktionen, Strategie-Interface-Parameter nach den Bedürfnissen der Strategie

Zunächst einmal sollte klargestellt werden, dass die bevorstehende Strategie eine digitale Währung ist. Wir haben die einfachste Absicherung entworfen, bei der nur die Preiserhöhungen zwischen den beiden Börsen verkauft und die Preiserhöhungen bei den niedrigeren Börsen gekauft werden.

Bei der Abwicklung von Aufträgen gibt es Präzisionsbeschränkungen für den Preis, die Menge und die Börse. Es gibt auch Mindest-Einheitsbeschränkungen. Zusätzlich zu Mindest-Einheitsbeschränkungen berücksichtigt die Strategie bei der Abwicklung auch die maximale Aufträgsgröße einer Abwicklung, wenn die Abwicklung zu groß ist. Es muss auch berücksichtigt werden, wie der Wechselkurs umgewandelt wird, wenn die beiden Währungen unterschiedlich sind.

Aufgrund dieser Überlegungen muss die Strategie einige Parameter gestalten:

  • Die Absicherungskosten:hedgeDiffPrice, wenn die Differenz diesen Wert überschreitet, wird eine Hedging-Operation ausgelöst.
  • Mindeste Absicherung:minHedgeAmountDas Mindestbetrag, das abgesichert werden kann, ist die Anzahl der Münzen.
  • Maximale Absicherung:maxHedgeAmountDie höchste Einheitsmenge für eine Hedging-Aktie (Koinzahl) ist:
  • A: Preisschärfe:pricePrecisionADie Preispräzision der Börse A (kleine Ziffern)
  • A: Die Präzision der einzelnen Mengen:amountPrecisionA, A ist die niedrigste Einheitspräzision (kleine Ziffern) der Börse.
  • B-Preispräzision:pricePrecisionB,B-Börse, Preissteigerung (kleine Ziffern)
  • B: Die Präzision der einzelnen Mengen:amountPrecisionBDie B-Börse hat eine niedrigere Einheitspräzision (kleine Ziffern) als die B-Börse.
  • Der Wechselkurs der A-Börse:rateA, der Wechselkurs des ersten hinzugefügten Austauschobjekts wird umgewandelt, 1 wird nicht umgewandelt.
  • Der Wechselkurs der Börse B:rateB, die Währungskonversion des zweiten hinzugefügten Austauschobjekts, die standardmäßig 1 nicht konvertiert wird.

Die Hedging-Strategie erfordert, dass die Anzahl der Münzen in den beiden Konten stets unverändert bleibt (d. h. keine Richtungsposition hält, neutral bleibt), so dass eine Balance-Logik in der Strategie erforderlich ist.

  • Aktualisierung
    function updateAccs(arrEx) {
        var ret = []
        for (var i = 0 ; i < arrEx.length ; i++) {
            var acc = arrEx[i].GetAccount()
            if (!acc) {
                return null
            }
            ret.push(acc)
        }
        return ret 
    }
    

Wenn nach dem Auftrag keine Transaktionen stattfinden, müssen wir die Bestellung rechtzeitig widerrufen und können die Bestellung nicht hängen lassen. Diese Operation muss sowohl im Ausgleichsmodul als auch in der Hedging-Logik bearbeitet werden, so dass eine vollständige Widerrufsfunktion für die Bestellung entworfen werden muss.

  • Absagen
    function cancelAll() {
        _.each(exchanges, function(ex) {
            while (true) {
                var orders = _C(ex.GetOrders)
                if (orders.length == 0) {
                    break
                }
                for (var i = 0 ; i < orders.length ; i++) {
                    ex.CancelOrder(orders[i].Id, orders[i])
                    Sleep(500)
                }
            }
        })
    }
    

Bei der Ausgleichszahl müssen wir in einer gewissen Tiefe der Daten die Preise finden, die bis zu einer bestimmten Anzahl von Münzen kumulieren, also benötigen wir eine Funktion wie diese, um sie zu bearbeiten.

  • GetDepthPrice ist ein
    function getDepthPrice(depth, side, amount) {
        var arr = depth[side]
        var sum = 0
        var price = null
        for (var i = 0 ; i < arr.length ; i++) {
            var ele = arr[i]
            sum += ele.Amount
            if (sum >= amount) {
                price = ele.Price
                break
            }
        }
        return price
    }
    

Dann müssen wir die spezifischen Abwicklungsvorgänge für die Sicherung entwerfen und schreiben, und wir müssen sie als gleichzeitige Abwicklungen entwerfen:

  • Hecke
    function hedge(buyEx, sellEx, price, amount) {
        var buyRoutine = buyEx.Go("Buy", price, amount)
        var sellRoutine = sellEx.Go("Sell", price, amount)
        Sleep(500)
        buyRoutine.wait()
        sellRoutine.wait()
    }
    

Schließlich haben wir die Gestaltung der Balance-Funktion abgeschlossen, die ein wenig komplex ist.

  • die Balance halten
    function keepBalance(initAccs, nowAccs, depths) {
        var initSumStocks = 0
        var nowSumStocks = 0 
        _.each(initAccs, function(acc) {
            initSumStocks += acc.Stocks + acc.FrozenStocks
        })
        _.each(nowAccs, function(acc) {
            nowSumStocks += acc.Stocks + acc.FrozenStocks
        })
      
        var diff = nowSumStocks - initSumStocks
        // 计算币差
        if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
            var index = -1
            var available = []
            var side = diff > 0 ? "Bids" : "Asks"
            for (var i = 0 ; i < nowAccs.length ; i++) {
                var price = getDepthPrice(depths[i], side, Math.abs(diff))
                if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
                    available.push(i)
                } else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
                    available.push(i)
                }
            }
            for (var i = 0 ; i < available.length ; i++) {
                if (index == -1) {
                    index = available[i]
                } else {
                    var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
                    var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
                    if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
                        index = available[i]
                    } else if (priceIndex && priceI && priceI < priceIndex) {
                        index = available[i]
                    }
                }
            }
            if (index == -1) {
                Log("无法平衡")            
            } else {
                // 平衡下单
                var price = getDepthPrice(depths[index], side, Math.abs(diff))
                if (price) {
                    var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
                    tradeFunc(price, Math.abs(diff))
                } else {
                    Log("价格无效", price)
                }
            }        
            return false
        } else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
            Log("错误:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

Diese Funktionen wurden nach den Bedürfnissen der Strategie gestaltet. Hier können Sie mit der Gestaltung der Hauptfunktionen beginnen.

Strategie-Hauptfunktionsdesign

Die Strategie auf FMZ ist:mainDie Funktion wird ausgeführt.mainWir haben einige Strategien, die wir an den Anfang der Funktion anfangen müssen.

  • Name der Börse Da viele Aktionen in der Strategie auf Börsenobjekte ausgerichtet sind, wie zum Beispiel Akquisition, Bestellung usw. Kann es problematisch sein, jedes Mal einen langen Namen zu verwenden. Ein kleiner Trick ist es, einen einfachen Namen zu verwenden.

    var exA = exchanges[0]
    var exB = exchanges[1]
    

    Das ist ein einfacher Weg, um später Code zu schreiben.

  • Wechselkurs, Präzisionsdesign

      // 精度,汇率设置
      if (rateA != 1) {
          // 设置汇率A
          exA.SetRate(rateA)
          Log("交易所A设置汇率:", rateA, "#FF0000")
      }
      if (rateB != 1) {
          // 设置汇率B
          exB.SetRate(rateB)
          Log("交易所B设置汇率:", rateB, "#FF0000")
      }
      exA.SetPrecision(pricePrecisionA, amountPrecisionA)
      exB.SetPrecision(pricePrecisionB, amountPrecisionB)
    

    Wenn die WechselkursparameterrateArateBEs gibt eine Einstellung von 1 (default ist 1), alsorateA != 1oderrateB != 1Der Wechselkurs wird nicht aktiviert, sodass keine Wechselkursumstellung eingerichtet wird.

  • Alle Daten zurücksetzen

    img

    Manchmal müssen alle Logs, Daten, die in den Registrierungsblättern liegen, gelöscht werden, wenn eine Politik gestartet wird.isReset, und dann den initialierten Teil der Konstruktions-Rückstellungscode in der Strategie, z. B.:

      if (isReset) {   // 当isReset为真时重置数据
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("重置所有数据", "#FF0000")
      }
    
  • Wiederherstellung der ursprünglichen Konto-Daten, Aktualisierung der aktuellen Konto-Daten Die Strategie erfordert eine kontinuierliche Erfassung der ursprünglichen Kontovermögen gegenüber der gegenwärtigen Vermögenslage, um den Ausgleich zu bestimmen.nowAccsDiese Variable wird verwendet, um die Daten des aktuellen Kontos zu speichern, mit der Funktion, die wir gerade entwickelt haben.updateAccsSie erhalten die Kontoinformationen der aktuellen Börse.initAccsFür die Erfassung des ursprünglichen Kontozustands (Daten wie Anzahl der Münzen an Börsen A und B, Anzahl der Preise)initAccsErstmal benutzt_G()Funktion Wiederherstellung ((_G Funktion wird dauerhaft aufgezeichnet und kann die aufgezeichneten Daten wiederherstellen, siehe API-Dokumentation:LinksWenn Sie keine Anfrage erhalten, verwenden Sie Ihre aktuellen Account-Informationen._GFunktionsprotokolle.

    Die folgenden Codes sind zum Beispiel:

      var nowAccs = _C(updateAccs, exchanges)
      var initAccs = _G("initAccs")
      if (!initAccs) {
          initAccs = nowAccs
          _G("initAccs", initAccs)
      }
    

Transaktionslogik, Hauptschleife in Hauptfunktionen

Der Code in der Hauptschleife ist der Prozess, der von der Strategie-Logik pro Runde ausgeführt wird, und die ständige Wiederholung der Ausführung bildet den Hauptschleife.

  • Erhalten Sie Marktdaten, um zu beurteilen, wie effektiv sie sind

          var ts = new Date().getTime()
          var depthARoutine = exA.Go("GetDepth")
          var depthBRoutine = exB.Go("GetDepth")
          var depthA = depthARoutine.wait()
          var depthB = depthBRoutine.wait()
          if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
              Sleep(500)
              continue 
          }
    

    Hier sehen Sie die Parallelfunktionen, die mit der FMZ-Plattform verwendet werden.exchange.GoSie haben einen Anruf erstellt.GetDepth()Gleichzeitige Objekte der SchnittstelledepthARoutinedepthBRoutine│ Bei der Erstellung dieser beiden gleichzeitigen Objekte wird einGetDepth()Die Schnittstelle wurde sofort eingerichtet, als beide Anfragen für die Vertiefungsdaten an die Börse weitergeleitet wurden. Dann rufen Sie an.depthARoutinedepthBRoutineGegenstandwait()Die Methode zur Gewinnung von Daten in der Tiefe.
    Nach dem Erhalt der Tiefendaten müssen die Tiefendaten überprüft werden, um ihre Wirksamkeit zu beurteilen.continueDie Sätze führen den Hauptkreislauf wieder aus.

  • Nutzung价差值Die Parameter?差价比例Die Parameter?

          var targetDiffPrice = hedgeDiffPrice
          if (diffAsPercentage) {
              targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
          }
    

    Wir haben die Parameter so gestaltet. FMZ-Parameter können auf Parametern basieren.angezeigtOderVerstecktAlso können wir eine Parameter machen, um zu entscheiden, ob wir sie verwenden.价格差Oder差价比例

    img

    Ein Parameter wurde in die Strategie-Interface-Parameter hinzugefügtdiffAsPercentageDie beiden anderen Optionen, die auf dieser Parameterbasis angezeigt oder versteckt werden, sind:hedgeDiffPrice@!diffAsPercentageWenndiffAsPercentageFür die falsche Anzeige dieses Parameters.hedgeDiffPercentage@diffAsPercentageWenndiffAsPercentageDie Parameter werden dann als wahr angezeigt. Wir haben uns mit dem Design beschäftigt und haben uns für das Projekt entschieden.diffAsPercentageParameter, die als Auslöser für die Absicherung im Verhältnis zu den Differenzpreisen dienen.diffAsPercentageDie Parameter werden von der Preisdifferenz als Auslöser für die Absicherung verwendet.

  • Begründung für die Auslösung von Hedges

          if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B 盘口条件满足            
              var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
              var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
              if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
                  amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
                  Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // 提示信息
                  hedge(exB, exA, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          } else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) {   // B -> A 盘口条件满足
              var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
              var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
              if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
                  amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
                  Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // 提示信息
                  hedge(exA, exB, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          }
    

    Es gibt verschiedene Auslöser für Hedging: 1. Das Hedging-Differenz-Parameter wird erst einmal erfüllt und nur dann abgesichert, wenn das Differenz-Differenz-Parameter des Aufschlags erfüllt wird. 2. Die in den Parametern festgelegte Mindest-Hedging-Menge muss von den unterschiedlichen Börsen mit unterschiedlichen Mindest-Hedging-Mengen abgedeckt werden. 3. Die Vermögenswerte an der Börse, an der die Operationen verkauft wurden, sind ausreichend, um sie zu verkaufen, und die Vermögenswerte an der Börse, an der die Operationen gekauft wurden, sind ausreichend, um sie zu kaufen. Wenn diese Bedingungen erfüllt sind, wird die Hedge-Funktion ausgeführt. Vor der Hauptfunktion erklären wir eine Variable.isTradeHier wird die Variable als "Wenn ein Hedge ausgelöst wird" gesetzt.trueUnd die globalen Variablen zurücksetzen.lastKeepBalanceTSAls 0 (lastKeepBalanceTS wird verwendet, um den Timestamp der letzten Balance-Operation zu markieren, die auf 0 gesetzt wird, um die Balance-Operation sofort auszulösen) und dann alle Anhängsel zu löschen.

  • Ausgleichsoperationen

          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 
                  }                
              }            
          }
    

    Sie können sehen, dass die Balance-Funktion regelmäßig ausgeführt wird, aber wenn die Hedge-Operation nach dem Auslösen ausgelöst wird, dann wird die Balance-Funktion nach dem Auslösen ausgelöst.lastKeepBalanceTSDie Balance-Operation wird sofort ausgelöst, wenn sie auf 0 gesetzt wird.

  • Status-Tablets

          LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n", 
              "当前A,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "当前B,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "初始A,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "初始B,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
    

    Die Statusbar ist nicht besonders kompliziert gestaltet und zeigt die aktuelle Zeit an, zeigt die Differenz von A zu B und von B zu A. Sie zeigt die aktuelle Differenz des Hedging-Ziels. Sie zeigt die Anlagendaten von A, die Anlagendaten von B.

Abwicklung von Paaren mit unterschiedlichen Währungen

In den Parametern haben wir die Parameter für die Umwandlung von Wechselkurswerten entwickelt.mainWir haben auch den Wechselkurs umgewandelt.SetRateDie Wechselkurskonvertierungsfunktion muss zuerst ausgeführt werden. Die Funktion wird auf zwei Ebenen eingesetzt:

  • Die Preise werden in allen Marktdaten, Bestelldaten und Lagerdaten ausgetauscht.
  • Die Zahlung der Währung in den Konto-Vermögenswerten. Zum Beispiel ist das aktuelle HandelspaarBTC_USDTDie Preise sind:USDTDas ist eine sehr schwierige Aufgabe.USDTWenn ich einen Wert in CNY umwandeln möchte, dann kann ich das in meinem Code festlegen.exchange.SetRate(6.8)Wir haben es.exchangeAlle Funktionsdaten, die unter diesem Austauschobjekt erfasst wurden, wurden in CNY umgerechnet. Ich habe die Münze für den Preis bezahlt.SetRateFunktionsübertragungWechselkurs der aktuellen Währung gegenüber der Zielwährung

Die volle Strategie:Die Strategie zur Hedging von verschiedenen Währungen


Verwandt

Mehr

Die Squirrels sind großzügig.Sehr gut.