book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Treasury Department

US Treasury Yield Curve

Introduction

The US Treasury Yield Curve datasets tracks the yield curve rate from the US Department of the Treasury. The data starts in January 1990 and is delivered on a daily frequency. This dataset is calculated from composites of indicative, bid-side market quotations (not actual transactions) obtained by the Federal Reserve Bank of New York at or near 3:30 PM Eastern Time (ET) each trading day.

For more information about the US Treasury Yield Curve dataset, including CLI commands and pricing, see the dataset listing.

About the Provider

The Treasury Department is the executive agency responsible for promoting economic prosperity and ensuring the financial security of the United States. The Department is responsible for a wide range of activities such as advising the President on economic and financial issues, encouraging sustainable economic growth, and fostering improved governance in financial institutions. The Department of the Treasury operates and maintains systems that are critical to the nation's financial infrastructure, such as the production of coin and currency, the disbursement of payments to the American public, revenue collection, and the borrowing of funds necessary to run the federal government.

Getting Started

The following snippet demonstrates how to request data from the US Treasury Yield Curve dataset:

self.dataset_symbol = self.add_data(USTreasuryYieldCurveRate, "USTYCR").symbol
_datasetSymbol = AddData<USTreasuryYieldCurveRate>("USTYCR").Symbol;

Data Summary

The following table describes the dataset properties:

PropertyValue
Start DateJanuary 1990
Coverage1 Dataset
Data DensitySparse
ResolutionDaily
TimezoneNew York

Requesting Data

To add US Treasury Yield Curve 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 QuiverCongressDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2020, 6, 1)
        self.set_cash(100000)

        self.dataset_symbol = self.add_data(USTreasuryYieldCurveRate, "USTYCR").symbol
public class USTreasuryYieldCurveDataAlgorithm : QCAlgorithm
{
    private Symbol _datasetSymbol;

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

        _datasetSymbol = AddData<USTreasuryYieldCurveRate>("USTYCR").Symbol;
    }
}

Accessing Data

To get the current US Treasury Yield Curve 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} one month value at {slice.time}: {data_point.one_month}")
public override void OnData(Slice slice)
{
    if (slice.ContainsKey(_datasetSymbol))
    {
        var dataPoint = slice[_datasetSymbol];
        Log($"{_datasetSymbol} one month value at {slice.Time}: {dataPoint.OneMonth}");
    }
}

Historical Data

To get historical US Treasury Yield Curve 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.dataset_symbol, 100, Resolution.DAILY)

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

For more information about historical data, see History Requests.

Remove Subscriptions

To remove your subscription to US Treasury Yield Curve data, call the RemoveSecurityremove_security method.

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

Example Applications

The US Treasury Yield Curve dataset enables you to monitor the yields of bonds with numerous maturities in your strategies. Examples include the following strategies:

  • Short selling SPY when the yield curve inverts
  • Buying short-term Treasuries and short selling long-term Treasuries when the yield curve becomes steeper (aka curve steepener trade)

Classic Algorithm Example

The following example algorithm short sells SPY for two years when the yield curve inverts:

from AlgorithmImports import *
from QuantConnect.DataSource import *

class USTreasuryDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2000, 3, 1)
        self.set_end_date(2021, 6, 1)
        self.set_cash(100000)

        # Request SPY as the market representative for trading
        self.spy_symbol = self.add_equity("SPY", Resolution.HOUR).symbol

        # Requesting yield curve data for trade signal generation (inversion)
        self.yield_curve_symbol = self.add_data(USTreasuryYieldCurveRate, "USTYCR").symbol

        # Historical data
        history = self.history(USTreasuryYieldCurveRate, self.yield_curve_symbol, 60, Resolution.DAILY)
        self.debug(f"We got {len(history)} items from our history request")
        
        self.last_inversion = datetime.min

    def on_data(self, slice: Slice) -> None:
        # Trade only based on updated yield curve data
        if not slice.contains_key(self.yield_curve_symbol):
            return
        rates = slice[self.yield_curve_symbol]
        
        # We need the 10-year bond yield rate and 2-year bond yield rate for trade signal generation
        if not (rates.ten_year is not None and rates.two_year is not None):
            return
        
        # Only advance if a year has gone by, since the inversion signal indicates longer term market regime that will not revert in a short period
        if (self.time - self.last_inversion < timedelta(days=365)):
            return

        # Normally, 10y yield should be greater than 2y yield due to default risk accumulation
        # But if an inversion occurs, it means the market expects a recession in short term such that the near-expiry bond is more likely to default
        # if there is a yield curve inversion after not having one for a year, short sell SPY for two years for the expected down market
        if (not self.portfolio.invested and rates.two_year > rates.ten_year):
            self.debug(f"{self.time} - Yield curve inversion! Shorting the market for two years")
            self.set_holdings(self.spy_symbol, -0.5)
            self.last_inversion = self.time
            return
        
        # If two years have passed, liquidate our position in SPY assuming the market starts resilience
        if (self.time - self.last_inversion >= timedelta(days=365 * 2)):
            self.liquidate(self.spy_symbol)
