Strategie zur Spot-Besicherung von Kryptowährung (1)

Schriftsteller:- Ich bin ein Idiot., Erstellt: 2022-04-14 11:57:46, aktualisiert: 2022-04-14 16:32:56

Strategie zur Spot-Besicherung von Kryptowährung (1)

Für Anfänger in der Strategieentwicklung ist die Hedge-Strategie sehr gut für die Praxis.

Designfunktionen und Parameter nach Strategieanforderung

Zunächst einmal müssen wir sicherstellen, dass die zu entwerfende Strategie eine Kryptowährungs-Spot-Hedging-Strategie ist. Wir entwerfen die einfachste Hedging-Strategie. Wir verkaufen nur auf der Plattform mit dem höheren Preis zwischen den beiden Spot-Plattformen und kaufen auf der Plattform mit dem niedrigeren Preis, um den Preis-Spread zu verdienen. Wenn die Plattform mit dem höheren Preis voller Quote-Währungs-Symbole ist (weil der Preis hoch ist, werden alle Währungs-Symbole verkauft), oder wenn die Plattform mit dem niedrigeren Preis voller Währungs-Symbole ist (weil der Preis niedrig ist, Währungs-Symbole werden von allen Vermögenswerten gekauft), kann sie nicht abgesichert werden. Zu diesem Zeitpunkt können Sie nur warten, bis der Preis umgekehrt ist, um zu sichern.

Für den Bestellpreis und die Menge während der Absicherung gibt es in jeder Plattform Präzisionsgrenzen, und es gibt auch eine Grenze für den Mindestbestellbetrag. Zusätzlich zum Mindestlimit muss die Strategie auch die maximale Bestellmenge für eine Absicherung berücksichtigen. Wenn die Bestellmenge zu groß ist, hat der Markt dafür kein ausreichendes Auftragsvolumen. Es ist auch notwendig, zu prüfen, wie der Wechselkurs umgerechnet wird, wenn die beiden Plattformen unterschiedliche Angebotskursen haben. Die Handlinggebühr während der Absicherung und der Rutsch des Auftragnehmers sind alle Handelskosten. Die Absicherung geschieht nicht immer, solange es einen Preisunterschied gibt. Daher hat die Absicherungspreisbreite auch einen Auslöserwert. Wenn sie niedriger ist als ein bestimmter Preisspreis, wird die Absicherung einen Verlust machen.

Auf dieser Grundlage muss die Strategie mit mehreren Parametern konzipiert werden:

  • Sicherungsspread:hedgeDiffPriceWenn der Spread den Wert übersteigt, wird eine Absicherung ausgelöst.
  • Mindestsicherungsbetrag:minHedgeAmount, der für eine Absicherung verfügbare Mindestauftragsbetrag (Symbolbetrag).
  • Höchstbetrag der Absicherung:maxHedgeAmount, der für eine Absicherung verfügbare maximale Auftragsbetrag (Symbolbetrag).
  • Preisgenauigkeit A:pricePrecisionA, die Präzision des Auftragspreises (Dezimalzahlen) der Plattform A.
  • Auftragsbetrag Präzision A:amountPrecisionA, die Auftragsbetragsgenauigkeit (Dezimalstellen) der Plattform A.
  • Preisgenauigkeit B:pricePrecisionB, die Präzision des Auftragspreises (Dezimalzahlen) der Plattform B.
  • Auftragsbetrag Genauigkeit B:amountPrecisionB, die Auftragsbetragsgenauigkeit (Dezimalzahlen) der Plattform B.
  • Wechselkurs A:rateA, der Wechselkurs der Umrechnung des ersten hinzugefügten Tauschgegenstands; Standardwert 1 bedeutet, dass keine Umrechnung erfolgt.
  • Wechselkurs B:rateB, der Umrechnungskurs des zweiten hinzugefügten Tauschgegenstandes; Standardwert 1 bedeutet, dass keine Umrechnung erfolgt.

Die Absicherungsstrategie muss den Währungssymbolbetrag der beiden Konten unverändert halten (d. h. keine Richtpositionen halten und neutral bleiben), so dass eine Balance-Logik in der Strategie vorhanden sein muss, um immer das Gleichgewicht zu erkennen.

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

Nach der Auftragserteilung, wenn es keinen ausgeführten Auftrag gibt, müssen wir ihn rechtzeitig stornieren, und der Auftrag kann nicht in Erwartung gehalten werden.

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

Wenn wir die Menge der Währungssymbole ausgleichen, müssen wir den Preis mit einer bestimmten Menge in einer bestimmten Tiefe Daten finden, also brauchen wir eine Funktion wie diese, um es zu handhaben.

  • 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 spezifische Absicherungsorder-Operation entwerfen und schreiben, die entworfen werden muss, um gleichzeitig Aufträge zu platzieren:

  • 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()
    }
    

