Introduction aux stratégies détaillées de négociation à haute fréquence pour les crypto-monnaies

Auteur:Inventeur de la quantification, Créé: 2023-03-19 19:56:11, Mis à jour: 2023-09-18 19:55:58

img

J'ai écrit un article en 2020 présentant les stratégies de trading à haute fréquence (https://www.fmz.com/digest-topic/6228Bien qu'il ait reçu une certaine attention, il n'a pas été très en profondeur. Deux ans et demi se sont écoulés depuis lors, et le marché a changé. Après avoir publié cet article, ma stratégie à haute fréquence a pu générer des profits stables pendant longtemps, mais les profits ont progressivement diminué et même cessé à un moment donné.

Conditions de négociation à haute fréquence

Comptes de remboursement de la Commission

En utilisant Binance comme exemple, offrent actuellement un rabais de fabricant de 0,05% pour chaque 100 000 unités négociées. Si le volume de négociation quotidien est de 100 millions d'U, le rabais est de 5 000 U. Bien sûr, les frais de prise dépendent toujours du taux VIP, donc si la stratégie n'a pas besoin de prendre des ordres, le niveau VIP a peu d'effet sur la stratégie à haute fréquence. Différents niveaux de rabais de commission sont disponibles sur différents échanges, ce qui nécessite un volume de négociation élevé. Au début, il y avait encore des profits à réaliser sans rabais, mais à mesure que la concurrence s'intensifiait, les rabais représentaient une plus grande proportion des profits et les traders à haute fréquence poursuivaient les taux les plus élevés.

Vitesse

Le trading à haute fréquence est appelé ainsi en raison de sa vitesse rapide. Rejoindre le serveur de colocation d'une bourse de trading et obtenir la plus faible latence et la connexion la plus stable est devenu l'une des conditions de concurrence. Le temps de traitement interne de la stratégie doit également être le plus court possible. Cet article présentera le framework WebSocket que j'ai utilisé, qui utilise l'exécution simultanée.

Marché approprié

Le trading à haute fréquence est considéré comme le joyau de la couronne du trading quantitatif, et je crois que de nombreux traders algorithmiques l'ont essayé, mais la plupart des gens auraient dû s'arrêter parce qu'ils ne pouvaient pas gagner d'argent et ne pouvaient pas trouver un moyen de s'améliorer. La raison principale est probablement qu'ils ont choisi le mauvais marché de trading. Dans la phase initiale de la stratégie, les marchés relativement faciles devraient être ciblés pour le trading afin de réaliser des profits et recevoir des commentaires pour l'amélioration, ce qui favorise le progrès de la stratégie. Si vous débutez sur le marché le plus compétitif et que vous êtes en concurrence avec de nombreux adversaires, vous perdrez de l'argent peu importe combien vous essayez et vous abandonnerez rapidement. Je recommande de commencer par des paires de trading de contrats perpétuels nouvellement lancées, où il y a moins de concurrents, en particulier ceux avec des volumes de trading relativement importants, ce qui facilite le trading.

Faire face à la concurrence

Le marché pour tout trading est en constante évolution, et aucune stratégie de trading ne peut être une solution unique. Cela est encore plus évident dans le trading à haute fréquence, où entrer sur le marché signifie rivaliser directement avec les traders les plus intelligents et les plus diligents. Dans un marché de jeu à somme nulle, plus vous gagnez, moins les autres gagnent. Plus vous entrez tard, plus cela devient difficile, et ceux qui sont déjà sur le marché doivent constamment s'améliorer et pourraient être éliminés à tout moment. Il y a trois ou quatre ans, c'était probablement la meilleure opportunité, mais avec le récent déclin de l'activité sur le marché de la monnaie numérique, il est devenu très difficile pour les débutants de commencer à faire du trading à haute fréquence.

Principes de négociation à haute fréquence

Il existe plusieurs stratégies de négociation à haute fréquence, telles que l'arbitrage à haute fréquence, qui consiste à trouver des opportunités d'arbitrage par le biais de ce ou d'autres échanges, en saisissant l'occasion de manger des ordres avant les autres et de réaliser des bénéfices avec un avantage de vitesse; le trading de tendance à haute fréquence, qui consiste à tirer profit des tendances à court terme; et la création de marché, qui consiste à placer des ordres des deux côtés des transactions d'achat et de vente, à bien contrôler les positions et à réaliser des bénéfices grâce à des rabais de commission. Ma stratégie combine la tendance et la création de marché, en identifiant d'abord les tendances puis en plaçant des ordres, en vendant immédiatement après l'exécution et en ne détenant pas de positions d'inventaire.

L'architecture stratégique

Le code suivant est basé sur l'architecture de base du contrat perpétuel Binance et souscrit principalement aux transactions de flux d'ordres de profondeur de websocket et aux informations de position. Puisque les données de marché et les informations de compte sont souscrites séparément, la lecture (-1) doit être utilisée en continu pour déterminer si les dernières informations ont été obtenues. Ici, EventLoop (1000) est utilisé pour éviter les boucles mortes directes et réduire la charge du système. EventLoop (1000) bloque jusqu'à ce qu'il y ait un retour de tâche wss ou simultanée, avec un temps d'arrêt 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()
    }
    // need 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 is the pair of symbol
    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)
    }
}

Indicateurs de stratégie

Comme mentionné précédemment, ma stratégie à haute fréquence nécessite d'identifier d'abord les tendances avant d'exécuter des transactions d'achat et de vente. Le jugement des tendances à court terme est principalement basé sur les données de transaction, c'est-à-dire l'aggTrade souscrit, qui comprend la direction, le prix, la quantité et le temps de transaction. Les transactions d'achat et de vente se réfèrent principalement à la profondeur et au volume des transactions. Voici des indicateurs détaillés à prendre en compte, dont la plupart sont divisés en deux groupes pour l'achat et la vente et sont dynamiquement comptés dans une certaine fenêtre de temps.

  • Volume moyen de négociation par transaction, qui est la collection de transactions dans le même sens, prix et différents ordres dans un délai de 100 ms. Cela reflète la taille des ordres d'achat et de vente et a un poids élevé. Si le volume de négociation des ordres d'achat est supérieur à celui des ordres de vente, on peut supposer que le marché est dominé par les acheteurs.
  • La fréquence moyenne des commandes ou l'intervalle des commandes, également basé sur les données de transaction, le volume de transaction moyen précédent n'a pas pris en compte le concept de temps et n'est pas tout à fait précis. Si un ordre dans une direction a un petit volume de transaction moyen mais une fréquence élevée, il contribue également à la force de ce sens.
  • L'écart moyen, qui est la différence entre le prix de vente et le prix d'achat. L'écart actuel est généralement d'un tick, et si l'écart augmente, cela indique souvent qu'il y a une tendance. Les prix d'achat et de vente moyens, qui calculent respectivement le prix moyen des transactions d'achat et de vente et les comparent avec le dernier prix.

La logique de la stratégie

Jugez les tendances à court terme

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 d'achat est supérieur au prix d'achat moyen et que le dernier prix d'achat est supérieur au prix d'achat moyen et que la valeur de l'ordre d'achat est supérieure à la valeur de l'ordre de vente à un intervalle fixe, il s'agit d'un marché haussier à court terme.

Placement des commandes

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, l'ancienne méthode d'itération de la profondeur à la quantité requise est toujours utilisée. en supposant qu'un ordre d'achat qui peut être exécuté pour 10 pièces dans 1 seconde et sans tenir compte de la situation des nouveaux ordres, le prix de vente est fixé à la position où l'ordre d'achat

La taille de la fenêtre de temps spécifique doit être définie par soi-même.

Quantité de commande

let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time

Le ratio représente une proportion fixe de la quantité de la dernière commande de vente, représentant la quantité de l'ordre d'achat comme une proportion fixe de la quantité de la dernière commande de vente, ce qui permet à la stratégie d'ajuster la taille de la commande en fonction de l'activité d'achat et de vente en cours.

Conditions de commande

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, l'avg_diff est la différence moyenne de spread, et seulement lorsque la différence d'achat et de vente dans la passation des ordres est supérieure à un certain multiple de cette valeur et que le marché est haussier, un ordre d'achat sera passé.

L'architecture concomitante

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 = []
}

/*
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() +"&timestamp="+Date.now()]})
*/

Données surveillées

  • L'importance de la vitesse des stratégies de trading à haute fréquence a été soulignée. La stratégie doit surveiller et enregistrer diverses latences, telles que la passation d'ordres, l'annulation d'ordres, le retour de positions, la profondeur, le flux d'ordres, le cycle global, etc. Toute latence anormale doit être rapidement étudiée et des moyens de raccourcir la latence globale de la stratégie doivent être trouvés.
  • Les statistiques montrent la proportion du volume des transactions par rapport au volume total des transactions. Si la proportion est faible, il est encore possible de s'améliorer.
  • Taux de profit de clôture: les statistiques montrent le taux de profit de clôture moyen, qui est la référence la plus importante pour juger de l'efficacité de la stratégie.
  • Le ratio de remise: Les statistiques montrent la proportion de remises par rapport au chiffre d'affaires total, reflétant le degré de dépendance de la stratégie par rapport aux remises. Taux d'échec des ordres: Les ordres sont uniquement passés et remplis, mais en raison de retards dans la passation des ordres, ils peuvent ne pas être remplis.
  • Ratio d'exécution des ordres: la plateforme a souvent des exigences pour les ratios d'exécution des ordres. S'il est trop bas, cela indique que la stratégie annule trop souvent les ordres et doit être résolue. Distance moyenne des ordres d'achat et de vente: ces données reflètent la distance entre le placement des ordres de la stratégie et la profondeur du marché, et la plupart des ordres occupent encore les positions des ordres d'achat et de vente.

D'autres suggestions

  • Commercialisez plusieurs devises: La stratégie de haute fréquence dans cet article est limitée aux échanges uniques, aux paires de devises uniques et aux conditions du marché unique, et a une applicabilité limitée. La plupart des devises ne peuvent pas être rentables, mais il est impossible de prédire quelles devises seront rentables à l'avenir, il est donc recommandé de négocier plusieurs ou même toutes les devises pour ne pas manquer d'opportunités. Même sous les restrictions de fréquence de l'échange, un seul robot peut négocier plusieurs paires de transactions. Bien sûr, pour la meilleure vitesse, un sous-compte peut négocier une paire de transactions, un serveur correspond à un robot, mais cette approche aura des coûts beaucoup plus élevés.
  • Déterminez la taille et les conditions de l'ordre en fonction de la rentabilité. Le trading de plusieurs devises peut entraîner un coût trop élevé d'essayer, donc si la surveillance montre qu'il n'est pas rentable, réduisez la fréquence de trading et utilisez le volume de trading minimum jusqu'à ce que la stratégie détecte dynamiquement un taux de profit positif, puis augmentez progressivement le volume de trading pour améliorer la rentabilité.
  • Obtenez plus d'informations: Une autre caractéristique du trading à haute fréquence est qu'il gère plus de données et utilise plus d'informations. Toutes les données du marché pour un seul échange et une seule paire de devises doivent être prises en compte, et les données perpétuelles peuvent également faire référence aux données au comptant ou aux données pour la même paire de devises sur d'autres échanges ou même d'autres devises. Plus il y a de données, plus l'avantage correspondant est grand.

Relationnée

Plus de