US Equity
Corporate Fundamentals
Introduction
Corporate fundamental data contains all the information on the underlying company of an Equity asset and the information in their financial statements. Since corporate data contains information not found in price and alternative data, adding corporate data to your trading strategies provides you with more information so you can make more informed trading decisions. Corporate fundamental data is available through the US Fundamental Data from Morningstar.
Direct Access
To get fundamental data for Equities in your algorithm, use the Fundamentals
fundamentals
property of the Equity
objects. The fundamental data represent the company's fundamentals for the current algorithm time.
var fundamentals = Securities[_symbol].Fundamentals;
fundamentals = self.securities[self._symbol].fundamentals
To get fundamental data for Equities, regardless of whether or not you have subscribed to them in your algorithm, call the Fundamentals
fundamentals
method. If you pass one Symbol
, the method returns a Fundamental
object. If you pass a list of Symbol
objects, the method returns a list of Fundamental
objects. The fundamental data represents the corporate fundamentals for the current algorithm time.
// Single asset var ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA); var ibmFundamental = Fundamentals(ibm); // Multiple assets var nb = QuantConnect.Symbol.Create("NB", SecurityType.Equity, Market.USA); var fundamentals = Fundamentals(new List<Symbol>{ nb, ibm }).ToList();
# Single asset ibm = QuantConnect.symbol.create("IBM", SecurityType.EQUITY, Market.USA) ibm_fundamental = self.fundamentals(ibm) # Multiple assets nb = QuantConnect.symbol.create("NB", SecurityType.EQUITY, Market.USA) fundamentals = self.fundamentals([ nb, ibm ])
Data Availability
Some assets don't have fundamentals (for example, ETFs) and the Morningstar dataset doesn't provide fundamentals for all US Equities. To check if fundamental data is available for an asset, use the HasFundamentalData
has_fundamental_data
property.
var hasFundamentalData = Securities[_symbol].Fundamentals.HasFundamentalData;
has_fundamental_data = self.securities[self._symbol].fundamentals.has_fundamental_data
Object References
If you save a reference to the Fundamentals
fundamentals
object or its properties, you can access the fundamental properties as they change over time.
_fundamentals = Securities[_symbol].Fundamentals; var earningRatios = _fundamentals.EarningRatios;
self._fundamentals = self.securities[self._symbol].fundamentals earning_ratios = self.fundamentals.earning_ratios
Universe Selection
You can access fundamental data in the selection function of your fundamental universe.
public class MyUniverseAlgorithm : QCAlgorithm { public override void Initialize() { UniverseSettings.Asynchronous = true; AddUniverse(FundamentalFilterFunction); } private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental) { return (from f in fundamental where f.HasFundamentalData select f.Symbol); } }
class MyUniverseAlgorithm(QCAlgorithm): def initialize(self) -> None: self.universe_settings.asynchronous = True self.add_universe(self._fundamental_function) def _fundamental_function(self, fundamental: List[Fundamental]) -> List[Symbol]: return [c.symbol for c in fundamental if c.has_fundamental_data]
Historical Data
To get historical fundamental data, call the History
history
method. The return type depends on how you call the method.
var ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA); // Fundamental objects var fundamentalHistory = History<Fundamental>(ibm, TimeSpan.FromDays(30)); // Fundamentals objects for all US Equities (including delisted companies) var fundamentalsHistory = History<Fundamentals>(TimeSpan.FromDays(30)); // Collection of Fundamental objects for all US Equities (including delisted companies) var collectionHistory = History(_universe, 30, Resolution.Daily); foreach (var fundamental in collectionHistory) { // Cast to Fundamental is required var highestMarketCap = fundamental.OfType<Fundamental>().OrderByDescending(x => x.MarketCap).Take(5); }
ibm = Symbol.create("IBM", SecurityType.EQUITY, Market.USA) # DataFrame of fundamental data for a given asset df_history = self.history(Fundamental, ibm, timedelta(30), flatten=True) # Fundamental objects fundamental_history = self.history[Fundamental](ibm, timedelta(30)) # Fundamentals objects for all US Equities (including delisted companies) fundamentals_history = self.history[Fundamentals](timedelta(30)) # DataFrame of fundamental data for universe constituents df_history = self.history(self._universe, 30, Resolution.DAILY, flatten=True) # Series of fundamental data for universe constituents series_history = self.history(self._universe, 30, Resolution.DAILY) for (universe_symbol, time), fundamental in series_history.items(): highest_market_cap = sorted(fundamental, key=lambda x: x.market_cap)[-5:]
For more information about historical fundamental data, see Equity Fundamental Data.
Data Updates
The US Fundamental dataset only provides the originally-reported figures. If there was a mistake in reporting a figure, the data value isn't fixed later. In live trading, new fundamental data is available to your algorithms at approximately 6/7 AM Eastern Time (ET) each day. The majority of the corporate data update occurs once per month, but the financial ratios update daily. If there is no new data for a period of time, the previous data is filled forward.
Properties
The US Fundamentals dataset provides Fundamental objects. To filter Fundamental objects, you can use the MorningstarSectorCode
, MorningstarIndustryGroupCode
, and MorningstarIndustryCode
enumeration values.
Fundamentals Attributes
Fundamentals objects have the following attributes:
MorningstarSectorCode Enumeration
Sectors are large super categories of data. To access the sector of an Equity, use the MorningstarSectorCodemorningstar_sector_code property.
filtered = fundamental.Where(x => x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology);
filtered = [x for x in fundamental if x.asset_classification.morningstar_sector_code == MorningstarSectorCode.TECHNOLOGY]
The MorningstarSectorCode enumeration has the following members:
MorningstarIndustryGroupCode Enumeration
Industry groups are clusters of related industries which tie together. To access the industry group of an Equity, use the MorningstarIndustryGroupCodemorningstar_industry_group_code property.
filtered = fundamental.Where(x => x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.ApplicationSoftware);
filtered = [x for x in fundamental if x.asset_classification.morningstar_industry_group_code == MorningstarIndustryGroupCode.APPLICATION_SOFTWARE]
The MorningstarIndustryGroupCode enumeration has the following members:
MorningstarIndustryCode Enumeration
Industries are the finest level of classification available and are the individual industries according to the Morningstar classification system. To access the industry group of an Equity, use the MorningstarIndustryCodemorningstar_industry_code property:
filtered = fundamental.Where(x => x.AssetClassification.MorningstarIndustryCode == MorningstarIndustryCode.SoftwareApplication);
filtered = [x for x in fundamental if x.asset_classification.morningstar_industry_code == MorningstarIndustryCode.SOFTWARE_APPLICATION]
The MorningstarIndustryCode enumeration has the following members:
Exchange Id Values
Exchange Id is mapped to represent the exchange that lists the Equity. To access the exchange Id of an Equity, use the PrimaryExchangeIDprimary_exchange_id property.
filtered = fundamental.Where(x => x.CompanyReference.PrimaryExchangeID == "NAS");
filtered = [x for x in fundamental if x.company_reference.primary_exchange_id == "NAS"]
The exchanges are represented by the following string values:
String Representation | Exchange |
---|---|
NYS | New York Stock Exchange (NYSE) |
NAS | NASDAQ |
ASE | American Stock Exchange (AMEX) |
TSE | Tokyo Stock Exchange |
AMS | Amsterdam Internet Exchange |
SGO | Santiago Stock Exchange |
XMAD | Madrid Stock Exchange |
ASX | Australian Securities Exchange |
BVMF | B3 (stock exchange) |
LON | London Stock Exchange |
TKS | Istanbul Stock Exchange Settlement and Custody Bank |
SHG | Shanghai Exchange |
LIM | Lima Stock Exchange |
FRA | Frankfurt Stock Exchange |
JSE | Johannesburg Stock Exchange |
MIL | Milan Stock Exchange |
TAE | Tel Aviv Stock Exchange |
STO | Stockholm Stock Exchange |
ETR | Deutsche Boerse Xetra Core |
PAR | Paris Stock Exchange |
BUE | Buenos Aires Stock Exchange |
KRX | Korea Exchange |
SWX | SIX Swiss Exchange |
PINX | Pink Sheets (OTC) |
CSE | Canadian Securities Exchange |
PHS | Philippine Stock Exchange |
MEX | Mexican Stock Exchange |
TAI | Taiwan Stock Exchange |
IDX | Indonesia Stock Exchange |
OSL | Oslo Stock Exchange |
BOG | Colombia Stock Exchange |
NSE | National Stock Exchange of India |
HEL | Nasdaq Helsinki |
MISX | Moscow Exchange |
HKG | Hong Kong Stock Exchange |
IST | Istanbul Stock Exchange |
BOM | Bombay Stock Exchange |
TSX | Toronto Stock Exchange |
BRU | Brussels Stock Exchange |
BATS | BATS Global Markets |
ARCX | NYSE Arca |
GREY | Grey Market (OTC) |
DUS | Dusseldorf Stock Exchange |
BER | Berlin Stock Exchange |
ROCO | Taipei Exchange |
CNQ | Canadian Trading and Quotation System Inc. |
BSP | Bangko Sentral ng Pilipinas |
NEOE | NEO Exchange |
Examples
The following examples demonstrate some common practices for US Equity corporate fundamentals.
Example 1: Capturing the Overreaction to Financial Reports
The following algorithm is based on the hypothesis that investors overreact to new financial report releases. It buys AAPL stock on every new 10Q or 8K filing and then liquidates the position after seven days.
public class USEquityCorporateFundamentalsExampleAlgorithm : QCAlgorithm { private Equity _aapl; // Add a member to track the last financial statement filing date. private DateTime? _lastFilingDate = null; private DateTime _exitTime; public override void Initialize() { // Add Equity data. _aapl = AddEquity("AAPL"); } public override void OnData(Slice slice) { // Get the most recent filing date. var lastFilingDate = _aapl.Fundamentals.FinancialStatements.FileDate.Value; // When new financial statements are released, buy AAPL. if (_lastFilingDate.HasValue && lastFilingDate != _lastFilingDate.Value) { SetHoldings(_aapl.Symbol, 1); _exitTime = Time.AddDays(7); } // Liquidate the position after 1 week. if (_aapl.Holdings.Invested && Time >= _exitTime) { Liquidate(); } // Update the last filing date to identify future changes. _lastFilingDate = lastFilingDate; } }
class USEquityCorporateFundamentalsExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # Add Equity data. self._aapl = self.add_equity("AAPL") # Add a member to track the last financial statement filing date. self._last_filing_date = None def on_data(self, slice: Slice) -> None: # Get the most recent filing date. last_filing_date = self._aapl.fundamentals.financial_statements.file_date.value # When new financial statements are released, buy AAPL. if self._last_filing_date and last_filing_date != self._last_filing_date: self.set_holdings(self._aapl.symbol, 1) self._exit_time = self.time + timedelta(7) # Liquidate the position after 1 week. if self._aapl.holdings.invested and self.time >= self._exit_time: self.liquidate() # Update the last filing date to identify future changes. self._last_filing_date = last_filing_date
Example 2: Diversifying Across Sectors
The follow algorithm aims to reduce concentration risk in any one sector. It selects the 500 largest Equities at the start of each month and then forms a portfolio that gives equal weight to each sector and equal weight to the assets within each sector.
public class USEquityCorporateFundamentalsExampleAlgorithm : QCAlgorithm { private Universe _universe; public override void Initialize() { SetCash(10_000_000); // Define the universe settings. var spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); UniverseSettings.Resolution = Resolution.Daily; UniverseSettings.Schedule.On(DateRules.MonthStart(spy)); // Add a universe of the 500 largest Equities. _universe = AddUniverse(coarse => coarse .OrderByDescending(x => x.MarketCap) .Take(500) .Select(x => x.Symbol) ); // Create a Scheduled Event to rebalance the portfolio each month. Schedule.On(DateRules.MonthStart(spy, 1), TimeRules.Midnight, Rebalance); } private void Rebalance() { // Wait until there are assets in the universe. if (_universe.Selected == null) { return; } // Group the universe constituents by sector. var symbolsBySector = new Dictionary<int, List<Symbol>>(); foreach (var symbol in _universe.Selected) { var equity = Securities[symbol]; if (equity.Price == 0) { continue; } var sectorCode = equity.Fundamentals.AssetClassification.MorningstarSectorCode; if (!symbolsBySector.ContainsKey(sectorCode)) { symbolsBySector[sectorCode] = new List<Symbol>(); } symbolsBySector[sectorCode].Add(symbol); } // Create targets to invest equally in each sector and invest equally in the assets within each sector. var targets = new List<PortfolioTarget>(); var sectorCount = symbolsBySector.Count; foreach (var symbols in symbolsBySector.Values) { var weight = 1m / sectorCount / symbols.Count; targets.AddRange(symbols.Select(symbol => new PortfolioTarget(symbol, weight))); } // Place the trades. SetHoldings(targets, true); } }
class USEquityCorporateFundamentalsExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_cash(10_000_000) # Define the universe settings. spy = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) self.universe_settings.resolution = Resolution.DAILY self.universe_settings.schedule.on(self.date_rules.month_start(spy)) # Add a universe of the 500 largest Equities. self._universe = self.add_universe( lambda fundamental: [ f.symbol for f in sorted(fundamental, key=lambda f: f.market_cap)[-500:] ] ) # Create a Scheduled Event to rebalance the portfolio each month. self.schedule.on(self.date_rules.month_start(spy, 1), self.time_rules.midnight, self._rebalance) def _rebalance(self) -> None: # Wait until there are asset in the universe. if not self._universe.selected: return # Group the universe constituents by sector. symbols_by_sector = {} for symbol in self._universe.selected: equity = self.securities[symbol] if not equity.price: continue sector_code = equity.fundamentals.asset_classification.morningstar_sector_code if sector_code not in symbols_by_sector: symbols_by_sector[sector_code] = [] symbols_by_sector[sector_code].append(symbol) # Create targets to invest equally in each sector and invest equally in the assets within each sector. targets = [] sector_count = len(symbols_by_sector) for symbols in symbols_by_sector.values(): weight = 1 / sector_count / len(symbols) targets.extend([PortfolioTarget(symbol, weight) for symbol in symbols]) # Place the trades. self.set_holdings(targets, True)