US Bureau of Economic Analysis

GDP by Industry

Introduction

The GDP by Industry dataset by the US Bureau of Economic Analysis (BEA) breaks US gross domestic product down by industry, showing how much each industry contributes to output through its value added, gross output, and intermediate inputs. The data covers 100 US industries, starts in January 2005, and is delivered on a quarterly cadence. This dataset is created by processing the official BEA Industry Economic Accounts from the public BEA API.

For more information about the GDP by Industry dataset, including CLI commands and pricing, see the dataset listing.

About the Provider

The Bureau of Economic Analysis (BEA) is an agency of the US Department of Commerce that produces the nation's official economic statistics, including gross domestic product. Through its Industry Economic Accounts, the BEA measures how each industry contributes to the economy and publishes the results as a public record, released free of charge through the BEA API.

Getting Started

The following snippet demonstrates how to request data from the GDP by Industry dataset:

self.dataset_symbol = self.add_data(BEAGDPByIndustry, BEA.Industries.MANUFACTURING, Resolution.DAILY).symbol
_datasetSymbol = AddData<BEAGDPByIndustry>(BEA.Industries.Manufacturing, Resolution.Daily).Symbol;

Data Summary

The following table describes the dataset properties:

PropertyValue
Start DateJanuary 2005
Data Points8,500
Asset Coverage100 US Industries
Data DensitySparse
ResolutionDaily*
TimezoneNew York

* The BEA publishes these accounts quarterly. We check the source daily and deliver each release on the day it lands.

Requesting Data

To add GDP by Industry data to your algorithm, call the AddDataadd_data method. The dataset is unlinked, so you pass a BEA industry code from the BEA.Industries helper instead of a security Symbol. Save a reference to the dataset Symbol so you can access the data later in your algorithm.

class BEAGDPByIndustryDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2020, 12, 31)
        self.set_cash(100000)

        self.dataset_symbol = self.add_data(BEAGDPByIndustry, BEA.Industries.MANUFACTURING, Resolution.DAILY).symbol
public class BEAGDPByIndustryDataAlgorithm : QCAlgorithm
{
    private Symbol _datasetSymbol;

    public override void Initialize()
    {
        SetStartDate(2019, 1, 1);
        SetEndDate(2020, 12, 31);
        SetCash(100000);

        _datasetSymbol = AddData<BEAGDPByIndustry>(BEA.Industries.Manufacturing, Resolution.Daily).Symbol;
    }
}

Accessing Data

To get the current GDP by Industry data, index the current Slice with the dataset Symbol. Slice objects deliver unique events to your algorithm as they happen, but the Slice may not contain data for your dataset at every time step. To avoid issues, check if the Slice contains the data you want before you index it.

def on_data(self, slice: Slice) -> None:
    if slice.contains_key(self.dataset_symbol):
        data_point = slice[self.dataset_symbol]
        self.log(f"{self.dataset_symbol} value added at {slice.time}: {data_point.value_added}")
public override void OnData(Slice slice)
{
    if (slice.ContainsKey(_datasetSymbol))
    {
        var dataPoint = slice[_datasetSymbol];
        Log($"{_datasetSymbol} value added at {slice.Time}: {dataPoint.ValueAdded}");
    }
}

To iterate through all of the dataset objects in the current Slice, call the Get method.

def on_data(self, slice: Slice) -> None:
    for dataset_symbol, data_point in slice.get(BEAGDPByIndustry).items():
        self.log(f"{dataset_symbol} value added at {slice.time}: {data_point.value_added}")
public override void OnData(Slice slice)
{
    foreach (var kvp in slice.Get<BEAGDPByIndustry>())
    {
        var datasetSymbol = kvp.Key;
        var dataPoint = kvp.Value;
        Log($"{datasetSymbol} value added at {slice.Time}: {dataPoint.ValueAdded}");
    }
}

Historical Data

To get historical GDP by Industry data, call the History method with the dataset Symbol. If there is no data in the period you request, the history result is empty. The accounts are quarterly, so a request counted in daily bars covers far fewer data points than the number you pass.

