Commodity Calendar Spread Strategy#

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 this notebook is to show a commodity calendar spread strategy. A commodity calendar spread strategy involves buying a futures contract for the same commodity in one month and selling one in a different month.

In this notebook we create new rolling future strategies to manage the rolls of commodity futures. These are then combined in ‘pair’ baskets to trade the spread in futures of the same commodity but different expiries. Finally, all of the commodities are combined in one strategy.

Environment#

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

[ ]:
import sigtech.framework as sig

import datetime as dtm
import pandas as pd
import numpy as np
import seaborn as sns

sns.set(rc={'figure.figsize': (18, 6)})

env = sig.init(env_date=dtm.date(2024, 2, 22))

Universe#

List of assets that will form part of the strategy.

[ ]:
contract_codes = [
    'LH',  # Lean Hogs
    'CO',  # Crude Oil Brent
    'S ',  # Soybean
    'W ',  # Wheat
]

For each of the commodities chosen, a RollingFutureStrategy object will be created, thus handling the roll of the future contracts.

[ ]:
def get_rf(contract, rolling_rule, direction, contract_offset=0, monthly_roll_days='1,2'):
    return sig.RollingFutureStrategy(
        currency='USD',
        start_date=dtm.date(2010, 1, 4),
        contract_code=contract,
        contract_sector='COMDTY',
        rolling_rule=rolling_rule,
        total_return=True,
        include_trading_costs=False,
        direction=direction,
        contract_offset=contract_offset,
        monthly_roll_days=monthly_roll_days,
    )

Strategy#

This strategy involves buying a futures contract for the same commodity in one month and selling one in a different month. In the example below we use the F_0 roll schedule to determine which contract to buy and sell.

Now another helper function can combine long and short versions of the rolling futures with different contract offsets. To perform the combination, the BasketStrategy class is used.

[ ]:
def get_pair(contract, rolling_rule, contract_offset, rebalance_frequency='EOM'):
    short_rf = get_rf(contract, rolling_rule, 'short')
    long_rf = get_rf(contract, rolling_rule, 'long',
                     contract_offset=contract_offset)
    return sig.BasketStrategy(
        currency='USD',
        start_date=dtm.date(2010, 1, 4),
        constituent_names=[long_rf.name, short_rf.name],
        weights=[0.5, 0.5],
        rebalance_frequency=rebalance_frequency,
    )

Portfolio#

Create an equal weight portfolio, of calendar spread rolling futures strategies, that rebalances once per month at the end of the month.

[ ]:
st = sig.BasketStrategy(
    currency='USD',
    start_date=dtm.date(2010, 1, 4),
    constituent_names=[get_pair(i, 'F_0', 3).name for i in contract_codes],
    weights=[1 / len(contract_codes)] * len(contract_codes),
    rebalance_frequency='EOM',
    intersecting_business_days=True,
)

Performance#

Here we will show the performance of the portfolio. To learn more about how to customise performance reports.

[ ]:
sig.PerformanceReport(st.history().rename('Commodity pair basket strategy'), cash=sig.CashIndex.from_currency('USD')).report()