Custom sizing for rolling futures
This page shows new SigTech users how to interpret and verify:
- Futures Rolling Strategy Building Block history output
- Strategy size
- Mark-to-market P&L calculation
- 1.Initial cash sizing Strategy
- 2.Strategy output reconciliation
- 3.Fixed number of Future Contracts Strategy
- 4.Generate the performance reports
import sigtech.framework as sig
from sigtech.framework.infra.objects.dtypes import FloatType
import datetime as dtm
import pandas as pd
import numpy as np
import seaborn as sns
sns.set(rc={'figure.figsize':(18,6)})
sig.config.init()
In this example the strategy will buy initially as many future contracts as possible as set by the
initial_cash
. We will start with a simple example to buy 100 contracts of Crude Oil Futures. Note: if no
initial_cash
is set the strategy assumes that 1000 currency units are available.Input
Output
# start date of the strategy
start_date = dtm.date(2017, 3, 2)
# contract to enter into (front)
co = sig.obj.get('COK17 COMDTY')
# number of contracts
n_contracts = 100
# price of the future at inception
price_t = co.history().loc['2017-03-02']
# initial_cash required for this strategy
initial_cash = co.contract_size * n_contracts * price_t
print(initial_cash)
5508000.0
We want to purely look at the mark-to-market P&L isolating trading costs and cash interest accrual.
co_strat = sig.RollingFutureStrategy(
currency='USD',
start_date=start_date,
contract_code='CO',
contract_sector='COMDTY',
rolling_rule='front',
front_offset='-5:-4',
include_trading_costs=False, # don't include trading costs
total_return=False, # don't include cash accrual
set_weight_from_initial_cash=True,
initial_cash=initial_cash
)
co_strat.history().plot();

The
history
method returns the Mark-to-Market (MtM) P&L. This can easily be reconciled using price_series()
method and calculating the MtM as:where:
is the notional of the future contract
is the number of contracts held
is the price difference from t to t+1
price = co_strat.price_series()
print(price.head())
price.plot();

Input
Output
print('MtM\n', initial_cash + (price.diff().head(8) * co.contract_size * n_contracts))
print('----')
print('history\n', co_strat.history()[2:9])
MtM
2017-03-03 NaN
2017-03-06 5519000.0
2017-03-07 5499000.0
2017-03-08 5227000.0
2017-03-09 5416000.0
2017-03-10 5426000.0
2017-03-13 5506000.0
2017-03-14 5465000.0
dtype: float64
----
history
2017-03-06 5519000.0
2017-03-07 5510000.0
2017-03-08 5229000.0
2017-03-09 5137000.0
2017-03-10 5055000.0
2017-03-13 5053000.0
2017-03-14 5010000.0
To verify your position and size, use
Strategy.plot.portfolio_table
.Note: as we are using previous day price to calculate
initial_cash
there could be some differences from our calculation and final allocation as the usage is relative to the execution day price. The output below shows 100.785% exposure of our AUM equivalent to 100 contracts.Since the size is relative to the cash available and the futures price, in the next roll our 100 contracts initial exposure could vary up or down. This is illustrated in the output below. From the available cash the strategy rolls from 100 to 101 trade units, or contracts:
co_strat.plot.portfolio_table(
'TOP_ORDER_PTS',
start_dt=start_date,
end_dt=start_date+dtm.timedelta(days=30),
unit_type='TRADE') # shows the portfolio in number of contracts

The default sizing explained above can be overwritten so that a fixed number of contracts is always traded independent of the
initial_cash
amount. The argument
fixed_contracts
in the RollingFuturesStrategy allows to modify the roll behaviour without affecting any other property. Comparing the two strategies we can quantify the impact of sizing in our strategies.
co_fixed_sizing = sig.RollingFutureStrategy(
currency='USD',
start_date=start_date,
contract_code='CO',
contract_sector='COMDTY',
rolling_rule='front',
front_offset='-5:-4',
include_trading_costs=False, # don't include trading costs
total_return=False, # don't include cash accrual
set_weight_from_initial_cash=True,
initial_cash=initial_cash,
fixed_contracts=100.0, # fixed sizing
)
pd.DataFrame({
'CO_fixed': co_fixed_sizing.history(),
'CO_AUM': co_strat.history()
}).plot(legend=True);

CO with initial cash sizing vs CO with fixed number of lots sizing
Ensuring the strategy is rolling 100 contracts:
co_fixed_sizing.plot.portfolio_table(
'TOP_ORDER_PTS',
start_dt=start_date,
end_dt=start_date+dtm.timedelta(days=30),
unit_type='TRADE'
)

sig.PerformanceReport([co_fixed_sizing, co_strat]).report()



RollingFuturesStrategies
can be sized by AUM or a fixed number of contracts.- The initial sizing is calculated as.
- Verifying the MtM is possible and easy.
Strategy.plot.portfolio_table
can return the portfolio using AUM or contracts as the unit type.
Last modified 8mo ago