# DataFrame
history_df = self.history(self.dataset_symbol, 100, Resolution.DAILY)

# Dataset objects
history_bars = self.history[BEAGDPByIndustry](self.dataset_symbol, 100, Resolution.DAILY)
var history = History<BEAGDPByIndustry>(_datasetSymbol, 100, Resolution.Daily);

For more information about historical data, see History Requests.

Remove Subscriptions

To remove your subscription to GDP by Industry data, call the RemoveSecurity method.

self.remove_security(self.dataset_symbol)
RemoveSecurity(_datasetSymbol);

Supported Industries

Every industry in the accounts has a readable named constant in the BEA.Industries helper, which resolves to the BEA NAICS-based industry code you pass to AddDataadd_data. Type BEA.Industries. in the editor and autocomplete will list them all. The following table shows a few examples:

ConstantIndustry
BEA.Industries.ManufacturingBEA.Industries.MANUFACTURINGManufacturing
BEA.Industries.ConstructionBEA.Industries.CONSTRUCTIONConstruction
BEA.Industries.FinanceAndInsuranceBEA.Industries.FINANCE_AND_INSURANCEFinance and insurance
BEA.Industries.RetailTradeBEA.Industries.RETAIL_TRADERetail trade
BEA.Industries.OilAndGasExtractionBEA.Industries.OIL_AND_GAS_EXTRACTIONOil and gas extraction
BEA.Industries.GrossDomesticProductBEA.Industries.GROSS_DOMESTIC_PRODUCTGross domestic product (all industries)

Not every metric applies to every industry in every quarter, so a field can be empty. The fields are nullable, so check for a missing value before you use it.

Example Applications

The GDP by Industry dataset lets you trade on the composition of growth instead of just its headline. Examples include the following strategies:

  • Rotating into cyclical exposure when an industry's real value added turns up quarter over quarter, and out when it turns down.
  • Ranking industries by the change in real gross output to tilt a sector portfolio toward the fastest-growing parts of the economy.
  • Reading an industry's price index as an industry-level inflation gauge to time rate-sensitive positions.

Classic Algorithm Example

The following example algorithm uses BEA GDP by Industry as a macro signal. It reads Manufacturing real value added each quarter and buys SPY when it rises quarter over quarter, then moves to cash when it falls.

from AlgorithmImports import *

class BEAGDPByIndustryDataAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2020, 12, 31)
        self.set_cash(100000)

        self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
        self._manufacturing = self.add_data(BEAGDPByIndustry, BEA.Industries.MANUFACTURING, Resolution.DAILY).symbol
        self._previous_real_value_added = None

    def on_data(self, slice):
        if not slice.contains_key(self._manufacturing):
            return

        # Real value added rising quarter over quarter is expansionary: go long, otherwise flat.
        real = slice[self._manufacturing].real_value_added
        if self._previous_real_value_added is not None and real is not None:
            if real > self._previous_real_value_added:
                self.set_holdings(self._spy, 1)
            else:
                self.liquidate(self._spy)
        self._previous_real_value_added = real
public class BEAGDPByIndustryDataAlgorithm : QCAlgorithm
{
    private Symbol _spy, _manufacturing;
    private decimal? _previousRealValueAdded;

    public override void Initialize()
    {
        SetStartDate(2019, 1, 1);
        SetEndDate(2020, 12, 31);
        SetCash(100000);

        _spy = AddEquity("SPY", Resolution.Daily).Symbol;
        _manufacturing = AddData<BEAGDPByIndustry>(BEA.Industries.Manufacturing, Resolution.Daily).Symbol;
    }

    public override void OnData(Slice slice)
    {
        if (!slice.ContainsKey(_manufacturing))
        {
            return;
        }

        // Real value added rising quarter over quarter is expansionary: go long, otherwise flat.
        var real = slice.Get<BEAGDPByIndustry>(_manufacturing).RealValueAdded;
        if (_previousRealValueAdded.HasValue && real.HasValue)
        {
            if (real > _previousRealValueAdded)
            {
                SetHoldings(_spy, 1);
            }
            else
            {
                Liquidate(_spy);
            }
        }
        _previousRealValueAdded = real;
    }
}

