Die Strategie der Ernte von Salami-Reinern ((1)

Schriftsteller:Kleine Träume, Erstellt: 2020-11-12 22:11:32, Aktualisiert: 2023-09-26 21:04:43

img

Die Strategie der Kohlensäure-Ernte-Maschine

Die jüngsten Diskussionen in der WeChat-Gruppe über die Erfindung von Quantumprint moneyIn der Diskussion, die sehr heiß ist, ist eine sehr alte Strategie wieder in den Blickfeld der Breitengäste getreten:Die Rebstöckeprint moneyDer Roboter-Trading-Prinzip von Cabbage Harvesters ist auf die Cabbage Harvester-Strategie zurückzuführen und beschuldigt sich, zu der Zeit nicht sehr klar und verständnisvoll zu sein.OKCoin-Transplantation von KabeljauernIch bin nicht derjenige. Es wird die Strategie des Portable-Cabbage Harvesters der Plattform quantifiziert, analysiert und die Ideen der Strategie ausgegraben, damit die Nutzer die Strategie lernen können. In diesem Artikel analysieren wir mehr auf der Ebene von strategischen Ideen, Absichten und so weiter, um den langweiligen Inhalt im Zusammenhang mit Programmieren zu reduzieren.

[OKCoin Transportieren] Strategie Quellcode:

function LeeksReaper() {
    var self = {}
    self.numTick = 0
    self.lastTradeId = 0
    self.vol = 0
    self.askPrice = 0
    self.bidPrice = 0
    self.orderBook = {Asks:[], Bids:[]}
    self.prices = []
    self.tradeOrderId = 0
    self.p = 0.5
    self.account = null
    self.preCalc = 0
    self.preNet = 0

    self.updateTrades = function() {
        var trades = _C(exchange.GetTrades)
        if (self.prices.length == 0) {
            while (trades.length == 0) {
                trades = trades.concat(_C(exchange.GetTrades))
            }
            for (var i = 0; i < 15; i++) {
                self.prices[i] = trades[trades.length - 1].Price
            }
        }
        self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) {
            // Huobi not support trade.Id
            if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
                self.lastTradeId = Math.max(trade.Id == 0 ? trade.Time : trade.Id, self.lastTradeId)
                mem += trade.Amount
            }
            return mem
        }, 0)

    }
    self.updateOrderBook = function() {
        var orderBook = _C(exchange.GetDepth)
        self.orderBook = orderBook
        if (orderBook.Bids.length < 3 || orderBook.Asks.length < 3) {
            return
        }
        self.bidPrice = orderBook.Bids[0].Price * 0.618 + orderBook.Asks[0].Price * 0.382 + 0.01
        self.askPrice = orderBook.Bids[0].Price * 0.382 + orderBook.Asks[0].Price * 0.618 - 0.01
        self.prices.shift()
        self.prices.push(_N((orderBook.Bids[0].Price + orderBook.Asks[0].Price) * 0.35 +
            (orderBook.Bids[1].Price + orderBook.Asks[1].Price) * 0.1 +
            (orderBook.Bids[2].Price + orderBook.Asks[2].Price) * 0.05))
    }
    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)
                }
            }
        }
    }

    self.poll = function() {
        self.numTick++
        self.updateTrades()
        self.updateOrderBook()
        self.balanceAccount()
        
        var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct
        var bull = false
        var bear = false
        var tradeAmount = 0
        if (self.account) {
            LogStatus(self.account, 'Tick:', self.numTick, ', lastPrice:', self.prices[self.prices.length-1], ', burstPrice: ', burstPrice)
        }
        
        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
        }
        if (self.vol < BurstThresholdVol) {
            tradeAmount *= self.vol / BurstThresholdVol
        }
        
        if (self.numTick < 5) {
            tradeAmount *= 0.8
        }
        
        if (self.numTick < 10) {
            tradeAmount *= 0.8
        }
        
        if ((!bull && !bear) || tradeAmount < MinStock) {
            return
        }
        var tradePrice = bull ? self.bidPrice : self.askPrice
        while (tradeAmount >= MinStock) {
            var orderId = bull ? exchange.Buy(self.bidPrice, tradeAmount) : exchange.Sell(self.askPrice, tradeAmount)
            Sleep(200)
            if (orderId) {
                self.tradeOrderId = orderId
                var order = null
                while (true) {
                    order = exchange.GetOrder(orderId)
                    if (order) {
                        if (order.Status == ORDER_STATE_PENDING) {
                            exchange.CancelOrder(orderId)
                            Sleep(200)
                        } else {
                            break
                        }
                    }
                }
                self.tradeOrderId = 0
                tradeAmount -= order.DealAmount
                tradeAmount *= 0.9
                if (order.Status == ORDER_STATE_CANCELED) {
                    self.updateOrderBook()
                    while (bull && self.bidPrice - tradePrice > 0.1) {
                        tradeAmount *= 0.99
                        tradePrice += 0.1
                    }
                    while (bear && self.askPrice - tradePrice < -0.1) {
                        tradeAmount *= 0.99
                        tradePrice -= 0.1
                    }
                }
            }
        }
        self.numTick = 0
    }
    return self
}

function main() {
    var reaper = LeeksReaper()
    while (true) {
        reaper.poll()
        Sleep(TickInterval)
    }
}

Übersicht über die Strategie

Wenn man eine Strategie lernen möchte, muss man sich zunächst die Gesamtstruktur des Programms anschauen. Die Strategiecode ist nicht viel, nur weniger als 200 Zeilen Code, ist sehr schlank und hat eine hohe Strategie-Rendernzierung gegenüber der Originalversion.main()Die Funktion beginnt mit der Ausführung, indem sie den gesamten Code der Strategie ausführt.main()Das ist ein Projekt namensLeeksReaper()Das ist die Funktion, die wir haben.LeeksReaper()Die Funktion ist auch gut verständlich, die als Konstruktionsfunktion für die Strategie Logikmodul (ein Objekt) des Cabbage Harvesters verstanden werden kann, einfach gesagt.LeeksReaper()Die Firma ist verantwortlich für die Konstruktion der Handelslogik einer Salami-Reinzelmaschine.

Schlüsselwort:img img

  • Die StrategiemainDie erste Zeile der Funktion:var reaper = LeeksReaper()Der Code erklärt eine lokale Variable.reaper, dann ruft man die LeeksReaper () Funktion, um einen strategischen Logikobjekt zu konstruieren, dem ein Wert zugewiesen wird.reaper

  • Die StrategiemainDie Funktion folgt:

    while (true) {
        reaper.poll()
        Sleep(TickInterval)
    }
    

    Einzug in einwhileDer Todeskreis, die ständige AusführungreaperObjektverarbeitungsfunktionpoll()poll()Die Funktion ist die Hauptlogik der Handelsstrategie, und der gesamte Strategieprozess beginnt mit der ständigen Ausführung der Handelslogik. Was istSleep(TickInterval)Die Linie ist gut verstanden, um die Pausezeit nach jeder Ausführung der gesamten Transaktionslogik zu kontrollieren, um die Drehzahl der Transaktionslogik zu kontrollieren.

AnatomieLeeksReaper()Konstruktionsfunktionen

Sieh dir das an.LeeksReaper()Wie konstruiert eine Funktion ein strategisches logisches Objekt?

LeeksReaper()Die Funktion beginnt und deklariert einen leeren Objekt.var self = {}DieLeeksReaper()Während der Funktionsdurchführung werden schrittweise Methoden und Eigenschaften zu diesem leeren Objekt hinzugefügt, um schließlich die Konstruktion des Objektes abzuschließen und schließlich dieses Objekt zurückzugeben.main()Die Funktion.var reaper = LeeksReaper()Das ist der Punkt, an dem das Objekt, das zurückgegeben wurde, den Wert erhält.reaper)。

Geben Sie mirselfObjekt-Zusatz von Eigenschaften

Dann kommt der nächsteselfEs wurden viele Eigenschaften hinzugefügt, die ich im Folgenden beschreibe, um diese Eigenschaften schnell zu verstehen, die Verwendung von Variablen, die Absicht, die einfache Strategie zu verstehen und zu vermeiden, dass der Stapel Code in einer Nebelwolke umgeben ist.

    self.numTick = 0         # 用来记录poll函数调用时未触发交易的次数,当触发下单并且下单逻辑执行完时,self.numTick重置为0
    self.lastTradeId = 0     # 交易市场已经成交的订单交易记录ID,这个变量记录市场当前最新的成交记录ID
    self.vol = 0             # 通过加权平均计算之后的市场每次考察时成交量参考(每次循环获取一次市场行情数据,可以理解为考察了行情一次)
    self.askPrice = 0        # 卖单提单价格,可以理解为策略通过计算后将要挂卖单的价格
    self.bidPrice = 0        # 买单提单价格
    self.orderBook = {Asks:[], Bids:[]}    # 记录当前获取的订单薄数据,即深度数据(卖一...卖n,买一...买n)
    self.prices = []                       # 一个数组,记录订单薄中前三档加权平均计算之后的时间序列上的价格,简单说就是每次储存计算得到的订单薄前三档加权平均价格,放在一个数组中,用于后续策略交易信号参考,所以该变量名是prices,复数形式,表示一组价格
    self.tradeOrderId = 0    # 记录当前提单下单后的订单ID
    self.p = 0.5             # 仓位比重,币的价值正好占总资产价值的一半时,该值为0.5,即平衡状态
    self.account = null      # 记录账户资产数据,由GetAccount()函数返回数据
    self.preCalc = 0         # 记录最近一次计算收益时的时间戳,单位毫秒,用于控制收益计算部分代码触发执行的频率
    self.preNet = 0          # 记录当前收益数值

Geben Sie mirselfMethode zum Hinzufügen von Objekten

Wenn wir selbst diese Eigenschaften hinzugefügt haben, dann können wir uns anfangen, selbst zu geben.selfEin Objekt kann Methoden hinzufügen, die es erlauben, einige Aufgaben zu erledigen und Funktionen zu haben.

Die erste Funktion, die hinzugefügt wurde:

    self.updateTrades = function() {
        var trades = _C(exchange.GetTrades)  # 调用FMZ封装的接口GetTrades,获取当前最新的市场成交数据
        if (self.prices.length == 0) {       # 当self.prices.length == 0时,需要给self.prices数组填充数值,只有策略启动运行时才会触发
            while (trades.length == 0) {     # 如果近期市场上没有更新的成交记录,这个while循环会一直执行,直到有最新成交数据,更新trades变量
                trades = trades.concat(_C(exchange.GetTrades))   # concat 是JS数组类型的一个方法,用来拼接两个数组,这里就是把“trades”数组和“_C(exchange.GetTrades)”返回的数组数据拼接成一个数组
            }
            for (var i = 0; i < 15; i++) {   # 给self.prices填充数据,填充15个最新成交价格
                self.prices[i] = trades[trades.length - 1].Price
            }
        }
        self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) {  # _.reduce 函数迭代计算,累计最新成交记录的成交量
            // Huobi not support trade.Id
            if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
                self.lastTradeId = Math.max(trade.Id == 0 ? trade.Time : trade.Id, self.lastTradeId)
                mem += trade.Amount
            }
            return mem
        }, 0)

    }

updateTradesDie Funktion erhält die aktuellsten Markttransaktionsdaten und macht darauf basierend einige Berechnungen und Aufzeichnungen, die für die Logik der Strategie zur Verfügung stehen. Ich habe die Kommentare direkt in den oben genannten Code geschrieben. Für_.reduceIch möchte Ihnen sagen, dass es für Leute, die keine Programmierkenntnisse haben, verwirrend sein könnte, aber ich möchte Ihnen sagen, dass es einfach ist, wenn Sie ein Programm schreiben._.reduceJa, das ist es.Underscore.jsDie Funktionen dieser Bibliothek werden von der FMZJS-Politik unterstützt, so dass sie für die Iderative sehr praktisch sind.Underscore.js资料链接

Die Bedeutung ist auch sehr einfach:

function main () {
   var arr = [1, 2, 3, 4]
   var sum = _.reduce(arr, function(ret, ele){
       ret += ele
       
       return ret
   }, 0)

   Log("sum:", sum)    # sum 等于 10
}

Das ist die Array.[1, 2, 3, 4]Wir haben eine Reihe von Zahlen, die wir zusammenzählen.tradesDie Summe der Zahlen der Transaktionen für jede Transaktionsprotokolldaten in der Matrix führt zu einer aktuellen Transaktionsprotokollsumme.self.vol = 0.7 * self.vol + 0.3 * _.reduce(...)Bitte erlauben Sie mir,...Es ist nicht schwer zu sehen, wie das mit der Anzahl der Code ersetzt wird.self.volDie Berechnung ist auch ein gewichteter Durchschnitt; d.h. die neueste Transaktion wird mit 30% der Gesamttransaktion gewogen, während die letzte Transaktion mit 70% der Transaktion gewogen wird. Dieser Prozentsatz wurde von den Strategie-Autoren selbst festgelegt und kann mit der Beobachtung von Marktregeln zusammenhängen. Wenn Sie mich fragen, was ich tun sollte, wenn die Schnittstelle, die die letzten Transaktionsdaten bekommt, mir wiederholte alte Daten zurückgibt, dann ist meine Daten falsch und haben sie einen Nutzen?

if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
    ...
}

Dieses Urteil kann basierend auf der Transaktions-ID in den Transaktionsprotokollen erfolgen, die nur dann aufgeladen werden, wenn die ID größer ist als die ID des letzten Aufzeichnungsprotokolls, oder wenn die Interface der Börse keine ID anbietet.trade.Id == 0Das ist eine sehr schwierige Zeit, um zu entscheiden, ob Sie in der Lage sind, die Daten zu speichern.self.lastTradeIdDie Zeitstempel der Transaktionsprotokolle werden gespeichert, nicht die ID.

Die zweite Funktion, die hinzugefügt wurde:

    self.updateOrderBook = function() {
        var orderBook = _C(exchange.GetDepth)
        self.orderBook = orderBook
        if (orderBook.Bids.length < 3 || orderBook.Asks.length < 3) {
            return
        }
        self.bidPrice = orderBook.Bids[0].Price * 0.618 + orderBook.Asks[0].Price * 0.382 + 0.01
        self.askPrice = orderBook.Bids[0].Price * 0.382 + orderBook.Asks[0].Price * 0.618 - 0.01
        self.prices.shift()
        self.prices.push(_N((orderBook.Bids[0].Price + orderBook.Asks[0].Price) * 0.35 +
            (orderBook.Bids[1].Price + orderBook.Asks[1].Price) * 0.1 +
            (orderBook.Bids[2].Price + orderBook.Asks[2].Price) * 0.05))
    }

Das ist nicht wahr.updateOrderBookDiese Funktion, wie man aus dem Namen der Funktion sehen kann, ist eine Funktion, die die Funktion "Update Order Thin" ("Erneuer den Auftrag dünn"), aber nicht nur "Erneuer den Auftrag dünn" ("Erneuer den Auftrag dünn") ausführt.GetDepth()Wir erhalten die aktuellen Marktorderabschnitte (Sell one...Sell n, Buy one...Buy n) und erfassen die Daten inself.orderBookDie Funktion wird dann als ungültig eingestuft, wenn weniger als 3 Bestelldaten zurückgegeben werden.

In der Folge wurden zwei Daten berechnet:

  • Berechnung der Gebühr Die Berechnung des Aufschlagspreises wird ebenfalls mit einem gewogenen Durchschnitt berechnet, bei der Berechnung der Auszahlung beträgt der Kaufanteil 61.8% ((0.618), der Verkauf beträgt 38.2% ((0.382) Bei der Berechnung des Verkaufspreises ist das gleiche der Fall. Die Preisberechtigung ist größer als die Verkaufspreisberechtigung. Warum 0.618 ist, ist möglicherweise der Grund, warum der Autor die Goldspaltung bevorzugt.

  • Updated Zeitreihenfolge der Bestellungen der ersten drei Klassen mit dem gewogenen Durchschnittspreis Für die ersten drei Bestellklassen, die mit dem Preis der Bestellung berechnet werden, wird das Gewicht der ersten Klasse 0,7, das Gewicht der zweiten Klasse 0,2, das Gewicht der dritten Klasse 0,1 betrachtet. Wir werden die Rechenprozesse weiterführen:

    (买一 + 卖一) * 0.35 + (买二 + 卖二) * 0.1 + (买三 + 卖三) * 0.05
    ->
    (买一 + 卖一) / 2 * 2 * 0.35 + (买二 + 卖二) / 2 * 2 * 0.1 + (买三 + 卖三) / 2 * 2 * 0.05
    ->
    (买一 + 卖一) / 2 * 0.7 + (买二 + 卖二) / 2 * 0.2 + (买三 + 卖三) / 2 * 0.1
    ->
    第一档平均的价格 * 0.7 + 第二档平均的价格 * 0.2 + 第三档平均的价格 * 0.1
    

    Hier kann man sehen, dass der endgültig errechnete Preis in Wirklichkeit die Preissituation der drei mittleren Klassen in der gegenwärtigen Marktposition ist. Dann wird der Preis berechnet und aktualisiert.self.pricesDie Array, die eine der ältesten Daten (z.B.shift()Funktion), aktualisiert in eine aktuelle Daten ((durchpush()Funktionen, Shift, Push sind Methoden, mit denen Arithmetikobjekte in der JS-Sprache erstellt werden können.self.pricesEine Array ist ein Datenstrom mit einer zeitlichen Reihenfolge.

Ich habe einen Husten, ich habe ein Wasser im Mund, ich muss mich hier untersuchen, bis dann.


Mehr

Ich bin immer stärker geworden.Selbst.prices ist eine Plattform, in der Sie die 15 historischen Transaktionspreise ausfüllen und dann die gewogenen Durchschnittspreise der ersten drei Bestellungen ausfüllen.

SchnlnppIch möchte meinen Traum loben.

m0606Leider haben viele Börsenhändler die Börse auf einen Kauf-und-Verkauf-Preis reduziert, so dass es keinen Sinn mehr hat, diese Strategie in einen Kauf-und-Verkauf-Zwischenhandel einzubeziehen.

MutterIch habe eine Python-Version geschrieben, die auf der Zytcoin läuft.

- Ich weiß nicht.Das ist großartig, ohne eine Traumdeutung kann ich es wirklich nicht ganz verstehen, danke für die geduldige Erklärung!

- Ich weiß.Die Goldspaltung 0.618 0.382 ist ein verwendeter Fibro Die Rinder

- Ich weiß nicht.Das ist wirklich eine Kuhmasse.

- Ich weiß nicht.Ich freue mich sehr, dass Sie diese Antwort so detailliert geben.

Ein bisschenDer Traum der Rinder

SchwimmenIch bin nicht derjenige, der das Wort "Kühe" benutzt. Ich habe die Anmerkung gemacht, aber es sieht sehr kompliziert aus.

Neun SonnenIch bin nicht derjenige, der das sagt.

Kleine TräumeJa, das stimmt.

Kleine TräumeEs geht vor allem darum, Ideen zu erlernen und Einblicke in diese hochfrequenten Handelsmöglichkeiten zu bekommen.

Kleine TräumeDie Strategie der Hochfrequenzstrategie braucht etwas Unterstützung.

Kleine TräumeDanke für Ihre Unterstützung. Wenn Sie es mögen, teilen Sie es mit uns.

Kleine TräumeDanke für die Unterstützung!

Kleine TräumeDanke für die Unterstützung!

Kleine TräumeDanke für die Unterstützung!

Kleine TräumeAls ich in die Schule ging, erinnerte ich mich besonders gut an diese goldene Verteilung und sagte, dass die Rechtecke in diesem Verhältnis am schönsten seien.

Kleine TräumeDanke für die Unterstützung.

Kleine TräumeEs ist nicht kompliziert, die Kommentare sind vergleichsweise kompliziert und versuchen, sie Zeile für Zeile so einfach wie möglich zu beschreiben.