Skip to content
Generic filters
Exact matches only

Backtest with grid search using only 3 lines of code on fastquant | by Lorenzo Ampil | Aug, 2020

Use fastquant to easily optimize your trading strategy’s parameters automatically!

Lorenzo Ampil

If you want to consistently earn money with your investments, backtesting is one of the best ways to assess the effectiveness of your trading strategies — of course, assuming that you implement it properly. The idea is that you can experiment with the different parameters for your chosen strategies, and see which combinations give you the best returns for your investment.

However, this can easily start getting tedious as you would have to run hundreds or even thousands of parameter combinations manually.

To solve this problem, we can use fastquant to implement a technique called “grid search”, which basically allows you to run a backtest across each of the parameter combinations that you want to run for your strategy.

For the rest of the article, I’ll be demonstrating how to apply automated grid search when backtesting your trading strategies.

Note: If you’re not yet familiar with how to do basic backtesting with fastquant, you may want to check out my previous article on how to do this in 3 lines of code.

Let’s start by installing fastquant via pip!

# Run this on your terminal
pip install fastquant

# Alternatively, you can run this from jupyter this way
!pip install fastquant

For example, let’s use Jollibee Food Corp. (JFC) stock from 2018–01–01 to 2019–12–31 as our sample data.

Note: get_stock_data supports all of the companies accessible from Yahoo Finance and PSE.

from fastquant import get_stock_data
df = get_stock_data("JFC", "2018-01-01", "2019-12-31")
# dt close
# 2018-01-03 255.4
# 2018-01-04 255.0
# 2018-01-05 255.0
# 2018-01-08 256.0
# 2018-01-09 255.8

Say you want to backtest a simple moving average crossover (SMAC) strategy on JFC stock with a fast period of 15 days, and slow period of 40 days.

from fastquant import backtest
backtest("smac", df, fast_period=15, slow_period=40)
# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 68742.36

You’ll notice that your final portfolio value went down by a lot (~31%), and by looking at the chart below, you’ll see that this is because the strategy was still recommending trades (green and red arrows) when the stock was on an overall down trend.

So now, we’ll want to see if there’s a combination of “slow period” and “fast period” that will lead to an SMAC strategy that knows not to make trades during the overall downtrend.

One way to do this is to try out a large number of possible fast period and slow period combinations. For this example, we’ll set the slow period to take values within the range 20 to 241 (skipping every 5), while the fast period can take values within the range 1 to 20.

This means fast period can take 20 possible values, while slow period can take 45 possible values. Together, that translates to 900 (20 x 45) possible combinations! Imagine doing this one by one right.

Thankfully, we can easily automate this by using fastquant’s built-in grid search capabilities by using iterators (e.g. list , range ) as inputs, rather than single numbers.

results = backtest("smac", df, fast_period=range(1, 21), slow_period=range(20, 241, 5))
results[["fast_period", "slow_period", "final_value"]].head()
# fast_period slow_period final_value
#0 3 105 107042.02
#1 8 205 103774.66
#2 11 170 103774.66
#3 8 200 103774.66
#4 9 95 103388.12

Note that “backtest” returns a pandas dataframe (“results”) which contains the results for each iteration on each row. Each column of the dataframe corresponds to either a parameter that was used (e.g. fast_period), or a performance metric for the strategy (e.g. final_value).

Conveniently, the rows are sorted in descending order based on each iteration’s portfolio return, and so the “best” parameter combinations are the ones at the top of the dataframe.

In this case, it seems that the top parameter combination is: fast_period=3 , and slow_period=105 , with a portfolio return of 7,042.02. This indicates that we may want to use this parameter combination when utilizing the SMAC strategy on JFC stock.

Note: It is very possible that this parameter combination is still overfitting to the chosen period. See the caveats and safeguards of backtesting in this previous article.

Now, let’s run our optimal strategy!

from fastquant import backtest
backtest("smac", df, fast_period=3, slow_period=105)
# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 107042.02

As shown in the plot below, the parameter combination above would have recommended us to sell our stock right before the overall downtrend — see the red downward arrow right before the drop. This explains how it was able to avoid the losses that we saw during our initial implementation of the SMAC strategy at the beginning of this article.

With the results dataframe, you can even visualize the effectiveness of each parameter combination with a heatmap like below!