एफएमजेड क्वांट प्लेटफॉर्म रणनीति लेखन के लिए उन्नत ट्यूटोरियल

लेखक:निनाबादास, बनाया गयाः 2022-03-22 09:00:57, अद्यतन किया गयाः 2022-03-29 10:02:52

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

प्लेटफ़ॉर्म के कच्चे डेटा तक पहुँचना

एफएमजेड क्वांट प्लेटफॉर्म सभी समर्थित प्लेटफार्मों को शामिल करता है। एकरूपता बनाए रखने के लिए, एक एकल प्लेटफॉर्म एपीआई के लिए हमारा समर्थन अभी भी पूरा नहीं है। उदाहरण के लिए, गेट रिकॉर्ड्स के-लाइनों की संख्या या प्रारंभ समय में पारित कर सकता है, जबकि यह एफएमजेड प्लेटफॉर्म पर तय है; कुछ प्लेटफॉर्म बैच ऑर्डर का समर्थन करते हैं, जबकि एफएमजेड इसका समर्थन नहीं करता है, और इसी तरह। इसलिए प्लेटफॉर्म डेटा तक सीधे पहुंचने के लिए एक तरीके की आवश्यकता है।सार्वजनिक इंटरफेस के लिए (जैसे बाजार उद्धरण), आप उपयोग कर सकते हैंHttpQuery, और एन्क्रिप्टेड इंटरफेस (जिसमें खाता जानकारी शामिल है) के लिए आपकोIO.विशिष्ट इनकमिंग मापदंडों के लिए, कृपया संबंधित मंच एपीआई दस्तावेज़ देखें। पिछले ट्यूटोरियल ने पेश किया है किInfoफ़ील्ड कच्ची जानकारी लौटाता है, लेकिन यह अभी भी इंटरफ़ेस का समर्थन नहीं करने की समस्या पर कोई फर्क नहीं पड़ता।

GetRawJSON (()

यह अंतिम REST एपीआई द्वारा अनुरोधित कच्ची सामग्री (स्ट्रिंग्स) लौटाता है, जिसका उपयोग विस्तारित जानकारी को स्वयं पार्स करने के लिए किया जा सकता है।

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery() सार्वजनिक इंटरफेस का उपयोग करना

सार्वजनिक इंटरफेस का उपयोग करने के लिए, Js उपयोग कर सकते हैंHttpQuery, और पायथन संबंधित पैकेज का उपयोग कर सकते हैं, जैसे किurllibयाrequests.

HttpQuery GET विधि के लिए डिफ़ॉल्ट है, और अधिक कार्यों का समर्थन करता है; अधिक विवरण के लिए एपीआई दस्तावेज़ देखें.

var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo)
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
var kline = JSON.parse(HttpQuery("https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596"))

अनुरोधों का उपयोग करके पायथन का उदाहरणः

import requests
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596')
data = resp.json()

आईओ एन्क्रिप्टेड इंटरफेस तक पहुंच

जिन इंटरफेस के लिए एपीआई-की हस्ताक्षर की आवश्यकता होती है, उनके लिए आईओ फ़ंक्शन का उपयोग किया जा सकता है, और उपयोगकर्ताओं को केवल इनकमिंग पैरामीटर की परवाह करने की आवश्यकता होती है, और विशिष्ट हस्ताक्षर प्रक्रिया को अंडरलेयर द्वारा पूरा किया जाएगा।

एफएमजेड प्लेटफॉर्म वर्तमान में बिटमेक्स स्टॉप-लॉस ऑर्डर का समर्थन नहीं करता है, जिसे निम्नलिखित चरणों के अनुसार IO के माध्यम से लागू किया जा सकता हैः

  • सबसे पहले, BitMEX एपीआई के निर्देश पृष्ठ खोजेंःhttps://www.bitmex.com/api/explorer/;
  • फिर, BitMEX का ऑर्डर पता ढूंढेंःhttps://www.bitmex.com/api/v1/order, विधि के साथPOST; एफएमजेड के लिए पहले से ही आंतरिक रूप से आधार पता निर्दिष्ट किया है, आपको केवल /api/v1/order में पास करने की आवश्यकता है।
  • संबंधित मापदंडःsymbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop.

विशिष्ट कोड:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
// You can also pass in the object 
var id = exchange.IO("api", "POST", "/api/v1/order", "", JSON.stringify({symbol:"XBTUSD",side:"Buy",orderQty:1,stopPx:4000,ordType:"Stop"}))

अधिक आईओ उदाहरणःhttps://www.fmz.com/bbs-topic/3683

वेबसॉकेट का प्रयोग करना

मूल रूप से, सभी क्रिप्टोक्यूरेंसी प्लेटफ़ॉर्म बाजार उद्धरण भेजने के लिए वेबसॉकेट का समर्थन करते हैं, और कुछ प्लेटफ़ॉर्म खाते की जानकारी को अपडेट करने के लिए वेबसॉकेट का समर्थन करते हैं। आराम एपीआई की तुलना में, वेबसॉकेट में आम तौर पर ऐसे फायदे होते हैं, जैसे कम विलंबता, उच्च आवृत्ति और प्लेटफ़ॉर्म आराम एपीआई की आवृत्ति द्वारा सीमित नहीं होना, आदि। नुकसान यह है कि एक रुकावट समस्या है, जिसका प्रसंस्करण सहज नहीं है।

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

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

आम तौर पर, सीधे वेबसॉकेट द्वारा कनेक्ट करें; उदाहरण के लिए, बिनेंस ट्रिकर पुश प्राप्त करने के लिएः

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")

यदि लौटाए गए डेटा संकुचित प्रारूप में है, तो कनेक्शन करते समय विनिर्देश किया जाना चाहिए; compress संकुचित प्रारूप को संदर्भित करता है, और mode दर्शाता है कि लौटाए गए डेटा को संकुचित करने की आवश्यकता है; उदाहरण के लिए, OKEX के साथ कनेक्शन करते समयः

var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")

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

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")

wss संदेशों की सदस्यता के लिए, कुछ प्लेटफ़ॉर्म अनुरोध यूआरएल में हैं, और कुछ को स्वयं सदस्यता प्राप्त चैनलों को भेजने की आवश्यकता है, जैसे कि सिक्काबेसः

client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')

2. एन्क्रिप्टेड इंटरफेस कनेक्शन

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

    //Push example of Huobi Futures
    var ACCESSKEYID = 'accesskey of your Huobi account'
    var apiClient = Dial('wss://api.hbdm.com/notification|compress=gzip&mode=recv')
    var date = new Date(); 
    var now_utc =  Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    var utc_date = new Date(now_utc)
    var Timestamp = utc_date.toISOString().substring(0,19)
    var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent(Timestamp)
    var signature = exchange.HMAC("sha256", "base64", quest, "{{secretkey} }") // Remove the extra blank spaces between }}
    auth = {op: "auth",type: "api",AccessKeyId: ACCESSKEYID, SignatureMethod: "HmacSHA256",SignatureVersion: "2", Timestamp: Timestamp, Signature:encodeURI(signature)}
    apiClient.write(JSON.stringify(auth))
    apiClient.write('{"op": "sub","cid": "orders","topic": "orders.btc'}')
    while (true){
        var data = datastream.read()
        if('op' in data && data.op == 'ping'){
            apiClient.write(JSON.stringify({op:'pong', ts:data.ts}))
        }
    }
    
    // Push example of Binance; pay attention that listenKey needs to be updated regularly   
    var APIKEY = 'accesskey of your Binance account'
    var req = HttpQuery('https://api.binance.com/api/v3/userDataStream',{method: 'POST',data: ''},null,'X-MBX-APIKEY:'+APIKEY);
    var listenKey = JSON.parse(req).listenKey;
    HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'DELETE',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
    listenKey = JSON.parse(HttpQuery('https://api.binance.com/api/v3/userDataStream','',null,'X-MBX-APIKEY:'+APIKEY)).listenKey;
    var datastream = Dial("wss://stream.binance.com:9443/ws/"+listenKey+'|reconnect=true',60);
    var update_listenKey_time =  Date.now()/1000;
    while (true){
        if (Date.now()/1000 - update_listenKey_time > 1800){
            update_listenKey_time = Date.now()/1000;
            HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'PUT',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
        }
        var data = datastream.read()
    }

    // push example of BitMEX
    var APIKEY = "your Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")// secretkey is automatically replaced during execution, so no need to fill in
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }

3.वेबसॉकेट पढ़ें

आम तौर पर, इसे अनंत लूप में लगातार पढ़ा जा सकता है। कोड इस प्रकार है:

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) // Parse json strings into quotable objects 
// Process data 
    }
}

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

यदिread()कोई पैरामीटर जोड़ता है, यह सबसे पुराना डेटा लौटा देगा, और कोई डेटा नहीं है जब तक वापस ब्लॉक. यदि आप नवीनतम डेटा चाहते हैं, तो आप उपयोग कर सकते हैंclient.read(-2)नवीनतम डेटा तुरंत वापस करने के लिए, लेकिन जब कोई डेटा नहीं है, यह शून्य लौटाएगा, जो संदर्भ से पहले न्याय करने की आवश्यकता है।

पुराने कैश किए गए डेटा से निपटने के तरीके पर निर्भर करता है और जब कोई डेटा नहीं होता है तो यह अवरुद्ध होता है या नहीं, read के अलग-अलग पैरामीटर होते हैं, जैसा कि नीचे दी गई तालिका में दिखाया गया है, जो जटिल दिखता है, लेकिन प्रोग्राम को अधिक लचीला बनाता है।img

4.वेबसोकेट द्वारा कई प्लेटफार्मों से कनेक्ट करना

इस मामले में यह स्पष्ट है कि read() का उपयोग करना प्रोग्राम में काम नहीं करता है, क्योंकि एक प्लेटफ़ॉर्म प्रतीक्षा संदेशों को ब्लॉक करेगा, और दूसरा प्लेटफ़ॉर्म नए संदेश होने पर भी प्राप्त नहीं करेगा। सामान्य प्रसंस्करण विधि हैः

    function main() {
        var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        var coinbase = Dial("wss://ws-feed.pro.coinbase.com", 60)
        coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
        while (true) {
            var msgBinance = binance.read(-1) // Parameter -1 represents no data and return null immediately; it will not occur that being blocked before there is data to be returned 
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // at this time, Binance has data to return 
            }
            if(msgCoinbase){
                // at this time, coinbase has data to return 
            }
            Sleep(1) // Sleep for 1 millisecond
        }
    }

5.डिस्कनेक्शन और रीकनेक्शन समस्याएं

प्रसंस्करण का यह भाग अधिक कष्टप्रद है, क्योंकि पुश डेटा बाधित हो सकता है, या पुश देरी बेहद लंबी है। भले ही दिल की धड़कन प्राप्त की जा सके, इसका मतलब यह नहीं है कि डेटा अभी भी पुश किया जा रहा है। आप एक घटना अंतराल सेट कर सकते हैं; यदि अंतराल के बाद कोई अपडेट प्राप्त नहीं होता है, तो फिर से कनेक्ट करें; यह देखने के लिए कि डेटा सटीक है या नहीं, यह देखने के लिए समय की अवधि के बाद rest द्वारा लौटे परिणामों की तुलना करना सबसे अच्छा है। बिनेंस के विशेष मामलों के लिए, आप सीधे स्वचालित पुनः कनेक्ट सेट कर सकते हैं।

6.वेबसॉकेट के सामान्य प्रोग्राम फ्रेम का उपयोग करना

पुश डेटा के लिए इस्तेमाल किया गया है, कार्यक्रम स्वाभाविक रूप से घटना-ट्रिगर के रूप में लिखा जाएगा; पुश डेटा की आवृत्ति पर ध्यान दें, क्योंकि उच्च आवृत्ति अनुरोधों को अवरुद्ध होने का कारण होगा; आम तौर पर आप लिख सकते हैंः

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//Here it limits only one trade in 2 seconds 
            tradeTime = Date.now()
            // Trading logic
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//Here it limits GetAccount only once in 5 seconds 
            accountTime = Date.now()
            return exchange.GetAccount()
        }
    }
    function main() {
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true");
        while (true) {
            var msg = client.read()
            var data = JSON.parse(msg)
            var account = GetAccount()
            trade(data)
        }
    }

7.Conclusion

प्रत्येक प्लेटफ़ॉर्म पर कनेक्शन विधि, डेटा ट्रांसमिशन विधि, सब्सक्राइब की गई सामग्री और वेबसॉकेट का डेटा प्रारूप अक्सर भिन्न होता है, इसलिए प्लेटफ़ॉर्म इसे कैप्सूल नहीं करता है और इसे अपने आप कनेक्ट करने के लिए डायल फ़ंक्शन का उपयोग करने की आवश्यकता होती है। यह लेख मूल रूप से कुछ बुनियादी सावधानियों को कवर करता है। यदि आपके पास कोई और प्रश्न हैं, तो कृपया पूछने के लिए स्वतंत्र महसूस करें।

PS: हालांकि कुछ प्लेटफ़ॉर्म वेबसॉकेट उद्धरण प्रदान नहीं करते हैं, वास्तव में, जब आप डिबगिंग फ़ंक्शन का उपयोग करने के लिए वेबसाइट पर लॉग इन करते हैं, तो आप पाएंगे कि वे सभी वेबसॉकेट पुश का उपयोग कर रहे हैं। शोध करने के बाद, आपको पता चलेगा कि कुछ सदस्यता प्रारूप और रिटर्न प्रारूप एन्क्रिप्टेड प्रतीत होते हैं, जिन्हें base64 के साथ डिकोडिंग और डीकॉम्प्रेसिंग करके देखा जा सकता है।

मल्टीथ्रेड समवर्ती

जावास्क्रिप्ट गो फ़ंक्शन द्वारा समवर्ती को महसूस कर सकता है, और पायथन संबंधित मल्टीथ्रेड लाइब्रेरी का उपयोग कर सकता है।

मात्रात्मक रणनीतियों के कार्यान्वयन के दौरान, समवर्ती निष्पादन समय देरी को कम कर सकता है और दक्षता में सुधार कर सकता है। उदाहरण के लिए हेजिंग रणनीति बॉट को लें। इसे दो सिक्कों की गहराई प्राप्त करने की आवश्यकता है, और क्रम में निष्पादित कोड इस प्रकार दिखाया गया हैः

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

जब एक अनुरोध के विश्राम एपीआई में देरी होती है, उदाहरण के लिए देरी का समय 100 मिलीसेकंड है, तो गहराई दो बार प्राप्त करने का समय वास्तव में अलग है; यदि अधिक पहुँच की आवश्यकता है, तो देरी की समस्या अधिक स्पष्ट होगी, जो रणनीति के निष्पादन को प्रभावित करेगी।

चूंकि जावास्क्रिप्ट में मल्टीथ्रेड नहीं है, इसलिए इस समस्या को हल करने के लिए अंडरलेयर गो फ़ंक्शन को कैप्सूल करता है। गो फ़ंक्शन का उपयोग उन एपीआई के लिए किया जा सकता है जिन्हें नेटवर्क एक्सेस की आवश्यकता होती है, जैसे किGetDepth, GetAccountऔर इसी तरह।IOयह भी समर्थित है, जैसेःexchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders)), लेकिन डिजाइन तंत्र के कारण, इसे लागू करना अधिक थकाऊ है।

var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() // Call "wait" method to wait for the return of the asynchronous GetDepth result 
var depthB = b.wait()

अधिकांश सरल मामलों में, इस तरह से रणनीतियों को लिखना ठीक है। लेकिन ध्यान दें कि प्रक्रिया हर बार दोहराई जाती है जब रणनीति लूप होती है, और मध्यवर्ती चर a और b वास्तव में केवल अस्थायी रूप से सहायक होते हैं। यदि हमारे पास बहुत सारे समवर्ती कार्य हैं, तो हमें अतिरिक्त रूप से a और depthA, b और depthB के बीच पत्राचार रिकॉर्ड करने की आवश्यकता होती है। जब हमारे समवर्ती कार्य अनिश्चित होते हैं, तो स्थिति अधिक जटिल होती है। इसलिए हम एक फ़ंक्शन को महसूस करने की उम्मीद करते हैंः जब Go फ़ंक्शन को समवर्ती रूप से लिखते हैं, तो एक ही समय में एक चर को बांधें; जब समवर्ती चल परिणाम वापस आता है, तो परिणाम मान स्वचालित रूप से चर को सौंपा जाता है, इस प्रकार मध्यवर्ती चर की आवश्यकता को समाप्त करना और कार्यक्रम को अधिक संक्षिप्त बनाना। विशिष्ट कार्यान्वयन निम्नानुसार हैः

function G(t, ctx, f) {
    return {run:function(){
        f(t.wait(1000), ctx)
    }}
}

हमने एक G फ़ंक्शन को परिभाषित किया है, जहां पैरामीटर t निष्पादित होने वाला Go फ़ंक्शन है, ctx रिकॉर्डिंग प्रोग्राम संदर्भ का फ़ंक्शन है, और f एक विशिष्ट मान असाइन करने वाला फ़ंक्शन है। आप इस फ़ंक्शन का प्रभाव बाद में देखेंगे।

इस समय, समग्र प्रोग्राम फ्रेमवर्क को एक मॉडल के रूप में लिखा जा सकता है, जो उत्पादक-उपभोक्ता मॉडल के समान है (कुछ अंतरों के साथ), निर्माता लगातार कार्य भेजता है, और उपभोक्ता उन्हें समवर्ती रूप से निष्पादित करता है। निम्नलिखित कोड केवल प्रदर्शन के लिए है और इसमें कोई कार्यक्रम निष्पादन तर्क शामिल नहीं है।

var Info = [{depth:null, account:null}, {depth:null, account:null}] // If we need to obtain the depth and account of the two platforms, more information can also be put in, such as order ID and status, etc.
var tasks = [ ] // Global task list 

function produce(){ // Issue all kinds of concurrent tasks
  // Here the task producing logic has been omitted, only for demo
  tasks.push({exchange:0, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:1, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:0, ret:'sellID', param:['Buy', Info[0].depth.Asks[0].Price, 10]})
  tasks.push({exchange:1, ret:'buyID', param:['Sell', Info[1].depth.Bids[0].Price, 10]})
}
function worker(){
    var jobs = []
    for(var i=0;i<tasks.length;i++){
        var task = tasks[i]
        jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
                    Info[task.exchange][task.ret] = v // Here "v" is the return value of the concurrent Go function "wait()", and you can think about it 
                }))
    }
    _.each(jobs, function(t){
            t.run() // Here all tasks are executed concurrently 
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // Give trading command
        worker()        // Concurrently execute
        Sleep(1000)
    }
}

ऐसा लगता है कि उपरोक्त कार्यों में केवल एक सरल फ़ंक्शन को लागू किया गया है। वास्तव में, इसने कोड की जटिलता को बहुत सरल कर दिया है। हमें केवल इस बात की परवाह करने की आवश्यकता है कि प्रोग्राम को क्या कार्य उत्पन्न करने की आवश्यकता है, और worker() प्रोग्राम स्वचालित रूप से उन्हें समवर्ती रूप से निष्पादित करेगा और संबंधित परिणाम लौटाएगा। लचीलापन में बहुत सुधार हुआ है।

चार्ट फ़ंक्शन द्वारा चित्रण

प्रारंभिक ट्यूटोरियल में, ड्राइंग क्लास लाइब्रेरी को ड्राइंग की शुरूआत में अनुशंसित किया गया है, जो ज्यादातर मामलों में जरूरतों को पूरा कर सकता है। यदि आपको आगे अनुकूलन की आवश्यकता है, तो आप सीधे Chart ऑब्जेक्ट को संचालित कर सकते हैं।

के आंतरिक मापदंडोंChart({…})HighStock और HighCharts के ऑब्जेक्ट हैं, लेकिन एक अतिरिक्त पैरामीटर है__isStockएफएमजेड मुख्य रूप से हाईचार्ट्स और हाईस्टॉक के बुनियादी मॉड्यूल का समर्थन करता है, लेकिन अतिरिक्त मॉड्यूल का समर्थन नहीं करता है।

विशिष्ट हाईचार्ट्स उदाहरणःhttps://www.highcharts.com/demo; हाईस्टॉक उदाहरण:https://www.highcharts.com/stock/demo. आप उन उदाहरणों में कोड का संदर्भ ले सकते हैं, और उन्हें FMZ में आसानी से प्रत्यारोपित कर सकते हैं.

