3
ध्यान केंद्रित करना
1444
समर्थक

एक नीति टेम्पलेट आपको वेबसॉकेट मार्केट का सहजता से उपयोग करने की अनुमति देता है

में बनाया: 2024-10-30 09:49:20, को अपडेट: 2024-11-05 17:45:31
comments   0
hits   1637

एक नीति टेम्पलेट आपको वेबसॉकेट मार्केट का सहजता से उपयोग करने की अनुमति देता है

यह FMZ द्वारा आधिकारिक रूप से विकसित एक WebSocket मार्केट टेम्पलेट है। इसे कॉपी करके टेम्पलेट के रूप में सेव करें, फिर इसका उपयोग करने के लिए नई रणनीति में इस टेम्पलेट का चयन करें: https://www.fmz.com/strategy/470349

हमें वेबसॉकेट की आवश्यकता क्यों है?

वर्तमान में, FMZ रणनीति मुख्य रूप से पारंपरिक REST API एनकैप्सुलेशन पर आधारित है। प्रत्येक API एक्सेस के लिए नेटवर्क कनेक्शन स्थापित करना और पोलिंग के माध्यम से बाज़ार डेटा प्राप्त करना आवश्यक है। यह विधि सरल एवं प्रयोग में आसान है, तथा अधिकांश आवश्यकताओं के लिए पर्याप्त है।

हालाँकि, REST प्रोटोकॉल में अंतर्निहित विलंबता की समस्याएँ हैं, जो तब और बढ़ जाएँगी जब कई व्यापारिक जोड़े और कई एक्सचेंज रणनीतियों की आवश्यकता होगी। हालाँकि प्लेटफ़ॉर्म के गो फ़ंक्शन को समवर्ती रूप से निष्पादित किया जा सकता है, फिर भी देरी की समस्या मौजूद है, जो अपेक्षाकृत उच्च-आवृत्ति रणनीति ट्रेडिंग की ज़रूरतों को पूरा करना मुश्किल बनाता है। इसके अलावा, अगर बहुत सारे ट्रेडिंग जोड़े हैं और पोलिंग फ़्रीक्वेंसी बहुत ज़्यादा है तेजी से, यह व्यापार मंच की पहुँच आवृत्ति सीमा का सामना करेगा।

वर्तमान में, एक्सचेंजों के सर्वर भी भारी बोझ के नीचे हैं। वे सभी एक पूर्ण WebSocket प्रोटोकॉल प्रदान करते हैं और API उपयोगकर्ताओं को इसकी अनुशंसा करते हैं। REST प्रोटोकॉल की तुलना में, WebSocket एक स्थायी दो-तरफ़ा कनेक्शन विधि प्रदान करता है, जो एक्सचेंज को वास्तविक समय में क्लाइंट तक डेटा भेजने में सक्षम बनाता है, जिससे बार-बार अनुरोध और प्रतिक्रियाओं से बचा जा सकता है और विलंबता को बहुत कम किया जा सकता है। सामान्यतया, यदि REST API तक पहुंचने की विलंबता लगभग 20ms है, तो WebSocket के माध्यम से डेटा पुश करने की विलंबता लगभग 2ms है। इसके अलावा, वेबसॉकेट प्रोटोकॉल प्लेटफॉर्म की एक्सेस आवृत्ति द्वारा सीमित नहीं है, और एक समय में दर्जनों ट्रेडिंग जोड़े की सदस्यता लेना मूल रूप से संभव है।

वेबसॉकेट कोट टेम्पलेट का परिचय

FMZ क्वांटिटेटिव ट्रेडिंग प्लेटफॉर्म ने लंबे समय तक वेबसॉकेट प्रोटोकॉल का समर्थन किया है, और यह कॉल करने के लिए अपेक्षाकृत सुविधाजनक है, लेकिन नौसिखिए उपयोगकर्ताओं के लिए, कई सदस्यता को संभालना, कई एक्सचेंज कोट्स की सदस्यता लेना और उन्हें कुशलतापूर्वक और सुविधाजनक रूप से एम्बेड करना अभी भी बहुत जटिल है। संपूर्ण रणनीति प्रक्रिया.. यह सार्वजनिक WebSocket वास्तविक समय बाजार डेटा त्वरण टेम्पलेट इस समस्या को हल करता है। इसका उपयोग करना बहुत आसान है और वर्तमान एनकैप्सुलेटेड API कॉल के साथ पूरी तरह से संगत है। अधिकांश मूल REST रणनीतियों के लिए, आप उन्हें आसानी से संशोधित कर सकते हैं और उन्हें सीधे गति देने के लिए उपयोग कर सकते हैं अपनी रणनीति.

