---
title: "Alternative Data"
description: "Alternative datasets provide signals to inform trading decisions. This page explains how to get historical data for alternative datasets."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/alternative-data
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/alternative-data.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/20%20Historical%20Data/05%20Alternative%20Data
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# Alternative Data

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Historical Data > Alternative Data

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

Alternative datasets provide signals to inform trading decisions. To view all the alternative datasets available on QuantConnect, see the [Dataset Market](https://www.quantconnect.com/datasets). This page explains how to get historical data for alternative datasets.

## Data Points

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

```python
class AlternativeDataHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 20)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a dataset.
        dataset_symbol = self.add_data(Fred, 'RVXCLS').symbol
        # Get the trailing 5 days of Fred data in DataFrame format.
        history = self.history(dataset_symbol, 5, Resolution.DAILY)
```

| symbol | time | value |
| --- | --- | --- |
| RVXCLS.Fred | 2024-12-17 | 23.02 |
| RVXCLS.Fred | 2024-12-18 | 24.01 |
| RVXCLS.Fred | 2024-12-19 | 32.76 |
| RVXCLS.Fred | 2024-12-20 | 29.90 |

```python
# Calculate the dataset's rate of change.
roc = history.pct_change().iloc[1:]
```

| symbol | time | value |
| --- | --- | --- |
| RVXCLS.Fred | 2024-12-18 | 0.043006 |
| RVXCLS.Fred | 2024-12-19 | 0.364431 |
| RVXCLS.Fred | 2024-12-20 | -0.087302 |

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.

```python
# Get the trailing 5 days of Fred data for an asset in Fred format.
history = self.history[Fred](dataset_symbol, 5, Resolution.DAILY)
# Iterate through the historical data points.
for data_point in history:
    t = data_point.end_time
    value = data_point.value
```

Some alternative datasets provide multiple entries per asset per [time step](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md). For example, the [US Regulatory Alerts](https://www.quantconnect.com/datasets/regalytics-us-regulatory-alerts) dataset can provide multiple alerts per day. In this case, to organize the data into a DataFrame, set the `flatten` argument to `True`.

```python
class RegalyticsHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 20)
        self.set_end_date(2024, 12, 31)
        # Get the all the Regalytics articles that were published over the last day, organized in a DataFrame.
        dataset_symbol = self.add_data(RegalyticsRegulatoryArticles, "REG").symbol
        history = self.history(dataset_symbol, 1, Resolution.DAILY, flatten=True)
```

| time | symbol | agencies | alerttype | ... | time | title |
| --- | --- | --- | --- | --- | --- | --- |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Experian Information Solutions, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Transunion Intermediate Holdings, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Transunion Intermediate Holdings, Inc. |
| 2024-12-20 | ... | ... | ... | ... | ... | ... |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |
| 2024-12-20 | REG.RegalyticsRegulatoryArticles | [Consumer Financial Protection Bureau] | Complaint | ... | 2024-12-21 | Complaint Filed: Equifax, Inc. |

```python
# Get all the unique alert types from the Regalytics articles.
alert_types = history.alerttype.unique()
```

```python
array(['Complaint', 'Press release', 'Event', 'Litigation Release',
       'Grant Information', 'Media Release', 'News', 'Announcement',
       'Transcript', 'Decree', 'Decision', 'Regulation',
       'Executive Order', 'Media Advisory', 'Disaster Press Release',
       'Notice', 'Procurement', 'Meeting', 'News release', 'Contract',
       'Publication', 'Blog', 'Tabled Document', 'Resolution', 'Bill',
       'Concurrent Resolution', 'Opinions and Adjudicatory Orders',
       'Proposed rule', 'Technical Notice', 'Sanction', 'Order',
       'Statement', 'Rule', 'enforcement action', 'Report',
       'Statement|Release',
       'AWCs (Letters of Acceptance, Waiver, and Consent)'], dtype=object)
```

## Universes

To get historical data for an [alternative data universe](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/equity/alternative-data-universes.md), call the `history` method with the `Universe` object. Set the `flatten` argument to `True` to get a DataFrame that has columns for the data point attributes.

```python
class AltDataUniverseHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 23)
        self.set_end_date(2024, 12, 31)
        # Add a universe of US Equities based on an alternative dataset.
        universe = self.add_universe(BrainStockRankingUniverse)
        # Get 5 days of history for the universe.
        history = self.history(universe, timedelta(5), flatten=True)
```

| time | symbol | rank10days | rank21days | rank2days | rank3days | rank5days | value |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 2024-12-18 | A RPTMYV3VC57P | -0.001895 | 0.005938 | -0.007858 | -0.006320 | 0.001771 | -0.007858 |
| 2024-12-18 | AAL VM9RIYHM8ACL | -0.003977 | 0.006520 | -0.005671 | -0.003738 | -0.004715 | -0.005671 |
| 2024-12-18 | AAPL R735QTJ8XC9X | 0.027450 | 0.037339 | 0.006018 | 0.001489 | 0.010102 | 0.006018 |
| 2024-12-18 | ABBV VCY032R250MD | -0.002814 | 0.012297 | -0.001717 | -0.000679 | -0.007454 | -0.001717 |
| 2024-12-18 | ABNB XK8H247DY6W5 | 0.020533 | 0.046173 | -0.002303 | 0.007350 | 0.011252 | -0.002303 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 2024-12-23 | ZI XF2DKG2HHLK5 | -0.038118 | -0.037527 | -0.035904 | -0.041195 | -0.041388 | -0.035904 |
| 2024-12-23 | ZM X3RPXTZRW09X | 0.006784 | 0.020690 | -0.005674 | -0.008556 | -0.002120 | -0.005674 |
| 2024-12-23 | ZS WSVU0MELFQED | 0.010422 | 0.019619 | -0.003743 | -0.002079 | 0.002778 | -0.003743 |
| 2024-12-23 | ZTO WF2L9EOCSQCL | -0.021455 | -0.015939 | -0.018053 | -0.020263 | -0.024979 | -0.018053 |
| 2024-12-23 | ZTS VDRJHVQ4FNFP | 0.030589 | 0.041400 | 0.024744 | 0.019891 | 0.031048 | 0.024744 |

```python
# Select the asset with the greatest value each day.
daily_winner = history.groupby('time').apply(lambda x: x.nlargest(1, 'value')).reset_index(level=1, drop=True).value
```

```python
time        symbol
2024-12-18  FIC R735QTJ8XC9X    0.054204
2024-12-19  FIC R735QTJ8XC9X    0.073250
2024-12-20  FIC R735QTJ8XC9X    0.065142
2024-12-21  FIC R735QTJ8XC9X    0.065142
2024-12-22  FIC R735QTJ8XC9X    0.065142
2024-12-23  FIC R735QTJ8XC9X    0.065142
Name: value, 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`.

```python
# Get the historical universe data over the last 5 days in a Series where
# the values in the series are lists of the universe selection objects.
history = self.history(universe, timedelta(5), flatten=False)
# Select the asset with the greatest value each day.
for (universe_symbol, time), data in history.items():
    leader = sorted(data, key=lambda x: x.value)[-1]
```

## Slices

To request `Slice` objects of historical data, call the `history` method without providing any `Symbol` objects. It returns data for all the data subscriptions in your algorithm, so the result may include more than just alternative data.

```python
class SliceHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 23)
        self.set_end_date(2024, 12, 31)
        # Add an asset and an alternative dataset.
        symbol = self.add_crypto('BTCUSD', Resolution.DAILY, Market.BITFINEX).symbol
        dataset_symbol = self.add_data(BitcoinMetadata, symbol).symbol
        # Get the latest 3 data points of all the securities/datasets in the algorithm, packaged into Slice objects.
        history = self.history(3)
        # Iterate through each Slice and get the synchronized data points at each moment in time.
        for slice_ in history:
            t = slice_.time
            if symbol in slice_:
                price = slice_[symbol].price
            if dataset_symbol in slice_:
                hash_rate = slice_[dataset_symbol].hash_rate
```

When your history request returns `Slice` objects, the `time` properties of these objects are based on the algorithm time zone, but the `end_time` properties of the individual data objects are based on the [exchange time zone](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/time-zones.md#03-Exchange-Time-Zone). The `end_time` is the end of the [sampling period](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/periods.md) and when the data is actually available.

## Sparse Datasets

A sparse dataset is a dataset that doesn't have data for every time step of its resolution. For example, the [US Energy Information Administration (EIA) datasets](https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/energy-information-administration/us-energy-information-administration-(eia).md) have a daily resolution but the data for the "U.S. Ending Stocks of Finished Motor Gasoline in Thousand Barrels (Mbbl)" series only updates once a week. So when you request the trailing 30 days of historical data for it, you only get a few data points.

```python
class SparseDatasetHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 23)
        self.set_end_date(2024, 12, 31)
        # Add a sparse dataset. In this case, the default resolution is daily.
        symbol = self.add_data(USEnergy, 'PET.WGFSTUS1.W').symbol
        # Get 30 days of history for the dataset.
        history = self.history(symbol, 30)
```

| symbol | time | value |
| --- | --- | --- |
| PET.WGFSTUS1.W.USEnergy | 2024-11-29 | 14445.0 |
| PET.WGFSTUS1.W.USEnergy | 2024-12-06 | 16528.0 |
| PET.WGFSTUS1.W.USEnergy | 2024-12-13 | 16452.0 |
| PET.WGFSTUS1.W.USEnergy | 2024-12-20 | 16833.0 |

Most alternative datasets have only one resolution, which is usually daily. To check if a dataset is sparse and to view its resolution(s), see the documentation in the [Dataset Market](https://www.quantconnect.com/datasets).

## Examples

The following examples demonstrate some common practices for trade with historical Alternative Data.

### Example 1: Inverted Yield Curve

The following algorithm trades the smoothened yield curve difference, calculated from the difference between 10-year yield and 2-year yield historical data and smoothened by the exponential moving average. If the yield curve is inverted, short SPY from this market downturn indicator.

```python
class AlternativeHistoricalDataAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(1000000)

        # Requesting yield curve data for trade signal generation (inversion)
        self._yield_curve_symbol = self.add_data(USTreasuryYieldCurveRate, "USTYCR").symbol
        # Request XAUUSD CFD contract to trade.
        self._spy = self.add_equity("SPY").symbol

        # Ignore orders with very small sizes.
        self.settings.minimum_order_margin_portfolio_percentage = 0.01

        # Trade every day after the market opens with an updated smoothened yield curve difference.
        self.schedule.on(
            self.date_rules.every_day(self._spy),
            self.time_rules.after_market_open(self._spy, 1),
            self.trade
        )

    def trade(self) -> None:
        # Obtain historical yield curve data to calculate the smoothened yield curve difference.
        history = self.history(self._yield_curve_symbol, 250, Resolution.DAILY).unstack(0)
        if "tenyear" in history and "twoyear" in history:
            diffs = history.tenyear - history.twoyear
            smoothened_diff = diffs.ewm(250).mean().values[-1]
            # If the smoothened yield curve difference is inverted, short SPY with the downside signal.
            self.set_holdings(self._spy, -1 if smoothened_diff < 0 else 1)
```
