クリプト通貨のスポットヘッジ戦略 (1)

作者: リン・ハーンニナバダス, 作成日:2022-04-14 11:57:46, 更新日:2022-04-14 16:32:56

クリプト通貨のスポットヘッジ戦略 (1)

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

戦略要件による設計機能とパラメータ

まず,設計する戦略が仮想通貨スポットヘッジ戦略であることを確認する必要があります.最もシンプルなヘッジを設計します.私たちは2つのスポットプラットフォーム間の高い価格を持つプラットフォームでのみ販売し,価格のスプレッドを得るために低い価格を持つプラットフォームで購入します.高い価格を持つプラットフォームが引換通貨シンボルで満たされたとき (価格が高いので,すべての通貨シンボルが販売されます),または低い価格を持つプラットフォームが通貨シンボルで満たされたとき (価格が低いので,通貨シンボルはすべての資産によって購入されます),ヘッジすることはできません.この時点で,あなたは価格がヘッジに逆転するのを待つだけです.

ヘージング中のオーダー価格と金額については,各プラットフォームに精度制限があり,最低オーダー金額にも制限があります.最低制限に加えて,戦略はヘージングのための最大オーダー金額も考慮する必要があります.オーダー金額が大きすぎると,市場にはそれのための十分なオーダーボリュームがありません.また,2つのプラットフォームが異なるコート通貨を持っている場合,為替レートを変換する方法も考慮する必要があります.ヘージング中の処理手数料とオーダーテイカーの滑り込みはすべて取引コストです.価格差がある限り,ヘージングは常に起こらない.したがって,ヘージング価格・スプレッドにはトリガー値もあります.特定の価格・スプレッドを下回る場合は,ヘージングは損失を発生します.

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

  • シェード・スプレッド:hedgeDiffPrice差が値を超えると,ヘッジが起動します.
  • 最低保証金額:minHedgeAmount,ヘッジに利用可能な最小オーダー金額 (シンボルの金額)
  • 保証金最大額:maxHedgeAmount, Hedge に利用可能な最大オーダー金額 (シンボルの金額)
  • 価格精度A:pricePrecisionA, プラットフォームAの注文価格精度 (小数点)
  • 注文金額の精度A:amountPrecisionA, プラットフォームAの注文金額精度 (小数位)
  • 価格精度B:pricePrecisionB, Bプラットフォームの注文価格精度 (小数点)
  • 注文金額の精度 B:amountPrecisionB, プラットフォームBの注文金額精度 (小数位)
  • 通貨レートA:rateA,最初の追加された交換対象物の換算為替レート;デフォルトは1,換算しないことを示す.
  • 通貨レートB:rateB,第2の追加された交換対象の換算為替レート;デフォルトは1で,換算しないことを示します.

ヘッジ戦略は,2つのアカウントの通貨シンボルの金額を変化しないようにする必要があります (すなわち,方向的なポジションを保持せず,中立を維持します),したがって,バランスを常に検出するために戦略にバランス論理が必要です.バランスを確認する際には,2つのプラットフォームから資産データを入手することが避けられません.したがって,使用のために関数を書く必要があります.

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

これらの機能は 戦略の要件に従って設計され 戦略の主要な機能を設計し始めることができます

戦略 主要機能設計

FMZでは,戦略はmain機能.main戦略の初期化を行う必要があります.

  • 交換オブジェクト名 取引対象を使用する. 例えば,市場引上げ,注文など. だから,毎回長い名前を使うのは不便でしょう. 私の小さなトリックは,代わりに簡単な短い名前を使用することです. 例えば:

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

    後にコードを書くのが楽になります.

  • 換算率と精度

      // 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)
    

    通貨レートのパラメータの一つ,すなわちrateAそしてrateB, は 1 に設定されます (デフォルトは 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 ドキュメンテーションを参照してください:リンク).
    割り当ておよび使用する 経常口座情報を使用します_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主ループを再実行するために命令が起動します.

  • 使用price spreadまたは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 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 
              }            
          }
    

    ヘッジの誘発条件はいくつかあります. 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", 
              "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)
    

    ステータスバーは特に複雑ではないように設計されています.現在の時間,プラットフォームAからプラットフォームBへの価格・スプレッド,またBからAへの価格・スプレッドを表示します.また,現在のヘッジ目標・スプレッド,プラットフォームAの口座資産データ,およびプラットフォームBの口座資産データを表示します.

異なるコート通貨の取引ペアの処理

通貨レートの値の変換のパラメータを設計し,main戦略の開始時に機能する.SetRate通貨レートの変換機能が最初に実行される必要があります.

この機能は2つの側面に影響します

  • すべての市場コートデータ,オーダーデータ,ポジションデータにおける価格変換
  • コート通貨を口座資産に変換する.

例えば,現在の取引対はBTC_USDT価格単位はUSDT口座の資産の可用コート通貨もUSDTCNYに変換したい場合,設定exchange.SetRate(6.8)すべての関数で取得されたデータを変換するコードexchangeCNYに換算する. コート通貨に変換するには,輸入現行コート通貨から目標コート通貨への為替レート中に入りますSetRate function.

完全な戦略:異なるコート通貨のスポットヘッジ戦略 (教学)


もっと