
Pada artikel sebelumnya, kita telah menerapkan strategi lindung nilai yang sederhana. Selanjutnya, kita akan mempelajari cara meningkatkan strategi ini. Perubahan strategi tidak akan besar, tetapi rincian perubahannya memerlukan perhatian. Definisi beberapa bagian dalam kode telah berubah dari sebelumnya dan perlu dipahami.
A交易所->B交易所,B交易所->A交易所Gambarkan garis horizontal yang memicu penyebaran. Kami langsung menggunakan画线类库Kelebihannya adalah sederhana dan mudah digunakan. Di sini kita juga akan belajar cara menggunakan FMZ模版类库Fungsi.Selanjutnya, mari kita implementasikan desain ini satu per satu.
Mengambil perdagangan spot Binance sebagai contoh, beralihlah ke mode leverage spot menggunakan kodeexchanges[i].IO, masukkan parametertrade_normalBeralih ke posisi leverage per posisi, dan teruskantrade_super_marginBeralih ke posisi penuh dengan leverage, pengujian ulang tidak didukung. Ini hanya digunakan dalam perdagangan nyata.
adamainTambahkan fase persiapan berikut ke awal 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 menambahkan kode untuk mengalihkan mode leverage koin-ke-koin untuk Binance spot, jadi pengalihan yang ditetapkan dalam parameter strategi hanya berlaku untuk Binance spot.
Sangat mudah untuk menggunakan templat gambar yang disertakan. Template yang kami gunakan bernama画线类库. Anda dapat mencari dan memperolehnya langsung di kotak strategi platform FMZ.

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

Klik tombol untuk menyalin pustaka templat ini ke pustaka strategi Anda sendiri.

Kemudian pada halaman penyuntingan kebijakan, Anda dapat memeriksa pustaka templat yang Anda perlukan di kolom templat. Setelah mencentang kotak dan menyimpan kebijakan, kebijakan ini akan merujuk ke templat ini. Di sini kami hanya menjelaskan secara singkat penggunaan pustaka templat. Strategi ini telah merujuk pada templat ini sehingga tidak perlu mengulang operasi tersebut. Setelah Anda menyalin strategi ini di Strategy Square, Anda dapat melihatnya di kolom templat halaman pengeditan strategi.画线类库Sudah dikutip.
Kami terutama belajar cara menggunakan画线类库berfungsi untuk menggambar grafik.

Kami berencana untukA->BPerbedaan harga,B->APerbedaan harga dan garis pemicu perbedaan harga digambar. Anda perlu menggambar dua kurva (selisih harga saat ini dari A ke B dan dari B ke A) dan dua garis horizontal (garis pemicu perbedaan harga), seperti yang ditunjukkan pada gambar di atas.
Karena kita perlu merancang lindung nilai unilateral,A->BDanB->AGaris pemicunya berbeda. Desain pada artikel sebelumnya tidak dapat digunakan.
Pada artikel sebelumnya:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Hanya ada satu penyebaran pemicutargetDiffPrice。
Jadi di sini kita perlu memodifikasi kodenya, pertama modifikasi parameternya.

Kemudian modifikasi kode berikut:
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 pemicu perbedaan harga berubah dari sebelumnyatargetDiffPriceSatu, menjadi duatargetDiffPriceA2B、targetDiffPriceB2A。
Berikutnya, Anda dapat menggunakan fungsi gambar garis dari pustaka gambar garis untuk menggambar data ini pada bagan.
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
Ketika strategi berjalan, grafik seperti ini akan muncul.

Berikutnya, gambarkan kurva sebaran waktu nyata untuk menghindari penggambaran berlebihan. Masukkan kode untuk menggambar kurva data perbedaan harga waktu nyata dalam pemeriksaan saldo.
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, hanya dengan 4 baris kode gambar, strategi dapat menampilkan grafik saat dijalankan.
Seperti yang disebutkan di atas, garis pemicu perbedaan harga telah diubah menjadi dua, mengendalikanA->BPemicu lindung nilaiB->ALindung nilai dipicu. Dengan cara ini, algoritma harga pesanan sebelumnya tidak dapat digunakan, dan metode harga pasar ditambah slippage digunakan sebagai gantinya.
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
}
}
Karena harga beli dan harga jual dipisahkan menjadi dua data, fungsi lindung nilaihedgeItu juga perlu dimodifikasi.
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()
}
Ada juga beberapa penyesuaian kecil berdasarkan perubahan ini, yang tidak akan saya bahas di sini. Anda dapat melihat kode untuk detailnya.
Tambahkan interaktivitas ke strategi sehingga strategi dapat memodifikasi garis pemicu penyebaran secara real-time. Ini adalah persyaratan desain untuk strategi semi-otomatis, yang juga diterapkan di sini sebagai demonstrasi pengajaran. Desain interaksi strategi juga sangat sederhana. Pertama, tambahkan kontrol interaktif ke strategi pada halaman penyuntingan strategi.

Dua kontrol ditambahkan, satu disebut A2B dan lainnya disebut B2A. Setelah memasukkan nilai dalam kotak masukan kontrol, klik tombol di sisi kanan kotak masukan. Instruksi akan segera dikirim ke strategi, misalnya: masukkan nilai di kotak input123, klikA2BTombol ini akan segera mengirimkan instruksi ke strategi.
A2B:123
Merancang kode deteksi dan pemrosesan interaksi dalam kode 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 bilah status lebih terorganisasi dan lebih mudah diamati.
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) + "`")

Pengujian ulang hanyalah pengujian strategi dan deteksi awal fungsi. Banyak bug yang sebenarnya dapat diuji selama tahap pengujian ulang. Tidak perlu terlalu memperhatikan hasil backtest. Strategi akhir masih perlu diuji di lingkungan nyata.


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