
موجد کوانٹیٹیو ٹریڈنگ پلیٹ فارم بہت پہلے قائم کیا گیا تھا، اس وقت بہت محدود تبادلے اور کرنسیز موجود تھیں، اس لیے ابتدائی API ڈیزائن نسبتاً آسان اور واحد کرنسی کی تجارتی حکمت عملیوں پر مرکوز تھا۔ کئی سالوں کے تکرار کے بعد، خاص طور پر تازہ ترین ورژن، یہ نسبتاً مکمل ہو گیا ہے، اور عام طور پر استعمال ہونے والے ایکسچینج APIs کو انکیپسلیٹڈ فنکشنز کے ساتھ مکمل کیا جا سکتا ہے۔ خاص طور پر کثیر کرنسی کی حکمت عملیوں کے لیے، مارکیٹ کی معلومات حاصل کرنا، اکاؤنٹس اور لین دین پہلے کے مقابلے بہت آسان ہیں، اور IO فنکشنز کو ایکسچینج کے API انٹرفیس تک رسائی کی ضرورت نہیں ہے۔ بیک ٹیسٹنگ کو بھی حقیقی ٹریڈنگ کے ساتھ ہم آہنگ ہونے کے لیے اپ گریڈ کیا گیا ہے۔ مختصراً، اگر آپ کی حکمت عملی میں اصل میں بہت سے مخصوص طریقے ہیں اور اسے متعدد تبادلے اور بیک ٹیسٹنگ کے لیے استعمال نہیں کیا جا سکتا، تو آپ اسے اپ گریڈ کرنا چاہیں گے۔ یہ مضمون حکمت عملی کے ساتھ مل کر موجودہ حکمت عملی کے فریم ورک کو متعارف کرائے گا۔
نگہبانوں کو اس کی مکمل حمایت کرنے کے لیے 3.7 میں اپ گریڈ کرنے کی ضرورت ہے۔
نحو گائیڈ: https://www.fmz.com/syntax-guide صارف گائیڈ: https://www.fmz.com/user-guide
فی الحال، API کے پاس درستگی حاصل کرنے کے لیے ایک متحد فنکشن ہے، جسے یہاں ایک مثال کے طور پر ایک مستقل معاہدے کا استعمال کرتے ہوئے متعارف کرایا گیا ہے۔
//全局的变量,储存数据,SYMBOLS代表要交易的币种,格式如"BTC,ETH,LTC", QUOTO为基础货币,永续合约常见的有USDT,USDC,INTERVAL代表循环的间隔。
var Info = { trade_symbols: SYMBOLS.split(","), base_coin: QUOTO, ticker: {}, order: {}, account: {}, precision: {},
position: {}, time:{}, count:{}, interval:INTERVAL}
function InitInfo() {
//初始化策略
if (!IsVirtual() && Version() < 3.7){
throw "FMZ平台升级API,需要下载最新托管者|Update to neweset docekr";
}
Info.account = {init_balance:0};
Info.time = {
update_ticker_time: 0,
update_pos_time: 0,
update_profit_time: 0,
update_account_time: 0,
update_status_time: 0,
last_loop_time:0,
loop_delay:0,
};
for (let i = 0; i < Info.trade_symbols.length; i++) {
let symbol = Info.trade_symbols[i];
Info.ticker[symbol] = { last: 0, ask: 0, bid: 0 };
Info.order[symbol] = { buy: { id: 0, price: 0, amount: 0 }, sell: { id: 0, price: 0, amount: 0 } };
Info.position[symbol] = { amount: 0, hold_price: 0, unrealised_profit: 0, open_time: 0, value: 0 };
Info.precision[symbol] = {};
}
}
//获取精度
function GetPrecision() {
let exchange_info = exchange.GetMarkets();
for (let pair in exchange_info) {
let symbol = pair.split('_')[0]; //永续合约交易对的格式为 BTC_USDT.swap
if (Info.trade_symbols.indexOf(symbol) > -1 && pair.split('.')[0].endsWith(Info.base_coin) && pair.endsWith("swap")) {
Info.precision[symbol].tick_size = exchange_info[pair].TickSize;
Info.precision[symbol].amount_size = exchange_info[pair].AmountSize;
Info.precision[symbol].price_precision = exchange_info[pair].PricePrecision
Info.precision[symbol].amount_precision = exchange_info[pair].AmountPrecision
Info.precision[symbol].min_qty = exchange_info[pair].MinQty
Info.precision[symbol].max_qty = exchange_info[pair].MaxQty
Info.precision[symbol].min_notional = exchange_info[pair].MinNotional
Info.precision[symbol].ctVal = exchange_info[pair].CtVal; //合约价值,如1张代表0.01个币
if (exchange_info[pair].CtValCcy != symbol){ //价值的计价货币,这里不处理币本位的情况,如1张价值100美元
throw "不支持币本位|Don't support coin margin type"
}
}
}
}
کثیر قسم کی حکمت عملی وضع کرنے کے لیے، مارکیٹ کے مکمل حالات کو حاصل کرنا ضروری ہے۔ یہ مجموعی مارکیٹ انٹرفیس ضروری ہے، اور GetTickers فنکشن زیادہ تر مرکزی دھارے کے تبادلے کی حمایت کرتا ہے۔
function UpdateTicker() {
//更新价格
let ticker = exchange.GetTickers();
if (!ticker) {
Log("获取行情失败|Fail to get market", GetLastError());
return;
}
Info.time.update_ticker_time = Date.now();
for (let i = 0; i < ticker.length; i++) {
let symbol = ticker[i].Symbol.split('_')[0];
if (!ticker[i].Symbol.split('.')[0].endsWith(Info.base_coin) || Info.trade_symbols.indexOf(symbol) < 0 || !ticker[i].Symbol.endsWith('swap')) {
continue;
}
Info.ticker[symbol].ask = parseFloat(ticker[i].Sell);
Info.ticker[symbol].bid = parseFloat(ticker[i].Buy);
Info.ticker[symbol].last = parseFloat(ticker[i].Last);
}
}
ایکویٹی فیلڈ اور UPnL فیلڈ کو فیوچر اکاؤنٹ کی معلومات میں شامل کیا گیا ہے تاکہ اضافی پروسیسنگ کی وجہ سے ہونے والی عدم مطابقتوں سے بچا جا سکے۔ GetPositions فنکشن تمام پوزیشنوں کو حاصل کرنے میں معاونت کرتا ہے ایک تفصیل یہ ہے کہ اصل نمبر حاصل کرنے کے لیے پوزیشنوں کی تعداد کو ایک کنٹریکٹ کی قیمت سے ضرب دینا ضروری ہے، اگرچہ OKX پرپیچوئل کنٹریکٹ ویب سائٹ آپ کو مقدار کے لحاظ سے تجارت کرنے کی اجازت دیتی ہے۔ API معاہدوں کی تعداد پر مبنی ہے۔
function UpdateAccount() {
//更新账户
if (Date.now() - Info.time.update_account_time < 60 * 1000) {
return;
}
Info.time.update_account_time = Date.now();
let account = exchange.GetAccount();
if (account === null) {
Log("更新账户失败|Fail to get account");
return;
}
Info.account.margin_used = _N(account.Equity - account.Balance, 2);
Info.account.margin_balance = _N(account.Equity, 2); //当前余额
Info.account.margin_free = _N(account.Balance, 2);
Info.account.wallet_balance = _N(account.Equity - account.UPnL, 2);
Info.account.unrealised_profit = _N(account.UPnL, 2);
if (!Info.account.init_balance) {
if (_G("init_balance") && _G("init_balance") > 0) {
Info.account.init_balance = _N(_G("init_balance"), 2);
} else {
Info.account.init_balance = Info.account.margin_balance;
_G("init_balance", Info.account.init_balance);
}
}
Info.account.profit = _N(Info.account.margin_balance - Info.account.init_balance, 2);
Info.account.profit_rate = _N((100 * Info.account.profit) / init_balance, 2);
}
function UpdatePosition() {
let pos = exchange.GetPositions(Info.base_coin + ".swap");
if (!pos) {
Log("更新仓位超时|Fail to get position");
return;
}
Info.time.update_pos_time = Date.now();
let position_info = {};
for (let symbol of Info.trade_symbols) {
position_info[symbol] = {
amount: 0,
hold_price: 0,
unrealised_profit: 0
}; //有的交易所没有仓位返回空
}
for (let k = 0; k < pos.length; k++) {
let symbol = pos[k].Symbol.split("_")[0];
if (!pos[k].Symbol.split(".")[0].endsWith(Info.base_coin) || Info.trade_symbols.indexOf(symbol) < 0) {
continue;
}
if (position_info[symbol].amount != 0){
throw "需要单向持仓|Position need net Mode:";
}
position_info[symbol] = {
amount: pos[k].Type == 0 ? pos[k].Amount * Info.precision[symbol].ctVal : -pos[k].Amount * Info.precision[symbol].ctVal,
hold_price: pos[k].Price,
unrealised_profit: pos[k].Profit
};
}
Info.count = { long: 0, short: 0, total: 0, leverage: 0 };
for (let symbol in position_info) {
let deal_volume = Math.abs(position_info[symbol].amount - Info.position[symbol].amount);
let direction = position_info[symbol].amount - Info.position[symbol].amount > 0 ? 1 : -1;
if (deal_volume) {
let deal_price = direction == 1 ? Info.order[symbol].buy.price : Info.order[symbol].sell.price;
Log(
symbol,
"仓位更新:|Position update:",
_N(Info.position[symbol].value, 1),
" -> ",
_N(position_info[symbol].amount * Info.ticker[symbol].last, 1),
direction == 1 ? ", 买|. Buy" : ", 卖|, Sell",
", 成交价:| Deal price: ",
deal_price,
", 成本价:| Hold price: ",
_N(Info.position[symbol].hold_price, Info.precision[symbol].price_precision),
);
}
Info.position[symbol].amount = position_info[symbol].amount;
Info.position[symbol].hold_price = position_info[symbol].hold_price;
Info.position[symbol].value = _N(Info.position[symbol].amount * Info.ticker[symbol].last, 2);
Info.position[symbol].unrealised_profit = position_info[symbol].unrealised_profit;
Info.count.long += Info.position[symbol].amount > 0 ? Math.abs(Info.position[symbol].value) : 0;
Info.count.short += Info.position[symbol].amount < 0 ? Math.abs(Info.position[symbol].value) : 0;
}
Info.count.total = _N(Info.count.long + Info.count.short, 2);
Info.count.leverage = _N(Info.count.total / Info.account.margin_balance, 2);
}
لین دین کو معاہدوں کی تعداد کے مسئلے سے نمٹنے کی بھی ضرورت ہوتی ہے۔
function Order(symbol, direction, price, amount, msg) {
let ret = null;
let pair = symbol + "_" + Info.base_coin + ".swap"
ret = exchange.CreateOrder(pair, direction, price, amount, msg)
if (ret) {
Info.order[symbol][direction].id = ret;
Info.order[symbol][direction].price = price;
}else {
Log(symbol, direction, price, amount, "下单异常|Error on order");
}
}
function Trade(symbol, direction, price, amount, msg) {
price = _N(price - (price % Info.precision[symbol].tick_size), Info.precision[symbol].price_precision);
amount = amount / Info.precision[symbol].ctVal;
amount = _N(amount - (amount % Info.precision[symbol].amount_size), Info.precision[symbol].amount_precision);
amount = Info.precision[symbol].max_qty > 0 ? Math.min(amount, Info.precision[symbol].max_qty) : amount;
let new_order = false;
if (price > 0 && Math.abs(price - Info.order[symbol][direction].price) / price > 0.0001) { //两次订单有差价了才撤单
new_order = true;
}
if (amount <= 0 || Info.order[symbol][direction].id == 0) { //传入amount为0 撤单
new_order = true;
}
if (new_order) {
if (Info.order[symbol][direction].id) { //原有订单撤销
CancelOrder(symbol, direction, Info.order[symbol][direction].id);
Info.order[symbol][direction].id = 0;
}
if ( //延时过高不下单
Date.now() - Info.time.update_pos_time > 2 * Info.interval * 1000 ||
Date.now() - Info.time.update_ticker_time > 2 * Info.interval * 1000 ||
) {
return;
}
if (price * amount <= Info.precision[symbol].min_notional || amount < Info.precision[symbol].min_qty) {
Log(symbol, "下单量太低|amount is too small", price * amount);
return;
}
Order(symbol, direction, price, amount, msg);
}
}
عام طور پر دو میزیں دکھائی جاتی ہیں: اکاؤنٹ کی معلومات اور لین دین کے جوڑے کی معلومات۔
unction UpdateStatus() {
if (Date.now() - Info.time.update_status_time < 4000) {
return;
}
Info.time.update_status_time = Date.now();
let table1 = {
type: "table",
title: "账户信息|Account info",
cols: [
"初始余额|Initial Balance",
"钱包余额|Wallet balance",
"保证金余额|Margin balance",
"已用保证金|Used margin",
"可用保证金|Avaiable margin",
"总收益|Profit",
"收益率|Profit rate",
"未实现收益|Unrealised profit",
"总持仓|Total value",
"已用杠杆|Leverage-used",
"循环延时|Delay",
],
rows: [
[
Info.account.init_balance,
Info.account.wallet_balance,
Info.account.margin_balance,
Info.account.margin_used,
Info.account.margin_free,
Info.account.profit,
Info.account.profit_rate + "%",
_N(Info.account.unrealised_profit, 2),
_N(Info.count.total, 2),
Info.count.leverage,
Info.time.loop_delay + "ms",
],
],
};
let table2 = {
type: "table",
title: "交易对信息|Symbol info",
cols: [
"币种|Symbol",
"方向|Direction",
"数量|Amount",
"持仓价格|Hold price",
"持仓价值|Value",
"现价|Price",
"挂单买价|Buy price",
"挂单卖价|Sell price",
"未实现盈亏|Unrealised profit",
],
rows: [],
};
for (let i in Info.trade_symbols) {
let symbol = Info.trade_symbols[i];
table2.rows.push([
symbol,
Info.position[symbol].amount > 0 ? "LONG" : "SHORT",
_N(Info.position[symbol].amount, Info.precision[symbol].amount_precision+2),
_N(Info.position[symbol].hold_price, Info.precision[symbol].price_precision),
_N(Info.position[symbol].value, 2),
_N(Info.ticker[symbol].last, Info.precision[symbol].price_precision),
Info.order[symbol].buy.price,
Info.order[symbol].sell.price,
_N(Info.position[symbol].unrealised_profit, 2),
]);
}
LogStatus(
"初始化时间: | Initial date: " + _D(new Date(Info.time.start_time)) + "\n",
"`" + JSON.stringify(table1) + "`" + "\n" + "`" + JSON.stringify(table2) + "`\n",
"最后执行时间: |Last run date: " + _D() + "\n",
);
if (Date.now() - Info.time.update_profit_time > 5 * 60 * 1000) {
UpdateAccount();
LogProfit(_N(Info.account.profit, 3));
Info.time.update_profit_time = Date.now();
}
}
اسکافولڈنگ کے سیٹ اپ ہونے کے بعد، بنیادی تجارتی منطق کوڈ آسان ہے یہاں سب سے آسان آئس برگ آرڈر کی حکمت عملی ہے۔
function MakeOrder() {
for (let i in Info.trade_symbols) {
let symbol = Info.trade_symbols[i];
let buy_price = Info.ticker[symbol].bid;
let buy_amount = 50 / buy_price;
if (Info.position[symbol].value < 2000){
Trade(symbol, "buy", buy_price, buy_amount, symbol);
}
}
}
function OnTick() {
try {
UpdateTicker();
UpdatePosition();
MakeOrder();
UpdateStatus();
} catch (error) {
Log("循环出错: | Loop error: " + error);
}
}
function main() {
InitInfo();
while (true) {
let loop_start_time = Date.now();
if (Date.now() - Info.time.last_loop_time > Info.interval * 1000) {
OnTick();
Info.time.last_loop_time = Date.now();
Info.time.loop_delay = Date.now() - loop_start_time;
}
Sleep(5);
}
}
یہ مضمون ایک سادہ دائمی کنٹریکٹ ملٹی کرنسی ٹریڈنگ فریم ورک فراہم کرتا ہے۔