ヘージング戦略は,戦略設計の初心者にとって非常に良い実践戦略です.この記事は,初心者が設計経験を学ぶことを期待して,シンプルで実用的な仮想通貨スポットヘージング戦略を実装しています.
まず最初に,設計される戦略は仮想通貨スポットヘッジ戦略であることは明らかである.我々は最も単純なヘッジ戦略を設計する.我々は2つのスポット取引所間の間でのみ,より高い価格で取引所で販売し,低価格で取引所で購入して違いを取ります.より高い価格を持つ取引所はすべて指名されたコイン (より高い価格を持つコインが販売されるため),低価格を持つ取引所はすべてコイン (より低い価格を持つコインが購入されるため) であるとき,それはヘッジすることはできません.この時点で,我々は価格逆転をヘッジするために待つしかできません.
ヘージングでは,注文の価格と量が取引所によって制限され,最低注文量にも制限があります.最低制限に加えて,ヘージングの戦略は同時に最大注文量も考慮する必要があります.注文量が大きすぎると,十分な注文量はありません.また,2つの交換通貨が異なる場合,為替レートを変換する方法も考慮する必要があります.ヘージングでは,注文受取者の処理手数料とスリップはすべての取引コストであり,価格の差がある限りヘージングができません.したがって,ヘージング価格の差はまたトリガー値を持っています.特定の価格の差を下回る場合は,ヘージングは損します.
これらの考慮に基づいて,戦略はいくつかのパラメータを考慮して設計する必要があります.
hedgeDiffPrice
差がこの値を超えると,ヘッジ操作が開始されます.minHedgeAmount
, 負債をカバーできる最小のオーダー金額 (コイン).maxHedgeAmount
, 1 つのヘージングの最大オーダー金額 (コイン)pricePrecisionA
, 取引所Aが設定した注文価格精度 (小数点数)amountPrecisionA
, 取引所Aが発した注文の金額精度 (小数点数)pricePrecisionB
, 取引所Bが設定した注文価格精度 (小数点数)amountPrecisionB
, 取引所Bが発行した注文の金額精度 (小数点数)rateA
,最初の追加された交換対象の為替レートの変換,デフォルトは1で,変換されていません.rateB
, 換算されていない第2の追加された換算対象の換算率変換,デフォルトは1です.ヘッジ戦略は,両口座のコインの数を変化しないようにする必要がある (つまり,いかなる方向にもポジションを保持せず,中立性を維持する),したがって,バランスを常に検出するために戦略にバランス論理が必要です.バランスを確認する際に,両取引所からの資産データを入手することは避けられません.使用する関数を書く必要があります.
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)
}
}
})
}
特定の値のコインに蓄積された価格を 特定の深さのデータで求めます そのためにはこのような関数が必要です
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()
}
微妙なバランス関数の設計を完成させましょう.
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
, rateB
1 に設定されます (デフォルトは1) つまりrateA != 1
またはrateB != 1
引き起こすので,為替レートの変換は設定されません.
すべてのデータをリセットする
ストラテジーのインターフェースパラメータを設計することができます. ストラテジーのインターフェースは,すべてのログを削除し,ストラテジーのインターフェースを削除します.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.Go
FMZプラットフォームの同時オブジェクトを作成するために使用されます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
.
パラメータ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
}
}
負債の負債の負債の負債の負債の負債の負債の負債
isTrade
初期設定で,ヘッジが発生するかどうかを表示します.ここで,ヘッジが起動した場合,変数はtrue
グローバル変数をリセットします.lastKeepBalanceTS
0 (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
口座の資産に含まれる通貨は,USDT
CNYに変換したい場合は,セットexchange.SetRate(6.8)
すべての関数で取得されたデータを変換するコードexchange
CNY に換算する.
通貨に換算するには,現貨から目標通貨への為替レートについてSetRate
function.