Stratégie de négociation à haute fréquence sur les contrats à terme sur matières premières écrite en C++

Auteur:La bonté, Créé: 2020-05-22 15:28:11, Mis à jour: 2023-11-02 19:54:28

img

Penny Jump Commodity Futures High Frequency Trading Strategy écrit par C++

Résumé

Le marché est le champ de bataille, l'acheteur et le vendeur sont toujours dans le jeu, ce qui est également le thème éternel de l'entreprise de trading.

Classification de la stratégie de haute fréquence

Dans le trading à haute fréquence, il existe deux principaux types de stratégies. La stratégie côté acheteur et la stratégie côté vendeur. La stratégie côté vendeur est généralement une stratégie de création de marché, et les deux côtés de ces stratégies sont opposés. Par exemple, la stratégie acheteur arbitrage à haute fréquence pour lisser tous les phénomènes déraisonnables sur le marché à la vitesse la plus rapide, en prenant l'initiative d'attaquer le prix rapidement, ou en mangeant le mauvais prix d'autres fabricants de marché.

Il existe également un moyen d'analyser les données historiques ou les règles d'ordre du marché, d'envoyer les ordres en attente à un prix déraisonnable à l'avance et d'envoyer les ordres de retrait avec le changement rapide du prix du marché.

Quelle est la stratégie de Penny Jump?

Penny Jump signifie "augmentation de micro-prix". Le principe est de suivre le prix d'achat et le prix de vente du marché. Ensuite, selon le prix du marché, plus ou moins l'augmentation de micro-prix du prix de suivi, il est évident que c'est une stratégie de trading passive, elle appartient à la stratégie de prise de marché côté vendeur. Son modèle commercial et sa logique sont de mener des transactions bilatérales sur des ordres de limite cotés en bourse pour fournir de la liquidité.

La stratégie de création de marché nécessite une certaine quantité d'inventaire à la main, puis négocie à la fois du côté de l'acheteur et du vendeur. Le principal revenu de cette stratégie est le rendement des frais de commission fournis par l'échange, ainsi que la différence de prix gagnée en achetant bas et en vendant haut.

Principe de la stratégie Penny Jump

Nous savons qu'il y a beaucoup d'investisseurs de détail sur le marché de négociation, et il y a aussi beaucoup de grands investisseurs, tels que: hot money, fonds publics, fonds privés, etc. Les investisseurs de détail ont généralement moins de fonds, leurs ordres ont un impact très faible sur le marché, ils peuvent facilement acheter et vendre une cible de négociation à tout moment. Mais pour les grands fonds de participer au marché, ce n'est pas si simple.

Si un grand investisseur veut acheter 500 lots de pétrole brut, il n'y a pas autant d'ordres au prix actuel pour vendre, et l'investisseur ne veut pas les acheter au prix plus élevé. s'ils insistent pour envoyer l'ordre d'achat au prix actuel, le coût des points de glissement sera trop élevé. par conséquent, il doit envoyer un ordre en attente au prix souhaité. tous les participants au marché verront un ordre d'achat hugh affichant sur le certain prix.

En raison de cette énorme commande, il semble maladroit sur le marché, parfois nous l'appelons ordres éléphant.

Selling Price 400.3, Order volume 50; buying price 400.1, Order volume 10. 

Soudain, cet éléphant encombrant saute sur le marché, et le prix de l'offre a été envoyé au prix de 400.1.

Selling Price 400.3, Order volume 50; Buying price 400.1, Order volume 510.

Les traders savent tous que s'il y a une énorme quantité d'ordres en attente à un certain prix, alors ce prix va former un fort support ((ou résistance).

Selling Price 400.3, Order volume 50; Buying price 400.2, Order volume 1,

le prix 400.1 devient Price d'achat 2 dans la profondeur du carnet d'ordres.

Même si le prix n'augmente pas, dans la position d'achat de 2, il y a toujours un éléphant qui détient le prix, et il peut être rapidement revendu à l'éléphant au prix de 400.1. C'est l'idée générale de la stratégie de Penny Jump. Sa logique est aussi simple que cela, en surveillant l'état de l'ordre de marché, pour spéculer sur les intentions de l'adversaire, puis prendre l'initiative de construire une position favorable, et finalement profiter d'un petit spread dans un court laps de temps.

Mise en œuvre de la stratégie Penny Jump

Tout d'abord, observez les opportunités de trading avec une très faible probabilité du marché, et faites des stratégies correspondantes selon la logique de trading. Si la logique est complexe, vous devez utiliser les connaissances mathématiques existantes, utiliser le modèle pour décrire la nature du phénomène irrationnel autant que possible, et minimiser le surajustement. En outre, il doit être vérifié par un moteur de backtest qui peut répondre au principe Price first then Volume first. Heureusement, nous avons la plateforme FMZ Quant qui prend actuellement en charge ce mode de backtesting.

Qu'est-ce que cela signifie de prendre en charge le moteur de backtest Price first then Volume first? Vous pouvez le comprendre comme ceci: vous envoyez un ordre en attente à 400.1 pour acheter, seulement lorsque le prix de vente dans la profondeur du carnet de commandes est 400.1 ou inférieur, votre ordre en attente peut être fermé. Il ne calcule que les données de prix des ordres en attente, et ne calcule pas les données de volume des ordres en attente, qui ne répond qu'à la priorité de prix ((prix first) dans les règles de correspondance des ordres d'échange.

Le volume first est une version améliorée du prix first. Il s'agit à la fois d'un prix prioritaire et d'un temps prioritaire. On peut dire que ce mode de correspondance est exactement le même que le modèle d'échange. En calculant le montant de l'ordre en attente, on juge si l'ordre en attente actuel atteint la condition de transaction passive pour réaliser la transaction en volume, afin d'obtenir une simulation réelle de l'environnement réel du marché.

En outre, certains lecteurs peuvent constater que la stratégie Penny Jump nécessite des opportunités de trading sur le marché, c'est-à-dire que le besoin du marché a au moins deux écarts de prix hop. Dans des circonstances normales, le contrat de trading principal des contrats à terme sur matières premières est relativement busy. La différence entre Buy 1 et Sell 1 hop est qu'il n'y a presque aucune chance de trading. Nous mettons donc notre énergie sur le contrat sous-primaire où le trading n'est pas trop actif. Ce type de contrat de trading a parfois deux ou même trois opportunités de hop. Par exemple, dans le contrat MA (code Methanol dans les contrats à terme sur matières premières chinois) 1909, la situation suivante se produit:

img

Vendre 1 prix 2225 avec volume 551, Acheter 1 prix 2223 avec volume 565, regarder vers le bas pendant quelques secondes. Après cela, il disparaîtra après plusieurs tiques. Dans ce cas, nous considérons le marché comme une auto-correction. Ce que nous devons faire est de rattraper. Avant que le marché ne le corrige activement. si nous le faisons manuellement, ce serait impossible, avec l'aide du trading automatique, nous pouvons le rendre possible.

La situation de l'apparition de l'écart de prix entre les deux hop se produit très souvent, mais les trois sauts sont les plus sûrs, mais les trois sauts se produisent rarement, ce qui entraîne une fréquence de négociation trop faible.

Ensuite, nous observons la différence entre le Vente 1 Achat 1 et le Achat 1 Vente 1 maintenant. Afin de combler l'écart de prix entre le marché, si la vitesse est assez rapide, il peut être placé à l'avant-garde des autres ordres. En outre, le temps de détention de la position est très court, avec cette logique de négociation, après la réalisation de la stratégie, prenons le MA909 à titre d'exemple, le test de marché réel recommande Esunny au lieu de l'interface CTP, le mécanisme de changement de position et de situation de fonds pour Esunny est par données poussées, très adapté au trading à haute fréquence.

Code de stratégie

Après avoir dégagé la logique de négociation, nous pouvons utiliser le code pour y parvenir. Puisque la plateforme FMZ Quant utilise C ++ exemples de stratégie d'écriture sont trop peu, ici nous utilisons C ++ pour écrire cette stratégie, ce qui est pratique pour tout le monde à apprendre, et la variété est des contrats à terme sur matières premières.fmz.com> Connexion > Tableau de bord > bibliothèque de stratégie > Nouvelle stratégie > Cliquez sur le menu déroulant dans le coin supérieur gauche > Sélectionnez C++ pour commencer à écrire la stratégie, faites attention aux commentaires dans le code ci-dessous.

  • Première étape: construire le cadre de la stratégie, dans lequel une classe HFT et une fonction principale sont définies. La première ligne de la fonction principale consiste à effacer le journal. Le but de cela est d'effacer les informations du journal précédemment exécutées à chaque fois que la stratégie est redémarrée. La deuxième ligne consiste à filtrer certains messages d'erreur qui ne sont pas nécessaires, tels que le délai de réseau et certains conseils apparaissent, de sorte que le journal enregistre uniquement des informations importantes et semble plus propre; la troisième ligne consiste à imprimer le message Init OK, ce qui signifie que le programme a commencé à démarrer. La quatrième ligne consiste à créer un objet selon la classe HFT, et le nom de l'objet est hft; la cinquième ligne du programme entre dans la boucle while, et exécute toujours la boucle dans la méthode hft, on peut voir que la méthode Loop est la logique de ce programme.

Ensuite, examinons la classe HFT, qui a cinq méthodes. La première méthode est la méthode de construction; la deuxième méthode consiste à obtenir le jour actuel de la semaine pour déterminer s'il s'agit d'une nouvelle ligne K; la troisième méthode consiste principalement à annuler tous les ordres non remplis et à obtenir des informations détaillées sur la position, car avant que l'ordre ne soit passé, il doit d'abord déterminer l'état de la position actuelle; la quatrième méthode est principalement utilisée pour imprimer certaines informations, pour cette stratégie, cette méthode n'est pas la principale; la cinquième méthode est la plus importante.

/ / Define the HFT class
Class HFT {
     Public:
         HFT() {
             // Constructor
         }
        
         Int getTradingWeekDay() {
             // Get the current day of the week to determine if it is a new K line
         }
        
         State getState() {
             / / Get order data
         }

         Void stop() {
             // Print orders and positions
         }
        
         Bool Loop() {
             // Strategy logic and placing orders
         }
};

// main function
Void main() {
     LogReset(); // clear the log
     SetErrorFilter("ready|timeout"); // Filter error messages
     Log("Init OK"); // Print the log
     HFT hft; // Create HFT object
     While (hft.Loop()); // enter loop
     Log("Exit"); // Program exits, prints the log
}

Donc, voyons comment chacune des méthodes de cette classe HFT est implémentée, et comment fonctionne la méthode Loop la plus fondamentale. De haut en bas, nous allons implémenter l'implémentation spécifique de chaque méthode une par une, et vous constaterez que la stratégie de haute fréquence originale est si simple. Avant de parler de la classe HFT, nous avons d'abord défini plusieurs variables globales pour stocker les résultats du calcul de l'objet hft. Elles sont: stockage de l'état de l'ordre, l'état de la position, la tenue de la position longue, la tenue de la position courte, le prix d'achat, la quantité d'achat, le prix de vente, la quantité de vente. Veuillez consulter le code ci-dessous:

/ / Define the global enumeration type State
Enum State {
     STATE_NA, // store order status
     STATE_IDLE, // store position status
     STATE_HOLD_LONG, // store long position directions
     STATE_HOLD_SHORT, // store short position direction
};

/ / Define global floating point type variable
Typedef struct {
     Double bidPrice; // store the buying price
     Double bidAmount; // store the buying amount
     Double askPrice; // store the selling price
     Double askAmount; // store the selling amount
} Book;

Avec les variables globales ci-dessus, nous pouvons stocker les résultats calculés par l'objet hft séparément, ce qui est pratique pour les appels ultérieurs par le programme. Ensuite, nous parlerons de la mise en œuvre spécifique de chaque méthode dans la classe HFT. Premièrement, la première méthode HFT est un constructeur qui appelle la deuxième méthode getTradingWeekDay et imprime le résultat sur le journal. La deuxième méthode getTradingWeekDay obtient le jour actuel de la semaine pour déterminer si c'est une nouvelle ligne K. Elle est également très simple à mettre en œuvre, obtenir l'horodatage, calculer l'heure et la semaine, et enfin retourner le nombre de semaines; la troisième méthode getState est un peu longue, je vais juste décrire l'idée générale, pour une explication spécifique, vous pouvez regarder les commentaires dans le bloc de codage suivant.

Ensuite, obtenons d'abord tous les ordres, renvoyons le résultat est un tableau normal, puis traversons ce tableau, un par un pour annuler l'ordre, puis obtenons les données de position, renvoyons un tableau, puis traversons ce tableau, obtenons des informations de position détaillées, y compris: direction, position, position d'hier ou actuelle, etc., et finalement renvoyons le résultat; la quatrième méthode d'arrêt est d'imprimer des informations; le code est le suivant:

Public:
    // Constructor
    HFT() {
        _tradingDay = getTradingWeekDay();
        Log("current trading weekday", _tradingDay);
    }
    
    // Get the current day of the week to determine if it is a new K line
    Int getTradingWeekDay() {
        Int seconds = Unix() + 28800; // get the timestamp
        Int hour = (seconds/3600)%24; // hour
        Int weekDay = (seconds/(60*60*24))%7+4; // week
        If (hour > 20) {
            weekDay += 1;
        }
        Return weekDay;
    }
    
    / / Get order data
    State getState() {
        Auto orders = exchange.GetOrders(); // Get all orders
        If (!orders.Valid || orders.size() == 2) { // If there is no order or the length of the order data is equal to 2
            Return STATE_NA;
        }
        
        Bool foundCover = false; // Temporary variable used to control the cancellation of all unexecuted orders
        // Traverse the order array and cancel all unexecuted orders
        For (auto &order : orders) {
            If (order.Id == _coverId) {
                If ((order.Type == ORDER_TYPE_BUY && order.Price < _book.bidPrice - _toleratePrice) ||
                    (order.Type == ORDER_TYPE_SELL && order.Price > _book.askPrice + _toleratePrice)) {
                    exchange.CancelOrder(order.Id, "Cancel Cover Order"); // Cancel order based on order ID
                    _countCancel++;
                    _countRetry++;
                } else {
                    foundCover = true;
                }
            } else {
                exchange.CancelOrder(order.Id); // Cancel order based on order ID
                _countCancel++;
            }
        }
        If (foundCover) {
            Return STATE_NA;
        }
        
        // Get position data
        Auto positions = exchange.GetPosition(); // Get position data
        If (!positions.Valid) { // if the position data is empty
            Return STATE_NA;
        }

        // Traverse the position array to get specific position information
        For (auto &pos : positions) {
            If (pos.ContractType == Symbol) {
                _holdPrice = pos.Price;
                _holdAmount = pos.Amount;
                _holdType = pos.Type;
                Return pos.Type == PD_LONG || pos.Type == PD_LONG_YD ? STATE_HOLD_LONG : STATE_HOLD_SHORT;
            }
        }
        Return STATE_IDLE;
    }
    
    // Print orders and positions information
    Void stop() {
        Log(exchange.GetOrders()); // print order
        Log(exchange.GetPosition()); // Print position
        Log("Stop");
    }

Enfin, nous nous concentrons sur la façon dont la fonction Loop contrôle la logique de la stratégie et l'ordre. Si vous voulez voir plus attentivement, vous pouvez consulter les commentaires dans le code. Déterminez d'abord si la transaction CTP et le serveur de marché sont connectés; puis obtenez le solde disponible du compte et obtenez le nombre de semaines; puis définissez le code de variété à échanger, en appelant la fonction officielle SetContractType de FMZ Quant, et pouvez utiliser cette fonction pour retourner les détails de la variété de trading; puis appelez la fonction GetDepth pour obtenir les données de profondeur du marché actuel. Les données de profondeur comprennent: prix d'achat, volume d'achat, prix de vente, volume de vente, etc., et nous les stockons avec des variables, car elles seront utilisées plus tard; Ensuite, sortez ces données vers la barre d'état pour faciliter à l'utilisateur de voir l'état actuel du marché; le code est le suivant:

// Strategy logic and placing order
Bool Loop() {
    If (exchange.IO("status") == 0) { // If the CTP and the quote server are connected
        LogStatus(_D(), "Server not connect ...."); // Print information to the status bar
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    
    If (_initBalance == 0) {
        _initBalance = _C(exchange.GetAccount).Balance; // Get account balance
    }
    
    Auto day = getTradingWeekDay(); // Get the number of weeks
    If (day != _tradingDay) {
        _tradingDay = day;
        _countCancel = 0;
    }
    
    // Set the futures contract type and get the contract specific information
    If (_ct.is_null()) {
        Log(_D(), "subscribe", Symbol); // Print the log
        _ct = exchange.SetContractType(Symbol); // Set futures contract type
        If (!_ct.is_null()) {
            Auto obj = _ct["Commodity"]["CommodityTickSize"];
            Int volumeMultiple = 1;
            If (obj.is_null()) { // CTP
                Obj = _ct["PriceTick"];
                volumeMultiple = _ct["VolumeMultiple"];
                _exchangeId = _ct["ExchangeID"];
            } else { // Esunny
                volumeMultiple = _ct["Commodity"]["ContractSize"];
                _exchangeId = _ct["Commodity"]["ExchangeNo"];
            }
            If (obj.is_null() || obj <= 0) {
                Panic("PriceTick not found");
            }
            If (_priceTick < 1) {
                exchange.SetPrecision(1, 0); // Set the decimal precision of the price and the quantity of the order.
            }
            _priceTick = double(obj);
            _toleratePrice = _priceTick * TolerateTick;
            _ins = _ct["InstrumentID"];
            Log(_ins, _exchangeId, "PriceTick:", _priceTick, "VolumeMultiple:", volumeMultiple); // print the log
        }
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    
    // Check orders and positions to set status
    Auto depth = exchange.GetDepth(); // Get depth data
    If (!depth.Valid) { // if no depth data is obtained
        LogStatus(_D(), "Market not ready"); // Print status information
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    _countTick++;
    _preBook = _book;
    _book.bidPrice = depth.Bids[0].Price; // "Buying 1" price
    _book.bidAmount = depth.Bids[0].Amount; // "Buying 1" amount
    _book.askPrice = depth.Asks[0].Price; // "Selling 1" price
    _book.askAmount = depth.Asks[0].Amount; // "Selling 1" amount
    // Determine the state of the port data assignment
    If (_preBook.bidAmount == 0) {
        Return true;
    }
    Auto st = getState(); // get the order data
    
    // Print the port data to the status bar
    LogStatus(_D(), _ins, "State:", st,
                "Ask:", depth.Asks[0].Price, depth.Asks[0].Amount,
                "Bid:", depth.Bids[0].Price, depth.Bids[0].Amount,
                "Cancel:", _countCancel,
                "Tick:", _countTick);
}

Après avoir fait tant, nous pouvons enfin placer des ordres. Avant le trading, nous jugeons d'abord l'état actuel de la position de détention du programme (pas de position de détention, des ordres de position longue, des ordres de position courte), ici nous avons utilisé le contrôle logique if...else if...else if. Ils sont très simples, s'il n'y a pas de position de détention, la position sera ouverte selon la condition logique. s'il y a une position de détention, la position sera fermée selon la condition logique. Afin de faciliter la compréhension de tout le monde, nous utilisons trois paragraphes pour expliquer la logique, pour la partie de position d'ouverture:

Tout d'abord, nous déclarons une variable booléenne, nous l'utilisons pour contrôler la position de clôture; ensuite, nous devons obtenir les informations du compte courant, et enregistrer la valeur du profit, puis déterminer l'état de l'ordre de retrait, si le nombre de retraits dépasse le maximum défini, imprimer les informations connexes dans le journal; puis calculer la valeur absolue de la différence de prix d'offre et d'offre actuelle pour déterminer s'il y a plus de 2 sauts entre le prix d'offre actuel et le prix de demande.

Ensuite, nous obtenons le prix d'achat 1 et le prix de vente 1, si le prix d'achat précédent est supérieur au prix d'achat actuel et que le volume de vente actuel est inférieur au volume d'achat, cela signifie que le prix d'achat 1 a disparu. le prix d'ouverture de la position longue et la quantité d'ordre sont définis; sinon, si le prix de vente précédent est inférieur au prix de vente actuel et le volume d'achat actuel est inférieur au volume de vente prouve que le prix de vente 1 a disparu, le prix d'ouverture de la position courte et la quantité d'ordre sont définis; à la fin, la position longue et les ordres courts entrent sur le marché en même temps.

Bool forceCover = _countRetry >= _retryMax; // Boolean value used to control the number of closings
If (st == STATE_IDLE) { // if there is no holding position
    If (_holdAmount > 0) {
        If (_countRetry > 0) {
            _countLoss++; // failure count
        } else {
            _countWin++; // success count
        }
        Auto account = exchange.GetAccount(); // Get account information
        If (account.Valid) { // If get account information
            LogProfit(_N(account.Balance+account.FrozenBalance-_initBalance, 2), "Win:", _countWin, "Loss:", _countLoss); // Record profit value
        }
    }
    _countRetry = 0;
    _holdAmount = 0;
    
    // Judging the status of withdrawal
    If (_countCancel > _cancelMax) {
        Log("Cancel Exceed", _countCancel); // Print the log
        Return false;
    }

    Bool canDo = false; // temporary variable
    If (abs(_book.bidPrice - _book.askPrice) > _priceTick * 1) { // If there is more than 2 hops between the current bid and ask price
        canDo = true;
    }
    If (!canDo) {
        Return true;
    }
    
    Auto bidPrice = depth.Bids[0].Price; // Buying 1 price
    Auto askPrice = depth.Asks[0].Price; // Selling 1 price
    Auto bidAmount = 1.0;
    Auto askAmount = 1.0;
    
    If (_preBook.bidPrice > _book.bidPrice && _book.askAmount < _book.bidAmount) { // If the previous buying price is greater than the current buying price and the current selling volume is less than the buying volume
        bidPrice += _priceTick; // Set the opening long position price
        bidAmount = 2; // set the opening long position volume
    } else if (_preBook.askPrice < _book.askPrice && _book.bidAmount < _book.askAmount) { // If the previous selling price is less than the current selling price and the current buying volume is less than the selling volume
        askPrice -= _priceTick; // set the opening short position volume
        askAmount = 2; // set the opening short position volume
    } else {
        Return true;
    }
    Log(_book.bidPrice, _book.bidAmount, _book.askPrice, _book.askAmount); // Print current market data
    exchange.SetDirection("buy"); // Set the order type to buying long
    exchange.Buy(bidPrice, bidAmount); // buying long and open position
    exchange.SetDirection("sell"); // Set the order type to selling short
    exchange.Sell(askPrice, askAmount); // short sell and open position
}

Ensuite, nous parlerons de la façon de fermer une position longue, en définissant d'abord le type d'ordre en fonction de l'état de la position actuelle, puis en obtenant le prix de Vente 1 . Si le prix de vente 1 actuel est supérieur au prix d'ouverture de l'achat, définissez le prix de fermeture de la position longue. Si le prix de vente 1 actuel est inférieur au prix d'ouverture de la position longue, réinitialisez la variable de quantité de fermeture à vrai, puis fermez toute la position longue.

Else if (st == STATE_HOLD_LONG) { // if holding long position
     exchange.SetDirection((_holdType == PD_LONG && _exchangeId == "SHFE") ? "closebuy_today" : "closebuy"); // Set the order type, and close position
     Auto sellPrice = depth.Asks[0].Price; // Get "Selling 1" price
     If (sellPrice > _holdPrice) { // If the current "selling 1" price is greater than the long position opening price
         Log(_holdPrice, "Hit #ff0000"); // Print long position opening price 
         sellPrice = _holdPrice + ProfitTick; // Set closing long position price
     } else if (sellPrice < _holdPrice) { // If the current "selling 1" price is less than the long position opening price
         forceCover = true;
     }
     If (forceCover) {
         Log("StopLoss");
     }
     _coverId = exchange.Sell(forceCover ? depth.Bids[0].Price : sellPrice, _holdAmount); // close long position
     If (!_coverId.Valid) {
         Return false;
     }
}

Enfin, voyons comment fermer une position courte. Le principe est l'opposé de la position longue de clôture mentionnée ci-dessus. Tout d'abord, selon l'état de la position actuelle, définissez le type d'ordre, puis obtenez le prix d'achat 1, si le prix d'achat 1 actuel est inférieur au prix d'ouverture de la position courte, le prix de la position courte de clôture sera fixé. Si le prix d'achat 1 actuel est supérieur au prix de la position courte d'ouverture, réinitialisez la variable de quantité de clôture à vrai, puis fermez toutes les positions courtes.

Else if (st == STATE_HOLD_SHORT) { // if holding short position
     exchange.SetDirection((_holdType == PD_SHORT && _exchangeId == "SHFE") ? "closesell_today" : "closesell"); // Set the order type, and close position
     Auto buyPrice = depth.Bids[0].Price; // Get "buying 1" price
     If (buyPrice < _holdPrice) { // If the current "buying 1" price is less than the opening short position price
         Log(_holdPrice, "Hit #ff0000"); // Print the log
         buyPrice = _holdPrice - ProfitTick; // Set the close short position price
     } else if (buyPrice > _holdPrice) { // If the current "buying 1" price is greater than the opening short position price
         forceCover = true;
     }
     If (forceCover) {
         Log("StopLoss");
     }
     _coverId = exchange.Buy(forceCover ? depth.Asks[0].Price : buyPrice, _holdAmount); // close short position
     If (!_coverId.Valid) {
         Return false;
     }
}

Ce qui précède est une analyse complète de cette stratégie.https://www.fmz.com/strategy/163427) pour copier le code source de la stratégie complète sans configurer l'environnement de backtest sur FMZ Quant.

Résultats des tests antérieurs

img

Logique de négociation

img

Déclaration de stratégie

Afin de satisfaire la curiosité du trading à haute fréquence et de voir les résultats plus clairement, ce coût de transaction de l'environnement de backtest de stratégie est défini à 0, ce qui conduit à une logique simple de vitesse rapide. si vous voulez couvrir le coût de transaction pour atteindre la rentabilité sur le marché réel. Plus d'optimisation est nécessaire. Par exemple, en utilisant le flux de commandes pour effectuer des prévisions à court terme pour améliorer le taux de gain, plus le remboursement des frais de change, Afin d'atteindre une stratégie rentable durable, il existe de nombreux livres sur le trading à haute fréquence. J'espère que tout le monde peut réfléchir davantage et aller sur le marché réel au lieu de simplement rester sur le principe.

À propos de nous

FMZ Quant est une équipe purement axée sur la technologie qui fournit un mécanisme de backtest disponible très efficace pour les amateurs de trading quantitatif.


Relationnée

Plus de