आप निर्दिष्ट सूचकांक के साथ श्रृंखला में डेटा जोड़ने के लिए add ([सीरीज़ इंडेक्स ((जैसे 0), डेटा]) को कॉल कर सकते हैं। चार्ट डेटा को साफ़ करने के लिए call reset (() को कॉल करें; reset एक संख्या पैरामीटर ले सकता है और सहेजने के लिए राशि निर्दिष्ट कर सकता है। एकाधिक चार्ट डिस्प्ले समर्थित है, जिसे केवल कॉन्फ़िगरेशन के दौरान सरणी मापदंडों में पारित करने की आवश्यकता होती है, जैसेः var chart = Chart (([{...}, {...}, {...}]) । उदाहरण के लिए, यदि Chart1 में दो श्रृंखलाएं हैं, Chart2 में एक श्रृंखला है, और Chart3 में एक श्रृंखला है, जब add को कॉल करते हैं, तो श्रृंखला ID 0 और 1 को अपडेट किए गए Chart1 में दो श्रृंखलाओं के डेटा को अलग से प्रतिनिधित्व करने के लिए निर्दिष्ट किया जाता है; श्रृंखला ID 2 को Chart2 में पहली श्रृंखला के डेटा का प्रतिनिधित्व करने के लिए निर्दिष्ट किया जाता है; श्रृंखला ID 3 को Chart3 में पहली श्रृंखला के डेटा का प्रतिनिधित्व करने के लिए निर्दिष्ट किया जाता है।

एक विशिष्ट उदाहरण:

var chart = { // This "chart" in JS is an object; before using the Chart function, we need to declare the object variable of a configured chart "chart" 
    __isStock: true,                                    // Mark whether it is a general chart; you can change it to false and try to operate it, if you are interested 
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // Zoom tool
    title : { text : 'spread chart'},                       // Theme
    rangeSelector: {                                    // Choose the range
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // Horizontal axis, namely X axis; currently set type: time
    yAxis : {                                           // Vertical axis, namely Y axis; the default changes according to the data 
        title: {text: 'spread'},                           // Theme
        opposite: false,                                // whether to enable the vertical axis on the right 
    },
    series : [                                          // Data series; the attribute saves all kinds of data series (lines, K-lines, labels, etc.)
        {name : "line1", id : "line1,buy1Price", data : []},  // The index is 0; the data stroed in the data array is the data of the index series 
        {name : "line2", id : "line2,lastPrice", dashStyle : 'shortdash', data : []}, // The index is 1; set  dashStyle: 'shortdash', namely: set  dashed line
    ]
};
function main(){
    var ObjChart = Chart(chart);  // Call the Chart function, and initialize the chart 
    ObjChart.reset();             // Empty 
    while(true){
        var nowTime = new Date().getTime();   // Obtain the timestamp of this polling, namely a millisecond tiemstamp, to ensure the location of writing to the X axis in the chart 
        var ticker = _C(exchange.GetTicker);  // Obtain the market quotes data
        var buy1Price = ticker.Buy;           // Get buy one price from the return value of the market quotes 
        var lastPrice = ticker.Last + 1;      // Get the final executed price, and we add 1 to split the 2 lines 
        ObjChart.add([0, [nowTime, buy1Price]]); // Use the timestamp as the value of X, and buy one price as the value of Y; pass in the data series of index 0  
        ObjChart.add([1, [nowTime, lastPrice]]); // Same as above. 
        Sleep(2000);
    }
}

चार्ट लेआउट का उपयोग करने का उदाहरणःhttps://www.fmz.com/strategy/136056

उन्नत बैकटेस्ट

पायथन स्थानीय बैकटेस्ट

विशिष्ट ओपन सोर्स पताःhttps://github.com/fmzquant/backtest_python

स्थापना

कमांड लाइन में निम्न कमांड दर्ज करें:

pip install https://github.com/fmzquant/backtest_python/archive/master.zip

सरल उदाहरण

बैकटेस्ट पैरामीटर को टिप्पणी के रूप में रणनीति कोड की शुरुआत में सेट करें, और विवरण एफएमजेड वेबसाइट के संपादन रणनीति पृष्ठ पर सेव सेटिंग्स के बटन पर दिखाई देंगे।

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"OKEX","currency":"LTC_BTC","balance":3,"stocks":0}]
'''
from fmz import *
task = VCtx(__doc__) # initialize backtest engine from __doc__
print exchange.GetAccount()
print exchange.GetTicker()
print task.Join() # print backtest result

बैकटेस्ट

पूर्ण रणनीतियों के लिए अनंत लूप की आवश्यकता होती है, EOF त्रुटि बैकटेस्ट खत्म होने के बाद उठाई जाएगी; इसलिए, हमें गलती सहिष्णुता को अच्छी तरह से करना चाहिए।

# !/usr/local/bin/python
# -*- coding: UTF-8 -*-

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD","balance":10000,"stocks":3}]
'''

from fmz import *
import math
import talib

task = VCtx(__doc__) # initialize backtest engine from __doc__

# ------------------------------ Start of the Strategy  --------------------------

print exchange.GetAccount()     # Call some interfaces, and print their return values 
print exchange.GetTicker()

def adjustFloat(v):             # the custom functions in the strategy 
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # Specific strategy code 


def main():
    InitAccount = GetAccount()
    while True:
        onTick()
        Sleep(1000)

# ------------------------------ End of the Strategy --------------------------

try:
    main()                     # The end of the backtest will raise EOFError() to stop stop the backtest loop. Therefore, we should handle with the error, and call task.Join() to print the backtest result, after the error is detected  
except:
    print task.Join()         

कस्टम बैकटेस्ट डेटा

exchange.SetData(arr) बैकटेस्ट डेटा स्रोत स्विच करता है और कस्टम K-लाइन डेटा का उपयोग करता है। पैरामीटर arr एक सरणी है, जिसका तत्व K-लाइन बार डेटा है (यानीः K-लाइन डेटा सरणी, जो अस्थायी रूप से केवल जावास्क्रिप्ट बैकटेस्ट का समर्थन करती है।

arr के सरणी में, एक एकल तत्व का डेटा प्रारूपः

[
    1530460800,    // time     Timestamp 
    2841.5795,     // open     Open Price 
    2845.6801,     // high     Highest Price
    2756.815,      // low      Lowest Price
    2775.557,      // close    Close Price
    137035034      // volume   Executed Volume 
]

टेम्पलेट में डेटा स्रोत आयात किया जा सकता है।

function init() {                                                          // The init function in the template will be executed first when the template is loaded; ensure the exchange.SetData(arr) function is executed first, initialized, and set the data to the backtest system
    var arr = [                                                            // The K-line data to be used during backtest
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // The data of the earliest K-line bar
        ... ,                                                              // If the K-line data is too long, use "..." to represent the omitted data here
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // The data of the latest K-line bar 
    ]
    exchange.SetData(arr)                                                  // Import the custom data mentioned above 
    Log("Import data successfully")
}

नोटः प्रारंभ के दौरान पहले कस्टम डेटा आयात करना सुनिश्चित करें (यानी, डेटा सेट करने के लिए एक्सचेंज.सेटडाटा फ़ंक्शन को कॉल करें). कस्टम के-लाइन डेटा अवधि बैकटेस्ट पृष्ठ पर सेट अंडरलेयर के-लाइन अवधि के अनुरूप होनी चाहिए, अर्थातः कस्टम के-लाइन डेटा; एक के-लाइन का समय 1 मिनट है, इसलिए बैकटेस्ट में सेट अंडरलेयर के-लाइन की अवधि भी 1 मिनट पर सेट होनी चाहिए।

FMZ द्वारा समर्थित नहीं प्लेटफार्मों का उपयोग करना

यदि असमर्थित प्लेटफ़ॉर्म का एपीआई आधार पते को छोड़कर, समर्थित प्लेटफ़ॉर्म के समान है, तो असमर्थित प्लेटफ़ॉर्म को आधार पते को स्विच करके समर्थित किया जा सकता है। विशिष्ट होने के लिए, प्लेटफ़ॉर्म जोड़ते समय एक समर्थित प्लेटफ़ॉर्म का चयन करें, लेकिन असमर्थित प्लेटफ़ॉर्म की एपीआई-की को भरें, और रणनीति में आधार पते को स्विच करने के लिए IO का उपयोग करें, जैसेः

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro is the base address of the unsupported platform API, and notice not to add api/v3 and so on, for the address will be automatically completed

एफएमजेड द्वारा सभी प्लेटफार्मों का समर्थन नहीं किया जाता है, लेकिन हमारे प्लेटफॉर्म ने सामान्य प्रोटोकॉल की पहुंच विधि प्रदान की है। विशिष्ट सिद्धांत हैंः

  • जब आप किसी प्लेटफ़ॉर्म तक पहुँचने के लिए कोड लिखते हैं, तो प्रोग्राम एक वेब सेवा बनाएगा।
  • जब आप FMZ में एक मंच जोड़ते हैं, तो वेब सेवा का पता और पोर्ट निर्दिष्ट करें.
  • जब डॉकर सामान्य प्रोटोकॉल के प्लेटफ़ॉर्म बॉट को चला रहा है, तो रणनीति में एपीआई एक्सेस अनुरोध सामान्य प्रोटोकॉल को भेजा जाएगा.
  • सामान्य प्रोटोकॉल अनुरोध द्वारा प्लेटफार्म तक पहुँच जाएगा, और डॉकर को परिणाम लौटाता है।

सरल शब्दों में कहें तो सामान्य प्रोटोकॉल एक मध्यस्थ की तरह है, जो डॉकर के अनुरोध को प्रॉक्सी करता है और संबंधित मानक के अनुसार डेटा लौटाता है। सामान्य प्रोटोकॉल का कोड स्वयं को पूरा करने की आवश्यकता होती है। सामान्य प्रोटोकॉल लिखने का वास्तव में मतलब है कि आप केवल मंच तक पहुंच सकते हैं और रणनीति को पूरा कर सकते हैं। एफएमजेड आधिकारिक कभी-कभी प्लेटफार्मों के सामान्य प्रोटोकॉल का exe संस्करण जारी करता है। सामान्य प्रोटोकॉल पायथन में भी किया जा सकता है, जिसे फिर एक साधारण बॉट के रूप में डॉकर पर चलाया जा सकता है।

सामान्य प्रोटोकॉल का विशिष्ट परिचय:https://www.fmz.com/bbs-topic/9120पायथन में सामान्य प्रोटोकॉल लिखने का उदाहरणःhttps://www.fmz.com/strategy/101399

अपना स्वयं का मात्रात्मक मंच बनाना

जैसे किसी प्लेटफ़ॉर्म के विभिन्न संचालन को एपीआई के माध्यम से लागू किया जा सकता है, वैसे ही एफएमजेड वेबसाइट भी एपीआई पर आधारित है। आप एपीआई दस्तावेज़ में अपने स्वयं के एपीआई-की के लिए आवेदन कर सकते हैं, जैसे कि create, restart, DeleteRobot, GetRobotList GetRobotLogs, आदि। विवरण के लिए कृपया एपीआई दस्तावेज़ में API एक्सटेंशन ऑफ एफएमजेड प्लेटफ़ॉर्म अनुभाग देखें।

एफएमजेड क्वांट प्लेटफ़ॉर्म की शक्तिशाली विस्तारशीलता के कारण, आप एपीआई एक्सटेंशन के आधार पर अपना स्वयं का मात्रात्मक प्लेटफ़ॉर्म बना सकते हैं, जिससे आपके उपयोगकर्ता आपके प्लेटफ़ॉर्म पर बॉट चला सकते हैं, आदि। विशिष्ट संदर्भःhttps://www.fmz.com/bbs-topic/1697 .

एफएमजेड का भागीदार बनना

नेटईज़ क्लासरूम का प्रचार

क्रिप्टोक्यूरेंसी ट्रेडिंग बाजार ने अपनी विशिष्टता के कारण मात्रात्मक व्यापारियों से अधिक से अधिक ध्यान आकर्षित किया है। वास्तव में, प्रोग्राम ट्रेडिंग क्रिप्टोक्यूरेंसी की मुख्यधारा बन गई है, और हेजिंग और मार्केट मेकिंग जैसी रणनीतियाँ हमेशा बाजार में सक्रिय होती हैं। कमजोर प्रोग्रामिंग नींव वाले शुरुआती इस नए क्षेत्र में प्रवेश करना चाहते हैं, कई प्लेटफार्मों और बदलते एपीआई का सामना करते हुए, कठिनाइयों से भरे हुए हैं। एफएमजेड क्वांट प्लेटफॉर्म, (पूर्व बॉटवी,www.fmz.com) वर्तमान में सबसे बड़ा क्रिप्टोक्यूरेंसी मात्रात्मक समुदाय और मंच है, जिसने 4 से अधिक वर्षों के लिए मात्रात्मक व्यापार की सड़क पर हजारों शुरुआती लोगों की मदद की है। नेटईज़ पर पाठ्यक्रम लेने के लिए, आपको केवल 20 युआन लगते हैं, और पाठ्यक्रम पूरी तरह से शुरुआती के लिए है।

प्रोत्साहननेटईज़ क्लाउड क्लासरूम पर क्रिप्टोकरेंसी मात्रात्मक ट्रेडिंग कोर्स. नेटईज़ क्लाउड क्लासरूम में लॉग इन करें और अपना कोर्स लिंक साझा करें (लिंक में एक अद्वितीय कोर्स आईडी है). अन्य, जो इस लिंक के माध्यम से पाठ्यक्रम को पंजीकृत करते हैं और खरीदते हैं, आपको कुल का 50% कमीशन के रूप में लाएंगे, अर्थात् 10 युआन। नकदी निकालने के लिए नेटईज़ क्लाउड क्लासरूम प्रीमियम कोर्स प्रमोशन के वीचैट सार्वजनिक खाते का पालन करें। आपको Weibo या QQ समूह में पाठ्यक्रम को बढ़ावा देने के लिए दूसरों को आमंत्रित करने का भी स्वागत है।

संबद्धता

प्रमोशन लिंक पर क्लिक करने, पंजीकरण करने और आधे वर्ष के भीतर रिचार्ज करने वाले उपभोक्ताओं को इस नीति का लाभ मिलेगा कि हमारी कंपनी वैध क्रम में प्रभावी राशि के अनुसार छूट देगी। कमीशन को प्रमोटर के खाते में अंक के रूप में वापस कर दिया जाएगा। उपयोगकर्ता एफएमजेड प्लेटफॉर्म के खाते के शेष राशि में 10: 1 के अनुपात में अंक का आदान-प्रदान कर सकते हैं, और उपयोगकर्ता भविष्य में एफएमजेड क्वांट के संबंधित उत्पादों का आदान-प्रदान करने के लिए भी अंक का उपयोग कर सकते हैं। गतिविधि के लिए विशिष्ट लिंकःhttps://www.fmz.com/bbs-topic/3828

उद्यमों के लिए FMZ क्वांट प्लेटफॉर्म

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

बाजार निर्माण प्रणाली

पेशेवर प्रणाली, जो प्लेटफार्मों के लिए बाजार तरलता और धन प्रबंधन प्रदान करती है, बाजार में सबसे बेहतर बाजार बनाने की प्रणाली हो सकती है। यह कई प्लेटफार्मों और टीमों द्वारा व्यापक रूप से उपयोग की जाती है।

प्लेटफार्म योजना

एफएमजेड प्रौद्योगिकी व्यापार प्रणाली मेमोरी मिलान तकनीक को अपनाती है, और ऑर्डर प्रोसेसिंग की गति 2 मिलियन ट्रेड प्रति सेकंड तक होती है, जो यह सुनिश्चित कर सकती है कि ऑर्डर प्रोसेसिंग में कोई देरी या देरी नहीं होगी। यह 20 मिलियन से अधिक एक साथ ऑनलाइन उपयोगकर्ताओं के साथ प्लेटफार्मों के सुचारू और स्थिर संचालन को बनाए रख सकती है। बहु-परत और बहु-क्लस्टर सिस्टम फ्रेमवर्क सिस्टम की सुरक्षा, स्थिरता और विस्तार को सुनिश्चित करता है। फ़ंक्शन की तैनाती और संस्करण अपडेट डाउनटाइम के बिना किया जा सकता है, जो टर्मिनल उपयोगकर्ताओं के ऑपरेटिंग अनुभव की अधिकतम गारंटी देता है। वर्तमान में, सिस्टम को wex.app सिमुलेटेड प्लेटफॉर्म में अनुभव किया जा सकता है।


अधिक