Commodity Futures High Frequency Trading Strategy written by C++

Summary

The market is the battleground, the buyer and the seller are always in the game, which is also the eternal theme of the trading business. The Penny Jump strategy shared today is one of high-frequency strategies, originally derived from the interbank foreign exchange market, and is often used in mainstream fait currency pairs.

High frequency strategy classification

In high-frequency trading, there are two main types of strategies. The buyer side strategy and the seller side strategy. The seller side strategy is usually a market-making strategy, and the these two side of strategies are opponents. For example, the high-frequency arbitrage buyer strategy of smoothing all unreasonable phenomena in the market at the fastest speed, taking the initiative to attack price quickly, or eating the wrong price of other market makers.

There is also a way to analyze the historical data or the ordering rules of the market, to send the pending orders at an unreasonable price in advance, and to send the withdrawal orders with the rapid change of the market price. Such strategies are common in passive market making, once the pending orders are executed, And after a certain profit or after reaching the stop-loss condition, the position will be closed. Passive market-making strategies usually do not require too much speed, but it requires a strong strategy logic and structure.

What is the Penny Jump strategy?

Penny Jump translates into English is the meaning of micro-price increase. The principle is to track the buying price and the selling price of the market. Then, according to the price of the market, plus or minus the micro-price increase of the tracking price, it is obvious that this is a passive trading strategy, it is belong to the seller side market-making strategy. Its business model and logic are to conduct bilateral transactions on exchange-listed limit orders to provide liquidity.

The market-making strategy requires a certain amount of inventory in hand, and then trades both at the buyer and seller side. The main income of this strategy is the commission fee return provided by the exchange, as well as the price difference earned by buying low and selling high. But for many high-frequency traders who want to market making, earning a bid-ask spread is a good thing, but it is not an absolute means of profit.

Penny Jump strategy principle

We know that there are many retail investors in the trading market, and there are also many large investors, such as: “hot money”, public funds, private funds, and so on. Retail investors usually have less funds, their orders has very small impact in the market, they can easily buy and sell a trading target at any time. But for large funds to participate the market, it is not that simple.

If a large investor wants to buy 500 lots of crude oil, there are not so many orders at the current price for sell, and the investor don’t want to buy them at the higher price. If they insist on send the buying order at current price, The cost of slippage points will be too much. therefore, it has to send a pending order at the desired price. All the participants in the market will see a hugh buying order showing on the certain price.

Because of this huge order, it looks clumsy in the market, sometimes we call it “elephant orders”. For example, the current market showing:

Traders all know that if there is a huge amount of pending orders at certain price, then this price will form a strong support(or resistance). Futhermore, high frequency traders also know, if they send a buying order above the “Buying 1” price in the order book depth, then the market becomes:

the price 400.1 becomes “Buying 2” price in the order book depth. Then if the price rises to 400.3, the high-frequency trader will earn a profit of 0.1.

Even if the price does not rise, in the position of “buying 2”, there still has an “elephant” holding the price, and it can be quickly sold back to the elephant at price 400.1. This is the general idea of Penny Jump strategy. Its logic is as simple as this, by monitoring the market order status, to speculate the opponent’s intentions, and then to take the lead in building a favorable position, and finally profit from a small spread in a short period of time. For this “elephant”, because he hangs a huge amount of buying order in the market, he exposed his trading intentions, and naturally became the hunted target of high-frequency traders.

“Penny Jump” strategy implementation

First, observe the trading opportunities with very low probability of the market, and make corresponding strategies according to the trading logic. If the logic is complex, you need to use the existing mathematical knowledge, use the model to describe the nature of the irrational phenomenon as much as possible, and minimize the overfitting. In addition, it must be verified by a backtest engine that can meet the “Price first then Volume first” principle. Luckily, we have FMZ Quant platform that currently supports this backtesting modes.

What is the meaning of supporting “Price first then Volume first” backtest engine? You can understand it as: you send a pending order at 400.1 to buy, only when the selling price in order book depth is 400.1 or lower, your pending order can be closed(executed). It only calculates the price data of the pending orders, and does not calculate the volume data of pending orders, which only meets the price priority(price first) in the exchange orders matching rules.

The “Volume first” is an upgraded version of the “price first”. It is both price-prioritized and time-first. It can be said that this matching mode is exactly the same as the exchange model. By calculating the amount of the pending order, it is judged whether the current pending order reaches the condition of passive transaction to realize the volume transaction, so as to achieve a real simulation of the real market environment.

In addition, some readers may find that the Penny Jump strategy requires market trading opportunities, that is, the market need has at least two “hop” price gaps. Under normal circumstances, the main trading contract of commodity futures is relatively “busy”. The difference between “Buying 1” and “Selling 1” hop is that there is almost no trading chance. So we put our energy on the sub-primary contract where the trading is not too active. This type of trading contract occasionally has two or even three “hop” opportunities. For example, in the MA (“Methanol” code in Chinese commodity futures) 1909 contract, the following situation occurs:

“Selling 1” price 2225 with volume 551, “Buying 1” price 2223 with volume 565, look down for a few seconds. After this happens, it will disappear after several ticks. In this case, we regard the market as self-correction. What we have to do is to catch up. Before the market actively corrects it. if we do it by manually, it would be impossible, with the help of automatic trading, we can make it possible.

The two “hop” price gap appearance situation happens very often, but the three hops are the safest, but the three hops rarely occur, resulting in trading frequency is too low.

Next, we observe the difference between the pervious “Selling 1” “Buying 1” and the “Buying 1” “Selling 1” now. In order to fill the price gap between the market, if the speed is fast enough, it can be placed at the forefront of other orders. Also, the position holding time is very short, with this trading logic, after the realization of the strategy, take the MA909 as an example, the real market test recommends Esunny instead of the CTP interface, the mechanism of position and fund changing situation for Esunny is by pushed data, very suitable for high frequency trading.

Strategy code

After clearing the trading logic, we can use the code to achieve it. Since the FMZ Quant platform use C++ writing strategy examples are too few, here we use C++ to write this strategy, which is convenient for everyone to learn, and the variety is commodity futures. First open: fmz.com > Login > Dashboard > strategy library > New Strategy > Click the drop-down menu in the top left corner > Select C++ to start writing the strategy, pay attention to the comments in the code below.

Step 1: First build the framework of the strategy, in which a HFT class and a main function are defined. The first line in the main function is to clear the log. The purpose of this is to clear the previously running log information every time the strategy is restarted. The second line is to filter some error messages that are not necessary, such as network delay and some tips appear, so that the log only records important information and looks more neat; the third line is to print the “Init OK” message, meaning that the program has started to start. the fourth line is to create an object according to the HFT class, and the object name is hft; the fifth line program enters the while loop, and always executes the loop in the object hft Method, it can be seen that the Loop method is the core logic of this program. Line 6 is another print message. Under normal circumstances, the program will not execute to line 6. If the program is executed to line 6, the proof program has ended.

Next, let’s look at the HFT class, which has five methods. The first method is the construction method; the second method is to obtain the current day of the week to determine whether it is a new K line; the third method is mainly to cancel all unfilled orders, and get detailed Position information, because before the order is placed, it must first determine the current position status; the fourth method is mainly used to print some information, for this strategy, this method is not the main one; the most important is the fifth method, This method is mainly responsible for processing trading logic and placing orders.

So let’s see how each of the methods in this HFT class is implemented, and how the most core Loop method works. From top to bottom, we will implement the specific implementation of each method one by one, and you will find that the original high frequency strategy is so simple. Before talking about the HFT class, we first defined several global variables for storing the results of the hft object calculation. They are: storing order status, position status, holding long position, holding short position, buying price, buying quantity, selling price, selling quantity. Please see the code below:

With the above global variables, we can store the results calculated by the hft object separately, which is convenient for subsequent calls by the program. Next we will talk about the specific implementation of each method in the HFT class. First, the first HFT method is a constructor that calls the second getTradingWeekDay method and prints the result to the log. The second getTradingWeekDay method gets the current day of the week to determine if it is a new K line. It is also very simple to implement, get the timestamp, calculate the hour and week, and finally return the number of weeks; the third getState method is a bit long, i will just describe the general idea, for specific explanation, you can look at the comments in the following coding block.

Next, let’s get all the orders first, return the result is a normal array, then traverse this array, one by one to cancel the order, then get the position data, return an array, and then traverse this Array, get detailed position information, including: direction, position, yesterday or current position, etc., and finally return the result; the fourth stop method is to print information; the code is as follows:

Finally, we focus on how the Loop function controls the strategy logic and the order. If you want to see more carefully, you can refer to the comments in the code. First determine whether the CTP transaction and the market server are connected; then obtain the available balance of the account and obtain the number of weeks; then set the variety code to be traded, by calling the FMZ Quant official SetContractType function, and can use this function to return the details of the trading variety; then call the GetDepth function to get the depth data of the current market. The depth data includes: buying price, buying volume, selling price, selling volume, etc., and we store them with variables, because they will be used later; Then output these port data to the status bar to facilitate the user to view the current market status; the code is as follows:

after done so much, we can finally placing orders. Before the trading, first we judge the current holding position status of the program (no holding position, long position orders, short position orders), here we used the if…else if…else if logic control. They are very simple, If there is no holding position, the position will be opened according the logic condition. If there is holding position, the position will closed according the logic condition. In order to facilitate everyone’s understanding, we use three paragraphs to explain the logic, For opening position part:

First declare a Boolean variable, we use it to control the closing position; next we need get the current account information, and record the profit value, then determine the status of the withdrawal order, if the number of withdrawal exceeds the set maximum, print the related information in the log; then calculate the absolute value of the current bid and offer price difference to determine whether there is more than 2 hops between the current bid price and the ask price.

Next, we get the “Buying 1” price and “Selling 1” price, if the previous buying price is greater than the current buying price, and the current selling volume is less than the buying volume, it means that “Buying 1” price is disappeared. the long position opening price and the order quantity are set; otherwise, if the previous selling price is less than the current selling price, and the current buying volume is less than The selling volume proves that the “Selling 1” price is disappeared, the short position opening price and the order quantity are set; in the end, the long position and the short position orders enter the market at the same time. The specific code is as follows:

Next, we will talk about how to close long position, first set the order type according to the current position status, and then get the “Selling 1” price. If the current “Selling 1” price is greater than the buying long opening price, set the closing long position price. If the current “selling 1” price is less than the long position opening price, then reset closing quantity variable to true, then close all long position. Coding part as below:

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;
}
}

Finally, let’s see how to close short position. The principle is the opposite of the above-mentioned closing long position. First, according to the current position status, set the order type, and then get the “Buying 1” price, if the current “buying 1” price is less than the short position opening price, the price of the closing short position will be set. If the current “buying 1” price is greater than the opening short position price, reset closing quantity variable to true, then close all short position.

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;
}
}

The above is a complete analysis of this strategy. Click here (https://www.fmz.com/strategy/163427) to copy the complete strategy source code without configuring backtest environment on FMZ Quant.

Backtest results

Trading logic

Strategy statement

In order to satisfy the curiosity of high-frequency trading and to see the results more clearly, this strategy backtest environment transaction fee is set to 0, which leads to a simple fast speed logic. if you want to cover the transaction fee to achieve profitability in the real market. More optimization is needed. Such as using the order stream to carry out short-term forecasting to improve the winning rate, plus the exchange fee refund, In order to achieve a sustainable profitable strategy, there are many books on high-frequency trading. I hope that everyone can think more and go to the real market instead of just staying on the principle.

About us

FMZ Quant is a purely technology-driven team that provides a highly efficient available backtest mechanism for quantitative trading enthusiasts. Our backtest mechanism is simulating a real exchange, rather than a simple price match. We hope users can take advantage of the platform to better play their own abilities.