Continuons d'expliquer le contenu du dernier chapitre (https://www.fmz.com/bbs-topic/9725).
La troisième fonction ajoutée:
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 ( \"\" Start Balance \"\", 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 ( \"\" Start Balance \"\", 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)
}
}
}
}
Lorsque le constructeurLeeksReaper ()
construit un objet, lebalanceAccount ()
La fonction ajoutée à l'objet met à jour les informations sur les actifs du compte stockées dans leself.account
, c'est-à-dire leaccount
calculer la valeur du revenu et l'imprimer à temps. Ensuite, selon les dernières informations de l'actif du compte, calculer le ratio de solde de la monnaie des spots (solde de la position des spots), lors du déclenchement du seuil de décalage, fermer la position avec un petit ordre, de sorte que la monnaie (position) retour à l'état d'équilibre. Attendre un certain temps pour traiter, puis annuler tous les fabricants, le prochain tour d'exécution de la fonction, il vérifiera le solde et effectuera à nouveau le traitement correspondant.
Examinons le code de cette fonction phrase par phrase:
Premièrement, la première phrasevar account = exchange.GetAccount ()
déclare une variable localeaccount
et appelle la fonction deexchange.GetAccount
sur l'interface FMZ API. Obtenez les dernières données du compte courant et l'assigner à la variableaccount
Alors jugez la variableaccount
. Si la variable estnull
(par exemple, temps d'arrêt, réseau, exception d'interface d'échange, etc.), il retournera (correspondant àif (!account) {...}
) directement.
self.account = account
est d'attribuer la variable localeaccount
à laaccount
attribut de l'objet construit permettant d'enregistrer les dernières informations de compte dans l'objet construit.
Var now = new Date().getTime ()
déclare une variable localenow
et appelle legetTime()
attribue une valeur à la variablenow
.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)){...}
détermine que si la différence entre l'horodatage actuel et l'horodatage enregistré la dernière fois dépasse le paramètreCalcNet Interval * 1000
, cela signifie qu'il a été mis à jour depuis la dernière fois.CalcNetInterval * 1000
en millisecondes (CalcNetInterval
Le prix d'achat d'une imprimante est utilisé pour calculer le revenu.self.orderBook.Bids.length > 0
est également défini dans la condition (données de profondeur, il doit y avoir des informations de niveau valides dans la liste d'ordre).self.PreCalc = now
est exécuté pour mettre à jour la variable timestamp de la déclaration imprimée la plus récenteself.preCalc
à l'horodatage actuelnow
Dans ce cas, la méthode de calcul de la valeur nette est utilisée dans les statistiques de rendement.var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
, c'est-à-dire convertir la monnaie en argent (monnaie libellée) en fonction du prix d'achat actuel, puis l'ajouter au montant de l'argent sur le compte et l'assigner à la variable locale déclaréenet
. Jugez si la valeur nette totale actuelle est compatible avec la valeur nette totale enregistrée la dernière fois:
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
Si ce n'est pas cohérent, c'est à dire,net! = self.preNet
est vrai, mettre à jour l'attribut deself.preNet
utilisé pour enregistrer la valeur nette avec la variablenet
. Ensuite imprimer le total net denet
les données à la courbe de rendement du robot de la plateforme de trading FMZ Quant (leLogProfit
La fonction peut être consultée dans le document de l'API FMZ).
Si l'impression régulière des gains n'est pas déclenchée, continuez le processus suivant pour enregistrer leaccount.Stocks
(monnaie disponible sur le compte courant) et leaccount.Balance
(monnaie disponible dans le compte courant) dans leself.BTC
etself.CNY
. Calculer l'échelle de décalage et enregistrer l'affectation dans leself.p
.
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, qui consiste à calculer le pourcentage de la valeur courante de la monnaie à la valeur nette totale du compte.
Que dire de juger quand déclencher le solde monétaire (position)?
Ici, je prends 50% plus ou moins 2 points de pourcentage comme tampon, et exécute le solde au-delà du tampon, c'est-à-dire si leself.p < 0.48
, le solde monétaire est déclenché par déviation. Si l'argent est inférieur, le prix augmentera de 0,01 à chaque fois de la position d'achat à l'ouverture du marché, et trois petits ordres seront organisés.self.p > 0.52
, si la devise est plus, vendre un et libérer de petites commandes. enfin, annuler toutes les commandes après avoir attenduSleep(BalanceTimeout)
pendant un certain temps selon les paramètres.
Var orders = exchange. Get Orders () # Get all current makers, with orders variable
If (orders) { # If the variable orders used to obtain the current order data is not null
for (var i = 0; i < orders.length; I + +) { # Loop through orders and cancel orders one by one
if (orders[i].Id != self.tradeOrderId) {
Exchange. CancelOrder (orders [I]. Id) # Call exchange. CancelOrder to cancel orders based on orders [I]. Id
}
}
}
La quatrième fonction ajoutée:
Dans la partie centrale de la stratégie, voici le jeu principal.self.poll = function(){...}
La stratégie de l'UE pour l'emploi et la promotion de l'innovation est une stratégie qui a pour objectif de renforcer la compétitivité et la compétitivité des entreprises.main()
fonction commence à exécuter et entre dans l'infiniwhile
La boucle, nous utilisonsvar reaper = LeeksReaper()
pour construire l'objet leeksreaper, puis exécuter l'appel de boucle dereaper.poll()
dans lemain()
function.
Leself.poll
La fonction commence à s'exécuter, en effectuant des travaux préparatoires avant chaque boucle.self.numTick++
Le nombre d'infections augmente.self.updateTrades()
Il met à jour les récents enregistrements de négociation sur le marché et calcule les données d'utilisation pertinentes.self.updateOrderBook()
Les données relatives aux commandes sont mises à jour et calculées.self.balanceAccount()
vérifier le solde monétaire (position).
Var burstPrice = self. Prices [self. Prices. Length-1] * BurstThresholdPct # Calculate Burst Price
Var bull = false # Declare a bull-marked variable, initially false
Var bear = false # Declare a bear marked variable, initially false
Var tradeAmount = 0 # Declare the transaction amount variable, initially 0
L'étape suivante consiste à juger si le marché à court terme actuel est un taureau ou un ours.
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
}
Vous vous souvenez duself.updateOrderBook()
fonction de l'article précédent où nous avons utilisé un algorithme de moyenne pondérée pour construire un ordre temporelprices
Trois nouvelles fonctions:_.min
, _.max
, etslice
sont utilisés dans le code et sont faciles à comprendre.
· _. min
: La fonction consiste à trouver la valeur minimale dans le tableau de paramètres.
· _.max
: La fonction consiste à trouver la valeur maximale dans le tableau de paramètres.
· slice
: La fonction est une fonction membre de l'ensemble des fonctionsJavaScript
Il est utilisé pour retourner une partie du tableau selon l'index. Par exemple:
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)) // it will intercept the elements from 4 to 1 and return a new array: [4,3,2,1]
}
Les conditions pour juger un marché baissier ou haussier sont les suivantes:
· Leself.numTick > 2
doit être vrai, c'est-à-dire que lorsqu'une nouvelle série de prix de détection éclate, elle doit être déclenchée après au moins trois séries de détection, afin d'éviter de déclencher au début.
· la différence entre les dernières données de laself.prices
Les prix de l'ensemble des prix de l'ensemble des prix de l'ensemble des prix de l'ensemble des prix de l'ensemble des prix de l'ensemble des prix de l'ensemble des prix.self.prices
Le prix de l'ensemble devrait dépasser le prix de rupture deburstPrice
.
Si toutes les conditions sont vraies, marquerbull
oubear
comme vrai, et attribuer une valeur à la variabletradeAmount
pour planifier la transaction avec Stud.
Dans ce cas, selon leself.vol
Les résultats de l'enquête ont été mis à jour et calculés au cours de l'année précédente.self.updateTrades()
fonction, leBurstThresholdVol
Le paramètre détermine si l'intensité de la transaction doit être réduite (réduire le volume de transaction prévu).
if (self.vol < BurstThresholdVol) {
TradeAmount * = self. Vol/BurstThresholdVol //Reduce the planned volume by self. Vol/BurstThresholdVol times of the previous volume
}
if (self.numTick < 5) {
TradeAmount * = 0.8 // reduced to 80% of the plan
}
If (self. NumTick < 10) { // reduce to 80% of the plan
tradeAmount *= 0.8
}
Ensuite, jugez si le signal de négociation et le volume répondent aux exigences:
If ( (!Bull && !Bear) | | tradeAmount < MinStock) { # If it is not a bull market and not a bear market, or the amount tradeAmount planned to trade is less than the minimum trading volume MinStock set by the parameter, the poll function returns without trading operations directly
return
}
Après le jugement susmentionné, exécutervar tradePrice = bull ? self.bidPrice: self.askPrice
fixe le prix de la transaction selon qu'il s'agit d'un marché baissier ou d'un marché haussier, et attribue la valeur avec le prix du connaissement correspondant.
Enfin, unewhile
La seule condition d'arrêt de la boucle est que le volume de négociation prévu detradeAmount > = MinStock
est inférieure au volume de négociation minimum.
Dans la boucle, l'ordre est exécuté en fonction de l'état actuel du marché.orderId
. Sleep(200)
Il attend 200 millisecondes après avoir placé une commande dans chaque boucle.orderId
est vrai (si l'ordre échoue, l'identifiant d'ordre ne sera pas retourné, et la condition if ne sera pas déclenchée).self.tradeOrderId
.
Déclarer une variableorder
utilisé pour stocker les données de commande, avec une valeur initiale denull
. Ensuite, les données d'ordre de l'ID sont obtenues dans une boucle, et juger si l'ordre est l'état de fabricant, si oui, l'ordre de l'ID est annulé, et si non, la boucle de détection est terminée.
Var order = null // Declare a variable to hold the order data
While (true) { // a while loop
Order = exchange. GetOrder (orderId) // Call GetOrder to query the order data whose order ID is orderId
If (order) { // If the order data is queried and the query fails and the order is null, the current if condition will not be triggered
If (order. Status = = ORDER _ STATE _ PENDING) { // Judge whether the order status is maker
Exchange. CancelOrder (orderId) // If the order is maker, cancel the order
Sleep(200)
} else { // otherwise execute break to end the current while loop
break
}
}
}
Le procédé suivant est ensuite effectué:
Self. TradeOrderId = 0 // Reset self. TradeOrderId.
TradeAmount-= order. DealAmount // Update tradeAmount, subtract the quantity of the order on the bill of lading that has been completed
TradeAmount * = 0.9 //Decrease the order amount
If (order. Status = = ORDER _ STATE _ CANCELED) { // if the order is already cancelled
Self. UpdateOrderBook () // Update data such as order book
While (bull & & self. BidPrice-tradePrice > 0.1) { // In a bull market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice += 0.1
}
While (bear & & self. AskPrice-tradePrice < -0.1) { // In a bear market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice -= 0.1
}
}
Lorsque le processus de programme se termine de la boucle dewhile (tradeAmount > = MinStock){...}
, il indique que l'exécution de ce processus de transaction d'éclatement des prix est terminée.
Exécuter leself.numTick = 0
, c'est-à-dire réinitialiserself.numTick
à 0.
LeLeeksReaper()
Le constructeur renvoie leself
objet à la fin de l'exécution, c'est-à-dire lorsquevar reaper = LeeksReaper()
, il est renvoyé àreaper
.
Jusqu'à présent, nous avons analysé comment leLeeksReaper()
constructeur construit l'objet LeeksReaper, chaque méthode de l'objet LeeksReaper, et le processus d'exécution des principales fonctions logiques. Je crois que vous aurez une compréhension claire de ce processus d'algorithme de stratégie à haute fréquence après avoir lu cet article.