Type/to search
8
Follow
1361
Followers
Analyse de la stratégie de récolte des poireaux (2)
HFT
Created 2020-11-16 10:03:52  Updated 2024-12-05 22:03:01
 23
 8482

img

Analyse de la stratégie de récolte des poireaux (2)

alorsContenu précédentexpliquer.

La troisième fonction ajoutée :

python
self.balanceAccount = function() { var account = exchange.GetAccount() if (!account) { return } self.account = account var now = new Date().getTime() if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) { self.preCalc = now var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)) if (net != self.preNet) { self.preNet = net LogProfit(net) } } self.btc = account.Stocks self.cny = account.Balance self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny) var balanced = false if (self.p < 0.48) { Log("开始平衡", self.p) self.cny -= 300 if (self.orderBook.Bids.length >0) { exchange.Buy(self.orderBook.Bids[0].Price + 0.00, 0.01) exchange.Buy(self.orderBook.Bids[0].Price + 0.01, 0.01) exchange.Buy(self.orderBook.Bids[0].Price + 0.02, 0.01) } } else if (self.p > 0.52) { Log("开始平衡", self.p) self.btc -= 0.03 if (self.orderBook.Asks.length >0) { exchange.Sell(self.orderBook.Asks[0].Price - 0.00, 0.01) exchange.Sell(self.orderBook.Asks[0].Price - 0.01, 0.01) exchange.Sell(self.orderBook.Asks[0].Price - 0.02, 0.01) } } Sleep(BalanceTimeout) var orders = exchange.GetOrders() if (orders) { for (var i = 0; i < orders.length; i++) { if (orders[i].Id != self.tradeOrderId) { exchange.CancelOrder(orders[i].Id) } } } }

ConstructeurLeeksReaper()Lors de la construction d'un objet, ajoutezbalanceAccount()La fonction est de mettre à jour les informations sur les actifs du compte, stockées dansself.account, c'est-à-dire l'objet construitaccountpropriété. Calculez et imprimez régulièrement la valeur du bénéfice. Ensuite, sur la base des dernières informations sur les actifs du compte, le ratio de solde de la devise au comptant (solde de la position au comptant) est calculé. Lorsque le seuil d'écart est atteint, un petit ordre est clôturé pour rétablir l'équilibre de la devise (position). Attendez un certain temps pour terminer la transaction, puis annulez toutes les commandes en attente. Le prochain cycle d'exécution de cette fonction vérifiera à nouveau le solde et effectuera le traitement correspondant.

Regardons le code de cette fonction ligne par ligne :
Première phrasevar account = exchange.GetAccount()Il déclare une variable localeaccount, et appelez l'interface API de l'inventeurexchange.GetAccount()Fonction, obtenir les dernières données du compte courant et les affecter àaccountvariable. Alors jugeaccountCette variable, si la variable estnullSi la valeur (comme le délai d'attente, le réseau, l'exception de l'interface d'échange, etc.) ne parvient pas à être obtenue, elle sera renvoyée directement (correspondant àif (!account){...}ici).

self.account = accountCette phrase sert à mettre la variable localeaccountAttribué à l'objet construitaccountLes attributs sont utilisés pour enregistrer les dernières informations de compte dans l'objet construit.

var now = new Date().getTime()Cette instruction déclare une variable localenowet appelez l'objet heure et date du langage JavaScriptgetTime()La fonction renvoie l'horodatage actuel. Affecter ànowvariable.

if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}Ce code détermine si la différence entre l'horodatage actuel et le dernier horodatage enregistré dépasse le paramètreCalcNetInterval * 1000Cela signifie que depuis la dernière mise à jour jusqu'à maintenant, plus deCalcNetInterval * 1000milliseconde(CalcNetIntervalsecondes), pour réaliser la fonction de chronométrage de l'impression du revenu. Étant donné que le prix de la première enchère est utilisé lors du calcul du revenu, les conditions limitent égalementself.orderBook.Bids.length > 0Cette condition (données de profondeur, il doit y avoir des informations d'engrenage valides dans la liste de commande d'achat). Lorsque cette condition d'instruction if est déclenchée, l'exécutionself.preCalc = nowMettre à jour la variable d'horodatage des revenus d'impression les plus récentsself.preCalcHorodatage actuelnow. Les statistiques sur les revenus ici utilisent la méthode de calcul de la valeur nette, le code estvar net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)), c'est-à-dire convertir la pièce en argent (dénominateur) en fonction du prix d'achat actuel, puis l'ajouter au montant d'argent sur le compte et l'affecter à la variable locale déclaréenet. Déterminer si la valeur nette totale actuelle est cohérente avec la valeur nette totale enregistrée la dernière fois :

