Strategi lindung nilai adalah strategi praktik yang sangat baik untuk pemula dalam desain strategi.
Pertama-tama, jelas bahwa strategi yang akan dirancang adalah strategi lindung nilai spot cryptocurrency. Kami merancang strategi lindung nilai paling sederhana. Kami menjual di bursa dengan harga yang lebih tinggi hanya antara dua bursa spot, dan membeli di bursa dengan harga yang lebih rendah untuk mengambil perbedaannya. Ketika bursa dengan harga yang lebih tinggi semua koin nominal (karena koin dengan harga yang lebih tinggi dijual), dan bursa dengan harga yang lebih rendah semua koin (koin dengan harga yang lebih rendah dibeli), itu tidak dapat dilindung nilai. Pada saat ini, kita hanya dapat menunggu pembalikan harga untuk lindung nilai.
Saat melakukan hedging, harga dan kuantitas order dibatasi oleh bursa, dan ada juga batas pada jumlah order minimum. Selain batas minimum, strategi dalam hedging juga perlu mempertimbangkan volume order maksimum pada satu waktu. Jika volume order terlalu besar, tidak akan ada volume order yang cukup. Juga perlu dipertimbangkan bagaimana mengubah nilai tukar jika dua koin yang berdenominasi bursa berbeda. Saat hedging, biaya penanganan dan slippage dari pemegang order adalah semua biaya transaksi, tidak selama ada perbedaan harga yang dapat dilindungi. Oleh karena itu, perbedaan harga hedging juga memiliki nilai pemicu. Jika lebih rendah dari perbedaan harga tertentu, hedging akan kehilangan.
Berdasarkan pertimbangan ini, strategi harus dirancang dengan beberapa parameter:
hedgeDiffPrice
, ketika selisihnya melebihi nilai ini, operasi lindung nilai dipicu.minHedgeAmount
, jumlah pesanan minimum (koin) yang dapat dilindungi.maxHedgeAmount
, jumlah pesanan maksimum (koin) untuk satu lindung nilai.pricePrecisionA
, presisi harga order (jumlah desimal) yang ditempatkan oleh Exchange A.amountPrecisionA
, jumlah presisi pesanan yang ditempatkan oleh Exchange A (jumlah tempat desimal).pricePrecisionB
, presisi harga order (jumlah desimal) yang ditempatkan oleh Exchange B.amountPrecisionB
, jumlah presisi pesanan yang ditempatkan oleh Exchange B (jumlah tempat desimal).rateA
, konversi nilai tukar dari objek pertukaran pertama yang ditambahkan, default adalah 1, tidak dikonversi.rateB
, konversi nilai tukar dari objek pertukaran kedua yang ditambahkan, default adalah 1, tidak dikonversi.Strategi lindung nilai perlu menjaga jumlah koin dalam dua akun tidak berubah (yaitu, tidak memegang posisi ke arah mana pun, dan menjaga netralitas), sehingga perlu ada logika keseimbangan dalam strategi untuk selalu mendeteksi keseimbangan.
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
}
Setelah menempatkan pesanan, jika tidak ada pesanan yang selesai, kita perlu membatalkannya tepat waktu, dan pesanan tidak dapat tetap menunggu. operasi ini perlu diproses baik dalam modul saldo dan logika lindung nilai, sehingga juga perlu untuk merancang fungsi penarikan pesanan penuh.
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)
}
}
})
}
Saat menyeimbangkan jumlah koin, kita perlu menemukan harga akumulasi untuk sejumlah koin dalam data kedalaman tertentu, jadi kita perlu fungsi seperti itu untuk menanganinya.
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
}
Kemudian kita perlu merancang dan menulis operasi pesanan lindung nilai tertentu, yang perlu dirancang untuk menempatkan pesanan bersamaan:
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()
}
Akhirnya, mari kita selesaikan desain fungsi keseimbangan, yang sedikit rumit.
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
}
}
Setelah mendesain fungsi-fungsi ini sesuai dengan persyaratan strategi, kemudian mulailah mendesain fungsi utama strategi.
Di platform FMZ, strategi dilaksanakan darimain
Pada awalmain
fungsi, kita harus melakukan beberapa pekerjaan inisialisasi strategi.
Nama objek pertukaran Karena banyak operasi dalam strategi harus menggunakan objek pertukaran, seperti mendapatkan penawaran pasar, menempatkan pesanan dan sebagainya. jadi akan rumit untuk menggunakan nama panjang setiap kali, tipnya adalah menggunakan nama sederhana sebagai gantinya, misalnya:
var exA = exchanges[0]
var exB = exchanges[1]
Ini membuat lebih mudah untuk menulis kode nanti.
Nilai tukar, desain terkait presisi
// 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)
Jika parameter nilai tukarrateA
, rateB
ditetapkan menjadi 1 (default adalah 1), yaitu,rateA != 1
ataurateB != 1
tidak akan memicu, sehingga konversi nilai tukar tidak akan ditetapkan.
Setel ulang semua data
Kadang-kadang perlu untuk menghapus semua log dan menghapus data yang tercatat ketika strategi dimulai.isReset
, dan merancang kode reset di bagian inisialisasi strategi, misalnya:
if (isReset) { // When isReset is true, reset the data
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("reset all data", "#FF0000")
}
Memulihkan data akun awal, memperbarui data rekening arus
Untuk menilai saldo, strategi perlu terus mencatat aset rekening awal untuk perbandingan dengan yang saat ini.nowAccs
digunakan untuk merekam data rekening current, menggunakan fungsi yang baru saja kita dirancangupdateAccs
untuk mendapatkan data akun dari bursa saat ini.initAccs
digunakan untuk mencatat status akun awal (jumlah koin, jumlah koin denominasi, dll pada bursa A dan B).initAccs
, gunakan_G()
fungsi untuk mengembalikan pertama (fungsi _G akan mencatat data secara terus menerus, dan dapat mengembalikan data yang tercatat lagi, lihat dokumentasi API untuk rincian: [link](https://www.fmz.com/api#_gk-v)), jika query tidak berhasil, gunakan informasi rekening current untuk menugaskan nilai dan_G
fungsi untuk merekam.
Seperti kode berikut:
var nowAccs = _C(updateAccs, exchanges)
var initAccs = _G("initAccs")
if (!initAccs) {
initAccs = nowAccs
_G("initAccs", initAccs)
}
Kode dalam loop utama adalah proses setiap putaran eksekusi logika strategi, yang dijalankan berulang kali untuk membentuk loop utama strategi.
Mendapatkan data pasar dan menilai validitas data pasar
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
}
Di sini kita bisa melihat bahwa fungsi paralelexchange.Go
dari platform FMZ digunakan untuk membuat objek bersamaandepthARoutine
, depthBRoutine
yang disebutGetDepth()
Ketika dua objek bersamaan ini dibuat,GetDepth()
antarmuka dipanggil segera, dan kedua permintaan untuk data kedalaman dikirim ke pertukaran.
Lalu hubungiwait()
metode daridepthARoutine
, depthBRoutine
objek untuk mendapatkan data kedalaman.
Setelah mendapatkan data kedalaman, perlu untuk memeriksa data kedalaman untuk menentukan keabsahannya.continue
pernyataan dipicu untuk mengeksekusi kembali loop utama.
Gunakanspread value
parameter atauspread ratio
Parameter?
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Dalam hal parameter, kami telah membuat desain seperti: parameter FMZ dapatpertunjukanataumenyembunyikanberdasarkan parameter, sehingga kita dapat membuat parameter untuk memutuskan apakah untuk menggunakanprice spread
, atauspread ratio
.
Sebuah parameterdiffAsPercentage
telah ditambahkan ke parameter antarmuka strategi. kedua pengaturan parameter lainnya untuk menunjukkan atau menyembunyikan berdasarkan parameter ini adalah:hedgeDiffPrice@!diffAsPercentage
, yang ditampilkan ketikadiffAsPercentage
adalah palsu.hedgeDiffPercentage@diffAsPercentage
, yang ditampilkan ketikadiffAsPercentage
Benar.
Setelah desain ini, kami memeriksadiffAsPercentage
parameter, yang merupakan kondisi pemicu lindung nilai berdasarkan rasio perbedaan harga.diffAsPercentage
Parameter diperiksa, lindung nilai dipicu oleh perbedaan harga.
Tentukan kondisi pemicu lindung nilai
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
}
}
Kondisi pemicu lindung nilai adalah sebagai berikut:
isTrade
Di sini, jika lindung nilai dipicu, variabel diatur menjaditrue
Dan reset variabel globallastKeepBalanceTS
ke 0 (lastKeepBalanceTS digunakan untuk menandai timestamp dari operasi penyeimbangan terakhir, mengaturnya ke 0 akan memicu operasi penyeimbangan segera), dan kemudian membatalkan semua pesanan yang menunggu.Operasi penyeimbangan
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
}
}
}
Hal ini dapat dilihat bahwa fungsi keseimbangan dijalankan secara berkala, tetapi jikalastKeepBalanceTS
Jika nilai dari transaksi ini dihitung kembali ke 0 setelah operasi lindung nilai dipicu, maka operasi penyeimbangan akan segera dipicu.
Informasi bilah status
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)
Bar status tidak terlalu rumit dalam desain. Ini menampilkan waktu saat ini, perbedaan harga dari Exchange A ke Exchange B dan perbedaan harga dari Exchange B ke Exchange A. Dan menampilkan spread target lindung nilai saat ini, data aset dari akun exchange A dan akun exchange B.
Dalam hal parameter, kami merancang nilai parameter nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilaimain
Hal ini harus dicatat bahwaSetRate
Fungsi konversi nilai tukar harus dijalankan terlebih dahulu.
Karena fungsi ini mempengaruhi dua aspek:
BTC_USDT
, satuan harga adalahUSDT
, dan mata uang denominasi yang tersedia dalam aset rekening jugaUSDT
Jika saya ingin mengkonversi nilai ke CNY, aturexchange.SetRate(6.8)
dalam kode untuk mengubah data yang diperoleh oleh semua fungsi di bawahexchange
objek pertukaran ke CNY.
Untuk mengkonversi ke mata uang denominasi apa, masukkannilai tukar dari mata uang denominasi saat ini ke mata uang denominasi targetuntukSetRate
function.Strategi lengkap:Strategi Hedging Spot dari Mata Uang yang Berbeda (Tutorial)