Gold futures with fixed lots#

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 create an investment strategy that trades Gold futures with a fixed number of lots. ## Environment This section will import relevant internal and external libraries, as well as setting up the platform environment.

[ ]:
import sigtech.framework as sig
from sigtech.framework.instruments.futures import Future

from typing import Optional

import datetime as dtm
import seaborn as sns


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

Universe#

Get the futures rolling schedule from an a simple RollingFutureStrategy.

[ ]:
rfs = sig.RollingFutureStrategy(
    currency="USD",
    contract_code="GC",
    contract_sector="COMDTY",
    rolling_rule="rici",
    start_date=dtm.date(2010, 1, 4)
)

# We build the strategy
rfs.build()
[ ]:
roll_schedule = rfs.rolling_table
roll_schedule
[ ]:
roll_schedule = roll_schedule["rolled_in_contract"]

roll_schedule = roll_schedule[:env.asofdate]

roll_schedule = roll_schedule.to_dict()

Strategy#

[ ]:
class CustomFutureStrategy(sig.DailyStrategy):
    """
    Custom future strategy that trades a fixed number of lots at each rebalance.
    """
    roll_schedule: dict[dtm.date, str]
    fixed_lots: Optional[int] = 10

    def __post_init__(self):
        super().__post_init__()

    def strategy_initialization(self, dt):
        """ "Magic" function that is run before the strategy's first trading date. """

        # We loop over every day in our roll schedule and schedule a _processor_ for that day
        for d in self.roll_schedule.keys():
            self.add_method(d, self.roll)  # a processor is just a method

        # We will also schedule a daily margin cleanup
        self.add_method(dt, self.set_up_margin_cleaning)

    def set_up_margin_cleaning(self, dt):
        """ Schedule margin clean-up after we buy futures every day. """
        for d in self.history_schedule().all_data_dates():
            if d >= dt.date():
                self.add_margin_cleanup(d, Future)

    def roll(self, dt):
        """ Perform the roll. dt - the datetime at which the method is called. """

        # Trade out of our existing position
        for instrument, units in self.positions.iterate_instruments(dt):
            self.add_position_target(dt, instrument.name, 0.0, transaction_type="roll")

        # Get the contract to trade
        roll_date = dt.date()
        new_contract = self.roll_schedule[roll_date]

        # Calculate number of lots to trade
        lots = sig.obj.get(new_contract).positions_to_units(self.fixed_lots, dt)

        # Trade a fixed number of lots for that contract
        self.add_position_target(dt, new_contract, lots, transaction_type="roll")

Portfolio Construction#

[ ]:
my_strategy = CustomFutureStrategy(
    currency=rfs.currency,
    start_date=rfs.rolling_table.first_valid_index(),

    roll_schedule=roll_schedule,
    fixed_lots=10,

    initial_cash=1e6,  # start with $1mn AUM
)

Performance Analytics#

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