Tài nguyên đang được tải lên... tải...

Giới thiệu về mã nguồn của Chiến lược giao dịch cặp tiền kỹ thuật số và API mới nhất của Nền tảng FMZ

Tác giả:FMZ~Lydia, Tạo: 2024-07-11 14:57:15, Cập nhật: 2024-07-12 15:55:53

img

Lời giới thiệu

Bài trước đã giới thiệu nguyên tắc và kiểm tra lại của giao dịch cặp,https://www.fmz.com/bbs-topic/10459. Dưới đây là một mã nguồn thực tế dựa trên nền tảng FMZ. Chiến lược đơn giản và rõ ràng, phù hợp cho người mới bắt đầu học. Nền tảng FMZ gần đây đã nâng cấp một số API để thân thiện hơn với các chiến lược cặp giao dịch đa. Bài viết này sẽ giới thiệu mã nguồn JavaScript của chiến lược này chi tiết. Mặc dù mã chiến lược chỉ có một trăm dòng, nó chứa tất cả các khía cạnh cần thiết cho một chiến lược hoàn chỉnh. API cụ thể có thể được xem trong tài liệu API, rất chi tiết.https://www.fmz.com/strategy/456143có thể được sao chép trực tiếp.

Sử dụng nền tảng FMZ

Nếu bạn không quen thuộc với nền tảng FMZ, tôi khuyên bạn nên đọc hướng dẫn này:https://www.fmz.com/bbs-topic/4145Nó giới thiệu các chức năng cơ bản của nền tảng chi tiết, cũng như cách triển khai một robot từ đầu.

Khung chiến lược

Sau đây là một khuôn khổ chiến lược đơn giản. Chức năng chính là điểm nhập. Vòng lặp vô hạn đảm bảo rằng chiến lược được thực hiện liên tục, và một thời gian ngủ nhỏ được thêm vào để ngăn chặn tần số truy cập vượt quá giới hạn trao đổi.

function main(){
    while(true){
        //strategy content
        Sleep(Interval * 1000) //Sleep
    }
}

Ghi lại dữ liệu lịch sử

Robot sẽ khởi động lại nhiều lần vì nhiều lý do khác nhau, chẳng hạn như lỗi, cập nhật tham số, cập nhật chiến lược, v.v., và một số dữ liệu cần được lưu cho lần khởi động tiếp theo. Dưới đây là một minh chứng về cách lưu vốn ban đầu để tính lợi nhuận. Chức năng _G() có thể lưu trữ các dữ liệu khác nhau. _G(key, value) có thể lưu trữ giá trị của giá trị và gọi nó bằng _G(key), trong đó key là một chuỗi.

let init_eq = 0 //defining initial equity
if(!_G('init_eq')){  //If there is no storage, _G('init_eq') returns null.
    init_eq = total_eq
    _G('init_eq', total_eq) //Since there is no storage, the initial equity is the current equity and is stored here
}else{
    init_eq = _G('init_eq') //If stored, read the value of the initial equity
}

Chiến lược dung nạp lỗi

Khi lấy dữ liệu như vị trí và điều kiện thị trường thông qua API, lỗi có thể được trả về do nhiều lý do. Việc gọi trực tiếp dữ liệu sẽ khiến chiến lược dừng lại do lỗi, vì vậy cần một cơ chế chịu lỗi. Chức năng _C() sẽ tự động thử lại sau khi lỗi cho đến khi dữ liệu chính xác được trả về. Hoặc kiểm tra xem dữ liệu có sẵn sau khi trả về hay không.

let pos = _C(exchange.GetPosition, pair)

let ticker_A = exchange.GetTicker(pair_a)
let ticker_B = exchange.GetTicker(pair_b)
if(!ticker_A || !ticker_B){
    continue //If the data is not available, exit the loop.
}

API tương thích nhiều loại tiền tệ

