
KemudianKonten sebelumnyamenjelaskan.
Fungsi tambahan ketiga:
self.balanceAccount = function() {
var account = exchange.GetAccount()
if (!account) {
return
}
self.account = account
var now = new Date().getTime()
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {
self.preCalc = now
var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
}
self.btc = account.Stocks
self.cny = account.Balance
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
var balanced = false
if (self.p < 0.48) {
Log("开始平衡", self.p)
self.cny -= 300
if (self.orderBook.Bids.length >0) {
exchange.Buy(self.orderBook.Bids[0].Price + 0.00, 0.01)
exchange.Buy(self.orderBook.Bids[0].Price + 0.01, 0.01)
exchange.Buy(self.orderBook.Bids[0].Price + 0.02, 0.01)
}
} else if (self.p > 0.52) {
Log("开始平衡", self.p)
self.btc -= 0.03
if (self.orderBook.Asks.length >0) {
exchange.Sell(self.orderBook.Asks[0].Price - 0.00, 0.01)
exchange.Sell(self.orderBook.Asks[0].Price - 0.01, 0.01)
exchange.Sell(self.orderBook.Asks[0].Price - 0.02, 0.01)
}
}
Sleep(BalanceTimeout)
var orders = exchange.GetOrders()
if (orders) {
for (var i = 0; i < orders.length; i++) {
if (orders[i].Id != self.tradeOrderId) {
exchange.CancelOrder(orders[i].Id)
}
}
}
}
KonstruktorLeeksReaper()Saat membuat objek, tambahkanbalanceAccount()Fungsinya adalah untuk memperbarui informasi aset akun yang disimpan diself.account, yaitu objek yang dibangunaccountmilik. Hitung dan cetak nilai keuntungan secara berkala. Kemudian, berdasarkan informasi aset akun terbaru, rasio saldo mata uang spot (saldo posisi spot) dihitung. Ketika ambang deviasi dipicu, order kecil ditutup untuk memulihkan mata uang (posisi) ke keadaan seimbang. Tunggu selama jangka waktu tertentu untuk menyelesaikan transaksi, lalu batalkan semua pesanan yang tertunda. Putaran pelaksanaan fungsi ini selanjutnya akan memeriksa saldo lagi dan melakukan pemrosesan yang sesuai.
Mari kita lihat kode fungsi ini baris demi baris:
Kalimat pertamavar account = exchange.GetAccount()Ini mendeklarasikan variabel lokalaccount, dan memanggil antarmuka API penemuexchange.GetAccount()Fungsi, dapatkan data terkini dari akun saat ini dan tetapkan keaccountvariabel. Kemudian hakimaccountVariabel ini, jika variabelnya adalahnullJika nilai (seperti batas waktu, jaringan, pengecualian antarmuka pertukaran, dll.) gagal diperoleh, maka akan dikembalikan secara langsung (sesuai denganif (!account){...}Di Sini).
self.account = accountKalimat ini untuk meletakkan variabel lokalaccountDitugaskan ke objek yang dibangunaccountAtribut digunakan untuk mencatat informasi akun terkini dalam objek yang dibangun.
var now = new Date().getTime()Pernyataan ini mendeklarasikan variabel lokalnow, dan memanggil objek waktu dan tanggal bahasa JavaScriptgetTime()Fungsi ini mengembalikan stempel waktu saat ini. Menetapkan kenowvariabel.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}Kode ini menentukan apakah perbedaan antara stempel waktu saat ini dan stempel waktu terakhir yang direkam melebihi parameterCalcNetInterval * 1000Artinya sejak pembaruan terakhir hingga sekarang, lebih dariCalcNetInterval * 1000milidetik(CalcNetIntervaldetik), untuk mencapai fungsi pengaturan waktu pencetakan pendapatan. Karena harga penawaran pertama digunakan saat menghitung pendapatan, kondisinya juga membatasiself.orderBook.Bids.length > 0Kondisi ini (data kedalaman, harus ada informasi perlengkapan yang valid dalam daftar pesanan beli). Ketika kondisi pernyataan if ini dipicu, eksekusiself.preCalc = nowPerbarui variabel stempel waktu pendapatan cetak terbaruself.preCalcStempel waktu saat ininow. Statistik pendapatan di sini menggunakan metode perhitungan nilai bersih, kodenya adalahvar net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)), yaitu mengkonversi koin menjadi uang (penyebut) sesuai dengan harga beli saat ini, lalu menambahkannya ke jumlah uang di akun dan menetapkannya ke variabel lokal yang dideklarasikannet. Tentukan apakah total nilai bersih saat ini konsisten dengan total nilai bersih yang tercatat terakhir kali:
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
Jika tidak konsisten,net != self.preNetJika benar, gunakannetPembaruan variabel digunakan untuk mencatat properti nilai bersihself.preNet. Kemudian cetak ininetData total kekayaan bersih ke grafik kurva keuntungan robot platform perdagangan kuantitatif penemu (dapat ditanyakan dalam dokumen API FMZLogProfitfungsi ini).
Jika pendapatan pencetakan terjadwal tidak terpicu, lanjutkan dengan proses berikut.account.Stocks(jumlah koin yang tersedia di rekening giro),account.Balance(Jumlah uang yang tersedia di rekening saat ini) dicatat dalamself.btc,self.cny. Hitung rasio offset dan tetapkan nilainya ke rekamanself.p。
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
Algoritmanya pun sangat sederhana, yakni menghitung nilai koin saat ini sebagai persentase dari total nilai bersih akun.
Jadi bagaimana kita menentukan kapan keseimbangan uang (posisi) dipicu?
Penulis menggunakan 2 poin persentase di atas dan di bawah 50% sebagai buffer, dan melakukan keseimbangan di luar buffer, yaitu,self.p < 0.48Ketika penyimpangan keseimbangan koin dipicu, diyakini bahwa ada lebih sedikit koin, jadi tiga pesanan kecil ditempatkan dimulai dari posisi pembelian pertama di pasar dan meningkatkan harga sebesar 0,01 setiap kali. Demikian pula dengan keseimbangan mata uangself.p > 0.52, jika Anda merasa memiliki terlalu banyak koin, Anda dapat mengajukan pesanan kecil dengan menjual pada harga pembukaan. Terakhir, tunggu beberapa saat sesuai dengan pengaturan parameterSleep(BalanceTimeout)Semua pesanan akan dibatalkan setelahnya.
var orders = exchange.GetOrders() # 获取当前所有挂单,存在orders变量
if (orders) { # 如果获取当前挂单数据的变量orders不为null
for (var i = 0; i < orders.length; i++) { # 循环遍历orders,逐个取消订单
if (orders[i].Id != self.tradeOrderId) {
exchange.CancelOrder(orders[i].Id) # 调用exchange.CancelOrder,根据orders[i].Id取消订单
}
}
}
Fungsi tambahan keempat:
Bagian inti dari strategi, yang menjadi sorotan adalah di sini,self.poll = function() {...}Fungsi adalah logika utama dari keseluruhan strategi. Kami juga membahasnya di artikel sebelumnya.main()Fungsi mulai dijalankan dan masukwhileSebelum loop tak terbatas, kita menggunakanvar reaper = LeeksReaper()Membuat objek pemanen daun bawang, lalumain()Panggilan loop dalam fungsireaper.poll()Inilah fungsi yang dipanggil.
self.pollFungsi mulai dijalankan dan melakukan beberapa pekerjaan persiapan sebelum setiap perulangan.self.numTick++Tingkatkan hitungannya,self.updateTrades()Perbarui catatan transaksi pasar terkini dan hitung data yang relevan.self.updateOrderBook()Perbarui data buku pesanan dan hitung data terkait.self.balanceAccount()Periksa saldo uang (posisi).
var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct # 计算爆发价格
var bull = false # 声明牛市标记的变量,初始为假
var bear = false # 声明熊市标记的变量,初始为假
var tradeAmount = 0 # 声明交易数量变量,初始为0
Langkah berikutnya adalah menentukan apakah pasar jangka pendek saat ini bullish atau bearish.
if (self.numTick > 2 && (
self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -1)) > burstPrice ||
self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -2)) > burstPrice && self.prices[self.prices.length-1] > self.prices[self.prices.length-2]
)) {
bull = true
tradeAmount = self.cny / self.bidPrice * 0.99
} else if (self.numTick > 2 && (
self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -1)) < -burstPrice ||
self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -2)) < -burstPrice && self.prices[self.prices.length-1] < self.prices[self.prices.length-2]
)) {
bear = true
tradeAmount = self.btc
}
Ingat, pada artikel sebelumnyaself.updateOrderBook()fungsi, di mana kita menggunakan algoritma rata-rata tertimbang untuk membangun deret waktu dengan urutanpricesSusunan. Tiga fungsi baru digunakan dalam kode ini_.min,_.max,sliceKetiga fungsi ini juga sangat mudah dipahami.
_.min: Fungsinya untuk mencari nilai terkecil pada array parameter.
_.max: Fungsinya untuk mencari nilai terbesar pada array parameter.
slice: Fungsi ini adalah fungsi anggota dari objek array JavaScript. Fungsinya adalah untuk mencegat bagian dari array menurut indeks dan mengembalikannya. Misalnya:
function main() {
// index .. -8 -7 -6 -5 -4 -3 -2 -1
var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Log(arr.slice(-5, -1)) // 会截取 4 ~ 1 这几个元素,返回一个新数组:[4,3,2,1]
}

