In this article, I will show you how to create and optimize a simple trend following system in QuantShare.
The strategy will have the following rules:
- Strategy uses end-of-day data to trade S&P 500 stocks
- Buy a maximum of 8 stocks at the same time
- Buy if a stock crosses above the 40-bar simple moving average and 80-bar simple moving average on the same day
- Sell if a stock moves below its 40-bar moving average or below its 80-bar moving average
- Do not enter any position if the S&P 500 index is trading below its 100-bar moving average
As you can see, the strategy is composed of very simple technical analysis rules and one market rule based on the S&P 500 index.
Let us see now how we can implement this strategy in QuantShare trading platform.
Set up your Trading System
First of all, let us create and set up our trend following trading system.
- In the main menu, select "Analysis" then click on "Simulator"
- In the "Simulator" manager, click on "New" to create a new trading system
- Set "8" next to "Number of positions" then click on the "Create trading system using the formula editor" tab
- Click on "Symbols & Dates" at the top
- Add a new "Index" condition in the symbols panel and choose S+P 500 as index
Note that if S+P 500 is not present there this means that your symbols are not managed by QuantShare. Please read this for more information:
Let QuantShare Manage your List of Securities
- Select the start and end date of the simulation (Example from 2004 to 2015)
- Make sure you already downloaded EOD data for your S&P 500 stocks (Download -> Download Manager in the main QuantShare menu)
Technical Analysis Rules
The buy rule consists of entering long a stock on the open of the next day if that stock crosses above both a short and medium-term moving averages on the same bar.
This can be implemented in QuantShare programming language using the "cross" function:
sm1 = sma(40);
sm2 = sma(80);
buy = cross(close, sm1) and cross(close, sm2);
NB: If you want to learn more about QS programming language, click here.
The selling rule tells us to exit any position if the stock moves below one of its moving averages (the short and medium ones)
Here is the sell rule formula:
sell = close < sm1 or close < sm2;
Note that we are referring here to the variables "sm1" and "sm2" which were calculated previously before the "buy" rule.
The role of the market rule is to reduce drawdown by preventing our system from entering any new position when the stock market is bearish.
A bearish market here is defined by: S&P 500 index below its 100-bar moving average
We now must retrieve the S&P 500 index time-series, calculates its moving average then add an additional condition to the "buy" variable.
Here is how:
mk = getseries("^GSPC", close); // Retrieve the S&P 500 index using the Yahoo-compatible symbol (^GSPC)
mksm = sma(mk, 100); // Calculate the S&P 500 100-bar moving average
buy = buy and mk > mksm; // Add an additional condition to the "buy" variable
The trading system is now ready and you can backtest it by selecting it in the "Simulator Manager" then clicking on "Backtest/Simulate" button.
A ready to use trading system is available on the sharing sever. You can download it here: S&P 500 Trend Following System
The strategy has a Sharpe ratio above 1, a maximum drawdown of -14.22% and an annual return of almost 20%.
Optimize Your Trading System
Let me now show how you can optimize your trading system. There are many variables that can be optimized here.
- Maximum number of positions
- Short-term moving average period
- Medium-term moving average period
- S&P 500 index moving average period
In this example, let us optimize the maximum number of positions and the index moving average period.
The maximum number of positions can be optimized by adding the following lines to the trading system formula:
Optimize("nb", 1, 10, 1); // Optimize the variable "nb" (Start at 1 until 10 by incrementing the value by 1)
The S&P 500 moving average is calculated here:
mksm = sma(mk, 100);
To optimize the moving average period, just replace that line with this:
Optimize("IndexPeriod", 10, 200, 10); // Optimize the variable "IndexPeriod" (Start at 10 until 200 by incrementing the value by 10)
mksm = sma(mk, IndexPeriod);