Các chức năng như GetPosition, GetTicker và GetRecords có thể thêm một tham số cặp giao dịch để có được dữ liệu tương ứng, mà không cần thiết lập cặp giao dịch liên quan đến sàn giao dịch, điều này tạo điều kiện tương thích cho nhiều chiến lược cặp giao dịch.https://www.fmz.com/bbs-topic/10456Tất nhiên, docker mới nhất là cần thiết để hỗ trợ nó. Nếu docker của bạn quá cũ, bạn cần nâng cấp.

Các thông số chiến lược

  • Pair_A: Cặp giao dịch A cần được ghép nối để giao dịch. Bạn cần tự chọn cặp giao dịch. Bạn có thể tham khảo phần giới thiệu và kiểm tra lại trong bài viết trước.
  • Pair_B: Cặp giao dịch B cần được ghép nối.
  • Định giá: Đồng tiền ký quỹ của sàn giao dịch tương lai, thường bằng USDT.
  • Pct: Bao nhiêu độ lệch để thêm các vị trí, xem bài viết về các nguyên tắc chiến lược để biết chi tiết, do phí xử lý và lý do trượt, nó không nên được đặt quá nhỏ.
  • Trade_Value: Giá trị giao dịch của việc thêm các vị trí cho mỗi độ lệch so với kích thước lưới.
  • Ice_Value: Nếu giá trị giao dịch quá lớn, bạn có thể sử dụng giá trị hoa hồng tảng băng để mở một vị trí.
  • Max_Value: Số lượng tối đa nắm giữ một đồng tiền duy nhất, để tránh rủi ro nắm giữ quá nhiều vị trí.
  • N: Các thông số được sử dụng để tính tỷ lệ giá trung bình, đơn vị là giờ, ví dụ, 100 đại diện cho mức trung bình của 100 giờ.
  • Khoảng thời gian: Thời gian ngủ giữa mỗi chu kỳ của chiến lược.

Ghi chú chiến lược đầy đủ

Nếu bạn vẫn không hiểu, bạn có thể sử dụng tài liệu API FMZ, công cụ gỡ lỗi và các công cụ đối thoại AI thường được sử dụng trên thị trường để giải quyết câu hỏi của bạn.

function GetPosition(pair){
    let pos = _C(exchange.GetPosition, pair)
    if(pos.length == 0){ //Returns null to indicate no position
        return {amount:0, price:0, profit:0}
    }else if(pos.length > 1){ //The strategy should be set to unidirectional position mode
        throw 'Bidirectional positions are not supported'
    }else{ //For convenience, long positions are positive and short positions are negative
        return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
    }
}

function GetRatio(){
    let kline_A = exchange.GetRecords(Pair_A+"_"+Quote+".swap", 60*60, N) //Hourly K-line
    let kline_B = exchange.GetRecords(Pair_B+"_"+Quote+".swap", 60*60, N)
    let total = 0
    for(let i= Math.min(kline_A.length,kline_B.length)-1; i >= 0; i--){ //Calculate in reverse to avoid the K-line being too short.
        total += kline_A[i].Close / kline_B[i].Close
    }
    return total / Math.min(kline_A.length,kline_B.length)
}

function GetAccount(){
    let account = _C(exchange.GetAccount)
    let total_eq = 0
    if(exchange.GetName == 'Futures_OKCoin'){ //Since the API here is not compatible, only OKX Futures Exchange obtains the total equity currently.
        total_eq = account.Info.data[0].totalEq //The equity information of other exchanges is also included. You can look for it yourself in the exchange API documentation.
    }else{
        total_eq = account.Balance //Temporary use of available balances on other exchanges will cause errors in calculating returns, but will not affect the use of strategies.
    }
    let init_eq = 0
    if(!_G('init_eq')){
        init_eq = total_eq
        _G('init_eq', total_eq)
    }else{
        init_eq = _G('init_eq')
    }
    LogProfit(total_eq - init_eq)
    return total_eq
}

