Search…
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.

Environment

This section will import the relevant internal and external libraries, as well as setting up the platform environment.
Learn more: Environment setup
1
import sigtech.framework as sig
2
from sigtech.framework.internal.strategies.timeline.trading_order import TradingOrder
3
4
import datetime as dtm
5
import pandas as pd
6
import seaborn as sns
7
8
sns.set(rc={'figure.figsize': (18, 6)})
9
10
if not sig.config.is_initialised():
11
sig.config.init()
Copied!

Strategy example

The following simple basket consists of a rolling future and rolling FX forwards, going long GBP and short EUR.
1
def get_fxrf(long_ccy, forward_tenor, direction):
2
return sig.RollingFXForwardStrategy(
3
currency='USD',
4
direction=direction,
5
forward_tenor=forward_tenor,
6
long_currency=long_ccy,
7
start_date=dtm.date(2010, 1, 5),
8
)
Copied!
1
st1 = get_fxrf('GBP', '3M_IMM', 'long')
2
st2 = get_fxrf('EUR', '3M_IMM', 'short')
Copied!
1
rf = sig.RollingFutureStrategy(
2
currency='USD',
3
start_date=dtm.date(2010, 1, 4),
4
contract_code='ES',
5
contract_sector='INDEX',
6
rolling_rule='front',
7
front_offset='-6:-4',
8
)
Copied!
1
st = sig.BasketStrategy(
2
currency='USD',
3
start_date=dtm.date(2011, 1, 10),
4
constituent_names=[
5
st1.name,
6
st2.name,
7
rf.name,
8
],
9
weights=[0.25, 0.25, 0.5],
10
rebalance_frequency='EOM',
11
)
Copied!
The full strategy:
Input
Output
1
st.history().tail().dropna()
Copied!
1
2021-03-29 2038.968037
2
2021-03-30 2037.233737
3
2021-03-31 2043.408612
4
2021-04-01 2054.245609
5
Name: (LastPrice, EOD, USD 84B0A0E8 BS STRATEGY), dtype: float64
Copied!
1
st.history().plot()
Copied!

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:
1
trade_date = dtm.date(2018, 6, 29)
Copied!
1
pos = st.timeline_holdings.positions()
2
dt = st.decision_dt_from_date(trade_date)
3
port = st.expanded_slice(dt)
4
orders_df = pd.DataFrame([TradingOrder(order).info() for order in port.orders])
5
positions_df = pd.DataFrame(
6
[(p.name, p.quantity) for p in port.positions],
7
columns=['name', 'quantity']
8
)
Copied!
1
# net and remove cash entries
2
positions = positions_df.groupby('name').sum().drop(
3
['USD CASH', 'ESU18 INDEX VALUATION OFFSET']
4
)
Copied!
1
# net and remove cash entries
2
positions = positions_df.groupby('name').sum().drop(
3
['USD CASH', 'ESU18 INDEX MARGIN']
4
)
Copied!
1
# target position
2
future_pos = (positions + orders)
3
future_pos
Copied!
1
# orders
2
orders
Copied!

Exposures

The notional exposures of the target and orders based on the strategies sizing date:
1
size_date = st.size_date_from_date(trade_date)
Copied!
1
model_target = {}
2
for name, quantity in future_pos['quantity'].items():
3
model_target[name] = st.get_exposure_weight(
4
sig.obj.get(name), quantity, size_date
5
)
6
7
model_target = pd.Series(model_target)
8
9
model_diff = {}
10
11
for name, quantity in orders['quantity'].items():
12
model_diff[name] = st.get_exposure_weight(
13
sig.obj.get(name), quantity, size_date
14
)
15
16
model_diff = pd.Series(model_diff)
Copied!
Input
Output
1
# target model exposures
2
model_target
Copied!
1
ESU18 INDEX 0.499491
2
EURUSD 1.187372750628 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD -0.254798
3
GBPUSD 1.341317214603 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD 0.255231
4
dtype: float64
Copied!
Input
Output
1
# order exposures
2
model_diff
Copied!
1
ESU18 INDEX -0.000006
2
EURUSD 1.187372750628 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD -0.001819
3
GBPUSD 1.341317214603 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD 0.003473
4
dtype: float64
Copied!

Scaling

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:
1
aum = 100000000
2
strategy_valuation = st.valuation_price_base(size_date)
3
scaling = aum / strategy_valuation
Copied!
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.
1
def future_scaling(instrument, qty, size_date):
2
imnt = sig.obj.get(instrument)
3
if hasattr(imnt, 'fut_val_pt'):
4
return round(qty / imnt.fut_val_pt(d=size_date), 0)
5
else:
6
return qty
7
8
def df_future_scaling(df, size_date):
9
df_copy = df.copy()
10
df_copy['quantity'] = [
11
future_scaling(x, y, size_date)
12
for x, y in df_copy['quantity'].items()
13
]
14
return df_copy
Copied!
The currently held positions are read in from a portfolio management system. Example data used in the following example:
1
pms_positions = pd.Series({
2
'GBPUSD 1.341317214603 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD': 33000000,
3
'EURUSD 1.187372750628 2018-06-12:2018-09-19 DELIVERABLE NAKED FXFORWARD': -21500000,
4
'ESU18 INDEX': 370,
5
})
Copied!
The resulting trade table is constructed:
1
trade_table = pd.concat([
2
df_future_scaling(future_pos, size_date),
3
df_future_scaling(orders, size_date),
4
df_future_scaling(future_pos * scaling, size_date),
5
df_future_scaling(orders * scaling, size_date),
6
pms_positions,
7
df_future_scaling(future_pos * scaling,
8
size_date).subtract(pms_positions, axis=0)
9
], axis=1, sort=True)
10
trade_table.index = [
11
sig.obj.get(name).trade_name for name in trade_table.index
12
]
13
trade_table.columns = [
14
'Target Strategy Pos', 'Strategy Orders', 'Model Target Pos', 'Model Orders', 'PMS Pos', 'Trade Qty'
15
]
Copied!
1
for col in ['Target Strategy Pos', 'Strategy Orders', 'Model Target Pos', 'Model Orders', 'PMS Pos', 'Trade Qty']:
2
trade_table[col] = trade_table[col].map('{:,.0f}'.format)
3
trade_table.index.name = 'Instrument Name'
Copied!
1
trade_table
Copied!
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.
1
st.inspect.evaluate_trades(dt, aum)
Copied!