
Dalam artikel sebelumnya, kami melaksanakan strategi lindung nilai yang mudah Seterusnya, kami akan mempelajari cara untuk meningkatkan strategi ini. Perubahan strategi tidak akan menjadi besar, tetapi butiran perubahan memerlukan perhatian. Takrifan beberapa bahagian dalam kod telah berubah dari sebelumnya dan perlu difahami.
A交易所->B交易所,B交易所->A交易所Lukis garisan mendatar yang mencetuskan sebaran. Kami secara langsung menggunakan画线类库Kelebihannya ialah ia mudah dan mudah digunakan Di sini juga kita akan belajar cara menggunakan FMZ模版类库Fungsi.Seterusnya, mari kita laksanakan reka bentuk ini satu persatu.
Mengambil perdagangan spot Binance sebagai contoh, beralih kepada mod leverage spot menggunakan kodexchanges[i].IO, lulus dalam parametertrade_normalBeralih kepada leveraj kedudukan demi kedudukan, dan masuktrade_super_marginBeralih kepada kedudukan penuh berleveraj, ujian belakang tidak disokong. Ini hanya digunakan dalam perdagangan sebenar.
wujudmainTambahkan fasa penyediaan berikut pada permulaan fungsi:
// 切换杠杆模式
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")
}
}
}
Strategi di sini hanya menambah kod untuk menukar mod leverage syiling kepada syiling untuk tempat Binance, jadi suis yang ditetapkan dalam parameter strategi hanya sah untuk tempat Binance.
Ia sangat mudah untuk menggunakan templat lukisan yang dibungkus. Templat yang kami gunakan dinamakan画线类库. Anda boleh mencari dan mendapatkannya terus di dataran strategi platform FMZ.

Atau terus klik pautan: https://www.fmz.com/strategy/27293 untuk melompat ke halaman salinan templat ini.

Klik butang untuk menyalin pustaka templat ini ke pustaka strategi anda sendiri.

Kemudian pada halaman penyuntingan dasar, anda boleh menyemak perpustakaan templat yang anda perlukan dalam lajur templat. Selepas menandai kotak dan menyimpan dasar, dasar ini akan merujuk templat ini. Di sini kami hanya menerangkan secara ringkas penggunaan perpustakaan templat Strategi ini telah pun merujuk templat ini jadi tidak perlu mengulangi operasi. Selepas anda menyalin strategi ini dalam Strategy Square, anda boleh melihatnya dalam lajur templat halaman penyuntingan strategi.画线类库Sudah dipetik.
Kami terutamanya belajar cara menggunakan画线类库berfungsi untuk melukis graf.

Kami merancang untukA->BPerbezaan harga,B->AGaris pencetus perbezaan harga dan perbezaan harga dilukis. Anda perlu melukis dua lengkung (perbezaan harga semasa dari A ke B dan dari B ke A) dan dua garisan mendatar (garisan perbezaan harga pencetus), seperti yang ditunjukkan dalam rajah di atas.
Kerana kita perlu mereka bentuk lindung nilai unilateral,A->BdanB->AGaris pencetus adalah berbeza. Reka bentuk dalam artikel sebelum ini tidak boleh digunakan lagi.
Dalam artikel sebelum ini:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Terdapat hanya satu penyebaran pencetustargetDiffPrice。
Jadi di sini kita perlu mengubah suai kod, mula-mula mengubah suai parameter.

Kemudian ubah suai kod:
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
}
Dengan cara ini, garis pencetus perbezaan harga berubah daripada sebelumnyatargetDiffPriceSatu, menjadi duatargetDiffPriceA2B、targetDiffPriceB2A。
Seterusnya, anda boleh menggunakan fungsi lukisan garisan perpustakaan lukisan garisan untuk melukis data ini pada carta.
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
Apabila strategi berjalan, carta seperti ini akan muncul.

Seterusnya, lukis keluk sebaran masa nyata untuk mengelakkan lukisan berlebihan. Letakkan kod untuk melukis keluk data perbezaan harga masa nyata dalam semakan baki.
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轴方向上的值
}
Dengan cara ini, dengan hanya 4 baris kod lukisan, strategi boleh memaparkan carta apabila ia dijalankan.
Seperti yang dinyatakan di atas, garis pencetus perbezaan harga telah diubah menjadi dua, mengawalA->BPencetus lindung nilaiB->ALindung nilai dicetuskan. Dengan cara ini, algoritma harga pesanan sebelumnya tidak boleh digunakan, dan sebaliknya kaedah harga pasaran ditambah gelinciran digunakan.
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
}
}
Oleh kerana harga belian dan jualan dipisahkan kepada dua data, fungsi lindung nilaihedgeIa juga perlu diubah suai.
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()
}
Terdapat juga beberapa pelarasan kecil berdasarkan perubahan ini, yang saya tidak akan pergi ke sini Anda boleh melihat kod untuk butiran.
Tambahkan interaktiviti pada strategi supaya strategi boleh mengubah suai garis pencetus penyebaran dalam masa nyata. Ini adalah keperluan reka bentuk untuk strategi separa automatik, yang juga dilaksanakan di sini sebagai demonstrasi pengajaran. Reka bentuk interaksi strategi juga sangat mudah Pertama, tambahkan kawalan interaktif pada strategi pada halaman penyuntingan strategi.

Dua kawalan ditambah, satu dipanggil A2B dan satu lagi dipanggil B2A. Selepas memasukkan nilai dalam kotak input kawalan, klik butang di sebelah kanan kotak input. Arahan akan dihantar kepada strategi serta-merta, contohnya: masukkan nilai dalam kotak input123, klikA2BButang ini akan segera menghantar arahan kepada strategi.
A2B:123
Reka bentuk pengesanan interaksi dan kod pemprosesan dalam kod strategi.
// 交互
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])
}
}
}
Jadikan data bar status lebih teratur dan lebih mudah untuk diperhatikan.
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) + "`")

Ujian belakang hanyalah ujian strategi dan pengesanan awal fungsi Banyak pepijat sebenarnya boleh diuji semasa peringkat ujian belakang. Tidak perlu memberi terlalu banyak perhatian kepada keputusan ujian belakang Strategi akhir masih perlu diuji dalam persekitaran sebenar.


Kod sumber strategi: https://www.fmz.com/strategy/302834