Aplikasi fungsi "__Thread" dalam desain strategi JavaScript

Penulis:Lydia, Dibuat: 2023-07-07 13:56:17, Diperbarui: 2023-09-18 19:31:40

img

Aplikasi fungsi __Thread dalam desain strategi JavaScript

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.

1. Desain simultan sederhana

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 adalahtickerdan 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 sendiriwhilelingkaran, 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:

img

Ini adalah salah satu desain aplikasi yang paling sederhana, jadi mari kita lihat beberapa desain persyaratan lainnya.

2. Desain penempatan pesanan bersamaan

Kita dapat merancang fungsi untuk membuat 10 thread secara bersamaan, masing-masing menjalankan fungsi penempatan pesanan.main()fungsi, kita dapat merancangwhileloop 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.

img

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)
    }
}
  • Tes ini mengadopsi pesanan yang sedang menunggu, meningkat dari 80% menjadi 90% dari harga saat ini, dalam lingkungan perdagangan simulasi.

Setelah mengklik tombol placeMultipleOrders, akan muncul pesan: Perintah placeMultipleOrders telah dikirim dengan sukses, harap tunggu tanggapan dari perdagangan langsung!

  • Log strategi menampilkan operasi penempatan pesanan bersamaan:

img

3. Buat koneksi WebSocket dalam fungsi eksekusi thread bersamaan

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.


Berkaitan

Lebih banyak