3
fokus pada
1444
Pengikut

Pengenalan kode sumber strategi perdagangan pasangan mata uang digital dan API terbaru dari platform FMZ

Dibuat di: 2024-07-10 16:36:54, diperbarui pada: 2024-07-12 15:53:41
comments   5
hits   2914

Pengenalan kode sumber strategi perdagangan pasangan mata uang digital dan API terbaru dari platform FMZ

Kata pengantar

Artikel sebelumnya memperkenalkan prinsip dan pengujian ulang perdagangan berpasangan, https://www.fmz.com/digest-topic/10457. Berikut adalah kode sumber praktis berdasarkan platform FMZ. Strateginya relatif sederhana dan jelas, cocok untuk dipelajari oleh pemula. Platform FMZ baru-baru ini memperbarui beberapa API-nya agar lebih ramah terhadap strategi pasangan perdagangan ganda. Artikel ini akan memperkenalkan kode sumber JavaScript dari strategi ini secara rinci. Walaupun strateginya hanya seratus baris, ia memuat semua aspek yang dibutuhkan untuk strategi yang lengkap. Untuk API tertentu, silakan lihat dokumentasi API, yang dijelaskan dengan sangat rinci. Alamat publik strategi: https://www.fmz.com/strategy/456143 dapat disalin langsung.

Penggunaan platform FMZ

Jika Anda tidak familiar dengan platform FMZ, saya sangat menyarankan Anda untuk membaca tutorial ini: https://www.fmz.com/bbs-topic/4145. Ini memperkenalkan fungsi dasar platform dan cara menyebarkan robot dari awal.

Kerangka Kebijakan

Berikut ini adalah kerangka strategi yang paling sederhana, fungsi utamanya adalah titik masuk. Perulangan tak terbatas memastikan bahwa strategi dijalankan secara terus-menerus, dan sedikit waktu tidur ditambahkan untuk mencegah frekuensi akses melampaui batas pertukaran terlalu cepat.

function main(){
    while(true){
        //策略内容
        Sleep(Interval * 1000) //Sleep
    }
}

Merekam data historis

Robot akan melakukan restart berulang kali karena berbagai alasan, seperti kesalahan, pembaruan parameter, pembaruan strategi, dll., dan beberapa data perlu disimpan untuk digunakan pada startup berikutnya. Berikut adalah demonstrasi cara menyimpan ekuitas awal untuk digunakan dalam perhitungan laba._Fungsi G() dapat menyimpan berbagai data._G(kunci, nilai) dapat menyimpan nilai value dan memanggilnya dengan _G(kunci), di mana kunci adalah string.

let init_eq = 0 //定义初始权益
if(!_G('init_eq')){  //如果没有储存_G('init_eq')返回null
    init_eq = total_eq
    _G('init_eq', total_eq) //由于没有储存,初始权益为当前权益,并在这里储存
}else{
    init_eq = _G('init_eq') //如果储存,读取初始权益的值
}

Toleransi Kesalahan Strategi

Saat memperoleh posisi, pasar, dan data lainnya melalui API, kesalahan dapat muncul karena berbagai alasan. Memanggil data di dalamnya secara langsung akan menyebabkan strategi menjadi error dan berhenti, sehingga diperlukan mekanisme yang toleran terhadap kesalahan._Fungsi C() akan secara otomatis mencoba lagi setelah terjadi kesalahan hingga data yang benar dikembalikan. Atau periksa apakah data tersedia setelah kembali.

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 //如果数据不可用,就跳出这次循环
}

API yang kompatibel dengan banyak mata uang

Fungsi seperti GetPosition, GetTicker, dan GetRecords dapat menambahkan parameter pasangan perdagangan untuk memperoleh data terkait tanpa harus menetapkan pasangan perdagangan terikat bursa, yang sangat memudahkan kompatibilitas berbagai strategi pasangan perdagangan. Untuk informasi peningkatan terperinci, silakan lihat artikel: https://www.fmz.com/digest-topic/10451. Tentu saja, Anda memerlukan hosting terbaru untuk mendukungnya, jika hosting Anda terlalu lama, Anda perlu meningkatkannya.

