
DannVorheriger Inhalterklären.
Die dritte hinzugefügte 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("开始平衡", 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)
}
}
}
}
KonstruktorLeeksReaper()Wenn Sie ein Objekt konstruieren, fügen Sie hinzubalanceAccount()Die Funktion dient zur Aktualisierung der Kontovermögensinformationen, gespeichert inself.account, das heißt das konstruierte ObjektaccountEigentum. Berechnen und drucken Sie regelmäßig den Gewinnwert. Anschließend wird auf Grundlage der neuesten Informationen zum Kontovermögen das Kassawährungsbilanzverhältnis (Kassapositionsbilanz) berechnet. Wenn der Abweichungsschwellenwert erreicht wird, wird eine kleine Order geschlossen, um die Währung (Position) wieder in einen ausgeglichenen Zustand zu versetzen. Warten Sie eine bestimmte Zeit, bis die Transaktion abgeschlossen ist, und stornieren Sie dann alle ausstehenden Aufträge. In der nächsten Ausführungsrunde dieser Funktion wird der Kontostand erneut überprüft und die entsprechende Verarbeitung durchgeführt.
Schauen wir uns den Code dieser Funktion Zeile für Zeile an:
Erster Satzvar account = exchange.GetAccount()Es deklariert eine lokale Variableaccountund rufen Sie die Inventor-API-Schnittstelle aufexchange.GetAccount()Funktion, holen Sie sich die neuesten Daten des Girokontos und ordnen Sie diese zuaccountVariable. Dann urteilenaccountDiese Variable, wenn die VariablenullWenn der Wert (z. B. Timeout, Netzwerk, Exchange-Schnittstellenausnahme usw.) nicht abgerufen werden kann, wird er direkt zurückgegeben (entsprichtif (!account){...}Hier).
self.account = accountDieser Satz dient zum Einfügen der lokalen VariableaccountDem konstruierten Objekt zugeordnetaccountAttribute werden verwendet, um die neuesten Kontoinformationen im erstellten Objekt aufzuzeichnen.
var now = new Date().getTime()Diese Anweisung deklariert eine lokale Variablenowund rufen Sie das Zeit- und Datumsobjekt der JavaScript-Sprache aufgetTime()Die Funktion gibt den aktuellen Zeitstempel zurück. Zuweisen annowVariable.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}Dieser Code bestimmt, ob die Differenz zwischen dem aktuellen Zeitstempel und dem zuletzt aufgezeichneten Zeitstempel den Parameter überschreitetCalcNetInterval * 1000Das bedeutet, dass seit dem letzten Update bis heute mehr alsCalcNetInterval * 1000Millisekunde(CalcNetIntervalSekunden), um die Funktion des Timing-Drucks des Einkommens zu erreichen. Da der Preis des ersten Gebots bei der Berechnung des Einkommens verwendet wird, begrenzen auch die Bedingungenself.orderBook.Bids.length > 0Diese Bedingung (Tiefendaten, es müssen gültige Ausrüstungsinformationen in der Kaufauftragsliste vorhanden sein). Wenn diese if-Anweisungsbedingung ausgelöst wird, wird die Ausführungself.preCalc = nowAktualisieren Sie die Zeitstempelvariable der aktuellsten Druckeinnahmenself.preCalcAktueller Zeitstempelnow. Die Einkommensstatistik verwendet hier die Nettowertberechnungsmethode, der Code istvar net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks)), d. h., die Münze wird entsprechend dem aktuellen Kaufpreis in Geld (Nenner) umgewandelt, dann zum Geldbetrag auf dem Konto addiert und der deklarierten lokalen Variablen zugewiesennet. Bestimmen Sie, ob der aktuelle Gesamtnettowert mit dem zuletzt erfassten Gesamtnettowert übereinstimmt:
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
Wenn sie inkonsistent sind,net != self.preNetWenn wahr, verwenden SienetVariablenaktualisierungen werden verwendet, um die Eigenschaften des Nettowertes aufzuzeichnenself.preNet. Drucken Sie dies dann ausnetGesamtvermögensdaten zum Gewinnkurvendiagramm des quantitativen Handelsplattformroboters des Erfinders (kann im FMZ API-Dokument abgefragt werden)LogProfitdiese Funktion).
Sollten die geplanten Druckeinnahmen nicht ausgelöst werden, fahren Sie mit dem folgenden Vorgang fort.account.Stocks(die Anzahl der auf dem Girokonto verfügbaren Coins),account.Balance(Der aktuell auf dem Konto verfügbare Geldbetrag) wird erfasst inself.btc,self.cny. Berechnen Sie das Offset-Verhältnis und weisen Sie den Wert dem Datensatz zuself.p。
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
Der Algorithmus ist ebenfalls sehr einfach: Er berechnet den aktuellen Wert der Münze als Prozentsatz des gesamten Nettowerts des Kontos.
Wie bestimmen wir also, wann der Geldbestand (die Position) erreicht wird?
Der Autor verwendet 2 Prozentpunkte über und unter 50 % als Puffer und führt einen Ausgleich über den Puffer hinaus durch, d. h.self.p < 0.48Die Abweichung des Münzbestands wird ausgelöst und man geht davon aus, dass weniger Münzen vorhanden sind. Beginnen Sie daher mit dem Kauf an einer Position auf dem Markt, erhöhen Sie den Preis jedes Mal um 0,01 und erteilen Sie drei kleine Aufträge. Ebenso Währungsbilanzself.p > 0.52Wenn Sie der Meinung sind, dass Sie zu viele Münzen haben, können Sie eine kleine Bestellung aufgeben, indem Sie zum Eröffnungspreis verkaufen. Warten Sie abschließend eine bestimmte Zeit entsprechend den ParametereinstellungenSleep(BalanceTimeout)Sämtliche Bestellungen werden danach storniert.
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取消订单
}
}
}
Die vierte hinzugefügte Funktion:
Der Kern der Strategie, das Highlight ist hier,self.poll = function() {...}Die Funktion ist die Hauptlogik der gesamten Strategie. Darüber haben wir auch im vorherigen Artikel gesprochen.main()Die Funktion wird ausgeführt und gibt einwhileVor der Endlosschleife verwenden wirvar reaper = LeeksReaper()Konstruierte ein Lauchernteobjekt und dannmain()Schleifenaufruf in der Funktionreaper.poll()Dies ist die Funktion, die aufgerufen wird.
self.pollDie Funktion beginnt mit der Ausführung und führt vor jeder Schleife einige Vorbereitungsarbeiten durch.self.numTick++Erhöhen Sie die Anzahl,self.updateTrades()Aktualisieren Sie die neuesten Markttransaktionsaufzeichnungen und berechnen Sie die relevanten Daten.self.updateOrderBook()Aktualisieren Sie die Auftragsbuchdaten und berechnen Sie die zugehörigen Daten.self.balanceAccount()Überprüfen Sie den Geldbestand (Position).
var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct # 计算爆发价格
var bull = false # 声明牛市标记的变量,初始为假
var bear = false # 声明熊市标记的变量,初始为假
var tradeAmount = 0 # 声明交易数量变量,初始为0
Der nächste Schritt besteht darin, festzustellen, ob der aktuelle kurzfristige Markt bullisch oder bearisch 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
}
Denken Sie daran, im vorherigen Artikelself.updateOrderBook()Funktion, in der wir den Algorithmus des gewichteten Durchschnitts verwenden, um eine Zeitreihe mit der ReihenfolgepricesAnordnung. In diesem Code werden drei neue Funktionen verwendet_.min,_.max,sliceAuch diese drei Funktionen sind sehr leicht zu verstehen.
_.min: Seine Funktion besteht darin, den kleinsten Wert im Parameter-Array zu finden.
_.max: Seine Funktion besteht darin, den größten Wert im Parameter-Array zu finden.
slice: Diese Funktion ist eine Mitgliedsfunktion des JavaScript-Array-Objekts. Ihre Funktion besteht darin, einen Teil des Arrays entsprechend dem Index abzufangen und zurückzugeben. 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)) // 会截取 4 ~ 1 这几个元素,返回一个新数组:[4,3,2,1]
}

