Các nhà phát minh đã tạo ra các nền tảng giao dịch định lượng quá sớm, khi đó các sàn giao dịch và loại tiền tệ rất hạn chế và không có nhiều mô hình giao dịch, do đó, thiết kế API ban đầu đơn giản hơn, tập trung vào chiến lược giao dịch loại tiền tệ duy nhất. Sau nhiều năm lặp lại, đặc biệt là phiên bản gần đây, đã được hoàn thiện hơn, API giao dịch thông thường được hoàn thành bằng các chức năng được đóng gói sẵn. Đặc biệt, chiến lược đa loại tiền tệ, truy cập giao dịch, tài khoản và giao dịch đã được đơn giản hóa nhiều hơn trước đây, không còn cần giao dịch IO.
Người quản lý cần nâng cấp lên 3.7 để có được hỗ trợ đầy đủ, thông tin về các tính năng mới của giao diện API đã được cập nhật đồng bộ với tài liệu API của nền tảng giao dịch định lượng của nhà phát minh:
Hướng dẫn ngữ pháp:https://www.fmz.com/syntax-guideHướng dẫn sử dụng:https://www.fmz.com/user-guide
Hiện tại, API có một chức năng chính xác thu thập thống nhất, ví dụ như hợp đồng vĩnh viễn.
//全局的变量,储存数据,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 "[trans]FMZ平台升级API,需要下载最新托管者|Update to neweset docekr[/trans]";
}
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 "[trans]不支持币本位|Don't support coin margin type[/trans]"
}
}
}
}
Để thiết kế các chiến lược đa dạng, cần phải có được toàn bộ thị trường. Giao diện thị trường tổng hợp này là rất cần thiết, chức năng GetTickers hỗ trợ hầu hết các sàn giao dịch chính thống.
function UpdateTicker() {
//更新价格
let ticker = exchange.GetTickers();
if (!ticker) {
Log("[trans]获取行情失败|Fail to get market[/trans]", 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);
}
}
Thông tin tài khoản tương lai được thêm vào các trường Equity Total Equity và UPnL, không cần xử lý thêm sự không tương thích. Chức năng GetPositions cũng hỗ trợ lấy tất cả các vị trí, một chi tiết là số lượng vị trí phải được nhân với giá trị của một hợp đồng để có được số lượng thực, chẳng hạn như OKX Permanent. Mặc dù có thể chọn giao dịch theo số lượng trên trang web, nhưng API là theo số trang.
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("[trans]更新账户失败|Fail to get account[/trans]");
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("[trans]更新仓位超时|Fail to get position[/trans]");
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 "[trans]需要单向持仓|Position need net Mode:[/trans]";
}
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,
"[trans]仓位更新:|Position update:[/trans]",
_N(Info.position[symbol].value, 1),
" -> ",
_N(position_info[symbol].amount * Info.ticker[symbol].last, 1),
direction == 1 ? "[trans], 买|. Buy[/trans]" : "[trans], 卖|, Sell[/trans]",
"[trans], 成交价:| Deal price: [/trans]",
deal_price,
"[trans], 成本价:| Hold price: [/trans]",
_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);
}
Các giao dịch ở đây cũng xử lý các vấn đề về số lượng đơn đặt hàng, sử dụng chức năng CreateOrder mới nhất để xử lý đơn đặt hàng, rất thuận tiện.
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, "[trans]下单异常|Error on order[/trans]");
}
}
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, "[trans]下单量太低|amount is too small[/trans]", price * amount);
return;
}
Order(symbol, direction, price, amount, msg);
}
}
Thông thường hiển thị hai biểu mẫu, thông tin tài khoản và thông tin giao dịch.
unction UpdateStatus() {
if (Date.now() - Info.time.update_status_time < 4000) {
return;
}
Info.time.update_status_time = Date.now();
let table1 = {
type: "table",
title: "[trans]账户信息|Account info[/trans]",
cols: [
"[trans]初始余额|Initial Balance[/trans]",
"[trans]钱包余额|Wallet balance[/trans]",
"[trans]保证金余额|Margin balance[/trans]",
"[trans]已用保证金|Used margin[/trans]",
"[trans]可用保证金|Avaiable margin[/trans]",
"[trans]总收益|Profit[/trans]",
"[trans]收益率|Profit rate[/trans]",
"[trans]未实现收益|Unrealised profit[/trans]",
"[trans]总持仓|Total value[/trans]",
"[trans]已用杠杆|Leverage-used[/trans]",
"[trans]循环延时|Delay[/trans]",
],
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: "[trans]交易对信息|Symbol info[/trans]",
cols: [
"[trans]币种|Symbol[/trans]",
"[trans]方向|Direction[/trans]",
"[trans]数量|Amount[/trans]",
"[trans]持仓价格|Hold price[/trans]",
"[trans]持仓价值|Value[/trans]",
"[trans]现价|Price[/trans]",
"[trans]挂单买价|Buy price[/trans]",
"[trans]挂单卖价|Sell price[/trans]",
"[trans]未实现盈亏|Unrealised profit[/trans]",
],
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(
"[trans]初始化时间: | Initial date: [/trans]" + _D(new Date(Info.time.start_time)) + "\n",
"`" + JSON.stringify(table1) + "`" + "\n" + "`" + JSON.stringify(table2) + "`\n",
"[trans]最后执行时间: |Last run date: [/trans]" + _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();
}
}
Sau khi đặt chân, mã logic giao dịch cốt lõi trở nên đơn giản, và đây là một chiến lược đơn giản nhất để hạ gục tảng băng giá.
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("[trans]循环出错: | Loop error: [/trans]" + 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);
}
}
Bài viết này cung cấp một khuôn khổ giao dịch đa đồng tiền hợp đồng bền vững đơn giản, sử dụng API mới nhất để dễ dàng xây dựng các chiến lược tương thích nhanh hơn và đáng thử.
Thanh Trẻ/upload/asset/2ff0c8463217e861599ae.png Bạn có thể hỏi câu hỏi này, có phải vì tôi là người quản lý cấp thấp?
Ianzeng123Xin cảm ơn vì đã hiểu được lối vào sâu xa như thế nào.
Cỏ nhỏSYMBOLS là một biến toàn cầu được định nghĩa trong chính sách và cần được định nghĩa trong các tham số chính sách.