3
ফোকাস
1444
অনুসারী

FMZ কোয়ান্টেটিভ প্ল্যাটফর্ম স্ট্র্যাটেজি রাইটিং অ্যাডভান্সড টিউটোরিয়াল

তৈরি: 2019-08-19 15:54:35, আপডেট করা হয়েছে: 2021-06-08 16:14:57
comments   8
hits   32175

[TOC] এই টিউটোরিয়ালটি শেখার আগে আপনাকে শিখতে হবেএফএমজেড ইনভেন্টরস কোয়ান্টাম প্ল্যাটফর্ম ব্যবহারের সূচনাএবংএফএমজেড কোয়ান্টামাইজেশন প্ল্যাটফর্মের কৌশল সম্পর্কে প্রাথমিক টিউটোরিয়ালএবং প্রোগ্রামিং ভাষা ব্যবহারে দক্ষ।প্রাথমিক টিউটোরিয়ালটি সর্বাধিক ব্যবহৃত ফাংশনগুলির সাথে সম্পর্কিত, তবে আরও অনেকগুলি ফাংশন এবং বৈশিষ্ট্য রয়েছে যা এই টিউটোরিয়ালটি কভার করবে না। প্ল্যাটফর্মের এপিআই ডকুমেন্টেশনটি নিজের জন্য দেখুন।এই টিউটোরিয়ালটি পড়ার পর, আপনি আরো স্বাধীন এবং কাস্টমাইজড কৌশল লিখতে সক্ষম হবেন, এবং এফএমজেড প্ল্যাটফর্মটি কেবল একটি হাতিয়ার।

এক্সচেঞ্জের কাঁচা তথ্য অ্যাক্সেস করুন

এফএমজেড প্ল্যাটফর্মটি সমস্ত সমর্থিত এক্সচেঞ্জের জন্য প্যাকেজ করা হয়েছে। একত্রীকরণের জন্য, একক এক্সচেঞ্জের জন্য এপিআই সমর্থন সম্পূর্ণ নয়। যেমন কে লাইন প্রাপ্তি সাধারণত কে লাইনের সংখ্যা বা শুরু হওয়ার সময় প্রেরণ করা যেতে পারে, যখন এফএমজেড প্ল্যাটফর্মটি স্থির থাকে, কিছু প্ল্যাটফর্ম বাল্ক অর্ডার সমর্থন করে, এফএমজেড সমর্থন করে না ইত্যাদি। সুতরাং এক্সচেঞ্জের ডেটাতে সরাসরি অ্যাক্সেসের একটি পদ্ধতি প্রয়োজন।প্রকাশ্য ইন্টারফেসের জন্য (যদি থাকে), ব্যবহার করা যেতে পারেHttpQuery(অ্যাকাউন্টের তথ্যের জন্য)IOনির্দিষ্ট ইনপুট প্যারামিটারগুলির জন্য, প্রাসঙ্গিক এক্সচেঞ্জ API ডকুমেন্টেশন দেখুন।Infoএই ক্ষেত্রটি মূল তথ্য ফেরত দেয়, কিন্তু এখনও ইন্টারফেস সমর্থন না করার সমস্যাটি সমাধান করতে পারে না।

GetRawJSON()

শেষ REST API অনুরোধের মূল বিষয়বস্তু ফেরত দেয় (string), যা এক্সটেনশন তথ্যটি নিজেরাই পার্স করতে ব্যবহার করা যেতে পারে।

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 পদ্ধতি, এবং আরও অনেক কিছু সমর্থন করে, API ডকুমেন্টেশন দেখুন।

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 ফাংশনটি ব্যবহার করা যেতে পারে, ব্যবহারকারীকে কেবলমাত্র প্যারামিটারগুলি প্রেরণ করতে হবে, নির্দিষ্ট স্বাক্ষর প্রক্রিয়াটি নীচের স্তর দ্বারা সম্পন্ন হবে।