Kondisi untuk menilai beruang dan banteng di sini adalah:
self.numTick > 2Agar dapat ditetapkan, artinya ketika putaran harga deteksi baru muncul, hal itu harus dipicu setelah setidaknya tiga putaran deteksi agar tidak dipicu di awal.self.pricesData terakhir diself.pricesPerbedaan antara harga maksimum atau minimum pada rentang sebelumnya dalam array harus dipecahburstPriceIni adalah harga ledakan.Jika semua syarat terpenuhi maka tandaibullataubear,untuktrue, dan memberitradeAmountTetapkan variabel dan rencanakan perdagangan Stud.
Sesuai dengan yang sebelumnyaself.updateTrades()Diperbarui dan dihitung dalam fungsiself.vol, untuk parameternyaBurstThresholdVolPutuskan apakah akan mengurangi intensitas perdagangan (mengurangi ukuran perdagangan yang direncanakan).
if (self.vol < BurstThresholdVol) {
tradeAmount *= self.vol / BurstThresholdVol // 缩减计划交易量,缩减为之前量的self.vol / BurstThresholdVol 倍
}
if (self.numTick < 5) {
tradeAmount *= 0.8 // 缩减为计划的80%
}
if (self.numTick < 10) { // 缩减为计划的80%
tradeAmount *= 0.8
}
Selanjutnya, tentukan apakah sinyal perdagangan dan volume perdagangan memenuhi persyaratan:
if ((!bull && !bear) || tradeAmount < MinStock) { # 如果非牛市并且也非熊市,或者计划交易的量tradeAmount小于参数设置的最小交易量MinStock,poll函数直接返回,不做交易操作
return
}
Setelah putusan di atas, jalankanvar tradePrice = bull ? self.bidPrice : self.askPriceTetapkan harga transaksi berdasarkan apakah itu pasar melemah atau pasar menguat, dan tetapkan nilai dengan harga bill of lading yang sesuai.
Akhirnya masuk kewhileSatu-satunya syarat untuk menghentikan loop adalahtradeAmount >= MinStockVolume transaksi yang direncanakan kurang dari volume transaksi minimum.
Dalam loop, pesanan ditempatkan berdasarkan apakah pasar saat ini bullish atau bearish. Dan catat ID pesanan dalam variabelorderId. Setelah setiap putaran pemesananSleep(200)Tunggu 200 milidetik. Kemudian menilai dalam lingkaranorderIdApakah benar (jika pesanan gagal, ID pesanan tidak akan dikembalikan dan kondisi if tidak akan dipicu), jika kondisinya benar. Dapatkan ID pesanan dan tetapkan keself.tradeOrderId。
Nyatakan variabel untuk menyimpan data pesananorderNilai awalnya adalahnull. Kemudian lakukan loop untuk mendapatkan data pesanan dari ID ini, dan tentukan apakah pesanan tersebut berstatus pending order. Jika berstatus pending order, batalkan pesanan dari ID ini. Jika tidak berstatus pending order, keluar dari ID ini. lingkaran deteksi.
var order = null // 声明一个变量用于保存订单数据
while (true) { // 一个while循环
order = exchange.GetOrder(orderId) // 调用GetOrder查询订单ID为 orderId的订单数据
if (order) { // 如果查询到订单数据,查询失败order为null,不会触发当前if条件
if (order.Status == ORDER_STATE_PENDING) { // 判断订单状态是不是正在挂单中
exchange.CancelOrder(orderId) // 如果当前正在挂单,取消该订单
Sleep(200)
} else { // 否则执行break跳出当前while循环
break
}
}
}
Kemudian ikuti proses di bawah ini:
self.tradeOrderId = 0 // 重置self.tradeOrderId
tradeAmount -= order.DealAmount // 更新tradeAmount,减去提单的订单已经成交的数量
tradeAmount *= 0.9 // 减小下单力度
if (order.Status == ORDER_STATE_CANCELED) { // 如果订单已经是取消了
self.updateOrderBook() // 更新订单薄等数据
while (bull && self.bidPrice - tradePrice > 0.1) { // 牛市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格
tradeAmount *= 0.99
tradePrice += 0.1
}
while (bear && self.askPrice - tradePrice < -0.1) { // 熊市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格
tradeAmount *= 0.99
tradePrice -= 0.1
}
}
Ketika aliran program melonjak keluarwhile (tradeAmount >= MinStock) {...}Siklus ini menunjukkan bahwa proses transaksi ledakan harga telah selesai.
melaksanakanself.numTick = 0, yaitu, mengatur ulangself.numTickadalah 0.
LeeksReaper()Konstruktor akhirnya dieksekusiselfObjek yang dikembalikan adalahvar reaper = LeeksReaper()Ketika dikembalikan kereaper。
Sejauh iniLeeksReaper()Kami telah menganalisis bagaimana konstruktor membangun objek pemanen daun bawang, berbagai metode objek pemanen daun bawang, dan proses pelaksanaan fungsi logika utama. Saya yakin bahwa setelah membaca artikel ini, Anda akan memiliki pemahaman yang lebih jelas tentang frekuensi tinggi proses algoritma strategi. mengerti.