book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Asset Classes

Crypto

Introduction

This page explains how to get historical data for Crypto. Some of the data you can get include prices, indicators, and universe selection data.

Trades

To get historical trade data, call the History<TradeBar> method with a security's Symbol.

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.

public class CryptoTradeBarHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Get the Symbol of a security.
        var symbol = AddCrypto("BTCUSD").Symbol;
        // Get the 5 trailing daily TradeBar objects of the security. 
        var history = History<TradeBar>(symbol, 5, Resolution.Daily);
        // Iterate through each TradeBar and calculate its dollar volume.
        foreach (var bar in history)
        {
            var t = bar.EndTime;
            var dollarVolume = bar.Close * bar.Volume;
        }
    }
}
class CryptoTradeBarHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Get the Symbol of a security.
        symbol = self.add_crypto('BTCUSD').symbol
        # Get the 5 trailing daily TradeBar objects of the security in DataFrame format. 
        history = self.history(TradeBar, symbol, 5, Resolution.DAILY)
closehighlowopenvolume
symboltime
BTCUSD2024-12-15101399.99102650.00100600.00101423.264054.541500
2024-12-16104439.88105100.00101221.34101400.007216.743790
2024-12-17106099.81107857.79103289.21104445.1522263.157625
2024-12-18106150.00108388.88105337.97106099.9811729.293641
2024-12-19100150.73106528.1399939.82106147.7721659.470502
# Calculate the daily returns.
daily_returns = history.close.pct_change().iloc[1:]
symbol  time      
BTCUSD  2024-12-16    0.029979
        2024-12-17    0.015894
        2024-12-18    0.000473
        2024-12-19   -0.056517
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<QuoteBar> method with a security's Symbol.

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.

public class CryptoQuoteBarHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Get the Symbol of a security.
        var symbol = AddCrypto("BTCUSD", market: Market.Bitfinex).Symbol;
        // Get the 5 trailing minute QuoteBar objects of the security. 
        var history = History<QuoteBar>(symbol, 5, Resolution.Minute);
        // Iterate through the QuoteBar objects and calculate the spread.
        foreach (var bar in history)
        {
            var t = bar.EndTime;
            var spread = bar.Ask.Close - bar.Bid.Close;
        }
    }
}
class CryptoQuoteBarHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Get the Symbol of a security.
        symbol = self.add_crypto('BTCUSD', market=Market.BITFINEX).symbol
        # Get the 5 trailing minute QuoteBar objects of the security in DataFrame format. 
        history = self.history(QuoteBar, symbol, 5, Resolution.MINUTE)
askcloseaskhighasklowaskopenasksizebidclosebidhighbidlowbidopenbidsizeclosehighlowopen
symboltime
BTCUSD2024-12-19 04:56:00100830.0100830.0100830.0100830.00.496728100820.0100820.0100820.0100820.00.050586100825.0100825.0100825.0100825.0
2024-12-19 04:57:00100810.0100830.0100810.0100830.01.200384100800.0100820.0100800.0100820.00.130504100805.0100825.0100805.0100825.0
2024-12-19 04:58:00100760.0100810.0100760.0100810.00.520363100750.0100800.0100750.0100800.00.275894100755.0100805.0100755.0100805.0
2024-12-19 04:59:00100710.0100760.0100710.0100760.01.716247100700.0100750.0100700.0100750.00.270080100705.0100755.0100705.0100755.0
2024-12-19 05:00:00100710.0100710.0100710.0100710.00.712784100700.0100700.0100700.0100700.00.389266100705.0100705.0100705.0100705.0
# Calculate the spread at each minute.
spread = history.askclose - history.bidclose
symbol  time               
BTCUSD  2024-12-19 04:56:00    10.0
        2024-12-19 04:57:00    10.0
        2024-12-19 04:58:00    10.0
        2024-12-19 04:59:00    10.0
        2024-12-19 05:00:00    10.0
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

Ticks

To get historical tick data, call the History<Tick> method with a security's Symbol and Resolution.Tick.

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.

public class CryptoTickHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Get the Symbol of a security.
        var symbol = AddCrypto("BTCUSD", market: Market.Bitfinex).Symbol;
        // Get the trailing 2 days of ticks for the security.
        var history = History<Tick>(symbol, TimeSpan.FromDays(2), Resolution.Tick);
        // Select the ticks that represent trades, excluding the quote ticks.
        var trades = history.Where(tick => tick.TickType == TickType.Trade);
    }
}
class CryptoTickHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Get the Symbol of a security.
        symbol = self.add_crypto('BTCUSD', market=Market.BITFINEX).symbol
        # Get the trailing 2 days of ticks for the security in DataFrame format.
        history = self.history(symbol, timedelta(2), Resolution.TICK)
