仮想通貨のスポットヘッジ戦略の設計 (1)

作者: リン・ハーンリディア, 作成日:2022-08-16 10:30:56, 更新日:2023-09-19 21:46:16

img

仮想通貨のスポットヘッジ戦略の設計 (1)

ヘージング戦略は,戦略設計の初心者にとって非常に良い実践戦略です.この記事は,初心者が設計経験を学ぶことを期待して,シンプルで実用的な仮想通貨スポットヘージング戦略を実装しています.

戦略の要件に従っていくつかの機能と戦略インターフェースのパラメータを設計

まず最初に,設計される戦略は仮想通貨スポットヘッジ戦略であることは明らかである.我々は最も単純なヘッジ戦略を設計する.我々は2つのスポット取引所間の間でのみ,より高い価格で取引所で販売し,低価格で取引所で購入して違いを取ります.より高い価格を持つ取引所はすべて指名されたコイン (より高い価格を持つコインが販売されるため),低価格を持つ取引所はすべてコイン (より低い価格を持つコインが購入されるため) であるとき,それはヘッジすることはできません.この時点で,我々は価格逆転をヘッジするために待つしかできません.

ヘージングでは,注文の価格と量が取引所によって制限され,最低注文量にも制限があります.最低制限に加えて,ヘージングの戦略は同時に最大注文量も考慮する必要があります.注文量が大きすぎると,十分な注文量はありません.また,2つの交換通貨が異なる場合,為替レートを変換する方法も考慮する必要があります.ヘージングでは,注文受取者の処理手数料とスリップはすべての取引コストであり,価格の差がある限りヘージングができません.したがって,ヘージング価格の差はまたトリガー値を持っています.特定の価格の差を下回る場合は,ヘージングは損します.

これらの考慮に基づいて,戦略はいくつかのパラメータを考慮して設計する必要があります.

  • ヘッジ差:hedgeDiffPrice差がこの値を超えると,ヘッジ操作が開始されます.
  • 最低保証金額:minHedgeAmount, 負債をカバーできる最小のオーダー金額 (コイン).
  • 保証金最大額:maxHedgeAmount, 1 つのヘージングの最大オーダー金額 (コイン)
  • Aの価格精度:pricePrecisionA, 取引所Aが設定した注文価格精度 (小数点数)
  • A の量精度:amountPrecisionA, 取引所Aが発した注文の金額精度 (小数点数)
  • Bの価格精度:pricePrecisionB, 取引所Bが設定した注文価格精度 (小数点数)
  • B の量精度:amountPrecisionB, 取引所Bが発行した注文の金額精度 (小数点数)
  • 換算率A:rateA,最初の追加された交換対象の為替レートの変換,デフォルトは1で,変換されていません.
  • 換算率B:rateB, 換算されていない第2の追加された換算対象の換算率変換,デフォルトは1です.

ヘッジ戦略は,両口座のコインの数を変化しないようにする必要がある (つまり,いかなる方向にもポジションを保持せず,中立性を維持する),したがって,バランスを常に検出するために戦略にバランス論理が必要です.バランスを確認する際に,両取引所からの資産データを入手することは避けられません.使用する関数を書く必要があります.

  • アップデートAccs
    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 
    }
    

オーダーが完了していない場合,オーダーを間に合ってキャンセルし,オーダーを待機状態に保つことはできません.この操作はバランスモジュールとヘジングロジックの両方で処理する必要があります.したがって,オーダーフル引き出機能も設計する必要があります.

  • キャンセル すべて
    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)
                }
            }
        })
    }
    

特定の値のコインに蓄積された価格を 特定の深さのデータで求めます そのためにはこのような関数が必要です

  • getDepthPrice について
    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
    }
    

特定のヘージングオーダー操作を設計し,書き込む必要があります.

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

微妙なバランス関数の設計を完成させましょう.

  • keep バランス
    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 the currency difference
        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("unable to balance")            
            } else {
                // balance order
                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("errors:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

戦略の要件に従ってこれらの機能を設計した後,戦略の主要な機能を設計し始める.

戦略の主な機能設計

FMZプラットフォームでは,戦略はmain機能.main戦略の初期化作業を行う必要があります.

  • 交換オブジェクト名 戦略内の多くの操作は,市場コートを取得し,オーダーを出すなど,交換オブジェクトを使用しなければならないため,常に長い名前を使用することは面倒になります.

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

    後にコードを書くのが簡単になります

  • 通貨レート,精密度に関する設計

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

    通貨レートのパラメータがrateA, rateB1 に設定されます (デフォルトは1) つまりrateA != 1またはrateB != 1引き起こすので,為替レートの変換は設定されません.

  • すべてのデータをリセットする

    img

    ストラテジーのインターフェースパラメータを設計することができます. ストラテジーのインターフェースは,すべてのログを削除し,ストラテジーのインターフェースを削除します.isReset戦略の初期化部分にリセットコードを設計します 例えば:

      if (isReset) {   // When isReset is true, reset the data
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("reset all data", "#FF0000")
      }
    
  • 初期口座データを復元し,現在口座データを更新する 戦略は,残高を判断するために,初期口座資産を継続的に記録し,現在の資産と比較する必要があります.nowAccsこの関数は,現在,現在,現在,現在,現在,今,今,今updateAccs現在の取引所の口座データを取得しますinitAccs取引所AとBで最初の口座状態 (コインの数,通貨名で表されたコインの数など) を記録するために使用されます.initAccs薬剤を_G()_G関数はデータを継続的に記録し,記録されたデータを再び返却することができます.詳細についてはAPIドキュメントを参照してください: [リンク]www.fmz.com/api#_gk-v) で,クエリがうまくいかない場合は,現在口座情報を使用して値を割り当て,_G記録する機能です

    例えば,次のコード:

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

トレーディング・ロジック,メイン・ループ・イン・メイン・機能

メインループのコードは,戦略ロジックの各実行ラウンドのプロセスであり,戦略のメインループを形成するために繰り返し実行されます. メインループのプログラムの各実行のプロセスを見てみましょう.

  • 市場データを取得し,市場データの有効性を判断する

          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 
          }
    

    この関数は,この関数とexchange.GoFMZプラットフォームの同時オブジェクトを作成するために使用されますdepthARoutine, depthBRoutineその呼び出しGetDepth()この2つの同時オブジェクトが作成されると,GetDepth()両方の深度データの要求が交換に送られます じゃあ電話してwait()方法depthARoutine, depthBRoutine深度データを取得するための物体です
    値の深さデータを取得した後,その有効性を確認する必要があります.異常データの場合,continue主ループを再実行するために命令が起動します.

  • 試しにspread valueパラメータまたはspread 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
          }
    

    FMZのパラメータはショーまたは隠れるパラメータを使用するかどうかを決定するパラメータを作ることができます.price spread,またはspread ratio.

    img

    パラメータdiffAsPercentageこのパラメータに基づいて表示または隠す他の2つのパラメータ設定は:hedgeDiffPrice@!diffAsPercentage, が表示される場合diffAsPercentage偽りですhedgeDiffPercentage@diffAsPercentage, が表示される場合diffAsPercentageそれは本当だ このデザインの後,我々はdiffAsPercentage価格差比をベースにしたヘッジトリガー条件である.diffAsPercentageパラメータがチェックされたら,価格差によってヘッジが起動します.

  • 負債の負債の負債の負債の負債の負債

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

    負債の負債の負債の負債の負債の負債の負債の負債

    1. オーダーのスプレッドが設定されたスプレッドパラメータを満たすときのみ,そのスプレッドをカバーできる.
    2. 市場でヘッジできる金額は,パラメータに設定された最低ヘッジ金額を満たさなければならない.異なる取引所によって制限される最小オーダーの金額が異なるため,両者のうち最小値を取るべきである.
    3. 売却取引の交換中の資産は売却に十分で,購入取引の交換中の資産は購入に十分です. 主な関数の前に,変数を宣言します. この式は,次の式を表示します.isTrade初期設定で,ヘッジが発生するかどうかを表示します.ここで,ヘッジが起動した場合,変数はtrueグローバル変数をリセットします.lastKeepBalanceTS0 (lastKeepBalanceTSは最後のバランス操作のタイムスタンプをマークするために使用され,0に設定するとすぐにバランス操作が開始されます),そしてすべての待機中の注文をキャンセルします.
  • バランス操作

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

    均衡機能が定期的に実行されるが,lastKeepBalanceTS負債の負債の負債の負債は,負債の負債の負債が負債の負債の負債である.

  • ステータスバー情報

          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", 
              "current A, Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "current B, Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "initial A, Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "initial B, Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
    

    ステータスバーは特に複雑なデザインではありません. 現在の時間,取引所Aから取引所Bへの価格差,取引所Bから取引所Aへの価格差を表示します. また,現在のヘッジターゲット・スプレッド,取引所Aの資産データ,取引所Bの口座を表示します.

異なる通貨に表された取引対の取引

換算率の値パラメータを設計し,また,最初の操作の為替レートの変換も設計しました.main戦略の開始時に機能する.SetRate通貨レートの変換機能が最初に実行される必要があります. この機能は2つの側面に影響を与えるからです

  • すべての市場データ,オーダーデータ,ポジションデータにおける価格変換
  • 口座資産の通貨の換算 例えば,現在の取引対はBTC_USDT価格単位はUSDT口座の資産に含まれる通貨は,USDTCNYに変換したい場合は,セットexchange.SetRate(6.8)すべての関数で取得されたデータを変換するコードexchangeCNY に換算する. 通貨に換算するには,現貨から目標通貨への為替レートについてSetRate function.

完全な戦略:異なる通貨のスポットヘージング戦略 (チュートリアル)


関連性

もっと