وسائل لوڈ ہو رہے ہیں... لوڈنگ...

ایف ایم زیڈ کو اپ گریڈ کرنے کے بعد کس طرح تیزی سے ایک عام ملٹی کرنسی ٹریڈنگ کی حکمت عملی کی تعمیر

مصنف:گھاس, تخلیق: 2024-09-30 15:22:55, تازہ کاری: 2024-10-10 17:18:56

img

پیش گوئی

ایجاد کاروں نے مقداری تجارتی پلیٹ فارمز کا قیام بہت پہلے کیا تھا ، تب تبادلے اور کرنسیوں کی تعداد بہت کم تھی ، اور تجارت کے بہت سارے طریقے بھی نہیں تھے ، لہذا ابتدائی API ڈیزائن نسبتا simple آسان تھا ، جس میں ایک ہی کرنسی کی تجارت کی حکمت عملی پر توجہ دی گئی تھی۔ کئی سالوں کے تکرار کے بعد ، خاص طور پر حالیہ ورژن ، بہت بہتر ہوچکا ہے ، عام طور پر استعمال ہونے والے تبادلے کے API کو پہلے سے ہی پیکڈ افعال کے ساتھ کیا جاسکتا ہے۔ خاص طور پر ملٹی کرنسی کی حکمت عملی ، ٹرانزیکشنز ، اکاؤنٹس اور تجارت کو حاصل کرنا پہلے سے کہیں زیادہ آسان کردیا گیا ہے ، اب کسی بھی تبادلے تک رسائی حاصل کرنے کے لئے API انٹرفیس کی ضرورت نہیں ہے۔ دوبارہ جانچ پڑتال کے لئے بھی اپ گریڈ کیا گیا ہے ، اور حقیقت پسندانہ مطابقت ہے۔ خلاصہ یہ ہے ، اگر آپ کی حکمت عملی پہلے سے ہی بہت سارے خصوصی طریقوں سے ہے ، جو متعدد تبادلے اور دوبارہ جانچ پڑتال کو ایک ساتھ استعمال نہیں کرسکتی ہے تو ، آپ کو ایک اپ گریڈ کرنے کی ضرورت ہے۔ مندرجہ ذیل میں حکمت عملی کا مجموعہ کیا جائے گا ، موجودہ حکمت عملی

میزبانوں کو مکمل حمایت کے لئے 3.7 پر اپ گریڈ کرنے کی ضرورت ہے ، اور API انٹرفیس کی نئی خصوصیات جیسے معلومات کو ایجاد کنندہ کے کوانٹیمیٹڈ ٹرانزیکشن پلیٹ فارم کے API دستاویزات کے ساتھ ہم آہنگ اپ ڈیٹ کیا گیا ہے۔

گرائمیکل گائیڈ: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 "[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]"
            }
        }
    }
}

مارکیٹ تک رسائی

کثیر اقسام کی حکمت عملیوں کو ڈیزائن کرنے کے لئے ، پورے بازار تک رسائی حاصل کرنا ضروری ہے۔ یہ مجموعی مارکیٹ انٹرفیس ضروری ہے ، اور گیٹ ٹکرز فنکشن زیادہ تر بڑے پیمانے پر تبادلوں کی حمایت کرتا ہے۔

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

اکاؤنٹ کی پوزیشن کی معلومات حاصل کریں

فیوچر اکاؤنٹ کی معلومات میں ایکوئٹی کل حقوق حاصل کرنے والے فیلڈ اور یو پی این ایل فیلڈ کو شامل کیا گیا ہے ، جس سے اضافی پروسیسنگ کی وجہ سے عدم مطابقت پیدا ہوتی ہے۔ گیٹ پوزیشنز فنکشن بھی تمام پوزیشنوں کو حاصل کرنے کی حمایت کرتا ہے ، ایک تفصیل یہ ہے کہ پوزیشنوں کی تعداد کو ایک معاہدے کی قیمت سے ضرب کرنا ایک حقیقی تعداد حاصل کرنا ہے ، جیسے کہ او کے ایکس مستقل۔ اگرچہ ویب پیج پر تجارتی تعداد کا انتخاب کیا جاسکتا ہے ، لیکن اے پی آئی شیٹ کی تعداد پر ہے۔

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

تجارت

یہاں پر آرڈر کی تعداد کا بھی انتظام کیا گیا ہے اور آرڈر کو جدید ترین تخلیق آرڈر فنکشن کے ساتھ سنبھالنا بہت آسان ہے۔

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

حالت دکھائیں

عام طور پر دو فارم دکھائے جاتے ہیں، اکاؤنٹ کی معلومات اور ٹرانزیکشن کی معلومات۔

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

ٹرانزیکشن منطق

ایک بار جب آپ کے پاؤں کی سلاخیں مل جاتی ہیں تو ، بنیادی تجارتی منطق کا کوڈ آسان ہوجاتا ہے ، یہاں ایک آسان ترین آئس مینڈل نیچے کی حکمت عملی ہے۔

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

خلاصہ

اس مضمون میں ایک آسان اور پائیدار معاہدہ کثیر کرنسی ٹریڈنگ فریم ورک دیا گیا ہے جو جدید ترین API کا استعمال کرتے ہوئے ہم آہنگی کی حکمت عملی کی تعمیر کو آسان اور تیز تر بناتا ہے ، جس کی کوشش کرنے کے قابل ہے۔


مزید

ianzeng123شکریہ، میں سمجھتا ہوں کہ یہاں کا دروازہ کتنا گہرا ہے!