
[TOC] Ich habe 2020 einen Artikel geschrieben, in dem ich Hochfrequenzstrategien vorstelle, https://www.fmz.com/digest-topic/6228. Obwohl es viel Aufmerksamkeit erhielt, war es nicht sehr ausführlich geschrieben. Mehr als zwei Jahre sind vergangen und der Markt hat sich verändert. Nach der Veröffentlichung dieses Artikels konnte ich mit meiner Hochfrequenzstrategie lange Zeit stetig Geld verdienen, die Gewinne gingen jedoch allmählich zurück und kamen irgendwann sogar zum Stillstand. Ich habe in den letzten Monaten viel Arbeit in die Renovierung gesteckt und kann mittlerweile auch etwas Geld damit verdienen. In diesem Artikel stelle ich meine Ideen für Hochfrequenzstrategien und einige vereinfachte Codes ausführlicher vor, was als Ausgangspunkt für Diskussionen dienen kann. Jeder ist herzlich eingeladen, zu kommunizieren und Feedback zu geben.
Für Konten, die Rabatte erhalten, beträgt der aktuelle Maker-Rabatt beispielsweise bei Binance 0,5 % von 100.000. Wenn das tägliche Transaktionsvolumen 100 Millionen U beträgt, beträgt der Rabatt 5.000 U. Natürlich basiert die Taker-Gebühr immer noch auf dem VIP-Tarif. Wenn die Strategie also keine Auftragsannahme erfordert, hat der VIP-Level bei Hochfrequenzstrategien nur geringe Auswirkungen. Im Allgemeinen gelten für unterschiedliche Austauschebenen unterschiedliche Rabattsätze und es ist erforderlich, ein höheres Transaktionsvolumen aufrechtzuerhalten. Vor langer Zeit, als der Markt einiger Währungen stark schwankte, gab es auch ohne Rabatte noch Gewinne. Mit der Intensivierung des internen Umlaufs machten Rabatte einen großen Teil der Gewinne aus und stützten sich sogar vollständig auf Rabatte. Hochfrequenzhändler verfolgen Top Preise.
Geschwindigkeit. Der Grund, warum die Hochfrequenzstrategie Hochfrequenz genannt wird, liegt darin, dass sie sehr schnell ist. Der Beitritt zum Colocation-Server der Börse, um die geringste Latenz und die stabilste Verbindung zu erhalten, ist ebenfalls eine der Voraussetzungen für den internen Umlauf geworden. Der interne Zeitaufwand der Strategie sollte außerdem so gering wie möglich sein. In diesem Artikel wird das von mir verwendete WebSocket-Framework vorgestellt, das eine parallele Ausführung verwendet.
Der richtige Markt. Hochfrequenzhandel gilt als das Juwel des quantitativen Handels. Ich glaube, dass viele programmatische Händler es versucht haben, aber die meisten hören wahrscheinlich auf, weil sie kein Geld verdienen und keinen Weg finden, sich zu verbessern. Der Hauptgrund ist wahrscheinlich dass sie den falschen Weg suchen. Den Handelsmarkt. In der Anfangsphase einer Strategie sollte man nach Märkten suchen, auf denen man mit dem Handel relativ leicht Geld verdienen kann, damit Gewinne erzielt werden und Feedback zu Verbesserungen entsteht, was der Weiterentwicklung der Strategie förderlich ist. Wenn Sie auf dem wettbewerbsintensivsten Markt beginnen und mit vielen potenziellen Konkurrenten konkurrieren, werden Sie trotz aller Bemühungen Geld verlieren und nicht länger durchhalten können. Ich empfehle die neu gelisteten unbefristeten Kontrakt-Handelspaare. Derzeit gibt es nicht so viele Konkurrenten, insbesondere wenn das Handelsvolumen relativ groß ist. Dies ist die einfachste Zeit, um Geld zu verdienen. BTC und ETH weisen das größte Handelsvolumen und die meisten aktiven Transaktionen auf, aber bei ihnen ist es auch am schwierigsten, zu überleben.
Stellen Sie sich der Konkurrenz direkt. Jeder Handelsmarkt verändert sich dynamisch. Keine Handelsstrategie kann ein für alle Mal funktionieren. Dies ist beim Hochfrequenzhandel noch offensichtlicher. Wer in diesen Markt einsteigt, tritt in direkten Wettbewerb mit einer Gruppe der intelligentesten und fleißigsten Händler. In einem Nullsummenmarkt verdienen die anderen umso weniger, je mehr Sie verdienen. Je später Sie einsteigen, desto schwieriger wird es. Auch die bereits auf dem Markt befindlichen Unternehmen müssen sich ständig verbessern, da sie jederzeit ausscheiden können. Vor drei oder vier Jahren hätte die beste Gelegenheit dafür sein sollen. In letzter Zeit hat die Gesamtaktivität des digitalen Währungsmarktes nachgelassen, und für Neulinge ist es jetzt sehr schwierig, sich am Hochfrequenzhandel zu beteiligen.
Es gibt viele Arten von Hochfrequenzstrategien
Meine Strategie ist eine Kombination aus Trend und Market Maker. Ich bestimme zuerst den Trend, platziere dann eine Order und platziere unmittelbar nach Abschluss der Transaktion eine Verkaufsorder. Ich halte keine Lagerbestände. Der Strategiecode wird unten vorgestellt.
Der folgende Code basiert auf der grundlegenden Architektur der unbefristeten Verträge von Binance und abonniert hauptsächlich Marktinformationen und Positionsinformationen zu Deep-Order-Flow-Trades über WebSocket. Da die Marktinformationen und die Kontoinformationen separat abonniert werden, muss read(-1) kontinuierlich verwendet werden, um festzustellen, ob die neuesten Informationen abgerufen werden. EventLoop(1000) wird hier verwendet, um eine direkte Endlosschleife zu vermeiden und die Systembelastung zu verringern. EventLoop(1000) wird mit einem Timeout von 1000 ms blockiert, bis WSS oder gleichzeitige Aufgaben zurückkehren.
var datastream = null
var tickerstream = null
var update_listenKey_time = 0
function ConncetWss(){
if (Date.now() - update_listenKey_time < 50*60*1000) {
return
}
if(datastream || tickerstream){
datastream.close()
tickerstream.close()
}
//需要APIKEY
let req = HttpQuery(Base+'/fapi/v1/listenKey', {method: 'POST',data: ''}, null, 'X-MBX-APIKEY:' + APIKEY)
let listenKey = JSON.parse(req).listenKey
datastream = Dial("wss://fstream.binance.com/ws/" + listenKey + '|reconnect=true', 60)
//Symbols是设定的交易对
let trade_symbols_string = Symbols.toLowerCase().split(',')
let wss_url = "wss://fstream.binance.com/stream?streams="+trade_symbols_string.join(Quote.toLowerCase()+"@aggTrade/")+Quote.toLowerCase()+"@aggTrade/"+trade_symbols_string.join(Quote.toLowerCase()+"@depth20@100ms/")+Quote.toLowerCase()+"@depth20@100ms"
tickerstream = Dial(wss_url+"|reconnect=true", 60)
update_listenKey_time = Date.now()
}
function ReadWss(){
let data = datastream.read(-1)
let ticker = tickerstream.read(-1)
while(data){
data = JSON.parse(data)
if (data.e == 'ACCOUNT_UPDATE') {
updateWsPosition(data)
}
if (data.e == 'ORDER_TRADE_UPDATE'){
updateWsOrder(data)
}
data = datastream.read(-1)
}
while(ticker){
ticker = JSON.parse(ticker).data
if(ticker.e == 'aggTrade'){
updateWsTrades(ticker)
}
if(ticker.e == 'depthUpdate'){
updateWsDepth(ticker)
}
ticker = tickerstream.read(-1)
}
makerOrder()
}
function main() {
while(true){
ConncetWss()
ReadWss()
worker()
updateStatus()
EventLoop(1000)
}
}
Wie bereits erwähnt, erfordert meine Hochfrequenzstrategie die Bestimmung des Trends vor der Ausführung von Käufen und Verkäufen. Der kurzfristige Trend wird hauptsächlich anhand der Transaktionsdaten jeder Transaktion beurteilt, d. h. anhand des AggTrade im Abonnement, das Transaktionsrichtung, Preis, Menge, Transaktionszeit usw. umfasst. Die wichtigsten Bezugspunkte für Kauf und Verkauf sind Tiefe und Handelsvolumen. Im Folgenden finden Sie eine detaillierte Einführung in die Indikatoren, die beachtet werden müssen. Die meisten Indikatoren sind in zwei Gruppen unterteilt: Kaufen und Verkaufen und werden dynamisch in einem bestimmten Zeitfenster gezählt. Das Zeitfenster meiner Strategie liegt innerhalb von 10 Sekunden.
//bull代表短期看涨,bear短期看跌
let bull = last_sell_price > avg_sell_price && last_buy_price > avg_buy_price &&
avg_buy_amount / avg_buy_time > avg_sell_amount / avg_sell_time;
let bear = last_sell_price < avg_sell_price && last_buy_price < avg_buy_price &&
avg_buy_amount / avg_buy_time < avg_sell_amount / avg_sell_time;
Wenn der letzte Verkaufspreis höher ist als der durchschnittliche Verkaufspreis, der letzte Kaufpreis höher ist als der durchschnittliche Kaufpreis und der Wert der Kauforder mit festem Intervall höher ist als der Wert der Verkaufsorder, dann wird dies als kurzfristig bullisch beurteilt. . Im Gegenteil, es ist bärisch.
function updatePrice(depth, bid_amount, ask_amount) {
let buy_price = 0
let sell_price = 0
let acc_bid_amount = 0
let acc_ask_amount = 0
for (let i = 0; i < Math.min(depth.asks.length, depth.bids.length); i++) {
acc_bid_amount += parseFloat(depth.bids[i][1])
acc_ask_amount += parseFloat(depth.asks[i][1])
if (acc_bid_amount > bid_amount && buy_price == 0) {
buy_price = parseFloat(depth.bids[i][0]) + tick_size
}
if (acc_ask_amount > ask_amount && sell_price == 0) {
sell_price = parseFloat(depth.asks[i][0]) - tick_size
}
if (buy_price > 0 && sell_price > 0) {
break
}
}
return [buy_price, sell_price]
}
Hier übernehmen wir noch die alte Idee und iterieren die Tiefe auf den erforderlichen Betrag. Hier gehen wir davon aus, dass eine Kauforder von 10 Münzen innerhalb von 1 Sekunde ausgeführt werden kann. Ohne Berücksichtigung neuer ausstehender Orders wird der Verkaufsorderpreis auf die Position gesetzt, an der die Kaufbestellung von 10 Münzen wird erfolgreich sein. Das konkrete Zeitfenster müssen Sie selbst festlegen.
let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time
Ratio steht für Fixed Ratio (Festgelegtes Verhältnis), was bedeutet, dass die Kaufauftragsmenge ein festes Verhältnis zur letzten Verkaufsauftragsmenge ist. Diese Strategie kann die Auftragsgröße basierend auf der aktuellen Kauf- und Verkaufsaktivität adaptiv anpassen.
if(bull && (sell_price-buy_price) > N * avg_diff) {
trade('buy', buy_price, buy_amount)
}else if(position.amount < 0){
trade('buy', buy_price, -position.amount)
}
if(bear && (sell_price-buy_price) > N * avg_diff) {
trade('sell', sell_price, sell_amount)
}else if(position.amount > 0){
trade('sell', sell_price, position.amount)
}
Unter ihnen ist avg_diff die Differenz des durchschnittlichen Marktpreises. Eine Kauforder wird nur dann platziert, wenn die Geld-Brief-Spanne größer als ein bestimmtes Vielfaches dieses Wertes ist und der Trend bullisch ist. Wenn Sie eine Short-Order halten, wird die Position wird zu diesem Zeitpunkt ebenfalls geschlossen, um eine langfristige Zurückhaltung der Bestellung zu vermeiden. Sie können eine Only-Maker-Order erteilen, um sicherzustellen, dass die ausstehende Order ausgeführt wird. Und Sie können die benutzerdefinierte Bestell-ID von Binance verwenden, sodass Sie nicht auf die Rücksendung der Bestellung warten müssen.
var tasks = []
var jobs = []
function worker(){
let new_jobs = []
for(let i=0; i<tasks.length; i++){
let task = tasks[i]
jobs.push(exchange.Go.apply(this, task.param))
}
_.each(jobs, function(t){
let ret = t.wait(-1)
if(ret === undefined){
new_jobs.push(t)//未返回的任务下次继续等待
}
})
jobs = new_jobs
tasks = []
}
/*
需要的任务参数写在param里
tasks.push({'type':'order','param': ["IO", "api", "POST","/fapi/v1/order",
"symbol="+symbol+Quote+"&side="+side+"&type=LIMIT&timeInForce=GTX&quantity="+
amount+"&price="+price+"&newClientOrderId=" + UUID() +"×tamp="+Date.now()]})
*/