avatar of 发明者量化-小小梦 发明者量化-小小梦
Suivre Messages privés
4
Suivre
1271
Abonnés

Conception d'une stratégie de couverture au comptant pour les devises numériques (2)

Créé le: 2021-07-30 16:36:48, Mis à jour le: 2023-09-20 10:36:43
comments   5
hits   2474

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Dans l’article précédent, nous avons mis en place une stratégie de couverture simple. Nous allons maintenant découvrir comment mettre à niveau cette stratégie. Les changements de stratégie ne seront pas majeurs, mais les détails des changements nécessitent une attention particulière. Les définitions de certaines parties du code ont changé par rapport à avant et doivent être comprises.

La nécessité de mettre à niveau cette stratégie

  • Changer le mode de levier de l’objet d’échange au comptant Ce changement ne concerne que le trading réel. Certaines bourses spot disposent d’interfaces à effet de levier spot, qui sont également encapsulées sur FMZ. Pour les objets d’échange qui ont été directement encapsulés sur FMZ et qui prennent en charge l’effet de levier spot, vous pouvez directement changer de mode.
  • Ajout de l’affichage du graphique de spread Ajoutez l’affichage du graphique de propagation, car seul le dessinA交易所->B交易所B交易所->A交易所Tracez la ligne horizontale qui déclenche la propagation. Nous utilisons directement画线类库L’avantage est qu’il est simple et facile à utiliser. Ici, nous allons également apprendre à utiliser FMZ模版类库Fonction.
  • Fonction de couverture unilatérale Ce changement est assez important car il est difficile d’inverser complètement la différence de prix entre les deux bourses dans des transactions de couverture spécifiques. La plupart du temps, le prix sur une bourse est systématiquement plus élevé que le prix sur une autre bourse. À ce stade, si nos actifs ont tous été couverts (c’est-à-dire que les pièces sont toutes dans les échanges à bas prix et l’argent est tout dans les échanges à prix élevés). La couverture est au point mort et il n’est plus possible de compter sur les fluctuations de prix pour réaliser des bénéfices. À ce stade, la stratégie doit être telle que vous puissiez perdre un peu d’argent pour couvrir les pièces (laisser les pièces exister à nouveau dans un échange avec un prix élevé), puis continuer à couvrir les bénéfices lorsque la différence de prix redevient plus grande.
  • Modifier de manière interactive des paramètres tels que les lignes de spread de couverture Ajoutez des fonctions interactives à la stratégie et vous pourrez modifier la ligne de déclenchement du spread en temps réel.
  • Organiser les informations de la barre d’état et les afficher sous forme de tableau Organisez les données à afficher pour une observation facile.

Ensuite, implémentons ces conceptions une par une.

Changer le mode de levier de l’objet d’échange au comptant

En prenant comme exemple le trading spot de Binance, passez au mode effet de levier spot à l’aide du codeexchanges[i].IO, passer des paramètrestrade_normalPassez à un effet de levier position par position et transmetteztrade_super_marginPassez à la position complète à effet de levier, le backtesting n’est pas pris en charge. Ceci n’est utilisé que dans le trading réel.

existermainLa phase de préparation au début de la fonction est augmentée :

    // 切换杠杆模式
    for (var i = 0 ; i < exchanges.length ; i++) {   // 遍历检测所有添加的交易所对象
        if (exchanges[i].GetName() == "Binance" && marginType != 0) {   // 如果当前i索引代表的交易所对象是币安现货,并且策略界面参数marginType选择的不是「普通币币」选项,执行切换
            if (marginType == 1) {
                Log(exchanges[i].GetName(), "设置为杠杆逐仓")
                exchanges[i].IO("trade_normal")
            } else if (marginType == 2) {
                Log(exchanges[i].GetName(), "设置为杠杆全仓")
                exchanges[i].IO("trade_super_margin")
            }
        }
    }

La stratégie ici ajoute uniquement le code permettant de changer le mode de levier coin-to-coin pour Binance spot, de sorte que le commutateur défini dans les paramètres de stratégie n’est valable que pour Binance spot.

Ajout de l’affichage du graphique de spread

