Analyse der Strategie der Gewinnsammler (2)

Schriftsteller:- Ich bin ein Idiot., Erstellt: 2022-04-26 15:57:02, aktualisiert: 2022-04-26 15:57:53

Analyse der Strategie der Gewinnsammler (2)

Lasst uns weitermachen.Inhalt des letzten MalesIch muss es erklären.

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 to 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 to 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()ist ein Objekt zu konstruieren, diebalanceAccount()Funktion, die dem Objekt hinzugefügt wird, wird verwendet, um die Kontovermögensinformationen zu aktualisieren, die inself.account, das heißt, um das Attribut zu konstruierenaccountDer Wert der Rückkehr wird regelmäßig berechnet und gedruckt. Dann wird nach den neuesten Kontoanlageninformationen das Saldoverhältnis der Spot-Währungssymbole (Spot-Positionssaldo) berechnet, und wenn die Offset-Schwelle ausgelöst wird, werden kleine Aufträge geschlossen, um die Symbole (Positionen) wieder in einen ausgewogenen Zustand zu bringen. Warten Sie eine gewisse Zeit, um den Handel auszuführen, und stornieren Sie dann alle ausstehenden Aufträge und führen Sie die Funktion in der nächsten Runde aus, das Gleichgewicht wird erneut erkannt und die entsprechende Verarbeitung erfolgt.

Schauen wir uns den Code dieser Funktionsanweisung Anweisung für Anweisung an: Zunächst einmal die erste Aussage.var account = exchange.GetAccount()erklärt eine lokale Variableaccount, ruft dieexchange.GetAccount()Funktion in FMZ API-Schnittstelle, erhalten Sie die neuesten Daten des Girokontos und zuweisen Sie es an die VariableaccountDann beurteilen Sie die Variable.account; wenn der Variablenwert:null(was passieren wird, wenn es nicht gelingt, die Variable zu erhalten, wie Timeout, Netzwerk, Plattform-Interface-Ausnahme, etc.), wird es direkt zurückkehren (entsprechendif (!account ){...}hier).

Die Erklärungself.account = accountist die lokale Variable zuzuweisenaccountzu dem Attributaccountdes gebauten Objekts, um die neuesten Kontoinformationen im gebauten Objekt aufzuzeichnen.

Die Erklärungvar now = new Date().getTime()erklärt eine lokale Variablenow, und ruft diegetTime()Funktion des Zeit- und Datumsobjekts der JavaScript-Sprache, um den aktuellen Zeitstempel zurückzugeben und den Zeitstempel der Variablen zuzuweisennow.

Der Code:if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}Beurteilt die Differenz zwischen dem aktuellen Zeitstempel und dem zuletzt aufgezeichneten Zeitstempel; wenn der Wert den Parameter übersteigtCalcNetInterval * 1000, bedeutet es, dass es überschritten hatCalcNetInterval * 1000in Millisekunden (CalcNetIntervalDer Marktpreis muss bei der Berechnung des Gewinns verwendet werden, so dass die Bedingung auch auf die Bedingung beschränkt ist, dass der Marktpreis für den Kauf 1 verwendet werden muss.self.orderBook.Bids.length > 0(Durchführungsdaten, die in der Bestellliste als Ebeneinformationen gültig sein müssen).

Wenn die Bedingung der Anweisung if ausgelöst wird, wird ausgeführtself.preCalc = nowzur Aktualisierung der Zeitstempelvariableself.preCalcdes letzten gedruckten Gewinns zum aktuellen ZeitstempelnowDie Gewinnstatistik verwendet hier die Berechnungsmethode des Nettovermögens, der Code lautet:var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)), d. h. die Währung nach dem aktuellen Kaufpreis 1 in einen Vermögenswert (Quotenwährung) umzuwandeln, ihn dann mit dem Vermögenswertbetrag auf dem Konto zu addieren und der angegebenen lokalen Variablen zuzuordnen.net. Bestimmen Sie, ob der aktuelle Gesamtnettowert mit dem zuletzt erfassten Gesamtnettowert übereinstimmt:

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

Wenn nicht konsistent, d.h.net != self.preNetist wahr, aktualisieren Sie das Attributself.preNetDer Nettowert wird mit dernetDann drucken Sie die Daten des Nettowertes.netSie können das Ergebnis der Überprüfung auf der Website des FMZ Quant Trading Platform-Bots anfragen (siehe unten).LogProfitFunktion in der FMZ-API-Dokumentation).

Wenn das regelmäßige Drucken der Rückkehr nicht ausgelöst wird, dann fortfahren Sie den folgenden Prozess:account.Stocks(die aktuell verfügbaren Währungssymbole auf dem Konto) undaccount.Balance(die zur Verfügung stehenden Aktiva auf dem Konto) inself.btcundself.cny. Berechnen Sie die Verschiebungsquote und ordnen Sie sie an, die inself.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 zu berechnen, wie viele Prozent des aktuellen Währungswerts im Gesamtnettowert des Kontos enthalten sind.

