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
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.
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:
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
setupWebsocket
Fungsi 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.
MyDial
Fungsi: Membuat koneksi WebSocket, mencatat waktu koneksi, dan output waktu penutupan saat koneksi ditutup.updateSymbols
Fungsi: Periodik memeriksa apakah ada permintaan langganan baru dan memperbarui daftar pasangan transaksi saat ini sesuai kebutuhan.2. Pengolahan data
supports
Objek mendefinisikan pertukaran yang didukung dan fungsi pengolahannya (misalnyaBinance
Fungsi pemrosesan setiap bursa bertanggung jawab untuk menganalisis pesan yang diterima dan mengekstrak data yang relevan.
processMsg
Fungsi: 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.
getFunction
FungsiFungsi pengolahan yang sesuai dengan nama bursa.this.wssPublic
Fungsi: 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.
threadMarket
Fungsi: 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.
$.setupWebsocket()
Inisialisasi koneksi WebSocket dari bursa target.GetDepth()
danGetTrades()
Fungsi yang secara otomatis menggunakan data WebSocket real-time untuk mengembalikan kedalaman pasar dan catatan transaksi.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);
}
}
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)
}
}
}
}