Il est très simple d’utiliser les modèles de dessin fournis. Le modèle que nous utilisons s’appelle画线类库. Vous pouvez le rechercher et l’obtenir directement sur le carré stratégique de la plateforme FMZ.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Ou cliquez directement sur le lien : https://www.fmz.com/strategy/27293 pour accéder à la page de copie de ce modèle.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Cliquez sur le bouton pour copier cette bibliothèque de modèles dans votre propre bibliothèque de stratégies.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Ensuite, sur la page d’édition des politiques, vous pouvez vérifier la bibliothèque de modèles dont vous avez besoin dans la colonne modèle. Après avoir coché la case et enregistré la politique, cette politique fera référence à ce modèle. Nous expliquons ici brièvement l’utilisation de la bibliothèque de modèles. Cette stratégie a déjà référencé ce modèle, il n’est donc pas nécessaire de répéter l’opération. Après avoir copié cette stratégie dans Strategy Square, vous pouvez la voir dans la colonne modèle de la page d’édition de stratégie.画线类库Déjà cité.

Nous apprenons principalement à utiliser画线类库fonction pour dessiner le graphique.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Nous prévoyons deA->BLa différence de prix,B->ALa différence de prix et la ligne de déclenchement de la différence de prix sont tracées. Vous devez tracer deux courbes (la différence de prix actuelle de A à B et de B à A) et deux lignes horizontales (lignes de différence de prix de déclenchement), comme indiqué dans la figure ci-dessus.

Parce que nous devons concevoir une haie unilatérale,A->BetB->ALa ligne de déclenchement est différente. Le design de l’article précédent ne peut plus être utilisé. Dans l’article précédent :

      var targetDiffPrice = hedgeDiffPrice
      if (diffAsPercentage) {
          targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
      }

Il n’y a qu’un seul spread de déclenchementtargetDiffPrice。 Donc ici, nous devons modifier le code, d’abord modifier les paramètres.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Modifiez ensuite le code :

        var targetDiffPriceA2B = hedgeDiffPriceA2B
        var targetDiffPriceB2A = hedgeDiffPriceB2A
        if (diffAsPercentage) {
            targetDiffPriceA2B = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageA2B
            targetDiffPriceB2A = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageB2A
        }

De cette façon, la ligne de déclenchement de la différence de prix change par rapport à la précédentetargetDiffPriceUn, devenu deuxtargetDiffPriceA2BtargetDiffPriceB2A。 Ensuite, vous pouvez utiliser la fonction de dessin de lignes de la bibliothèque de dessins de lignes pour dessiner ces données sur le graphique.

        // 画图
        $.PlotHLine(targetDiffPriceA2B, "A->B")  // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
        $.PlotHLine(targetDiffPriceB2A, "B->A")

Lorsque la stratégie est en cours d’exécution, un graphique comme celui-ci apparaîtra.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Ensuite, dessinez la courbe de spread en temps réel pour éviter de trop dessiner. Placez le code permettant de tracer des courbes de données de différence de prix en temps réel dans le contrôle de solde.

        if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
            nowAccs = _C(updateAccs, exchanges)
            var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
            cancelAll()
            if (isBalance) {
                lastKeepBalanceTS = ts
                if (isTrade) {
                    var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                    var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                    LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
                    isTrade = false 
                }                
            }

            $.PlotLine("A2B", depthA.Bids[0].Price - depthB.Asks[0].Price)  // 画实时差价曲线
            $.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price)  // 第一个参数是曲线名称,第二个参数是曲线当前时刻的值,即当前时刻Y轴方向上的值
        }

De cette façon, avec seulement 4 lignes de code de dessin, la stratégie peut afficher un graphique lorsqu’elle est en cours d’exécution.

Fonction de couverture unilatérale

Comme mentionné ci-dessus, la ligne de déclenchement de la différence de prix a été transformée en deux, contrôlantA->BLe déclencheur de haieB->ALa haie est déclenchée. De cette façon, l’algorithme du prix de l’ordre précédent ne peut pas être utilisé, et la méthode du prix du marché plus le glissement est utilisée à la place.

        if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B 盘口条件满足            
            var priceSell = depthA.Bids[0].Price - slidePrice
            var priceBuy = depthB.Asks[0].Price + slidePrice
            var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
            if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance * 0.8 / priceSell > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance * 0.8 / priceSell, maxHedgeAmount)
                Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks)  // 提示信息
                hedge(exB, exA, priceBuy, priceSell, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        } else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPriceB2A && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) {   // B -> A 盘口条件满足
            var priceBuy = depthA.Asks[0].Price + slidePrice
            var priceSell = depthB.Bids[0].Price - slidePrice
            var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
            if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance * 0.8 / priceBuy > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance * 0.8 / priceBuy, maxHedgeAmount)
                Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks)  // 提示信息
                hedge(exA, exB, priceBuy, priceSell, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        }