askpriceasksizebidpricebidsizelastpricequantity
symboltime
BTCUSD2024-12-17 05:00:00.915569106390.01.072804106380.016.521214106385.00.0
2024-12-17 05:00:01.119192106390.01.302212106380.016.521214106385.00.0
2024-12-17 05:00:05.981284106390.01.131937106380.016.521214106385.00.0
2024-12-17 05:00:07.302974106390.01.498471106380.016.521214106385.00.0
2024-12-17 05:00:07.514624106390.01.631937106380.016.521214106385.00.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)
lastpricequantity
symboltime
BTCUSD2024-12-17 05:00:13.647106380.00.201870
2024-12-17 05:01:13.130106390.00.000747
2024-12-17 05:01:23.446106380.00.197494
2024-12-17 05:01:31.421106390.00.031909
2024-12-17 05:01:31.460106390.00.000086

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 Historyhistory 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.

public class SliceHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 1);
        // Add some securities and datasets.
        AddCrypto("BTCUSD");
        // Get the historical Slice objects over the last 5 days for all the subcriptions in your algorithm.
        var history = History(5, Resolution.Daily);
        // Iterate through each historical Slice.
        foreach (var slice in history)
        {
            // Iterate through each TradeBar in this Slice.
            foreach (var kvp in slice.Bars)
            {
                var symbol = kvp.Key;
                var bar = kvp.Value;
            }
        }
    }
}
class SliceHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 1)
        # Add some securities and datasets.
        self.add_crypto('BTCUSD')
        # 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

Universes

To get historical universe data, call the History method with the Universe object. This method doesn't apply your selection function. It returns all of the universe data.

To get historical universe data, call the history method with the Universe object. This method doesn't apply your selection function. It returns all of the universe data in a DataFrame with columns for the data point attributes.

public class CryptoUniverseHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 23);
        // Add a universe of Cryptocurrencies on Coinbase.
        var universe = AddUniverse(CryptoUniverse.Coinbase());
        // Get 5 days of history for the universe.
        var history = History(universe, TimeSpan.FromDays(5));
        // Iterate through each day of the universe history.
        foreach (var constituents in history)
        {
            // Select the 2 assets with the smallest weights in the ETF on this day.
            var dailyLargest = constituents.Select(c => c as ETFConstituentData).OrderByDescending(c => c.Weight).Take(2);
        }
    }
}
class CryptoUniverseHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 23)
        # Add a universe of Cryptocurrencies on Coinbase.
        universe = self.add_universe(CryptoUniverse.coinbase())
        # Get 5 days of history for the universe.
        history = self.history(universe, timedelta(5), flatten=True)
closehighlowopenpricevolumevolumeinusd
timesymbol
2024-12-1900USD 2XR0.0503000.0515000.0492000.0515000.0503003.173495e+061.596268e+05
00USDC 2XR0.0503000.0515000.0492000.0515000.0503003.173495e+061.596268e+05
1INCHBTC 2XR0.0000040.0000050.0000040.0000050.0000049.815380e+034.584371e+03
1INCHEUR 2XR0.4460000.4670000.4420000.4650000.4460009.007325e+044.215390e+04
1INCHGBP 2XR0.3690000.3850000.3660000.3810000.3690003.932220e+041.845807e+04
...........................
2024-12-23ZETAUSDC 2XR0.5745000.6386000.5626000.5984000.5745001.522481e+068.746654e+05
ZROUSD 2XR5.4870006.3630005.3930005.6350005.4870001.312069e+057.199321e+05
ZROUSDC 2XR5.4870006.3630005.3930005.6350005.4870001.312069e+057.199321e+05
ZRXUSD 2XR0.4499440.5094250.4415900.4760010.4499443.371118e+061.516814e+06
ZRXUSDC 2XR0.4499440.5094250.4415900.4760010.4499443.371118e+061.516814e+06
# Select the 2 assets with the largest dollar volume each day.
most_traded = history.groupby('time').apply(lambda x: x.nlargest(2, 'volumeinusd')).reset_index(level=1, drop=True).volumeinusd
time        symbol     
2024-12-19  BTCUSD         1.245065e+09
            BTCUSDC 2XR    1.245065e+09
2024-12-20  BTCUSD         2.169212e+09
            BTCUSDC 2XR    2.169212e+09
2024-12-21  BTCUSD         2.231721e+09
            BTCUSDC 2XR    2.231721e+09
2024-12-22  BTCUSD         2.077999e+09
            BTCUSDC 2XR    2.077999e+09
2024-12-23  BTCUSD         6.169765e+08
            BTCUSDC 2XR    6.169765e+08
Name: volumeinusd, 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 assets with the largest dollar volume this day.
    most_liquid = sorted(constituents, key=lambda c: c.volume_in_usd)[-10:]

Alternative Data

To get historical alternative data, call the History<alternativeDataClass> method with the dataset Symbol.

To get historical alternative data, call the history method with the dataset Symbol. This method returns a DataFrame that contains the data point attributes.

public class CryptoAlternativeDataHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Get the Symbol of an asset.
        var symbol = AddEquity("BTCUSD").Symbol;
        // Add the alternative dataset and save a reference to its Symbol.
        var datasetSymbol = AddData<BitcoinMetadata>(symbol).Symbol;
        // Get the trailing 5 days of alternative data for the asset.
        var history = History<BitcoinMetadata>(datasetSymbol, 5, Resolution.Daily);
        // Iterate each data point and access its attributes.
        foreach (var dataPoint in history)
        {
            var t = dataPoint.EndTime;
            var marketCap = dataPoint.MarketCapitalization;
        }
    }
}
class CryptoAlternativeDataHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Get the Symbol of an asset.
        symbol = self.add_crypto('BTCUSD').symbol
        # Add the alternative dataset and save a reference to its Symbol.
        dataset_symbol = self.add_data(BitcoinMetadata, symbol).symbol
        # Get the trailing 5 days of alternative data for the asset in DataFrame format.
        history = self.history(dataset_symbol, 5, Resolution.DAILY)
averageblocksizeblockchainsizecostpercentoftransactionvolumecostpertransactiondifficultyestimatedtransactionvolumeestimatedtransactionvolumeusdhashratemarketcapitalizationmediantransactionconfirmationtime...mywalletnumberofusersnumberoftransactionperblocknumberoftransactionsnumberoftransactionsexcludingpopularaddressesnumberofuniquebitcoinaddressesusedtotalbitcoinstotalnumberoftransactionstotaloutputvolumetotaltransactionfeestotaltransactionfeesusd
symboltime
BTCUSD.BitcoinMetadata2024-12-151.5554622522.46290.964599.78451.039196e+1452757.22405.353586e+098.213738e+081.999814e+127.5167...89780467.03254.6038517482.0517269.0547370.01.979622e+071.131425e+09430661.419811.99331.216796e+06
2024-12-161.5014622769.75690.6667118.20011.039196e+1466749.25766.822123e+097.077246e+082.038652e+127.8167...89784782.02762.9708378527.0378325.0540459.01.979658e+071.131942e+09435592.16129.56609.890319e+05
2024-12-171.5993622975.38760.2560120.90251.082427e+14185055.06771.948991e+107.963548e+082.096909e+127.6167...89788382.02788.8311412747.0412506.0628257.01.979710e+071.132320e+09944149.598112.32761.295375e+06
2024-12-181.6135623212.24830.2910111.21041.085226e+14150308.18661.603829e+107.336779e+082.099723e+128.2167...89792154.03086.0809419707.0419484.0587955.01.979750e+071.132733e+09899983.477512.73761.359282e+06
2024-12-191.5915623431.59710.3013116.34021.085226e+14154047.10231.600095e+107.768354e+082.034833e+128.3833...89797436.02877.5417414366.0414128.0583495.01.979795e+071.133152e+09863124.937813.11341.363842e+06
# Calculate the growth in market cap.
growth = history.marketcapitalization.pct_change().iloc[1:]
symbol                  time      
BTCUSD.BitcoinMetadata  2024-12-16    0.019420
                        2024-12-17    0.028577
                        2024-12-18    0.001342
                        2024-12-19   -0.030904
Name: marketcapitalization, 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 IndicatorHistoryindicator_history method with an indicator and the security's Symbol.

public class CryptoIndicatorHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Get the Symbol of a security.
        var symbol = AddCrypto("BTCUSD").Symbol;
        // Get the 21-day SMA values of the security for the last 5 trading days. 
        var history = IndicatorHistory(new SimpleMovingAverage(21), symbol, 5, Resolution.Daily);
        // Get the maximum of the SMA values.
        var maxSMA = history.Max(indicatorDataPoint => indicatorDataPoint.Current.Value);
    }
}
class CryptoIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Get the Symbol of a security.
        symbol = self.add_crypto('BTCUSD').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
currentrollingsum
2024-12-1597734.0628572052415.32
2024-12-1698039.3819052058827.02
2024-12-1798663.1819052071926.82
2024-12-1899340.6409522086153.46
2024-12-1999540.6190482090353.00
# Get the maximum of the SMA values.
sma_max = history_df.current.max()

The IndicatorHistoryindicator_history method resets your indicator, makes a history request, and updates the indicator with the historical data. Just like with regular history requests, the IndicatorHistoryindicator_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 IndicatorHistoryindicator_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.
var history = IndicatorHistory(indicator, symbol, TimeSpan.FromDays(30), selector: Field.Volume);
# 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.

public class CryptoMultiAssetIndicatorHistoryAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2024, 12, 19);
        // Add the target and reference securities.
        var targetSymbol = AddCrypto("DOGEUSD").Symbol;
        var referenceSymbol = AddCrypto("BTCUSD").Symbol;
        // Create a 21-period Beta indicator.
        var beta = new Beta("", targetSymbol, referenceSymbol, 21);
        // Get the historical values of the indicator over the last 10 trading days.
        var history = IndicatorHistory(beta, new[] {targetSymbol, referenceSymbol}, 10, Resolution.Daily);
        // Get the average Beta value.
        var avgBeta = history.Average(indicatorDataPoint => indicatorDataPoint.Current.Value);
    }
}
class CryptoMultiAssetIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        # Add the target and reference securities.
        target_symbol = self.add_crypto('DOGEUSD').symbol
        reference_symbol = self.add_crypto('BTCUSD').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()

If you already have a list of Slice objects, you can pass them to the IndicatorHistoryindicator_history method to avoid the internal history request.

var slices = History(new[] {symbol}, 30, Resolution.Daily);
var history = IndicatorHistory(indicator, slices);

Examples

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: