संसाधन लोड हो रहा है... लोड करना...

एफएमजेड क्वांटिफाइड प्लेटफॉर्म की रणनीति

लेखक:घास, बनाया गयाः 2019-08-19 15:54:35, अद्यतन किया गयाः 2021-06-08 16:14:57

[TOC] इस ट्यूटोरियल को सीखने से पहले, आपको सीखना होगा।FMZ के आविष्कारक क्वांटिफाइंग प्लेटफॉर्म का उपयोग करते हैंऔरएफएमजेड क्वांटिफाइड प्लेटफॉर्म की रणनीति, और प्रोग्रामिंग भाषाओं का उपयोग करने में कुशल है ।प्रारंभिक ट्यूटोरियल में सबसे अधिक उपयोग किए जाने वाले फ़ंक्शन शामिल हैं, लेकिन कई अन्य फ़ंक्शन और कार्यक्षमताएं हैं जिन्हें इस ट्यूटोरियल में शामिल नहीं किया गया है।इस ट्यूटोरियल को पढ़ने के बाद, आप अधिक स्वतंत्र, अधिक अनुकूलित रणनीतियों को लिखने में सक्षम होंगे, 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 ((() सार्वजनिक इंटरफ़ेस का उपयोग करें

सार्वजनिक इंटरफ़ेस का उपयोग करें, जे का उपयोग कर सकते हैं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()

आईओ फ़ंक्शन एक्सेस प्लस क्लोजर

API-KEY हस्ताक्षर की आवश्यकता वाले इंटरफेस के लिए, IO फ़ंक्शन का उपयोग किया जा सकता है, उपयोगकर्ता को केवल इनपुट पैरामीटर के बारे में चिंता करने की आवश्यकता होती है, और विशिष्ट हस्ताक्षर प्रक्रिया को निचले स्तर से पूरा किया जाता है।

FMZ प्लेटफॉर्म वर्तमान में BitMEX स्टॉप लॉस को सपोर्ट नहीं करता है, इसे IO के माध्यम से निम्न चरणों का पालन करके किया जाता है।

  • BitMEX के एपीआई के बारे में जानने के लिए नीचे दिए गए पेज पर जाएंःhttps://www.bitmex.com/api/explorer/
  • BitMEX का पता लगाने के लिए नीचे दिए गए पते पर जाएंःhttps://www.bitmex.com/api/v1/order, विधि हैPOST│ चूंकि FMZ ने आंतरिक रूप से रूट पता निर्दिष्ट कर दिया है, इसलिए केवल "/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")
//也可以直接传入对象
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

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

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

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

1.websocket连接

आम तौर पर, सीधे कनेक्ट करें, जैसे कि सिक्का सुरक्षा टिकर प्राप्त करेंः

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

लौटने वाले डेटा के लिए संपीड़ित प्रारूप है, जो कनेक्शन के दौरान निर्दिष्ट किया जाना चाहिए, संपीड़ित संपीड़ित प्रारूप निर्दिष्ट करता है, मोड उस डेटा को वापस भेजने के लिए प्रतिनिधित्व करता है जिसे संपीड़ित किया जाना चाहिए, जैसे कि कनेक्शन 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")

कुछ एक्सचेंजों के अनुरोध यूआरएल में हैं, और कुछ चैनलों को भी सदस्यता भेजने की आवश्यकता है, जैसे कि Coinbase:

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

2.加密接口连接

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

    //火币期货推送例子
    var ACCESSKEYID = '你的火币账户的accesskey'
    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} }") //去掉}}之间的多余空格
    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}))
        }
    }
    
    //币安推送例子,注意需要定时更新listenKey
    var APIKEY = '你的币安accesskey'
    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()
    }

    //BitMEX推送例子
    var APIKEY = "你的Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")//secretkey在执行时自动替换,不用填写
    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.websocket读取

आम तौर पर, मृत चक्र में पढ़ना जारी है, कोड इस प्रकार हैः

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) //把json字符串解析为可引用的object
// 处理data数据
    }
}

wss डेटा बहुत तेज़ गति से पुश किया जाता है, Go के निचले स्तर में सभी डेटा को कतार में रख दिया जाता है, और जब कोई प्रोग्राम read को कॉल करता है, तो यह क्रमशः वापस आ जाता है। जबकि वास्तविक डिस्क पर नीचे की सूची जैसे ऑपरेशन देरी का कारण बनते हैं, जिससे डेटा का संचय हो सकता है। लेनदेन पुश, खाता पुश, गहराई प्लग इन पुश आदि के लिए, हमें ऐतिहासिक डेटा की आवश्यकता होती है, बाजार डेटा के लिए, हम ज्यादातर मामलों में केवल नवीनतम, ऐतिहासिक डेटा की परवाह नहीं करते हैं।

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

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

4.连接多个交易所websocket

इस स्थिति के लिए प्रक्रिया में स्पष्ट रूप से सरल रीड () का उपयोग नहीं किया जा सकता है, क्योंकि एक एक्सचेंज प्रतीक्षा संदेशों को अवरुद्ध कर देता है, इस समय दूसरा एक्सचेंज नए संदेशों के साथ भी प्राप्त नहीं करेगा।

    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) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // 此时币安有数据返回
            }
            if(msgCoinbase){
                // 此时coinbase有数据返回
            }
            Sleep(1) // 可以休眠1ms
        }
    }

5.断线重连问题

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

6.使用websocket的一般程序框架

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

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//这里即限制了2s内只交易一次
            tradeTime = Date.now()
            //交易逻辑
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//这里即限制了5s内只获取账户一次
            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.总结

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

PS. कुछ एक्सचेंजों ने वेबसॉकेट बाजार की पेशकश नहीं की है, लेकिन वे वास्तव में वेबसॉकेट पुशिंग का उपयोग करते हैं। कुछ एक्सचेंजों में सब्सक्रिप्शन प्रारूप और रिटर्न प्रारूप दिखाई देते हैं। कुछ ऐसा दिखते हैं जैसे वे एन्क्रिप्टेड हैं, जिन्हें base64 डिकोडिंग के साथ फिर से अनक्राफ्ट किया जा सकता है।

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

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

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

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

एक बार अनुरोध करने पर rest API में देरी होती है, मान लीजिए कि 100ms है, तो दो बार गहराई प्राप्त करने का समय वास्तव में अलग होता है, और यदि अधिक पहुंच की आवश्यकता होती है, तो देरी का मुद्दा अधिक प्रमुख होगा, जो रणनीति के निष्पादन को प्रभावित करता है।

जावास्क्रिप्ट में बहुत सारे थ्रेड नहीं हैं, इसलिए गो फ़ंक्शन को नीचे लिपटे हुए इस समस्या को हल करता है। गो फ़ंक्शन एपीआई के लिए उपयोग किया जा सकता है जिसे नेटवर्क एक्सेस की आवश्यकता होती है, जैसे कि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() //调用wait方法等待返回异步获取depth结果 
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}] //加入我们需要获取两个交易所的深度和账户,跟多的信息也可以放入,如订单Id,状态等。
var tasks = [ ] //全局的任务列表

function produce(){ //下发各种并发任务
  //这里省略了任务产生的逻辑,仅为演示
  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 //这里的v就是并发Go函数wait()的返回值,可以仔细体会下
                }))
    }
    _.each(jobs, function(t){
            t.run() //在这里并发执行所有任务
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // 发出交易指令
        worker()        // 并发执行
        Sleep(1000)
    }
}

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

Chart फ़ंक्शन का चित्र

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

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

HighCharts के कुछ उदाहरणःhttps://www.highcharts.com/demoहाईस्टॉक उदाहरणःhttps://www.highcharts.com/stock/demo⇒ इन उदाहरणों के संदर्भ में कोड को FMZ में आसानी से स्थानांतरित किया जा सकता है.

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

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

var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
    __isStock: true,                                    // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // 缩放工具
    title : { text : '差价分析图'},                       // 标题
    rangeSelector: {                                    // 选择范围
        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'},                         // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
    yAxis : {                                           // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
        title: {text: '差价'},                           // 标题
        opposite: false,                                // 是否启用右边纵轴
    },
    series : [                                          // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
        {name : "line1", id : "线1,buy1Price", data : []},  // 索引为0, data 数组内存放的是该索引系列的 数据
        {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
    ]
};
function main(){
    var ObjChart = Chart(chart);  // 调用 Chart 函数,初始化 图表。
    ObjChart.reset();             // 清空
    while(true){
        var nowTime = new Date().getTime();   // 获取本次轮询的 时间戳,  即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
        var ticker = _C(exchange.GetTicker);  // 获取行情数据
        var buy1Price = ticker.Buy;           // 从行情数据的返回值取得 买一价
        var lastPrice = ticker.Last + 1;      // 取得最后成交价,为了2条线不重合在一起 ,我们加1
        ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
        ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
        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

पुनरीक्षण

चूंकि पूरी रणनीति के लिए एक मृत चक्र की आवश्यकता होती है, इसलिए गलतियों के लिए तैयार रहना आवश्यक है, क्योंकि ईओएफ असामान्यता को रीट्रीट के अंत में प्रक्रिया को समाप्त करने के लिए फेंक दिया जाएगा।

# !/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__

# ------------------------------ 策略部分开始 --------------------------

print exchange.GetAccount()     # 调用一些接口,打印其返回值。
print exchange.GetTicker()

def adjustFloat(v):             # 策略中自定义的函数
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # 具体的策略代码


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

# ------------------------------ 策略部分结束 --------------------------

try:
    main()                     # 回测结束时会 raise EOFError() 抛出异常,来停止回测的循环。所以要对这个异常处理,在检测到抛出的异常后调用 task.Join() 打印回测结果。
except:
    print task.Join()         

कस्टम रीसेट डेटा

exchange.SetData ((arr), कस्टम K-लाइन डेटा का उपयोग करके पुनः परीक्षण डेटा स्रोतों को स्विच करता है। Arr पैराग्राफ, एक तत्व है जो K-लाइन स्तंभ डेटा के लिए एक सरणी है ((यानीः K-लाइन डेटा सरणी, जो केवल जावास्क्रिप्ट पुनः परीक्षण का समर्थन करती है) ।

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

[
    1530460800,    // time     时间戳
    2841.5795,     // open     开盘价
    2845.6801,     // high     最高价
    2756.815,      // low      最低价
    2775.557,      // close    收盘价
    137035034      // volume   成交量
]

डेटा स्रोतों को तालिकाओं में रखा जा सकता है।

function init() {                                                          // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
    var arr = [                                                            // 回测的时候需要使用的K线数据
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // 时间最早的一根 K线柱 数据
        ... ,                                                              // K线数据太长,用 ... 表示,数据此处省略。
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // 时间最近的一根 K线柱 数据
    ]
    exchange.SetData(arr)                                                  // 导入上述 自定义的数据
    Log("导入数据成功")
}

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

एफएमजेड के बिना एक्सचेंजों का उपयोग करें

यदि असमर्थित एक्सचेंज और समर्थित एक्सचेंज के एपीआई बिल्कुल समान हैं, केवल आधार पते अलग हैं, तो आधार पते को स्विच करने के तरीके से समर्थन किया जा सकता है। विशेष रूप से एक्सचेंज को जोड़ने के लिए समर्थित एक्सचेंज का चयन करें, लेकिन एपीआई-केई द्वारा समर्थित एक्सचेंज को भरें, नीति में आईओ के साथ आधार पते को स्विच करें, जैसेः

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全

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

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

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

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

अपना स्वयं का क्वांटिफाइंग प्लेटफॉर्म बनाना

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

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

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

क्लाउड क्लासेस को बढ़ावा देना

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

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

काम पर लौटने का प्रचार

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

FMZ क्वांटिफाइंग प्लेटफॉर्म उद्यम संस्करण

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

नगर प्रणाली

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

एक्सचेंज कार्यक्रम

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


अधिक

बीबीडब्ल्यूड2009क्या आप समूह में शामिल हो सकते हैं?

मैकेओघास के देवता, वीर!

घास`` // टोकन फ्यूचर पुश उदाहरण var ACCESSKEYID = 'आपके टोकन खाते के लिए एक्सेस की' var apiClient = Dial (('wss://api.hbdm.com/notificationके लिए संपीड़ित करें=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 टाइमस्टैम्प = utc_date.toISOSstring (().substring ((0,19) var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent ((टाइमस्टैम्प) var signature = exchange.HMAC (("sha256", "base64", quest, "{{secretkey}}") ``

बीट सेनाकृपया मुझे बताएं कि यदि वेबसॉकेट एक सदस्यता बाजार से जुड़ा हुआ है, तो यह बाजार डेटा को read (() फ़ंक्शन के साथ प्राप्त करता है, है ना? यदि आप exchange.GetTicker (() का उपयोग करते हैं, तो यह स्थानीय कैश से डेटा नहीं निकालता है, लेकिन डेटा को वापस करने के लिए एक rest अनुरोध करता है, है ना? केवल टोकन एक समर्थन के माध्यम से exchange.IO (("वेबसॉकेट") बाजार को स्वीकार करने के तरीके को बदलता है, और फिर exchange.GetTicker (() और exchange.GetDepth (()) के साथ व्यापार के लिए डेटा का अनुरोध नहीं करता है, और स्थानीय बफ़र में मौजूद प्राप्त किए गए सदस्यता बाजार में डेटा प्राप्त करता है। मैं समझता हूँ, है ना?

घाससुझाव सत्यापन के अनुसार करें

जज़्लिउयुकृपया निम्नलिखित एफएमजेड टेलीग्राम समूह की सत्यापन जानकारी के बारे में पूछें।

शाल्तीलठीक है

घासहाँ, यह बेहतर है कि सभी वेबसॉकेट डायल के साथ हैं, अधिक सहज नियंत्रण के लिए