Trade sizing

This page shows how trade sizing is configured on the SigTech platform.

The framework runs strategies in a model world to give target positions and orders. These need to be scaled and combined with the actual positions held to obtain actual executable trades. This action is performed by a separate trading module.

Learn more: Example notebooks.


This section will import the 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.internal.strategies.timeline.trading_order import TradingOrder

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

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

if not sig.config.is_initialised():

Strategy example

The following simple basket consists of a rolling future and rolling FX forwards, going long GBP and short EUR.

def get_fxrf(long_ccy, forward_tenor, direction):
    return sig.RollingFXForwardStrategy(
        long_currency=long_ccy,, 1, 5),
st1 = get_fxrf('GBP', '3M_IMM', 'long')
st2 = get_fxrf('EUR', '3M_IMM', 'short')
rf = sig.RollingFutureStrategy(
    currency='USD',, 1, 4),
st = sig.BasketStrategy(
    currency='USD',, 1, 10),
    weights=[0.25, 0.25, 0.5],

The full strategy:


Model trades

The orders and positions are extracted from the strategy timeline, on the specified trade_date. These are used to calculate netted positions and an overall target model position:

trade_date =, 6, 29)
pos = st.timeline_holdings.positions()
dt = st.decision_dt_from_date(trade_date)
port = st.expanded_slice(dt)
orders_df = pd.DataFrame([TradingOrder(order).info() for order in port.orders])
positions_df = pd.DataFrame(
    [(, p.quantity) for p in port.positions],
    columns=['name', 'quantity']
# net and remove cash entries
positions = positions_df.groupby('name').sum().drop(
# net and remove cash entries
positions = positions_df.groupby('name').sum().drop(
# target position
future_pos = (positions + orders)
# orders


The notional exposures of the target and orders based on the strategies sizing date:

size_date = st.size_date_from_date(trade_date)
model_target = {}
for name, quantity in future_pos['quantity'].items():
    model_target[name] = st.get_exposure_weight(
        sig.obj.get(name), quantity, size_date

model_target = pd.Series(model_target)

model_diff = {}

for name, quantity in orders['quantity'].items():
    model_diff[name] = st.get_exposure_weight(
        sig.obj.get(name), quantity, size_date

model_diff = pd.Series(model_diff)
# target model exposures
# order exposures


The strategy is valued as of the sizing date, then a scaling factor is applied based on a funds AUM. The AUM is set to $100mn:

aum = 100000000
strategy_valuation = st.valuation_price_base(size_date)
scaling = aum / strategy_valuation

The model future units do not include contract size factors. To obtain the contract numbers the following functions need to be defined:

Note: These functions can then be applied to DataFrames to scale the future entries.

def future_scaling(instrument, qty, size_date):
    imnt = sig.obj.get(instrument)
    if hasattr(imnt, 'fut_val_pt'):
        return round(qty / imnt.fut_val_pt(d=size_date), 0)
        return qty

def df_future_scaling(df, size_date):
    df_copy = df.copy()
    df_copy['quantity'] = [
        future_scaling(x, y, size_date)
        for x, y in df_copy['quantity'].items()
    return df_copy

The currently held positions are read in from a portfolio management system. Example data used in the following example:

pms_positions = pd.Series({
    'GBPUSD 1.341317214603 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD': 33000000,
    'EURUSD 1.187372750628 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD': -21500000,
    'ESU18 INDEX': 370,

The resulting trade table is constructed:

trade_table = pd.concat([
    df_future_scaling(future_pos, size_date),
    df_future_scaling(orders, size_date),
    df_future_scaling(future_pos * scaling, size_date),
    df_future_scaling(orders * scaling, size_date),
    df_future_scaling(future_pos * scaling,
                      size_date).subtract(pms_positions, axis=0)
], axis=1, sort=True)
trade_table.index = [
    sig.obj.get(name).trade_name for name in trade_table.index
trade_table.columns = [
    'Target Strategy Pos', 'Strategy Orders', 'Model Target Pos', 'Model Orders', 'PMS Pos', 'Trade Qty'
for col in ['Target Strategy Pos', 'Strategy Orders', 'Model Target Pos', 'Model Orders', 'PMS Pos', 'Trade Qty']:
    trade_table[col] = trade_table[col].map('{:,.0f}'.format) = 'Instrument Name'

This is formatted and combined with trade flags to give the execution output.

Note: the forward quantities here are not given in USD and the future positions are given in contract number.

An overview of placed FX forward orders:

Another example output follows in the case of a random futures portfolio. In this example the PMS is Murex.

Murex PMS screenshot showing futures orders:

There is a separation of the strategy model world and trading module. The strategy output is run and stored in a database. This output is then read by the trading module and combined with positions, read from the PMS.

The model order quantities can be obtained directly from the strategy using the evaluate_trades method.

st.inspect.evaluate_trades(dt, aum)

Last updated

© 2023 SIG Technologies Limited