STRATEGY DEVELOPMENT PHASE
It is very popular among traders to develop and trade intraday strategies. The reasons are simple. This type of strategy greatly limits the potential maximum drawdown by not exposing the strategy to the risk of night movements and weekend gaps. The rule that the less total time a strategy is in position, the lower you expose it to overall risk certainly applies.
On the other hand, you are quite limited by the overall potential for profitability. Let’s show how traditionally we could develop an intraday strategy.
Our favorite types of strategies include those that use certain price patterns on entry conditions. We will also focus on them.
First, let’s recall the basic points under which conditions we are going to develop the strategy:
Market: E-mini Russell 2000 (for lower capital Micro E-mini Russell 2000)
Timeframe: 60 min bar
Trading session: 08:45 a.m. – 03:03 p.m.
In-Sample data: 1.1.2006 – 1.7.2015
Out-of-sample: 1.7.2015 – 10.11.2020
Conditions for strategy development:
1. Definition of the exit conditions at the end of the trading session
The basic output condition is that we do not want to hold the position overnight. So we always want to leave the position at the latest at the end of the trading session. EasyLanguage has one exit condition market order that meets this condition and is:
SetExitOnClose;
This code meets the criteria:
Exit Conditions – The condition is that the strategy exits the position at the end of the day, in our case 03:03 p.m.
Exit Orders – strategy closes all positions with the Market trade order. This command can distinguish whether to exit a long or short position.
2. Definition of THE ENTRY PRICE PATTERN CONDITIONS
The premise is that we want to develop a strategy that trades on both sides – long and short, and has mirror conditions for both sides. The motivation for developing these systems is to have a strategy that will be consistently profitable, ideally in any market regime (bulls, bear markets, flat).
Entry conditions are variables that determine whether predefined entry criteria are met in order to enter a position. If the conditions are met, we enter a long or short position. If the conditions are not met, we will not enter the position. Mathematical operators are often used within input conditions. There are these types:
<, which means it is smaller
>, which means it is larger
=, which means equals
<=, which means is less-than or equal to
>=, which means is larger-than or equal to
<>, which means does not equal
Price Patterns work mainly with these Functions, which have a predefined task (Functions):
OpenD (PeriodsAgo)
HighD (PeriodsAgo)
LowD (PeriodsAgo)
CloseD (PeriodsAgo)
These are the opening (OpenD), closing (CloseD), highest (HighD) or lowest (LowD) prices within a defined trading session for a given day, which is defined by the PeriodsAgo value.
So, for example, the value CloseD (1) means the closing price of the previous day, in our case, at 03:03 p.m. In contrast, HighD (0) means the highest High value for the current day.
In the case of HighD (2), this would be the highest High value from the trading session two days ago. And also, OpenD (0) means the value of the opening price for the current day, in our case 08:45 a.m.
So let’s have a look at one Price Pattern example in this strategy:
{Variables for entry and exit conditions}
Var: EntryConditionLong(false),
EntryConditionsShort(false);
{Entry and exit conditions}
EntryConditionLong = CloseD(1) <= LowD(0) and OpenD(0) >= O;
EntryConditionShort = CloseD(1) >= HighD(0) and OpenD(0) <= O;
To explain Var: They define so-called variables, which are words or letters defined by the programmer that are used to store certain information. Variables are always defined at the beginning of the code and carry information that changes over time. EasyLanguage has two types of Variables:
1) Numeric – Variables, which are assigned a numeric value that can change over time. In this particular example, what we have presented here, there is no numerical condition.
2) Boolean – Variables that store information only true or false. That is, over time, the stored information is only true or false. When it is true, the information is active, and when it is false, the information is inactive.
Example Boolean – Variables in code are
Var: EntryConditionLong(false),
EntryConditionsShort(false);
Let’s now explain the specific conditions:
EntryConditionLong = CloseD(1) <= LowD(0) and OpenD(0) >= O;
EntryConditionShort = CloseD(1) >= HighD(0) and OpenD(0) <= O;
The first thing you may notice is the fact that the code contains two mirror conditions that are reflected on both the long and short side.
EntryConditionLong
The condition of entering a long position means that the closing price of the Close trading session from the previous day, ie at 03.03 p.m. (“CloseD (1)”) is less than the lowest Low of the current day (“LowD (0)”) and at the same time the opening value of the current day at 08:45 a.m. (“OpenD (0)”) greater than the Open (“O”) value of the last bar
EntryConditionShort
Below is the EasyLanguage code, which clearly defines entry into both long and short positions
{ Entry orders }
Long position
If (MarketPosition = 0) and (EntriesToday(Date) < 1) and EntryConditionLong then begin
Buy(“EntryConditionLong”) next bar at market;
end;
This part of the code means:
If we are not in the position (“MarketPosition = 0”) and at the same time we have not entered the position for the day (EntriesToday (Date) <1) and at the same time the EntryConditionLong condition is met, then enter the long position bar (Buy (“EntryConditionLong”) next bar at market).
If (MarketPosition = 0) and (EntriesToday(Date) < 1) and EntryConditionShort and EntryConditionLong = false then begin
Sell short(“EntryConditionShort”) next bar at market;
end;
This part of the code means:
If we are not in the position (“MarketPosition = 0”) and at the same time we have not entered the position for the day (EntriesToday (Date) <1) and at the same time the condition EntryConditionShort is met and the condition EntryConditionLong does not apply
(“EntryConditionLong = false”) position with the Sell Short Market order at the next bar immediately after the close of the current bar (“Sell short (” EntryConditionShort “) next bar at the market”)
And with this, we basically defined a very simple strategy literally in a few lines.
In Figure 1 we can see the whole code in EasyLanguage:
Figure 1: Intraday Strategy with Simple Price Pattern in EasyLanguage, TradeStation Platform
Initial situation of the Intraday Strategy with Simple Price Pattern:
It has a simple price pattern for entering both long and short positions that are mirrored. When these simple conditions are met, the strategy enters the position with the long or short market order when the next bar is opened
It can open a maximum of one position per day
Trades fixedly with one contract
It does not contain any input parameters (input parameters can be, for example, the length of the moving average, etc.). Thus, it is a very simple strategy with additional potential for improvement (i.e., we can add additional conditions)
The strategy conditions were built on In-Sample data, ie, from 1.1.2006 to 1.7.2015; let’s now look at the Equity curve of the strategy. We expect a total cost of $ 10 USD per slippage and round-turn for one trade. The equity curve looks like this:
Figure 2: Equity curve of the Intraday Strategy with Simple Price Pattern
From Figure 2, we can see that the In-Sample strategy generated a total of 1374 trades with a total net profit of $ 43,165. (For a Micro E-mini contract, that would be $ 4316.5. On the long side of the strategy, it earned $ 19,035
Long trades is 702, Short 672
Maximum drawdown is $ 9,805 (Micro E-mini $ 980)
The average profit per trade after deducting $ 10 per trade is $ 31.42
The strategy was the most profitable in 2008, earning as much as $ 19,630
The most loss-making then in 2012: – $ 5405
Strategy benefits
The strategy is very simple; it does not contain any parameters for optimization. The simpler the strategies, the better (less risk of over-optimization of strategies).
Makes money with mirror conditions on both the long and short side (even more on the short side)
It is very efficient in the crisis year of 2008. The question is whether it will confirm its performance even in the context of the crisis in 2020
It contains a significant number of trades, so we can try further to improve the strategy
Strategy disadvantages
The equity curve is not stable enough. The strategy contains a lot of periods of stagnation and two periods of relatively large drawdown
Suggestions for strategy improvements
We can try to improve the strategy on two fronts:
Add another input condition
Thanks to a large sample of trades, we can afford to try to add another entry condition. It is obvious that the strategy indicates a period of higher volatility (for example the 2008 year). So let’s try to add an input condition that will work with the well-known Average True Range volatility indicator with a period of 14:
We will define the input parameter:
Input: ATRTreshold(10);
Also a boolean paramenter:
Vars: ATREntryCondition(false);
And we add the condition that if the ATR must be greater than a certain value in order for us to enter the position. We subject the ATRTreshold to an optimization test in order to find its optimal value:
ATREntryCondition = AvgTrueRange(14) > ATRTreshold;
The final code will look like as follows (Figure 3):
Figure 3: Intraday Strategy with Simple Price Pattern in EasyLanguage with the addition of an entry condition with an ATR volatility indicator, TradeStation EasyLanguage
Figure 3 shows a strategy with a newly defined single input parameter (ATRTreshold), which we use under the new general condition for both the long and short side (ATREntryCondition). Note that this condition is now incorporated into Entry Orders.
We are now ready to test the new condition on optimization tests to assess whether it has a clearly definable added value:
Figure 4: Results of optimization tests of the “Intraday Strategy with Simple Price Pattern” strategy in EasyLanguage with the addition of an entry condition with an ATR volatility indicator (from 1 to 10), TradeStation EasyLanguage
In Figure 4 can be seen how the ATR input condition gives clear logic. The higher the volatility in the markets, the more likely it is that a given enrty signal with an exit at the end of the day will work. We clearly see the conclusion from two things. With the value of the ATRTreshold (first column), the % Profitable increases (percentage of successful trades, the Profit Factor increases and logically the number of trades decreases, because the period with higher volatility tends to be less than the period with lower volatility).
Application of Stop-Loss
We will test whether it is not possible within this strategy to better manage the exit from the position, for example, by activating the Stop-Loss, or the trailing Stop-Loss, or the Profit Target. In our example, we will show the classic Stop Loss from the entry price working with the Average True Range with a period of 14 and examine whether it could bring us an improvement in the In-Sample data:
Fixed ATR Stop-Loss
Let’s start with Stop Loss if we enter a long position.
{Variables }
Inputs: Multiplier(1);
Var: LongStopLoss(0),
ShortStopLoss(0);
{ Exit orders, long trades }
If MarketPosition = 1 then begin
If BarsSinceEntry = 0 then begin
LongStopLoss = EntryPrice – Multiplier * (AvgTrueRange(14));
end;
Sell(“StopLossATR-Long”) next bar at LongStopLoss stop;
end;
This code basically says if we are in a long position (Market Position = 1), then we start calculating within the given bar (BarsSinceEntry = 0) and then we start with the calculation of LongStopLoss, which is equal to the value of EntryPrice – Multiple ( Multiplier) * Average True Range (14). The exit price level will change with each bar based on the changing Average True Range value (14). The multiplier is a constant that we can choose based on optimization tests.
In the event that this price is hit, we will exit the long position
(Sell) at the LongStopLoss price level with the stop market order
Now let’s look at exiting from a short position.
{ Exit orders, short trades }
If MarketPosition = -1 then begin
If BarsSinceEntry = 0 then begin
ShortStopLoss = EntryPrice + Multiplier * (AvgTrueRange(14));
end;
Buy to cover(“StopLossATR-Short”) next bar at ShortStopLoss stop;
end;
This code basically says if we are in a short position (Market Position = -1), then we start calculating within the given bar (BarsSinceEntry = 0) and then we start with the calculation of ShortStopLoss, which is equal to the value of EntryPrice + Multiple (Multiplier) * Average True Range (14). The exit level will change with each bar based on the changing Average True Range value (14). A multiplier is a constant that we can choose based on optimization tests.
In the event that this price is hit, we will exit from the short position (Buy to cover) at the ShortStopLoss price level with the stop market order.
Now let’s try to optimize the Multiplier and find its ideal value (Figure 5):
Figure 5: Results of optimization tests of the “Intraday Strategy with Simple Price Pattern with entry volatility indicator” and the addition of a Stop Loss based on Average True Range 14, TradeStation Platform
Figure 5 shows that the Multiplier constant was optimized from 0.1 to 3.1, with an increment of 0.3. It is clear that the lowest value of 0.1 had a big impact on the overall performance of the strategy because the stop loss was hit very often, which had a huge impact on the overall net profit and the percentage of successful trades. We wanted to include Stop Loss in the strategy mainly for potentially lower drawdowns, which is essentially true (Max Intraday Drawdown column), but it is clear that the use of this type of Stop Loss significantly reduces the overall profit, Average Profit per Trade (Avg Trade), trading success (% Profitable). Therefore, the use seems rather counterproductive, and for that reason, we will not use it in the end.
Strategy verification on Out-of-Sample data
The final code of the strategy is available in Figure 3. Now let’s see how the strategy will perform on completely unknown data (Out-of-Sample) from 1.7.2015 to 13.11.2020 (Figure 6):
Figure 6: “Intraday Strategy with Simple Price Pattern” in EasyLanguage with the addition of an entry condition with ATR volatility indicator and its result on Out-of-Sample data, TradeStation Platform
Overall evaluation of the “Intraday Strategy with Simple Price Pattern”
The great advantage of this strategy was its obvious simplicity. The resulting code contained a simple entry condition in the form of a Price Pattern, one parameter to be optimized (ATRTreshold), and a simple exit condition at the end of the trading session. Remember, the simpler the strategy is, the better for your trading.
The backtest process was successful. The strategy was developed and created within the In-Sample data.
However, it is clear that the strategy did not confirm its stable performance from In-Sample data (Figure 15). At first sight, it is clear that this is most likely an over-optimized strategy, which did not confirm its performance in the Out-of-Sample data. One statistic for all: Within the In-Sample data, the average profit per trade was $ 80.69. In the Out-of-Sample data, the average profit per trade is only $ 23.95. The strategy practically stagnated from March 2017 to March 2020. The strategy was then significantly profitable in the COVID crisis from early March 2020 to early May 2020. From May 2020 to November 2020, it has an almost $ 10,000 drawdown. Thus, the strategy has not confirmed its stable performance over the years, and it is clear that it will most likely not be robust in live trading.
Due to the simplicity of development, minimal risk of Selection Bias can be stated with a high probability, we did not generate any huge number of strategies. Over-optimization is also unlikely, the code is very simple.
The strategy does not use any limit orders, which is very suitable and accurate for backtesting.
Look-ahead bias can be virtually eliminated due to the simplicity of the strategy code. The risk is absolutely minimal; however, of course, this potential bias would still need to be verified within the simulated live trading. However, if the strategy has not shown potential in Out-of-Sample tests, it is, of course, not worth dealing with simulated trading at all.
Unfortunately, the strategy did not pass out-of-sample tests. So there is no point in dealing with other robustness tests in any way, which we will discuss later in this Ebook.
Advice: If out-of-sample shows that strategy is not good enough, just try to develop a new one
If you don’t want to read all I want to share with you article by article, grab our Ultimate Guide To Successful Algorithmic Trading here and read it anytime you want! 12 chapters, 112 pages: all in one place and completely FREE of charge!
Search
Search
Recent Posts
Topics
Advanced (6)Algorithmic Trading (17)Basics (24)Futures (1)Investing (6)Libraries (1)Python (10)Statistics (1)Stock Market (9)Stock Pairs (2)Strategy Development (16)Time Series (2)Trading (8)volatility (2)
Recent Comments
eyeCrato on Selection of Market or Set Of Markets for Trading, TimeFrame and Trading Session 4/12
eyeCrato on Selection of Market or Set Of Markets for Trading, TimeFrame and Trading Session 4/12
Peter Kostovčík on Correlation approaches for stock pairs you have not seen before
ted thedog on Correlation approaches for stock pairs you have not seen before
Jakub on Trading Stocks Make Sense Post Earnings & Long Bias
Comments