यह FMZ द्वारा आधिकारिक रूप से विकसित एक वेबसॉकेट बाजार टेम्पलेट है, जिसे टेम्पलेट के रूप में कॉपी किया जा सकता है और नई नीति में इस टेम्पलेट को टैप करके उपयोग किया जा सकता हैःhttps://www.fmz.com/strategy/470349
वर्तमान में एफएमजेड की रणनीति मुख्य रूप से पारंपरिक आरईएसटी एपीआई पैकेजिंग है, जिसमें एपीआई एक्सेस के प्रत्येक चरण में एक नेटवर्क कनेक्शन स्थापित किया जाता है, जो परामर्श के माध्यम से बाजार डेटा प्राप्त करता है। यह तरीका सरल और आसान है, और अधिकांश आवश्यकताओं के लिए ऐसा करना पूरी तरह से पर्याप्त है।
हालांकि, REST प्रोटोकॉल में अंतर्निहित विलंबता समस्या है, जब कई व्यापारिक जोड़े, बहु-विनिमय रणनीतियों की आवश्यकता होती है, तो विलंबता समस्या को बढ़ाया जाता है। हालांकि प्लेटफ़ॉर्म के गो फ़ंक्शन का उपयोग करके समवर्ती रूप से निष्पादित किया जा सकता है, लेकिन विलंबता समस्या अभी भी मौजूद है, जो अपेक्षाकृत उच्च आवृत्ति वाले रणनीतिक व्यापार की आवश्यकता को पूरा करना मुश्किल है, और बहुत अधिक लेनदेन, बहुत तेजी से पूछताछ की आवृत्ति और ट्रेडिंग प्लेटफ़ॉर्म तक पहुंच की आवृत्ति की सीमा का सामना करना पड़ता है।
वर्तमान में एक्सचेंजों का सर्वर लोड भी भारी है, सभी वेबसॉकेट प्रोटोकॉल को पूरा करते हैं, और एपीआई उपयोगकर्ताओं के उपयोग की सिफारिश की जाती है; REST प्रोटोकॉल के मुकाबले, वेबसॉकेट एक स्थायी दो-तरफा कनेक्शन प्रदान करता है, जो एक्सचेंजों को क्लाइंट को वास्तविक समय में डेटा पुश करने की अनुमति देता है, लगातार अनुरोधों और प्रतिक्रियाओं से बचता है, और देरी को बहुत कम करता है। आम तौर पर, यदि REST एपीआई तक पहुंचने की देरी लगभग 20 एमएस है, तो वेबसॉकेट के लिए पुश डेटा में लगभग 2 एमएस की देरी होती है। और लिंक वेबसॉकेट प्रोटोकॉल को प्लेटफॉर्म तक पहुंच की आवृत्ति की सीमा नहीं है, जो मूल रूप से एक बार में दर्जनों लेनदेन के लिए सब्सक्राइब कर सकता है।
एफएमजेड क्वांटिफाइड ट्रेडिंग प्लेटफॉर्म ने वेबसॉकेट प्रोटोकॉल का समर्थन किया है और अपेक्षाकृत सुविधाजनक कॉल किया है, लेकिन नए उपयोगकर्ताओं के लिए, कई सदस्यताओं को संभालना, कई एक्सचेंजों के लिए सदस्यता लेना, और पूरी रणनीति प्रक्रिया में कुशलतापूर्वक और आसानी से एम्बेड करना बहुत जटिल है। यह सार्वजनिक वेबसॉकेट वास्तविक समय बाजार डेटा त्वरण टेम्पलेट इस समस्या को हल करता है, बहुत आसान उपयोग, पूरी तरह से वर्तमान में पैक किए गए एपीआई कॉल के साथ संगत है, और अधिकांश मूल आरईएसटी नीतियों के लिए, सीधे अपनी नीतियों को गति देने के लिए सीधे उपयोग करने के लिए सरल परिवर्तन।
मुख्य विशेषताएंः
ध्यान दें कि यह नीति टाइपस्क्रिप्ट का उपयोग करती है, जो कि यदि आप केवल जावास्क्रिप्ट से परिचित हैं, तो थोड़ा अजीब लग सकता है। टाइपस्क्रिप्ट ने जावास्क्रिप्ट के आधार पर टाइप सिस्टम और अधिक समृद्ध भाषा सुविधाओं को पेश किया है, जो कि जटिल लॉजिक को संभालने की आवश्यकता वाले अनुप्रयोगों जैसे कि मात्रात्मक लेनदेन के लिए है। टाइपस्क्रिप्ट का उपयोग करने से संभावित त्रुटियों को कम किया जा सकता है और कोड की पठनीयता और रखरखाव में सुधार हो सकता है। इसलिए यह सरल सीखने की सिफारिश की जाती है।
इसके अलावा, यह नीति FMZ प्लेटफॉर्म के असिंक्रोनस तंत्र का उपयोग करती है, जिसमें उप-प्रणाली __threadPostMessage फ़ंक्शन के माध्यम से मुख्य थ्रेड को संदेश भेज सकती है। यह विधि असिंक्रोनस है और यह मुख्य थ्रेड को सूचित करने के लिए है कि उप-थ्रेड में उत्पन्न डेटा अद्यतन किया गया है। मुख्य थ्रेड और उप-थ्रेड के बीच __threadGetData और __threadSetData फ़ंक्शन के माध्यम से डेटा साझा किया जा सकता है। यह विधि थ्रेड को साझा की गई स्थिति को देखने और संशोधित करने की अनुमति देती है। यदि आप कई थ्रेडों को सीखना चाहते हैं, तो यह रणनीति प्लेटफॉर्म दस्तावेज़ के साथ मिलकर एक अच्छा सीखने का उदाहरण भी है।
इस रणनीति का मुख्य सिद्धांत मुख्यधारा के डिजिटल मुद्रा एक्सचेंजों को वेबसॉकेट के माध्यम से कनेक्ट करना और वास्तविक समय में बाजार डेटा प्राप्त करना है (जैसे कि गहराई और लेनदेन की जानकारी) ताकि मात्रात्मक लेनदेन निर्णयों के लिए डेटा का समर्थन किया जा सके।
1. वेबसॉकेट कनेक्शन सेटिंग
setupWebsocket
फ़ंक्शन का उपयोग वेबसॉकेट कनेक्शन को आरंभ करने और बाजार डेटा प्राप्त करने के लिए किया जाता है. यह एक पैरामीटर प्राप्त करता हैmain_exchanges
यह एक बहुत ही दिलचस्प और दिलचस्प लेख है।
MyDial
फ़ंक्शन: वेबसॉकेट कनेक्शन बनाना, कनेक्शन का समय रिकॉर्ड करना, और कनेक्शन बंद होने पर आउटपुट बंद होने का समय।updateSymbols
फ़ंक्शन: समय-समय पर जांचें कि क्या कोई नया सदस्यता अनुरोध है और यदि आवश्यक हो तो वर्तमान लेनदेन जोड़ी सूची को अपडेट करें।2. डाटा प्रोसेसिंग
supports
ऑब्जेक्ट समर्थित एक्सचेंजों और उनके प्रसंस्करण कार्यों को परिभाषित करता है (जैसेBinance
) ; प्रत्येक एक्सचेंज के प्रसंस्करण कार्य प्राप्त संदेशों का विश्लेषण करने और संबंधित डेटा निकालने के लिए जिम्मेदार हैं।
processMsg
फ़ंक्शन: एक्सचेंजों से आने वाले संदेशों को संसाधित करना, विभिन्न प्रकार के डेटा (जैसे गहराई से अपडेट, लेनदेन आदि) की पहचान करना और उन्हें एक एकीकृत घटना ऑब्जेक्ट के रूप में स्वरूपित करना।3. सदस्यता डेटा
प्रत्येक कनेक्शन के दौरान, सिस्टम वर्तमान लेनदेन के आधार पर सदस्यता से संबंधित बाजार डेटा चैनल का पता लगाता है।
getFunction
फ़ंक्शन: एक्सचेंज के नाम के आधार पर संबंधित प्रसंस्करण कार्य प्राप्त करें.this.wssPublic
फ़ंक्शन: वेबसॉकेट कनेक्शन को आरंभ करें और डेटा प्राप्त करना प्रारंभ करें.4. थ्रेड प्रबंधन
प्रत्येक एक्सचेंज के लिए एक थ्रेड शुरू करें, वास्तविक समय में डेटा प्राप्त करें और रिकॉल फ़ंक्शन के माध्यम से डेटा संसाधित करें।
threadMarket
फ़ंक्शन: सबथ्रेड में डेटा प्राप्त करें, नवीनतम गहराई और लेनदेन जानकारी को पार्सल और संग्रहीत करें।5. डेटा प्राप्त करने के तरीके को फिर से लिखें
प्रत्येक एक्सचेंज के लिए गहराई और लेनदेन की जानकारी प्राप्त करने के तरीके को फिर से लिखना, वास्तविक समय में अपडेट किए गए डेटा को प्राथमिकता देना।
$.setupWebsocket()
लक्ष्य एक्सचेंजों के लिए वेबसॉकेट कनेक्शन को आरंभ करना।GetDepth()
औरGetTrades()
फ़ंक्शन, जो स्वचालित रूप से वेबसॉकेट के वास्तविक समय के डेटा का उपयोग करके बाजार की गहराई और लेनदेन रिकॉर्ड के लिए करता है।यदि नीति में EventLoop () फ़ंक्शन जोड़ा जाता है, तो इसे ट्रिगर में बदल दिया जाता है, जब कोई wss डेटा अपडेट होता है तो यह स्वचालित रूप से तुरंत प्राप्त होता है, कोई अद्यतन डेटा नहीं होता है। स्मार्ट स्लीप फ़ंक्शन के बराबर, आप सीधे स्लीप का उपयोग कर सकते हैं।
function main() {
$.setupWebsocket()
while (true) {
exchanges.map(e=>{
Log(e.GetName(), e.GetDepth())
Log(e.GetName(), e.GetTrades())
})
EventLoop(100) // trigger by websocket
}
}
मेरा पिछला लेख देखें बहु मुद्रा व्यापार रणनीति गाइडhttps://www.fmz.com/digest-topic/10506यह एक बहुत ही सुविधाजनक तरीका है वेबसॉकेट समर्थन के लिए इसे बदलने के लिएः
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);
}
}
यदि आप नीति के टेम्पलेट का पालन करते हैं, तो आप नीचे दिए गए प्रारूप की नकल कर सकते हैं और अपने स्वयं के एक्सचेंज एपीआई दस्तावेजों का संदर्भ ले सकते हैंः
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)
}
}
}
}