प्रमुख विशेषताऐं:

  • एकाधिक एक्सचेंजों का समर्थनयह रणनीति कई एक्सचेंजों जैसे कि बिनेंस, ओकेएक्स, बायबिट, बिटगेट आदि के वेबसोकेट कनेक्शन का समर्थन करती है। उपयोगकर्ता स्वयं अधिक एक्सचेंजों का समर्थन करने के लिए इस टेम्पलेट की पैकेजिंग विधि का अनुकरण कर सकते हैं।
  • अनुकूलन योग्य सदस्यता: विशिष्ट बाजार चैनलों (जैसे गहराई, व्यापार, आदि) की सदस्यता और व्यापार रणनीतियों द्वारा तत्काल उपयोग के लिए प्राप्त आंकड़ों के कुशल प्रसंस्करण की अनुमति देता है।
  • उन्नत त्रुटि प्रबंधनडेटा प्रवाह की विश्वसनीयता और निरंतरता सुनिश्चित करने के लिए अंतर्निहित त्रुटि ट्रैकिंग और वेबसॉकेट पुन: कनेक्शन तंत्र।

कार्यान्वयन सिद्धांत का संक्षिप्त परिचय

ध्यान दें कि यह रणनीति टाइपस्क्रिप्ट का उपयोग करती है, जो थोड़ा अपरिचित लग सकता है यदि आप केवल जावास्क्रिप्ट से परिचित हैं। टाइपस्क्रिप्ट जावास्क्रिप्ट पर आधारित एक प्रकार प्रणाली और समृद्ध भाषा सुविधाएँ पेश करता है। मात्रात्मक व्यापार जैसे अनुप्रयोगों के लिए जिन्हें जटिल तर्क को संसाधित करने की आवश्यकता होती है, टाइपस्क्रिप्ट का उपयोग करके संभावित त्रुटियों को कम किया जा सकता है और कोड की पठनीयता और रखरखाव में सुधार किया जा सकता है। इसलिए, इसे सरलता से सीखने की सिफारिश की जाती है।

इसके अलावा, रणनीति FMZ मंच के अतुल्यकालिक तंत्र का उपयोग करती है, और तंत्र उप-थ्रेड कोथ्रेडपोस्टमैसेज फ़ंक्शन मुख्य थ्रेड को एक संदेश भेजता है। यह विधि अतुल्यकालिक है और चाइल्ड थ्रेड में उत्पन्न डेटा अपडेट की सूचना मुख्य थ्रेड को देने के लिए उपयुक्त है। मुख्य थ्रेड और चाइल्ड थ्रेड को किसके माध्यम से जोड़ा जा सकता है?threadGetData और__threadSetData फ़ंक्शन डेटा साझा करता है. यह दृष्टिकोण थ्रेड्स को साझा स्थिति तक पहुंचने और उसे संशोधित करने की अनुमति देता है। यदि आप मल्टीथ्रेडिंग के बारे में सीखना चाहते हैं, तो यह रणनीति प्लेटफ़ॉर्म दस्तावेज़ीकरण के साथ संयोजन में सीखने का एक अच्छा उदाहरण भी है।

इस रणनीति का मुख्य सिद्धांत वेबसॉकेट के माध्यम से मुख्यधारा के डिजिटल मुद्रा एक्सचेंजों से जुड़ना और मात्रात्मक व्यापार निर्णयों के लिए डेटा समर्थन प्रदान करने के लिए वास्तविक समय में बाजार डेटा (जैसे गहन जानकारी और लेनदेन की जानकारी) प्राप्त करना है। विशिष्ट कार्यान्वयन प्रक्रिया इस प्रकार है:

1. वेबसॉकेट कनेक्शन सेटिंग्स