এফএমজেড প্ল্যাটফর্ম বর্তমানে বিটএমইএক্স স্টপ ওয়ারেন্ট সমর্থন করে না, নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করে আইওর মাধ্যমে বাস্তবায়ন করুন:

  • BitMEX এর API ইন্টারফেস সম্পর্কে জানার জন্য এখানে যানঃhttps://www.bitmex.com/api/explorer/
  • বিটমেক্সের ঠিকানাঃhttps://www.bitmex.com/api/v1/order, পদ্ধতিPOST。 FMZ এর ভিতরে root address দেওয়া আছে, তাই শুধু “/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

ওয়েবসকেট ব্যবহার করে

মূলত সমস্ত ডিজিটাল মুদ্রা এক্সচেঞ্জ ওয়েবসকেট প্রেরণ সমর্থন করে, কিছু এক্সচেঞ্জ ওয়েবসকেট আপডেট অ্যাকাউন্টের তথ্য সমর্থন করে। রেস্ট এপিআইয়ের তুলনায়, ওয়েবসকেট সাধারণত কম বিলম্ব, উচ্চ ফ্রিকোয়েন্সি, প্ল্যাটফর্মের রেস্ট এপিআই ফ্রিকোয়েন্সি সীমাবদ্ধতা ছাড়াই কিছুটা, অসুবিধা হ’ল বিরতি সমস্যা, প্রক্রিয়াটি স্বজ্ঞাত নয়।

এই নিবন্ধটি মূলত এফএমজেড ইনভেন্টর কোয়ান্টিফিকেশন প্ল্যাটফর্মের সাথে সম্পর্কিত হবে, জাভাস্ক্রিপ্ট ভাষা ব্যবহার করে, প্ল্যাটফর্মের সাথে সংযুক্ত ডায়াল ফাংশন ব্যবহার করে, ডকুমেন্টেশনে বিশদ বিবরণ এবং প্যারামিটার, ডায়াল অনুসন্ধান করুন, বিভিন্ন কার্যকারিতা বাস্তবায়নের জন্য ডায়াল ফাংশনটি বেশ কয়েকবার আপডেট করা হয়েছে, এই নিবন্ধটি এটিকে কভার করবে এবং ডাব্লুএসএস-ভিত্তিক ইভেন্ট-চালিত কৌশল এবং একাধিক এক্সচেঞ্জের সাথে সংযোগ স্থাপনের বিষয়ে আলোচনা করবে। পাইথন ডায়াল ফাংশনটি ব্যবহার করতে পারে, বা সংশ্লিষ্ট লাইব্রেরি ব্যবহার করতে পারে।

1. ওয়েবসকেট সংযোগ

সাধারণত, সরাসরি সংযোগের মাধ্যমে, যেমন মুদ্রা সুরক্ষা টিকার প্রেরণঃ

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")

কিছু এক্সচেঞ্জের অনুরোধগুলি url-এ রয়েছে, এবং কিছু চ্যানেলের জন্য তাদের নিজস্ব সাবস্ক্রিপশন প্রয়োজন, যেমন coinbase:

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

২. ঘনিষ্ঠভাবে সংযুক্ত

সাধারণত ওয়েবসকেট ব্যবহার করা হয়, তবে এটি অর্ডার এবং অ্যাকাউন্টের জন্যও ব্যবহার করা যেতে পারে। এই ধরনের এনক্রিপ্ট করা ডেটা প্রেরণ কখনও কখনও খুব বিলম্বিত হতে পারে, তাই সাবধানতা অবলম্বন করা উচিত। যেহেতু এনক্রিপশন পদ্ধতিটি জটিল, এখানে কয়েকটি উদাহরণ দেওয়া হয়েছে। নোট করুন যে কেবলমাত্র অ্যাক্সেসকি প্রয়োজন, এটি নীতিগত প্যারামিটার হিসাবে সেট করা যেতে পারে, যদি সিক্রেটকি প্রয়োজন হয় তবে এক্সচেঞ্জ.এইচএমএসি () ফাংশনটি গোপনীয়ভাবে কল করা যেতে পারে, যা সুরক্ষা নিশ্চিত করে।

    //火币期货推送例子
    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 ডেটা ধাক্কা খুব দ্রুত, গো এর নীচের স্তরটি সমস্ত ডেটা ক্যুতে সংরক্ষণ করে, যেমন প্রোগ্রামটি পড়ার জন্য কল করে এবং তারপরে ফিরে আসে। এবং রিয়েল-ডিস্কে অর্ডার করার মতো ক্রিয়াকলাপগুলি বিলম্বিত হতে পারে, যা ডেটা জমে থাকতে পারে। লেনদেনের ধাক্কা, অ্যাকাউন্টের ধাক্কা, গভীরতার ইনস্টলড ধাক্কা ইত্যাদির জন্য, আমাদের ইতিহাসের ডেটা প্রয়োজন, এবং বাস্তবতার ডেটা জন্য, আমরা বেশিরভাগ ক্ষেত্রে কেবলমাত্র সাম্প্রতিকতম সম্পর্কে যত্নশীল, historicalতিহাসিক ডেটা সম্পর্কে চিন্তা করি না।

read()যদি কোন প্যারামিটার না থাকে, তাহলে সবচেয়ে পুরনো ডাটা রিটার্ন করা হবে। যদি ডাটা না থাকে তাহলে রিটার্ন করার জন্য ব্লক করা হবে।client.read(-2)এখনই সাম্প্রতিকতম ডেটা ফেরত দিন, তবে ডেটা শেষ হয়ে গেলে null ফেরত দিন, পুনরায় উল্লেখ করার জন্য বিচার করা দরকার

ক্যাশে থাকা পুরানো ডেটা কীভাবে ব্যবহার করা হয় এবং ডেটা না থাকলে এটি আটকে যায় কিনা তার উপর নির্ভর করে, read এর বিভিন্ন প্যারামিটার রয়েছে, যা নীচের চিত্রের মতো জটিল বলে মনে হচ্ছে, তবে এটি প্রোগ্রামটিকে আরও নমনীয় করে তোলে। FMZ কোয়ান্টেটিভ প্ল্যাটফর্ম স্ট্র্যাটেজি রাইটিং অ্যাডভান্সড টিউটোরিয়াল

৪. একাধিক এক্সচেঞ্জের ওয়েবসকেট সংযুক্ত করুন

এই ধরনের পরিস্থিতির জন্য সহজ 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) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // 此时币安有数据返回
            }
            if(msgCoinbase){
                // 此时coinbase有数据返回
            }
            Sleep(1) // 可以休眠1ms
        }
    }

৫. সংযোগ বিচ্ছিন্ন সমস্যা

এই অংশটি পরিচালনা করা বেশ ঝামেলাজনক, কারণ ধাক্কা দেওয়া ডেটা বাধাগ্রস্ত হতে পারে, বা ধাক্কা দেওয়া বিলম্ব খুব বেশি, এমনকি যদি হার্টবিট গ্রহণ করা হয় তবে ডেটা এখনও ধাক্কা দেওয়া হচ্ছে না, আপনি একটি ইভেন্টের ব্যবধান সেট করতে পারেন, যদি আপডেট না পাওয়া যায় তবে পুনরায় সংযোগ করুন, এবং কিছু সময়ের পরে বিশ্রামের সাথে ফিরে আসা ফলাফলের তুলনা করে দেখুন যে ডেটা সঠিক কিনা। এই বিশেষ পরিস্থিতির জন্য, সরাসরি স্বয়ংক্রিয় পুনরায় সংযোগ স্থাপন করা যেতে পারে।

৬. ওয়েবসকেট ব্যবহার করে সাধারণ প্রোগ্রামিং ফ্রেমওয়ার্ক

যেহেতু পুশ ডেটা ব্যবহার করা হয়েছে, তাই প্রোগ্রামটি ইভেন্ট ড্রাইভ হিসাবেও লিখতে হবে, তবে সতর্কতা অবলম্বন করুন যে পুশ ডেটা প্রায়শই থাকে, খুব বেশি অনুরোধ না করে ব্লক করা হয়, সাধারণত এটি লিখতে পারেঃ

    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)
        }
    }

৭. সংক্ষিপ্তসার

বিভিন্ন এক্সচেঞ্জের ওয়েবসকেটের সংযোগ পদ্ধতি, ডেটা প্রেরণ পদ্ধতি, সাবস্ক্রাইবযোগ্য সামগ্রী এবং ডেটা ফর্ম্যাট প্রায়শই আলাদা হয়, তাই প্ল্যাটফর্মটি মোড়ানো হয় না, ডায়াল ফাংশন দিয়ে স্বয়ংক্রিয়ভাবে সংযুক্ত হওয়া প্রয়োজন। এই নিবন্ধটি মূলত কিছু মৌলিক সতর্কতা কভার করে, যদি আরও প্রশ্ন থাকে তবে জিজ্ঞাসা করতে স্বাগতম।

PS. কিছু এক্সচেঞ্জ যদিও ওয়েবসকেট ফর্ম্যাট দেয় না, কিন্তু আসলে তারা ডিকম্প্রেসড ফাংশন ব্যবহার করে এবং তারা ওয়েবসকেট প্রেরণ ব্যবহার করে। আপনি সাবস্ক্রিপশন ফর্ম্যাট এবং রিটার্ন ফর্ম্যাট খুঁজে পেতে পারেন। কিছু কিছু দেখতে এনক্রিপ্ট করা হয়েছে এবং এটি base64 ডিকম্প্রেসড দিয়ে ডিকম্প্রেস করা হয়েছে।

মাল্টিথ্রেড সমান্তরাল

জাভাস্ক্রিপ্ট Go ফাংশন দ্বারা সমান্তরাল বাস্তবায়ন করতে পারে এবং পাইথন সংশ্লিষ্ট মাল্টিথ্রেড লাইব্রেরি ব্যবহার করতে পারে।

কোয়ান্টাম কৌশল বাস্তবায়নের ক্ষেত্রে, অনেক ক্ষেত্রে, সমান্তরালভাবে সম্পাদন করা বিলম্বের দক্ষতা হ্রাস করতে পারে। উদাহরণস্বরূপ, একটি হিজারি কৌশল রিয়েল-ডিস্কের জন্য, দুটি মুদ্রার গভীরতা অর্জন করা প্রয়োজন, ক্রমিকভাবে সম্পাদিত কোডটি নিম্নরূপঃ

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

বিশ্রামের এপিআই একবার অনুরোধ করতে দেরি হয়, ধরে নিলাম যে দুবার গভীরতা পাওয়ার সময়টি যদি আরও বেশি অ্যাক্সেসের প্রয়োজন হয়, তাহলে বিলম্বের সমস্যাটি আরও প্রকট হবে এবং কৌশলটি কার্যকর করাকে প্রভাবিত করবে৷

জাভাস্ক্রিপ্টের কোন মাল্টিথ্রেড নেই, তাই Go ফাংশনটি এই সমস্যার সমাধান করে। Go ফাংশনটি এমন এপিআইগুলির জন্য ব্যবহার করা যেতে পারে যা নেটওয়ার্ক অ্যাক্সেস প্রয়োজন, যেমন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({…})অভ্যন্তরীণ প্যারামিটার হল HighStock এবং HighCharts অবজেক্ট, শুধুমাত্র একটি অতিরিক্ত প্যারামিটার যোগ করা হয়েছে__isStockHighStock কি না তা আলাদা করার জন্য। HighStock টাইম সিকোয়েন্সের উপর বেশি মনোযোগ দেয়, তাই এটি বেশি ব্যবহৃত হয়। FMZ মূলত HighCharts এবং HighStock এর মৌলিক মডিউল সমর্থন করে, তবে অতিরিক্ত মডিউল সমর্থন করে না।

HighCharts এর উদাহরণঃ https://www.highcharts.com/demo; HighStock এর উদাহরণঃ https://www.highcharts.com/stock/demo। এই উদাহরণগুলির কোডগুলি FMZ এ সহজেই পোর্ট করা যায়।

add (_) কল করা যাবে[series index ((যেমন 0), data)) একটি নির্দিষ্ট সূচকের series এ ডেটা যোগ করে, reset () কল করে খালি চার্ট ডেটা, reset একটি ডিজিটাল প্যারামিটার নিয়ে যেতে পারে, সংরক্ষিত কলামের সংখ্যা নির্দিষ্ট করে। একাধিক চার্ট প্রদর্শন সমর্থন করে, কনফিগার করার সময় কেবল অ্যারে প্যারামিটার পাস করা দরকার যেমনঃ var chart = Chart ()[{…}, {…}, {…}]), উদাহরণস্বরূপ, চিত্র একের দুটি সিরিজ রয়েছে, চিত্র দুইটির একটি সিরিজ রয়েছে, চিত্র তিনটির একটি সিরিজ রয়েছে, সুতরাং add যখন 0 এবং 1 ক্রম আইডি নির্দিষ্ট করে তখন চিত্র 1 এর দুটি ক্রমের ডেটা আপডেট করা হয়, add যখন ক্রম আইডি 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

পর্যবেক্ষণ

পাইথন স্থানীয় প্রতিক্রিয়া

এটির জন্য, আপনি আপনার কম্পিউটারে একটি পিএইচপি ফাইল তৈরি করতে পারেন।

ইনস্টল করুন

কমান্ড লাইনে নিম্নলিখিত কমান্ড লিখুনঃ

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), পুনরাবৃত্তিমূলক ডেটা উত্সকে পরিবর্তন করে কাস্টমাইজড কে-লাইন ডেটা ব্যবহার করে। Arr, একটি অ্যারে যার উপাদানগুলি কে-লাইন স্তম্ভের ডেটা ((যেমনঃ কে-লাইন ডেটা অ্যারে, যা আপাতত কেবল জাভাস্ক্রিপ্ট পুনরাবৃত্তি সমর্থন করে) ।

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("导入数据成功")
}

দ্রষ্টব্যঃ ইনিশিয়েলাইজেশনের সময় অবশ্যই কাস্টম ডেটা আমদানি করতে হবে (অর্থাৎ exchange.SetData ফাংশন সেটআপ ডেটা কল করুন) । কাস্টম K-লাইন ডেটা পিরিয়ডটি অবশ্যই রিটার্নিং পৃষ্ঠায় সেট করা নীচের K-লাইন পিরিয়ডের সাথে সামঞ্জস্যপূর্ণ হতে হবে। অর্থাৎ, কাস্টম K-লাইন ডেটা, একটি K-লাইন সময় 1 মিনিট, তারপরে রিটার্নিংয়ে সেট করা নীচের K-লাইন পিরিয়ডটি 1 মিনিট হিসাবেও সেট করা হবে।

FMZ ব্যবহার করে অ-সমর্থিত এক্সচেঞ্জ

যদি একটি অসমর্থিত এক্সচেঞ্জ এবং একটি সমর্থিত এক্সচেঞ্জের এপিআই সম্পূর্ণরূপে একই হয়, তবে বেস ঠিকানাটি আলাদা, তবে বেস ঠিকানাটি স্যুইচ করে সমর্থন করা যেতে পারে। এক্সচেঞ্জ যুক্ত করার জন্য নির্দিষ্টভাবে সমর্থিত এক্সচেঞ্জ নির্বাচন করুন, তবে API-KEY অসমর্থিত এক্সচেঞ্জটি পূরণ করুন, নীতিতে আইও দিয়ে বেস ঠিকানাটি স্যুইচ করুন, যেমনঃ

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

সব এক্সচেঞ্জ FMZ সমর্থন করে না, কিন্তু এই প্ল্যাটফর্মটি সাধারণ প্রোটোকল অ্যাক্সেস প্রদান করে।

  • এই প্রোগ্রামটি একটি নেটওয়ার্ক সার্ভিস তৈরি করবে।
  • FMZ প্ল্যাটফর্মে এক্সচেঞ্জ যোগ করুন, নেটওয়ার্ক পরিষেবাদির ঠিকানা এবং পোর্ট নির্দিষ্ট করুন।
  • যখন ট্রাস্টি একটি সাধারণ প্রোটোকল এক্সচেঞ্জের রিয়েল-টাইমে চালায়, তখন নীতিমালার এপিআই অ্যাক্সেসগুলি সাধারণ প্রোটোকলে প্রেরণ করা হয়।
  • সাধারণ চুক্তি অনুসারে অনুরোধের ভিত্তিতে এক্সচেঞ্জ পরিদর্শন করুন এবং ফলাফলটি ট্রাস্টিকে ফেরত দিন।

সহজ কথায় বলতে গেলে, জিপিও একটি মধ্যস্থতাকারী, যা হোস্টের অনুরোধের প্রতিনিধিত্ব করে এবং সংশ্লিষ্ট মান অনুসারে ডেটা ফেরত দেয়। জিপিওর কোডটি নিজের দ্বারা সম্পন্ন করা প্রয়োজন, এবং জিপিও লিখতে আসলে আপনি এক্সচেঞ্জের সাথে একচেটিয়াভাবে অ্যাক্সেস করতে পারেন, কৌশলটি সম্পন্ন করুন। এফএমজেড অফিসিয়ালরা কখনও কখনও এক্সচেঞ্জের জিপিওর এক্সই সংস্করণ প্রকাশ করে। জিপিও পাইথন ব্যবহার করেও সম্পন্ন করা যেতে পারে, যা একটি সাধারণ ডিস্ক হিসাবে হোস্টের উপর চালিত হতে পারে।

এফএমজেড-এর প্রতিবেদনে বলা হয়, এই চুক্তির বিষয়ে বিস্তারিত জানার জন্য, পাইথন একটি সাধারণ প্রোটোকল লেখার উদাহরণঃhttps://www.fmz.com/strategy/101399

আপনার নিজের কোয়ান্টাম প্ল্যাটফর্ম তৈরি করুন

এক্সচেঞ্জের মতো, সমস্ত ক্রিয়াকলাপ এপিআইয়ের মাধ্যমে বাস্তবায়িত হতে পারে, এফএমজেড ওয়েবসাইটটিও এপিআই ভিত্তিক, আপনি নিজের এফএমজেড ওয়েবসাইটের এপিআই-কেই বাস্তবায়নের জন্য আবেদন করতে পারেন যেমন তৈরি, পুনরায় চালু, বাস্তব ডিস্ক মুছে ফেলা, বাস্তব ডিস্ক তালিকা প্রাপ্তি, বাস্তব ডিস্ক লগ প্রাপ্তি ইত্যাদি বিভিন্ন ফাংশন, বিশেষ উল্লেখ করুন এপিআই ডকুমেন্টেশন বিভাগ এফএমজেড প্ল্যাটফর্ম এক্সটেনশন এপিআই বিভাগ।

FMZ প্ল্যাটফর্মের শক্তিশালী এক্সটেনশনযোগ্যতার কারণে, আপনি এক্সটেনশন API এর উপর ভিত্তি করে আপনার নিজস্ব পরিমাণ প্ল্যাটফর্ম তৈরি করতে পারেন, ব্যবহারকারীদের আপনার প্ল্যাটফর্মে রিয়েল-টাইম চালানোর অনুমতি দিন।

এফএমজেড-এর অংশীদার হোন

নেটিজেন ক্লাউড ক্লাসরুম

ডিজিটাল মুদ্রা লেনদেনের বাজারটি ক্রমবর্ধমান পরিমাণে ব্যবসায়ীদের মনোযোগের কেন্দ্রবিন্দুতে রয়েছে, কারণ এর বিশেষত্বটি হ’ল কার্যকরী লেনদেন ইতিমধ্যে ডিজিটাল মুদ্রার মূলধারার একটি অংশ, এবং বাজারের মতো কৌশলগুলি সর্বদা সক্রিয় থাকে। এবং প্রোগ্রামিংয়ের দুর্বল ভিত্তিযুক্ত শিক্ষানবিসরা এই ক্ষেত্রে প্রবেশ করতে চান, বিপুল সংখ্যক এক্সচেঞ্জ এবং একাধিক পরিবর্তনশীল এপিআইয়ের মুখোমুখি হন। উদ্ভাবক (FMZ) কোয়ান্টেশন প্ল্যাটফর্ম (মূলত BotVs, www.fmz.com) বর্তমানে বৃহত্তম ডিজিটাল মুদ্রা সম্প্রদায়ের কোয়ান্টেশন প্ল্যাটফর্ম, 4 বছরেরও বেশি সময় ধরে হাজা