Sumber daya yang dimuat... Pemuatan...

Sebuah template kebijakan yang memungkinkan Anda untuk menggunakan WebSocket secara mulus

Penulis:Rumput, Dibuat: 2024-10-30 09:49:20, Diperbarui: 2024-11-05 17:45:31

img

Ini adalah template pasar WebSocket yang dikembangkan secara resmi oleh FMZ, yang dapat disalin dan disimpan sebagai template yang dapat digunakan dengan mengkliknya di kebijakan baru:https://www.fmz.com/strategy/470349

Mengapa WebSocket Dibutuhkan

Strategi FMZ saat ini sebagian besar adalah pembungkus REST API tradisional, dimana setiap langkah akses API membangun koneksi jaringan untuk mendapatkan data pasar melalui metode konsultasi.

Namun, protokol REST memiliki masalah keterlambatan yang inheren, dimana masalah keterlambatan akan diperkuat ketika diperlukan banyak pasangan perdagangan, strategi multi-bursa. Meskipun fungsi Go dapat dijalankan secara paralel dengan platform, masalah keterlambatan masih ada, sulit untuk memenuhi kebutuhan perdagangan strategi yang relatif tinggi, dan terlalu banyak transaksi, frekuensi routing terlalu cepat dan akan menghadapi batasan frekuensi akses platform perdagangan.

Bursa saat ini juga memiliki beban server yang berat, yang semuanya menyediakan protokol WebSocket yang sempurna, dan pengguna API disarankan untuk menggunakannya. Dibandingkan dengan protokol REST, WebSocket memberikan koneksi dua arah yang tahan lama, yang memungkinkan bursa untuk memajukan data ke klien secara real-time, menghindari permintaan dan respons yang sering, dan sangat mengurangi keterlambatan.

WebSocket Industri Template Pengantar

FMZ Quantitative Trading Platform mendukung protokol WebSocket sejak awal dan relatif mudah untuk dihubungi, tetapi untuk pengguna baru, memproses beberapa langganan, berlangganan beberapa pasar bursa, dan secara efisien dan mudah dimasukkan ke dalam seluruh proses strategi terlalu rumit. Template WebSocket Real-time Market Data Accelerator yang terbuka ini memecahkan masalah ini, sangat mudah digunakan, sepenuhnya kompatibel dengan panggilan API yang saat ini terbungkus, untuk sebagian besar kebijakan REST asli, perubahan sederhana langsung digunakan untuk mempercepat kebijakan Anda.

Fitur Utama:

  • Dukungan dari BursaKebijakan ini mendukung koneksi WebSocket dari berbagai pertukaran seperti Bitcoin, OKX, ByBit, Bitget, dan lain-lain. Pengguna dapat meniru metode pembungkus template ini untuk mendukung lebih banyak pertukaran.
  • Langganan dapat disesuaikan: Memungkinkan untuk berlangganan saluran pasar tertentu (seperti kedalaman, perdagangan, dll) dan memproses data yang diterima secara efisien untuk strategi perdagangan yang dapat digunakan secara instan.
  • Pengelolaan kesalahan tingkat tinggiFungsi ini dapat dilakukan dengan cara: Memperbaiki sistem operasi, memperkuat sistem operasi, memperkuat sistem operasi, dan meningkatkan kinerja.

Penjelasan sederhana tentang implementasi

Perhatikan bahwa kebijakan ini menggunakan TypeScript, yang akan terlihat sedikit asing jika Anda hanya akrab dengan JavaScript. TypeScript memperkenalkan sistem tipe dan fitur bahasa yang lebih kaya berdasarkan JavaScript, untuk aplikasi yang membutuhkan pengolahan logika yang rumit seperti transaksi kuantitatif. Menggunakan TypeScript dapat mengurangi potensi kesalahan, meningkatkan keterbacaan dan pemeliharaan kode.

Kebijakan ini juga menggunakan mekanisme asinkronisasi dari platform FMZ, dimana sub-threads dapat mengirim pesan ke thread utama melalui fungsi __threadPostMessage. Cara ini tidak asinkron dan digunakan untuk memberi tahu thread utama tentang pembaruan data yang dihasilkan di sub-threads. Data dapat dibagikan antara thread utama dan sub-threads melalui fungsi __threadGetData dan __threadSetData.