setupWebsocket इस फ़ंक्शन का उपयोग वेबसॉकेट कनेक्शन को आरंभ करने और बाज़ार डेटा प्राप्त करने के लिए किया जाता है। यह एक पैरामीटर प्राप्त करता हैmain_exchanges, जो उस एक्सचेंज को इंगित करता है जिसे कनेक्ट करने की आवश्यकता है।

  • MyDial समारोह: एक वेबसॉकेट कनेक्शन बनाएं, कनेक्शन समय रिकॉर्ड करें, और कनेक्शन बंद होने पर बंद समय आउटपुट करें।
  • updateSymbols समारोह: नए सदस्यता अनुरोधों की नियमित जांच करें और आवश्यकतानुसार वर्तमान ट्रेडिंग जोड़ी सूची को अपडेट करें।

2. डेटा प्रोसेसिंग

supports ऑब्जेक्ट समर्थित एक्सचेंजों और उनके प्रसंस्करण कार्यों (जैसेBinance). प्रत्येक एक्सचेंज का प्रसंस्करण कार्य प्राप्त संदेशों को पार्स करने और प्रासंगिक डेटा निकालने के लिए जिम्मेदार होता है।

  • processMsg समारोहएक्सचेंजों से संदेशों को संसाधित करें, विभिन्न प्रकार के डेटा (जैसे गहराई अपडेट, लेनदेन, आदि) की पहचान करें, और उन्हें एकीकृत घटना ऑब्जेक्ट्स में स्वरूपित करें।

3. सदस्यता डेटा

प्रत्येक कनेक्शन पर, सिस्टम वर्तमान ट्रेडिंग जोड़ी के आधार पर प्रासंगिक बाजार डेटा चैनलों की सदस्यता लेगा।

  • getFunction समारोह: एक्सचेंज नाम के अनुसार संबंधित प्रसंस्करण फ़ंक्शन प्राप्त करें।
  • this.wssPublic समारोह: वेबसॉकेट कनेक्शन आरंभ करें और डेटा प्राप्त करना प्रारंभ करें।

4. थ्रेड प्रबंधन

प्रत्येक एक्सचेंज के लिए एक थ्रेड शुरू करें, वास्तविक समय में डेटा प्राप्त करें और कॉलबैक फ़ंक्शन के माध्यम से डेटा को संसाधित करें।

  • threadMarket समारोह: चाइल्ड थ्रेड में डेटा प्राप्त करें, नवीनतम गहराई और लेनदेन जानकारी को पार्स और संग्रहीत करें।

5. डेटा अधिग्रहण विधि को फिर से लिखें

प्रत्येक एक्सचेंज के लिए गहन और व्यापारिक जानकारी प्राप्त करने के तरीकों को पुनः लिखें, तथा वास्तविक समय में अद्यतन किए गए डेटा को लौटाने को प्राथमिकता दें।

टेम्पलेट का उपयोग कैसे करें

  1. प्रारंभ:उपयोग $.setupWebsocket() लक्ष्य एक्सचेंज के लिए WebSocket कनेक्शन आरंभ करें.
  2. सदस्यतासिस्टम स्वचालित रूप से आपके द्वारा व्यापार किए जाने वाले उत्पादों के लिए प्रासंगिक चैनलों (जैसे गहराई, व्यापार, आदि) की सदस्यता ले लेगा।
  3. आंकड़ा अधिग्रहण: फोन करकेGetDepth() और GetTrades() फ़ंक्शन, बाज़ार की गहराई और लेनदेन रिकॉर्ड को वापस करने के लिए स्वचालित रूप से वेबसॉकेट वास्तविक समय डेटा का उपयोग करता है।
  4. त्रुटि प्रबंधननीति में एक ट्रैकिंग तंत्र शामिल है जो कनेक्शन और डेटा त्रुटियों को लॉग करता है और यदि कनेक्शन टूट जाता है तो स्वचालित रूप से पुनः कनेक्ट करने का प्रयास करता है।

यदि रणनीति में 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);
    }
}

स्वयं नया एक्सचेंज कैसे जोड़ें

बस रणनीति टेम्पलेट का पालन करें, निम्नलिखित प्रारूप का अनुकरण करें, और एक्सचेंज 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)
                }
            }
        }
    }