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.

Getting Started

The following snippet demonstrates how to request data from the Systemic Stress dataset:

self.euro_area = self.add_data(ECBSystemicStress, ECB.StressAreas.EURO_AREA, Resolution.DAILY).symbol
_euroArea = AddData<ECBSystemicStress>(ECB.StressAreas.EuroArea, Resolution.Daily).Symbol;

Data Summary

The following table describes the dataset properties:

PropertyValue
Start DateJanuary 1980
Asset Coverage14 Economies
Data DensitySparse
ResolutionDaily*
TimezoneBerlin

* Weekly data we fetch daily.

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.

Remove Subscriptions

To remove your subscription to Systemic Stress data, call the RemoveSecurityremove_security method.

self.remove_security(self._euro_area)
RemoveSecurity(_euroArea);

Supported Economies

The following table shows the accessor code you need to add each economy to your algorithm:

EconomyConstantDecomposition
Euro areaECB.StressAreas.EuroAreaECB.StressAreas.EURO_AREAFull
AustriaECB.StressAreas.AustriaECB.StressAreas.AUSTRIAHeadline and sovereign
BelgiumECB.StressAreas.BelgiumECB.StressAreas.BELGIUMHeadline and sovereign
FinlandECB.StressAreas.FinlandECB.StressAreas.FINLANDHeadline and sovereign
FranceECB.StressAreas.FranceECB.StressAreas.FRANCEHeadline and sovereign
GermanyECB.StressAreas.GermanyECB.StressAreas.GERMANYHeadline and sovereign
IrelandECB.StressAreas.IrelandECB.StressAreas.IRELANDHeadline and sovereign
ItalyECB.StressAreas.ItalyECB.StressAreas.ITALYHeadline and sovereign
NetherlandsECB.StressAreas.NetherlandsECB.StressAreas.NETHERLANDSHeadline and sovereign
PortugalECB.StressAreas.PortugalECB.StressAreas.PORTUGALHeadline and sovereign
SpainECB.StressAreas.SpainECB.StressAreas.SPAINHeadline and sovereign
ChinaECB.StressAreas.ChinaECB.StressAreas.CHINAHeadline
United KingdomECB.StressAreas.UnitedKingdomECB.StressAreas.UNITED_KINGDOMHeadline
United StatesECB.StressAreas.UnitedStatesECB.StressAreas.UNITED_STATESHeadline

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);
        }
    }
}

Data Point Attributes

The Systemic Stress dataset provides ECBSystemicStress 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: