Python

Backtesting intraday stock strategies in Python with vectorbt

Backtesting intraday stock strategies in Python with vectorbt

Creating trading bots these days on intraday data become more and more popular days. For simple backtesting trades usually go to Pine Script. But with libraries like vectorbt backtesting in Python become quite simple. Also, not many people know that you can get intraday data for stocks from Yahoo Finance for free. So in summary intraday backtest can be written just in a few lines of code and in this article I’ll show you an example.

First, let’s export vectorbt library:

import vectorbt as vbt

Next, let’s get some data. We’re getting data from yahoo finance and currently, the following timeframes are supported:

  • 1m – 1 minute
  • 2m – 2 minutes
  • 5m – 5 minutes
  • 15m – 15 minutes
  • 30m – 30 minutes
  • 60m – 60 minutes
  • 90m – 90 minutes
  • 1h – 1 hour
  • 1d – 1 day
  • 5d – 5 days
  • 1wk – 1 week
  • 1mo – 1 month
  • 3mo – 3 month

Also, be careful with the start parameter of your function. For every timeframe, there is a corresponding limit so it won’t allow you to download too much data. For example for a 5-minute timeframe the limit is 60 days, so only about 3k records will be downloaded for you. Of course that’s not a lot for a backtest. You can try to get this data from Yahoo Finance and save it yourself, this way you will be able to collect more history over time.

The syntax for getting data from Yahoo Finance is the following:

aapl_data = vbt.YFData.download(
    'AAPL',
    interval='5m', 
    missing_index='drop',
    start='2022-07-01'
)

aapl_close = aapl_data.get('Close')

If you get an error about data quantity – increase your start date. Also in the code, I’m getting only close of my data because I’ll use only it in my calculations.

Next, let’s compute moving averages variables:

fast_ma = vbt.MA.run(aapl_close, 10, short_name='fast MA')
slow_ma = vbt.MA.run(aapl_close, 50, short_name='fast MA')

After that I’m computing entry/exit signals for the backtest:

long_entries = fast_ma.ma_crossed_above(slow_ma)
short_entries = fast_ma.ma_crossed_below(slow_ma)

Now we already can run our strategy:

pf = vbt.Portfolio.from_signals(
    aapl_close,
    entries=long_entries,
    short_entries=short_entries, 
    freq = '5m'
)

When you run the strategy also provide a parameter with frequency so it will know how to compute certain metrics. So backtest is computed so now you can check its performance:

pf.stats()
Start                         2022-07-01 13:30:00+00:00
End                           2022-08-15 20:00:00+00:00
Period                                  8 days 09:35:00
Start Value                                       100.0
End Value                                     97.434231
Total Return [%]                              -2.565769
Benchmark Return [%]                          26.600876
Max Gross Exposure [%]                            100.0
Total Fees Paid                                     0.0
Max Drawdown [%]                               8.293664
Max Drawdown Duration                   7 days 09:40:00
Total Trades                                         50
Total Closed Trades                                  49
Total Open Trades                                     1
Open Trade PnL                                 1.907165
Win Rate [%]                                  34.693878
Best Trade [%]                                 3.890129
Worst Trade [%]                               -1.932058
Avg Winning Trade [%]                          1.159227
Avg Losing Trade [%]                          -0.749084
Avg Winning Trade Duration    0 days 06:43:14.117647058
Avg Losing Trade Duration               0 days 01:51:15
Profit Factor                                  0.809225
Expectancy                                    -0.091284
Sharpe Ratio                                  -1.715084
Calmar Ratio                                   -8.16064
Omega Ratio                                    0.982959
Sortino Ratio                                  -2.37456
dtype: object

Or plot results on a chart:

fig = pf.plot(subplots=['orders','trade_pnl','cum_returns'])
fast_ma.ma.vbt.plot(fig=fig)
slow_ma.ma.vbt.plot(fig=fig)
fig.show()

Here is the full code of the backtest of this article:

import vectorbt as vbt

aapl_data = vbt.YFData.download(
    'AAPL',
    interval='5m', 
    missing_index='drop',
    start='2022-06-18'
)

aapl_close = aapl_data.get('Close')

fast_ma = vbt.MA.run(aapl_close, 10, short_name='fast MA')
slow_ma = vbt.MA.run(aapl_close, 50, short_name='fast MA')

long_entries = fast_ma.ma_crossed_above(slow_ma)
short_entries = fast_ma.ma_crossed_below(slow_ma)

pf = vbt.Portfolio.from_signals(
    aapl_close,
    entries=long_entries,
    short_entries=short_entries, 
    freq = '5m'
)

pf.stats()

fig = pf.plot(subplots=['orders','trade_pnl','cum_returns'])
fast_ma.ma.vbt.plot(fig=fig)
slow_ma.ma.vbt.plot(fig=fig)
fig.show()

Off course, Yahoo Finance is not perfect to run intraday strategies for stocks, but it can be a good place to start. In future articles, I’ll share with you better-suited APIs.


Follow me on TradingView and YouTube.

This image has an empty alt attribute; its file name is wide.png

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Pine Script Programming Courses
Pine Script Programming Courses
Learn to build your own TradingView Indicators and Strategies
Sidebar Signup Form
If you want to be the first in this business, subscribe to the latest news