Framework v8
Search
K

Position rounding

This page shows the platform's functionality to investigate the impact of rounding off orders on the strategy performance.
Orders have a minimum size and can often only be traded in discrete units. By default, the platform simulation allows fractional units, with rounding applied when trades are exported. This allows strategies to be analysed and compared without consideration for the capital allocated to them.
The platform has additional functionality to see the impact that size has, or run the simulation with the discrete sizes enforced.
Learn more: Example notebooks

Environment

This section will import relevant internal and external libraries, as well as setting up the platform environment.
Learn more: Environment setup
import sigtech.framework as sig
from sigtech.framework.instruments.bonds import GovernmentBond
import datetime as dtm
import pandas as pd
import pytz
import seaborn as sns
sns.set(rc={'figure.figsize': (18, 6)})
if not sig.config.is_initialised():
sig.config.init()
sig.config.set(sig.config.FORCE_ORDER_ROUNDING, True)

Unit rounding definitions

The tradable sizes for each instrument vary and are defined on the instrument classes.
An example for government bonds:
Input
Output
GovernmentBond.rounded_units??
Signature: GovernmentBond.rounded_units(self, units, dt, to_trade=True)
Source:
def rounded_units(self, units, dt, to_trade=True):
"""Round bond face values to multiples of 1000"""
return self.positions_to_units(int(self.units_to_positions(units, dt) / 1000), dt) * 1000
File: ~/code/framework/sigtech/framework/instruments/bonds.py
Type: function
If required these settings can be adjusted. An example for adjusting this is given in the code below.
from sigtech.framework.instruments.bonds import GovernmentBond
def rounded_units(self, units, dt, to_trade=True):
"""Round bond face values to multiples of 10000"""
return self.positions_to_units(int(self.units_to_positions(units, dt) / 10000), dt) * 10000
GovernmentBond.rounded_units = rounded_units

Large AUM strategy example

To observe the impact of this flag we can create a simple basket of two rolling future strategies. Each of the rolling futures strategies are initialised with an AUM of 1m USD and the basket has 10m USD:
def get_rfs(contract_code: str) -> sig.RollingFutureStrategy:
return sig.RollingFutureStrategy(
currency='USD',
start_date=dtm.date(2010, 1, 4),
contract_code=contract_code,
contract_sector='INDEX',
rolling_rule='front',
front_offset='-6:-4'
)
ROLLING_FUTURE_START_AUM = 10 ** 6
st = sig.BasketStrategy(
currency='USD',
start_date=dtm.date(2017, 1, 6),
constituent_names=[
get_rfs('ES').clone_strategy(
{'initial_cash': ROLLING_FUTURE_START_AUM}
).name,
get_rfs('NQ').clone_strategy(
{'initial_cash': ROLLING_FUTURE_START_AUM}
).name
],
weights=[0.5, 0.5],
rebalance_frequency='EOM',
initial_cash=10000000,
)
Input
Output
st.history().plot(title='Basket Strategy Performance');
All the trades are in whole units:
Input
Output
st.inspect.evaluate_trades(dtm.datetime(2017, 1, 10, tzinfo=pytz.utc))

Small AUM strategy example

If the size of the basket is reduced to 100,000 USD, it is now too small to support the holdings of the rolling future strategies and no positions are held:
st2 = sig.BasketStrategy(
currency='USD',
start_date=dtm.date(2017, 1, 6),
constituent_names=[
get_rfs('ES').clone_strategy(
{'initial_cash': ROLLING_FUTURE_START_AUM}
).name,
get_rfs('NQ').clone_strategy(
{'initial_cash': ROLLING_FUTURE_START_AUM}
).name
],
weights=[0.5, 0.5],
rebalance_frequency='EOM',
initial_cash=100000,
)
Input
Output
st2.inspect.evaluate_trades(dtm.datetime(2017, 1, 10, tzinfo=pytz.utc))

Rounding impact summary

In addition to the flag provided in the configuration, each strategy has a method to investigate the impact of trading it with different allocations.
Note: this is independent of the FORCE_ORDER_ROUNDING flag, so does not require it to be active.
Call the approximate_rounding_summary method on the strategy to generate a report:
Input
Output
impact_data = st.analytics.approximate_rounding_summary(steps=24)
impact_data.plot(subplots=True);
The performance of this basket drops off near an AUM of 10e5.5 USD:
Input
Output
st.inspect.evaluate_trades(dtm.datetime(2019, 4, 10, tzinfo=pytz.utc), aum=10**5.5)

Impact approximation

The deviation from the simulated performance can also be observed over the history using the approximate_rounding_impact method on the strategy.
Input
Output
ax = (100 * pd.concat(
[st.analytics.approximate_rounding_impact(initial_aum=10 ** x).rename(str(10 ** x) + ' AUM') for x in (5, 6, 7)],
axis=1)).plot()
ax.set_ylabel('% Return Deviation');
© 2023 SIG Technologies Limited