Bond Auctions#

New user? The best way to learn SigTech is to follow the steps in our user guide.

Unrestricted data: This notebook only uses data in our core offer to all users. Go ahead and run it.

Changes will not be saved: Edits made to SigTech’s example notebooks like this will only persist for the duration of your session. When you restart the research environment, this notebook will have been restored to its original state, and any changes you have made will have been lost. To make permanent changes, copy and paste the content to a new notebook in one of your workspaces.

Introduction#

The purpose of thise notebook is to show how a to include non-tradeable data such as bond auction data as a basis for a strategy, which in this case are expressed via bond futures.

Environment#

This section will import relevant internal and external libraries, as well as setting up the platform environment.

[ ]:
import sigtech.framework as sig

import calendar
import datetime as dtm
import pandas as pd
import seaborn as sns

sns.set(rc={'figure.figsize': (18, 6)})
env = sig.init(env_date=dtm.date(2024, 2, 22))

Universe#

The aim is to get exposure to the bonds through futures. However, because we don’t want to worry about expiring futures contracts, we will not invest in the contracts directly but rather trade them through a RollingFutureStrategy.

RollingFutureStrategy is a built-in strategy that takes exposure in a futures contract and rolls down the term structure according to a given rule.

[ ]:
rfs = sig.RollingFutureStrategy(
    currency="USD",
    contract_code="TY",
    contract_sector="COMDTY",
    rolling_rule="front",
    front_offset="-4,-4",  # roll 4 days before expiry
    total_return=False,  # returns excess of cash
    initial_cash=1e6,  # AUM of $1mn
)
rfs.history().plot(title="NAV of tradable asset (strategy)")

The SigTech platform offers bond auction data on specific tenors and issuing country. Once the bond auction data is queried, the auction dates can be retrieved by using the property .calendar_days such as below:

[ ]:
ust_cal = sig.obj.get("US_GOVT_AUC_10Y CALENDAR")
ust_cal.calendar_days[0:10]

Strategy#

We will now construct a signal dataframe. The column name will be the name (ticker) of the asset we intend to trade and the value will be a simple binary +1 (long) or -1 (short).

The strategy involves going long on the bond auction date, and staying long in the bond future until the end-of-month at which point the strategy exits the position, and then stays flat until the next auction date.

[ ]:
sdf = pd.DataFrame(-1., index=rfs.history().index, columns=[rfs.name])

auction_dates = pd.to_datetime([i for i in ust_cal.calendar_days if i >= rfs.start_date])

for h in auction_dates:

    # Go long on auction date
    last = sdf.index.asof(h)
    sdf.loc[last] = 1.

    # Get EOM
    _, ndim = calendar.monthrange(h.year, h.month)
    eom = dtm.date(h.year, h.month, ndim)

    # Stay long until EOM
    sdf.loc[h:eom, :] = 1.

sdf.iloc[80:110]

We will truncate the signal to only cover the days when an actual change of weights has occurred.

[ ]:
sdf = sdf[sdf.diff() != 0].dropna()
sdf.head(10)

Portfolio construction#

[ ]:
strategy = sig.SignalStrategy(
    currency=rfs.currency,
    start_date=dtm.date(2000, 5, 4),
    end_date=dtm.date(2010, 5, 4),

    signal_name=sig.signal_library.core.from_ts(sdf).name,

    # we will only rebalance when our signal has values
    use_signal_for_rebalance_dates=True,

    # owing to the predictability of the strategy, we are comfortable executing on T0
    t0_execution=True,

    # AUM of $1mn
    initial_cash=1e6,

    total_return=False,
    convert_long_short_weight=False,
    include_trading_costs=False,
    ticker='GOV BOND AUCTION'
)
strategy.history().plot(title="Backtest resulting NAV");

Performance analytics#

[ ]:
sig.PerformanceReport(strategy.history()).report()