3
fokus pada
1444
Pengikut

Pengenalan kepada kod sumber strategi dagangan pasangan mata wang digital dan API terkini platform FMZ

Dicipta dalam: 2024-07-10 16:36:54, dikemas kini pada: 2024-07-12 15:53:41
comments   5
hits   2914

Pengenalan kepada kod sumber strategi dagangan pasangan mata wang digital dan API terkini platform FMZ

Mukadimah

Artikel sebelum ini memperkenalkan prinsip dan ujian belakang dagangan pasangan, https://www.fmz.com/digest-topic/10457. Berikut ialah kod sumber praktikal berdasarkan platform FMZ Strategi ini agak mudah dan jelas, sesuai untuk dipelajari oleh pemula. Platform FMZ baru-baru ini telah meningkatkan beberapa APInya agar lebih mesra kepada strategi pasangan berbilang dagangan. Artikel ini akan memperkenalkan kod sumber JavaScript strategi ini secara terperinci. Walaupun strategi hanya seratus baris, ia mengandungi semua aspek yang diperlukan untuk strategi yang lengkap. Untuk API tertentu, sila rujuk dokumentasi API, yang diterangkan dengan terperinci. Alamat awam strategi: https://www.fmz.com/strategy/456143 boleh disalin terus.

Penggunaan platform FMZ

Jika anda tidak biasa dengan platform FMZ, saya amat mengesyorkan anda membaca tutorial ini: https://www.fmz.com/bbs-topic/4145. Ia memperkenalkan fungsi asas platform dan cara menggunakan robot dari awal.

Rangka Kerja Dasar

Berikut adalah rangka kerja strategi yang paling mudah, fungsi utama adalah titik masuk. Gelung tak terhingga memastikan strategi dilaksanakan secara berterusan, dan masa tidur yang kecil ditambah untuk mengelakkan kekerapan akses daripada melebihi had pertukaran terlalu cepat.

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

Merekod data sejarah

Robot akan dimulakan semula berulang kali atas pelbagai sebab, seperti ralat, kemas kini parameter, kemas kini strategi, dsb., dan beberapa data perlu disimpan untuk digunakan pada permulaan seterusnya. Berikut ialah demonstrasi cara menyimpan ekuiti awal untuk digunakan dalam mengira pulangan._Fungsi G() boleh menyimpan pelbagai data._G(kunci, nilai) boleh menyimpan nilai nilai dan memanggilnya dengan _G(kunci), dengan kunci ialah rentetan.

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

Apabila mendapatkan data seperti kedudukan dan keadaan pasaran melalui API, ralat mungkin dikembalikan atas pelbagai sebab. Memanggil data di dalamnya secara terus akan menyebabkan strategi menjadi ralat dan berhenti, jadi mekanisme toleransi kesalahan diperlukan._Fungsi C() akan mencuba semula secara automatik selepas ralat sehingga data yang betul dikembalikan. Atau semak sama ada data tersedia selepas dikembalikan.

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 serasi berbilang mata wang

Fungsi seperti GetPosition, GetTicker dan GetRecords boleh menambah parameter pasangan dagangan untuk mendapatkan data yang sepadan tanpa perlu menetapkan pasangan dagangan terikat pertukaran, yang sangat memudahkan keserasian beberapa strategi pasangan dagangan. Untuk maklumat peningkatan terperinci, sila rujuk artikel: https://www.fmz.com/digest-topic/10451. Sudah tentu, anda memerlukan hosting terkini untuk menyokongnya, jika hosting anda terlalu lama, anda perlu menaik taraf.

Parameter strategi

  • Pair_A Trading currency A: Trading pair A yang perlu dipasangkan untuk trading Anda perlu memilih sendiri pasangan trading Anda boleh rujuk pengenalan dan backtesting dalam artikel sebelumnya.
  • Pair_B Dagangan mata wang B: Dagangan pasangan B yang perlu dipasangkan
  • Sebut Harga Mata Wang Asas: Mata wang margin pertukaran niaga hadapan, biasanya USDT
  • Saiz grid pc: berapa banyak sisihan untuk menambah kedudukan, lihat artikel tentang prinsip strategi untuk butiran, disebabkan oleh yuran dan sebab kegelinciran, ia tidak boleh terlalu kecil
  • Trade_Value: Nilai transaksi untuk menambah kedudukan untuk setiap sisihan daripada saiz grid.
  • Ice_Value: Jika nilai transaksi terlalu besar, anda boleh menggunakan nilai aisberg untuk membuka kedudukan Secara umumnya, ia boleh ditetapkan kepada nilai yang sama dengan nilai transaksi.
  • Max_Value Pegangan maksimum: Pegangan maksimum mata wang tunggal, untuk mengelakkan risiko memegang terlalu banyak jawatan
  • N Parameter harga purata: parameter yang digunakan untuk mengira nisbah harga purata, unit ialah jam, seperti 100 mewakili purata 100 jam
  • Masa tidur selang (saat): Masa tidur antara setiap kitaran strategi

Nota polisi penuh

Jika anda masih tidak faham, anda boleh menggunakan dokumentasi API FMZ, alat penyahpepijatan dan alat dialog AI yang biasa digunakan di pasaran untuk menyelesaikan soalan 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
    }
}