Étant donné que les prix d’achat et de vente sont séparés en deux données, la fonction de couverturehedgeIl faut également le modifier.

function hedge(buyEx, sellEx, priceBuy, priceSell, amount) {
    var buyRoutine = buyEx.Go("Buy", priceBuy, amount)
    var sellRoutine = sellEx.Go("Sell", priceSell, amount)
    Sleep(500)
    buyRoutine.wait()
    sellRoutine.wait()
}

Il y a également quelques ajustements mineurs basés sur ces changements, que je n’aborderai pas ici. Vous pouvez consulter le code pour plus de détails.

Modifier de manière interactive des paramètres tels que les lignes de spread de couverture

Ajoutez de l’interactivité à la stratégie afin que celle-ci puisse modifier la ligne de déclenchement du spread en temps réel. Il s’agit d’une exigence de conception pour une stratégie semi-automatique, qui est également mise en œuvre ici comme démonstration pédagogique. La conception des interactions de stratégie est également très simple. Tout d’abord, ajoutez des contrôles interactifs à la stratégie sur la page d’édition de stratégie.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Deux contrôles sont ajoutés, l’un appelé A2B et l’autre appelé B2A. Après avoir entré une valeur dans la zone de saisie de contrôle, cliquez sur le bouton situé à droite de la zone de saisie. Une instruction sera immédiatement envoyée à la stratégie, par exemple : saisir une valeur dans la zone de saisie123, cliquezA2BCe bouton enverra immédiatement des instructions à la stratégie.

A2B:123

Concevez le code de détection et de traitement des interactions dans le code de stratégie.

        // 交互
        var cmd = GetCommand()   // 每次循环执行到这里时,都检测有没有交互指令过来,没有则返回空字符串
        if (cmd) {               // 检测到有交互指令,例如:A2B:123
            Log("接收到命令:", cmd)
            var arr = cmd.split(":")   // 拆分出交互控件名称和输入框中的值,arr[0]就是A2B,arr[1]就是123
            if (arr[0] == "A2B") {     // 判断触发的交互控件是不是A2B
                Log("修改A2B的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageB2A = parseFloat(arr[1])     // 修改触发差价线
                } else {
                    hedgeDiffPriceA2B = parseFloat(arr[1])          // 修改触发差价线
                }
            } else if (arr[0] == "B2A") {           // 检测到触发的控件是B2A     
                Log("修改B2A的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageA2B = parseFloat(arr[1])
                } else {
                    hedgeDiffPriceB2A = parseFloat(arr[1])
                }
            }
        }

Organiser les informations de la barre d’état et les afficher sous forme de tableau

Rendez les données de la barre d’état plus organisées et plus faciles à observer.

        var tbl = {
            "type" : "table", 
            "title" : "数据", 
            "cols" : ["交易所", "币", "冻结币", "计价币", "冻结计价币", "触发差价", "当前差价"], 
            "rows" : [], 
        }
        tbl.rows.push(["A:" + exA.GetName(), nowAccs[0].Stocks, nowAccs[0].FrozenStocks, nowAccs[0].Balance, nowAccs[0].FrozenBalance, "A->B:" + targetDiffPriceA2B, "A->B:" + (depthA.Bids[0].Price - depthB.Asks[0].Price)])
        tbl.rows.push(["B:" + exB.GetName(), nowAccs[1].Stocks, nowAccs[1].FrozenStocks, nowAccs[1].Balance, nowAccs[1].FrozenBalance, "B->A:" + targetDiffPriceB2A, "B->A:" + (depthB.Bids[0].Price - depthA.Asks[0].Price)])

        LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Backtesting

Le backtesting n’est qu’un test de stratégie et une détection préliminaire des fonctions. De nombreux bugs peuvent en fait être testés lors de la phase de backtesting. Il n’est pas nécessaire de prêter trop d’attention aux résultats des backtests. La stratégie finale doit encore être testée dans un environnement réel.

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Conception d’une stratégie de couverture au comptant pour les devises numériques (2)

Code source de la stratégie : https://www.fmz.com/strategy/302834