
[TOC] J’ai écrit un article en 2020 présentant les stratégies à haute fréquence, https://www.fmz.com/digest-topic/6228. Bien qu’il ait reçu beaucoup d’attention, il n’a pas été écrit en profondeur. Plus de deux ans se sont écoulés et le marché a changé. Après la publication de cet article, ma stratégie à haute fréquence a pu générer des revenus réguliers pendant une longue période, mais les bénéfices ont progressivement diminué et ont même été stoppés à un moment donné. Ces derniers mois, j’ai consacré beaucoup d’efforts à la rénovation et je suis actuellement en mesure de gagner un peu d’argent. Cet article présentera plus en détail mes idées sur les stratégies à haute fréquence et certains codes simplifiés, qui peuvent servir de point de départ à la discussion. Tout le monde est invité à communiquer et à donner son avis.
Pour les comptes qui reçoivent des remises, en prenant Binance comme exemple, la remise actuelle du fabricant est de 0,5 % de 100 000. Si le volume de transactions quotidien est de 100 millions d’U, la remise sera de 5 000 U. Bien entendu, les frais de prise de commande sont toujours basés sur le taux VIP, donc si la stratégie ne nécessite pas de prise d’ordres, le niveau VIP aura peu d’impact sur les stratégies à haute fréquence. En général, les différents niveaux d’échanges ont des taux de remise différents et nécessitent le maintien d’un volume de transactions plus élevé. Il y a longtemps, lorsque le marché de certaines devises fluctuait fortement, il y avait encore des bénéfices même sans rabais. Avec l’intensification de la circulation interne, les rabais ont représenté une grande partie des bénéfices, et reposaient même entièrement sur les rabais. Les meilleurs tarifs.
vitesse. La raison pour laquelle la stratégie à haute fréquence est appelée haute fréquence est qu’elle est très rapide. Rejoindre le serveur colo de l’échange pour obtenir la latence la plus faible et la connexion la plus stable est également devenu l’une des conditions de circulation interne. La consommation de temps interne de la stratégie doit également être aussi faible que possible. Cet article présentera le framework websocket que j’utilise, qui utilise l’exécution simultanée.
Le bon marché. Le trading haute fréquence est connu comme le joyau du trading quantitatif. Je pense que de nombreux traders programmatiques l’ont essayé, mais la plupart des gens arrêtent probablement parce qu’ils ne gagnent pas d’argent et ne trouvent pas de moyen de s’améliorer. La raison principale est probablement qu’ils cherchent la mauvaise voie. Le marché commercial. Au stade initial d’une stratégie, il convient de rechercher des marchés relativement faciles sur lesquels gagner de l’argent en négociant, afin de générer des bénéfices et des retours sur les améliorations, qui seront propices à l’avancement de la stratégie. Si vous démarrez sur le marché le plus compétitif, en concurrence avec de nombreux rivaux potentiels, vous perdrez de l’argent, quels que soient vos efforts, et vous ne pourrez plus tenir le coup. Je recommande les paires de contrats perpétuels nouvellement cotées. À l’heure actuelle, il n’y a pas beaucoup de concurrents, surtout lorsque le volume des échanges est relativement important. Il est plus facile de gagner de l’argent à ce moment-là. BTC et ETH ont le plus grand volume d’échanges et les transactions les plus actives, mais ils sont également les plus difficiles à survivre.
Affrontez la concurrence de front. Tout marché de trading évolue de manière dynamique. Aucune stratégie de trading ne peut durer éternellement. Cela est encore plus évident dans le trading à haute fréquence. Entrer sur ce marché signifie entrer en compétition directe avec un groupe de traders les plus intelligents et les plus diligents. Dans un marché à somme nulle, plus vous gagnez, moins les autres gagnent. Plus tard vous entrerez sur le marché, plus ce sera difficile. Ceux qui sont déjà sur le marché doivent également continuer à s’améliorer car ils peuvent être éliminés à tout moment. Il y a trois ou quatre ans, la meilleure opportunité aurait dû se présenter. Récemment, l’activité globale du marché des devises numériques a diminué et il est désormais très difficile pour les novices de se lancer dans le trading à haute fréquence.
Il existe de nombreux types de stratégies à haute fréquence
Ma stratégie est une combinaison de tendance et de teneur de marché. Je détermine d’abord la tendance, puis je passe un ordre et je passe immédiatement un ordre de vente une fois la transaction terminée. Je ne détiens pas de positions en stock. Le code de la stratégie est présenté ci-dessous.
Le code suivant est basé sur l’architecture de base des contrats perpétuels Binance et s’abonne principalement aux flux d’ordres de profondeur WebSocket, aux informations de marché et aux informations de position. Les informations de marché et les informations de compte étant souscrites séparément, il est nécessaire d’utiliser read(-1) en continu pour déterminer si les informations les plus récentes sont obtenues. EventLoop(1000) est utilisé ici pour éviter une boucle infinie directe et réduire la charge du système. EventLoop(1000) sera bloqué jusqu’au retour de wss ou de tâches simultanées, avec un délai d’expiration de 1000 ms.
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)
}
}
Comme mentionné précédemment, ma stratégie à haute fréquence nécessite de déterminer la tendance avant d’exécuter des achats et des ventes. La tendance à court terme est principalement jugée sur la base des données de transaction de chaque transaction, c’est-à-dire aggTrade dans l’abonnement, qui comprend la direction de la transaction, le prix, la quantité, l’heure de la transaction, etc. Les principales références pour l’achat et la vente sont la profondeur et le volume des transactions. Voici une introduction détaillée aux indicateurs qui nécessitent une attention particulière. La plupart des indicateurs sont divisés en deux groupes : achat et vente, et sont comptés de manière dynamique dans une certaine fenêtre temporelle. La fenêtre temporelle de ma stratégie est de 10 secondes.
//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;
Si le dernier prix de vente est supérieur au prix de vente moyen, le dernier prix d’achat est supérieur au prix d’achat moyen et la valeur de l’ordre d’achat à intervalle fixe est supérieure à la valeur de l’ordre de vente, alors on juge qu’il s’agit d’une tendance haussière à court terme. . Au contraire, c’est baissier.
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]
}
Ici, nous adoptons toujours l’ancienne idée et itérons la profondeur jusqu’au montant requis. Ici, nous supposons qu’un ordre d’achat de 10 pièces peut être exécuté en 1 seconde. Sans tenir compte des nouveaux ordres en attente, le prix de l’ordre de vente est fixé à la position où le l’ordre d’achat de 10 pièces sera atteint. Vous devez définir vous-même la taille spécifique de la fenêtre temporelle.
let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time
Ratio signifie Fixed Ratio, ce qui signifie que la quantité de l’ordre d’achat est un ratio fixe de la quantité de l’ordre de vente le plus récent. Cette stratégie peut ajuster de manière adaptative la taille de la commande en fonction de l’activité d’achat et de vente actuelle.
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)
}
Parmi eux, avg_diff est la différence du prix moyen du marché. Un ordre d’achat ne sera placé que lorsque l’écart entre l’offre et la demande est supérieur à un certain multiple de cette valeur et que la tendance est haussière. Si vous détenez un ordre court, la position sera également fermé à ce moment-là pour éviter un maintien à long terme de la commande. Vous pouvez passer un ordre réservé au fabricant pour garantir que l’ordre en attente soit exécuté. Et vous pouvez utiliser l’ID de commande personnalisé de Binance, vous n’avez donc pas à attendre que la commande soit renvoyée.
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()]})
*/