Abschließend wollen wir das Design der Balance-Funktion, die etwas komplizierter ist, abschließen.

  • 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
        // calculate currency spread 
        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("cannot balance")            
            } else {
                // balanced ordering 
                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("invalid price", price)
                }
            }        
            return false
        } else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
            Log("error:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

Diese Funktionen wurden nach den Anforderungen der Strategie konzipiert, und wir können mit der Konzeption der Hauptfunktion der Strategie beginnen.

Strategie Hauptfunktion Design

Auf FMZ wird die Strategie von dermainIn den letzten Jahren hat sich die Zahl dermainFunktion, müssen wir einige Initialisierung der Strategie zu tun.

  • Name des Exchange-Objekts Für viele Operationen in der Strategie verwenden Austauschobjekte, wie zum Beispiel das Erhalten von Marktnoten, Platzieren von Aufträgen, und so weiter, so wäre es unbequem, einen längeren Namen jedes Mal zu verwenden, mein kleiner Trick ist, einen einfachen kurzen Namen stattdessen zu verwenden, zum Beispiel:

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

    Dann wird es bequemer sein, den Code später zu schreiben.

  • Wechselkurs und Präzision

      // settings of precision and exchange rate
      if (rateA != 1) {
          // set exchange rate A 
          exA.SetRate(rateA)
          Log("Platform A sets exchange rate:", rateA, "#FF0000")
      }
      if (rateB != 1) {
          // set exchange rate B
          exB.SetRate(rateB)
          Log("Platform B sets exchange rate:", rateB, "#FF0000")
      }
      exA.SetPrecision(pricePrecisionA, amountPrecisionA)
      exB.SetPrecision(pricePrecisionB, amountPrecisionB)
    

    Wenn einer der Wechselkursparameter, nämlichrateAundrateB, wird auf 1 gesetzt (Standard ist 1), d. h.rateA != 1oderrateB != 1Der Wechselkurs kann nicht umgerechnet werden.

  • Alle Daten zurücksetzen

    img

    Manchmal ist es notwendig, alle Protokolle zu löschen und die Datensätze zu säubern, wenn die Strategie gestartet wird.isReset, und dann den Reset-Code im Initialisierungsteil der Strategie entwerfen, zum Beispiel:

      if (isReset) {   // when "isReset" is true, reset the data 
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("Reset all data", "#FF0000")
      }
    
  • Wiederherstellen der ursprünglichen Kontodaten und Aktualisieren der aktuellen Kontodaten Um den Saldo zu beurteilen, muss die Strategie die Ausgangszustand des Kontovermögens kontinuierlich für den Vergleich mit dem aktuellen Konto erfassen.nowAccsDie Daten für das Leistungsbilanzkonto werden mit demupdateAccsFunktion, die wir gerade entwickelt haben, um die Konto-Daten der aktuellen Plattform zu erhalten.initAccswird verwendet, um den ursprünglichen Kontozustand zu erfassen (Daten wie Währungssymbolbetrag sowohl für A als auch für B, Kurswährungssatz usw.).initAccs, verwenden Sie zunächst die_G()Funktion zur Wiederherstellung (die _G-Funktion wird Daten dauerhaft aufzeichnen und kann die aufgezeichneten Daten erneut zurückgeben; lesen Sie die API-Dokumentation für Details:Verbindung).
    Wenn Sie die Daten nicht abfragen können, verwenden Sie die Leistungskontoinformationen zuzuweisen und zu verwenden_G()Funktion zum Aufzeichnen.

    Der folgende Code:

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

Handelslogik, Hauptschleife in Hauptfunktion

Der Code in der Hauptschleife ist der Prozess jeder Runde der Strategie-Logik-Ausführung, und die non-stop wiederholende Ausführung konstruiert die Strategie-Hauptschleife.

  • Erhalten Sie die Marktzitate und beurteilen Sie die Gültigkeit

          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 können Sie sehen, dass die gleichzeitige Funktionexchange.Goder FMZ-Plattform verwendet wird, um gleichzeitige Objekte zu erstellendepthARoutineunddepthBRoutineDas nennen dieGetDepth()Wenn diese beiden gleichzeitigen Objekte erstellt werden,GetDepth()Die Anforderung der Tiefendaten wird sofort an die Plattform gesendet. Dann rufen Sie diewait()Methode des ObjektsdepthARoutineund ObjektdepthBRoutineUm die Tiefendaten zu erhalten. Nach Erhalt der Tiefendaten ist es notwendig, die Tiefendaten zu überprüfen, um deren Gültigkeit zu beurteilen.continueDie Anweisung wird ausgelöst, um die Hauptschleife erneut auszuführen.

  • Verwendungprice spreadoderspread ratio?

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

    Die Parameter von FMZ könnenSchauoderversteckenbasierend auf einem Parameter, so können wir einen Parameter zu entscheiden, ob zu verwendenprice spread, oderspread ratio.

    img

    Der ParameterdiffAsPercentageDie beiden anderen Parameter, die je nach Parameter angezeigt oder ausgeblendet werden, werden so eingestellt:hedgeDiffPrice@!diffAsPercentage; wenndiffAsPercentageist falsch, wird gezeigt.hedgeDiffPercentage@diffAsPercentage; wenndiffAsPercentageist wahr, wird es angezeigt.
    Nach dem Entwurf haben wir diediffAsPercentageDie Risikopositionsquote ist eine Parameterfunktion, bei der die Spread-Ratio als Auslöserbedingungen für die Absicherung verwendet wird.diffAsPercentageDer Parameter wird nicht geprüft, wird der Kursspread als Triggerbedingung für die Absicherung verwendet.

  • Richter Hedge Trigger

          if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B market condition satisfied             
              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("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // prompt message 
                  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 market condition satisfied 
              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("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // prompt message
                  hedge(exA, exB, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          }
    

    Es gibt mehrere Auslösebedingungen für die Absicherung: 1.Zunächst ist die Absicherungsspanne zu erfüllen; die Absicherung ist nur möglich, wenn die Marktspannen den festgelegten Parameter der Absicherungsspanne erfüllen.

    2.Der Sicherungsbetrag des Marktes sollte dem in den Parametern festgelegten Mindestsicherungsbetrag entsprechen.Da der Mindestauftragssatz verschiedener Plattformen unterschiedlich ist, sollte der kleinste der beiden platziert werden.

    3.Die Vermögenswerte in der Plattform mit der Verkaufsoperation sind ausreichend zum Verkaufen und die Vermögenswerte in der Plattform mit der Kaufoperation sind ausreichend zum Kaufen.Wenn diese Bedingungen erfüllt sind, wird die Absicherungsfunktion ausgeführt, um Aufträge nach Absicherung zu platzieren.isTradeHier, wenn die Absicherung ausgelöst wird, wird die Variable auftrue. Und die globale Variable zurücksetzenlastKeepBalanceTSDie Ausgabe von LastKeepBalanceTS wird verwendet, um den Zeitstempel der letzten Balance-Operation zu kennzeichnen, und wenn sie auf 0 gesetzt wird, wird die Balance-Operation sofort ausgelöst.

  • Ausgleichsbetrieb

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

    Es ist zu sehen, daß die Balancefunktion periodisch ausgeführt wird, aber wenn dielastKeepBalanceTSWenn der Wert der Risikoposition nach Auslösung der Absicherungsoperation auf 0 zurückgesetzt wird, wird die Saldooperation sofort ausgelöst.

  • Informationen aus der Statusleiste

          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", 
              "currentA,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "currentB,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "initialA,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "initialB,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
    

    Die Statusleiste ist nicht besonders kompliziert konzipiert. Sie zeigt die aktuelle Uhrzeit, den Preis-Spread von Plattform A auf Plattform B sowie den Preis-Spread von Plattform B auf Plattform A an; sie zeigt auch den aktuellen Hedge-Ziel-Spread, die Kontoanlagendaten von Plattform A und die Kontoanlagendaten von Plattform B an.

Handelspaarverarbeitung für verschiedene Kurswährungen

In bezug auf die Parameter haben wir den Parameter der Umrechnung des Wechselkurswerts entworfen, und wir haben auch die Umrechnung des Wechselkurses immainDie Strategie wird von der Kommission und den Mitgliedstaaten in Zusammenarbeit mit den Mitgliedstaaten durchgeführt.SetRateDie Wechselkursumrechnung muss zuerst ausgeführt werden.

Für die Funktion werden zwei Aspekte betroffen sein:

  • Preisumrechnung in allen Marktnoten, Auftragsdaten und Positionsdaten.
  • Umrechnung der Kurswährungen in Kontovermögen.

Zum Beispiel ist das aktuelle HandelspaarBTC_USDT, ist die PreiseinheitUSDT, und die verfügbare Kurswährung in den Kontovermögen ist ebenfallsUSDT. Wenn ich den Wert der Vermögenswerte in CNY umwandeln möchte, setzenexchange.SetRate(6.8)in dem Code, um die Daten zu konvertieren, die von allen Funktionen im Rahmen derexchangeGegenstand und dann in CNY umgerechnet. Um zu welcher Währung zu konvertieren, importierender Wechselkurs von der aktuellen Kurswährung zur Zielkurswährungin dieSetRate function.

Vollständige Strategie:Strategie zur Spot-Besicherung verschiedener Notenwährungen (Teaching)


Mehr