[TOC] এই টিউটোরিয়ালটি শেখার আগে আপনাকে শিখতে হবে।এফএমজেড ইনভেন্টর কোয়ালিফাইং প্ল্যাটফর্ম ব্যবহার করেএবংএফএমজেড কোয়ালিফাইড প্ল্যাটফর্মের কৌশল লিখুনতিনি বলেন, 'আমি আমার পরিবার ও বন্ধুবান্ধবদের সঙ্গে কথা বলেছি।প্রাথমিক টিউটোরিয়ালটি সর্বাধিক ব্যবহৃত ফাংশনগুলির সাথে সম্পর্কিত, তবে আরও অনেকগুলি ফাংশন এবং কার্যকারিতা রয়েছে যা এই টিউটোরিয়ালে অন্তর্ভুক্ত করা হয়নি এবং আপনার নিজের জন্য প্ল্যাটফর্মের এপিআই ডকুমেন্টেশনটি দেখতে হবে।এই টিউটোরিয়ালটি পড়ার পর, আপনি আরও স্বাধীন, কাস্টমাইজড কৌশল লিখতে সক্ষম হবেন।
এফএমজেড প্ল্যাটফর্মটি সমস্ত সমর্থিত এক্সচেঞ্জের জন্য প্যাকেজ করা হয়েছে, যাতে একীকরণ বজায় রাখা যায়, একক এক্সচেঞ্জের জন্য এপিআই সমর্থন সম্পূর্ণ নয়। যেমন, কে-লাইন পাওয়ার জন্য সাধারণত কে-লাইন সংখ্যা বা শুরু হওয়ার সময় প্রেরণ করা হয়, যখন এফএমজেড প্ল্যাটফর্মটি স্থির হয়, কিছু প্ল্যাটফর্ম বাল্ক অর্ডার সমর্থন করে, এফএমজেড সমর্থন করে না, ইত্যাদি। সুতরাং সরাসরি এক্সচেঞ্জের ডেটা অ্যাক্সেস করার একটি পদ্ধতি প্রয়োজন।এটি একটি উন্মুক্ত ইন্টারফেসের জন্য ব্যবহার করা যেতে পারে (যেমন বাজারে)HttpQuery
অ্যাকাউন্টের তথ্য যোগ করার জন্য, এটি ব্যবহার করা প্রয়োজন।IO
。নির্দিষ্ট ইনপুট প্যারামিটার, এছাড়াও সংশ্লিষ্ট এক্সচেঞ্জ এপিআই ডকুমেন্টেশন পড়ুন; পূর্ববর্তী টিউটোরিয়ালে বর্ণনা করা হয়েছেInfo
ক্ষেত্রটি মূল তথ্য ফেরত দেয়, কিন্তু ইন্টারফেস সমর্থন করে না এমন সমস্যাটি এখনও সমাধান করতে পারে না।
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)
}
পাবলিক ইন্টারফেস অ্যাক্সেস, Js ব্যবহার করা যেতে পারেHttpQuery
Python এর সাথে সম্পর্কিত প্যাকেজগুলি নিজে নিজে ব্যবহার করতে পারেন, যেমনঃ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 ফাংশন ব্যবহার করা যেতে পারে, ব্যবহারকারীকে কেবলমাত্র ইনপুট পরামিতিগুলির সাথে উদ্বিগ্ন হতে হবে এবং নির্দিষ্ট স্বাক্ষর প্রক্রিয়াটি নীচের স্তর থেকে সম্পন্ন হবে।
এফএমজেড প্ল্যাটফর্ম বর্তমানে বিটমেক্স স্টপ লস টিকিট সমর্থন করে না।
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
মূলত সকল ডিজিটাল মুদ্রা বিনিময় প্রতিষ্ঠান ওয়েবসকেট প্রেরণ বাজারকে সমর্থন করে, কিছু বিনিময় প্রতিষ্ঠান ওয়েবসকেট অ্যাকাউন্টের তথ্য আপডেট করতে সহায়তা করে। rest API এর তুলনায়, websocket সাধারণত কম বিলম্ব, উচ্চ ফ্রিকোয়েন্সি এবং প্ল্যাটফর্ম rest API এর ফ্রিকোয়েন্সি সীমাবদ্ধতার অধীনে থাকে।
এই নিবন্ধটি প্রধানত FMZ ইনভেন্টর কোয়ালিফাইং প্ল্যাটফর্মের সাথে সম্পর্কিত, জাভাস্ক্রিপ্ট ভাষা ব্যবহার করে, প্ল্যাটফর্ম প্যাকেজযুক্ত ডায়াল ফাংশন ব্যবহার করে সংযোগ স্থাপন, ডকুমেন্টেশনে নির্দিষ্ট বিবরণ এবং পরামিতি, ডায়াল অনুসন্ধান, বিভিন্ন কার্যকারিতা বাস্তবায়নের জন্য ডায়াল ফাংশনটি বেশ কয়েকবার আপডেট করা হয়েছে। এই নিবন্ধটি এটিকে কভার করবে এবং ডাব্লুএসএস-ভিত্তিক ইভেন্ট ড্রাইভিং কৌশলগুলি এবং মাল্টি-এক্সচেঞ্জ সংযোগের সমস্যাগুলি সম্পর্কে আলোচনা করবে।
সাধারণভাবে, আপনি সরাসরি সংযোগ করতে পারেন, যেমন একটি টিকিট সুরক্ষা টিকার পাওয়ার জন্যঃ
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")
ডায়াল ফাংশনটি পুনরায় সংযোগ সমর্থন করে, যা অন্তর্নিহিত Go ভাষায় সম্পন্ন হয়, সনাক্তকরণের সংযোগটি বিচ্ছিন্ন হয়ে পুনরায় সংযোগ স্থাপন করে, অনুরোধকৃত ডেটা সামগ্রীটি ইতিমধ্যে ইউআরএলে রয়েছে, যেমন মাত্র বিয়াননের উদাহরণটি, এটি ব্যবহারের জন্য খুব সুবিধাজনক, সুপারিশ করা হয়। যারা বার্তা পাঠাতে চান তাদের জন্য পুনরায় সংযোগ প্রক্রিয়াটি নিজেরাই বজায় রাখতে পারেন।
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"]}')
ওয়েবসকেট সাধারণত ট্রেডিং পড়তে ব্যবহৃত হয়, তবে এটি অর্ডার এবং অ্যাকাউন্টের প্রেরণের জন্যও ব্যবহার করা যেতে পারে, এই ধরণের এনক্রিপশন ডেটা প্রেরণ কখনও কখনও খুব দীর্ঘ সময় নিতে পারে এবং সতর্কতার সাথে ব্যবহার করা উচিত। কারণ এনক্রিপশন পদ্ধতিগুলি আরও জটিল, এখানে কয়েকটি উদাহরণ দেওয়া হয়েছে। নোট করুন যে কেবলমাত্র অ্যাক্সেস কী প্রয়োজন, এটি গোপনীয় কী প্রয়োজন হলে নীতিগত প্যারামিটার হিসাবে সেট করা যেতে পারে, যা নিরাপত্তার জন্য এক্সচেঞ্জ.এইচএমএসি () ফাংশনটি গোপন কল করতে পারে।
//火币期货推送例子
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)
}
}
সাধারণত মৃত্যুর চক্রের সময় ক্রমাগত পাঠ করা হয়, কোডটি নিম্নরূপঃ
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 এর নীচের স্তরটি সমস্ত ডেটা ক্যোয়ারে বিলম্বিত করে, যেমন প্রোগ্রামটি পাঠ্য কল করার সময় আবার ফিরে আসে; এবং বাস্তব ডিস্কের নীচের তালিকা এবং অন্যান্য ক্রিয়াকলাপগুলি বিলম্বিত করে, যা ডেটা জমে উঠতে পারে। লেনদেনের প্রেরণ, অ্যাকাউন্টের প্রেরণ, গভীরতার ইনপুট প্রেরণ ইত্যাদির জন্য, আমাদের historicalতিহাসিক ডেটা দরকার, বাজারের ডেটার জন্য, আমরা বেশিরভাগ ক্ষেত্রে কেবলমাত্র সর্বশেষের বিষয়ে উদ্বিগ্ন, historicalতিহাসিক ডেটা নিয়ে উদ্বিগ্ন নই।
read()
যদি কোন প্যারামিটার যোগ না করা হয়, তাহলে পুরোনো তথ্য ফেরত দেওয়া হবে, কোন তথ্য না থাকলে ফিরে আসা পর্যন্ত ব্লক করা হবে।client.read(-2)
এটি তাত্ক্ষণিকভাবে সর্বশেষতম ডেটা ফেরত দেয়, তবে যখন কোনও ডেটা নেই তখন এটি ফিরে আসে এবং পুনরায় উল্লেখ করার জন্য সিদ্ধান্ত নিতে হবে।
ক্যাশে থাকা পুরনো ডেটা কিভাবে ব্যবহার করা হয় এবং কোন ডেটা না থাকলে এটি আটকে যায় কিনা তার উপর নির্ভর করে, 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
}
}
এই অংশটি হ'ল সমস্যাযুক্ত, কারণ প্রেরণের ডেটা বাধাগ্রস্ত হতে পারে, বা প্রেরণের বিলম্ব খুব বেশি, এমনকি যদি হার্টবিট গ্রহণ করা যায় না তবে ডেটা এখনও প্রেরণের প্রতিনিধিত্ব করে না, একটি ইভেন্টের ব্যবধান সেট করা যায়, যদি কোনও আপডেট না পাওয়া যায় তবে পুনরায় সংযোগ স্থাপন করা যায়, এবং এটি একটি নির্দিষ্ট সময় এবং rest ফিরে আসা ফলাফলের সাথে তুলনা করা ভাল।
যেহেতু ইতিমধ্যে পাঠানো ডেটা ব্যবহার করা হয়েছে, তাই প্রোগ্রামটি অবশ্যই ইভেন্ট ড্রাইভ হিসাবে লিখতে হবে, প্রায়শই ডেটা চালানোর জন্য মনোযোগ দিন, যাতে খুব বেশি অনুরোধের ফলে বন্ধ না হয়।
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)
}
}
বিভিন্ন এক্সচেঞ্জের ওয়েবসকেটের সংযোগের পদ্ধতি, ডেটা প্রেরণের পদ্ধতি, সাবস্ক্রাইবযোগ্য সামগ্রী, ডেটা ফর্ম্যাট প্রায়শই আলাদা হয়, তাই প্ল্যাটফর্মটি প্যাকেজ করা হয় না এবং ডায়াল ফাংশন দিয়ে স্বয়ংক্রিয়ভাবে সংযোগের প্রয়োজন হয়। এই নিবন্ধটি মূলত কিছু মৌলিক সতর্কতা coversেকেছে, যদি প্রশ্ন থাকে তবে প্রশ্নগুলি স্বাগতম।
PS. কিছু এক্সচেঞ্জ যদিও ওয়েবসকেট মার্কেট অফার করে না, কিন্তু প্রকৃতপক্ষে ল্যান্ডিং সাইটটি টেমপ্লেট ফাংশন ব্যবহার করে, আপনি দেখতে পাবেন যে ওয়েবসকেট প্রেরণ ব্যবহার করা হয়।
জাভাস্ক্রিপ্ট Go ফাংশনের মাধ্যমে সমান্তরালভাবে বাস্তবায়ন করতে পারে, এবং পাইথন একটি সংশ্লিষ্ট মাল্টি-থ্রেড লাইব্রেরি ব্যবহার করতে পারে।
অনেক ক্ষেত্রে, কুইন্টিফিকেশন কৌশল বাস্তবায়নের সময়, সমান্তরাল কার্যকরকরণ বিলম্বিত উত্সাহের দক্ষতা হ্রাস করতে পারে। হেজিং কৌশলগুলির বাস্তব ক্ষেত্রে, দুটি মুদ্রার গভীরতা অর্জন করা প্রয়োজন, ক্রমটি নিম্নরূপ কার্যকর করা হয়ঃ
var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()
একটি অনুরোধের সময় rest API বিলম্বিত হয়, যদি অনুমান করা হয় যে এটি 100ms হয়, তবে দুটি গভীরতা অর্জনের সময় আসলে ভিন্ন, যদি আরও বেশি পরিদর্শন প্রয়োজন হয় তবে বিলম্বের সমস্যাটি আরও বিশিষ্ট হবে এবং নীতির কার্যকরকরণকে প্রভাবিত করবে।
জাভাস্ক্রিপ্টের অনেকগুলি থ্রেড নেই, তাই নীচের অংশে 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 অবজেক্ট, শুধু একটি অতিরিক্ত পরামিতি যোগ করা হয়েছে__isStock
এটিকে হাইস্টক কিনা তা আলাদা করার জন্য; হাইস্টকটি একটি টাইমসকিউর চার্টে বেশি মনোনিবেশ করে, তাই এটি আরও বেশি ব্যবহৃত হয়। FMZ মূলত হাইচার্টস এবং হাইস্টকের মৌলিক মডিউলগুলি সমর্থন করে তবে অতিরিক্ত মডিউলগুলি সমর্থন করে না।
হাইচার্টের উদাহরণঃhttps://www.highcharts.com/demoহাইস্টক উদাহরণঃhttps://www.highcharts.com/stock/demo⇒ এই উদাহরণগুলির কোডটি FMZ-এ সহজেই স্থানান্তরিত করা যায়।
আপনি add (([series index ((যেমন ০, ডেটা]) কল করে নির্দিষ্ট সূচকের সিরিজে ডেটা যোগ করতে পারেন, reset () কল করুন) খালি গ্রাফ ডেটা, reset একটি সংখ্যাগত পরামিতি সহ সংরক্ষিত রেখাটি নির্দিষ্ট করতে পারে। একাধিক গ্রাফ প্রদর্শন করতে সহায়তা করে, কনফিগারেশনের সময় কেবলমাত্র অ্যারে পরামিতি প্রেরণ করা যেতে পারে যেমনঃ var chart = Chart (([{...}, {...}, {...}]), উদাহরণস্বরূপ, একটি গ্রাফের দুটি সিরিজ রয়েছে, গ্রাফটির একটি সিরিজ রয়েছে, গ্রাফটি তিনটি সিরিজ, তাহলে add যখন একটি 01 সিরিজ আইডি নির্দিষ্ট করে তখন এটি গ্রাফ 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
উন্মুক্ত উত্সের নির্দিষ্ট ঠিকানাঃ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__
# ------------------------------ 策略部分开始 --------------------------
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 পরামিতি, একটি উপাদান যা 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("导入数据成功")
}
দ্রষ্টব্যঃ ইনস্টলেশনের সময় অবশ্যই কাস্টম ডেটা (যেমন exchange.SetData ফাংশন সেট ডেটা কল করা) আমদানি করা আবশ্যক। কাস্টম K-লাইন ডেটা চক্রটি পুনরুদ্ধার পৃষ্ঠার সেটিংসের অন্তর্নিহিত K-লাইন চক্রের সাথে সামঞ্জস্যপূর্ণ হতে হবে, অর্থাৎঃ কাস্টম K-লাইন ডেটা, একটি K-লাইন সময় 1 মিনিট, তাহলে পুনরুদ্ধারে সেট করা অন্তর্নিহিত K-লাইন চক্রটিও 1 মিনিটের জন্য সেট করা হবে।
যদি অসমর্থিত এক্সচেঞ্জ এবং সমর্থিত এক্সচেঞ্জের এপিআই সম্পূর্ণরূপে একই হয়, কেবলমাত্র বেস অ্যাড্রেস ভিন্ন হয়, তবে বেস অ্যাড্রেস স্যুইচ করার পদ্ধতিতে সমর্থন করা যেতে পারে। বিশেষত এক্সচেঞ্জ যোগ করার সময় সমর্থিত এক্সচেঞ্জ নির্বাচন করুন, তবে API-KEY অসমর্থিত এক্সচেঞ্জগুলি পূরণ করে, নীতিতে আইও দিয়ে বেস অ্যাড্রেস স্যুইচ করুন, যেমনঃ
exchange.IO("base", "http://api.huobi.pro")
//http://api.huobi.pro为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全
যদিও সব এক্সচেঞ্জ এফএমজেড সমর্থন করে না, তবে এই প্ল্যাটফর্মটি সাধারণ প্রোটোকলের অ্যাক্সেস প্রদান করে।
সহজভাবে বলতে গেলে, একটি সাধারণ প্রোটোকল হল একজন মধ্যস্থতাকারী, যিনি হোস্টের অনুরোধের জন্য উপযুক্ত মানদণ্ড অনুসারে প্রতিনিধিত্ব করেন এবং ডেটা ফেরত দেন। একটি সাধারণ প্রোটোকলের কোডটি নিজের দ্বারা সম্পন্ন করা দরকার, এবং একটি সাধারণ প্রোটোকল লিখতে আসলে এটি প্রতিনিধিত্ব করে যে আপনি পৃথকভাবে এক্সচেঞ্জটি অ্যাক্সেস করতে পারেন এবং নীতিগুলি সম্পাদন করতে পারেন। FMZ অফিসিয়াল কখনও কখনও এক্সচেঞ্জের একটি সাধারণ প্রোটোকল এক্সই সংস্করণ প্রকাশ করে। একটি সাধারণ প্রোটোকল পাইথন দিয়েও সম্পন্ন করা যেতে পারে, যা একটি সাধারণ বাস্তব ডিস্ক হিসাবে হোস্টের উপর চালিত হতে পারে।
বিশেষ চুক্তির বিবরণঃhttps://www.fmz.com/bbs-topic/1052পাইথনে সাধারণ প্রোটোকল লেখার উদাহরণঃhttps://www.fmz.com/strategy/101399
এক্সচেঞ্জের মতো বিভিন্ন ক্রিয়াকলাপগুলি এপিআই এর মাধ্যমে বাস্তবায়িত হতে পারে, এফএমজেড ওয়েবসাইটটিও এপিআই ভিত্তিক। আপনি আপনার নিজের এফএমজেড ওয়েবসাইটের এপিআই-কেই বাস্তবায়নের জন্য আবেদন করতে পারেন, যেমন ভার্চুয়াল ডিস্ক তৈরি, পুনরায় চালু করা, মুছে ফেলা, ভার্চুয়াল ডিস্ক তালিকা প্রাপ্তি, ভার্চুয়াল ডিস্ক লগ প্রাপ্তি ইত্যাদি বিভিন্ন ফাংশন।
এফএমজেড প্ল্যাটফর্মের শক্তিশালী প্রসারণযোগ্যতার কারণে, আপনি এক্সটেনশন এপিআই-র উপর ভিত্তি করে আপনার নিজস্ব পরিমাণগত প্ল্যাটফর্ম তৈরি করতে পারেন, ব্যবহারকারীদের আপনার প্ল্যাটফর্মে বাস্তব ড্রাইভ চালানোর অনুমতি দিতে পারেন।
ডিজিটাল মুদ্রার লেনদেনের বাজার ক্রমবর্ধমানভাবে পরিমাণগত ব্যবসায়ীদের দৃষ্টি আকর্ষণ করে, কারণ এর বিশেষত্বগুলির কারণে, বাস্তবে প্রোগ্রামযুক্ত লেনদেন ডিজিটাল মুদ্রার মূলধারার হয়ে উঠেছে, হেজিং বাজার করার কৌশলগুলি সর্বদা বাজারে সক্রিয় থাকে।www.fmz.comএই কোর্সটি মাত্র ২০ ইউএস ডলারে শুরু করা হয়েছে এবং এটি নতুনদের জন্য।
প্রচারনেটওয়ার্ক ক্লাউড ক্লাস ডিজিটাল মুদ্রা পরিমাণগত লেনদেন কোর্স⇒ নেটিউন ক্লাউড ক্লাসে লগইন করুন, আপনার কোর্সের লিঙ্কটি শেয়ার করুন ((লিঙ্কটি একচেটিয়া কোর্স আইডি সহ), অন্যরা এই লিঙ্কটি ব্যবহার করে নিবন্ধন করুন এবং কোর্সটি কিনুন, আপনি ৫০% মোট ১০ ইউয়ান ভাগ পাবেন। ⇒ নোট করুন নেটিউন ক্লাউড ক্লাসের বুটিক কোর্স প্রচার করুন।
গ্রাহকরা প্রচার লিঙ্কটি ক্লিক করে এবং অর্ধ বছরের মধ্যে নিবন্ধন পুনরায় পূরণ করে, আমরা কার্যকর আদেশের কার্যকর পরিমাণ অনুসারে কমিশন ফেরত দেব। কমিশনটি পয়েন্টের আকারে প্রচারকের অ্যাকাউন্টে ফিরে আসবে। ব্যবহারকারীরা আবিষ্কারককে পরিমাণযুক্ত ট্রেডিং প্ল্যাটফর্ম অ্যাকাউন্টের ব্যালেন্সের বিনিময়ে 10:1 অনুপাতের বিনিময়ে ব্যবহার করতে পারবেন।https://www.fmz.com/bbs-topic/3828
সম্পূর্ণ এফএমজেড ওয়েবসাইটটি একটি সংস্থা বা দলের একচেটিয়া সার্ভারে স্থাপন করা যেতে পারে, যাতে সম্পূর্ণ নিয়ন্ত্রণ এবং কার্যকারিতা কাস্টমাইজ করা যায়। এফএমজেড ওয়েবসাইটটি প্রায় ১০০,০০০ ব্যবহারকারীর ব্যবহার এবং পরীক্ষার পরে উচ্চতর ব্যবহারযোগ্যতা এবং সুরক্ষা অর্জন করেছে, যা পরিমাণগত দল এবং ব্যবসায়ের সময় সাশ্রয় করতে পারে। এন্টারপ্রাইজ সংস্করণটি মাঝারি আকারের পরিমাণগত ট্রেডিং দল, পণ্যের ফিউচার সার্ভিস ইত্যাদির জন্য, নির্দিষ্ট উদ্ধৃতি পরিচালকের সাথে যোগাযোগ করে।
এক্সচেঞ্জগুলির জন্য বাজারের তরলতা এবং তহবিল পরিচালনার জন্য পেশাদার সিস্টেমগুলি সম্ভবত বাজারে সর্বাধিক পরিপূর্ণ বাজারের সিস্টেম, যা অনেকগুলি এক্সচেঞ্জ এবং দলের দ্বারা ব্যবহৃত হয়।
উদ্ভাবক প্রযুক্তিগত লেনদেন সিস্টেমটি মেমরি শট প্রযুক্তি ব্যবহার করে, অর্ডার প্রক্রিয়াজাতকরণের গতি 2 মিলিয়ন পয়েন্ট / সেকেন্ড পর্যন্ত, যা অর্ডার প্রক্রিয়াজাতকরণকে কোনও বিলম্ব এবং কার্টন থেকে রক্ষা করতে পারে। একই সাথে 20 মিলিয়নেরও বেশি অনলাইন ব্যবহারকারীর সাথে এক্সচেঞ্জের স্রোত এবং স্থিতিশীল অপারেশন বজায় রাখতে পারে। বহু-স্তরযুক্ত, বহু-সেটযুক্ত সিস্টেম আর্কিটেকচারটি সিস্টেমের সুরক্ষা, স্থায়িত্ব, সহজেই প্রসারণযোগ্যতা নিশ্চিত করে। বৈশিষ্ট্য স্থাপনের জন্য, সংস্করণ আপডেটগুলি সর্বাধিক বন্ধের প্রয়োজন ছাড়াই করা হয়, যা টার্মিনাল ব্যবহারকারীর অপারেটিং অভিজ্ঞতা সর্বাধিক সুরক্ষিত করে। বর্তমানে এই সিস্টেমটি wex.app অ্যানিমাল ট্রেডিংয়ে উপলব্ধ।
বিবিডব্লিউড ২০০৯আপনি কি দলে যোগ দিতে পারবেন?
মাইকিওগ্রীস গড, ওয়াই-ওয়াউ!
ঘাস`` // টোকন ফিউচার প্রেরণ উদাহরণ var ACCESSKEYID = 'আপনার টোকেন অ্যাকাউন্টের অ্যাক্সেস কী' 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 টাইমস্ট্যাম্প = utc_date.toISOSstring (().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}}") ``
বিট সেনাবাহিনীঅনুগ্রহ করে শেখাবেন, যদি ওয়েবসকেটটি একটি সাবস্ক্রিপশন মার্কেটের সাথে সংযুক্ত হয়, তাহলে মার্কেটের ডেটা read (()) ফাংশন দিয়ে পাওয়া যাবে, তাই না? যদি exchange.GetTicker (()) ব্যবহার করা হয় তবে এটি স্থানীয় ক্যাশে থেকে ডেটা বের করবে না, কিন্তু একটি rest অনুরোধ শুরু করবে যা ডেটা ফেরত দেবে, তাই না? কেবলমাত্র টোকন একটি সমর্থন করে যা এক্সচেঞ্জ.আইও (("ওয়েবসকেট") এর মাধ্যমে বাজারের গ্রহণযোগ্যতা পরিবর্তন করে এবং তারপর exchange.GetTicker (() এবং exchange.GetDepth (()) এর মাধ্যমে এক্সচেঞ্জের rest থেকে ডেটা অনুরোধ করে না, এবং স্থানীয় বাফারে বিদ্যমান ইতিমধ্যে গৃহীত সাবস্ক্রিপশন বাজারে ডেটা পান। আমি বুঝতে পারছি, তাই না?
ঘাসটিপস যাচাই করুন
জজলিউয়ুএফএমজেড টেলিগ্রাফ গ্রুপের তথ্য যাচাই করুন।
শালটিয়েলঠিক আছে
ঘাসহ্যাঁ, ডায়াল দিয়ে সব ওয়েবসকেট ব্যবহার করা ভাল, এটা আরো স্বজ্ঞাত