Type/to search
8
Follow
1364
Followers
Conception d'une stratégie de couverture au comptant pour les devises numériques (2)
Original
Created 2021-07-30 16:36:48  Updated 2023-09-20 10:36:43
 5
 2731

img

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.

img

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

img

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

img

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.

img

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.

img

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.

img

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.

img

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) + "`")

img

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.

img

img

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

Related Recommendations
Comment
All comments (5)

    这个交易策略加入 合约功能 就好了 就是把永续合约 交割合约 都加进去

    4 years ago

    好的,有机会出个教程。

    4 years ago

    梦大,回测提示 main:127:9 - TypeError: Cannot read property 'SetPrecision' of undefined
    【不同计价币的现货对冲策略 Ver1.1】

    5 years ago

    要添加两个交易所对象。

    5 years ago

    明白了,谢谢梦大。

    5 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)