public class USTreasuryDataAlgorithm : QCAlgorithm
{
    private Symbol _spySymbol;
    private Symbol _yieldCurveSymbol;
    private DateTime _lastInversion = DateTime.MinValue;
    
    public override void Initialize()
    {
        SetStartDate(2000, 3, 1);
        SetEndDate(2021, 6, 1);
        SetCash(100000);

        // Request SPY as the market representative for trading
        _spySymbol = AddEquity("SPY", Resolution.Hour).Symbol;

        // Requesting yield curve data for trade signal generation (inversion)
        _yieldCurveSymbol = AddData<USTreasuryYieldCurveRate>("USTYCR").Symbol;

        // Historical data
        var history = History<USTreasuryYieldCurveRate>(_yieldCurveSymbol, 60, Resolution.Daily);
        Debug($"We got {history.Count()} items from our history request");
    }
    
    
    public override void OnData(Slice slice)
    {
        // Trade only based on updated yield curve data
        if (!slice.TryGetValue(_yieldCurveSymbol, out var rates))
        {
            return;
        }
        
        // We need the 10-year bond yield rate and 2-year bond yield rate for trade signal generation
        if (!rates.TenYear.HasValue || !rates.TwoYear.HasValue)
        {
            return;
        }
        
        // Only advance if a year has gone by, since the inversion signal indicates longer term market regime that will not revert in a short period
        if (Time - _lastInversion < TimeSpan.FromDays(365))
        {
            return;
        }
        
        // Normally, 10y yield should be greater than 2y yield due to default risk accumulation
        // But if an inversion occurs, it means the market expects a recession in short term such that the near-expiry bond is more likely to default
        // if there is a yield curve inversion after not having one for a year, short sell SPY for two years for the expected down market
        if (!Portfolio.Invested && rates.TwoYear > rates.TenYear)
        {
            Debug($"{Time} - Yield curve inversion! Shorting the market for two years");
            SetHoldings(_spySymbol, -0.5); 
                _lastInversion = Time;
            return;
        }
        
        
        // If two years have passed, liquidate our position in SPY assuming the market starts resilience
        if (Time - _lastInversion >= TimeSpan.FromDays(365 * 2))
        {
            Liquidate(_spySymbol);
        }
    }
}

Framework Algorithm Example

The following example algorithm short sells SPY for two years when the yield curve inverts:

from AlgorithmImports import *
from QuantConnect.DataSource import *

class USTreasuryDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2000, 3, 1)
        self.set_end_date(2021, 6, 1)
        self.set_cash(100000)

        self.universe_settings.resolution = Resolution.HOUR
        # Universe only have SPY as the market representative for trading
        symbols = [Symbol.create("SPY", SecurityType.EQUITY, Market.USA)]
        self.add_universe_selection(ManualUniverseSelectionModel(symbols))   
        # Custom alpha model that emit insight according to US Treasury data
        self.add_alpha(USTreasuryAlphaModel(self))
        # Use insight weighting PCM to limit the size of investment, reduce the fluctuation of the portfolio value
        self.set_portfolio_construction(InsightWeightingPortfolioConstructionModel(lambda time: None))
        