Parameter strategi

  • Pair_A Mata uang perdagangan A: Pasangan perdagangan A yang perlu dipasangkan untuk perdagangan. Anda perlu memilih sendiri pasangan perdagangan tersebut. Anda dapat merujuk pada pendahuluan dan pengujian ulang pada artikel sebelumnya.
  • Pair_B Mata uang perdagangan B: Pasangan perdagangan B yang perlu dipasangkan
  • Mata Uang Dasar Kutipan: Mata uang margin bursa berjangka, biasanya USDT
  • Ukuran grid Pct: seberapa banyak deviasi untuk menambahkan posisi, lihat artikel tentang prinsip strategi untuk detailnya, karena biaya penanganan dan alasan slippage, seharusnya tidak terlalu kecil
  • Nilai_Perdagangan Nilai perdagangan: Nilai perdagangan penambahan posisi untuk setiap penyimpangan dari ukuran grid
  • Ice_Value: Jika nilai transaksi terlalu besar, Anda dapat menggunakan nilai iceberg untuk membuka posisi. Secara umum, nilai ini dapat ditetapkan pada nilai yang sama dengan nilai transaksi.
  • Max_Value Kepemilikan maksimum: Kepemilikan maksimum mata uang tunggal, untuk menghindari risiko memegang terlalu banyak posisi
  • N Parameter harga rata-rata: parameter yang digunakan untuk menghitung rasio harga rata-rata, satuannya adalah jam, seperti 100 mewakili rata-rata 100 jam
  • Waktu tidur interval (detik): Waktu tidur di antara setiap siklus strategi

Catatan kebijakan lengkap

Jika Anda masih belum mengerti, Anda dapat menggunakan dokumentasi API FMZ, alat debugging, dan alat dialog AI yang umum digunakan di pasaran untuk menyelesaikan pertanyaan Anda.

function GetPosition(pair){
    let pos = _C(exchange.GetPosition, pair)
    if(pos.length == 0){ //返回为空代表没有持仓
        return {amount:0, price:0, profit:0}
    }else if(pos.length > 1){ //策略要设置为单向持仓模式
        throw '不支持双向持仓'
    }else{ //为了方便,多仓持仓量为正,空仓持仓量为负
        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) //小时K线
    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--){ //反过来计算,避免K线长度不够
        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'){ //由于这里的API并不兼容,目前仅OKX期货交易所获取到总权益
        total_eq = account.Info.data[0].totalEq //其他交易所的宗权益Info中也包含,可以自己对着交易所API文档找找
    }else{
        total_eq = account.Balance //其它交易所暂时使用可用余额,会造成计算收益错误,但不影响策略使用
    }
    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() //这里获取精度
    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){ //每10分钟更新下均价和账户信息
            ratio = GetRatio()
            total_eq = GetAccount()
            last_get_ratio_time = Date.now()
        }
        let pair_a = Pair_A+"_"+Quote+".swap" //交易对的设置形如BTC_USDT.swap
        let pair_b = Pair_B+"_"+Quote+".swap"
        let CtVal_a = "CtVal" in precision[pair_a] ? precision[pair_a].CtVal : 1 //有的交易所用张来代表数量,如一张代表0.01个币,因此需要换算下
        let CtVal_b = "CtVal" in precision[pair_b] ? precision[pair_b].CtVal : 1 //不含这个字段的不用张
        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){ //如果返回数据异常,跳出这次循环
            continue
        }
        let diff = (ticker_A.Last / ticker_B.Last - ratio) / ratio //计算偏离的比例
        let aim_value = - Trade_Value * diff / Pct //目标持有的仓位
        let id_A = null
        let id_B = null
        //以下是具体的开仓逻辑
        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) //这里直接撤销
        }
        if(id_B){
            exchange.CancelOrder(id_B)
        }
        let table = {
            type: "table",
            title: "交易信息",
            cols: ["初始权益", "当前权益", Pair_A+"仓位", Pair_B+"仓位", Pair_A+"持仓价", Pair_B+"持仓价", Pair_A+"收益", Pair_B+"收益", Pair_A+"价格", Pair_B+"价格", "当前比价", "平均比价", "偏离均价", "循环延时"],
            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) + "`") //这个函数会在机器人页面显示包含以上信息的表格
        Sleep(Interval * 1000) //休眠时间为ms
    }
}