যদিওBinance.comবিটিসি দীর্ঘদিন ধরে প্রতিষ্ঠিত হয়নি, এর দুর্দান্ত প্রযুক্তির কারণে, এপিআই স্থিতিশীল এবং দক্ষ, অনুরোধের ফ্রিকোয়েন্সি সীমাও শিথিল, এবং অনেক মুদ্রা এবং সক্রিয় লেনদেন রয়েছে, যা ইতিমধ্যে স্পট ট্রেডিংয়ের জন্য পছন্দের প্ল্যাটফর্ম। বর্তমানে, 150 টিরও বেশি ধরণের মুদ্রা রয়েছে যা বিটিসি দ্বারা মূল্য নির্ধারণ করা হয় এবং তারা এখনও বাড়ছে, যা অনেক মুদ্রার দাম এবং কে-লাইন পাওয়া কঠিন করে তোলে। এই নিবন্ধটি মূলত এফএমজেড পরিমাণগত ট্রেডিং প্ল্যাটফর্মে মাল্টি-মুদ্রা কৌশলগুলি কীভাবে পরিচালনা করা যায় এবং এমনকি সমস্ত মুদ্রা সমস্যা ছাড়াই পরিচালনা করার জন্য মূলত একটি নির্দিষ্ট জ্ঞানের ভিত্তি সহ ব্যবহারকারীদের জন্য।
আপনি যদি একই সময়ে 150 টি মুদ্রা পরিচালনা করতে চান তবে বাজারের উদ্ধৃতি পেতে REST প্রোটোকল ব্যবহার করা স্পষ্টতই অনুপযুক্ত। এটি পোলিংয়ের পরে অনেক সময় নষ্ট করবে এবং ওয়েবসকেট একই সাথে এতগুলি মুদ্রায় সাবস্ক্রাইব করতে পারে না।Binance.comমার্কেট কোট পাওয়ার জন্য মাল্টি-ভেরিয়েট স্ট্র্যাটেজির সমস্যা উপলব্ধি করে এবং একটি সমষ্টিগত মার্কেট কোট ইন্টারফেস প্রদান করে।
এই REST ইন্টারফেস (/api/v1/ticker/24hr) সরাসরি ব্যবহার করার সময়, এটির ওজন 40 বলে মনে রাখতে হবে, যার অর্থ হল যে একটি অ্যাক্সেস সাধারণ 40 বার অ্যাক্সেসের সমতুল্য, এমনকি যদি আপনি 5 বা 6 সেকেন্ডে একবার এই ইন্টারফেসটি অ্যাক্সেস করেন তবে সীমা অতিক্রম করাও সম্ভব।
সুতরাং, আমাদের এই ইন্টারফেসের ওয়েবসকেট সংস্করণে অ্যাক্সেস করা দরকার, তবে সচেতন থাকুন যে বিপুল পরিমাণে ডেটার কারণে, ডেটাগুলি কেবলমাত্র বাজারের পরিবর্তনের সাথে ডেটাটি ধাক্কা দেওয়ার জন্য 1s এর জন্য স্থির করা হয়। কিছু অপ্রচলিত মুদ্রার জন্য যা কয়েক মিনিটের জন্য বাণিজ্য করা হয়নি, এটি দীর্ঘ সময়ের জন্য ধাক্কা দেওয়া নাও হতে পারে। স্থির ধাক্কা সময়গুলি উচ্চ ফ্রিকোয়েন্সি কৌশলগুলির জন্য উপযুক্ত নয়, তবে সাধারণ মাল্টি-মুদ্রা কৌশলগুলির জন্য পর্যাপ্ত। নির্দিষ্ট কোডটি নিম্নরূপঃ
function main() {
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
while (true){
var data = client.read();
var msg = JSON.parse(data);
updateTicker(msg);//The updateTicker function handles market quotes and transactions, which will be introduced below.
}
}
বাইনারেন্সের ট্রেডিং, ন্যূনতম লেনদেনের মূল্য, ন্যূনতম লেনদেনের পরিমাণ, দামের নির্ভুলতা এবং লেনদেনের পরিমাণের উপর অনেক বিধিনিষেধ রয়েছে। এগুলিকে আগে থেকে প্রস্তুত করা দরকার।
Defined global variables:
var totalbtc = 0;//Total value, not necessarily btc
var baseCoin = ['BTC', 'ETH', 'BNB', 'USDT'][baseCoin_select];//Base currency selection baseCoin_select is a parameter of the drop-down box
var exceptList = Except_list_string.split(',');//Excluded currency, Except_list_string is the strategy parameter
//K line cycle selects PERIOD_M1, PERIOD_M5 is FMZ default global variable
var period = [PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H1, PERIOD_D1][period_select]
var periodSecond = [60, 300, 900, 1800, 3600, 3600*24][period_select]//The number of seconds corresponding to each cycle
var lastPeriodTime = 0;//The most recent cycle time, used to update the K line
var updateProfitTime = 0//Recently updated earnings time to update revenue
var buyList = []//buying order list
var sellList = []//selling order list
var accountInfo = {};//Used to store transaction related data lists
পরবর্তী ধাপ হল accountInfo এর বিষয়বস্তু উন্নত করা, এবং ট্রেডিং জোড়ার সাথে সম্পর্কিত সমস্ত বিষয়বস্তু এতে সংরক্ষণ করা হয়।
if (!_G('accountInfo')){//If accountInfo is not stored in the database, reacquire the data.
var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'));//Get transaction related data
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'));//First use the rest protocol to get a full amount of ticker
var tradeSymbol = exchangeInfo.symbols.filter(function(x){return x.quoteAsset == baseCoin});//Filter the required trading pairs
accountInfo[baseCoin] = {free:0, frozen:0, last:1, value:0};//Base currency information
for (var i=0; i<tradeSymbol.length; i++){
var info = tradeSymbol[i];
if(exceptList.indexOf(info.symbol.slice(0,info.symbol.length-baseCoin.length)) >= 0){
continue;//Filter out the currencies that was kicked out
}
for (var j=0; j<ticker.length; j++){
var symbol = info.symbol.slice(0,info.symbol.length-baseCoin.length)//Currency name
if(ticker[j].symbol.slice(ticker[j].symbol.length-baseCoin.length) == baseCoin && ticker[j].symbol == info.symbol){
//The stored contents of the exchangeInfo and ticker
accountInfo[symbol] = {
last:parseFloat(ticker[j].lastPrice), free:0, frozen:0,
minQty:parseFloat(info.filters[2].minQty), minNotional:parseFloat(info.filters[3].minNotional)
tickerSize:parseFloat(info.filters[0].tickSize), stepSize:parseFloat(info.filters[2].stepSize),
ask:parseFloat(ticker[j].askPrice), bid:parseFloat(ticker[j].bidPrice), volume:parseFloat(ticker[j].quoteVolume),
lowPrice:parseFloat(ticker[j].lowPrice), highPrice:parseFloat(ticker[j].highPrice),
priceChangePercent:parseFloat(ticker[j].priceChangePercent),
sellPrice:0, buyPrice:0, state:0, value:0, records:null
}
break;
}
}
}
}else{
accountInfo = _G('accountInfo');
}
//Automatically save accountInfo to the database when exiting
function onexit(){
_G('accountInfo', accountInfo);
}
রিয়েল-টাইম আপডেট ছাড়াই অ্যাকাউন্ট তথ্য ফাংশন আপডেট করুন।
function updateAccount(){
account = exchange.GetAccount();
if (!account){
Log('time out');
return;//Returning directly here is to save time, and the account information acquisition is not affected in time.
}
for (var i=0; i<account.Info.balances.length; i++){
var symbol = account.Info.balances[i].asset
//Are stored in accountInfo
if (symbol in accountInfo){
accountInfo[symbol].free = parseFloat(account.Info.balances[i].free);
accountInfo[symbol].frozen = parseFloat(account.Info.balances[i].locked);
accountInfo[symbol].value = (accountInfo[symbol].free + accountInfo[symbol].frozen)*accountInfo[symbol].last
}
}
}
//Update the current account total value in the selected base currency
function updateTotalBTC(){
var btc = 0;
for (var symbol in accountInfo){
btc += accountInfo[symbol].value
totalbtc = btc;
}
}
Update the K line, the initial update can use the GetRecords function in stages, and the later update uses push data synthesis.
function initRecords(){
for (var symbol in accountInfo){
if(symbol == baseCoin){continue}
if(!accountInfo[symbol].records){
var currency = symbol + '_' + baseCoin;
//Switch trading pair
exchange.IO("currency", currency)
accountInfo[symbol].records = exchange.GetRecords(period)
Log('Update', currency, 'K line', accountInfo[symbol].records[accountInfo[symbol].records.length-1])
Sleep(250)//Update four per second, no limit will be reached
}
//Recent K-line time
lastPeriodTime = Math.max(accountInfo[symbol].records[accountInfo[symbol].records.length-1].Time/1000, lastPeriodTime)
}
}
//Update K line based on push ticker data
function updateRecords(msgTime){
//If the current time is greater than the last updated cycle, it indicates that a new K line needs to be generated.
if(parseFloat(msgTime)/1000 - lastPeriodTime > periodSecond){
for (var symbol in accountInfo){
if(symbol != baseCoin){
//If the K line missing of a trading pair is too much, it will be re-acquired once, it may be that the transaction is not active, ticker did not push
if(parseFloat(msgTime)/1000 - accountInfo[symbol].records[accountInfo[symbol].records.length-1].Time/1000 > 1.5*periodSecond){
var currency = symbol + '_' + baseCoin;
exchange.IO("currency", currency)
var records = exchange.GetRecords(period)
if(records){
accountInfo[symbol].records = exchange.GetRecords(period)
}
Log(symbol, 'K line is missing, regain')
}else{
//Push a new K line
accountInfo[symbol].records.push({"Time":parseInt(lastPeriodTime + periodSecond)*1000, "Open":accountInfo[symbol].last, "High":accountInfo[symbol].last,
"Low":accountInfo[symbol].last, "Close":accountInfo[symbol].last, "Volume":0})
}
}
}
lastPeriodTime = lastPeriodTime + periodSecond
Log(parseFloat(msgTime)/1000, 'Adding K line')
}else{
//If it is in the current K line cycle, update the current K line
for (var symbol in accountInfo){
if(symbol != baseCoin){
var length = accountInfo[symbol].records.length
accountInfo[symbol].records[length-1].Close = accountInfo[symbol].last
accountInfo[symbol].records[length-1].Volume += accountInfo[symbol].volume
if(accountInfo[symbol].last > accountInfo[symbol].records[length-1].High){
accountInfo[symbol].records[length-1].High = accountInfo[symbol].last
}
else if(accountInfo[symbol].last < accountInfo[symbol].records[length-1].Low){
accountInfo[symbol].records[length-1].Low = accountInfo[symbol].last
}
}
}
}
}
//Cancel current trading pair orders
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j]);
}
}
//Cancel all trading pair orders
function cancellAll(){
try{
var openOrders = exchange.IO('api', 'GET', '/api/v3/openOrders');
for (var i=0; i<openOrders.length; i++){
var order = openOrders[i];
var currency = order.symbol.slice(0,order.symbol.length-baseCoin.length) + '_' + baseCoin;
exchange.IO("currency", currency);
exchange.CancelOrder(order.orderId);
}
}
catch(err){
Log('Cancel order failed');
}
for (var symbol in accountInfo){
accountInfo[symbol].state = 0;
accountInfo[symbol].buyprice = 0;
accountInfo[symbol].sellPrice = 0;
}
}
//Placing the buying long order
function toBuy(){
//The currencies you need to buy are stored in the buyList
if (buyList.length == 0){
return;
}
for (var i=0; i<buyList.length; i++){
var symbol = buyList[i];
//Slippage is the "selling price 1" plus minimum trading unit, may not be completely executed immediately, you can modify it yourself
var buyPrice = accountInfo[symbol].ask + accountInfo[symbol].tickerSize;
buyPrice = _N(buyPrice, parseInt((Math.log10(1.1/accountInfo[symbol].tickerSize))));//Meet price accuracy
var currency = symbol + '_' + baseCoin;
exchange.IO("currency", currency);//Switch trading pair
//If you have placed an order and the price is same as this one, do not operate.
if (accountInfo[symbol].state && accountInfo[symbol].bid == accountInfo[symbol].buyprice){
continue;
}else{
//Order placed first will be cancelled first
if (accountInfo[symbol].state == 1){
CancelPendingOrders();
accountInfo[symbol].state = 0;
accountInfo[symbol].buyprice = 0;
}
var amount = (accountInfo[symbol].free + accountInfo[symbol].frozen)*buyPrice; //Value of existing currency
var needBuyBTC = HoldAmount - amount;//HoldAmount is a global parameter, which require value of the hold
var buyAmount = needBuyBTC/buyPrice;
buyAmount = _N(scale*buyAmount, parseInt((Math.log10(1.1/accountInfo[symbol].stepSize))));//Order quantity accuracy
//Meet minimum transaction volume and minimum transaction value requirements
if (buyAmount > accountInfo[symbol].minQty && buyPrice*buyAmount > accountInfo[symbol].minNotional){
if (accountInfo[baseCoin].free < buyPrice*buyAmount){return;}//Have enough base currency to buy
var id = exchange.Buy(buyPrice, buyAmount, currency);//Final order
if(id){
accountInfo[symbol].buyprice = buyPrice;
accountInfo[symbol].state = 1;
}
}
}
//If the buying orders are too much, it need a pause, Binance allows 10 orders every 1s maximum
if(buyList.length > 5){
Sleep(200)
}
}
}
//Placing the selling orders principles are similar to the buying orders
function toSell(){
if (sellList.length == 0){
return;
}
for (var i=0; i<sellList.length; i++){
var currency = symbol + '_' + baseCoin;
exchange.IO("currency", currency);
var sellPrice = accountInfo[symbol].bid - accountInfo[symbol].tickerSize;
sellPrice = _N(sellPrice, parseInt((Math.log10(1.1/accountInfo[symbol].tickerSize))));
if (accountInfo[symbol].state == 1 && accountInfo[symbol].bid != accountInfo[symbol].buyprice){
CancelPendingOrders();
accountInfo[symbol].state = 0;
accountInfo[symbol].sellPrice = 0;
}
var sellAmount = accountInfo[symbol].free;
sellAmount = _N(Math.min(scale*sellAmount,accountInfo[symbol].free), parseInt((Math.log10(1.1/accountInfo[symbol].stepSize))));
if (sellAmount > accountInfo[symbol].minQty && sellPrice*sellAmount > accountInfo[symbol].minNotional){
var id = exchange.Sell(sellPrice, sellAmount, currency);
if(id){
accountInfo[symbol].state = 1;
accountInfo[symbol].sellPrice = sellPrice;
}
}
if(sellList.length > 5){
Sleep(200)
}
}
}
ট্রেডিং খুবই সহজ, শুধু কিনে বিক্রি করা মুদ্রাকে buyList এবং sellList এ চাপুন।
function checkTrade(){
buyList = []
sellList = []
for(var symbol in accountInfo){
if(symbol == baseCoin){
continue
}
var length = accountInfo[symbol].records.length
//Simple moving average, this is a simple demonstration example, don't use it at the real market.
var fast = TA.MA(accountInfo[symbol].records, FastPeriod)[length-1]
var slow = TA.MA(accountInfo[symbol].records, SlowPeriod)[length-1]
if(accountInfo[symbol].value > 2*accountInfo[symbol].minNotional && fast < 0.99*slow){
sellList.push(symbol)
}
//HoldAmount strategy parameter
if(accountInfo[symbol].value < 0.9*HoldAmount && fast > 1.01*slow){
buyList.push(symbol)
}
}
}
কিভাবে এতগুলি ট্রেডিং মুদ্রা প্রদর্শন করা যায় তাও একটি সমস্যা। সৌভাগ্যক্রমে, এফএমজেড পরিমাণগত প্ল্যাটফর্ম একটি সম্পূর্ণ টেবিল ফাংশন সরবরাহ করে। এটি সংখ্যা অনুসারেও সাজানো যায়, যা সহজ এবং সুবিধাজনক। যখনই ওয়েবসকেট টিকারটি চাপবে, এটি ইভেন্ট-চালিত, লেনদেন এবং বিভিন্ন আপডেট লজিকের কারণে আপডেট হবে।
function updateStatus(msgTime){
//The specific data to be displayed can be defined by itself.
var table = {type: 'table', title: 'Position information',
cols: ['Currency', 'Bid', 'Ask','Last', 'Lowest price','Highest price','Price Amplitude','Volume','buying price','Selling price', 'frozen','Available','Present value'],
rows: []};
for (var symbol in accountInfo){
if(symbol == baseCoin){
var infoList = [symbol,0, 0, 1,0, 0, 0,0, 0, 0, 0, _N(accountInfo[symbol].frozen,4),_N(accountInfo[symbol].free,4), _N(accountInfo[symbol].value,5)];
}else{
var infoList = [symbol,accountInfo[symbol].bid, accountInfo[symbol].ask, accountInfo[symbol].last,
accountInfo[symbol].lowPrice, accountInfo[symbol].highPrice, accountInfo[symbol].priceChangePercent,
_N(accountInfo[symbol].volume,2), accountInfo[symbol].buyPrice, accountInfo[symbol].sellPrice,
_N(accountInfo[symbol].frozen,4),_N(accountInfo[symbol].free,4), _N(accountInfo[symbol].value,5)];
}
table.rows.push(infoList);
}
var logString = _D() + ' Net value:' + _N(totalbtc,6) + (typeof(msgTime) == 'number' ? (', Latest market time: ' + _D(msgTime)) : '') + '\n';
logString += 'The currency to be bought:' + buyList.join(',') + ' \n';
logString += 'The currency to be sold:' + sellList.join(',') + ' \n';
logString += 'Currently available'+ baseCoin + ':' + _N(accountInfo[baseCoin].free,6) + ',frozen:' + _N(accountInfo[baseCoin].frozen,6) + '\n';
LogStatus(logString + '`' + JSON.stringify(table) + '`');//Update to robot interface
}
//Every time pushes the ticker, it is updated because of the event-driven, transactional and various update logic.
function updateTicker(msg){
var ticker = msg;
var msgTime = 0;
for (var i=0; i<ticker.length; i++){
msgTime = Math.max(msgTime, ticker[i].E);
var symbol = ticker[i].s.slice(0,ticker[i].s.length-baseCoin.length)
if (ticker[i].s.slice(ticker[i].s.length-baseCoin.length) == baseCoin && parseFloat(ticker[i].c) && symbol in accountInfo){
accountInfo[symbol].last = parseFloat(ticker[i].c);
accountInfo[symbol].volume = _N(parseFloat(ticker[i].q),1);
accountInfo[symbol].lowPrice = parseFloat(ticker[i].l);
accountInfo[symbol].highPrice = parseFloat(ticker[i].h);
accountInfo[symbol].ask = parseFloat(ticker[i].a);
accountInfo[symbol].bid = parseFloat(ticker[i].b);
accountInfo[symbol].priceChangePercent = parseFloat(ticker[i].P);
accountInfo[symbol].value = (accountInfo[symbol].free + accountInfo[symbol].frozen)*accountInfo[symbol].last
}
}
if (Date.now() - updateProfitTime > LogProfitTime*1000){
updateAccount();
updateProfitTime = Date.now();//Reset revenue time
LogProfit(totalbtc);//Update revenue
}
updateRecords(msgTime)//Update K line
updateTotalBTC();//Update total market value
updateStatus(msgTime);//Update robot status
checkTrade()//Check which orders need to be placed
toBuy();//placing buying order
toSell();//placing selling order
}
function main() {
cancellAll();
initRecords()
updateAccount();
updateTotalBTC()
Log('Total transaction digital currency:', Object.keys(accountInfo).length-1);
updateStatus();
var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
while (true){
var data = client.read();
var msg = JSON.parse(data);
updateTicker(msg);
}
}
এই নিবন্ধটি মূলত একটি বেসিক বাইনারেন্স মাল্টি-মুদ্রা ট্রেডিং ফ্রেমওয়ার্ক দেখায়, যা মূলত ট্রেডিং তথ্য কীভাবে সঞ্চয় করতে হয়, টিকার অনুসারে কে-লাইন কীভাবে সংশ্লেষণ করা যায়, কীভাবে অর্ডার দেওয়া যায়, কীভাবে কৌশল চার্ট প্রদর্শন করা যায় এবং টিকার পুশ ইভেন্টগুলির উপর ভিত্তি করে ট্রেডিং ট্রিগার করা যায়। অনেকগুলি জায়গা রয়েছে যা পরিবর্তন এবং কাস্টমাইজ করা যায়। পুরোটি আমার ব্যক্তিগত কৌশল থেকে বের করা হয়েছে। এটি একটি বাগ বোঝাতে পারে এবং এটি কেবলমাত্র নির্দিষ্ট জ্ঞান ভিত্তিযুক্ত ব্যবহারকারীদের জন্য।