Prinsip utama dari strategi ini adalah menghubungkan pertukaran mata uang digital utama melalui WebSocket untuk menerima data pasar secara real-time (seperti informasi mendalam dan informasi transaksi) untuk memberikan dukungan data untuk membuat keputusan transaksi kuantitatif. Secara khusus, prosesnya adalah sebagai berikut:

1. Koneksi WebSocket

setupWebsocketFungsi ini digunakan untuk menginisialisasi koneksi WebSocket, menerima data pasar.main_exchanges"Selain itu, saya juga ingin berbagi pengalaman saya dengan orang-orang di sekitar saya.

  • MyDialFungsi: Membuat koneksi WebSocket, mencatat waktu koneksi, dan output waktu penutupan saat koneksi ditutup.
  • updateSymbolsFungsi: Periodik memeriksa apakah ada permintaan langganan baru dan memperbarui daftar pasangan transaksi saat ini sesuai kebutuhan.

2. Pengolahan data

supportsObjek mendefinisikan pertukaran yang didukung dan fungsi pengolahannya (misalnyaBinanceFungsi pemrosesan setiap bursa bertanggung jawab untuk menganalisis pesan yang diterima dan mengekstrak data yang relevan.

  • processMsgFungsi: memproses pesan dari bursa, mengidentifikasi berbagai jenis data (seperti pembaruan mendalam, transaksi, dll) dan memformatnya menjadi objek acara yang seragam.

3. Data langganan

Pada setiap koneksi, sistem akan membagikan saluran data pasar yang terkait dengan langganan berdasarkan transaksi saat ini.

  • getFunctionFungsiFungsi pengolahan yang sesuai dengan nama bursa.
  • this.wssPublicFungsi: Inisialisasi koneksi WebSocket dan memulai penerimaan data.

4. Manajemen thread

Memulai satu thread untuk setiap bursa, menerima data secara real-time dan memproses data melalui fungsi callback.

  • threadMarketFungsi: Mengambil data dalam sub-thread, menguraikan dan menyimpan informasi kedalaman dan transaksi terbaru.

5. Menulis ulang metode pengambilan data

Cara menulis ulang untuk mendapatkan informasi kedalaman dan transaksi untuk setiap bursa, dengan memprioritaskan kembali data yang diperbarui secara real-time.

Cara menggunakan template

  1. InisialisasiPenggunaan:$.setupWebsocket()Inisialisasi koneksi WebSocket dari bursa target.
  2. Subscribe: Sistem akan secara otomatis berlangganan saluran yang terkait dengan jenis perdagangan Anda (seperti kedalaman, perdagangan, dll.).
  3. Mendapatkan dataDengan panggilan telepon:GetDepth()danGetTrades()Fungsi yang secara otomatis menggunakan data WebSocket real-time untuk mengembalikan kedalaman pasar dan catatan transaksi.
  4. Pengelolaan yang salahKebijakan: termasuk mekanisme pelacakan untuk mencatat kesalahan koneksi dan data, dan mencoba koneksi kembali secara otomatis ketika koneksi terputus.

Jika Anda menambahkan fungsi EventLoop (,) ke dalam kebijakan, itu akan berubah menjadi mekanisme pemicu, yang akan secara otomatis segera diambil ketika ada pembaruan data wss, dan tidak ada data terbaru yang menunggu.

function main() {
    $.setupWebsocket()
    while (true) {
        exchanges.map(e=>{
            Log(e.GetName(), e.GetDepth())
            Log(e.GetName(), e.GetTrades())
        })
        EventLoop(100) // trigger by websocket
    }
}

Lihat artikel saya sebelumnya tentang strategi perdagangan multi mata uang.https://www.fmz.com/digest-topic/10506Di sini Anda dapat dengan mudah mengubahnya untuk mendukung WebSocket:

function MakeOrder() {
    for (let i in Info.trade_symbols) {
        let symbol = Info.trade_symbols[i];
        let buy_price = exchange.GetDepth(symbol + '_USDT').Asks[0].Price;
        let buy_amount = 50 / buy_price;
        if (Info.position[symbol].value < 2000){
            Trade(symbol, "buy", buy_price, buy_amount, symbol);
        }
    }
}

function OnTick() {
    try {
        UpdatePosition();
        MakeOrder();
        UpdateStatus();
    } catch (error) {
        Log("循环出错: " + error);
    }
}

function main() {
    $.setupWebsocket()
    InitInfo();
    while (true) {
        let loop_start_time = Date.now();
        if (Date.now() - Info.time.last_loop_time > Info.interval * 1000) {
            OnTick();
            Info.time.last_loop_time = Date.now();
            Info.time.loop_delay = Date.now() - loop_start_time;
        }
        Sleep(5);
    }
}

Cara menambahkan bursa baru sendiri

Jika Anda mengikuti pola kebijakan dan meniru format di bawah ini, Anda dapat menggunakan dokumen API:

    supports["Binance"] = function (ctx:ICtx) {
        let processMsg = function (obj) {
            let event = {
                ts: obj.E,
                instId: obj.s,
                depth: null,
                trades: [],
            }

            if (obj.e == "depthUpdate") {
                let depth = {
                    asks: [],
                    bids: []
                }
                obj.b.forEach(function (item) {
                    depth.bids.push({
                        price: Number(item[0]),
                        qty: Number(item[1])
                    })
                })
                obj.a.forEach(function (item) {
                    depth.asks.push({
                        price: Number(item[0]),
                        qty: Number(item[1])
                    })
                })
                event.depth = depth
            } else if (obj.e == 'bookTicker') {
                event.depth = {
                    asks: [{ price: Number(obj.a), qty: Number(obj.A) }],
                    bids: [{ price: Number(obj.b), qty: Number(obj.B) }]
                }
            } else if (obj.e == 'aggTrade') {
                event.ts = obj.E
                event.trades = [{
                    price: Number(obj.p),
                    qty: Number(obj.q),
                    ts: obj.T,
                    side: obj.m ? "sell" : "buy"
                }]
            } else if (typeof (obj.asks) !== 'undefined') {
                event.ts = obj.E || new Date().getTime()
                let depth = {
                    asks: [],
                    bids: []
                }
                obj.bids.forEach(function (item) {
                    depth.bids.push({
                        price: Number(item[0]),
                        qty: Number(item[1])
                    })
                })
                obj.asks.forEach(function (item) {
                    depth.asks.push({
                        price: Number(item[0]),
                        qty: Number(item[1])
                    })
                })
                event.depth = depth
            } else {
                return
            }
            return event
        }
        let channels = ["depth20@100ms", /*"bookTicker", */"aggTrade"]
 
        let ws = null
        let endPoint = "wss://stream.binance.com/stream"
        if (ctx.name == "Futures_Binance") {
            endPoint = "wss://fstream.binance.com/stream"
        }
        
        while (true) {
            if (!ws) {
                let subscribes = []
                ctx.symbols.forEach(function (symbol) {
                    channels.forEach(function (channel) {
                        subscribes.push(symbol.toLowerCase() + "@" + channel)
                    })
                })
                ws = MyDial(endPoint + (subscribes.length > 0 ? ("?streams=" + subscribes.join("/")) : ""))
            }
            if (!ws) {
                Sleep(1000)
                continue
            }
            updateSymbols(ctx, function(symbol:string, method:string) {
                ws.write(JSON.stringify({ 
                    "method": method.toUpperCase(), 
                    "params": channels.map(c=>symbol.toLowerCase()+'@'+c),
                    "id": 2
                }))
            })
            let msg = ws.read(1000)
            if (!msg) {
                if (msg == "") {
                    trace("websocket is closed")
                    ws.close()
                    ws = null
                }
                continue
            }
            if (msg == 'ping') {
                ws.write('pong')
            } else if (msg == 'pong') {

            } else {
                let obj = JSON.parse(msg)
                if (obj.error) {
                    trace(obj.error.msg, "#ff0000")
                    continue
                }
                if (!obj.stream) {
                    continue
                }
                if (obj.stream.indexOf("depth") != -1) {
                    if (typeof(obj.data.s) !== 'string') {
                        // patch
                        obj.data.s = obj.stream.split('@')[0].toUpperCase()
                    }
                }
                let event = processMsg(obj.data)
                if (event) {
                    ctx.callback(event)
                }
            }
        }
    }
    

Lebih banyak