Framework Algorithm Example

The following example algorithm implements the same Manufacturing signal in the algorithm framework. It uses a manual universe of SPY, an alpha model that emits insights from BEA GDP by Industry, and equal-weighting portfolio construction.

from AlgorithmImports import *

class BEAGDPByIndustryFrameworkAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2020, 12, 31)
        self.set_cash(100000)

        self.universe_settings.resolution = Resolution.DAILY
        symbols = [Symbol.create("SPY", SecurityType.EQUITY, Market.USA)]
        self.set_universe_selection(ManualUniverseSelectionModel(symbols))
        self.add_alpha(BEAGDPByIndustryAlphaModel(self))
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())

class BEAGDPByIndustryAlphaModel(AlphaModel):
    def __init__(self, algorithm):
        self._manufacturing = algorithm.add_data(BEAGDPByIndustry, BEA.Industries.MANUFACTURING, Resolution.DAILY).symbol
        self._previous_real_value_added = None
        self._tradable_symbols = []

    def update(self, algorithm, slice):
        insights = []
        if not slice.contains_key(self._manufacturing):
            return insights

        real = slice[self._manufacturing].real_value_added
        if self._previous_real_value_added is not None and real is not None:
            direction = InsightDirection.UP if real > self._previous_real_value_added else InsightDirection.DOWN
            insights = [Insight.price(symbol, timedelta(days=90), direction) for symbol in self._tradable_symbols]
        self._previous_real_value_added = real
        return insights

    def on_securities_changed(self, algorithm, changes):
        for security in changes.added_securities:
            if security.symbol != self._manufacturing:
                self._tradable_symbols.append(security.symbol)
        for security in changes.removed_securities:
            if security.symbol in self._tradable_symbols:
                self._tradable_symbols.remove(security.symbol)
public class BEAGDPByIndustryFrameworkAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2019, 1, 1);
        SetEndDate(2020, 12, 31);
        SetCash(100000);

        UniverseSettings.Resolution = Resolution.Daily;
        var symbols = new[] { QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA) };
        SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
        AddAlpha(new BEAGDPByIndustryAlphaModel(this));
        SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
    }
}

public class BEAGDPByIndustryAlphaModel : AlphaModel
{
    private readonly Symbol _manufacturing;
    private decimal? _previousRealValueAdded;
    private readonly List<Symbol> _tradableSymbols = new();

    public BEAGDPByIndustryAlphaModel(QCAlgorithm algorithm)
    {
        _manufacturing = algorithm.AddData<BEAGDPByIndustry>(BEA.Industries.Manufacturing, Resolution.Daily).Symbol;
    }

    public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice)
    {
        var insights = new List<Insight>();
        if (!slice.ContainsKey(_manufacturing))
        {
            return insights;
        }

        var real = slice.Get<BEAGDPByIndustry>(_manufacturing).RealValueAdded;
        if (_previousRealValueAdded.HasValue && real.HasValue)
        {
            var direction = real > _previousRealValueAdded ? InsightDirection.Up : InsightDirection.Down;
            foreach (var symbol in _tradableSymbols)
            {
                insights.Add(Insight.Price(symbol, TimeSpan.FromDays(90), direction));
            }
        }
        _previousRealValueAdded = real;
        return insights;
    }

    public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
    {
        foreach (var security in changes.AddedSecurities)
        {
            if (security.Symbol != _manufacturing)
            {
                _tradableSymbols.Add(security.Symbol);
            }
        }
        foreach (var security in changes.RemovedSecurities)
        {
            _tradableSymbols.Remove(security.Symbol);
        }
    }
}

Data Point Attributes

The GDP by Industry dataset provides BEAGDPByIndustry objects, which have the following attributes:

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: