Retrieval Of 5 Minutes Bars For Backtesting

Hi

I’m trying to build a scalp strategy for 5min bars (just began).
However, I can’t find a way to retrieve the 5 min bars for the last 22 days.
Here is the code I’m using ‘tradingbot.py’

from config import ALPACA_CONFIG
from datetime import datetime, timedelta
from lumibot.backtesting import YahooDataBacktesting
from lumibot.brokers import Alpaca
from lumibot.strategies import Strategy
from lumibot.traders import Trader
import numpy as np
import pandas as pd

# General trading parameters
sleeptime = "1H"  # Interval between trading iterations
symbol = "SPY"  # Symbol to trade
start_test = "2023-06-24"
cash_at_risk = 0.02  # 2% of available cash at risk
risk_reward_ratio = 3  # Risk-reward ratio for profit target calculation
num_bars = 1716  # Number of 5-minute bars to retrieve (22 trading days of 5-minute bars). It assumes that a typical trading day has 390 minutes (6.5 hours) of trading. Therefore, in 22 trading days, there are 22×390/5=1716 => 5-minute bars.

class Trend(Strategy):

    def initialize(self):
        self.signal = None
        self.symbol = symbol
        self.sleeptime = sleeptime
        self.start = start_test
        self.last_trade = None
        self.cash_at_risk = cash_at_risk
        self.risk_reward_ratio = risk_reward_ratio

    def position_sizing(self):
        """Calculate position sizing based on available cash and risk."""
        cash = self.get_cash()
        last_price = self.get_last_price(self.symbol)
        quantity = round(cash / last_price, 0)
        return cash, last_price, quantity

    def calculate_stop_loss(self, entry_price, long=True):
        """Calculate the stop loss point."""
        cash = self.get_cash()
        position_size = cash / entry_price
        risk_amount = cash * self.cash_at_risk
        risk_per_share = risk_amount / position_size
        
        if long:
            stop_loss = entry_price - risk_per_share
        else:
            stop_loss = entry_price + risk_per_share
        
        return stop_loss

    def calculate_target_point(self, entry_price, long=True):
        """Calculate the target point."""
        cash = self.get_cash()
        position_size = cash / entry_price
        risk_amount = cash * self.cash_at_risk
        risk_per_share = risk_amount / position_size
        reward_per_share = risk_per_share * self.risk_reward_ratio
        
        if long:
            target_point = entry_price + reward_per_share
        else:
            target_point = entry_price - reward_per_share
        
        return target_point

    def on_trading_iteration(self):
        bars = self.get_historical_prices(self.symbol, num_bars, "5 minute")
        data = bars.df
        
        data['9-period'] = data['close'].rolling(9).mean()
        data['21-period'] = data['close'].rolling(21).mean()
        data['Signal'] = np.where(np.logical_and(data['9-period'] > data['21-period'],
                                                 data['9-period'].shift(1) < data['21-period'].shift(1)),
                                  "BUY", None)
        data['Signal'] = np.where(np.logical_and(data['9-period'] < data['21-period'],
                                                 data['9-period'].shift(1) > data['21-period'].shift(1)),
                                  "SELL", data['Signal'])
        self.signal = data.iloc[-1].Signal
        
        cash, last_price, quantity = self.position_sizing()
        
        if self.signal == 'BUY':
            stop_loss = self.calculate_stop_loss(last_price, long=True)
            target_point = self.calculate_target_point(last_price, long=True)
            pos = self.get_position(self.symbol)
            if pos is not None:
                self.sell_all()
                
            order = self.create_order(self.symbol, quantity, "buy")
            self.submit_order(order)
            # Here you should implement setting the stop loss and target point in your trading platform

        elif self.signal == 'SELL':
            stop_loss = self.calculate_stop_loss(last_price, long=False)
            target_point = self.calculate_target_point(last_price, long=False)
            pos = self.get_position(self.symbol)
            if pos is not None:
                self.sell_all()
                
            order = self.create_order(self.symbol, quantity, "sell")
            self.submit_order(order)
            # Here you should implement setting the stop loss and target point in your trading platform

if __name__ == "__main__":
    trade = False
    if trade:
        broker = Alpaca(ALPACA_CONFIG)
        strategy = Trend(broker=broker)
        bot = Trader()
        bot.add_strategy(strategy)
        bot.run_all()
    else:
        start = datetime(2023, 6, 24)
        end = datetime(2024, 6, 23)
        Trend.backtest(
            YahooDataBacktesting,
            start,
            end
        )

BTW ‘config.py’ => ALPACA_CONFIG is just

API_KEY = ""
SECRET_KEY = ""

ALPACA_CONFIG = {
# Put your own Alpaca key here:
"API_KEY": "XXXXX",
# Put your own Alpaca secret here:
"API_SECRET": "XXXXX",
# If you want to go live, you must change this
"ENDPOINT": "https://paper-api.alpaca.markets",
}

What am I doing wrong?
How can I retrieve the 5 min bars and test the strategy?

Thanks in advance,
Z

@ziv I’m certainly not a lumibot expert, but from the documentation it seems you may need to enter the timestep as "5 minutes" (notice the “s”). Your code has “5 minute”. Not sure if that’s the issue but maybe give it a try.

Hi Dan

Thank you very much for the quick reply.
Unfortunately it didn’t work - no luck…
I’ve tried every combination I can think of, still receiving errors such as

tradingbot.py", line 66, in on_trading_iteration
    bars = self.get_historical_prices(self.symbol, num_bars, "5 minutes")

AND

...lumibot/data_sources/data_source.py", line 283, in _parse_source_timestep
    raise UnavailabeTimestep(self.SOURCE, timestep)
lumibot.data_sources.exceptions.UnavailabeTimestep: YAHOO data source does not have data with '5 minutes' timestep

I’m using ‘lumibot’ because I’ve seen some examples of it in Youtube and it looks solid, but ALL these examples (like this or this ) were using DAILY bars data and I’m interested in developing scalp strategy.

If anyone knows how to make this happen, it would be great.
however, I’m also open to other suggestions how to develop my strategy without using ‘lumibot’.

Thank you,
Ziv

You’d need to look at the documentation for the data source you are using, find what are the available timesteps and then use the correct key for 5 minute bars.

Why not just use the Alpaca historical data?

Well, I’ve found the reason… :grimacing:
From lumibot website

Backtesting

Lumibot has three modes for backtesting.

  1. Yahoo Backtesting: Daily stock backtesting with data from Yahoo.
  2. Pandas Backtesting: Intra-day and inter-day testing of stocks and futures using CSV data supplied by you.
  3. Polygon Backtesting: Intra-day and inter-day testing of stocks and futures using Polygon data from polygon.io

Thank you for your help