Lassen Sie uns den Inhalt des letzten Kapitels weiter erläutern (https://www.fmz.com/bbs-topic/9725).
Die dritte zusätzliche Funktion:
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)
}
}
}
}
Wenn der KonstrukteurLeeksReaper ()
Konstruiert ein Objekt, diebalanceAccount ()
Funktion, die dem Objekt hinzugefügt wird, aktualisiert die in der Konto-Aktivausgabe gespeicherten Informationen.self.account
, d. h. dieaccount
Berechnen Sie den Umsatzwert und drucken Sie ihn rechtzeitig. Berechnen Sie dann nach den aktuellen Kontovermögensdaten die Spot-Währungsbilanzquote (Spot-Positionsbilanz), schließen Sie die Position mit einer kleinen Bestellung, damit die Währung (Position) wieder in den Gleichgewichtszustand zurückkehrt. Warten Sie eine gewisse Zeit, um zu handeln, dann stornieren Sie alle Maker, die nächste Runde der Ausführung der Funktion wird nach dem Gleichgewicht suchen und die entsprechende Verarbeitung erneut durchführen.
Schauen wir uns den Code dieser Funktion Satz für Satz an:
Erstens, der erste Satz.var account = exchange.GetAccount ()
erklärt eine lokale Variableaccount
und ruft die Funktion vonexchange.GetAccount
Auf FMZ API-Schnittstelle. Holen Sie sich die neuesten Daten des Girokontos und zuordnen Sie es an die Variableaccount
Dann beurteilen Sie die Variable.account
. Wenn die Variable istnull
(z.B. Timeout, Netzwerk, Exchange-Interface-Ausnahme usw.), wird es zurückkehren (entsprechendif (!account) {...}
) direkt.
self.account = account
ist die lokale Variable zuzuweisenaccount
Dieaccount
Attribut des konstruierten Objekts zur Aufzeichnung der neuesten Kontoinformationen im konstruierten Objekt.
Var now = new Date().getTime ()
erklärt eine lokale Variablenow
und ruft diegetTime()
Funktion des Zeitdatumsobjekts der JavaScript-Sprache, um den aktuellen Zeitstempel zurückzugeben.now
.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)){...}
bestimmt, dass, wenn die Differenz zwischen dem aktuellen Zeitstempel und dem Zeitstempel, der zuletzt aufgezeichnet wurde, den Parameter übersteigtCalcNet Interval * 1000
, bedeutet, daß es seit dem letzten Mal aktualisiert wurde.CalcNetInterval * 1000
in Millisekunden (CalcNetInterval
Der Preis für den Kauf eines Druckers wird für die Berechnung des Einkommens verwendet.self.orderBook.Bids.length > 0
ist auch in der Bedingung definiert (Tiefe Daten, es muss gültige Ebene Informationen in der Reihenfolge Liste).self.PreCalc = now
wird ausgeführt, um die Zeitstempelvariable der zuletzt gedruckten Rückkehr zu aktualisierenself.preCalc
bis zum aktuellen Zeitstempelnow
Hier wird die Berechnungsmethode des Nettovermögens für die Renditestatistik verwendet.var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
, d. h. die Währung in Geld (in Währung) umwandeln, entsprechend dem aktuellen Kaufpreis, und sie dann dem Geldbetrag auf dem Konto hinzufügen und der angegebenen lokalen Variablen zuordnennet
Beurteilen Sie, ob der aktuelle Gesamtnettowert mit dem letztmalig erfassten Gesamtnettowert übereinstimmt:
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
Wenn es nicht konsistent ist, das heißt,net! = self.preNet
ist wahr, aktualisieren Sie das Attribut vonself.preNet
verwendet, um den Nettowert mit der Variablen zu erfassennet
. Dann drucken Sie die Netto-Gesamtzahl vonnet
Daten für das Rendite-Kurvendiagramm des FMZ Quant Trading-Plattformrobot (dieLogProfit
Funktion im FMZ-API-Dokument abgefragt werden kann).
Wenn die regelmäßige Ausgabe des Gewinns nicht ausgelöst wird, geht man mit dem folgenden Verfahren fort, um dieaccount.Stocks
(Währung auf dem Girokonto) undaccount.Balance
(in der Leistungsbilanz verfügbare Währung)self.BTC
undself.CNY
. Berechnen Sie die Offset-Skala und notieren Sie die Zuweisung in derself.p
.
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
Der Algorithmus ist auch sehr einfach, nämlich den Prozentsatz des aktuellen Wertes der Währung zum Gesamtnettowert des Kontos zu berechnen.
Was ist mit der Beurteilung, wann die Geldbilanz (Position) ausgelöst werden soll?
Hier nehme ich 50% plus oder minus 2 Prozentpunkte als Puffer, und führt den Saldo über den Puffer, das heißt, wenn dieself.p < 0.48
Wenn das Geld weniger ist, steigt der Preis jedes Mal um 0,01 von der Kaufposition bei der Marktöffnung und drei kleine Aufträge werden angeordnet.self.p > 0.52
, wenn die Währung mehr ist, verkaufen Sie eine und kleine Aufträge freigeben.Sleep(BalanceTimeout)
für eine bestimmte Zeit gemäß den Parametereinstellungen.
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
}
}
}
Die vierte zusätzliche Funktion:
Der Kern der Strategie ist das Hauptstück.self.poll = function(){...}
Die wichtigste Strategie ist, daß diemain()
Funktion beginnt auszuführen und geht in die endlosewhile
Schleife, wir verwendenvar reaper = LeeksReaper()
um das Leeksreaper-Objekt zu konstruieren und dann den Loop-Aufruf vonreaper.poll()
in dermain()
function.
Dieself.poll
Die Funktion beginnt, vor jeder Schleife einige Vorbereitungsarbeiten durchzuführen.self.numTick++
Die Zahl derself.updateTrades()
Die Daten werden in den letzten Jahren auf dem Markt gehandelt und berechnet.self.updateOrderBook()
Die Daten über die Bestellungen werden aktualisiert und berechnet.self.balanceAccount()
Überprüfen Sie den Geldstand.
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
Der nächste Schritt besteht darin, zu beurteilen, ob der aktuelle kurzfristige Markt ein Bullenmarkt oder ein Bärenmarkt ist.
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
}
Erinnern Sie sich an denself.updateOrderBook()
Funktion aus dem vorherigen Artikel, wo wir einen gewichteten Durchschnittsalgorithmus verwendet haben, um eine zeitlich geordneteprices
Drei neue Funktionen:_.min
, _.max
, undslice
Sie werden im Code verwendet und sind leicht verständlich.
· _. min
: Die Funktion besteht darin, den Mindestwert im Parameter-Array zu finden.
· _.max
: Die Funktion besteht darin, den maximalen Wert im Parameter-Array zu finden.
· slice
: Die Funktion ist ein Mitglied derJavaScript
Es wird verwendet, um einen Teil des Arrays nach dem Index zurückzugeben. Zum Beispiel:
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]
}
Die Voraussetzungen für die Beurteilung eines Bären- oder Bullenmarktes sind:
· Dieself.numTick > 2
muss wahr sein, d. h. wenn eine neue Runde des Detektionspreises ausbricht, muss sie nach mindestens drei Detektionsrunden ausgelöst werden, um zu vermeiden, dass sie zu Beginn ausgelöst wird.
· Die Differenz zwischen den letzten Daten in derself.prices
Der Preisverlauf, d. h. die jüngsten Daten, und der Höchst- oder Mindestpreis im vorherigen Bereich in derself.prices
Die Anlage sollte den Burst-Preis vonburstPrice
.
Wenn alle Bedingungen wahr sind, markierenbull
oderbear
als wahr, und einen Wert für die Variable zuweisentradeAmount
um die Stud-Transaktion zu planen.
Dann, nach derself.vol
die in den vorangegangenenself.updateTrades()
Funktion, dieBurstThresholdVol
Parameter bestimmt, ob die Transaktionsintensität reduziert werden soll (das geplante Transaktionsvolumen reduzieren).
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
}
Beurteilen Sie anschließend, ob das Handelssignal und das Volumen die Anforderungen erfüllen:
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
}
Nach dem oben genannten Urteil, vollstreckenvar tradePrice = bull ? self.bidPrice: self.askPrice
stellt den Transaktionspreis entsprechend dem Bären- oder Bullenmarkt fest und weist den Wert mit dem entsprechenden Frachtbriefpreis an.
Schließlich einewhile
Die Schleife wird eingegeben, und die einzige Haltbedingung der Schleife ist, dass das geplante Handelsvolumen vontradeAmount > = MinStock
unter dem Mindesthandelsvolumen liegt.
In der Schleife wird der Auftrag nach dem aktuellen Marktzustand ausgeführt.orderId
. Sleep(200)
Die Schleife bestimmt dann, ob dieorderId
ist wahr (wenn die Bestellung fehlschlägt, wird die Order-ID nicht zurückgegeben und die if-Bedingung wird nicht ausgelöst). Wenn die Bedingung wahr ist.self.tradeOrderId
.
Eine Variable deklarierenorder
für die Speicherung von Auftragsdaten mit einem Anfangswert vonnull
. Dann werden die Auftragsdaten der ID in einer Schleife erhalten und beurteilt, ob die Bestellung der Maker-Zustand ist, wenn ja, wird die Bestellung der ID annulliert, und wenn nicht, wird die Detektionsschleife beendet.
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
}
}
}
Anschließend wird folgender Vorgang durchgeführt:
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
}
}
Wenn der Programmprozess endet der Schleife vonwhile (tradeAmount > = MinStock){...}
, bedeutet, dass die Ausführung dieses Preis-Break-Transaktionsprozesses abgeschlossen ist.
Ausführen derself.numTick = 0
, d. h. dieself.numTick
auf 0.
DieLeeksReaper()
Konstruktor gibt dieself
Gegenstand am Ende der Ausführung, d. h. wennvar reaper = LeeksReaper()
, wird es an diereaper
.
Wir haben bisher analysiert, wie dieLeeksReaper()
Ich glaube, dass Sie nach dem Lesen dieses Artikels ein klares Verständnis für diesen Hochfrequenz-Strategie-Algorithmus-Prozess haben werden.