Wie beurteilen Sie also, wann die Währungsbilanz (Position) ausgelöst wird? Hier verwendet der Entwickler 50% nach oben und 2 Prozentpunkte nach unten als Puffer; wenn er den Puffer übersteigt, führt er den Saldo aus, d.h. wennself.p < 0.48Wenn Sie der Meinung sind, dass der Währungsbetrag wenig ist, platzieren Sie jedes Mal, wenn der Preis um 0,01% steigt, drei kleine Aufträge.self.p > 0.52, wenn Sie denken, die Währung beträgt ist groß, warten kleine Aufträge zu verkaufen 1 Preis auf dem Markt. Schließlich warten Sie für eine bestimmte Zeit, nach den Parameter-EinstellungenSleep(BalanceTimeout)Und alle Bestellungen stornieren.

        var orders = exchange.GetOrders()                  # obtain all the current pending orders, and save them in the variable orders"
        if (orders) {                                      # if the variable "orders", which obtains all the current pending orders, is not null
            for (var i = 0; i < orders.length; i++) {      # use the loop to traverse "orders", and cancel the orders one by one 
                if (orders[i].Id != self.tradeOrderId) {
                    exchange.CancelOrder(orders[i].Id)     # call "exchange.CancelOrder", and cancel orders by "orders[i].Id"
                }
            }
        }

Vierte Funktion:

Hier kommt der Kern der Strategie, der Höhepunkt.self.poll = function() {...}Wir haben auch in dem vorherigen Artikel darüber gesprochen.main( )Funktion, starten Sie die Ausführung; vor dem Eintritt derwhileUnendliche Schleife, wir verwendenvar reaper = LeeksReaper()um das Gewinnernteobjekt zu konstruieren, und dannReaper.poll()wird zyklisch in dermain() function.

Dieself.pollFunktion beginnt zu exekutieren und macht einige Vorbereitungen vor jeder Schleife;self.numTick++die Anzahl erhöht;self.updateTrades()aktualisiert die jüngsten Handelsdaten auf dem Markt und berechnet die verwendeten Daten;self.updateOrderBook()aktualisiert die Marktdaten (Auftragsbuch) und berechnet die relevanten Daten;self.balanceAccount()Überprüft den Währungsstand (Position).

        var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct   # calculate the burst price 
        var bull = false             # declare the variable marked by the bull market; the initial value is false
        var bear = false             # declare the variable marked by the bear market; the initial value is false
        var tradeAmount = 0          # declare the variable of trading amount; the initial value is 0

Als nächstes müssen wir beurteilen, ob der aktuelle kurzfristige Markt ein Stier oder ein Bär 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 im vorherigen Artikel, in dem wir den gewogenen Durchschnittsalgorithmus verwendet haben, um eine Zeitreihe zu konstruierenpricesDieses Stück Code verwendet drei neue Funktionen, nämlich_.min, _.max, slice, die auch sehr leicht zu verstehen sind.

  • _.min: Die Funktion besteht darin, das Minimum im Parameter-Array zu finden.

  • _.max: Die Funktion besteht darin, das Maximum im Parameter-Array zu finden.

  • slice: Diese Funktion ist eine Mitgliederfunktion des JavaScript-Array-Objekts. Sie soll einen Teil des Arrays nach dem Index abfangen und zurückgeben.

    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 several elements from 4 to 1, and return a new array: [4,3,2,1]
    }
    

Hier sind die Voraussetzungen für die Beurteilung, ob es sich um einen Bullenmarkt oder einen Bärenmarkt handelt:

  • self.numTick > 2muss wahr sein, d. h. wenn der Preisburst in einer neuen Erkennungsrunde stattfindet, muss er nach mindestens drei Erkennungsrunden ausgelöst werden und zu Beginn nicht ausgelöst werden.
  • Die letzten Daten der Preisreiheself.prices, d. h. die Differenz zwischen den jüngsten Daten und dem Höchst- oder Mindestpreis in derself.pricesDas Array im vorherigen Bereich sollte durchbrechenburstPrice .

Wenn alle Bedingungen wahr sind, markierenbulloderbearalstrue, und die Variable einen Wert zuweisentradeAmount, und planen einen Stallhandel.

Für den ParameterBurstThresholdVol, auf der Grundlage derself.voldie in den vorangegangenenself.updateTrades()Die Kommission hat die Kommission aufgefordert, im Hinblick auf die Anwendung der in der Verordnung (EG) Nr. 1083/2006 vorgesehenen Maßnahmen die

        if (self.vol < BurstThresholdVol) {
            tradeAmount *= self.vol / BurstThresholdVol   // reduce the planned trading volume, and reduce it to the previous volume multiplied by "self.vol / BurstThresholdVol" 
        }
        
        if (self.numTick < 5) {
            tradeAmount *= 0.8      // reduced to 80% of the plan 
        }
        
        if (self.numTick < 10) {    // reduced to 80% of the plan
            tradeAmount *= 0.8
        }

Beurteilen Sie anschließend, ob das Handelssignal und das Handelsvolumen die Anforderungen erfüllen:

        if ((!bull && !bear) || tradeAmount < MinStock) {   # if it is not a bull market nor a bear market, or the planned trading volume "tradeAmount" is less than the minimum trading volume "MinStock" set by the parameter, the "poll" function returns directly without any trading operation
            return
        }

Nach dem oben genannten Urteil, vollstreckenvar tradePrice = bull ? self.bidPrice : self.askPrice- je nachdem, ob es sich um einen Bärenmarkt oder einen Bullenmarkt handelt, den Handelspreis festlegen und den Wert mit dem entsprechenden Lieferbefehlspreis zuordnen.

Schließlich geben Sie einwhileSchleife; die einzige Halt- und Ausbruchbedingung der Schleife isttradeAmount >= MinStock, d. h. das geplante Handelsvolumen ist kleiner als das Mindesthandelsvolumen. In der Schleife, nach dem aktuellen Bullenmarkt-Zustand oder der Bärenmarkt-Zustand, ausführen Sie den Auftrag.orderId- Vernichten Sie ihn.Sleep(200)Die Schleife beurteilt dann, oborderIdist wahr (wenn die Bestellung fehlschlägt, wird die Order-ID nicht zurückgegeben und die Bedingung if wird nicht ausgelöst). Wenn die Bedingung wahr ist, erhalten Sie die Order-ID und weisen Sie sie anself.tradeOrderId.

Eine Variable deklarierenorderdie Auftragsdaten mit dem Anfangswert vonnull. Verwenden Sie dann eine Schleife, um die Auftragsdaten mit der ID zu erhalten und festzustellen, ob die Bestellung sich im Status der ausstehenden Bestellung befindet; wenn sie sich im Status der ausstehenden Bestellung befindet, stornieren Sie die Bestellung mit der ID; wenn sie sich nicht im Status der ausstehenden Bestellung befindet, bricht sie aus der Detektionsschleife aus.

                var order = null           // declare a variable to save the order data 
                while (true) {             // a while loop 
                    order = exchange.GetOrder(orderId)    // call "GetOrder" to query the order data with the ID of  orderId
                    if (order) {                          // if the order data is queried,and the query fails, the order is null, and "if" will not be triggered  
                        if (order.Status == ORDER_STATE_PENDING) {   // judge whether the current order status is pending order
                            exchange.CancelOrder(orderId)            // if the current order status is pending order, cancel the order 
                            Sleep(200)
                        } else {                                     // if not, execute "break" to break out of the while loop 
                            break
                        }
                    }
                }

Führen Sie dann folgendes Verfahren durch:

                self.tradeOrderId = 0              // reset "self.tradeOrderId"
                tradeAmount -= order.DealAmount    // update "tradeAmount", and subtract the executed amount of the orders in the delivery order 
                tradeAmount *= 0.9                 // reduce the intensity of ordering  
                if (order.Status == ORDER_STATE_CANCELED) {     // if the order is canceled 
                    self.updateOrderBook()                      // update the data, including the order book data
                    while (bull && self.bidPrice - tradePrice > 0.1) {   // in a bull market, if the updated bid price exceeds the current trading price by 0.1, reduce the trading intensity, and slightly adjust the trading price 
                        tradeAmount *= 0.99
                        tradePrice += 0.1
                    }
                    while (bear && self.askPrice - tradePrice < -0.1) {  // in a bear market, if the updated ask price exceeds the current trading price by 0.1, reduce the trading intensity, and slightly adjust the trading price 
                        tradePrice -= 0.1
                    }
                }

Wenn der Programmfluss aus demwhile (tradeAmount >= MinStock) {...}Schleife, bedeutet, dass die Ausführung des Preisburst-Handelsprozesses abgeschlossen ist. Ausführenself.numTick = 0, das heißt, zurücksetzenself.numTickauf 0.

Die letzte Ausführung des KonstrukteursLeeksReaper()Gibt dieselfObjekt, das heißt, wennvar reaper = LeeksReaper(), wird das Objekt zurück inreaper.

Wir haben bisher analysiert, wie dieLeeksReaper()Der Konstruktor konstruiert dieses Profit Harvester Objekt, die verschiedenen Methoden des Objekts und den Ausführungsvorgang der wichtigsten Logikfunktionen.


Mehr