European Central Bank
Systemic Stress
Introduction
The Systemic Stress dataset by the European Central Bank (ECB) tracks the Composite Indicator of Systemic Stress (CISS), a measure of stress in the financial system. The data covers 14 economies, starts in January 1980, and is delivered on a weekly frequency. This dataset is created by processing the indicator the ECB publishes on its Data Portal. Only the euro area carries the breakdown by market segment.
For more information about the Systemic Stress dataset, including CLI commands and pricing, see the dataset listing.
About the Provider
The European Central Bank is the central bank of the euro area, established in 1998 and based in Frankfurt. Its main task is to keep prices stable in the countries that use the euro, and it sets the interest rates for the euro area. It also publishes statistics on the euro area economy and its financial markets.
Requesting Data
To add Systemic Stress data to your algorithm, call the AddDataadd_data method. Save a reference to the dataset Symbol so you can access the data later in your algorithm.
class ECBSystemicStressExampleAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2020, 1, 1)
self.set_end_date(2021, 1, 1)
self._euro_area = self.add_data(ECBSystemicStress, ECB.StressAreas.EURO_AREA).symbol public class ECBSystemicStressExampleAlgorithm : QCAlgorithm
{
private Symbol _euroArea;
public override void Initialize()
{
SetStartDate(2020, 1, 1);
SetEndDate(2021, 1, 1);
_euroArea = AddData<ECBSystemicStress>(ECB.StressAreas.EuroArea).Symbol;
}
}
Accessing Data
To get the current Systemic Stress 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._euro_area):
data_point = slice[self._euro_area]
self.log(f"{self._euro_area} composite stress at {slice.time}: {data_point.composite}") public override void OnData(Slice slice)
{
if (slice.ContainsKey(_euroArea))
{
var dataPoint = slice[_euroArea];
Log($"{_euroArea} composite stress at {slice.Time}: {dataPoint.Composite}");
}
}
To iterate through all of the dataset objects in the current Slice, call the Getget method.
def on_data(self, slice: Slice) -> None:
for dataset_symbol, data_point in slice.get(ECBSystemicStress).items():
self.log(f"{dataset_symbol} composite stress at {slice.time}: {data_point.composite}") public override void OnData(Slice slice)
{
foreach (var kvp in slice.Get<ECBSystemicStress>())
{
var datasetSymbol = kvp.Key;
var dataPoint = kvp.Value;
Log($"{datasetSymbol} composite stress at {slice.Time}: {dataPoint.Composite}");
}
}
Historical Data
To get historical Systemic Stress data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty.
# DataFrame history_df = self.history(self._euro_area, 100, Resolution.DAILY) # Dataset objects history_bars = self.history[ECBSystemicStress](self._euro_area, 100, Resolution.DAILY)
var history = History<ECBSystemicStress>(_euroArea, 100, Resolution.Daily);
For more information about historical data, see History Requests.
Supported Economies
The following table shows the accessor code you need to add each economy to your algorithm:
| Economy | Constant | Decomposition |
|---|---|---|
| Euro area | ECB.StressAreas.EuroAreaECB.StressAreas.EURO_AREA | Full |
| Austria | ECB.StressAreas.AustriaECB.StressAreas.AUSTRIA | Headline and sovereign |
| Belgium | ECB.StressAreas.BelgiumECB.StressAreas.BELGIUM | Headline and sovereign |
| Finland | ECB.StressAreas.FinlandECB.StressAreas.FINLAND | Headline and sovereign |
| France | ECB.StressAreas.FranceECB.StressAreas.FRANCE | Headline and sovereign |
| Germany | ECB.StressAreas.GermanyECB.StressAreas.GERMANY | Headline and sovereign |
| Ireland | ECB.StressAreas.IrelandECB.StressAreas.IRELAND | Headline and sovereign |
| Italy | ECB.StressAreas.ItalyECB.StressAreas.ITALY | Headline and sovereign |
| Netherlands | ECB.StressAreas.NetherlandsECB.StressAreas.NETHERLANDS | Headline and sovereign |
| Portugal | ECB.StressAreas.PortugalECB.StressAreas.PORTUGAL | Headline and sovereign |
| Spain | ECB.StressAreas.SpainECB.StressAreas.SPAIN | Headline and sovereign |
| China | ECB.StressAreas.ChinaECB.StressAreas.CHINA | Headline |
| United Kingdom | ECB.StressAreas.UnitedKingdomECB.StressAreas.UNITED_KINGDOM | Headline |
| United States | ECB.StressAreas.UnitedStatesECB.StressAreas.UNITED_STATES | Headline |
Example Applications
The Systemic Stress dataset enables you to measure financial stress in Europe and other major economies. Examples include the following strategies:
- Reducing risk exposure as the stress indicator rises
- Comparing euro area and US stress to tell a regional shock from a global one
- Using sovereign stress to time peripheral versus core European exposure
Classic Algorithm Example
The following example algorithm liquidates SPY when the composite stress indicator is above 0.1 in both the euro area and the United States. Otherwise, it holds SPY.
from AlgorithmImports import *
class ECBSystemicStressAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2019, 1, 1)
self.set_end_date(2021, 3, 31)
self.set_cash(100000)
self.equity = self.add_equity("SPY", Resolution.DAILY).symbol
self.euro_area = self.add_data(ECBSystemicStress, ECB.StressAreas.EURO_AREA, Resolution.DAILY).symbol
self.united_states = self.add_data(ECBSystemicStress, ECB.StressAreas.UNITED_STATES, Resolution.DAILY).symbol
self.euro_area_stress = None
self.united_states_stress = None
def on_data(self, slice: Slice) -> None:
readings = slice.get(ECBSystemicStress)
# Keep the latest composite reading of each economy.
if self.euro_area in readings and readings[self.euro_area].composite is not None:
self.euro_area_stress = readings[self.euro_area].composite
self.log(f"{readings[self.euro_area].end_time} euro area stress {self.euro_area_stress}, "
f"of which intermediaries {readings[self.euro_area].financial_intermediaries_contribution}")
if self.united_states in readings and readings[self.united_states].composite is not None:
self.united_states_stress = readings[self.united_states].composite
if self.euro_area_stress is None or self.united_states_stress is None:
return
# Wait for the SPY bar before trading.
if self.equity not in slice.bars:
return
# Exit SPY when stress is elevated in both economies.
stressed = self.euro_area_stress > 0.1 and self.united_states_stress > 0.1
if stressed:
if self.portfolio[self.equity].invested:
self.liquidate(self.equity)
elif not self.portfolio[self.equity].invested:
self.set_holdings(self.equity, 1) public class ECBSystemicStressAlgorithm : QCAlgorithm
{
private Symbol _equity;
private Symbol _euroArea;
private Symbol _unitedStates;
private decimal? _euroAreaStress;
private decimal? _unitedStatesStress;
public override void Initialize()
{
SetStartDate(2019, 1, 1);
SetEndDate(2021, 3, 31);
SetCash(100000);
_equity = AddEquity("SPY", Resolution.Daily).Symbol;
_euroArea = AddData<ECBSystemicStress>(ECB.StressAreas.EuroArea, Resolution.Daily).Symbol;
_unitedStates = AddData<ECBSystemicStress>(ECB.StressAreas.UnitedStates, Resolution.Daily).Symbol;
}
public override void OnData(Slice slice)
{
var readings = slice.Get<ECBSystemicStress>();
// Keep the latest composite reading of each economy.
if (readings.ContainsKey(_euroArea) && readings[_euroArea].Composite.HasValue)
{
_euroAreaStress = readings[_euroArea].Composite;
Log($"{readings[_euroArea].EndTime} euro area stress {_euroAreaStress}, "
+ $"of which intermediaries {readings[_euroArea].FinancialIntermediariesContribution}");
}
if (readings.ContainsKey(_unitedStates) && readings[_unitedStates].Composite.HasValue)
{
_unitedStatesStress = readings[_unitedStates].Composite;
}
if (!_euroAreaStress.HasValue || !_unitedStatesStress.HasValue)
{
return;
}
// Wait for the SPY bar before trading.
if (!slice.Bars.ContainsKey(_equity))
{
return;
}
// Exit SPY when stress is elevated in both economies.
var stressed = _euroAreaStress > 0.1m && _unitedStatesStress > 0.1m;
if (stressed)
{
if (Portfolio[_equity].Invested)
{
Liquidate(_equity);
}
}
else if (!Portfolio[_equity].Invested)
{
SetHoldings(_equity, 1);
}
}
}
Framework Algorithm Example
The following example algorithm emits flat insights for SPY when the composite stress indicator exceeds 0.1 in both the euro area and the United States. Otherwise, it emits up insights.
from AlgorithmImports import *
class ECBSystemicStressFrameworkAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2019, 1, 1)
self.set_end_date(2021, 3, 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(ECBSystemicStressAlphaModel(self))
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
self.set_execution(ImmediateExecutionModel())
class ECBSystemicStressAlphaModel(AlphaModel):
"""Emits insights from systemic stress on both sides of the Atlantic."""
def __init__(self, algorithm):
self._euro_area = algorithm.add_data(ECBSystemicStress, ECB.StressAreas.EURO_AREA, Resolution.DAILY).symbol
self._united_states = algorithm.add_data(ECBSystemicStress, ECB.StressAreas.UNITED_STATES, Resolution.DAILY).symbol
history = algorithm.history[ECBSystemicStress](self._euro_area, timedelta(days=365), Resolution.DAILY)
algorithm.debug(f"Got {len(list(history))} historical stress readings")
self._euro_area_stress = None
self._united_states_stress = None
self._symbols = []
def update(self, algorithm, data):
readings = data.get(ECBSystemicStress)
# Keep the latest composite reading of each economy.
if self._euro_area in readings and readings[self._euro_area].composite is not None:
self._euro_area_stress = readings[self._euro_area].composite
if self._united_states in readings and readings[self._united_states].composite is not None:
self._united_states_stress = readings[self._united_states].composite
if self._euro_area_stress is None or self._united_states_stress is None:
return []
# Emit flat insights when stress is elevated in both economies.
stressed = self._euro_area_stress > 0.1 and self._united_states_stress > 0.1
direction = InsightDirection.FLAT if stressed else InsightDirection.UP
# Emit insights only for the securities that have a bar in this slice.
return [Insight.price(symbol, timedelta(days=14), direction)
for symbol in self._symbols if symbol in data.bars]
def on_securities_changed(self, algorithm, changes):
for security in changes.added_securities:
self._symbols.append(security.symbol)
for security in changes.removed_securities:
if security.symbol in self._symbols:
self._symbols.remove(security.symbol) public class ECBSystemicStressFrameworkAlgorithm : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2019, 1, 1);
SetEndDate(2021, 3, 31);
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
var symbols = new[] { QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA) };
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
AddAlpha(new ECBSystemicStressAlphaModel(this));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
}
}
public class ECBSystemicStressAlphaModel : AlphaModel
{
private readonly Symbol _euroArea;
private readonly Symbol _unitedStates;
private readonly List<Symbol> _symbols = new();
private decimal? _euroAreaStress;
private decimal? _unitedStatesStress;
public ECBSystemicStressAlphaModel(QCAlgorithm algorithm)
{
_euroArea = algorithm.AddData<ECBSystemicStress>(ECB.StressAreas.EuroArea, Resolution.Daily).Symbol;
_unitedStates = algorithm.AddData<ECBSystemicStress>(ECB.StressAreas.UnitedStates, Resolution.Daily).Symbol;
var history = algorithm.History<ECBSystemicStress>(_euroArea, TimeSpan.FromDays(365), Resolution.Daily);
algorithm.Debug($"Got {history.Count()} historical stress readings");
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var readings = data.Get<ECBSystemicStress>();
// Keep the latest composite reading of each economy.
if (readings.ContainsKey(_euroArea) && readings[_euroArea].Composite.HasValue)
{
_euroAreaStress = readings[_euroArea].Composite;
}
if (readings.ContainsKey(_unitedStates) && readings[_unitedStates].Composite.HasValue)
{
_unitedStatesStress = readings[_unitedStates].Composite;
}
if (!_euroAreaStress.HasValue || !_unitedStatesStress.HasValue)
{
return Enumerable.Empty<Insight>();
}
// Emit flat insights when stress is elevated in both economies.
var stressed = _euroAreaStress > 0.1m && _unitedStatesStress > 0.1m;
var direction = stressed ? InsightDirection.Flat : InsightDirection.Up;
// Emit insights only for the securities that have a bar in this slice.
return _symbols.Where(symbol => data.Bars.ContainsKey(symbol))
.Select(symbol => Insight.Price(symbol, TimeSpan.FromDays(14), direction));
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var security in changes.AddedSecurities)
{
_symbols.Add(security.Symbol);
}
foreach (var security in changes.RemovedSecurities)
{
_symbols.Remove(security.Symbol);
}
}
}