#!pip install fastquant
/Users/enzoampil/quant/fastquant
get_stock_data
has been added, which now includes all Yahoo Finance data (on top of PSE)backtest
function is now ready to use!Colab notebook on this link
pip3 install jupyter
git clone https://github.com/enzoampil/fastquant.git
cd fastquant
jupyter notebook
lessons/fastquant_lesson2_backtest_your_trading_strategy.ipynb
¶from matplotlib import pyplot as plt
from fastquant import backtest, get_stock_data
%matplotlib inline
jfc = get_stock_data("JFC", "2018-01-01", "2019-01-01")
jfc.close.plot(figsize=(10, 6))
plt.title("Daily Closing Prices of JFC\nfrom 2018-01-01 to 2019-01-01", fontsize=20)
Reading cached file found: JFC_2018-01-01_2019-01-01.csv
Text(0.5, 1.0, 'Daily Closing Prices of JFC\nfrom 2018-01-01 to 2019-01-01')
In this section, we will attempt to visually assess the performance of a SMA crossover strategy. There are many ways to do this strategy, but we will go with a “price crossover” approach with a 30 day SMA.
In this case, it’s considered a “buy” signal when the closing price crosses the simple moving average from below, and considered a “sell” signal when the closing price crosses the simple moving average from above.
So how do we know our SMA price crossover strategy is effective? Visually, we can assess this by seeing if the “sell” signal happens right before the stock price starts going down, and if the “buy” signal happens right before the stock price starts going up.
import pandas as pd
ma30 = jfc.close.rolling(30).mean()
close_ma30 = pd.concat([jfc.close, ma30], axis=1).dropna()
close_ma30.columns = ['Closing Price', 'Simple Moving Average (30 day)']
close_ma30.plot(figsize=(10, 6))
plt.title("Daily Closing Prices vs 30 day SMA of JFC\nfrom 2018-01-01 to 2019-01-01", fontsize=20)
Text(0.5, 1.0, 'Daily Closing Prices vs 30 day SMA of JFC\nfrom 2018-01-01 to 2019-01-01')
Now, let's get started with backtesting!
Below, I show how you can use fastquant
to backtest a simple moving average crossover (similar to what we have above).
The three steps are:
backtest
and get_pse_data
functions from fastquant
from fastquant import backtest, get_stock_data
Here, we get DCV (date, closing, volume) data from JFC using the get_pse_data
function
jfc = get_stock_data("JFC", "2018-01-01", "2019-01-01")
Reading cached file found: JFC_2018-01-01_2019-01-01.csv
jfc
dt | close | volume | |
---|---|---|---|
0 | 2018-01-03 | 255.4 | 745780 |
1 | 2018-01-04 | 255.0 | 617010 |
2 | 2018-01-05 | 255.0 | 946040 |
3 | 2018-01-08 | 256.0 | 840630 |
4 | 2018-01-09 | 255.8 | 978180 |
... | ... | ... | ... |
238 | 2018-12-20 | 303.0 | 659480 |
239 | 2018-12-21 | 302.4 | 715510 |
240 | 2018-12-26 | 292.0 | 1087620 |
241 | 2018-12-27 | 295.0 | 585760 |
242 | 2018-12-28 | 291.8 | 425440 |
243 rows × 3 columns
smac
) strategy on the JFC dataWe perform the backtest using a 15 day moving average as the "fast" moving average, and a 35 day moving average as the "slow" moving average. If we want to change these parameter values, we can just replace the numbers in the backtest
function.
We call these the strategy level arguments since they are unique to a specific strategy.
Do note that by default, the backtesting algorithm assumes that you start out with PHP 100,000 as cash (init_cash
), while using all of that cash during a buy signal (buy_prop
), and selling all of your current stock holdings during a sell signal (sell_prop
). We call these the global level arguments since they can be shared across companies.
%matplotlib
backtest('smac', jfc, fast_period=15, slow_period=35)
Using matplotlib backend: MacOSX Starting Portfolio Value: 100000.00 ===Global level arguments=== init_cash : 100000 buy_prop : 1 sell_prop : 1 ===Strategy level arguments=== fast_period : 15 slow_period : 35 2018-08-06, BUY CREATE, 280.00 2018-08-06, Cash: 100000.0 2018-08-06, Price: 280.0 2018-08-06, Buy prop size: 354 2018-08-06, Afforded size: 354 2018-08-06, Final size: 354 2018-08-07, BUY EXECUTED, Price: 280.00, Cost: 99120.00, Comm 743.40 2018-09-20, SELL CREATE, 272.00 2018-09-21, SELL EXECUTED, Price: 272.00, Cost: 99120.00, Comm 722.16 2018-09-21, OPERATION PROFIT, GROSS -2832.00, NET -4297.56 2018-10-31, BUY CREATE, 276.00 2018-10-31, Cash: 95702.44 2018-10-31, Price: 276.0 2018-10-31, Buy prop size: 343 2018-10-31, Afforded size: 343 2018-10-31, Final size: 343 2018-11-05, BUY EXECUTED, Price: 276.00, Cost: 94668.00, Comm 710.01 Final Portfolio Value: 100411.83
The idea of backtesting is that we should choose the best strategy based on which one has worked best over time.
%matplotlib
backtest('smac', jfc, fast_period=1, slow_period=30)
Using matplotlib backend: MacOSX Starting Portfolio Value: 100000.00 ===Global level arguments=== init_cash : 100000 buy_prop : 1 sell_prop : 1 ===Strategy level arguments=== fast_period : 1 slow_period : 30 2018-02-26, BUY CREATE, 292.00 2018-02-26, Cash: 100000.0 2018-02-26, Price: 292.0 2018-02-26, Buy prop size: 339 2018-02-26, Afforded size: 339 2018-02-26, Final size: 339 2018-02-27, BUY EXECUTED, Price: 292.00, Cost: 98988.00, Comm 742.41 2018-03-14, SELL CREATE, 284.00 2018-03-15, SELL EXECUTED, Price: 284.00, Cost: 98988.00, Comm 722.07 2018-03-15, OPERATION PROFIT, GROSS -2712.00, NET -4176.48 2018-03-16, BUY CREATE, 305.40 2018-03-16, Cash: 95823.51999999999 2018-03-16, Price: 305.4 2018-03-16, Buy prop size: 311 2018-03-16, Afforded size: 311 2018-03-16, Final size: 311 2018-03-19, BUY EXECUTED, Price: 305.40, Cost: 94979.40, Comm 712.35 2018-03-20, SELL CREATE, 285.00 2018-03-21, SELL EXECUTED, Price: 285.00, Cost: 94979.40, Comm 664.76 2018-03-21, OPERATION PROFIT, GROSS -6344.40, NET -7721.51 2018-03-26, BUY CREATE, 295.00 2018-03-26, Cash: 88102.012 2018-03-26, Price: 295.0 2018-03-26, Buy prop size: 296 2018-03-26, Afforded size: 296 2018-03-26, Final size: 296 2018-03-27, BUY EXECUTED, Price: 295.00, Cost: 87320.00, Comm 654.90 2018-04-04, SELL CREATE, 280.00 2018-04-05, SELL EXECUTED, Price: 280.00, Cost: 87320.00, Comm 621.60 2018-04-05, OPERATION PROFIT, GROSS -4440.00, NET -5716.50 2018-04-12, BUY CREATE, 300.00 2018-04-12, Cash: 82385.512 2018-04-12, Price: 300.0 2018-04-12, Buy prop size: 272 2018-04-12, Afforded size: 272 2018-04-12, Final size: 272 2018-04-13, BUY EXECUTED, Price: 300.00, Cost: 81600.00, Comm 612.00 2018-04-13, SELL CREATE, 291.60 2018-04-16, SELL EXECUTED, Price: 291.60, Cost: 81600.00, Comm 594.86 2018-04-16, OPERATION PROFIT, GROSS -2284.80, NET -3491.66 2018-04-18, BUY CREATE, 294.20 2018-04-18, Cash: 78893.84800000001 2018-04-18, Price: 294.2 2018-04-18, Buy prop size: 265 2018-04-18, Afforded size: 265 2018-04-18, Final size: 265 2018-04-19, BUY EXECUTED, Price: 294.20, Cost: 77963.00, Comm 584.72 2018-04-19, SELL CREATE, 291.00 2018-04-20, SELL EXECUTED, Price: 291.00, Cost: 77963.00, Comm 578.36 2018-04-20, OPERATION PROFIT, GROSS -848.00, NET -2011.08 2018-04-23, BUY CREATE, 294.00 2018-04-23, Cash: 76882.763 2018-04-23, Price: 294.0 2018-04-23, Buy prop size: 259 2018-04-23, Afforded size: 259 2018-04-23, Final size: 259 2018-04-24, BUY EXECUTED, Price: 294.00, Cost: 76146.00, Comm 571.09 2018-04-24, SELL CREATE, 281.60 2018-04-25, SELL EXECUTED, Price: 281.60, Cost: 76146.00, Comm 547.01 2018-04-25, OPERATION PROFIT, GROSS -3211.60, NET -4329.70 2018-05-16, BUY CREATE, 286.60 2018-05-16, Cash: 72553.06000000001 2018-05-16, Price: 286.6 2018-05-16, Buy prop size: 251 2018-05-16, Afforded size: 251 2018-05-16, Final size: 251 2018-05-17, BUY EXECUTED, Price: 286.60, Cost: 71936.60, Comm 539.52 2018-05-17, SELL CREATE, 285.00 2018-05-18, SELL EXECUTED, Price: 285.00, Cost: 71936.60, Comm 536.51 2018-05-18, OPERATION PROFIT, GROSS -401.60, NET -1477.64 2018-05-18, BUY CREATE, 285.00 2018-05-18, Cash: 71075.42300000001 2018-05-18, Price: 285.0 2018-05-18, Buy prop size: 247 2018-05-18, Afforded size: 247 2018-05-18, Final size: 247 2018-05-21, BUY EXECUTED, Price: 285.00, Cost: 70395.00, Comm 527.96 2018-05-21, SELL CREATE, 284.00 2018-05-22, SELL EXECUTED, Price: 284.00, Cost: 70395.00, Comm 526.11 2018-05-22, OPERATION PROFIT, GROSS -247.00, NET -1301.07 2018-05-23, BUY CREATE, 287.00 2018-05-23, Cash: 69774.35050000002 2018-05-23, Price: 287.0 2018-05-23, Buy prop size: 241 2018-05-23, Afforded size: 241 2018-05-23, Final size: 241 2018-05-24, BUY EXECUTED, Price: 287.00, Cost: 69167.00, Comm 518.75 2018-05-24, SELL CREATE, 281.20 2018-05-25, SELL EXECUTED, Price: 281.20, Cost: 69167.00, Comm 508.27 2018-05-25, OPERATION PROFIT, GROSS -1397.80, NET -2424.82 2018-06-01, BUY CREATE, 283.80 2018-06-01, Cash: 67349.52900000001 2018-06-01, Price: 283.8 2018-06-01, Buy prop size: 235 2018-06-01, Afforded size: 235 2018-06-01, Final size: 235 2018-06-04, BUY EXECUTED, Price: 283.80, Cost: 66693.00, Comm 500.20 2018-06-04, SELL CREATE, 280.20 2018-06-05, SELL EXECUTED, Price: 280.20, Cost: 66693.00, Comm 493.85 2018-06-05, OPERATION PROFIT, GROSS -846.00, NET -1840.05 2018-06-07, BUY CREATE, 282.60 2018-06-07, Cash: 65509.479000000014 2018-06-07, Price: 282.6 2018-06-07, Buy prop size: 229 2018-06-07, Afforded size: 229 2018-06-07, Final size: 229 2018-06-08, BUY EXECUTED, Price: 282.60, Cost: 64715.40, Comm 485.37 2018-06-13, SELL CREATE, 279.20 2018-06-14, SELL EXECUTED, Price: 279.20, Cost: 64715.40, Comm 479.53 2018-06-14, OPERATION PROFIT, GROSS -778.60, NET -1743.49 2018-06-19, BUY CREATE, 284.00 2018-06-19, Cash: 63765.98750000001 2018-06-19, Price: 284.0 2018-06-19, Buy prop size: 222 2018-06-19, Afforded size: 222 2018-06-19, Final size: 222 2018-06-20, BUY EXECUTED, Price: 284.00, Cost: 63048.00, Comm 472.86 2018-06-20, SELL CREATE, 270.00 2018-06-21, SELL EXECUTED, Price: 270.00, Cost: 63048.00, Comm 449.55 2018-06-21, OPERATION PROFIT, GROSS -3108.00, NET -4030.41 2018-07-27, BUY CREATE, 266.00 2018-07-27, Cash: 59735.57750000001 2018-07-27, Price: 266.0 2018-07-27, Buy prop size: 222 2018-07-27, Afforded size: 222 2018-07-27, Final size: 222 2018-07-30, BUY EXECUTED, Price: 266.00, Cost: 59052.00, Comm 442.89 2018-09-06, SELL CREATE, 281.00 2018-09-07, SELL EXECUTED, Price: 281.00, Cost: 59052.00, Comm 467.87 2018-09-07, OPERATION PROFIT, GROSS 3330.00, NET 2419.24 2018-09-07, BUY CREATE, 281.00 2018-09-07, Cash: 62154.82250000001 2018-09-07, Price: 281.0 2018-09-07, Buy prop size: 219 2018-09-07, Afforded size: 219 2018-09-07, Final size: 219 2018-09-10, BUY EXECUTED, Price: 281.00, Cost: 61539.00, Comm 461.54 2018-09-11, SELL CREATE, 269.00 2018-09-12, SELL EXECUTED, Price: 269.00, Cost: 61539.00, Comm 441.83 2018-09-12, OPERATION PROFIT, GROSS -2628.00, NET -3531.38 2018-10-19, BUY CREATE, 265.00 2018-10-19, Cash: 58623.44750000001 2018-10-19, Price: 265.0 2018-10-19, Buy prop size: 219 2018-10-19, Afforded size: 219 2018-10-19, Final size: 219 2018-10-22, BUY EXECUTED, Price: 265.00, Cost: 58035.00, Comm 435.26 Final Portfolio Value: 64057.39
%matplotlib
backtest('smac', jfc, fast_period=30, slow_period=50)
Using matplotlib backend: MacOSX Starting Portfolio Value: 100000.00 ===Global level arguments=== init_cash : 100000 buy_prop : 1 sell_prop : 1 ===Strategy level arguments=== fast_period : 30 slow_period : 50 2018-08-23, BUY CREATE, 293.00 2018-08-23, Cash: 100000.0 2018-08-23, Price: 293.0 2018-08-23, Buy prop size: 338 2018-08-23, Afforded size: 338 2018-08-23, Final size: 338 2018-08-24, BUY EXECUTED, Price: 293.00, Cost: 99034.00, Comm 742.75 2018-10-05, SELL CREATE, 243.00 2018-10-08, SELL EXECUTED, Price: 243.00, Cost: 99034.00, Comm 616.00 2018-10-08, OPERATION PROFIT, GROSS -16900.00, NET -18258.76 2018-11-19, BUY CREATE, 282.00 2018-11-19, Cash: 81741.23999999999 2018-11-19, Price: 282.0 2018-11-19, Buy prop size: 287 2018-11-19, Afforded size: 287 2018-11-19, Final size: 287 2018-11-20, BUY EXECUTED, Price: 282.00, Cost: 80934.00, Comm 607.00 Final Portfolio Value: 83946.83
We can conclude that across all the parameter combinations we've tried, the best performing one is the one where fast_period
= 15, while slow_period
= 40.
%matplotlib
backtest('smac', jfc, fast_period=15, slow_period=40)
Using matplotlib backend: MacOSX Starting Portfolio Value: 100000.00 ===Global level arguments=== init_cash : 100000 buy_prop : 1 sell_prop : 1 ===Strategy level arguments=== fast_period : 15 slow_period : 40 2018-08-07, BUY CREATE, 270.00 2018-08-07, Cash: 100000.0 2018-08-07, Price: 270.0 2018-08-07, Buy prop size: 367 2018-08-07, Afforded size: 367 2018-08-07, Final size: 367 2018-08-08, BUY EXECUTED, Price: 270.00, Cost: 99090.00, Comm 743.17 2018-09-21, SELL CREATE, 271.00 2018-09-24, SELL EXECUTED, Price: 271.00, Cost: 99090.00, Comm 745.93 2018-09-24, OPERATION PROFIT, GROSS 367.00, NET -1122.10 2018-11-05, BUY CREATE, 280.00 2018-11-05, Cash: 98877.89749999999 2018-11-05, Price: 280.0 2018-11-05, Buy prop size: 350 2018-11-05, Afforded size: 350 2018-11-05, Final size: 350 2018-11-06, BUY EXECUTED, Price: 280.00, Cost: 98000.00, Comm 735.00 Final Portfolio Value: 102272.90
fastquant/strategies.py
¶