
前回の記事では、シンプルなヘッジ戦略を実装しました。次は、この戦略をアップグレードする方法を学びます。 戦略の変更は大きなものではありませんが、変更の詳細には注意が必要です。コード内の一部の部分の定義は以前から変更されており、理解する必要があります。
A交易所->B交易所,B交易所->A交易所スプレッドをトリガーする水平線を描きます。直接使用する画线类库利点はシンプルで使いやすいことです。ここではFMZの使い方も学びます模版类库関数。次に、これらのデザインを1つずつ実装してみましょう。
Binanceのスポット取引を例にとると、コードを使用してスポットレバレッジモードに切り替えますexchanges[i].IO、パラメータを渡すtrade_normalレバレッジポジションに切り替えて、パスインするtrade_super_marginレバレッジフルポジションに切り替えます。バックテストはサポートされていません。これは実際の取引でのみ使用されます。
存在するmain関数の先頭に次の準備フェーズを追加します。
// 切换杠杆模式
for (var i = 0 ; i < exchanges.length ; i++) { // 遍历检测所有添加的交易所对象
if (exchanges[i].GetName() == "Binance" && marginType != 0) { // 如果当前i索引代表的交易所对象是币安现货,并且策略界面参数marginType选择的不是「普通币币」选项,执行切换
if (marginType == 1) {
Log(exchanges[i].GetName(), "设置为杠杆逐仓")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "设置为杠杆全仓")
exchanges[i].IO("trade_super_margin")
}
}
}
ここでの戦略は、Binance スポットのコイン間レバレッジ モードを切り替えるコードのみを追加するため、戦略パラメータで設定されたスイッチは Binance スポットに対してのみ有効です。
パッケージ化された描画テンプレートを使用するのは非常に簡単です。私たちが使用するテンプレートの名前は画线类库。 FMZプラットフォーム戦略広場で直接検索して取得できます。

または、リンク https://www.fmz.com/strategy/27293 を直接クリックして、このテンプレートのコピー ページに移動します。

このテンプレート ライブラリを独自の戦略ライブラリにコピーするには、ボタンをクリックします。

次に、ポリシー編集ページのテンプレート列で必要なテンプレートライブラリを確認できます。チェックボックスをオンにしてポリシーを保存すると、このポリシーはこのテンプレートを参照するようになります。ここでは、テンプレート ライブラリの使用について簡単に説明します。この戦略ではこのテンプレートがすでに参照されているため、操作を繰り返す必要はありません。この戦略を戦略スクエアにコピーすると、戦略編集ページのテンプレートの列に表示されます。画线类库すでに引用されています。
主に使い方を学びます画线类库グラフを描画する関数。

私たちは計画していますA->B価格差、B->A価格差と価格差トリガーラインが描画されます。上の図に示すように、2 つの曲線 (A から B への現在の価格差と B から A への価格差) と 2 つの水平線 (トリガー価格差線) を描く必要があります。
一方的なヘッジを設計する必要があるため、A->BそしてB->Aトリガーラインが異なります。前回の記事のデザインはもう使えません。
前の記事:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
トリガースプレッドは1つだけtargetDiffPrice。
したがって、ここではコードを変更して、まずパラメータを変更する必要があります。

次にコードを変更します。
var targetDiffPriceA2B = hedgeDiffPriceA2B
var targetDiffPriceB2A = hedgeDiffPriceB2A
if (diffAsPercentage) {
targetDiffPriceA2B = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageA2B
targetDiffPriceB2A = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageB2A
}
このように、価格差トリガーラインは前回から変更されますtargetDiffPrice一つが二つになったtargetDiffPriceA2B、targetDiffPriceB2A。
次に、線描画ライブラリの線描画機能を使用して、このデータをチャートに描画します。
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
戦略が実行されると、このようなチャートが表示されます。

次に、過剰描画を避けるためにリアルタイムのスプレッド カーブを描画します。残高チェックにリアルタイムの価格差データの曲線を描画するコードを入れます。
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
}
}
$.PlotLine("A2B", depthA.Bids[0].Price - depthB.Asks[0].Price) // 画实时差价曲线
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // 第一个参数是曲线名称,第二个参数是曲线当前时刻的值,即当前时刻Y轴方向上的值
}
この方法では、わずか 4 行の描画コードで、戦略の実行時にチャートを表示できます。
前述のように、価格差トリガーラインは2つに変わり、A->BヘッジトリガーB->Aヘッジがトリガーされます。この方法では、以前の注文価格アルゴリズムは使用できず、代わりに市場価格プラススリッページ方式が使用されます。
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B 盘口条件满足
var priceSell = depthA.Bids[0].Price - slidePrice
var priceBuy = depthB.Asks[0].Price + slidePrice
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance * 0.8 / priceSell > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance * 0.8 / priceSell, maxHedgeAmount)
Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // 提示信息
hedge(exB, exA, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPriceB2A && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B -> A 盘口条件满足
var priceBuy = depthA.Asks[0].Price + slidePrice
var priceSell = depthB.Bids[0].Price - slidePrice
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance * 0.8 / priceBuy > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance * 0.8 / priceBuy, maxHedgeAmount)
Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) // 提示信息
hedge(exA, exB, priceBuy, priceSell, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
買い価格と売り価格が2つのデータに分かれているので、ヘッジ関数はhedgeこれも修正する必要があります。
function hedge(buyEx, sellEx, priceBuy, priceSell, amount) {
var buyRoutine = buyEx.Go("Buy", priceBuy, amount)
var sellRoutine = sellEx.Go("Sell", priceSell, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
これらの変更に基づいていくつかの小さな調整も行われていますが、ここでは詳しく説明しません。詳細についてはコードを参照してください。
戦略にインタラクティブ性を追加して、戦略がスプレッド トリガー ラインをリアルタイムで変更できるようにします。これは半自動戦略の設計要件であり、ここでは教育デモンストレーションとしても実装されています。 戦略のインタラクション設計も非常にシンプルです。まず、戦略編集ページで戦略にインタラクティブなコントロールを追加します。

2 つのコントロールが追加されます。1 つは A2B と呼ばれ、もう 1 つは B2A と呼ばれます。コントロール入力ボックスに値を入力した後、入力ボックスの右側にあるボタンをクリックします。指示はすぐに戦略に送信されます。例:入力ボックスに値を入力します123、 クリックA2Bこのボタンは、戦略に指示をすぐに送信します。
A2B:123
戦略コード内にインタラクション検出および処理コードを設計します。
// 交互
var cmd = GetCommand() // 每次循环执行到这里时,都检测有没有交互指令过来,没有则返回空字符串
if (cmd) { // 检测到有交互指令,例如:A2B:123
Log("接收到命令:", cmd)
var arr = cmd.split(":") // 拆分出交互控件名称和输入框中的值,arr[0]就是A2B,arr[1]就是123
if (arr[0] == "A2B") { // 判断触发的交互控件是不是A2B
Log("修改A2B的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // 修改触发差价线
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // 修改触发差价线
}
} else if (arr[0] == "B2A") { // 检测到触发的控件是B2A
Log("修改B2A的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageA2B = parseFloat(arr[1])
} else {
hedgeDiffPriceB2A = parseFloat(arr[1])
}
}
}
ステータス バーのデータを整理して見やすくします。
var tbl = {
"type" : "table",
"title" : "数据",
"cols" : ["交易所", "币", "冻结币", "计价币", "冻结计价币", "触发差价", "当前差价"],
"rows" : [],
}
tbl.rows.push(["A:" + exA.GetName(), nowAccs[0].Stocks, nowAccs[0].FrozenStocks, nowAccs[0].Balance, nowAccs[0].FrozenBalance, "A->B:" + targetDiffPriceA2B, "A->B:" + (depthA.Bids[0].Price - depthB.Asks[0].Price)])
tbl.rows.push(["B:" + exB.GetName(), nowAccs[1].Stocks, nowAccs[1].FrozenStocks, nowAccs[1].Balance, nowAccs[1].FrozenBalance, "B->A:" + targetDiffPriceB2A, "B->A:" + (depthB.Bids[0].Price - depthA.Asks[0].Price)])
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")

バックテストは戦略のテストと機能の予備的な検出に過ぎません。バックテストの段階では、実際に多くのバグをテストすることができます。バックテストの結果にあまり注意を払う必要はありません。最終的な戦略は、実際の環境でテストする必要があります。


戦略ソースコード: https://www.fmz.com/strategy/302834