Die Bedingungen zur Beurteilung von Bären und Bullen sind hier:
self.numTick > 2Um etabliert zu sein, bedeutet dies, dass bei Ausbruch einer neuen Runde von Erkennungspreisen diese nach mindestens drei Erkennungsrunden ausgelöst werden muss, um eine Auslösung zu Beginn zu vermeiden.self.pricesDie letzten Daten imself.pricesDie Differenz zwischen dem Maximal- oder Minimalpreis im vorherigen Bereich im Array soll aufgebrochen werdenburstPriceDas ist der Explosionspreis.Wenn alle Bedingungen erfüllt sind, markieren Siebulloderbear,fürtrueund geben SietradeAmountWeisen Sie Variablen zu und planen Sie Stud-Trades.
Nach der vorherigenself.updateTrades()Aktualisiert und berechnet in der Funktionself.volfür den ParameterBurstThresholdVolEntscheiden Sie, ob die Handelsintensität reduziert werden soll (Reduzierung der Größe geplanter Trades).
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
}
Bestimmen Sie als nächstes, ob das Handelssignal und das Handelsvolumen die Anforderungen erfüllen:
if ((!bull && !bear) || tradeAmount < MinStock) { # 如果非牛市并且也非熊市,或者计划交易的量tradeAmount小于参数设置的最小交易量MinStock,poll函数直接返回,不做交易操作
return
}
Nach dem obigen Urteil führen Sievar tradePrice = bull ? self.bidPrice : self.askPriceLegen Sie den Transaktionspreis danach fest, ob es sich um einen Bärenmarkt oder einen Bullenmarkt handelt, und ordnen Sie den Wert dem entsprechenden Frachtbriefpreis zu.
Geben Sie abschließend einewhileDie einzige Bedingung zum Stoppen der Schleife isttradeAmount >= MinStockDas geplante Transaktionsvolumen ist geringer als das Mindesttransaktionsvolumen.
In der Schleife werden Aufträge erteilt, je nachdem, ob der aktuelle Markt bullisch oder bearisch ist. Und erfassen Sie die Bestellnummer in der VariablenorderId. Nach jeder BestellrundeSleep(200)Warten Sie 200 Millisekunden. Dann urteilen Sie in der SchleifeorderIdIst „true“ (wenn die Bestellung fehlschlägt, wird die Bestell-ID nicht zurückgegeben und die If-Bedingung wird nicht ausgelöst), wenn die Bedingung erfüllt ist. Holen Sie sich die Bestell-ID und ordnen Sie sie zuself.tradeOrderId。
Deklarieren Sie eine Variable zum Speichern von BestelldatenorderDer Anfangswert istnull. Dann durchlaufen Sie eine Schleife, um die Bestelldaten dieser ID abzurufen und festzustellen, ob die Bestellung im Status „Ausstehende Bestellung“ ist. Wenn sie im Status „Ausstehende Bestellung“ ist, stornieren Sie die Bestellung dieser ID. Wenn sie nicht im Status „Ausstehende Bestellung“ ist, springen Sie aus dieser Erkennungsschleife.
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
}
}
}
Befolgen Sie dann die nachstehenden Schritte:
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
}
}
Wenn der Programmfluss aus dem Ruder läuftwhile (tradeAmount >= MinStock) {...}Dieser Zyklus zeigt an, dass der Transaktionsprozess der Preisexplosion abgeschlossen ist.
implementierenself.numTick = 0, das heißt, zurücksetzenself.numTickist 0.
LeeksReaper()Der Konstruktor wird schließlich ausgeführtselfDas zurückgegebene Objekt istvar reaper = LeeksReaper()Als es zurückgegeben wurdereaper。
Bis jetztLeeksReaper()Wir haben analysiert, wie der Konstruktor das Lauchernteobjekt konstruiert, die verschiedenen Methoden des Lauchernteobjekts und den Ausführungsprozess der wichtigsten Logikfunktionen. Ich glaube, dass Sie nach dem Lesen dieses Artikels ein klareres Verständnis der Hochfrequenz haben sollten Strategie-Algorithmus-Prozess. Verstehen.