class USTreasuryAlphaModel(AlphaModel):

    spy_symbol = None
    last_inversion = datetime.min
    
    def __init__(self, algorithm: QCAlgorithm) -> None:
        # Requesting yield curve data for trade signal generation (inversion)
        self.yield_curve_symbol = algorithm.add_data(USTreasuryYieldCurveRate, "USTYCR").symbol

        # Historical data
        history = algorithm.history(self.yield_curve_symbol, 60, Resolution.DAILY)
        algorithm.debug(f"We got {len(history)} items from our history request")

    def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]:
        # Trade only based on updated yield curve data
        if not (slice.contains_key(self.yield_curve_symbol) and self.spy_symbol is not None):
            return []
        rates = slice[self.yield_curve_symbol]
        
        # We need the 10-year bond yield rate and 2-year bond yield rate for trade signal generation
        if not (rates.ten_year is not None and rates.two_year is not None):
            return []
        
        # Only advance if a year has gone by, since the inversion signal indicates longer term market regime that will not revert in a short period
        if (slice.time - self.last_inversion < timedelta(days=365)):
            return []
        
        # Normally, 10y yield should be greater than 2y yield due to default risk accumulation
        # But if an inversion occurs, it means the market expects a recession in short term such that the near-expiry bond is more likely to default
        # if there is a yield curve inversion after not having one for a year, short sell SPY for two years for the expected down market
        if (not algorithm.portfolio.invested and rates.two_year > rates.ten_year):
            algorithm.debug(f"{slice.time} - Yield curve inversion! Shorting the market for two years")
            self.last_inversion = slice.time
            return [Insight.price(self.spy_symbol, slice.time + timedelta(days=2*365), InsightDirection.DOWN, None, None, None, 0.5)]
        return []
        

    def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for security in changes.added_securities:
            self.spy_symbol = security.symbol
public class USTreasuryYieldCurveDataAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2000, 3, 1);
        SetEndDate(2021, 6, 1);
        SetCash(100000);

        UniverseSettings.Resolution = Resolution.Hour;
        // Universe only have SPY as the market representative for trading
        var symbols = new[] {QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)};
        AddUniverseSelection(new ManualUniverseSelectionModel(symbols));
        // Custom alpha model that emit insight according to US Treasury data
        AddAlpha(new USTreasuryAlphaModel(this));
        // Use insight weighting PCM to limit the size of investment, reduce the fluctuation of the portfolio value
        SetPortfolioConstruction(new InsightWeightingPortfolioConstructionModel((time) => None));
    }
}

public class USTreasuryAlphaModel : AlphaModel
{
    private Symbol? _spySymbol = None;
    private Symbol _yieldCurveSymbol;
    private DateTime _lastInversion = DateTime.MinValue;
    
    public USTreasuryAlphaModel(QCAlgorithm algorithm)
    {
        // Requesting yield curve data for trade signal generation (inversion)
        _yieldCurveSymbol = algorithm.AddData<USTreasuryYieldCurveRate>("USTYCR").Symbol;

        // Historical data
        var history = algorithm.History<USTreasuryYieldCurveRate>(_yieldCurveSymbol, 60, Resolution.Daily);
        algorithm.Debug($"We got {history.Count()} items from our history request");
    }

    public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice)
    {
        var insights = new List<Insight>();

        // Trade only based on updated yield curve data
        if (!slice.TryGetValue(_yieldCurveSymbol, out var rates) || _spySymbol == None)
        {
            return insights;
        }
        
        // We need the 10-year bond yield rate and 2-year bond yield rate for trade signal generation
        if (!rates.TenYear.HasValue || !rates.TwoYear.HasValue)
        {
            return insights;
        }
        
        // Only advance if a year has gone by, since the inversion signal indicates longer term market regime that will not revert in a short period
        if (slice.Time - _lastInversion < TimeSpan.FromDays(365))
        {
            return insights;
        }
        
        // Normally, 10y yield should be greater than 2y yield due to default risk accumulation
        // But if an inversion occurs, it means the market expects a recession in short term such that the near-expiry bond is more likely to default
        // if there is a yield curve inversion after not having one for a year, short sell SPY for two years for the expected down market
        if (!algorithm.Portfolio.Invested && rates.TwoYear > rates.TenYear)
        {
            algorithm.Debug($"{slice.Time} - Yield curve inversion! Shorting the market for two years");
            _lastInversion = slice.Time;
            insights.Add(Insight.Price(_spySymbol, slice.Time + TimeSpan.FromDays(2*365), InsightDirection.Down, None, None, None, 0.5));
        }
        
        return insights;
    }

    public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
    {
        foreach (var security in changes.AddedSecurities)
        {
            _spySymbol = security.Symbol;
        }
    }
}

Data Point Attributes

The US Treasury Yield Curve dataset provides USTreasuryYieldCurveRate 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: