Asset Classes
US Equities
Trades
To get historical trade data, call the history
method with the TradeBar
type and a security's Symbol
.
This method returns a DataFrame with columns for the open, high, low, close, and volume.
class USEquityTradeBarHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_equity('SPY').symbol # Get the 5 trailing daily TradeBar objects of the security in DataFrame format. history = self.history(TradeBar, symbol, 5, Resolution.DAILY)
close | high | low | open | volume | ||
---|---|---|---|---|---|---|
symbol | time | |||||
SPY | 2024-12-12 16:00:00 | 604.33 | 607.160 | 604.33 | 606.64 | 24962360.0 |
2024-12-13 16:00:00 | 604.21 | 607.100 | 602.82 | 606.38 | 29250856.0 | |
2024-12-16 16:00:00 | 606.79 | 607.775 | 605.22 | 606.00 | 33686372.0 | |
2024-12-17 16:00:00 | 604.29 | 605.160 | 602.89 | 604.22 | 38527534.0 | |
2024-12-18 16:00:00 | 586.28 | 606.400 | 585.89 | 604.00 | 80642184.0 |
# Calculate the daily returns. daily_returns = history.close.pct_change().iloc[1:]
symbol time SPY 2024-12-13 16:00:00 -0.000199 2024-12-16 16:00:00 0.004270 2024-12-17 16:00:00 -0.004120 2024-12-18 16:00:00 -0.029804 Name: close, dtype: float64
If you intend to use the data in the DataFrame to create TradeBar
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of TradeBar
objects instead of a DataFrame, call the history[TradeBar]
method.
# Get the 5 trailing daily TradeBar objects of the security in TradeBar format. history = self.history[TradeBar](symbol, 5, Resolution.DAILY) # Iterate through the TradeBar objects and access their volumes. for trade_bar in history: t = trade_bar.end_time volume = trade_bar.volume
Quotes
To get historical quote data, call the history
method with the QuoteBar
type and a security's Symbol
.
This method returns a DataFrame with columns for the open, high, low, close, and size of the bid and ask quotes.
The columns that don't start with "bid" or "ask" are the mean of the quote prices on both sides of the market.
class USEquityQuoteBarHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_equity('SPY').symbol # Get the 5 trailing minute QuoteBar objects of the security in DataFrame format. history = self.history(QuoteBar, symbol, 5, Resolution.MINUTE)
askclose | askhigh | asklow | askopen | asksize | bidclose | bidhigh | bidlow | bidopen | bidsize | close | high | low | open | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
symbol | time | ||||||||||||||
SPY | 2024-12-18 15:56:00 | 588.65 | 590.44 | 588.60 | 590.42 | 10700.0 | 588.61 | 590.40 | 588.56 | 590.38 | 700.0 | 588.630 | 590.420 | 588.580 | 590.400 |
2024-12-18 15:57:00 | 588.37 | 588.92 | 588.25 | 588.65 | 100.0 | 588.34 | 588.89 | 588.24 | 588.61 | 100.0 | 588.355 | 588.905 | 588.245 | 588.630 | |
2024-12-18 15:58:00 | 588.13 | 588.50 | 588.08 | 588.37 | 100.0 | 588.11 | 588.47 | 588.06 | 588.34 | 500.0 | 588.120 | 588.485 | 588.070 | 588.355 | |
2024-12-18 15:59:00 | 587.93 | 588.34 | 587.70 | 588.13 | 8000.0 | 587.92 | 588.31 | 587.68 | 588.11 | 100.0 | 587.925 | 588.325 | 587.690 | 588.120 | |
2024-12-18 16:00:00 | 586.33 | 587.95 | 585.89 | 587.93 | 200.0 | 586.30 | 587.93 | 585.88 | 587.92 | 74700.0 | 586.315 | 587.940 | 585.885 | 587.925 |
# Calculate the spread at each minute. spread = history.askclose - history.bidclose
symbol time SPY 2024-12-18 15:56:00 0.04 2024-12-18 15:57:00 0.03 2024-12-18 15:58:00 0.02 2024-12-18 15:59:00 0.01 2024-12-18 16:00:00 0.03 dtype: float64
If you intend to use the data in the DataFrame to create QuoteBar
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of QuoteBar
objects instead of a DataFrame, call the history[QuoteBar]
method.
# Get the 5 trailing minute QuoteBar objects of the security in QuoteBar format. history = self.history[QuoteBar](symbol, 5, Resolution.MINUTE) # Iterate through each QuoteBar and calculate the dollar volume on the bid. for quote_bar in history: t = quote_bar.end_time bid_dollar_volume = quote_bar.last_bid_size * quote_bar.bid.close
Request second or minute resolution data. Otherwise, the history request won't return any data.
Ticks
To get historical tick data, call the history
method with a security's Symbol
and Resolution.TICK
.
This method returns a DataFrame that contains data on bids, asks, and last trade prices.
class USEquityTickHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_equity('SPY').symbol # Get the trailing 2 days of ticks for the security in DataFrame format. history = self.history(symbol, timedelta(2), Resolution.TICK)
askprice | asksize | bidprice | bidsize | exchange | lastprice | quantity | ||
---|---|---|---|---|---|---|---|---|
symbol | time | |||||||
SPY | 2024-12-17 09:30:00.000214 | 0.00 | 0.0 | 604.17 | 1000.0 | NASDAQ | 604.17 | 0.0 |
2024-12-17 09:30:00.000214 | 604.19 | 1900.0 | 0.00 | 0.0 | ARCA | 604.19 | 0.0 | |
2024-12-17 09:30:00.001110 | NaN | NaN | NaN | NaN | NYSE | 604.19 | 100.0 | |
2024-12-17 09:30:00.001480 | NaN | NaN | NaN | NaN | ARCA | 604.19 | 69.0 | |
2024-12-17 09:30:00.001482 | 0.00 | 0.0 | 604.17 | 1000.0 | NASDAQ | 604.17 | 0.0 |
# Select the rows in the DataFrame that represent trades. Drop the bid/ask columns since they are NaN. trade_ticks = history[history.quantity > 0].dropna(axis=1)
exchange | lastprice | quantity | ||
---|---|---|---|---|
symbol | time | |||
SPY | 2024-12-17 09:30:00.001110 | NYSE | 604.19 | 100.0 |
2024-12-17 09:30:00.001480 | ARCA | 604.19 | 69.0 | |
2024-12-17 09:30:00.001483 | ARCA | 604.19 | 100.0 | |
2024-12-17 09:30:00.001483 | ARCA | 604.19 | 231.0 | |
2024-12-17 09:30:00.001564 | NASDAQ | 604.19 | 100.0 |
If you intend to use the data in the DataFrame to create Tick
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of Tick
objects instead of a DataFrame, call the history[Tick]
method.
# Get the trailing 2 days of ticks for the security in Tick format. history = self.history[Tick](symbol, timedelta(2), Resolution.TICK) # Iterate through each quote tick and calculate the quote size. for tick in history: if tick.tick_type == TickType.Quote: t = tick.end_time size = max(tick.bid_size, tick.ask_size)
Ticks are a sparse dataset, so request ticks over a trailing period of time or between start and end times.
Slices
To get historical Slice data, call the history
method without passing any Symbol
objects.
This method returns Slice
objects, which contain data points from all the datasets in your algorithm.
If you omit the resolution
argument, it uses the resolution that you set for each security and dataset when you created the subscriptions.
class SliceHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Add some securities and datasets. self.add_equity('SPY') # Get the historical Slice objects over the last 5 days for all the subcriptions in your algorithm. history = self.history(5, Resolution.DAILY) # Iterate through each historical Slice. for slice_ in history: # Iterate through each TradeBar in this Slice. for symbol, trade_bar in slice_.bars.items(): close = trade_bar.close
Fundamentals
To get historical fundamental data, call the history
method with the Fundamental
type and an asset's Symbol
.
This method returns a DataFrame with columns for the data point attributes.
class USEquityFundamentalHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 27) # Get the Symbol of an asset. symbol = self.add_equity('AAPL').symbol # Get the 3 trailing daily Fundamental objects of the asset in DataFrame format. history = self.history(Fundamental, symbol, 3, Resolution.DAILY)
adjustedprice | assetclassification | companyprofile | companyreference | dollarvolume | earningratios | earningreports | financialstatements | hasfundamentaldata | market | marketcap | operationratios | pricefactor | pricescalefactor | securityreference | splitfactor | valuationratios | value | volume | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
symbol | time | |||||||||||||||||||
AAPL | 2024-12-17 | 250.764283 | QuantConnect.Data.Fundamental.AssetClassification | QuantConnect.Data.Fundamental.CompanyProfile | QuantConnect.Data.Fundamental.CompanyReference | 1.140352e+10 | QuantConnect.Data.Fundamental.EarningRatios | QuantConnect.Data.Fundamental.EarningReports | QuantConnect.Data.Fundamental.FinancialStatements | True | usa | 3587438272590 | QuantConnect.Data.Fundamental.OperationRatios | 0.998902 | 0.998902 | QuantConnect.Data.Fundamental.SecurityReference | 1.0 | QuantConnect.Data.Fundamental.ValuationRatios | 251.04 | 45425121 |
2024-12-18 | 253.201603 | QuantConnect.Data.Fundamental.AssetClassification | QuantConnect.Data.Fundamental.CompanyProfile | QuantConnect.Data.Fundamental.CompanyReference | 1.196673e+10 | QuantConnect.Data.Fundamental.EarningRatios | QuantConnect.Data.Fundamental.EarningReports | QuantConnect.Data.Fundamental.FinancialStatements | True | usa | 3587438272590 | QuantConnect.Data.Fundamental.OperationRatios | 0.998902 | 0.998902 | QuantConnect.Data.Fundamental.SecurityReference | 1.0 | QuantConnect.Data.Fundamental.ValuationRatios | 253.48 | 47209742 | |
2024-12-19 | 247.777567 | QuantConnect.Data.Fundamental.AssetClassification | QuantConnect.Data.Fundamental.CompanyProfile | QuantConnect.Data.Fundamental.CompanyReference | 1.284373e+10 | QuantConnect.Data.Fundamental.EarningRatios | QuantConnect.Data.Fundamental.EarningReports | QuantConnect.Data.Fundamental.FinancialStatements | True | usa | 3587438272590 | QuantConnect.Data.Fundamental.OperationRatios | 0.998902 | 0.998902 | QuantConnect.Data.Fundamental.SecurityReference | 1.0 | QuantConnect.Data.Fundamental.ValuationRatios | 248.05 | 51778802 |
# Get the Current Ratio of each row. current_ratios = history.apply(lambda row: row.operationratios.current_ratio.value, axis=1)
symbol time AAPL 2024-12-24 0.867313 2024-12-25 0.867313 2024-12-27 0.867313 dtype: float64
To avoid consuming unnecessary computational resources populating the DataFrame, you can instead request Fundamental
objects.
To get a list of Fundamental
objects, call the history[Fundamental]
method.
# Get the 3 trailing daily Fundamental objects of an asset in Fundamental format. history = self.history[Fundamental](symbol, 3, Resolution.DAILY) # Iterate through each Fundamental object and access its properites. for fundamental in history: symbol = fundamental.symbol pe_ratio = fundamental.valuation_ratios.pe_ratio
Splits
To get historical split data, call the history
method with the Split
type and an asset's Symbol
.
This method returns a DataFrame with columns for the reference price, split factor, and split type.
Splits are a sparse dataset, so use a time period history request since most days have no data.
class USEquitySplitHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Get the Symbol of an asset. symbol = self.add_equity('AAPL').symbol # Get the splits that occured for the stock over the last 5 years in DataFrame format. history = self.history(Split, symbol, timedelta(5*365))
referenceprice | splitfactor | type | value | ||
---|---|---|---|---|---|
symbol | time | ||||
AAPL | 2020-08-28 | 0.00 | 0.25 | 0 | 0.00 |
2020-08-31 | 499.23 | 0.25 | 1 | 499.23 |
In the preceding DataFrame, the type
column represents the SplitType
enumeration, where 0=SplitType.WARNING
and 1=SplitType.SPLIT_OCCURRED
.
# Select the prices where splits occurred. split_prices = history[history.type == SplitType.SPLIT_OCCURRED].value
symbol time AAPL 2020-08-31 499.23 Name: value, dtype: float64
If you intend to use the data in the DataFrame to create Split
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of Split
objects instead of a DataFrame, call the history[Split]
method.
# Get the splits that occured for a stock over the last 5 years in Split format. history = self.history[Split](symbol, timedelta(5*365)) # Iterate through each Split object. for split in history: # Select the time when each split occurred. if split.type == SplitType.SPLIT_OCCURRED: t = split.end_time
Dividends
To get historical dividend data, call the history
method with the Dividend
type and an asset's Symbol
.
This method returns a DataFrame with columns for the dividend payment and reference price.
Dividends are a sparse dataset, so use a time period history request since most days have no data.
class USEquityDividendHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Get the Symbol of an asset. symbol = self.add_equity('AAPL').symbol # Get the dividends that the stock paid over the last 2 years in DataFrame format. history = self.history(Dividend, symbol, timedelta(2*365))
distribution | referenceprice | value | ||
---|---|---|---|---|
symbol | time | |||
AAPL | 2022-12-23 | 0.17 | 132.23 | 0.17 |
2023-02-10 | 0.23 | 150.87 | 0.23 | |
2023-05-12 | 0.24 | 173.75 | 0.24 | |
2023-08-11 | 0.24 | 177.97 | 0.24 | |
2023-11-10 | 0.24 | 182.41 | 0.24 |
# Calculate the mean dividend payment. mean_dividend = history.distribution.mean()
If you intend to use the data in the DataFrame to create Dividend
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of Dividend
objects instead of a DataFrame, call the history[Dividend]
method.
# Get the dividends that a stock paid over the last 2 years in Dividend format. history = self.history[Dividend](symbol, timedelta(2*365)) # Iterate through each Dividend object. for dividend in history: distribution = dividend.distribution
Symbol Changes
To get historical symbol change data, call the history
method with the SymbolChangedEvent
type and an asset's Symbol
.
This method returns a DataFrame with columns for the old symbol and new symbol during each change.
class USEquitySymbolChangedEventHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Get the Symbol of an asset. symbol = self.add_equity('META').symbol # Get the symbol changes of the stock over the last 10 years in DataFrame format. history = self.history(SymbolChangedEvent, symbol, timedelta(10*365))
newsymbol | oldsymbol | ||
---|---|---|---|
symbol | time | ||
META | 2022-06-09 | META | FB |
# Select the dates of each ticker change. dates = list(history.index.levels[1])
If you intend to use the data in the DataFrame to create SymbolChangedEvent
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of SymbolChangedEvent
objects instead of a DataFrame, call the history[SymbolChangedEvent]
method.
# Get the symbol changes of a stock over the last 10 years in SymbolChangedEvent format. history = self.history[SymbolChangedEvent](symbol, timedelta(10*365)) # Iterate through each SymbolChangedEvent object. for symbol_changed_event in history: t = symbol_changed_event.end_time old_symbol = symbol_changed_event.old_symbol new_symbol = symbol_changed_event.new_symbol
Delistings
To get historical delisting data, call the history
method with the Delisting
type and an asset's Symbol
.
This method returns a DataFrame with columns for the old symbol and new symbol during each change.
Delistings are a sparse dataset, so use a time period history request since most days have no data.
class USEquityDelistingHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Get the Symbol of an asset. symbol = self.add_equity('BBBY').symbol # Get the deslistings of the asset over the last 10 years in DataFrame format. history = self.history(Delisting, symbol, timedelta(10*365))
type | ||
---|---|---|
symbol | time | |
BBBY | 2023-05-02 | 0 |
2023-05-03 | 1 |
In the preceding DataFrame, the type
column represents the DelistingType
enumeration, where 0=DelistingType.WARNING
and 1=DelistingType.DELISTED
.
# Select the rows in the DataFrame that represent deslist warnings. warnings = history[history.type == DelistingType.WARNING].type
symbol time BBBY 2023-05-02 0 Name: type, dtype: int64
If you intend to use the data in the DataFrame to create Delisting
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of Delisting
objects instead of a DataFrame, call the history[Delisting]
method.
# Get the deslistings of an asset over the last 10 years in Delisting format. history = self.history[Delisting](symbol, timedelta(10*365)) # Iterate through each Deslisting object and access the warning dates. for deslisting in history: if deslisting.type == DelistingType.WARNING: warning_date = deslisting.end_time
Universes
To get historical universe data, call the history
method with the Universe
object.
This method returns a DataFrame with columns for the data point attributes.
class USEquityUniverseHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 23) # Add a universe of US Equities based on the constituents of an ETF. universe = self.add_universe(self.universe.etf('SPY')) # Get 5 days of history for the universe. history = self.history(universe, timedelta(5), flatten=True)
lastupdate | period | sharesheld | weight | ||
---|---|---|---|---|---|
time | symbol | ||||
2024-12-19 | A RPTMYV3VC57P | 2024-12-17 | 1 days | 3682327.0 | 0.000777 |
AAPL R735QTJ8XC9X | 2024-12-17 | 1 days | 191633535.0 | 0.075065 | |
ABBV VCY032R250MD | 2024-12-17 | 1 days | 22256743.0 | 0.006032 | |
ABNB XK8H247DY6W5 | 2024-12-17 | 1 days | 5536841.0 | 0.001131 | |
ABT R735QTJ8XC9X | 2024-12-17 | 1 days | 21919703.0 | 0.003837 | |
... | ... | ... | ... | ... | ... |
2024-12-21 | XYL V18KR26TE3XH | 2024-12-19 | 1 days | 2947931.0 | 0.000569 |
YUM R735QTJ8XC9X | 2024-12-19 | 1 days | 3412693.0 | 0.000737 | |
ZMH S6ZZPKTVDY05 | 2024-12-19 | 1 days | 2471688.0 | 0.000433 | |
ZBRA R735QTJ8XC9X | 2024-12-19 | 1 days | 625772.0 | 0.000400 | |
ZTS VDRJHVQ4FNFP | 2024-12-19 | 1 days | 5484351.0 | 0.001486 |
# Select the 2 assets with the smallest weights in the ETF each day. daily_smallest = history.groupby('time').apply(lambda x: x.nsmallest(2, 'weight')).reset_index(level=1, drop=True).weight
time symbol 2024-12-19 AMTMW YM37RIGZUD0L 0.000053 NWSVV VHJF6S7EZRL1 0.000068 2024-12-20 AMTMW YM37RIGZUD0L 0.000051 NWSVV VHJF6S7EZRL1 0.000069 2024-12-21 AMTMW YM37RIGZUD0L 0.000048 NWSVV VHJF6S7EZRL1 0.000069 Name: weight, dtype: float64
To get the data in the format of the objects that you receive in your universe filter function instead of a DataFrame, use flatten=False
.
This call returns a Series where the values are lists of the universe data objects.
# Get the historical universe data over the last 30 days in a Series where # the values in the series are lists of the universe selection objects. history = self.history(universe, timedelta(30), flatten=False) # Iterate through each day of universe selection. for (universe_symbol, end_time), constituents in history.items(): # Select the 10 largest assets in the ETF on this day. largest = sorted(constituents, key=lambda c: c.weight)[-10:]
Alternative Data
To get historical alternative data, call the history
method with the dataset Symbol
.
This method returns a DataFrame that contains the data point attributes.
class USEquityAlternativeDataHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of an asset. symbol = self.add_equity('GME').symbol # Add the alternative dataset and save a reference to its Symbol. dataset_symbol = self.add_data(QuiverWallStreetBets, symbol).symbol # Get the trailing 5 days of QuiverWallStreetBets data for the asset in DataFrame format. history = self.history(dataset_symbol, 5, Resolution.DAILY)
date | mentions | rank | sentiment | ||
---|---|---|---|---|---|
symbol | time | ||||
GME.QuiverWallStreetBets | 2024-12-15 | 2024-12-14 | 2 | 48 | 0.74245 |
2024-12-16 | 2024-12-15 | 1 | 136 | -0.51600 | |
2024-12-17 | 2024-12-16 | 8 | 53 | 0.13987 | |
2024-12-18 | 2024-12-17 | 17 | 32 | 0.08564 | |
2024-12-19 | 2024-12-18 | 4 | 117 | 0.61682 |
# Calculate the changes in sentiment. sentiment_diff = history.sentiment.diff().iloc[1:]
symbol time GME.QuiverWallStreetBets 2024-12-16 -1.25845 2024-12-17 0.65587 2024-12-18 -0.05423 2024-12-19 0.53118 Name: sentiment, dtype: float64
If you intend to use the data in the DataFrame to create alternativeDataClass
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of dataset objects instead of a DataFrame, call the history[alternativeDataClass]
method.
# Get the trailing 5 days of QuiverWallStreetBets data for an asset in QuiverWallStreetBets format. history = self.history[QuiverWallStreetBets](dataset_symbol, 5, Resolution.DAILY) # Iterate through each QuiverWallStreetBets object. for data_point in history: t = data_point.end_time sentiment = data_point.sentiment
Some alternative datasets provide multiple entries per asset per time step.
For example, the True Beats dataset provides EPS and revenue predictions for several upcoming quarters per asset per day.
In this case, to organize the data into a DataFrame, set the flatten
argument to True
.
class USEquityTrueBeatsHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 1, 3) # Get the ExtractAlphaTrueBeats data for AAPL on 01/02/2024 organized in a flat DataFrame. aapl = self.add_equity("AAPL", Resolution.DAILY) aapl.true_beats = self.add_data(ExtractAlphaTrueBeats, aapl.symbol).symbol history = self.history( aapl.true_beats, datetime(2024, 1, 2), datetime(2024, 1, 3), Resolution.DAILY, flatten=True )
analystestimatescount | annual | earningsmetric | end | expectedreportdate | expertbeat | fiscalquarter | fiscalyear | managementbeat | quarterly | time | trendbeat | truebeat | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
time | symbol | |||||||||||||
2024-01-02 12:30:00 | AAPL.ExtractAlphaTrueBeats | 28 | False | 0 | 2023-12-31 | 2024-01-25 | -0.001241 | 4.0 | 2023 | 0.013694 | True | 2024-01-02 12:30:00 | 0.016899 | 0.029352 |
AAPL.ExtractAlphaTrueBeats | 29 | True | 0 | 2024-09-30 | 2024-10-24 | NaN | NaN | 2024 | NaN | False | 2024-01-02 12:30:00 | NaN | -0.020608 | |
AAPL.ExtractAlphaTrueBeats | 24 | False | 0 | 2024-03-31 | 2024-04-25 | NaN | 1.0 | 2024 | NaN | True | 2024-01-02 12:30:00 | NaN | -0.016578 | |
AAPL.ExtractAlphaTrueBeats | 24 | False | 0 | NaT | NaT | NaN | 2.0 | 2024 | NaN | True | 2024-01-02 12:30:00 | NaN | 0.011859 | |
AAPL.ExtractAlphaTrueBeats | 26 | False | 0 | NaT | NaT | NaN | 3.0 | 2024 | NaN | True | 2024-01-02 12:30:00 | NaN | 0.017517 | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | |
AAPL.ExtractAlphaTrueBeats | 11 | False | 0 | NaT | NaT | NaN | 1.0 | 2025 | NaN | True | 2024-01-02 12:30:00 | NaN | -0.009165 | |
AAPL.ExtractAlphaTrueBeats | 11 | False | 0 | NaT | NaT | NaN | 2.0 | 2025 | NaN | True | 2024-01-02 12:30:00 | NaN | -0.020219 | |
AAPL.ExtractAlphaTrueBeats | 11 | False | 0 | NaT | NaT | NaN | 3.0 | 2025 | NaN | True | 2024-01-02 12:30:00 | NaN | -0.042210 | |
AAPL.ExtractAlphaTrueBeats | 1 | False | 0 | NaT | NaT | NaN | 4.0 | 2025 | NaN | True | 2024-01-02 12:30:00 | NaN | 0.000000 | |
AAPL.ExtractAlphaTrueBeats | 10 | True | 0 | NaT | NaT | NaN | NaN | 2026 | NaN | False | 2024-01-02 12:30:00 | NaN | -0.001965 |
# Calculate the mean TrueBeat estimate for each day. mean_true_beats_by_day = history.drop('time', axis=1).groupby('time').apply(lambda g: g.truebeat.mean())
time 2024-01-02 12:30:00 -0.007034 dtype: float64
For information on historical data for other alternative datasets, see the documentation in the Dataset Market.
Indicators
To get historical indicator values, call the indicator_history
method with an indicator and the security's Symbol
.
class USEquityIndicatorHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_equity('SPY').symbol # Get the 21-day SMA values of the security for the last 5 trading days. history = self.indicator_history(SimpleMovingAverage(21), symbol, 5, Resolution.DAILY)
To organize the data into a DataFrame, use the data_frame
property of the result.
# Organize the historical indicator data into a DataFrame to enable pandas wrangling. history_df = history.data_frame
current | rollingsum | |
---|---|---|
2024-12-12 16:00:00 | 599.186667 | 12582.92 |
2024-12-13 16:00:00 | 599.520952 | 12589.94 |
2024-12-16 16:00:00 | 600.160952 | 12603.38 |
2024-12-17 16:00:00 | 601.043810 | 12621.92 |
2024-12-18 16:00:00 | 600.954762 | 12620.05 |
# Get the maximum of the SMA values. sma_max = history_df.current.max()
The indicator_history
method resets your indicator, makes a history request, and updates the indicator with the historical data.
Just like with regular history requests, the indicator_history
method supports time periods based on a trailing number of bars, a trailing period of time, or a defined period of time.
If you don't provide a resolution
argument, it defaults to match the resolution of the security subscription.
To make the indicator_history
method update the indicator with an alternative price field instead of the close (or mid-price) of each bar, pass a selector
argument.
# Get the historical values of an indicator over the last 30 days, applying the indicator to the security's volume. history = self.indicator_history(indicator, symbol, timedelta(30), selector=Field.VOLUME)
Some indicators require the prices of two securities to compute their value (for example, Beta).
In this case, pass a list of the Symbol
objects to the method.
class USEquityMultiAssetIndicatorHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Add the target and reference securities. target_symbol = self.add_equity('AAPL').symbol reference_symbol = self.add_equity('SPY').symbol # Create a 21-period Beta indicator. beta = Beta("", target_symbol, reference_symbol, 21) # Get the historical values of the indicator over the last 10 trading days. history = self.indicator_history(beta, [target_symbol, reference_symbol], 10, Resolution.DAILY) # Get the average Beta value. beta_avg = history.data_frame.mean()
Short Availability
To get historical values for the borrow fee rate, borrow rebate rate, or shortable quantity of a US Equity, call the fee_rate
, rebate_rate
, or shortable_quantity
methods of its shortable provider.
class USEquityShortAvailabilityHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Add an asset and save a reference to its Equity object. security = self.add_equity('SPY') # Overwrite the default shortable provider to one that provides data. security.set_shortable_provider(InteractiveBrokersShortableProvider()) # Select a time in the past. t = self.time - timedelta(30) # Pass the time argument to shortable provider to get historical values. fee_rate = security.shortable_provider.fee_rate(security.symbol, t) rebate_rate = security.shortable_provider.rebate_rate(security.symbol, t) shortable_quantity = security.shortable_provider.shortable_quantity(security.symbol, t)
For more information about security initializers, see Set Security Initializer.
Examples
The following examples demonstrate some common practices for trading using historical requests.
Example 1: Mean-Variance Portfolio
The following algorithm constructs a monthly rebalance mean-variance portfolio using the top 20 liquid equities. The position sizing can be optimized by 1-year historical daily return of the universe members.
from Portfolio.MaximumSharpeRatioPortfolioOptimizer import MaximumSharpeRatioPortfolioOptimizer class HistoricalRequestAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 4, 1) self.set_end_date(2020, 9, 30) # Monthly renewal of the top 20 liquid universe to trade popular stocks. self.universe_settings.schedule.on(self.date_rules.month_start()) self._universe = self.add_universe(self.universe.dollar_volume.top(20)) # Instantiate the optimizer to perform mean-variance optimization. # Mean-variance optimization will not consider a risk-free rate, so we use 0. self._optimizer = MaximumSharpeRatioPortfolioOptimizer(0.0, 1.0, 0.0) # Set a scheduled event to rebalance the portfolio at the start of every month. self.schedule.on( self.date_rules.month_start(), self.time_rules.at(9, 31), self.rebalance ) def rebalance(self) -> None: # Historical data request to get 1-year data for optimization. symbols = self._universe.selected history = self.history(symbols, 253, Resolution.DAILY).close.unstack(0).dropna() # Daily return on the universe members to calculate the optimized weights. returns = history.pct_change().dropna() # Calculate the optimized weights. weights = self._optimizer.optimize(returns) # Rebalance the portfolio according to the optimized weights. targets = [PortfolioTarget(symbol, size) for symbol, size in zip(symbols, weights)] self.set_holdings(targets, liquidate_existing_holdings=True)
Other Examples
For more examples, see the following algorithms: