Historical Data
Getting Started
Introduction
There are two ways to request historical data in your algorithms: direct historical data requests and indirect algorithm warm up.
History Requests
History requests return all of the data you request as a single object. Follow these steps to get some historical data:
- Create a new project.
- In the
initialize
Initialize
method, add an asset. - Call the
history
History
method with the asset's Symbol and a lookback period.
Projects contain files to run backtests, launch research notebooks, perform parameter optimizations, and deploy live trading strategies. You need to create projects in order to create strategies and share your work with other members.
The process to create a new project depends on if you use the Cloud Platform, Local Platform, or CLI.
The Initialize
initialize
method is the entry point of your algorithm where you define a series of settings, including security subscriptions, starting cash balances, and warm-up periods.
LEAN only calls the Initialize
initialize
method one time, at the start of your algorithm.
var spy = AddEquity("SPY");
spy = self.add_equity('SPY')
Symbol
objects are a way to identify or "finger-print" tradable assets so that no further database look-up is required.
All QuantConnect and LEAN Algorithm API methods use Symbol
objects to identify assets.
var history = History(spy.Symbol, 5, Resolution.Daily);
history = self.history(spy.symbol, 5, Resolution.DAILY)
close | high | low | open | volume | ||
---|---|---|---|---|---|---|
symbol | time | |||||
SPY | 2025-02-12 16:00:00 | 603.36 | 604.54 | 598.520 | 599.26 | 38247065.0 |
2025-02-13 16:00:00 | 609.73 | 609.94 | 603.215 | 604.43 | 36445673.0 | |
2025-02-14 16:00:00 | 609.70 | 610.99 | 609.080 | 609.98 | 23498431.0 | |
2025-02-18 16:00:00 | 611.49 | 611.49 | 608.390 | 610.86 | 24030531.0 | |
2025-02-19 16:00:00 | 612.93 | 613.23 | 609.560 | 610.04 | 26847903.0 |
Warm Up Periods
Warm-up simulates winding back the clock from the time you deploy the algorithm. In a backest, this is the start date of your algorithm. In live trading, it's the current date. Follow these steps to add a warm-up period to the start of your algorithm:
- Create a new project.
- In the
initialize
Initialize
method, set the backtest dates and add an asset. - In the
initialize
Initialize
method, call theset_warm_up
SetWarmUp
method with the warm-up duration. - In the
on_data
OnData
method, log the time and warm-up state.
The process to create a new project depends on if you use the Cloud Platform, Local Platform, or CLI.
SetStartDate(2024, 12, 1); SetEndDate(2024, 12, 2); AddEquity("SPY", Resolution.Daily);
self.set_start_date(2024, 12, 1) self.set_end_date(2024, 12, 2) self.add_equity("SPY", Resolution.DAILY)
SetWarmUp(10, Resolution.Daily);
self.set_warm_up(10, Resolution.DAILY)
Log($"IsWarmingUp at {Time}: {IsWarmingUp}");
self.log(f"self.is_warming_up at {self.time}: {self.is_warming_up}")
Algorithm starting warm up... IsWarmingUp at 11/22/2024 4:00:00 PM: True IsWarmingUp at 11/25/2024 4:00:00 PM: True IsWarmingUp at 11/26/2024 4:00:00 PM: True IsWarmingUp at 11/27/2024 4:00:00 PM: True IsWarmingUp at 11/29/2024 1:00:00 PM: True Algorithm finished warming up. IsWarmingUp at 12/2/2024 4:00:00 PM: False
Algorithm starting warm up... self.is_warming_up at 2024-11-22 16:00:00: True self.is_warming_up at 2024-11-25 16:00:00: True self.is_warming_up at 2024-11-26 16:00:00: True self.is_warming_up at 2024-11-27 16:00:00: True self.is_warming_up at 2024-11-29 13:00:00: True Algorithm finished warming up. self.is_warming_up at 2024-12-02 16:00:00: False
For more information about warm-up, see Warm Up Periods.
Examples
The following examples demonstrate some common practices for historical data.
Example 1: Simple Moving Average
The following example demonstrates weekly-resampled historical data to calculate the 50-week Simple Moving Average to implement an SMA-cross strategy.
public class HistoricalDataAlgorithm : QCAlgorithm { private Symbol _spy; private TradeBarConsolidator _consolidator; private RollingWindow<decimal> _window = new(50); public override void Initialize() { SetStartDate(2024, 1, 1); SetEndDate(2024, 12, 31); SetCash(100000); // Request SPY data for historical data call and trading. _spy = AddEquity("SPY", Resolution.Daily).Symbol; // Set up a consolidator to resample historical data to weekly. _consolidator = new TradeBarConsolidator(Calendar.Weekly); _consolidator.DataConsolidated += (_, updated) => _window.Add(updated.Close); // Set a scheduled event to trade SPY with a weekly SMA signal. Schedule.On(DateRules.WeekStart(_spy), TimeRules.AfterMarketOpen(_spy, 1), Trade); } private void Trade() { // Historical data call to calculate signal. var history = History<TradeBar>(_spy, 252, Resolution.Daily); // Obtain the weekly close price to calculate the weekly EMA. foreach (var bar in history) { _consolidator.Update(bar); } // Calculate the current 50-week SMA as a trading signal. var sma50 = _window.Average(); // Trade the SMA cross strategy. var price = history.Last().Close; if (price > sma50 && !Portfolio[_spy].IsLong) { SetHoldings(_spy, 1m); } else if (price < sma50 && !Portfolio[_spy].IsShort) { SetHoldings(_spy, -1m); } } }
class HistoricalDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 1, 1) self.set_end_date(2024, 12, 31) self.set_cash(100000) # Request SPY data for historical data call and trading. self.spy = self.add_equity("SPY", Resolution.DAILY).symbol # Set a scheduled event to trade SPY with a weekly SMA signal. self.schedule.on(self.date_rules.week_start(self.spy), self.time_rules.after_market_open(self.spy, 1), self.trade) def trade(self) -> None: # Historical data call to calculate signal. history = self.history(self.spy, 252, Resolution.DAILY) # Obtain the weekly close price to calculate the weekly SMA. weekly_close = history.unstack(0).close.resample("W").last() # Calculate the current 50-week SMA as a trading signal. sma50 = weekly_close.rolling(50).mean().iloc[-1, 0] # Trade the SMA cross strategy. price = self.securities[self.spy].price if price > sma50 and not self.portfolio[self.spy].is_long: self.set_holdings(self.spy, 1) elif price < sma50 and not self.portfolio[self.spy].is_short: self.set_holdings(self.spy, -1)