function main(){
    var precision = exchange.GetMarkets() //Get the precision here
    var last_get_ratio_time = Date.now()
    var ratio = GetRatio()
    var total_eq = GetAccount()
    while(true){
        let start_loop_time = Date.now()
        if(Date.now() - last_get_ratio_time > 10*60*1000){ //Update the average price and account information every 10 minutes
            ratio = GetRatio()
            total_eq = GetAccount()
            last_get_ratio_time = Date.now()
        }
        let pair_a = Pair_A+"_"+Quote+".swap" //The trading pair is set as BTC_USDT.swap
        let pair_b = Pair_B+"_"+Quote+".swap"
        let CtVal_a = "CtVal" in precision[pair_a] ? precision[pair_a].CtVal : 1 //Some exchanges use sheets to represent quantity, such as one sheet represents 0.01 coin, so you need to convert.
        let CtVal_b = "CtVal" in precision[pair_b] ? precision[pair_b].CtVal : 1 //No need to include this field
        let position_A = GetPosition(pair_a)
        let position_B = GetPosition(pair_b)
        let ticker_A = exchange.GetTicker(pair_a)
        let ticker_B = exchange.GetTicker(pair_b)
        if(!ticker_A || !ticker_B){ //If the returned data is abnormal, jump out of this loop
            continue
        }
        let diff = (ticker_A.Last / ticker_B.Last - ratio) / ratio //Calculate the ratio of deviation
        let aim_value = - Trade_Value * diff / Pct //Target holding position
        let id_A = null
        let id_B = null
        //The following is the specific logic of opening a position
        if( -aim_value + position_A.amount*CtVal_a*ticker_A.Last > Trade_Value && position_A.amount*CtVal_a*ticker_A.Last > -Max_Value){
            id_A = exchange.CreateOrder(pair_a, "sell", ticker_A.Buy, _N(Ice_Value / (ticker_A.Buy * CtVal_a), precision[pair_a].AmountPrecision))
        }
        if( -aim_value - position_B.amount*CtVal_b*ticker_B.Last > Trade_Value && position_B.amount*CtVal_b*ticker_B.Last < Max_Value){
            id_B = exchange.CreateOrder(pair_b, "buy", ticker_B.Sell, _N(Ice_Value / (ticker_B.Sell * CtVal_b), precision[pair_b].AmountPrecision))
        }
        if( aim_value - position_A.amount*CtVal_a*ticker_A.Last > Trade_Value && position_A.amount*CtVal_a*ticker_A.Last < Max_Value){
            id_A = exchange.CreateOrder(pair_a, "buy", ticker_A.Sell, _N(Ice_Value / (ticker_A.Sell * CtVal_a), precision[pair_a].AmountPrecision))
        }
        if( aim_value + position_B.amount*CtVal_b*ticker_B.Last > Trade_Value &&  position_B.amount*CtVal_b*ticker_B.Last > -Max_Value){
            id_B = exchange.CreateOrder(pair_b, "sell", ticker_B.Buy, _N(Ice_Value / (ticker_B.Buy * CtVal_b), precision[pair_b].AmountPrecision))
        }
        if(id_A){
            exchange.CancelOrder(id_A) //Cancel directly here
        }
        if(id_B){
            exchange.CancelOrder(id_B)
        }
        let table = {
            type: "table",
            title: "trading Information",
            cols: ["initial equity", "current equity", Pair_A+"position", Pair_B+"position", Pair_A+"holding price", Pair_B+"holding price", Pair_A+"profits", Pair_B+"profits", Pair_A+"price", Pair_B+"price", "current price comparison", "average price comparison", "deviation from average price", "loop delay"],
            rows: [[_N(_G('init_eq'),2), _N(total_eq,2), _N(position_A.amount*CtVal_a*ticker_A.Last, 1), _N(position_B.amount*CtVal_b*ticker_B.Last,1),
                _N(position_A.price, precision[pair_a].PircePrecision), _N(position_B.price, precision[pair_b].PircePrecision),
                _N(position_A.profit, 1), _N(position_B.profit, 1), ticker_A.Last, ticker_B.Last,
                _N(ticker_A.Last / ticker_B.Last,6), _N(ratio, 6), _N(diff, 4), (Date.now() - start_loop_time)+"ms"
            ]]
        }
        LogStatus("`" + JSON.stringify(table) + "`") //This function will display a table containing the above information on the robot page.
        Sleep(Interval * 1000) //Sleep time in ms
    }
}

Thêm nữa