Untuk pemula dalam reka bentuk strategi, strategi lindung nilai adalah satu yang sangat baik untuk amalan.
Pertama sekali, kita perlu memastikan bahawa strategi yang akan direka adalah strategi lindung nilai mata wang kripto spot. Kami merancang lindung nilai yang paling mudah. Kami hanya menjual di platform dengan harga yang lebih tinggi di antara dua platform spot, dan membeli di platform dengan harga yang lebih rendah untuk memperoleh spread harga. Apabila platform dengan harga yang lebih tinggi penuh dengan simbol mata wang kutipan (kerana harga tinggi, semua simbol mata wang dijual), atau apabila platform dengan harga yang lebih rendah penuh dengan simbol mata wang (kerana harga rendah, simbol mata wang dibeli oleh semua aset), ia tidak dapat dilindung nilai. Pada masa ini, anda hanya boleh menunggu harga terbalik untuk lindung nilai.
Untuk harga pesanan dan jumlah semasa lindung nilai, terdapat had ketepatan di setiap platform, dan juga terdapat had pada jumlah pesanan minimum. Selain had minimum, strategi juga perlu mempertimbangkan jumlah pesanan maksimum untuk lindung nilai. Jika jumlah pesanan terlalu besar, pasaran tidak akan mempunyai jumlah pesanan yang mencukupi untuk itu. Ia juga perlu mempertimbangkan bagaimana menukar kadar pertukaran jika kedua-dua platform mempunyai mata wang kutipan yang berbeza. Yuran penanganan semasa lindung nilai dan slippage pemegang pesanan adalah semua kos perdagangan. lindung nilai tidak selalu berlaku selagi terdapat perbezaan harga. Oleh itu, penyebaran harga lindung nilai juga mempunyai nilai pemicu. Jika lebih rendah daripada penyebaran harga tertentu, lindung nilai akan membuat kerugian.
Berdasarkan itu, strategi perlu direka dengan beberapa parameter:
hedgeDiffPrice
; apabila perbezaan melebihi nilai, lindung nilai akan dicetuskan.minHedgeAmount
, jumlah pesanan minimum (jumlah simbol) yang tersedia untuk lindung nilai.maxHedgeAmount
, jumlah pesanan maksimum (jumlah simbol) yang tersedia untuk lindung nilai.pricePrecisionA
, ketepatan harga pesanan (angka perpuluhan) platform A.amountPrecisionA
, ketepatan jumlah pesanan (angka perpuluhan) platform A.pricePrecisionB
, ketepatan harga pesanan (angka perpuluhan) platform B.amountPrecisionB
, ketepatan jumlah pesanan (angka perpuluhan) platform B.rateA
, kadar pertukaran menukar objek pertukaran pertama yang ditambah; lalai adalah 1, yang menunjukkan tidak untuk menukar.rateB
, kadar pertukaran menukar objek pertukaran kedua yang ditambah; lalai adalah 1, menunjukkan tidak untuk menukar.Strategi lindung nilai perlu mengekalkan jumlah simbol mata wang dari kedua-dua akaun tidak berubah (iaitu, tidak memegang mana-mana kedudukan arah, dan mengekalkan neutral), jadi perlu ada logik baki dalam strategi untuk sentiasa mengesan baki.
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
}
Selepas meletakkan pesanan, jika tidak ada pesanan yang dilaksanakan, kita perlu membatalkannya tepat pada masanya, dan pesanan tidak boleh disimpan menunggu. Operasi ini perlu diproses di kedua-dua modul baki dan logik lindung nilai, jadi ia juga perlu untuk merancang fungsi membatalkan semua pesanan.
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)
}
}
})
}
Apabila menyeimbangkan jumlah simbol mata wang, kita perlu mencari harga dengan jumlah tertentu dalam data kedalaman tertentu, jadi kita memerlukan fungsi seperti ini untuk mengendalikannya.
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 direka untuk meletakkan pesanan serentak:
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 reka bentuk fungsi keseimbangan, yang sedikit lebih 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 currency spread
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("cannot balance")
} else {
// balanced ordering
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("error:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
return true
} else {
return true
}
}
Fungsi-fungsi ini telah direka mengikut keperluan strategi, dan kita boleh mula merancang fungsi utama strategi.
Pada FMZ, strategi dilaksanakan darimain
Pada permulaanmain
fungsi, kita perlu melakukan beberapa inisialisasi strategi.
Nama Objek Exchange Untuk banyak operasi dalam strategi menggunakan objek pertukaran, seperti mendapatkan sebut harga pasaran, meletakkan pesanan, dan sebagainya, jadi ia akan menjadi tidak selesa untuk menggunakan nama yang lebih lama setiap kali, trik kecil saya adalah untuk menggunakan nama pendek yang mudah sebagai gantinya, sebagai contoh:
var exA = exchanges[0]
var exB = exchanges[1]
Kemudian, ia akan lebih selesa untuk menulis kod kemudian.
Kadar Pertukaran & Ketepatan
// settings of precision and exchange rate
if (rateA != 1) {
// set exchange rate A
exA.SetRate(rateA)
Log("Platform A sets exchange rate:", rateA, "#FF0000")
}
if (rateB != 1) {
// set exchange rate B
exB.SetRate(rateB)
Log("Platform B sets exchange rate:", rateB, "#FF0000")
}
exA.SetPrecision(pricePrecisionA, amountPrecisionA)
exB.SetPrecision(pricePrecisionB, amountPrecisionB)
Jika salah satu parameter kadar pertukaran, iaiturateA
danrateB
, ditetapkan kepada 1 (default adalah 1), iaitu,rateA != 1
ataurateB != 1
bermakna tidak dicetuskan, dan kadar pertukaran tidak boleh ditukar.
Tetapkan semula semua tarikh
Kadang-kadang, ia adalah perlu untuk memadamkan semua log dan vakum rekod data apabila strategi dimulakan.isReset
, dan kemudian merancang kod reset dalam bahagian inisialisasi strategi, contohnya:
if (isReset) { // when "isReset" is true, reset the data
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("Reset all data", "#FF0000")
}
Memulihkan Data Akaun Awal dan Mengemas kini Data Akaun semasa
Untuk menilai baki, strategi perlu terus mencatat keadaan aset akaun awal untuk perbandingan dengan yang semasa.nowAccs
digunakan untuk merakam data akaun semasa.updateAccs
Fungsi yang kita buat untuk mendapatkan data akaun platform semasa.initAccs
digunakan untuk merakam status akaun awal (data seperti jumlah simbol mata wang kedua-dua A dan B, jumlah mata wang sebut harga, dll.).initAccs
, mula-mula gunakan_G()
fungsi untuk memulihkan (fungsi _G akan merakam data secara berterusan, dan boleh mengembalikan data yang direkodkan lagi; baca dokumentasi API untuk butiran:pautan).
Jika anda tidak boleh pertanyaan data, menggunakan maklumat akaun semasa untuk menetapkan dan menggunakan_G()
fungsi untuk merekod.
Seperti kod berikut:
var nowAccs = _C(updateAccs, exchanges)
var initAccs = _G("initAccs")
if (!initAccs) {
initAccs = nowAccs
_G("initAccs", initAccs)
}
Kod dalam gelung utama adalah proses setiap pusingan pelaksanaan logik strategi, dan pelaksanaan berulang tanpa henti membina gelung utama strategi.
Dapatkan Kutipan Pasaran dan Menilai Validiti
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 anda boleh melihat bahawa fungsi serentakexchange.Go
dari platform FMZ digunakan untuk mencipta objek serentakdepthARoutine
dandepthBRoutine
yang memanggilGetDepth()
Apabila kedua-dua objek serentak ini dicipta,GetDepth()
Antara muka dipanggil dengan segera, dan kedua-dua permintaan untuk data kedalaman dihantar ke platform.
Kemudian, hubungiwait()
kaedah objekdepthARoutine
dan objekdepthBRoutine
untuk mendapatkan data kedalaman.
Selepas mendapatkan data kedalaman, adalah perlu untuk memeriksa data kedalaman untuk menilai kesahihannya.continue
Perintah akan dicetuskan untuk menjalankan semula gelung utama.
Penggunaanprice spread
atauspread 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
}
Dari segi parameter, kita telah membuat reka bentuk seperti. parameter FMZ bolehmenunjukkanataubersembunyiberdasarkan parameter, jadi kita boleh membuat parameter untuk memutuskan sama ada untuk menggunakanprice spread
, atauspread ratio
.
ParameterdiffAsPercentage
telah ditambah kepada parameter antara muka strategi. dua parameter lain, yang akan menunjukkan atau menyembunyikan berdasarkan parameter ditetapkan sebagai:hedgeDiffPrice@!diffAsPercentage
; apabiladiffAsPercentage
adalah palsu, ia akan ditunjukkan.hedgeDiffPercentage@diffAsPercentage
; apabiladiffAsPercentage
adalah benar, ia akan ditunjukkan.
Selepas reka bentuk, kami telah memeriksadiffAsPercentage
parameter, yang adalah untuk menggunakan nisbah spread sebagai keadaan pencetus lindung nilai.diffAsPercentage
parameter tidak diperiksa, spread harga digunakan sebagai keadaan pencetus lindung nilai.
Hakim Hedge Trigger
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B market condition satisfied
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("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks) // prompt message
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 condition satisfied
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("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks) // prompt message
hedge(exA, exB, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Terdapat beberapa syarat pemicu untuk lindung nilai: 1.Pertama, memenuhi spread lindung nilai; hanya apabila spread pasaran memenuhi parameter spread yang ditetapkan, lindung nilai boleh dilakukan.
2.Jumlah lindung nilai pasaran harus memenuhi jumlah lindung nilai minimum yang ditetapkan dalam parameter.
3.Aset dalam platform dengan operasi jualan adalah cukup untuk menjual, dan aset dalam platform dengan operasi pembelian adalah cukup untuk membeli. Apabila syarat-syarat ini dipenuhi, melaksanakan fungsi lindung nilai untuk meletakkan pesanan dengan lindung nilai. Sebelum fungsi utama, kita mengisytiharkan pembolehubahisTrade
di hadapan untuk menandakan sama ada lindung nilai berlaku. di sini, jika lindung nilai dicetuskan, pembolehubah ditetapkan kepadatrue
. Dan menetapkan semula pembolehubah globallastKeepBalanceTS
kepada 0 (lastKeepBalanceTS digunakan untuk menandakan cap masa operasi baki terakhir, dan menetapkannya kepada 0 akan mencetuskan operasi baki dengan serta-merta), dan kemudian membatalkan semua pesanan yang menunggu.
Operasi imbangan
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
}
}
}
Ia dapat dilihat bahawa fungsi imbangan dijalankan secara berkala, tetapi jikalastKeepBalanceTS
Jika nilai semula ke 0 selepas operasi lindung nilai telah dicetuskan, operasi imbangan akan dicetuskan dengan serta-merta.
Maklumat Bar 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",
"currentA,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n",
"currentB,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n",
"initialA,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n",
"initialB,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
Bar status tidak direka untuk menjadi sangat rumit. Ia memaparkan masa semasa, harga penyebaran dari platform A ke platform B serta harga penyebaran dari B ke A; ia juga memaparkan penyebaran sasaran lindung nilai semasa, data aset akaun platform A, dan data aset akaun platform B.
Dari segi parameter, kita telah merancang parameter menukar nilai kadar pertukaran, dan kita juga telah merancang penukaran kadar pertukaran dalam operasi awal sistem.main
Ia harus diperhatikan bahawaSetRate
Fungsi penukaran kadar pertukaran perlu dilaksanakan terlebih dahulu.
Untuk fungsi akan mempengaruhi dua aspek:
Sebagai contoh, pasangan dagangan semasa adalahBTC_USDT
, unit harga adalahUSDT
, dan mata wang sebut harga yang tersedia dalam aset akaun jugaUSDT
Jika saya mahu menukar nilai aset ke CNY, tetapkanexchange.SetRate(6.8)
dalam kod untuk menukar data yang diperoleh oleh semua fungsi di bawahexchange
objek, dan kemudian menukar kepada CNY.
Untuk menukar kepada apa mata wang sebut harga, importkadar pertukaran dari mata wang sebut harga semasa ke mata wang sebut harga sasaranke dalamSetRate
function.
Strategi lengkap:Strategi lindung nilai spot mata wang sebut harga yang berbeza (Pengajaran)