Dalam desain awal strategi FMZ, jika operasi serentak asinkron diperlukan,exchange.Go()
fungsi hanya dapat digunakan untuk mencapai eksekusi bersamaan antarmuka FMZ terkapsul, dan tidak mungkin untuk secara bersamaan menjalankan beberapa operasi kustom (fungsi). Meskipun desain ini sangat meningkatkan efisiensi program strategi, siswa yang memiliki pengalaman dalam desain bersamaan dalam bahasa pemrograman asli sering merasa sangat tidak nyaman.
Bahkan siswa baru yang menggunakan FMZ untuk perdagangan kuantitatif pengantar mungkin tidak mengerti penggunaanexchange.Go()
menggunakanexchange.Go()
Dalam artikel ini, kita akan mengeksplorasi penggunaan fungsionalitas thread paralel yang baru ditambahkan di platform FMZ:__Thread()
dan fungsi terkait lainnya, serta desain asinkron program strategi.
Jika kita ingin thread utama dari strategi berjalan bersamaan dengan sub-thread yang menjalankan fungsi kustom yang telah kita tulis, kita dapat menggunakan desain yang mirip dengan kode berikut.GetTickerAsync()
dan menulis fungsi spesifik dari fungsi ini. fungsi ini menjalankan loop tak terbatas dan terus memanggil antarmuka FMZ APIGetTicker()
untuk mengambil data pasar.
Kemudian, gunakan pernyataan__threadSetData(0, "ticker", t)
untuk menulis data ke thread utama. nama data adalahticker
dan nilai data adalaht
, yang merupakan nilai pengembalianGetTicker()
.
__threadSetData(0, "ticker", t)
Setelah merancang fungsi kustom untuk eksekusi thread bersamaan, kita dapat menulis kode dimain()
Pada awalmain()
fungsi, kita menggunakan:
__Thread(GetTickerAsync, 0) // GetTickerAsync is a custom function that needs to be executed concurrently, and 0 is the parameter that is passed to the GetTickerAsync function.
Buat thread bersamaan yang memulai pelaksanaanGetTickerAsync()
fungsi.main()
fungsi mulai menjalankan sendiriwhile
lingkaran, di mana ia menerima data diperbarui olehGetTickerAsync()
fungsi dan mencetak:
var t = __threadGetData(0, "ticker")
Log(t)
Contoh kode lengkap:
function GetTickerAsync(index) {
while (true) {
var t = exchanges[index].GetTicker()
__threadSetData(0, "ticker", t)
Sleep(500)
}
}
function main() {
__Thread(GetTickerAsync, 0)
while(true) {
var t = __threadGetData(0, "ticker")
Log(t)
Sleep(1000)
}
}
Tes perdagangan langsung:
Ini adalah salah satu desain aplikasi yang paling sederhana, jadi mari kita lihat beberapa desain persyaratan lainnya.
Kita dapat merancang fungsi untuk membuat 10 thread secara bersamaan, masing-masing menjalankan fungsi penempatan pesanan.main()
fungsi, kita dapat merancangwhile
loop untuk mendeteksi strategi perintah interaksi.placeMultipleOrders
, kita menyebut fungsi penempatan pesanan bersamaantestPlaceMultipleOrders()
.
if (cmd == "placeMultipleOrders") {
// ...
}
Tambahkan desain interaksi strategi pada halaman pengeditan strategi dengan menambahkan tombol dengan perintah: placeMultipleOrders.
Contoh kode lengkap:
function placeOrder(exIndex, type, price, amount) {
var id = null
if (type == "Buy") {
id = exchanges[exIndex].Buy(price, amount)
} else if (type == "Sell") {
id = exchanges[exIndex].Sell(price, amount)
} else {
throw "type error! type:" + type
}
}
function testPlaceMultipleOrders(index, beginPrice, endPrice, step, type, amount) {
Log("beginPrice:", beginPrice, ", endPrice:", endPrice, ", step:", step, ", type:", type, ", amount:", amount)
var tids = []
for (var p = beginPrice; p <= endPrice; p += step) {
var tid = __Thread(placeOrder, index, type, p, amount)
tids.push(tid)
Sleep(10)
}
Sleep(1000)
for (var i = 0; i < tids.length; i++) {
__threadTerminate(tids[i])
}
}
function main() {
while(true) {
LogStatus(_D())
var cmd = GetCommand()
if (cmd) {
if (cmd == "placeMultipleOrders") {
var t = _C(exchange.GetTicker)
var beginPrice = t.Last * 0.8
var endPrice = t.Last * 0.9
var step = t.Last * 0.01
testPlaceMultipleOrders(0, beginPrice, endPrice, step, "Buy", 0.01)
var orders = exchange.GetOrders()
for (var i = 0; i < orders.length; i++) {
Log(orders[i])
}
}
}
Sleep(1000)
}
}
Setelah mengklik tombol
Persyaratan ini diangkat oleh pengguna FMZ yang ingin contoh sederhana menunjukkan bagaimana menggunakanWebSocketkoneksi pada thread bersamaan dan bagaimana untuk menyampaikan data kemain()
fungsi dalam benang utama.
Sebenarnya, ini cukup sederhana dan mirip dengan membuat thread paralel dalam contoh sebelumnya.__threadPeekMessage()
dan__threadPostMessage()
mengambil panggilan WebSocket API untuk pertukaran Binance sebagai contoh, kita juga perlu menangani operasi penutupan koneksi WebSocket. Contoh berikut menunjukkan cara memberi tahu thread bersamaan untuk berhenti.
Contoh kode lengkap:
var tid = null
function createWS() {
// wss://stream.binance.com:9443/ws/<streamName> , <symbol>@ticker
var stream = "wss://stream.binance.com:9443/ws/btcusdt@ticker"
var ws = Dial(stream)
Log("Create a WS connection:", stream)
while (true) {
var data = ws.read()
if (data) {
__threadPostMessage(0, data)
}
Log("receiving data pushed by the WS link, data:", data)
// __threadPeekMessage timeout parameter set to -1, no blocking
var msg = __threadPeekMessage(-1)
if (msg) {
if (msg == "stop") {
Log("Concurrent Thread Id:", __threadId(), "Received stop command")
break
}
}
}
Log("Concurrent threads finish execution, close ws connection")
ws.close()
}
function main() {
tid = __Thread(createWS)
Log("Create concurrent threads, thread Id:", tid)
while(true) {
// __threadPeekMessage's timeout parameter is set to 0, blocking for data
var data = __threadPeekMessage(0)
Log("Received from concurrent thread", ", Id:", tid, ", the data sent, data:", data, "#FF0000")
var tbl = {
type : "table",
title : "<symbol>@ticker channel push message",
cols : ["Event Type", "Event Time", "Trading Pairs", "24 Hour Price Change", "24 Hour Price Change %", "Average Price", "Last Traded Price", "Volume in 24 Hours", "Turnover in 24 Hours"],
rows : []
}
try {
data = JSON.parse(data)
tbl.rows.push([data.e, _D(data.E), data.s, data.p, data.P, data.w, data.c, data.v, data.q])
} catch (e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
}
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
}
}
function onexit() {
Log("Finalize function, send a stop command to the concurrent thread with ID ", tid,"")
__threadPostMessage(tid, "stop")
Log("Wait for the concurrent thread with ID ", tid, " to stop")
__threadJoin(tid)
Log("Finalize function execution completed")
}
Selama pengujian perdagangan langsung, kita dapat melihat bahwamain()
Fungsi terus menerima data pasar dari koneksi WebSocket yang dibuat oleh thread bersamaan.
Saat menghentikan strategi perdagangan langsung, fungsi finalisasi akan mulai bekerja.