python
if (net != self.preNet) { self.preNet = net LogProfit(net) }

S'ils sont incohérents,net != self.preNetSi c'est vrai, utiliseznetLes mises à jour variables sont utilisées pour enregistrer les propriétés de la valeur netteself.preNet. Ensuite, imprimez cecinetDonnées sur la valeur nette totale du graphique de la courbe de profit du robot de la plateforme de trading quantitatif de l'inventeur (peut être interrogé dans le document API FMZ)LogProfitcette fonction).

Si les revenus d’impression planifiés ne sont pas déclenchés, continuez avec le processus suivant.account.Stocks(le nombre de pièces disponibles sur le compte courant),account.Balance(Le montant actuel d'argent disponible sur le compte) est enregistré dansself.btcself.cny. Calculer le rapport de décalage et attribuer la valeur à l'enregistrementself.p

python
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)

L'algorithme est également très simple, il consiste à calculer la valeur actuelle de la pièce en pourcentage de la valeur nette totale du compte.

Alors, comment déterminons-nous quand l’équilibre monétaire (position) est déclenché ?
L'auteur utilise 2 points de pourcentage au-dessus et en dessous de 50 % comme tampon et effectue un équilibre au-delà du tampon, c'est-à-dire,self.p < 0.48L'écart du solde des pièces est déclenché et on pense qu'il y a moins de pièces, alors commencez à acheter à une position sur le marché et augmentez le prix de 0,01 à chaque fois, et passez trois petites commandes. De même, la balance des devisesself.p > 0.52, si vous pensez avoir trop de pièces, vous pouvez passer une petite commande en vendant au prix d'ouverture. Enfin, attendez un certain temps en fonction des réglages des paramètresSleep(BalanceTimeout)Toutes les commandes seront annulées par la suite.

python
var orders = exchange.GetOrders() # 获取当前所有挂单,存在orders变量 if (orders) { # 如果获取当前挂单数据的变量orders不为null for (var i = 0; i < orders.length; i++) { # 循环遍历orders,逐个取消订单 if (orders[i].Id != self.tradeOrderId) { exchange.CancelOrder(orders[i].Id) # 调用exchange.CancelOrder,根据orders[i].Id取消订单 } } }

La quatrième fonction ajoutée :

La partie centrale de la stratégie, le point culminant est ici,self.poll = function() {...}La fonction est la logique principale de toute stratégie. Nous en avons également parlé dans l'article précédent.main()La fonction commence à s'exécuter et entrewhileAvant la boucle infinie, nous utilisonsvar reaper = LeeksReaper()J'ai construit un objet de récolte de poireaux, puismain()Appel de boucle dans la fonctionreaper.poll()C'est la fonction qui est appelée.

self.pollLa fonction commence à s'exécuter et effectue un travail de préparation avant chaque boucle.self.numTick++Augmenter le nombre,self.updateTrades()Mettez à jour les derniers enregistrements de transactions du marché et calculez les données pertinentes.self.updateOrderBook()Mettre à jour les données du carnet de commandes et calculer les données associées.self.balanceAccount()Vérifiez le solde de l'argent (position).

python
var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct # 计算爆发价格 var bull = false # 声明牛市标记的变量,初始为假 var bear = false # 声明熊市标记的变量,初始为假 var tradeAmount = 0 # 声明交易数量变量,初始为0

L’étape suivante consiste à déterminer si le marché à court terme actuel est haussier ou baissier.

python
if (self.numTick > 2 && ( self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -1)) > burstPrice || self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -2)) > burstPrice && self.prices[self.prices.length-1] > self.prices[self.prices.length-2] )) { bull = true tradeAmount = self.cny / self.bidPrice * 0.99 } else if (self.numTick > 2 && ( self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -1)) < -burstPrice || self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -2)) < -burstPrice && self.prices[self.prices.length-1] < self.prices[self.prices.length-2] )) { bear = true tradeAmount = self.btc }

Rappelez-vous, dans l'article précédentself.updateOrderBook()fonction, dans laquelle nous utilisons l'algorithme de moyenne pondérée pour construire une série temporelle avec l'ordrepricesTableau. Trois nouvelles fonctions sont utilisées dans ce code_.min_.maxsliceCes trois fonctions sont également très faciles à comprendre.

  • _.min:Sa fonction est de trouver la plus petite valeur dans le tableau de paramètres.

  • _.max:Sa fonction est de trouver la plus grande valeur dans le tableau de paramètres.

  • slice: Cette fonction est une fonction membre de l'objet tableau JavaScript. Sa fonction est d'intercepter une partie du tableau en fonction de l'index et de la renvoyer. Par exemple :

    javascript
    function main() { // index .. -8 -7 -6 -5 -4 -3 -2 -1 var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] Log(arr.slice(-5, -1)) // 会截取 4 ~ 1 这几个元素,返回一个新数组:[4,3,2,1] }

    img

Les conditions pour juger les ours et les taureaux ici sont les suivantes :

  • self.numTick > 2Pour être établi, cela signifie que lorsqu'un nouveau cycle de prix de détection éclate, il doit être déclenché après au moins trois cycles de détection pour éviter d'être déclenché au début.
  • Série de prixself.pricesLes dernières données de laself.pricesLa différence entre le prix maximum ou minimum de la plage précédente du tableau doit être rompueburstPriceC'est le prix explosif.

Si toutes les conditions sont remplies, alors marquezbulloubear,pourtrue, et donnetradeAmountAffectez des variables et planifiez les transactions Stud.

D'après le précédentself.updateTrades()Mis à jour et calculé dans la fonctionself.vol, pour le paramètreBurstThresholdVolDécidez s’il faut réduire l’intensité des transactions (réduire la taille des transactions prévues).

python
if (self.vol < BurstThresholdVol) { tradeAmount *= self.vol / BurstThresholdVol // 缩减计划交易量,缩减为之前量的self.vol / BurstThresholdVol 倍 } if (self.numTick < 5) { tradeAmount *= 0.8 // 缩减为计划的80% } if (self.numTick < 10) { // 缩减为计划的80% tradeAmount *= 0.8 }

Ensuite, déterminez si le signal de trading et le volume de trading répondent aux exigences :

python
if ((!bull && !bear) || tradeAmount < MinStock) { # 如果非牛市并且也非熊市,或者计划交易的量tradeAmount小于参数设置的最小交易量MinStock,poll函数直接返回,不做交易操作 return }

Après le jugement ci-dessus, exécutezvar tradePrice = bull ? self.bidPrice : self.askPriceDéfinissez le prix de la transaction selon qu'il s'agit d'un marché baissier ou haussier, et attribuez la valeur au prix du connaissement correspondant.

Entrez enfin unwhileLa seule condition pour arrêter la boucle esttradeAmount >= MinStockLe volume de transaction prévu est inférieur au volume de transaction minimum.
Dans la boucle, les ordres sont passés en fonction du caractère haussier ou baissier du marché actuel. Et enregistrez l'ID de commande dans la variableorderId. Après chaque tour de commandeSleep(200)Attendez 200 millisecondes. Alors jugez dans la boucleorderIdEst-ce vrai (si la commande échoue, l'ID de la commande ne sera pas renvoyé et la condition if ne sera pas déclenchée), si la condition est vraie. Obtenez l'ID de commande et attribuez-le àself.tradeOrderId

Déclarer une variable pour stocker les données de commandeorderLa valeur initiale estnull. Ensuite, faites une boucle pour obtenir les données de commande de cet ID et déterminez si la commande est en statut de commande en attente. Si elle est en statut de commande en attente, annulez la commande de cet ID. Si elle n'est pas en statut de commande en attente, sortez de cet état boucle de détection.

pine
var order = null // 声明一个变量用于保存订单数据 while (true) { // 一个while循环 order = exchange.GetOrder(orderId) // 调用GetOrder查询订单ID为 orderId的订单数据 if (order) { // 如果查询到订单数据,查询失败order为null,不会触发当前if条件 if (order.Status == ORDER_STATE_PENDING) { // 判断订单状态是不是正在挂单中 exchange.CancelOrder(orderId) // 如果当前正在挂单,取消该订单 Sleep(200) } else { // 否则执行break跳出当前while循环 break } } }

Suivez ensuite le processus ci-dessous :

pine
self.tradeOrderId = 0 // 重置self.tradeOrderId tradeAmount -= order.DealAmount // 更新tradeAmount,减去提单的订单已经成交的数量 tradeAmount *= 0.9 // 减小下单力度 if (order.Status == ORDER_STATE_CANCELED) { // 如果订单已经是取消了 self.updateOrderBook() // 更新订单薄等数据 while (bull && self.bidPrice - tradePrice > 0.1) { // 牛市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格 tradeAmount *= 0.99 tradePrice += 0.1 } while (bear && self.askPrice - tradePrice < -0.1) { // 熊市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格 tradeAmount *= 0.99 tradePrice -= 0.1 } }

Lorsque le déroulement du programme sautewhile (tradeAmount >= MinStock) {...}Ce cycle indique que le processus de transaction d’explosion des prix est terminé.
mettre en œuvreself.numTick = 0, c'est-à-dire réinitialiserself.numTickest 0.

LeeksReaper()Le constructeur s'exécute enfinselfL'objet renvoyé estvar reaper = LeeksReaper()Lorsqu'il a été retourné àreaper

Jusqu'à présentLeeksReaper()Nous avons analysé la manière dont le constructeur construit l'objet récolteur de poireaux, les différentes méthodes de l'objet récolteur de poireaux et le processus d'exécution des principales fonctions logiques. Je pense qu'après avoir lu cet article, vous devriez avoir une compréhension plus claire de la haute fréquence processus d'algorithme de stratégie. comprendre.

Related Recommendations
Comment
All comments (19)

    感谢梦总。梦总,请问韭菜收割机跟草神的高频机器人两者结合的思路有没有搞头啊?

    4 years ago

    草神有篇文章讲过,高频需要有市场环境。策略而言韭菜收割机跟草神的高频机器人有思路上的共同点。

    4 years ago

    说了一堆废话。核心的一句都没讲。

    4 years ago

    实在抱歉,这个文章主要是给入门初学者讲执行流程的,讲了一堆废话确实扎眼了,您忽略就行了。

    4 years ago

    有一点不明白,为什么一定要保持币和钱的平衡,如果没有达到平衡,就得操作买和卖。之后过BalanceTimeout又取消订单,不再平衡,而是进入下一个爆发环节。

    5 years ago

    下单命令在哪里。。。

    5 years ago

    之前看的云里雾里,用了一阵FMZ,重新看了一遍。总结思路来说。这个策略的思路是:
    监控盘口价格异动,发现价格爆发,顺着趋势的方向,以交易量大小作为参照计算出梭哈百分比,进行梭哈交易。梭哈交易完以后不持仓,长期保持一个币钱平衡的状态。
    我说的对吗,梦总?嘿嘿。

    5 years ago

    great !~

    5 years ago

    请教梦总,程序不停的在平衡币和钱,这个功能出于什么考虑?去掉balanceAccount()程序会怎样发展?

    5 years ago

    原版韭菜收割机是有一个平衡模块,可以考虑去掉。具体影响不太清楚了。

    5 years ago

    感谢梦总,fmz真的是大宝库

    5 years ago

    不客气 ~

    5 years ago

    还是看不明白

    5 years ago

    ~囧~

    5 years ago

    BurstThresholdVol 这个参数是干嘛的?该怎么设置啊

    6 years ago

    爆发量,这个是策略参数,人为设置的,详细看下策略、文章,就知道这个变量控制什么了。

    6 years ago

    细节满满,看了1小时才勉强理解细节,赞

    6 years ago

    梦总666,研究明白后我能写出跟print money 一样的韭菜收割机么

    6 years ago

    原理应该是差不多吧

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