Les ressources ont été chargées... Je charge...

Le code source de la stratégie de trading de paire de devises numériques et l'API la plus récente de la plateforme FMZ

Auteur:Le foin, Créé à: 2024-07-10 16:36:54, Mis à jour à: 2024-07-12 15:53:41

img

Préambule

Dans un article précédent, j'ai expliqué les principes et les retouches de l'appariement.https://www.fmz.com/digest-topic/10457; ici est donné le code source pratique basé sur la plate-forme FMZ, la stratégie est relativement simple et claire et adaptée à l'apprentissage pour les débutants. ; la plate-forme FMZ a récemment mis à niveau une partie de l'API pour être plus conviviale pour les transactions multiples. ; Cet article détaille le code source JavaScript de cette stratégie.https://www.fmz.com/strategy/456143Il est possible de le copier directement.

Utilisation de la plateforme FMZ

Si vous n'êtes pas familier avec la plateforme FMZ, je vous recommande fortement de lire ce tutoriel:https://www.fmz.com/bbs-topic/4145Dans le même temps, le site Web de l'équipe de développement de la plate-forme a été mis à jour et a été mis à jour pour permettre aux utilisateurs de déployer un robot.

Cadre stratégique

Voici le cadre de stratégie le plus simple, dont la fonction principale est l'entrée. La stratégie de la garantie du cycle mort est d'exécuter en permanence, en ajoutant une petite période de repos pour éviter que la fréquence d'accès dépasse trop rapidement les limites de l'échange.

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

Les données historiques

Le robot redémarre à plusieurs reprises pour diverses raisons, telles que des erreurs, des paramètres de mise à jour, des politiques de mise à jour, etc. Il est nécessaire de sauvegarder certaines données pour les utiliser lors du prochain démarrage.

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') //如果储存,读取初始权益的值
}

La stratégie est faussée

Lorsque des données telles que des positions, des marchés, etc. sont obtenues via l'API, des erreurs peuvent être renvoyées pour diverses raisons. Cela entraînerait un arrêt d'erreur de la politique en appelant directement les données, ce qui nécessite un mécanisme d'erreur.

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 compatible avec les monnaies

Des fonctions telles que GetPosition, GetTicker, GetRecords peuvent ajouter des paramètres à une paire de transactions pour obtenir les données correspondantes sans avoir à configurer une paire de transactions liée à l'échange, ce qui facilite considérablement la compatibilité de plusieurs stratégies de transactions.https://www.fmz.com/digest-topic/10451Bien sûr, vous devez avoir un hôte le plus récent pour le prendre en charge, mais si votre hôte est trop vieux, vous devez le mettre à niveau.

Paramètres stratégiques

  • Pair_A Transaction de monnaie A: la paire de transactions A doit être associée à la transaction et doit choisir sa propre paire de transactions.
  • Pair_B Transaction de monnaie B: paire de transactions B qui nécessite une paire de transactions
  • Quote monnaie de base: monnaie de garantie sur les marchés à terme, généralement USDT
  • Taille de la grille Pct: déviation de la quantité de mise en place, voir l'article sur les principes de la stratégie.
  • Trade_Value Valeur de la transaction: valeur de la transaction augmentée pour chaque écart de taille de grille
  • Ice_Value Valeur de la montagne de glace: si la valeur de la transaction est trop grande, vous pouvez ouvrir une position avec la valeur de la montagne de glace, généralement réglée à la même valeur que la valeur de la transaction
  • Max_Value Maximum de possession: la plus grande possession d'une seule monnaie pour éviter le risque de possession excessive
  • N paramètre de prix moyen: paramètre utilisé pour calculer la comparaison des prix moyens, dont l'unité est l'heure, par exemple, 100 représente la moyenne de 100 h
  • Interval Temps de sommeil (s): la durée de sommeil de chaque intervalle de cycle de la stratégie

Commentaires complets sur la stratégie

Si vous ne comprenez pas encore, vous pouvez résoudre vos questions avec la documentation de l'API FMZ, les outils de débogage et les outils de dialogue d'IA couramment utilisés sur le marché.

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

Plus de

77924998Il y a une version python?

Les haricots 888Je ne sais pas si je peux vous aider. Le front est un peu creux.

L'inventeur de la quantification - un petit rêveLes tests de réévaluation ne prennent pas en charge les fonctions GetMarkets pour l'instant, vous pouvez attendre un peu.

ChaoZhang est là.Mise à niveau vers le dernier hôte