Framework v8

Framework v8#

v8.28.0#

Added support for sig.VarianceSwap in sig.DynamicMultiOptionsStrategy and sig.DynamicOptionsStrategy classes.#

Code example:

import datetime as dtm
import sigtech.framework as sig

import pandas as pd
import numpy as np

sig.init()

def basket_creation_method(strategy, dt, positions, **additional_parameters):
    signal = additional_parameters['signal']
    option_group = additional_parameters['option_group']
    size_date = dt.date()
    d = pd.Timestamp(dt.date())
    if d in signal.index:
        vs = sig.VarianceSwap(
            currency='USD',
            start_date=size_date,
            maturity_date=dtm.date(2023, 1, 4),
            option_group=option_group.name,
            use_option_replication=True
        )
        return {vs: 100}
    else:
        return {}

index = sig.obj.get("SPX INDEX")
option_group = sig.obj.get('SPX INDEX OTC OPTION GROUP')

signal = np.sign(index.history().pct_change()).dropna().loc["2022-01-01":"2022-03-05"]
signal = signal[signal.shift() !=  signal]

bc_params = {"signal": signal,
             'option_group': option_group,
}

strat = sig.DynamicOptionsStrategy(
    currency='USD',
    start_date=dtm.date(2022,1,1),
    group_name=option_group.name,
    end_date=dtm.date(2022, 3, 5),
    rolling_frequencies=['1BD'],
    basket_creation_method=basket_creation_method,
    basket_creation_kwargs=bc_params
)

hist = strat.history()
hist.plot()

Added swap_rate_shift_details and risk_ladder methods to sig.OISSwap class#

Added swap_rate_shift_details and risk_ladder methods to sig.OISSwap:

  • swap_rate_shift_details allows swap rate shifts for single tenor and parallel

  • risk_ladder allows forward and zero rate shifts for single tenor and parallel

Users can now carry out rate shifts and evaluate the effect on net present value (NPV) and PV01 yield curves.

Code example:

import sigtech.framework as sig
import datetime as dtm
sig.init()

# create ois swap
ois_swap = sig.OISSwap(
    currency="USD",
    tenor="5Y",
    trade_date=dtm.date(2022, 4, 6),
    start_date=dtm.date(2022, 4, 8),
)

# shift 5Y tenor of discounting curve by 10 bps
ois_swap.swap_rate_shift_details(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    tenor='5Y',
    notional=10_000_000.0
)

# shift forward and zero rates for all tenors individually as well as
# simultaneously (parallel) for discounting curve by
# 10 bps and evaluate change in NPV
ois_swap.risk_ladder(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    field='NPV',
    notional=10_000_000.0
)

# shift forward and zero rates for all tenors individually as well as
# simultaneously (parallel) for discounting curve by 10 bps and
# evaluate change in PV01
ois_swap.risk_ladder(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    field='PV01',
    notional=10_000_000.0
)

Added period lengths and replacement options to add_bootstrap_timeseries_modifier method#

Added periods and replace parameters to add_bootstrap_timeseries_modifier method. This allows users to simulate circular block bootstrapping with time series data.

When backtesting strategies, users can now utilize variable period lengths for returns and differences, as well as choose whether to bootstrap with or without replacement.

Code example:

import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter

import datetime as dtm
sig.init()

sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_bootstrap_timeseries_modifier(
    "SPX INDEX",
    change_type="RETURN",
    start_date=dtm.date(2024, 4, 15),
    end_date=dtm.date(2024, 4, 19),
    periods=1,
    replace=True
)

Added new method to sim_adapter class to allow spot price shock simulation#

Added add_overwrite_timeseries_modifier method to sim_adapter to override the following change_type:

  • ‘PRICE’ - value of time series

  • ‘RETURN’ - percentage change of time series

  • ‘DIFF’ - value change of time series

Users can now simulate spot price shocks to see how this affects an option’s net asset value.

Code example:

import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
from sigtech.framework.infra.data_adapter.common import DataPoint
import datetime as dtm
sig.init()

# override value of effective federal funds rate
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_timeseries_modifier(
    'FEDL01 INDEX',
    change_type='PRICE',
    overwrites={
        dtm.date(2000, 7, 3): 6.5,
        dtm.date(2005, 1, 3): 2.0,
        dtm.date(2023, 3, 3): 4.3
    },
)

# override return of EURO STOXX 50
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_timeseries_modifier(
    'SX5E INDEX',
    change_type='RETURN',
    overwrites={
        dtm.date(2006, 6, 12): -0.05, # -5%
        dtm.date(2018, 6, 12): 0.08,  # +8%
    },
)

# override value change of GBPUSD CURNCY on 04/01/2007
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_timeseries_modifier(
    'GBPUSD CURNCY',
    change_type='DIFF',
    fields=['MidPrice'],
    data_points=[DataPoint('LONDON_1600')],
    overwrites={
        dtm.date(2007, 1, 4): 0.2,
    },
)

# override value of S&P 5pp index to 1100 on 04/09/2010
# and propagate change to forward and volatility surface
# i.e. shift volatility curve horizontally
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_timeseries_modifier(
    "SPX INDEX",
    change_type="PRICE",
    overwrite_fwd = True,
    shift_vol = True,
    overwrites={
        dtm.date(2010, 4, 9): 1100.0,
    },
)

# newly created options will use the modified time series
# of S&P 500
option_group = sig.obj.get('SPX INDEX OTC OPTION GROUP')
option = option_group.get_option(
    option_type='Call',
    strike=1100,
    start_date=dtm.date(2010, 4, 6),
    maturity=dtm.date(2011, 4, 6)
)
option.history()

Added option to return swap_details and swap_rate_shift_details dataframes for sig.OISSwap and sig.InterestRateSwap classes#

Added option to return swap_details and swap_rate_shift_details as a DataFrame instead of a dictionary.

  • To get swap_details as a DataFrame, users will need to set the ‘as_df’ parameter to ‘TRUE’

  • swap_rate_shift_details will always return a DataFrame

Code example:

import sigtech.framework as sig
import datetime as dtm
sig.init()

# create interest rate swap
irs = sig.InterestRateSwap(
    currency='USD',
    trade_date=dtm.date(2022, 4, 6),
    start_date=dtm.date(2022, 4, 8),
    tenor='5Y',
)

# get swap details as DataFrame
irs.swap_details(
    d=dtm.date(2023, 4, 12),
    notional=10_000_000.0,
    as_df=True
)

# get swap rate shift details as DataFrame
irs.swap_rate_shift_details(
    d=dtm.date(2023, 4, 12),
    shift_bps=10,
    curves='forecasting',
    tenor='5Y',
    notional=10_000_000.0
)

Added new non-rolling options strategy classes#

Added the following non-rolling options strategies: OptionsStrategy, StraddleOptionStrategy, StrangleOptionStrategy, SpreadOptionsStrategy and ButterflyOptionsStrategy.

Users can utilize these options structures when plotting dynamic options strategies.

Code example:

import sigtech.framework as sig
import datetime as dtm
sig.init()

# create option strategy
s = sig.OptionsStrategy(
    start_date=dtm.date(2018, 1, 4),
    end_date=dtm.date(2018, 2, 4),
    currency='USD',
    group_name='SPX INDEX OTC OPTION GROUP',
    maturity='3M',
    option_type='Call',
    strike='SPOT',
    target_quantity=1,
)
s.history().plot()

# create 50 delta call straddle option strategy
s = sig.StraddleOptionStrategy(
    start_date=dtm.date(2018, 1, 4),
    end_date=dtm.date(2018, 2, 4),
    currency='USD',
    group_name='SPX INDEX OTC OPTION GROUP',
    maturity='3M',
    option_type='Call',
    strike_type='Delta',
    strike=0.5,
    target_quantity=1,
)
s.history().plot()

# create 20 delta strangle option strategy
s = sig.StrangleOptionStrategy(
    start_date=dtm.date(2018, 1, 4),
    end_date=dtm.date(2018, 2, 4),
    currency='USD',
    group_name='SPX INDEX OTC OPTION GROUP',
    maturity='3M',
    strike_type='Delta',
    call_strike=0.2,
    put_strike=-0.2,
    target_quantity=1,
)
s.history().plot()

# create 20/30 delta bull call spread strategy
s = sig.SpreadOptionsStrategy(
    start_date=dtm.date(2018, 1, 4),
    end_date=dtm.date(2018, 2, 4),
    currency='USD',
    group_name='SPX INDEX OTC OPTION GROUP',
    maturity='3M',
    option_type='Call',
    spread_direction='Bull',
    strike_type='Delta',
    strike_1='0.2',
    strike_2='0.3',
    target_quantity=1,
)
s.history().plot()

# create 10/20/30 delta long call butterfly strategy
s = sig.ButterflyOptionsStrategy(
    start_date=dtm.date(2018, 1, 4),
    end_date=dtm.date(2018, 2, 4),
    currency='USD',
    group_name='SPX INDEX OTC OPTION GROUP',
    maturity='3M',
    option_type='Call',
    butterfly_direction='long',
    strike_type='Delta',
    strike_1='0.1',
    strike_2='0.2',
    strike_3='0.3',
    target_quantity=1,
)
s.history().plot()

Added attributes to sig.RFPriceIndex class#

Added front_offset_from_expiry and month_end_offset attributes to sig.RFPriceIndex class. Users can now roll contracts at days prior to expiry.

Code example:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

es_rfp = sig.RFPriceIndex(
    currency='USD',
    start_date=dtm.date(2023, 4, 4),
    end_date=dtm.date(2024, 4, 4),
    contract_code='ES',
    contract_sector='INDEX',
    rolling_rule='front',
    front_offset_from_expiry=True,
    front_offset='-6,-6',
    initial_cash=1,
)

New display_sizing_calculation method to print the data points and sources used to calculate a strategy#

Added data_point and source to display_sizing_calculation method. Users can now use display_sizing_calculation to print the data points and sources used to calculate a trading strategy.

Added parameter display_sizing_data=True to trade_timings_df, which gets the sizing calculation to output a dataframe and check if the trade_size calculation is correct.

Code example:

import pandas as pd
import datetime as dtm
import numpy as np

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

rfs = sig.RollingFutureStrategy(
    start_date = dtm.date(2019,12,20),
    contract_code = 'CL',
    contract_sector = 'COMDTY',
    rolling_rule = 'F_0',
    monthly_roll_days = '1:1',
    total_return = False,
    initial_cash=1000000,
)
rfs_s = rfs.clone_object({'direction': 'short', 'monthly_roll_days': '3:3'})

bs = sig.BasketStrategy(
    start_date = dtm.date(2019,12,29),
    constituent_names = [rfs.name, rfs_s.name],
    # weights = [2.3, 2.3],
    weights = [0.5, 0.5],
    rebalance_frequency = '5BDOM',
    total_return = False,
    instant_sizing=True,
    initial_cash=10000000,
    unit_type='WEIGHT',
)

bs.inspect.display_sizing_calculation(end_dt= dtm.datetime(2020,8,6,20,0))

bs.inspect.trade_timings_df(display_sizing_data=True)

Added cost variable to bottom_trades_df#

Added cost variable to bottom_trades_df. Users can now get the cost per trade in their strategy in order to carry out a cost analysis.

Code example:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

b = sig.RollingFutureStrategy(
    start_date=dt.date(2017, 1, 10),
    contract_code='ES',
    contract_sector='INDEX',
    monthly_roll_days='1,1',
    total_return=False
    )
cost = b.inspect.bottom_trades_df()['t_cost']

Added parameter back_adjustment_type to classes sig.RollingFutureStrategy and sig.RFPriceIndex#

Added back_adjustment_type parameter to sig.RFPriceIndex and sig.RollingFutureStrategy.

With back_adjustment_type, you can now choose between the difference method or the ratio method to calculate the back adjustment.

Code examples:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

# Get frozen orange juice commodity futures group
oj = sig.obj.get('JO COMDTY FUTURES GROUP')
# All params (except back adjustment) will be the same in each example
params = {
    'start_date': dtm.date(2023, 1, 1),
    'end_date': dtm.date(2024, 1, 1),
    'currency': 'USD',
    'contract_code': oj.contract_code,
    'contract_sector': oj.contract_sector,
    'rolling_rule': 'f_0',

}
# Create a time slice that covers a roll period to observe adjustments
_slc = slice('2023-05-25','2023-06-05')

# Example rolling future strategies
print('*'*80+'\n', 'JO RFS.price_series:')
oj_rfs = sig.RollingFutureStrategy(**params,
    back_adjusted=False,
    back_adjustment_type=None,
)
oj_rfs_back_adj_ratio = sig.RollingFutureStrategy(**params,
    back_adjusted=True,
    back_adjustment_type='ratio',
)
print('Default (no back-adjustment)')
print(oj_rfs.price_series()[_slc])
print('Back-adjusted using ratio method')
print(oj_rfs_back_adj_ratio.price_series()[_slc])

# Example rolling future price indices
print('*'*80+'\n', 'JO RFPI:')
oj_pi = sig.RFPriceIndex(**params,
    back_adjusted=False,
    back_adjustment_type=None,
)
oj_pi_back_adj = sig.RFPriceIndex(**params,
    back_adjusted=True,
    back_adjustment_type=None,
)
print('Default (no back-adjustment)')
print(oj_pi.history()[_slc])
print('Back-adjusted using default (diff) method')
print(oj_pi_back_adj.history()[_slc])

v8.27.0#

New class: RollingSpreadOptionsStrategy#

Create options trading strategies based on spread direction (Bull or Bear) and option type (Call or Put).

Example:

import datetime as dtm
import sigtech.framework as sig

sig.init()

group = sig.obj.get('USDJPY OTC OPTION GROUP')

# Create a Bull Call Spread options trading strategy
spread = sig.RollingSpreadOptionsStrategy(
    start_date=dtm.date(2021, 1, 4),
    end_date=dtm.date(2023, 1, 4),
    currency=group.underlying_obj.currency,
    group_name=group.name,
    rolling_frequencies=['3M'],
    maturity='12M',
    option_type='Call',
    spread_direction='Bull',
    strike_type='SPOT',
    strike_1='ATM',
    strike_2='ATM+3%',
    target_type='Vega',
    target_quantity=10.0,
)

New class: RollingButterflyOptionsStrategy#

Create butterfly spread options trading strategies based on butterfly direction ('long' or 'short') and option type (Call or Put).

Example:

import datetime as dtm
import sigtech.framework as sig

sig.init()

group = sig.obj.get('USDJPY OTC OPTION GROUP')

# Create a long butterfly spread with calls
butterfly = sig.RollingButterflyOptionsStrategy(
    start_date=dtm.date(2021, 1, 4),
    end_date=dtm.date(2023, 1, 4),
    currency=group.underlying_obj.currency,
    group_name=group.name,
    rolling_frequencies=['3M'],
    maturity='12M',
    option_type='Call',
    butterfly_direction='long',
    strike_type='SPOT',
    strike_1='ATM',
    strike_2='ATM+3%',
    strike_3='ATM+5%',
    target_type='Vega',
    target_quantity=10.0,
)

New feature: Target the net of a target quantity#

Set net_target_quantity to True to target net of target quantity in options trading strategies.

You can force target quantity by adjusting the ratio of option legs.

Example:

import datetime as dtm
import sigtech.framework as sig

sig.init()

# Create strangle on SPX INDEX with call strike of 4500 and put strike 5500.
# Scale option legs to get net target delta of 1.

group = sig.obj.get('SPX INDEX OTC OPTION GROUP')
strangle = sig.Strangle(
    start_date=dtm.date(2023, 1, 4),
    end_date=dtm.date(2024, 1, 4),
    currency=group.underlying_obj.currency,
    group_name=group.name,
    rolling_frequencies=['1M'],
    maturity='3M',
    strike_type='Price',
    put_strike=4500,
    call_strike=5500,
    target_type='Delta',
    target_quantity=1.0,
    net_target_quantity=True,
    total_return=False
)
strangle.history().plot()

This change applies to strategies created with the following classes:

  • DynamicMultiOptionsStrategy

  • DynamicMultiSwaptionsStrategy

  • DynamicOptionsStrategy

  • DynamicSwaptionsStrategy

  • RollingButterflyOptionsStrategy

  • RollingOptionStrategy

  • RollingSpreadOptionsStrategy

  • RollingStraddleOptionStrategy

  • RollingStrangleOptionStrategy

  • RollingVarianceSwapStrategy

  • Any custom class inheriting from RollingOptionsStrategyBase

Improved transaction cost handling for IR and OIS OTC swaps#

Transaction costs for IR and OIS OTC swaps can now be handled separately from the valuation price of the swap. This is in line with market conventions for modeling transaction costs.

To use this functionality, set INCLUDE_OTC_T_COSTS_IN_CASH to True.

Example:

import datetime as dtm
import sigtech.framework as sig

sig.env()[sig.config.IGNORE_T_COSTS] = False
sig.env()[sig.config.INCLUDE_OTC_T_COSTS_IN_CASH] = True

rolling_swap= sig.RollingSwapStrategy(
        tenor="10Y",
        currency='USD',
        swap_currency='USD',
        rolling_frequency_months=6,
        forward_start_months=6,
        start_date=dtm.date(2023, 12, 5),
        initial_cash=0,
        notional_target = 2000000,
    )
rolling_swap.build()

rolling_swap.plot.portfolio_table(dts='ACTION_PTS')

New method for OISSwap class: swap_details#

Get information about a swap for a specified reference date.

Example:

import sigtech.framework as sig
import datetime as dtm

sig.init()

ois_swap = sig.OISSwap(
    currency="USD",
    tenor="5Y",
    start_date=dtm.date(2020, 11, 9),
    trade_date=dtm.date(2020, 11, 9),
)

ois_swap.swap_details(d=dtm.date(2020, 11, 9), notional=10_000_000.0)

New method for discounting and projection curves: yield_curve#

This change adds the yield_curve method to display forward and zero rates for a given discounting or projection curve.

Example:

import datetime as dtm
import sigtech.framework as sig

from sigtech.framework.instruments.ir_otc import IRSwapMarket

sig.init()

# Get a discounting curve
discounting_curve = sig.obj.get(IRSwapMarket.discounting_curve_name('USD'))

# Get the yield curve for the discounting curve
yield_curve = discounting_curve.yield_curve(d=dtm.date(2024, 3, 13))

Pass a list of holiday calendars when creating a dynamic strategy#

Add non-trading days to a dynamic strategy by passing the extra_holidays parameter on creation.

The extra_holidays parameter can be a string or a list of strings. It must contain the object names of the holiday calendars you want the strategy to use.

Example:

fx_option_group = sig.obj.get('EURUSD OTC OPTION GROUP')

trade_dictionary = {dtm.date(2010, 4, 7): {
        fx_option_group.get_option('Call', 1.3, dtm.date(2010, 4, 6), dtm.date(2011, 4, 6)) : 1,
        fx_option_group.get_option('Put', 1.3, dtm.date(2010, 4, 6), dtm.date(2011, 4, 6)) : -1
    }
}

strat = sig.DynamicStrategy(
    currency=fx_option_group.over,
    start_date=dtm.date(2010, 1, 6),
    end_date=dtm.date(2012, 1, 20),
    trade_dictionary=trade_dictionary,
    #extra_holidays=['CMX(T) CALENDAR','SINGEX_JP(T) CALENDAR'],
    extra_holidays='CMX(T) CALENDAR,SINGEX_JP(T) CALENDAR',
)

strat.history()

v8.26#

Swaps: New attributes for interest rate swaps#

Added the following attributes to InterestRateSwap instruments:

  • fixed_day_count: Fixed leg day count convention.

  • float_day_count: Floating leg day count convention.

  • fixing_lag: Delay in days between the fixing date and effective date of an interest rate.

  • index: Swap fixing index.

Example:

import datetime as dtm
import sigtech.framework as sig

env = sig.init()

irs = sig.InterestRateSwap(
    currency='USD',
    trade_date=dtm.date(2022, 4, 6),
    start_date=dtm.date(2022, 4, 8),
    tenor='5Y'
)

print(irs.fixed_day_count)  # 30/360
print(irs.float_day_count)  # ACT/360
print(irs.fixing_lag)  # 2
print(irs.index)  # US0003M INDEX

Various strategies: New parameter to close all positions at end date#

Added trade_out_end parameter to various strategies. When trade_out_end is set to True, the strategy closes all positions upon end date.

The trade_out_end parameter is supported for strategies based on the following classes:

  • BasketStrategy

  • RollingAssetSwap

  • RollingButterflyBonds

  • RollingButterflySwaps

  • RollingCurveSteepenerBonds

  • RollingCurveSteepenerSwaps

  • RollingFutureStrategy

  • RollingStructureBasket

  • SignalStrategy

Example: Close out all trades at the end of a rolling future strategy

import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig

env = sig.init()

rfs = sig.RollingFutureStrategy(
    currency="USD",
    start_date=dtm.date(2022, 6, 14),
    end_date=dtm.date(2023, 9, 29),
    contract_code="ES",
    contract_sector="INDEX",
    trade_out_end=True,
)
rfs.history()

Swaps: Added methods for swap rate shift#

Examples 1, 2, and 3 in this section use the following setup code:

import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig

env = sig.init()

irs = sig.InterestRateSwap(
    currency='USD',
    trade_date=dtm.date(2022, 4, 6),
    start_date=dtm.date(2022, 4, 8),
    tenor='5Y'
)

Example 1: Shift 5Y tenor of forecasting and discounting curve by 10 bps.

# Shift 5Y tenor of forecasting and discounting curve by 10 bps
irs.swap_rate_shift_details(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    curves='both',
    tenor='5Y',
    notional=10_000_000.0
)

Example 2:

  • Shift forward and zero rates for all tenors individually by 10bps.

  • Perform same shift simultaneously (in parallel) forecasting and discounting curve.

  • Evaluate change in NPV.

irs.risk_ladder(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    curves='both',
    field='NPV',
    notional=10_000_000.0
)

Example 3:

  • Shift forward and zero rates for all tenors individually by 10bps.

  • Perform same shift simultaneously (in parallel) forecasting and discounting curve.

  • Evaluate change in PV01.

irs.risk_ladder(
    d=dtm.date(2022, 4, 8),
    shift_bps=10,
    curves='discounting',
    field='PV01',
    notional=10_000_000.0
)

Options: New strike type 'Premium'#

Options can now be retrieved from option groups using 'Premium' as the strike type. For example:

import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig

env = sig.init()

start_date = dtm.date(2018, 1, 4)
maturity = dtm.date(2018, 6, 26)
option_type = 'Call'

# Get call option on SPX INDEX with a premium of 100
option_group = sig.obj.get('SPX INDEX OTC OPTION GROUP')
option = option_group.get_option(
    start_date=start_date,
    option_type=option_type,
    strike=100.0,
    strike_type='Premium',
    maturity=maturity
)

Analytics: Added functionality to get explicit information on daily trades for execution#

You can now get more explicit information on which trades to execute each day. To use the new functionality, call Strategy.inspect.evaluate_trades with the following new parameters:

  • summary: Show summarized output with only 'CURRENT', 'TARGET', and 'TRADE'. Defaults to False.

  • dt_orders_only: Show only the trades on dt.date; exclude subsequent days. Defaults to False.

  • rounded_units: Round the trade quantities. Default depends on the type of instrument.

Example:

import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig

env = sig.init()

strat = sig.default_strategy_objects.rolling_swaps.usd_2y()
strat.inspect.evaluate_trades(
    dt=dtm.datetime(2010, 6, 16),
    rounded_units=True,
    summary=True,
    dt_orders_only=False,
)

v8.25#

All objects#

This release improves the formatting of the data frame returned by the data_df method. All framework objects, including strategies, instruments, and instrument groups, have this functionality.

This feature is disabled by default. To enable the improved formatting, pass pretty_print=True to data_df:

import datetime as dtm
import sigtech.framework as sig

env = sig.init()

irs = sig.InterestRateSwap(
    currency='USD',
    trade_date=dtm.date(2022, 4, 6),
    start_date=dtm.date(2022, 4, 8),
    tenor='5Y'
)
pretty_df = irs.data_df(pretty_print=True)
pretty_df

Added new property alias to all instruments. Added position information to the strategy portfolio table.

Strategies: Option to simplify plot portfolio tables#

To simplify plot portfolio tables when composing a strategy from other strategies, use flatten_strategy_orders. When set to True, only the bottom level trades for each order are shown.

Methods affected:

  • Strategy.plot.portfolio_table

  • Strategy.plot.portfolio_tree

Example:

import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig
from sigtech.framework.default_strategy_objects import rolling_futures

env = sig.init()

tickers = sig.get_single_stock_strategy(exchange_tickers=['AAPL','TSLA'])
signal_1_df = pd.DataFrame({ticker.name: np.sign(ticker.history().pct_change()) for ticker in tickers}).dropna()

# Building 2 strategies to be traded
strategy_stock = sig.SignalStrategy(
        currency='USD',
        start_date=dtm.date(2022, 1, 4),
        end_date=dtm.date(2022, 12, 30),
        signal_name=sig.signal_library.from_ts(signal_1_df).name,
        # instrument_mapping = long_instrument_mapping,
        # use_signal_for_rebalance_dates = True,
        rebalance_frequency='EOM',
        allocation_function=sig.signal_library.allocation.normalize_weights,
        ticker = 'Long Stock'
    )
es_rfs = rolling_futures.es_index_front()
gc_rfs = rolling_futures.gc_comdty_rici()
signal_2 = pd.DataFrame({
    es_rfs.name: es_rfs.history(),
    gc_rfs.name: gc_rfs.history(),
}).loc['2022']
signal_2 = 1 + 0 * signal_2
strategy_index = sig.SignalStrategy(
    currency='USD',
    start_date=dtm.date(2022, 1, 4),
    end_date=dtm.date(2022, 12, 30),
    rebalance_frequency='EOM',
    signal_name=sig.signal_library.from_ts(signal_2).name,
    ticker = 'Long Index'
)

# Building a basket of those 2 strategies
strat = sig.BasketStrategy(
    start_date=dtm.date(2022, 2, 1),
    end_date = dtm.date(2022, 12, 30),
    constituent_names=[strategy_stock.name, strategy_index.name],
    weights=[0.6, 0.4],
    rebalance_frequency='EOM',
    # total_return=False,
)

# Display portfolio_table
strat.plot.portfolio_table('ACTION_PTS', flatten_strategy_orders=True)

Strategy analytics: Improvements to help validate trade size#

Added new parameter display_sizing_data to trade_timings_df. To use it, call Strategy.inspect.trade_timings_df with display_sizing_data=True.

For example:

import pandas as pd
import datetime as dtm
import numpy as np

import sigtech.framework as sig
env = sig.init()

rfs = sig.RollingFutureStrategy(
    start_date = dtm.date(2019,12,20),
    contract_code = 'CL',
    contract_sector = 'COMDTY',
    rolling_rule = 'F_0',
    monthly_roll_days = '1:1',
    total_return = False,
    initial_cash=1000000,
)
rfs_s = rfs.clone_object({'direction': 'short', 'monthly_roll_days': '3:3'})

bs = sig.BasketStrategy(
    start_date = dtm.date(2019,12,29),
    constituent_names = [rfs.name, rfs_s.name],
    # weights = [2.3, 2.3],
    weights = [0.5, 0.5],
    rebalance_frequency = '5BDOM',
    total_return = False,
    instant_sizing=True,
    initial_cash=10000000,
    unit_type='WEIGHT',
)

bs.inspect.display_sizing_calculation(end_dt= dtm.datetime(2020,8,6,20,0))
bs.inspect.trade_timings_df(display_sizing_data=True)

New bonds strategy classes#

Added new curve steepener bonds and butterfly bonds strategy classes:

import sigtech.framework as sig

help(sig.ButterflyBonds)
help(sig.CurveSteepenerBonds)
help(sig.RollingButterflyBonds)
help(sig.RollingButterflySwaps)
help(sig.RollingCurveSteepenerBonds)
help(sig.RollingCurveSteepenerSwaps)

v8.24#

Futures: New syntax for front_offset, month_end_offset, monthly_roll_days#

For improved consistency, interval boundaries are now included in the interval.

For example, to roll a third of the contract each of the 3 days from 4th to 2nd day before contract expiry:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

rfs = sig.RollingFutureStrategy(
        start_date=dtm.datetime(2010,1,4),
        currency=group.currency,
        contract_code=group.contract_code,
        contract_sector=group.contract_sector,
        month_end_offset='-5,-3',
        rolling_rule = 'prev_month',
    )
rfs.rolling_table

Strategies: Add option to remove string formatting in portfolio_table#

In Strategy.plot.portfolio_table, you can now pass str_format=False to prevent string formatting in the resulting data frame.

v8.23#

Futures: Added custom_rolling_table to RollingFutureStrategy#

Strategies: Added stop_trigger allocation function and stop_trigger parameters#

Fixes#

  • TRBC operators in EquityUniverseFilter now perform partial matching

  • Single-letter futures codes no longer need padding with an extra space

v8.22#

  • CustomView can now access PerformanceReport properties.

    from sigtech.framework.analytics.performance.performance_report \
    import PerformanceReport, View, CustomView
    
    help(CustomView)
    help(PerformanceReport)
    help(View)
    
  • Added new class MarketCapWeightedIndex.

    sig.instruments.indices.MarketCapWeightedIndex?
    
  • Added new class DynamicStrategy.

    sig.DynamicStrategy?
    
  • Bond futures: Added ffill input to bond futures strategy method spot_dv01.

    Bond futures strategy method spot_dv01 now has an additional argument, ffill, with default set to True.

    This parameter behaves similarly to pandas.DataFrame.ffill.

    When ffill is set to True and DV01 is requested for a DatetimeIndex d, then the DV01 series is reindexed using d and any NaN value is filled by propagating the last valid observation to the next valid one.

v8.21.1#

Enhanced print_dependencies method#

The print_dependencies method has been significantly improved to offer users more control and clarity when printing dependency trees. Here’s a breakdown of its features:

  • root_dependency: allows users to specify the starting dependency of the tree.

  • resolve_future_dependencies: ensures that future dependencies are resolved before printing. If set to False, the method will not print anything, ensuring that users only see resolved dependencies in their output.

  • fields: Users can now select additional fields to extract from the dependencies object. While the default fields include product_type, currency, frequency, and data_source, this enhancement allows users to include other relevant fields from the dependency object. To determine which fields are available for an object, users can utilize the data_dict method.

New position_value_series and get_cash_valuation methods#

position_value_series returns the valuation of position holdings (excluding cash) in the strategy’s currency. Users can specify various options for the datetime points (dts) to include in the series enabling granular analysis of your strategy’s performance at critical moments, such as when orders are executed or when top-level holdings change.

get_cash_valuation returns the value of cash positions in a strategy at a specified time.

Enhanced RollingSwapStrategy with swap_rate and swap_rate_series methods#

You can now view the swap rate of a RollingSwapStrategy at any given datetime (using swap_rate) or the historical swap rates across the lifetime of a strategy using swap_rate_series.

import sigtech.framework as sig
import datetime as dtm

sig.init()

s = sig.RollingSwapStrategy(
    tenor="10Y",
    currency="USD",
    swap_currency="USD",
    rolling_frequency_months=6,
    forward_start_months=6,
    start_date=dtm.date(2010, 1, 4)
)

sr = s.swap_rate(dtm.datetime(2014,4,4))
print(sr)

s.swap_rate_series()

Enhanced InterestRateSwap with data_df and fair_rate methods and InterestRateSwapGroup with data_df and fair_rate_df#

Interest Rate Swap

  • Deprecated the static method fair_swap_rate.

  • Introduced new methods: fair_rate and data_df.

    • data_df: returns a dataframe containing all the data available for this interest rate swap. Typically, this includes the LastPrice, Rate and PV01.

    • fair_rate: returns the fair swap rate for an interest rate swap for a particular date. Note that unlike fair_swap_rate, env and currency are not required arguments.

import sigtech.framework as sig
import datetime as dtm

sig.init()

ir_swap = sig.InterestRateSwap(
    currency='EUR',
    trade_date=dtm.date(2017, 4, 14),
    start_date=dtm.date(2017, 1, 5),
    tenor=dtm.date(2022, 7, 5),
    fixed_rate=0.05,
)

ir_swap.data_df()

ir_swap.fair_rate()

Interest Rate Swap Group

  • Deprecated the static method fair_swap_rate.

  • Introduced two new methods: fair_rate_df (static) and data_df (non-static).

    • data_df: returns a dataframe containing all the data available for this interest rate swap group.

    • fair_rate_df: returns a dataframe containing all the fair rate data for the interest rate swap group.

import sigtech.framework as sig
import datetime as dtm

sig.init()

# Using fair_rate_df (static)
df1 = sig.InterestRateSwapGroup.fair_rate_df(
    tenor='5Y',
    start_date=dtm.date(2016, 12, 20),
    end_date=dtm.date(2017, 1, 3),
    fwd_tenor='3Y',
    currency='EUR'
)

# Using data_df
g = sig.obj.get('EUR INTEREST RATE SWAP GROUP')
df2 = g.data_df(
    tenor='5Y',
    start_date=dtm.date(2016, 12, 20),
    end_date=dtm.date(2017, 1, 3),
    fwd_tenor='3Y',
)
# Further data manipulations are possible using data_df

g.data_df('5Y', dtm.date(2016, 12, 20))
g.data_df('5Y', start_date=dtm.date(2016, 12, 20), end_date=dtm.date(2016, 12, 23))

Fixes#

  • Replaced hard-coded OBJECT_CLASS_REGISTER with automated logic to fetch framework classes and corresponding modules; exceptions may apply.

  • The start date of rolling future strategies will be computed using the first contract in the roll table to ensure accuracy.

  • All relevant greeks are now available when using the portfolio_greeks method.

  • Fixed a data concatenation issue in the intraday history retrieval for fx_otc.

  • Updated the timeline to the latest version (6.18.7) for live foreign exchange orders.

  • Enhanced the rolling logic to fetch open interest data only when it’s available.

  • Implemented additional checks on callability features within session_data methods.

  • Expanded the historical data available for the Chinese Yuan (CNY) cash index.

  • Optimized the application of price factors on intraday price data columns.

  • Improved error notifications for incorrect valuation time inputs, making them more user-friendly.

  • Introduced a new calculation method for dv01, specifically for bonds quoted by yield.

  • Added further callability checks within the trading manager get_exchange_open_close_dt method.

  • destroy_env procedure added to final step in FunctionJob and StrategyJob decorators.

v8.20.0#

New custom_hedge_exposure parameter for FXForwardHedgingStrategy and additional maturity options in roll_offset#

The custom_hedge_exposure parameter allows you to customize the hedge exposure for each currency in your FXForwardHedgingStrategy, enabling you to hedge specific portions of the underlying strategy’s exposure based on your unique requirements. By passing a dictionary of currency exposures as {"CCY": exposure}, you can now specify the desired hedge percentages for individual currencies. For example, you can hedge 50% of the GBP exposure and 20% of the JPY exposure by passing {"GBP":0.5, "JPY":0.2}. This new feature empowers users to tailor their hedging approach to better align with their risk management strategies and investment goals.

Additionally, this update introduces further maturity options for the roll_offset parameter in the FXForwardHedgingStrategy. The roll_offset parameter allows you to specify the tenor of the FX forwards used for hedging.

New size_from_first_roll_trade parameter for RollingFutureStrategy#

With the size_from_first_roll_trade parameter, you now have the option to adjust how roll trades are sized in the strategy. By default, this feature is activated, meaning that all roll trades will be sized based on the first trade of the roll. This ensures a consistent sizing approach across roll trades.

However, with the size_from_first_roll_trade parameter, you have the flexibility to customize trade sizes individually for each roll trade. When set to True, each roll trade will be sized based on the first trade of the roll. On the other hand, if set to False, you can size each trade separately, allowing for more fine-grained control over the trade sizes.

SchedulePeriodic now has business day of the month frequency#

By entering an integer appended by BDOM you can specify a specific business day of the month as for your schedule.

For example 16BDOM represents the 16th business day of the month.

Fixes#

  • Implemented a workaround to ensure accurate CVaR (Conditional Value at Risk) calculation for small datasets and a new trigger has been introduced to generate comprehensive summary reports for single transactions.

  • Added support for AUDUSD cross-currency swap fx_datapoint.

  • The framework now performs a thorough check of initial rolls and automatically adjusts the first contract forward, if necessary.

  • Added commodity futures groups to F_0_table

  • Enhanced the data parsing mechanism to ensure correct string ID extraction when the data source is available.

  • Added informative error messages for early trading scenarios within SignalStrategy.

  • The computation of spot DV01 series now utilizes valuation points.

  • Fixed an issue that caused potential field availability discrepancies during the reindexing process in get_series. The system now ensures that all relevant fields are available and correctly aligned.

  • The default value of closing_only in the bottom_trades_pnl_df function has been updated.

v8.19.0#

More statistics have been added to the performance report#

New trade related statistics have been added to the performance report. These can be found within the trade_statistics table method. The new statistics added are as follows:

  • Trades (number),

  • Win (number),

  • Loss (number),

  • Win/loss ratio,

  • Win probability

  • Kelly Criterion

See the code example below for an example of how to run this new table.

Also available is a new inspect wrapper view called bottom_trade_pnl_df.

Code Example:

start_date = dtm.date(2020, 1, 10)
end_date = dtm.date(2021, 1, 10)
etf_ids = [
    '1001692.SINGLE_STOCK.TRADABLE',
]
etfs = sig.get_single_stock_strategy(etf_ids, {'start_date': start_date, 'end_date': end_date})
rs = {e.underlyer_object.exchange_ticker: e for e in etfs}
spy = rs['SPY']
signal_ts = np.sign(spy.history()-spy.history().rolling(20).mean()).fillna(1)

strat = sig.SignalStrategy(
    currency='USD',
    signal_name=sig.signal.library.from_ts(signal_ts.to_frame(spy.name)).name,
    start_date=start_date,
    end_date=end_date,
)
sig.PerformanceReport(strat, views='ALL').report()

To run the new trade_statistics method: strat.analytics.trades_statistics() New inspect wrapper view: strat.inspect.bottom_trades_pnl_df(closing_only=False)

Upgrade QuantLib to 1.30#

The QuantLib dependency has been updated from v1.28 to v1.30. For more information on this release, see the QuantLib release notes.

Add risk reversal method to vol surfaces#

Before this release, the risk_reversal method was available only for FX vol surfaces. (this method returns the history of Call Vol minus Put Vol for a given vol surface).

With this release, the risk_reversal method has been extended and is now available for equity and commodity vol surfaces.

In addition, two optional parameters, start_date and end_date have been added, allowing you to specify a date range for the returned historical date. This is useful if you want to get a small date range as it makes the calculations much quicker.

Code Example

# Commodity vol surface
vs1 = sig.obj.get('GC COMDTY VOLSURFACE')
vs1.risk_reversal(tenor='1M',
delta=25,
start_date=dtm.date(2020, 1, 1),
end_date=dtm.date(2020, 2, 10))
# Equity vol surface
vs2 = sig.obj.get('SPX INDEX VOLSURFACE')
vs2.risk_reversal('1M', 25) # No range specified

Fixes#

  • Any override of the rolling parameters is now correctly applied in the RollingFutureStrategy constructor.

  • The dependencies for the FX objects used in a basket strategy or signal strategy are now correctly updated according to their expected evaluation start date and end date.

  • Strategies no longer fail when basktesting times are approaching midnight UTC.

  • When using CapADVOrderTransform the volume parameter is now case-insensitive.

  • Before this release, the optimized_allocations and instrument_mapping parameters within the SignalStrategy were not compatible. With this release, instrument_mapping can be a parameter of the optimization function.

  • With this release, the data_df method no longer restructures the internal history data.

v8.18.0#

This release combines versions 8.18.0 and 8.17.0.

Breaking change to swap tickers#

With this release, a # character has been added to swap tickers to distinguish if only valuing pre-start. If you have hard-coded the name of a swap, this could break your analysis notebook. For example, the following function obj.get('USD LIBIMM S3M 0.0254578 2010-06-15 U10X5Y IRS') needs to be changed to obj.get('USD LIBIMM S3M 0.0254578 2010-06-15 U10X5Y # IRS') to continue working.

Two new child-classes (StopLossStrategy and TakeProfitStrategy) have been added to the StopStrategy building block#

With this release, two child classes have been added to the StopStrategy building block, allowing you to create stop loss orders and take profit events. Below are code examples for StopLossStrategy and TakeProfitStrategy.

import datetime as dtm
import sigtech.framework as sig
env = sig.init()
future = env.object.get('ESZ19 INDEX')

stop_loss = sig.StopLossStrategy(
    currency='USD',
    trade_date=dtm.date(2019,9,1),
    instrument_name=future.name,
    trigger_type='FIXED_PCT_PROFIT',
    trigger_level=0.01,
)

take_profit = sig.TakeProfitStrategy(
    currency='USD',
    trade_date=dtm.date(2019,9,1),
    instrument_name=future.name,
    trigger_type='FIXED_PCT_PROFIT',
    trigger_level=0.01,
)

New threshold function added to achieve dynamic rebalancing in the SignalStrategy#

In previous releases, the threshold function returned a boolean value that was passed into the SignalStrategy, serving as an “on/off switch” that controlled if the strategy rebalanced or not.

In this release, the threshold output can either be a boolean value or a dictionary of strategy weighting, giving you greater control of the threshold you wish to apply.

A built-in threshold function called signal_threshold_rebalance_dict has been introduced. This requires an additional keyword argument in the form of a dictionary which contains float values that represent:

  • A threshold for a change in the weighting.

  • How much of the strategy to rebalance (as a percentage).

For example, to achieve the following dynamic rebalancing of:

  • 10% deviated from the target position, rebalance 100%,

  • 30% deviated from the target position, rebalance 70%,

  • 50% deviated from the target position, rebalance 50%.

Pass the following dictionary:

rebalance_dict = {0.1: 1.0, 0.3: 0.7, 0.5: 0.5, 1.0: 0.0}

To use this new threshold function, import it from the signal_rebalancing library.

Below is a code example of this new threshold function used within a signal strategy.

from sigtech.framework.signal.signal_rebalancing import signal_threshold_rebalance_dict

rebalance_dict = {0.1: 1.0, 0.3: 0.7, 0.5: 0.5, 1.0: 0.0}

strategy = sig.SignalStrategy(
    currency='USD',
    start_date=start_date,
    signal_name=signal_name,
    rebalance_frequency='EOM',
    allocation_function=sig.signal_library.allocation.equally_weighted,
    threshold_function=signal_threshold_rebalance_dict,
    threshold_kwargs={'rebalance_dict': rebalance_dict},
)

Added get_yield_curve and data_df methods to the BondYieldCurve objects#

With this release, two new methods have been added that return yield curve data from a BondYieldCurve object.

  • get_yield_curve(date, tenor) creates the yield curve for a reference date up to a specified tenor. By default, this tenor is 30Y.

  • data_df() returns a DataFrame containing all history dates for bonds that have a otr_tenor (2Y, 3Y, 5Y, 7Y, 10Y, 30Y). As this function returns a lot of data, it may affect your runtimes.

Below is a code example of how to call these new methods:

US_bonds = sig.obj.get("US GOVT BOND GROUP")
curve = US_bonds.get_bond_yield_curve()
date = dtm.date(2023, 3, 31)
tenor = '10Y'

yield_curve = curve.get_yield_curve(date=date, tenor=tenor)

yield_df = curve.data_df()

New parameter min_periods added to rolling statistics methods#

With this release a new parameter min_periods has been added to the following performance metrics summary methods:

  • summary_rolling_series

  • summary_rolling_ccy_series

min_periods is the minimum number of observations in the period window that require a value.

If this parameter is not set, the default value of 252 is used instead - this is the same value as the previous period parameter, where 252 is the number of business days in a year.

description property now available for CommodityIndex objects#

In previous releases, the description property was missing from the CommodityIndex sub-asset class, and was only available for EquityIndex objects.

With this release, the property has been moved to the parent class Index so all sub-classes can inherit this property. Therefore, the description property can be called for all types of Index objects.

Below is a code example of how to call this property.

import sigtech.framework as sig
sig.init()

equity_index = sig.obj.get('SPX INDEX')
equity_index.description

cmdty_index = sig.obj.get('SPGSINTR INDEX')
cmdty_index.description

More statistics have been added to the Performance Report#

The following statistics have been added to the report function found in the PerformanceReport class:

  • Calmar Ratio

  • VaR - 99% and 95% (both 1day)

  • cVaR - 99% and 95% (both 1day)

To view these new parameters, run the following code:

import sigtech.framework as sig
sig.init()
from sigtech.framework.default_strategy_objects.rolling_futures import bo_comdty_f_0
data = bo_comdty_f_0().history()
sig.PerformanceReport(data).report()

Fixes#

  • The object_service docstring has been updated.

  • Before this release, there were errors when creating an equity index option after a vol surface was assessed the with data_df() method. With this release, the DataLoadError issues have been resolved.

  • The deprecated exchange_open property has been removed from the info() method and replaced with exchange_open_on_day.

  • Certain methods now cannot be accessed while a strategy is being built.

  • The price series index has been converted to a datetime index in the RollingFutureStrategy building block.

  • When plotting a volatility surface, adjustments have to be made to improve the ticks on the tenor axis.

  • Decimal values have replaced commas in prices. For example, 1000,00 is now displayed as 1000.00.

  • Missing credibility fields have been added to available_fields method when using DataCredibilityAdapter.

v8.17.0#

This release was merged with 8.18. Please refer to the release notes for version v8.18.0 to see what was included in version 8.17.0.

v8.16.0#

Enhanced sig.object.get can now query all cross pairs#

With this release, you can use sig.obj.get() to query FX spot rates for any currency pair, even those which are not available in our data browser. Previously, sig.obj.get() you could only query FX spot rates for currency pairs in our data browser.

A couple of examples are shown below:

import sigtech.framework as sig
sig.init()

usdeur = sig.obj.get('USDEUR CURNCY')
usdeur

seknok = sig.obj.get('SEKNOK CURNCY')
seknok

Store and load environment configs from a file#

You can save your Sigtech environment in your JupyterLab instance. This saves any variables or attributes that you have configured in your environment. JSON serialisable attributes are saved in a .JSON format and non-JSON serialisable attributes are saved in .PKL. Once an environment is saved, you can easily reload it in a new notebook.

See the code example below for an example:

import sigtech.framework as sig

# Saves environment config as 'env.json' and 'env.pkl'
env = sig.init()
env.save_config('env')

# Destroys the environment instance
sig.de_init()

# Loads environment config from 'env.json' and 'env.pkl'
loaded_env = sig.init(load_env=True, env_file='env')

Added minimalist attributes view to BuildingBlockBrowser widget#

A new Minimalist View option is available on the BuildingBlockBrowser widget. Selecting this option reduces the list of the class attributes shown in the BuildingBlockBrowser by only showing you the mandatory attributes. Not selecting/deselecting this option will result in all the attributes available for a class is visible.

New data_df method added and history_df method deprecated#

A new method data_df() has been added to all framework instruments. The data_df() method replaces the history_df() method as it returns improved data. This new method returns a pandas DataFrame containing all data available for this object.

The data_df() method takes the following optional arguments:

  • data_point: Choose the data point from which to return the history of the object.

  • multi_index: Set to True to index rows uniquely by a multi-index (if applicable). Default is False.

  • drop_nan_cols: Set to True to drop all NaN columns. Default is False.

data_df() is an improvement over the previous history_df method as it can perform clean-up operations as the data is queried. Such clean-up operations include column rearrangement and renaming, reset of indices and forward filling of values when placeholders are set.

See the code example below for how to use data_df:

import sigtech.framework as sig

sig.init()

# Single stock
sig.obj.get('1000045.SINGLE_STOCK.TRADABLE').data_df(drop_nan_cols=True)

# Credit index curve
sig.obj.get('CDX.NA CURVE').data_df(multi_index=True)

# Vol surface
sig.obj.get('EURUSD VOLSURFACE').data_df()

Lists of holidays and instruments can be passed into SchedulePeriod method#

With this release, you can now pass a single or a mixed list of holiday calendar names and instruments objects into the holidays parameter of the SchedulePeriod method. This generates a calendar that accommodates all the holidays in the passed list. If a list of instruments has been passed, then the calendar will accommodate the holidays for each of the instruments in the list. This is particularly useful if the list consists of different indices.

See the code example below for how to create a weekly schedule:

instrument_list = ['ESH23 INDEX', 'COH22 COMDTY', '1000045.SINGLE_STOCK.TRADABLE']
basket = [sig.obj.get(ins) for ins in instrument_list]

weekly_schedule = sig.SchedulePeriodic(
    start_date=dtm.date(2020, 2, 1),
    end_date=dtm.date(2020, 3, 28),
    holidays=basket,
    frequency='1W-WED',
    offset='1BD',
    offset_backwards=True,
    bdc=sig.calendar.BDC_MODIFIED_FOLLOWING)

print(weekly_schedule.get_holidays())
print(weekly_schedule.get_holidays().all_data_dates())

New back_adjusted feature and equivalent get_rf_price_index method added to RollingFutureStrategy#

A back_adjusted parameter has been added to the price_series method (belonging to the RollingFutureStrategy class). This parameter calculates the back-adjusted prices for underlying futures.

Furthermore, a new method get_rf_price_index has been added to RollingFutureStrategy, it returns the corresponding rolling future price index object. Likewise, an additional method get_rolling_future_strategy has been added to the RFPriceIndex class, it returns the corresponding rolling future strategy.

See the code example below for how to pass the back_adjusted parameter:

rfs = sig.RollingFutureStrategy(
            currency='USD',
            start_date=dtm.date(2020, 1, 1),
            end_date=dtm.date(2022, 1, 1),
            contract_code='NG',
            contract_sector='COMDTY',
            rolling_rule='front',
            front_offset='-2:-1'
        )
rfs.price_series(back_adjusted=True)

The following example queries the rolling future price index from a back-adjusted rolling future strategy.

rfs_pi = rfs.get_rf_price_index(back_adjusted=True)

The following example gets a rolling futures strategy from the back-adjusted price index.

rfpi_strat = rfpi.get_rolling_future_strategy()

New parameters added to SignalStrategy that allow for order execution delays#

You can now pass an execution_delay argument to a signal strategy.

This allows you to delay an order execution by a set period. In addition, you can use the bump_execution_delay parameter to ensure the order execution falls within trading hours. Set bump_execution_delay to False to ignore orders that would be executed out of trading hours. This means the order will not be executed if the delay causes it to execute outside of trading hours. Set bump_execution_delay to True (default) to ensure the order will be executed within trading hours by moving the execution time forward to the next available data point (that falls within trading hours).

For example:


import pytz
import datetime as dtm
import pandas as pd
import numpy as np
import sigtech.framework as sig
env = sig.init()

rfs = sig.default_strategy_objects.rolling_futures.es_index_front()
rfs.history();

start_date = dtm.date(2023,3,1)
signal = pd.Series({d: np.random.uniform(0,1) for d in pd.date_range(start_date, env.asofdate)}).to_frame(rfs.name)

rfs = sig.default_strategy_objects.rolling_futures.es_index_front()
rfs.history();

# Use bump_execution_delay=False to skip trades that would execute outside trading hours based on the delay provided via execution_delay
strategy = sig.SignalStrategy(
    currency='USD',
    signal_name=sig.signal.library.from_ts(signal).name,
    start_date=start_date,
    execution_delay = dtm.timedelta(days=1),
    bump_execution_delay = False,
)

strategy.plot.portfolio_table('TOP_ORDER_PTS', end_dt=dtm.date(2023,3,6))

# Use bump_execution_delay=True to bump trades that would execute outside trading hours to the EOD execution on the next day based on the delay provided via execution_delay
strategy = sig.SignalStrategy(
    currency='USD',
    signal_name=sig.signal.library.from_ts(signal).name,
    start_date=start_date,
    execution_delay = dtm.timedelta(days=1),
    bump_execution_delay = True,
)

strategy.plot.portfolio_table('TOP_ORDER_PTS', end_dt=dtm.date(2023,3,6))

Fixes#

  • The copy code issues in BuildingBlockBrowser have been resolved.

  • Overridden attributes in the BuildingBlockBrowser have been updated.

  • The data_date and env_date in the intraday notebook have been updated so that they no longer return errors.

  • Bugs involving abe_encryption_key and stream_access endpoints have been resolved.

  • Timeline retrieval is now prevented before a strategy is run.

  • OTC instruments can now trade before the instrument’s start date.

  • Use holidays to check the exchange open/close times and skip trades that occur outside of trading hours.

  • FX forwards now include the current date in the history time series.

  • The timestamp behaviour of the FX convert_at_d method has been corrected.

  • An attribute filter has been added to the DataBrowser widget.

  • The intraday argument can now be used in stoploss allocation functions.

  • The trading_decision_time argument has been removed following its deprecation.

  • Interactive optimizers now clear correctly.

v8.16.1#

Fixes#

  • Grouped strategy orders now execute at EOD.

  • Conversion errors on FX objects causing FXFix datapoint retrieval issues have been fixed.

  • The behavior of the back_adjusted parameter in the price_series function of the RollingFutureStrategy building block has been fixed.

v8.15.0#

New curve CollateralizedOISCurve added#

A new discount curve called CollateralizedOISCurve has been added to the framework. This new curve implements discounting on-the-fly using a collateral OIS discount curve and FX forwards. The curve applies the discounts based on collateral posted in a different currency (USD by default). The future cash flows are converted to the collateral currency using FX forwards and discounted using the collateral OIS curve.

The following code creates a curve that discounts JPY cash flows assuming that USD collateral is used for the instrument.

CollateralizedOISCurve(currency='JPY',
    curve_name='JPY.C',
    group_name="OIS ICE CURVE GROUP",
    interpolation_type='CS',
    collateral_currency='USD')

Date range parameters added to pnl_explain()#

Two new start_date and end_date parameters have been added to the portfolio_greeks and pnl_explain functions (these functions belong to the rolling options/swaption strategies and also the DeltaHedgingStrategy).

Pass the start and end dates as a datetime. For example, start_date=datetime.date(2020,1,1).

This new feature has been introduced to increase the computation speeds. If a small date range is entered then the greeks and pnl are calculated for just this small date range, making the calculations faster.

New input data_points added to portfolio_greeks function#

A new optional parameter data_points has been added to the portfolio_greeks function. When using this parameter in the rolling options strategies and the DeltaHedgingStrategy, the reported greek times will be overridden with the times specified by the data points list passed to the data_points parameter.

An example of this is shown below:

# creates the strategy
ro=sig.RollingOption(
    currency='USD',
    start_date=dtm.date(2019,1,4),
    group_name='EURUSD OTC OPTION GROUP',
    maturity='3M',
    rolling_frequencies=['1M'],
    option_type='Call',
    strike_type='SPOT',
    strike='ATM+3%',
    target_type='SpotNotionalAsProportionOfNAV',
    target_quantity=-10,
    end_date=dtm.date(2019,3,4)
)
# calls the function with the new data points
ro.portfolio_greeks(start_date=dtm.datetime(2019,1,8,17),
    end_date=dtm.date(2019,1,10),
    data_points=['LONDON_1600','LONDON_2000'])

Transaction costs updates#

The interface for the defined transaction costs has been improved. These improvements include:

  • When entering parameters into a model, you must now enter them as a dictionary of parameter values. Previously, this was supported for only some transaction cost models but with this release, it is now available for all models.

  • The docstrings for each model have been updated and now also provide an example of how these transaction costs work.

  • Previously, some instruments (such as bonds and single stocks) used cost models defined on the objects instead of being defined via configured models. This made it harder to get additional information on the cost models. With this release, these cost models are now included.

Limits removed when plotting portfolio_table#

Previously, when calling plot.portfolio_table with more than 100 rows the table would error.

With this release, if there are more than 100 rows the table is still plotted but a warning message is provided telling you that only the last 100 rows of the portfolio_table have been plotted.

If you want to view a DataFrame version of the portfolio_table, pass the argument as_df=True. In previous releases, the DataFrame would also error if there were more than 100 nows. With this release, the DataFrame returns every row available, even if there are more than 100 rows.

New parameter basket_creation_kwargs added to DynamicOptionsStrategy#

You can now pass additional keyword arguments for the basket creation strategy when creating a DynamicOptionsStrategy. Pass the optional keyword arguments as a dictionary. An example of how to pass these arguments is shown in the code below:

# pass the additional keyword arguments in a dictionary.
bc_params = {'signal':signal,
             'option_group':spx_option_name,
             'strike':'SPOT',
             'maturity':'2M'}

strategy = sig.DynamicOptionsStrategy(
    currency='USD',
    start_date=dtm.date(2022,1,1),
    group_name=spx_option_name.name,
    end_date=dtm.date(2022, 12, 5),
    rolling_frequencies=['1BD',],
    basket_creation_method=basket_creation_method,
    basket_creation_kwargs=bc_params
    )

Added ability aggregate trades in bottom_trades_df#

A new parameter net_trades has been added to the inspect.bottom_trades_df method. If set to True, you can now see the aggregated orders for trades happening at the same time for the same instrument.

An example of this is shown below:

from sigtech.framework.default_strategy_objects import rolling_futures

rfs = rolling_futures.es_index_front()
rfs1 = rfs.clone_object({'fixed_contracts': 1, 'ticker': 'C1'})
rfs2 = rfs.clone_object({'fixed_contracts': 2, 'ticker': 'C2'})
rfs1.build()
rfs2.build()

signal = pd.DataFrame({
    'C1 STRATEGY': -1 + 0 * rfs1.history(),
    'C2 STRATEGY': 1 + 0 * rfs2.history(),
}).loc['2018':].dropna()

ns = sig.SignalStrategy(
    currency='USD',
    start_date=signal.first_valid_index(),
    end_date=signal.last_valid_index(),
    signal_name=sig.signal_library.from_ts(signal).name,
    rebalance_frequency='EOM',
)
ns.build()

ns.inspect.bottom_trades_df(net_trades=True).loc[:'2018-01-10']
ns.inspect.bottom_trades_df(net_trades=False).loc[:'2018-01-10'].sort_values(by='instrument_name')

New parameter profit_metrics_only added to performance reports#

Previously, the metrics used in the performance report and strategy widget were calculated using percentage returns or returns relative to a provided AUM.

With this release, these metrics are now calculated using the absolute P&L (with the P&L calculated in the strategy currency). By default, these metrics are chosen if the strategy valuation is negative at any point.

To access the metrics directly, use the profit_metrics_only parameter. An example of how to get the parameter is as follows:

import sigtech.framework as sig
sig.init()
strat = sig.default_strategy_objects.rolling_futures.es_index_front()
sig.PerformanceReport(strat, profit_metrics_only=True).report()
strat.plot.performance(profit_metrics_only=True)

This new performance parameter can be included in the following custom report views:

    View.SUMMARY_SINGLE_CCY,
    View.HISTORY_CCY,
    View.ROLLING_PLOTS_CCY,
    View.DRAWDOWN_PLOT_CCY,
    View.MONTHLY_STATS_HEATMAP_CCY

Please note, these views are independent of the entered reference AUM.

FX spot trades can now be generated using cross identifiers#

Previously, FX spot trades had to be entered by setting a trade of the cash instrument. If you were using a custom strategy, these FX spot trades have to be entered using an add_fx_spot_trade method.

With this release, FX spot trades can be entered with an FX cross identifier, which are mapped to the cash exchange. This can then control which currencies are exchanged. Additional labels have also been added to FX orders to show the FX cross gaining exposure.

An example of this new input is shown for a basket strategy below:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()
env[sig.config.FX_SPOT_EXECUTION_DELAY] = dtm.timedelta(hours=1)

strategy = sig.BasketStrategy(
    currency='EUR',
    start_date=dtm.date(2015, 1, 10),
    constituent_names=[
        'USDEUR CURNCY',
        'GBPEUR CURNCY',
    ],
    weights=[0.5, 0.5],
    rebalance_frequency='EOM',
)
strategy.plot.portfolio_table('ACTION_PTS')

Python typings upgrades#

Prior to this release and when the framework was created, Python did not have native type hinting syntax. This meant that SigTech had to use custom type hints (defined in sigtech.framework.infra.objects.dtypes).

With this release, a more up-to-date version of python has been utilized and we have now ported all typings to Python’s native type hinting.

In addition to using these native types, we have also enforced the use of beartype. This is a strict, runtime type checker. If you pass an unexpected value into a class using the beartype, an error will appear telling you the correct variable type to use instead.

The logic in our codebase tries to match an input and its type. An edge case for this logic involves the Union type. This Union type is usually used to indicate a single variable can hold multiple types of values, for example, the date variable can hold a date as a str or as a dt.datetime, hence the date can be represented as date: Union[str, dt.datetime].

However, the order of these inputs is important in the framework, as it would try to cast the variable to the type in the order given in the Union.

For example, with Union[str, dt.datetime], the framework would try to cast the variable to a string first, then to the datetime. This behaviour can be incorrect if, for example, you used a dt.datetime only as the framework would cast the variable to a string first. This may interfere with your code and cause errors.

Fixes#

  • If a strategy attempts to size a trade prior to the strategy start date, the framework will then change to sizing date to the valid start date of the strategy.

  • If you exceed the time point limit when plotting a portfolio_table, the number of time points displayed is reduced to fit within this limit. The time points that are reduced are from the start of the table.

  • The transaction_cost notebook has been updated.

  • A new option group, trading_group, has been added to the rolling option strategies. The trading_group lets you specify the type of traded options to use in the strategy.

  • Fill added to futures methods to fill ctd data in reindex so that it can match asof calls for individual dates.

  • Corrections were added to several default dictionary inputs for strategies and signals.

  • Several new calendars (HolidayCalendar, AuctionCalendar, EconomicCalendar) have been added to the API.

v8.14.0#

Ensure strategy names are unique#

In previous releases, if different strategies were assigned the same name, the notebook could error when rerunning certain cells.

With this release, a version number is automatically added to the name of the strategy if the name provided is not unique. For example, if we have two rolling future strategies with the same ticker, "RFS 2023 Q1", then the first strategy keeps this name, but the second strategy is renamed to "RFS 2023 Q1 V2".

Local objects are also returned when using get_names method#

With this release, when calling the get_names method for strategies and instruments, you can return an ordered list of object names associated with the class.

This method now accepts the following parameters:

  • include_db - set this to True to include objects from the database (default is True).

  • include_local - set this to True to include objects available in the local environment or cache (default is True).

  • include_children - set this to True to include objects from the child classes (default is False).

  • ignore_unmapped - set this to True to ignore errors caused by unmapped database objects (default is True).

Add unit_type input to positions_df methods#

Previously, when using the inspect.bottom_trades_df method, the trade_price column in the returned DataFrame was incorrect and displayed values from PricingResult objects instead.

With this release, the error has been fixed and the trade_price column now displays the correct data.

Added new curve class MultiDiscountCurve#

A new discounting curve MultiDiscountCurve has been added. This new curve is a mix of previously defined curves that are used at different times. The standard required arguments are currency, group_name, curve_name, and a new parameter curves_dict. This new parameter requires a dictionary of curves names, where the keys are dates from which the curves should be used.

For example:

from sigtech.framework.internal.infra.curves.dynamic_curve import MultiDiscountCurve

MultiDiscountCurve(currency='USD',group_name='DISC CURVES',curve_name='USD.MC',
                  curves_dict={dtm.date(2006,1,1):'USD.F3M CURVE',
                  dtm.date(2021,1,1):'USD.D'})

The code above creates a curve that uses:

  • USD.F3M CURVE for discounting from 2006-01-01 to 2020-12-31.

  • USD.D CURVE for discounting from 2021-01-01 onwards.

This curve behaves as the other curves within the SigTech framework.

New OIS swaption added#

With this release, OIS swaptions have been added. They are similar to regular LIBOR swaptions, the only difference being the underlying swap is an OIS swap instead of LIBOR. The functionality is the same as for regular swaptions; just use the prefix OIS in the class names. For example:

OISSwaptionGroup.get_group('USD')
OISSwaption(start_date=dtm.date(2022,2,3),
                       expiry='3M',
                       swap_tenor='5Y',
                       option_type='Payer,
                       strike='ATM,
                       currency='USD')

Unlike LIBOR swaptions, the OIS swaptions do not support old-style cash-settlement (such as the EUR standard pre November 2018), and the only cash settlement is the par market value of the underlying swap (this is the new EUR standard).

The vol surface expected for the OIS swaptions uses the relevant OIS SABR parameters USD OIS SWAPTION SABR VOLSURFACE (or any other currency).

Add dv01_exposure support for rolling future strategies on bond futures#

With this release, it is now possible to set dv01_exposure for rolling future strategies using bond futures.

Example:

import datetime as dtm
import sigtech.framework as sig

s1 = sig.RollingFutureStrategy(
    currency='USD',
    contract_code='US',
    start_date=dtm.date(2020, 1, 3),
    contract_sector='COMDTY',
    rolling_rule='front',
    front_offset='-5:-4',
    dv01_exposure=0.003,
    initial_cash=100,
    include_trading_costs=False,)
s1.build()

Fixes#

  • Fallback added to close trade if open is missing in stocks.

  • Un-built strategies in get_many_with_history are now allowed.

  • Default rolling bond strategies have been updated.

  • CZK, HUF and PLN cash strategies have been added with fallback.

  • Serialization of IntradayHistoryContainer has been fixed.

  • American and Barrier options have been disabled for Vol index group.

  • na values that are introduced through the batch termstructure retrieval are now dropped.

  • Bond errors with early start dates or NaN in OTR have been resolved.

  • Column names used for session data have been updated.

  • The use of custom NumPy methods in cvxpy solver is now prevented.

  • The correct future and rolling strategy dv01 has been implemented.

  • class_name in turnover grouping to allow for cash can now be used.

  • Details have been added to the info method for futures and futures contract groups.

  • Intraday history DataFrame now works with missing fields.

  • Trade price from PricingResult in bottom_trades_df now displays correct values.

  • QuantLib has been updated to version 1.28.

v8.14.1#

Fixes#

  • The volatility option instruments and group have been renamed.

  • Correction of del item in IntradayHistoryContainer.

  • The Swaption vol surface prior_index has been fixed.

  • Vol index options are now redirected into a new class VolIndexOTCOption.

  • A fix has been added to the fx forward when the input is pd.Timestamp.

v8.13.0#

Additions to portfolio optimizer and optimized_allocations function#

The following additions have been added to the portfolio optimizer and optimized_allocations function.

  • A check has been added to the time-varying signal allocation input

  • Inbuilt correlation data source has been provided

  • Initial parameter specification

  • Allow time-varying problems

This change allows you to add your own objectives and constraints to a problem. Below is an example of specifying a custom objective for an optimiser:

import pandas as pd
import datetime as dtm
import sigtech.framework as sig
sig.init()

amazon = sig.default_strategy_objects.single_stock_strategies.amazon_equity_rs()
apple = sig.default_strategy_objects.single_stock_strategies.apple_equity_rs()

returns = pd.concat([amazon.history(), apple.history()], axis=1, keys=[amazon.name, apple.name]).dropna().pct_change().dropna()
returns.head();

import cvxpy
base_opt = sig.PortfolioOptimizer()
base_opt.prefer_maximum_return()
base_opt.prefer_custom(lambda x, data: -cvxpy.quad_form(x, data['covariance']))
base_opt.calculate_weights(returns)

New input as_df added to portfolio_table() that displays the table as a DataFrame#

With this release, you can pass the input as_df=True to the portfolio_table() method to return the portfolio table as a DataFrame.

Fixes#

  • The SGD fix delay has been corrected and the DB CashIndex test usage has been removed

v8.12.0#

Return fundamental data on EquityIndex objects#

In previous releases, fundamental data could only be retrieved for single stocks. With this release, fundamental data can be retrieved for equity indices also.

You can call the following for EquityIndex objects

  • fundamentals() - this returns a DataFrame of fundamental data for the equity index.

  • fundamental_fields - this returns the a list of fundamental fields for which you can collect data. You can enter these fields into the fundamental_series() input.

  • fundamental_series(field) - this return a fundamental series available for the entered field.

For example:
sig.obj.get('SPX INDEX').fundamentals()
sig.obj.get('SPX INDEX').fundamental_fields
sig.obj.get('SPX INDEX').fundamental_series('dividend_yield')

Use real-time intraday data if available#

Previously, only data up until midnight from the day before is returned when calling data from the framework. With this release, you can get real-time data (or at least data from 30 minutes ago. To access this latest, intraday data, append .intraday_history() to the object on which you want to collect data. For example:

import sigtech.framework as sig
sig.init(env_date='now')
sig.obj.get('ESZ22 INDEX').intraday_history()

The code above gets the history data between midnight last night and the latest data available.

User-defined benchmarks in the Performance Report now rebase correctly#

Previously, when a user-defined benchmark was used in the Performance report that was using the AUM parameter, the benchmark series was not correctly rebased relative to the AUM level.

With this release, a new parameter adjust_benchmark_by_aum has been added to the PerformanceReport constructor to fix this issue. Set this parameter to True, and the benchmark history series is considered relative to the constant AUM level (assuming a benchmark history series is provided).

Logic added to backtests to handle unfilled or partial filled orders#

Trade pricer methods can now optionally return a PricingResult(price, executed_quantity) object instead of a price (but only where executed_quantity is less than or equal to the quantity given to the trade pricer method).

In this situation, the method simulates a scenario where it was not possible to execute the full quantity due to low liquidity in the market.

When the strategy calls any of the methods to add to the trade, it is possible to use a callback method. This callback method allows the strategy to decide how to proceed and whether to trade now with less than the expected quantity or to wait to trade at a point in the future.

Look-through position-based risk analytics have been added to strategies#

In previous releases, risk-based portfolios were based on just historical strategy level performance. With this release, the portfolio strategy uses look-through position-based risk analytics. These new analytics include:

  • parametric_var() - calculates the value at risk (VaR) for a timeseries using the parametric (Gaussian) covariance-variance approach.

  • historical_var() - computes the VaR for a timeseries using the historical timeseries.

  • portfolio_var() - computes the portfolio’s VaR, where the portfolio is represented as a list of tuples containing portfolio units and timeseries.

  • portfolio_var_historical() - computes the portfolio’s VaR using the historical timeseries and correlations from portfolio components.

  • portfolio_var_parametric() - computes the portfolio’s VaR using the parametric (gaussian) covariance-variance approach.

  • var_portfolio_sizing() - is a sizing method based on the historical portfolio VaR of the strategy. It requires a target VaR and VaR estimation time.

Walk-forward grid optimization helper class has been added to strategies#

A new helper class has been added that enables repeated grid optimization of a strategy as well as the subsequent use of optimized parameters. This walk-forward A new helper class has been added that enables repeated grid optimization of a strategy as well as the subsequent use of optimized parameters. This walk-forward optimization can help to reduce overfitting since each optimization uses the same lookback method. Additionally, this method avoids in-sample fitting since each optimization at time t only uses data available up to t.

These walk-forward grid optimization parameters include:

  • strategy_generator - the method called to return the strategy.

  • parameter_space - this is a dictionary (keyed by parameter names) and contains a list of possible values that will be iterated over at each optimization step.

  • fitting_metric - the metric method that evaluates each parameter combination.

  • fitting_lookback - the lookback of training data used at each optimization step. This can be input as a tenor string (e.g. '1M', '2W-MON') or pandas offset.

  • fitting_frequency - the time elapsed between each optimization step. This can be input as a tenor string (e.g. '1M', '2W-MON'), or as a list of dates.

Fixes#

  • Ensure intraday delta hedged portfolio_greeks() is intraday.

  • The SOFR start date has been removed from the calculation of earliest start date in strategies that use CashIndex.

  • Inconsistencies with the End of Day (EOD) price lookup have been resolved.

  • META ticker is now used for facebook’s default strategy.

  • TRBC codes have been updated.

  • RollingFutureStrategy.spot_dv01() has been changed so it is now based on positions instead of weights.

  • The use of PricingResult has been removed when using direct trade_price calls.

  • Portfolio table exposure weight now uses the current time.

  • The FXforward history now starts at the earliest available datapoint.

  • allow get_tc_model now runs for strategies.

  • Division by zero is prevent when computing RSI.

  • Ensure negative strikes work in SABR.

v8.11.0#

Intraday history data cleared when the environment is low on memory#

When using the IntradayHistoryContainer and the research environment is low on memory, the intraday history data (which has not been used recently) is cleared. This happens automatically and you do not need to input or action anything.

Use Regex to find the names of the transaction cost models#

With this release when searching for transaction cost you can use Regular Expressions (Regex) to find the names of the transaction cost models.

Currency input no longer mandatory for applicable default strategies#

Previously, you had to input the currency of the underlying instruments used by a strategy. With this release, strategies can now infer the currency from the futures group, equity instrument, bond group, etc that is being used in the strategy.

Intraday portfolio greeks are now calculated using intraday FX data#

A new input intraday has been added to the FX portfolio_greeks function. If intraday=True, the greeks are calculated using the most recent intraday data. This new input is supported for FX options only, so when intraday=True, the relevant FX forwards are calculated using the latest available FX spot and the latest available forward curves (although these forward curves are less granular).

For example, here is the new input for a rolling options strategy ro that is already defined.

ro.portfolio_greeks(dates=
  [dtm.datetime(2019,1,8,17),
  dtm.datetime(2019,1,8,18)],
  intraday=True)

This will calculate the different greeks at 5pm and once again at 6pm on 2019-01-08.

By default, intraday=False.

Fixes#

  • The index error in live streaming has been fixed.

  • Errors with copy overrides in the ticker loop for get_single_stock_strategy have been fixed.

  • Checks put in place to make sure intraday delta is always computed using intraday data in delta hedging strategy.

  • The short conversion error has been changed to a warning with additional information.

  • Unsupported pandas logic has been removed.

v8.10.0#

New function trade_timings_df() added to inspect wrapper#

A new function trade_timings_df() has been added to the inspect wrapper. Append this function to an object and a DataFrame is returned that contains the timings associated with each trade in the strategy. For example, run the following code to get the trade timing DataFrame.

qqq = sig.ReinvestmentStrategy(underlyer='QQQ UP EQUITY', currency='USD')
qqq.inspect.trade_timings_df(

The DataFrame contains the following columns:

  • instrument_name - the instrument traded.

  • decision_dt - the datetime for when the decision to trade was made.

  • execution_dt - the datetime for when the trade was executed.

  • default_instrument_size_dt - the time the trade was likely to have been sized (unless this was overridden at the time).

  • default_strategy_size_dt - the time the strategy value was likely to have been sized for the purposes of a weight calculation (unless this was overridden at the time).

  • trade_size - the size of the trade.

New sizing methods added to strategies#

Previously, the default sizing method targeted model units. Some strategies (i.e. BasketStrategy) could override the default sizing method.

With this release, the default sizing methods can be over ridden in all general strategies. Use sizing_quantity and default_sizing_method to configure the sizing method with values such as AUM, INITIAl_AUM or any fixed values.

New mixin strategy incorporated into existing strategies#

A new strategy RatesStrategyMixin has been added. This strategy inherits aspects of the RatesStrategy, RatesStrategyBasket and RatesSignalStrategy strategies. This incorporation now provides the strategies with a pv01_exposure method, which gives a breakdown of exposures, and also changes the default sizing methods so that traded quantities should be entered in terms of pv01.

New allocation function called stop_loss added to SignalStrategy building block#

With this release, SigTech has introduced a new allocation function called stop_loss to the SignalStrategy building block. This new allocation function places a stop order each time a new position is entered. This is equivalent to creating a stop strategy every time the signal changes. See the example below for how to configure the input and the required keyword arguments (allocation_kwargs).

mean_rev_signal = sig.signal_library.from_ts(mean_rev_signal_ts.to_frame(es_index_front().name))

es_mean_rev_stop_loss = sig.SignalStrategy(
    start_date=dtm.date(2010, 4, 1),
    currency='USD',
    rebalance_frequency='1W-WED',
    signal_name=mean_rev_signal.name,
    allocation_function=sig.signal.library.allocation.stop_loss,
    allocation_kwargs={'trigger_level': 0.05, 'trigger_type': 'TRAILING_PCT_LOSS'},
)

Strategies can now treat listed options as OTC#

When passing an exchange-traded option group as an input to any of the rolling options strategies, the options could be priced using exchange prices, stored in a database.

Alternatively, these options can also be priced from the relevant volatility surface (as over-the-counter (OTC) options created from the option’s static data). To use options priced from the relevant volatility surface, pass price_listed_as_model='VolSurface' as an input.

If you need to use the database prices as well as calculate the “Greeks” for the options, pass price_listed_as_model='VolFromPrice' as an input. (The Greeks are a collective term for delta, gamma, vega, and theta of the option positions which provide a way to measure the sensitivity of an option’s price to observable factors).

Strategies can now be used as sizing method inputs#

With this release, an extra input has been added to the sizing_method call. This input looks at information from the strategy being used and allows this information to be incorporated in the sizing method which converts the traded units. An example of using this available input is weight based sizing, where the valuation of the strategy is required to complete the conversions.

Earliest available start date is now used when creating a strategy#

It is now optional to specify a certain start date when creating a strategy (the start date used to be a mandatory input). If you do not enter a start date, SigTech scans all the market data required for the strategy to run and finds the earliest, valid start date.

You can find this start date by appending .earliest_start_date() to the end of your strategy. For example, the following prints the earliest useable start date for the 5-year US treasury notes:

us5yearNoteFuture = sig.default_strategy_objects.rolling_futures.fv_comdty_front()
us5yearNoteFuture.earliest_start_date()

Allow position sizing at execution for rolling options and swaptions#

A new input, size_at_execution, has been added to all rolling option and swaption strategies.

Set size_at_execution=True to force the strategy to calculate the position sizing at the execution time instead of the standard position sizing time which is calculated using parameters from the previous day.

By default, size_at_execution=False as the execution time may occur after market close and therefore the strategy will error.

You can use the same size_at_execution input in the DeltaHedgingStrategy.

Add custom FX forward transaction costs using the environment configuration#

To add custom FX forward transaction costs to your SigTech environment, enter a dictionary value containing the outright and roll values. These dictionary values should be entered as forward base points per maturity, on a monthly basis.

An example of how to input these FX forward trading costs is shown below:

env[sig.config.T_COST_OVERRIDES]
  = {'EURUSD FXFORWARD':
    {'outright':{1: 20},
    'roll': {1: 10}
    }
  }

Fixes#

  • The has_preloaded_history function in BondBase for calculated fields has been adjusted.

  • The fx_spot_inverse function has been fixed.

  • Fix added for shorter underlying strategy inside of delta hedged strategy.

  • Allow delta at execution in delta hedged strategy.

  • Remove exception in strategy performance viewer.

  • Allow choice of option exercise type in rolling option strategies.

  • Fix dynamic option basket dependency.

  • Default values of AlphaReport metrics based on input features have been updated.

  • Datetime error in vol surface corrected.

  • Fix for xccy swap_info in resettable swaps for periods prior to first reset.

  • History start date added to swaption name, if different from the start date.

  • Removed the wrong swap start date in rolling asset swap.

  • Allow different start date and history start date for variance swap.

  • Fix added for performance plot for aum equal to zero case.

  • QuantLib has been upgraded to the latest version (1.27).

  • history_start added to get_swaption in line with options functionality.

  • Propagate exceptions which occur while loading dependencies in a thread pool.

v8.9.0#

Analytics#

Set and add timezones to display methods#

This release introduces a new environment variable TM_DISPLAY_TIMEZONE and a new property display_tz.

Use the TM_DISPLAY_TIMEZONE variable to change the timezone for times display in analytics interfaces. This feature can be used if the trading manager timezone (TM_TIMEZONE) differs from the timezone in which you want to display time data. The following code is an example of how to add these two separate timezones when initializing your SigTech environment:

env = sig.init()
sig.config.set('TM_TIMEZONE', 'America/New_York') #This sets the time zone for the trading manager timezone, in this case 'America/New_York'
sig.config.set('TM_DISPLAY_TIMEZONE', 'Europe/London') #This sets the time zone in which the times are displayed, in this case 'Europe/London'

The display_tz property ensures a timezone is always displayed and uses the timezone provided to TM_DISPLAY_TIMEZONE. However, if TM_DISPLAY_TIMEZONE was not set, the TM_TIMEZONE is used.

Currently, the TM_DISPLAY_TIMEZONE variable only works on the analytics interfaces such as strategy.plot. By default, the portfolio_table and .diagnostics.to_dataframe() display times using the UTC timezone, however, if a TM_TIMEZONE is provided, the trading manager timezone is used to display time in these interfaces.

(Experimental) Custom metrics for AlphaReport#

You can now create customised metrics for the experimental AlphaReport. The new metric will be available in the report’s Metrics view.

Example usage:

def my_metric(x: pd.Series, y: pd.Series, **kwargs):
  return x.min() * y.max()

ar = sig.AlphaReport(x_df=df_features, y_df=df_targets)
ar.add_metric(my_metric, 'My Metric')
ar.interactive_report()

Strategies: Currency parameters no longer case-sensitive in public methods#

The currency parameter is no longer case-sensitive in a variety of public class constructors and methods, including:

  • When creating strategies

  • When using Strategy.analytics.pnl_breakdown and Strategy.analytics.total_return_valuation_history

  • When using strategy trading methods (e.g. Strategy.add_position_target, Strategy.add_trade)

  • When creating strategy instruments such as FX forwards, swaps, and rolling swaptions

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

strat = sig.RollingFXForwardStrategy(
    long_currency='eur',
    currency='usd',
    forward_tenor='3M_IMM',
    start_date=dtm.date(2022, 1, 1),
    custom_roll_offset=5,
    end_date=dtm.date(2022, 2, 1),
)
print(strat.analytics.pnl_breakdown(ccy='eur'))

instr = sig.FXOTCOption(
    over='usd',
    under='eur',
    strike=1.0635,
    start_date=dtm.date(2017, 1, 6),
    maturity_date=dtm.date(2017, 4, 6),
    option_type='Call'
)
print(instr)

Options and Swaptions: Determine rolling options/swaptions strikes at execution#

When you create a new strategy based on rolling options or rolling swaptions, you can now use the t0_option_selection flag to specify that option strikes should be determined using the same market data point as order execution:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

rc = sig.RollingOption(
    currency='USD',
    start_date=dtm.date(2022, 1, 1),
    end_date=dtm.date(2022, 6, 1),
    group_name='CO COMDTY OTC OPTION GROUP',
    option_type='Call',
    maturity='3M',
    rolling_frequencies=['1M'],
    strike_type='SPOT',
    strike='ATM+10%',
    target_quantity=1,
    t0_option_selection=True,
)
rc.plot.performance()

{% hint style=”warning” %} Warning: t0_option_selection can cause inconsistencies in some circumstances.

  • Use t0_option_selection for backtesting research only; avoid using it in production strategies.

  • Avoid using t0_option_selection if you customize the data_date when initializing the framework environment. {% endhint %}

To see all classes with the t0_option_selection option:

import sigtech.framework as sig

def get_klz_names(klz=None, tail=None):
    if len(klz.__subclasses__()):
        if tail == None:
            tail = []
        tail += klz.__subclasses__()
    name = klz.__name__
    if len(tail):
        klz = tail[0]
        return list(set([name, *get_klz_names(klz, tail[1:])]))
    else:
        return [name]
get_klz_names(sig.RollingOptionsStrategyBase)

Bonds: New options to load reduced bond history#

When you call a method or create a strategy that uses a bond instrument’s history, by default, SigTech loads the whole history. If the history data is not already cached, SigTech computes and caches it.

Framework v9.1 introduces new functionality to load reduced bond histories, which can help speed up some strategies.

Reduced bond history functionality for bond instruments#

Set limits for computing and caching bond history data

Use set_history_limits to limit the start and/or end dates when SigTech computes and caches history data for a particular bond instrument:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

bond = sig.obj.get('US 0.125 2022/06/30 GOVT')

bond.set_history_limits(
  # You can include one or both dates here
  start_date=dtm.date(2022, 6, 1),
  end_date=dtm.date(2022, 6, 5),
)

Bond history limits are ignored when history is already cached beyond them

The start and/or end date parameters of set_history_limits are ignored if the cached history already exceeds them:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

bond = sig.obj.get('US 0.125 2022/06/30 GOVT')
# Cache entire history
bond.history()

# Both parameters ignored
bond.set_history_limits(
  start_date=dtm.date(2022, 6, 1),
  end_date=dtm.date(2022, 6, 5),
)

Reset bond history limits when history is already cached

To force SigTech to recompute and re-cache the history, call set_history_limits with parameter reset_all=True. This applies the history limits you specify, even if history was already cached:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

bond = sig.obj.get('US 0.125 2022/06/30 GOVT')

# Compute and cache full history
bond.history()

bond.set_history_limits(
  # You can include one or both dates here. If you omit one, it is reset
  # to the default (i.e. the earliest/latest for which history is available).
  start_date=dtm.date(2022, 6, 1),
  end_date=dtm.date(2022, 6, 5),
  reset_all=True,
)

View existing bond history limits

To view any existing history limits on a bond instrument, call its history_limits method. The history_limits method returns an object with attributes start_date and end_date:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

bond = sig.obj.get('US 0.125 2022/06/30 GOVT')
bond.set_history_limits(
  start_date=dtm.date(2022, 6, 1),
  end_date=dtm.date(2022, 6, 5),
)
bond.history_limits()
# {'start_date': datetime.date(2022, 6, 1),
#  'end_date': datetime.date(2022, 6, 5)}

Clear bond history limits

To clear the limits and load the full history, call set_history_limits and pass reset_all=True with no other parameters:

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

bond = sig.obj.get('US 0.125 2022/06/30 GOVT')
bond.set_history_limits(
  start_date=dtm.date(2022, 6, 1),
  end_date=dtm.date(2022, 6, 5)
)

# Clear limits and load full history
bond.set_history_limits(reset_all=True)
bond.history_limits()
# {'start_date': None, 'end_date': None}

Reduced bond history functionality for bond strategies#

To set bond history limits to the date range used by a a SingleBondStrategy, pass optional parameter reduce_bond_history=True when you create the strategy:

bond = sig.obj.get('US 1.75 2022/06/15 GOVT')
sig.SingleBondStrategy(
    currency='USD',
    start_date=dtm.date(2022, 6, 1),
    end_date=dtm.date(2022, 6, 5),
    bond_name=bond.name,
    reinvest_coupon=True,
    entry_transaction_type='outright',
    tax_withholding=10,
    reduce_bond_history=True,
)
bond.history_limits()
# {'start_date': datetime.date(2022, 6, 1),
#  'end_date': datetime.date(2022, 6, 5)}

To set bond history limits to the date range used by a a RollingBondHistory, pass optional parameter reduce_bond_histories=True when you create the strategy:

bond = sig.obj.get('US 1.75 2022/06/15 GOVT')
sig.SingleBondStrategy(
    currency='USD',
    start_date=dtm.date(2022, 6, 1),
    end_date=dtm.date(2022, 6, 5),
    bond_name=bond.name,
    reinvest_coupon=True,
    entry_transaction_type='outright',
    tax_withholding=10,
    reduce_bond_histories=True,
)
bond.history_limits()
# {'start_date': datetime.date(2022, 6, 1),
#  'end_date': datetime.date(2022, 6, 5)}
  • Both reduce_bond_history and reduce_bond_histories are optional and False by default.

  • If a cached history already exists beyond the start or end date, the date is ignored and the limit is not enforced.

To reset, view, or clear the history limits on an instrument in a SingleBondStrategy or RollingBondStrategy, see the sections above on this page.

Deprecations#

Rename objective-based optimization methods#

In the Portfolio Optimizer (sig.analytics.optimization.portfolio_optimizer.PortfolioOptimzer), the following methods have been renamed for clarity:

Old method name

New method name

require_equal_risk_contribution

prefer_equal_risk_contribution

require_inverse_vol_weighting

prefer_inverse_vol_weighting

require_maximum_diversification

prefer_maximum_diversification

require_maximum_return

prefer_maximum_return

require_mean_variance

prefer_mean_variance

require_minimum_turnover

prefer_minimum_turnover

require_minimum_variance

prefer_minimum_variance

require_target_return

prefer_target_return

require_weights_l1_penalty

prefer_weights_l1_penalty

require_weights_l2_penalty

prefer_weights_l2_penalty

The old method names are deprecated; you should convert your code to use the new method names listed above. The behavior of the renamed functions has not changed.

Example using new method names:

import datetime as dtm
import pandas as pd
import sigtech.framework as sig
from sigtech.framework.analytics.optimization.portfolio_optimizer import PortfolioOptimizer

env = sig.init()

START_DATE = dtm.date(2021, 1, 1)
END_DATE = dtm.date(2022, 1, 1)

tix = [
    ('AAPL', '1000045'),
    ('MSFT', '1001489'),
    ('GOOGL', '1083049'),
]

rtns = pd.DataFrame({
    tick: sig.ReinvestmentStrategy(
        currency='USD',
        start_date=START_DATE,
        end_date=END_DATE,
        underlyer=f'{id}.SINGLE_STOCK.TRADABLE',
    ).history().pct_change().dropna()
    for (tick, id) in tix
})

po1 = PortfolioOptimizer()
po1.prefer_equal_risk_contribution()
po1.calculate_weights(rtns)
#AAPL     0.314943
#MSFT     0.352582
#GOOGL    0.330322
#dtype: float64

po2 = PortfolioOptimizer()
po2.prefer_mean_variance()
po2.calculate_weights(rtns)
#AAPL    -0.688930
#MSFT     3.318468
#GOOGL    3.199416
#dtype: float64

po3 = PortfolioOptimizer()
po3.prefer_inverse_vol_weighting()
po3.calculate_weights(rtns)
#AAPL     0.307067
#MSFT     0.366956
#GOOGL    0.325977
#dtype: float64

Fixes#

Fixes for strategies and instruments#

  • Futures

    • For default LME rolling futures strategies, select correct contract when start date precedes first roll day.

    • For rolling futures strategies:

      • Fix monthly roll dates in BCOM roll schedule.

      • Add copper (‘HG COMDTY’) to BCOM rolling table.

  • Swaps

    • Add dependencies for asset swaps and rolling asset swaps.

    • Interest rate swaps: Ignore cash flows occurring before history start date.

  • Bonds

    • Fix issue with bond history start date in cases where mid price is missing, but bid and ask prices are present

  • FX

    • Fix issue with FX spot trade execution times in various strategy classes.

    • Ensure consistency between calculate_forward_rate and calculate_forward_rate_batch methods.

  • Options

    • In rolling options strategies, avoid creating options with maturity date in the past.

    • In rolling options strategies, enable PV or Delta sizing:

      • For option holidays.

      • When determining option strike with same market datapoint as order execution.

Fixes for utilities and analytics#

  • Portfolio optimizer: Update weight distribution parameter to prevent memory error when creating histogram.

  • Equity universe filter: Fix EquityUniverseFilter.list output by avoiding overriding filters when executing them.

  • Data adapter: Fix issue requesting LastPrice field from projection curve.

Fixes for experimental features#

  • Fix font warnings related to AlphaReport.

  • Enable saving images via capture_png cell magic.

v8.8.0#

Analytics (experimental): Improved AlphaReport replaces SignalReport#

Framework v8.8 deprecates SignalReport (sig.experimental.analytics.signal_design.SignalReport) and replaces it with improved and expanded AlphaReport (sig.experimental.analytics.alpha_report.alpha_report.AlphaReport).

Strategy inspection: More flexibility for cash methods#

The base Strategy class provides a range of cash methods via the inspect interface:

  • Strategy.inspect.bottom_cash_df

  • Strategy.inspect.cash_df

  • Strategy.inspect.weights_df

  • Strategy.inspect.positions_df

  • Strategy.inspect.bottom_positions_df

These methods previously only gave values at action points (points where the strategy simulation performs an action). To make these methods more flexible, framework v8.8 adds an optional parameter, dts.

The dts parameter can be:

  • One of the following strings, specifying a set of times:

    • 'ACTION_PTS': Every point where the strategy simulation performs an action on any level.

    • 'EXECUTION_PTS': Points where orders are executed.

    • 'HOLDING_CHG_PTS': Points where the strategy’s top level holdings change (excluding orders).

    • 'TOP_ORDER_PTS': Points where the strategy enters and executes top level orders.

    • 'TOP_POSITION_CHG_PTS': Points where the strategy’s top level holdings change.

    • 'VALUATION_PTS': Valuation points.

  • A Datetime

  • An iterable of Datetimes

Default values are as follows:

  • bottom_cash_df: 'ACTION_PTS'

  • cash_df: 'HOLDING_CHG_PTS'

  • weights_df: 'TOP_POSITION_CHG_PTS'

  • positions_df: 'HOLDING_CHG_PTS'

  • bottom_positions_df: 'ACTION_PTS'

Deprecations#

Framework v8.8.0 deprecates the following classes:

  • sig.experimental.analytics.signal_design.SignalReport

    Use sig.experimental.analytics.alpha_report.alpha_report.AlphaReport instead.

Fixes#

Framework v8.8.0 adds the following bug fixes:

  • Interest rate swaps: v8.8 now uses existing swap ticker in class constructor, if provided

v8.7.0#

Volatility#

VarianceSwap functionality expanded#

Framework v8.7 adds improved pricing and risk for variance swaps from volatility surfaces.

Deprecations:

  • The VarianceSwapReplicator class is deprecated. Instead, use VarianceSwap with use_option_replication=True.

  • When creating a VarianceSwap, setting use_vol_surface=True is no longer necessary; framework v8.7 and later ignore the use_vol_surface parameter.

Create a VarianceSwap using a volatility surface

Old syntax:

variance_swap = sig.VarianceSwap(
    currency='USD',
    maturity_date=dtm.date(2011, 4, 6),
    start_date=dtm.date(2010, 4, 6),
    option_group='SPX INDEX OTC OPTION GROUP',
    use_vol_surface=True,
)
variance_swap

New syntax:

variance_swap = sig.VarianceSwap(
    currency='USD',
    maturity_date=dtm.date(2011, 4, 6),
    start_date=dtm.date(2010, 4, 6),
    option_group='SPX INDEX OTC OPTION GROUP',
)
variance_swap

Create a VarianceSwap using option replication

Old syntax:

variance_swap_replicator = sig.VarianceSwapReplicator(
    currency='USD',
    maturity_date=dtm.date(2011, 4, 6),
    start_date=dtm.date(2010, 4, 6),
    option_group='SPX INDEX OTC OPTION GROUP',
    upper_strike_fraction=3.0,
    lower_strike_fraction=0.0,
    one_sided_option_num=100,
)
variance_swap_replicator

New syntax:

variance_swap_use_or = sig.VarianceSwap(
    currency='USD',
    maturity_date=dtm.date(2011, 4, 6),
    start_date=dtm.date(2010, 4, 6),
    option_group='SPX INDEX OTC OPTION GROUP',
    upper_strike_fraction=3.0,
    lower_strike_fraction=0.0,
    one_sided_option_num=100,
    use_option_replication=True,
)
variance_swap_use_or

Rolling swaptions delta neutral strike#

When creating a rolling swaption strategy (SwaptionStraddle) or getting a Swaption object, you can now pass strike='DN' to compute a delta-neutral strike.

import datetime as dtm
import sigtech.framework as sig

env = sig.init()

strat = sig.SwaptionStraddle(
    start_date=dtm.date(2020, 1, 23),
    expiry='3M',
    strike='DN',
    currency='USD',
    swap_tenor='3Y',
)
print(strat)

swapt = sig.SwaptionGroup.get_group('USD').get_swaption(
    start_date=dtm.date(2020, 1, 23),
    strike='DN',
    expiry='3M',
    swap_tenor='3Y',
    option_type='Payer',
)
print(swapt)

When strike is set to 'DN', the framework computes the strike automatically such that the payer and receiver swaptions at this strike have the same delta. This strike is usually slightly lower than the par forward rate.

Rolling options and swaptions pnl_explain method#

v8.7 adds the pnl_explain method to all rolling options and rolling swaptions strategies. This method provides a breakdown of actual PnL (profit and loss) and greeks PnL over time.

To use the new functionality, call the pnl_explain method of any strategy based on rolling options or rolling swaptions:

nky_option_group = sig.obj.get('NKY INDEX OTC OPTION GROUP')

strangle = sig.Strangle(
    currency = 'USD',
    strike_type = 'SPOT',
    put_strike = -0.05,
    call_strike = 0.25,
    group_name = nky_option_group.name,
    maturity = '3M',
    start_date = dtm.date(2018, 1, 4),
    end_date = dtm.date(2020, 1, 4),
    rolling_frequencies = ['1M']
)
strangle.pnl_explain()

Analytics: Covariance estimators moved#

This change deprecates the COV_ESTIMATORS class and replaces it with CovEstimators in the same module (sig.analytics.optimization.factor_exposure).

New syntax:

import pandas as pd
import datetime as dtm
from sigtech.framework.analytics.optimization.factor_exposure import CovEstimators

import sigtech.framework as sig

env = sig.init()

START_DATE = dtm.date(2021, 1, 1)
END_DATE = dtm.date(2022, 1, 1)

tix = [
    ('AAPL', '1000045'),
    ('MSFT', '1001489'),
    ('GOOGL', '1083049'),
]

rtns = pd.DataFrame({
    tick: sig.ReinvestmentStrategy(
        currency='USD',
        start_date=START_DATE,
        end_date=END_DATE,
        underlyer=f'{id}.SINGLE_STOCK.TRADABLE',
    ).history().pct_change().dropna()
    for (tick, id) in tix
})

pd.DataFrame({
    cov_type: sig.PortfolioOptimizer(
        fo_kwargs={'factor_exposure_kwargs':{'covariance_estimation_method': cov_type}}
    ).prefer_minimum_variance().require_fully_invested().calculate_weights(rtns)
    for cov_type in CovEstimators
})

For more information on CovEstimators, run the following code cell:

from sigtech.framework.analytics.optimization.factor_exposure import CovEstimators
CovEstimators?

Utilities: Modify holiday calendars#

A new function, HolidayCalendar.modify_calendar, lets you add dates to and remove dates from the holidays list.

Parameters of modify_calendar are as follows:

  • new_name: Optional string for new calendar object name.

    • If None, the calendar object is replaced.

    • If provided, a new calendar object is created with object name '{new_name} CALENDAR'.

  • add_holidays: Optional list of holiday dates to add.

  • remove_holidays: Optional list of holiday dates to remove.

Example:

import datetime as dtm
from calendar import monthrange
import sigtech.framework as sig

env = sig.init(repeat_mode='reinit', log_level='ERROR')

cal = sig.obj.get('US/NEW_YORK CALENDAR')
cal.modify_calendar(new_name='MOD US/NEW_YORK', add_holidays=[dtm.date(2022, 10, 31)])
modcal = sig.obj.get('MOD US/NEW_YORK CALENDAR')

def print_month(cal, year, month):
    _, last = monthrange(year, month)
    start = dtm.date(year, month, 1)
    end = dtm.date(year, month, last)
    print()
    print(cal.name)
    print([
        hol.strftime('%d %B %Y')
        for hol in cal.holidays
        if (hol >= start and hol <=end)
    ])

print_month(cal, 2022, 10)
print_month(modcal, 2022, 10)

Deprecations#

Framework v8.7.0 deprecates the following classes:

  • sig.VarianceSwapReplicator

    Use sig.VarianceSwap with use_option_replication=True instead.

  • sig.analytics.optimization.factor_exposure.COV_ESTIMATORS

    Replaced by sig.analytics.optimization.factor_exposure.CovEstimators.

Framework v8.7.0 deprecates the following parameters:

  • sig.VarianceSwap.use_vol_surface

    When creating a VarianceSwap with a volatility surface, you no longer need to set use_vol_surface=True.

    Framework v8.7 and later ignore the use_vol_surface parameter.

Fixes#

Framework v8.7.0 adds the following bug fixes:

  • (Experimental - SigTech cell magics) Applies default JupyterNotebook styles to output cells when saving them as HTML.

  • Extends TRBC codes to include Real Estate, Government Activity and Academic and Educational Services.

  • Makes sigtech.framework.infra.data_adapter.identifier.Symbology available as sig.Symbology when importing sigtech.framework as sig.

  • Avoids incorrect country code lookup when an instrument’s country attribute exists, but is set to None.

  • Allows cloning with the clone_strategy method of any strategy object without additional parameters.

  • Updates intraday history functionality to prevent re-requesting missing data; uses available data instead.

  • Updates trading session data management functionality to avoid producing pandas warnings.

  • Updates object management for compatibility with objects created in SigTech framework v7.

  • Updates object caching service to avoid caching empty DataFrames.

  • Updates the Trading Manager. When choosing the best intraday datapoint for instrument valuation, use end-of-day (EOD) if:

    • The exchange has closed, AND

    • The instrument’s valuation point has passed. This avoids a potential error if an exchange closes early.

  • Updates RollingFutureStrategy: The contract_sector, contract_code, and rolling_rule parameters are no longer case-sensitive.

  • Corrects error handling during framework object creation when the object is cached, and the cached object doesn’t have the same set of keys as the new object.

  • Corrects the sector label for single stocks where TRBC data is missing.

  • Updates the build_calendar method in sigtech.framework.infra.calendar.dates so that build_calendar works with all calendar objects, instead of just instances of HolidayCalendar.

  • Adds cash accrual to the pnl_explain method in all strategies based on delta hedging, rolling options, and rolling swaptions.

v8.6.0#

Experimental features#

Please note that these features are experimental and might change quickly.

Siglang cell magic#

Please note that this feature is experimental and might change quickly.

For notebooks running in a JupyterLab Research environment, an experimental cell magic, %%siglang, is now available.

To try it out, run the following code cells in a notebook:

import sigtech.siglang
import datetime as dtm
START_DATE = dtm.date(2018, 1, 2)
END_DATE = dtm.date.today()
DATA_DATE = dtm.date(2022, 1, 17)
CURRENCY = 'USD'
%%siglang

Initialize

For more information, navigate to the /example-notebooks/03_siglang/ folder in your JupyterHub workspace and open the SIG_primer_siglang.ipynb notebook.

Spreadsheet widget#

Please note that this feature is experimental and might change quickly.

A simple, experimental spreadsheet widget to view pandas DataFrame objects is now available.

# Import and initialize
import pandas as pd
import sigtech.framework as sig
from sigtech.framework.experimental.ui.spreadsheet import Spreadsheet
env = sig.init()

# Get or create a pandas DataFrame
stock = sig.obj.get('1000045.SINGLE_STOCK.TRADABLE')
df = stock.history_df().dropna(how='all', axis=1)

# Create the spreadsheet object from the dataframe
sheet = Spreadsheet(data=df)

# Display the spreadsheet object in a notebook cell
sheet.display('40vh')

You can edit the spreadsheet in the widget, and retrieve a DataFrame containing the updated data:

df_edited = sheet.fetch_data()

Please note that this feature is experimental and might change quickly.

For more information, in a notebook cell, run the following code:

from sigtech.framework.experimental.ui.spreadsheet import Spreadsheet
Spreadsheet?
#Spreadsheet.display?

DataCredibilityAdapter improvements#

Please note that this feature is experimental and might change quickly.

  • A new function, ohlc_credibility, computes a credibility score from Open, High, Low, and Close prices.

  • Credibility functions Winsorize (cap and floor) data prior to computing rolling mean as part of the Xi variable.

For more information, in a notebook, run the following code:

import sigtech.framework as sig
sig.DataCredibilityAdapter?
#sig.DataCredibilityAdapter.ohlc_credibility?

Equities: Analyst estimates interface improvements#

Adds a helper function, analyst_estimate_series, which accepts the following parameters:

  • field: String; the name of a fundamental field, e.g. 'Price/Earnings Ratio'.

  • metric: String; the name of a metric, e.g. 'std_dev', 'high_est', 'low_est', 'mean_est', 'median_est'.

  • period_end_date: Date for which the estimate is being made (if None, returns the entire history).

  • historical_period_index: Identifier of the historical period index (default is 'FY1').

import sigtech.framework as sig

env = sig.init()

stock = sig.obj.get('1000045.SINGLE_STOCK.TRADABLE')
stock.analyst_estimate_series('Net Sales or Revenues', 'mean_est', '2021-09-30')

OIS Swaps: Add carry_roll_down method#

OIS swaps have a new method, carry_roll_down, which computes carry and roll-down of the swap:

import sigtech.framework as sig
import datetime as dtm

env = sig.init()

swap=sig.OISSwap(currency='USD',tenor='1Y',start_date=dtm.date(2022,6,5))
swap.carry_roll_down(dtm.date(2022,6,15),['1m', '2m', '1y'])

This change extends the functionality available for LIBOR swaps to OIS swaps. The method works the same as for InterestRateSwap, and the resulting table has the same columns and meaning.

Services: DataframeService renamed to ObjectService#

The DataframeService class has been renamed to ObjectService. Likewise, the dataframe_service_cache decorator has been renamed to object_sercice_cache. ObjectService has the same functionality as DataframeService; methods and properties have not changed.

ObjectService caches any picklable object:

# Import and initialize
import sigtech.framework as sig
env = sig.init()

# Get object service from configured environment
OBJECT_SERVICE = env.object_service()

# Cache anything picklable
OBJECT_SERVICE.put('cache_key', { 'some_key': 'some value' })

# Destroy the environment; create a new one; get object service
sig.de_init()
env = sig.init()
OBJECT_SERVICE = env.object_service()

# Get cached object
from_cache = OBJECT_SERVICE.get('cache_key')
print(from_cache)

Use the object_service_cache decorator to cache the output of a function:

# Import, initialize, get object service from `env`
import sigtech.framework as sig
from sigtech.framework.services.strategy_service.service import object_service_cache
env = sig.init()
OBJECT_SERVICE = env.object_service()

# Define function with `object_service_cache` decorator
# Cache key has a string prefix and includes env.asofdate
@object_service_cache('my_prefix')
def get_some_obj():
    return { 'some_key': 'some value' }

# Cache the output of the decorated function
get_some_obj()

#
my_key = OBJECT_SERVICE.keys('my_prefix')[0]
print(my_key)
my_obj = OBJECT_SERVICE.get(my_key)
print(my_obj)

Fixes#

Framework v8.6.0:

  • Updates the underlying quantlib wrapper to allow faster execution of strategies containing many swaptions.

  • Fixes an issue when converting from yield quotes to price quotes. The framework now applies a check so that only the relevent fields are transformed.

  • Corrects cross-currency coupon notional scaling with pay delay and resettable notional.

  • Fixes retrieval of cached rolling swaptions strategies.

  • Correctly runs profit and loss (PnL) breakdown with daily and intraday data.

  • Fixes execution datetime for forward-starting resettable cross-currency swap strategies.

  • Starts notional correction in resettable cross-currency swap strategies only from swap start.

  • Allows zero execution delay for signal strategies.

  • When inspecting a strategy, modifies the weights_df function to accept a datetime, list of datetimes, or a string identifying a predefined set of times for inspection.

  • Improves the readability and color coding of performance reports.

  • Removes some undesired commas when handling lists of holidays.

  • Allows short or long direction in RollingCreditIndexStrategy.

  • Corrects a case error in the tenor parameter for credit indexes and rolling credit index strategies.

  • Fixes issues with Japanese bonds in OTR series.

v8.5.0#

Optional parameter max_absolute_delta for delta hedging strategies#

Adds optional float parameter max_absolute_delta to DeltaHedgingStrategy class.

max_absolute_delta defaults to None. If supplied, max_absolute_delta is the maximal allowed hedged delta at any moment in time, in the same units as delta (basis points for swaptions; number of underlying units for regular options).

Diagnostic functions for cross-currency swaps#

This release adds 3 diagnostic functions to the CrossCurrencySwap class:

  • swap_metrics

  • coupon_payment_dates

  • swap_details

Retrieve swap quotes from swap quote groups#

This release adds functionality to retrieve swap quotes from swap quote groups:

# Retrieve swap quotes from swap quote groups

import sigtech.framework as sig

env = sig.init()

for curr in ['EUR', 'GBP', 'USD']:
  group = sig.obj.get(f'{curr} SWAP QUOTE GROUP')
  names = group.query_instrument_names()
  print(names)
  for n in names:
    obj = sig.obj.get(n)
    print(n, obj.tenor, obj.group_name, obj.float_day_count, obj.fixed_day_count, obj.float_frequency, obj.fixed_frequency, obj.interest_rate_index_object)
    print(obj.intraday_history(period=dtm.timedelta(minutes=1)))

Fixes#

Framework v8.5.0:

  • Checks that at least one valid value is present before calculating weighted stock factors in a basket strategy.

  • Shows Costs & Slippage in PnL breakdown when transaction costs are off.

  • Allows creation of cross-currency swaps that start in the past, ensuring that resettable cross-currency swaps work post-maturity.

  • Successfully validates futures expiry dates when expiry_month_offset > 0.

  • Checks for strike when required for rolling options.

  • Fixes an issue with get_single_stock_strategy when most_liquid=True and a list of tickers or exchange tickers is provided.

  • Fixes multiple issues with the DataCredibilityAdapter class.

v8.4.0#

Simulations now handle intraday data series#

The simulation adapter now handles intraday data series. You can use the same functions to provide the framework with transformed market data.

Add method holiday_data to all Calendar objects#

For all Calendar objects, method holiday_data returns a time series with holiday information:

import sigtech.framework as sig

env = sig.init()
sig.obj.get('AUD CALENDAR').holiday_data()

Add RollingSwaption to framework imports#

When you import the SigTech framework under the standard alias, sig, you can now refer to the RollingSwaption class with sig.RollingSwaption:

import sigtech.framework as sig

# sig.RollingSwaption is available

List cached keys and strategies#

Adds new methods:

  • StrategyService.list_keys

  • StrategyService.list_strategies

  • DataFrameService.list_keys

To list available keys and strategies in StrategyService:

stratserv = sig.env().strategy_service()
available_keys = stratserv.list_keys()
available_keys = stratserv.list_strategies()

To list available keys in DataFrameService:

dfserv = sig.env().dataframe_service()
available_keys = dfserv.list_keys()

By default, returned values are filtered to those compatible with the environment.

Add resettable notional option to cross-currency swaps#

Adds parameters to CrossCurrencySwap class:

  • use_notional_reset

  • ignore_future_notional_reset

Supported only for floating-floating swaps.

Fixes#

Framework v8.4.0:

  • Strategies

    • reinvestment_strategy_overrides can now be either a datetime or a date.

    • Fixes a bug with time series indicies in basket strategies.

  • Swaps

    • Removes cross-currency coupons between valuation and settlement date.

  • Futures

    • Fixes a Copp-Clarke parsing error in 'PP INDEX' and 'KC COMDTY'.

    • Fixes a type error when computing exchange open/close from Copp-Clarke data.

    • For rolling futures, makes the rolling_table a property, calculated at request.

    • Fixes issue with SyntheticFXCross.

    • Fixes an issue with curve default data points in calculating forward rates.

  • Intraday

    • Fixes IndexError in intraday_history method

  • Data adapter, utilities, and services

    • Updates credibility aggregation logic in the DataCredibilityAdapter class.

    • Resolves pandas warning about fragmented DataFrame.

    • Resolves an issue with sig.obj.get_many_with_history for Bonds.

    • Raises an exception when fetching a non-existent key from the DataFrame Service.

    • HolidayCalendar.get_names now replaces deprecated Calendar.get_names.

v8.2.0#

Define and use instrument group labels#

Use instrument group labels to return grouped PnL and weights results.

You can group by predefined labels, or define your own.

To group PnL and weights by predefined instrument group label 'CURRENCY':

# Group PnL and weights by 'CURRENCY'

import sigtech.framework as sig
env=sig.init()

strat = sig.default_strategy_objects.rolling_futures.es_index_front()
strat.analytics.pnl_breakdown(label='CURRENCY')
strat.inspect.weights_df(label='CURRENCY')
strat.positions.get_exposure_weight(label='CURRENCY')

You can also define your own group labels. For example:

import sigtech.framework as sig
env=sig.init()

def currency_label_method(instrument_name):
    return sig.obj.get(instrument_name).currency

sig.register_labelling_method('MY_CURRENCY_LABEL', currency_label_method)

To get an instrument group label for a particular instrument, use sig.get_label:

# Get instrument group label for a particular instrument

print(sig.get_label('CURRENCY', 'ESZ20 INDEX'))
print(sig.get_label('MY_CURRENCY_LABEL', 'ESZ20 INDEX'))

MacroEconomicFix method history_df replaces macro#

In sig.instruments.fixes.MacroEconomicFix, v8.2 deprecates the macro method and replaces it with history_df. This change makes method names more consistent between instrument types.

Convert your code to use history_df instead of macro:

# Replace deprecated method `macro` with `history_df`

import sigtech.framework as sig
env = sig.init()

# Deprecated in v8.2
# print(sig.obj.get('ECO PPP OECD US MACROECONOMICFIX').macro())

print(sig.obj.get('ECO PPP OECD US MACROECONOMICFIX').history_df())

Enable overnight index cross currency swaps#

v8.2 enables overnight index swaps (OIS) when creating cross currency (XCCY) swaps.

To create an OIS XCCY swap, pass is_ois=True when creating a CrossCurrencySwap. Optionally, pass ois_params (a dictionary with additional OIS parameters).

# Create an OIS XCCY swap

import sigtech.framework as sig
env = sig.init()

my_ois_xccy_swap = sig.CrossCurrencySwap(
    currency='JPY',
    pay_currency='USD',
    trade_date=dtm.date(2018, 6, 15),
    tenor='2Y',
    is_ois=True,
    # ois_params={...}
)

Improved live streaming of intraday data#

SigTech framework v8.2 improves intraday market data streaming. Subscribing to live market data now gives all updates since midnight, ensuring that no intraday data is missed.

This improvement is automatic upon subscription; you don’t need to do anything differently to use it.

Futures#

Add settlement times to futures groups#

In sig.FuturesContractGroup, property settlement_time gives the time of day when the futures price was generated.

This change allows product-specific settlement times for futures groups.

To get the settlement time for a futures group:

# Get settlement time for futures group

import sigtech.framework as sig
env = sig.init()

future = sig.obj.get('CLZ22 COMDTY')
print(future.group().settlement_time)
print(future.valuation_dt(env.asofdate))

Date parameter d in FuturesContractGroup.active_contract defaults to today#

In sig.instruments.FuturesContractGroup.active_contract, date parameter d is now optional, and defaults to datetime.date.today.

# Date param in FCG.active_contract is optional

import datetime as dtm
import sigtech.framework as sig
env = sig.init()

group = sig.obj.get('ES INDEX FUTURES GROUP')

# Equivalent
print(group.active_contract(dtm.date.today()))
print(group.active_contract())

Futures contract groups use Copp-Clarke session data in exchange open and close times#

In v8.2, futures contract groups use Copp-Clarke trading session data, if it’s available, to determine the exchange opening and closing times for futures exchange.

This change is automatic; you don’t need to do anything differently to use it.

v8.1.0#

Improve chart formatting in notebook files#

In notebook (.ipynb) files, after initializing the framework environment, you can enable improved chart formatting.

To enable improved chart formatting in notebook files:

# Enable improved chart formatting in notebook files

import sigtech.framework as sig
env = sig.init()

sig.set_plot_mode()

Retrieve spot dollar duration series#

For a RollingFutureStrategy or RFPriceIndex with underlying BondFuture or InterestRateFuture, spot_dv01 returns a series of spot dollar duration (DV01) values for the history of the instrument:

# Retrieve spot dollar duration values

ty = sig.RFPriceIndex(
    currency='USD',
    start_date=dtm.date(2020,1,4),
    contract_code='TY',
    contract_sector='COMDTY',
    rolling_rule='front',
    front_offset='-6:-5')
ty.spot_dv01()

Add position targets for CVaR and VaR#

Add position targets for Conditional Variable at Risk (CVaR) and Value at Risk (VaR) to strategies.

To add a position target for CVaR, call strat.add_position_target with parameter unit_type='HISTORICAL_CVAR':

# Add a position target for CVaR

class MyStrategy(sig.DailyStrategy):
  def strategy_initialization(self, dt):
    self.add_position_target(
      dtm.date(2021,7,10),
      instrument_name='1003331.SINGLE_STOCK.TRADABLE',
      units=0.5,
      unit_type='HISTORICAL_CVAR'
    )

To add a position target for VaR, call strat.add_position_target with parameter unit_type='HISTORICAL_VAR':

# Add a position target for VaR

class MyStrategy(sig.DailyStrategy):
  def strategy_initialization(self, dt):
    self.add_position_target(
      dtm.date(2021,7,10),
      instrument_name='1003331.SINGLE_STOCK.TRADABLE',
      units=0.5,
      unit_type='HISTORICAL_VAR'
    )

v8.0.0#

New features and package upgrades#

TensorFlow support#

From version 8.0, the SigTech framework supports TensorFlow 2.8.0.

To install TensorFlow in Jupyter Lab:

  1. In the SigTech Research environment, create or open a Jupyter Lab workspace.

    At Set up your Research environment > Framework version, select V8-latest.

  2. In a notebook, install and import TensorFlow:

    # Install and import TensorFlow
    
    !pip install tensorflow
    import tensorflow as tf
    print("TensorFlow version:", tf.__version__)
    

Python package upgrades#

To support newer features of Python, pandas, TensorFlow, and other packages, SigTech framework v8 upgrades the version requirement of the following dependencies:

Package

v7 requirement (Python 3.7.10)

v8 requirement (Python 3.9)

cvxpy

1.0.15

1.1.18

matplotlib

3.2.2

3.5.1

numpy

1.18.4

1.22.2

pandas

1.0.5

1.4.1

scipy

1.5.4

1.8.0

scikit-learn

0.23.2

1.0.2

Breaking changes in pandas upgrade

For pandas data frames indexed by a pandas DatetimeIndex, DataFrame.loc is no longer subscriptable with a basic Python datetime.date object. Instead, use pandas.to_datetime to convert a Python date object to a pandas datetime object:

# `DataFrame.loc` not subscriptable with `datetime.date` in pandas 1.4
# Use `pd.to_datetime` to convert `datetime.date` to pandas datetime object

import pandas as pd
import numpy as np
import datetime as dtm

index = pd.date_range(dtm.date(2021, 1, 1), dtm.date(2021, 1, 31))

df = pd.DataFrame(
    index = index,
    data = {'Zeros': np.zeros(len(index))},
)

# Not supported in pandas 1.4
# df.loc[dtm.date(2021, 1, 1)]

df.loc[pd.to_datetime(dtm.date(2021, 1, 1))]

New strategy performance visualization#

To display an interactive visualization of a strategy’s performance, use plot.performance:

# Display interactive strategy performance visualization

import sigtech.framework as sig
import datetime as dtm
env = sig.init()

strat = sig.ReinvestmentStrategy(
    currency='USD',
    start_date=dtm.date(2021, 1, 1),
    underlyer='1000045.SINGLE_STOCK.TRADABLE',
)
strat.plot.performance()

In SigTech framework v8, plot.performance uses a new visualization with improved interface design and UX controls. The v8 framework also adds a Share button to the interface, so you can share the visualization as an image or embed the interactive chart anywhere on the web.

Use the v7 performance visualization in v8

To use the v7 performance visualization in v8, pass fallback=True to Strategy.plot.performance:

# Use v7 strategy performance visualization in v8

import sigtech.framework as sig
import datetime as dtm
env = sig.init()

strat = sig.ReinvestmentStrategy(
    currency='USD',
    start_date=dtm.date(2021, 1, 1),
    underlyer='1000045.SINGLE_STOCK.TRADABLE',
)
strat.plot.performance(fallback=True)

plot.performance no longer accepts deprecated inline parameter

Passing the deprecated inline parameter to plot.performance raises an error in v8. Remove the inline parameter from calls to plot.performance:

# Remove `inline` parameter from calls to `plot.performance`

import sigtech.framework as sig
import datetime as dtm
env = sig.init()

strat = sig.ReinvestmentStrategy(
    currency='USD',
    start_date=dtm.date(2021, 1, 1),
    underlyer='1000045.SINGLE_STOCK.TRADABLE',
)

# Raises `TypeError` in v8
# strat.plot.performance(inline=True)

# Works correctly in v8
strat.plot.performance()

Changes to the framework environment#

Initialize and configure the framework environment#

To initialize the v8 framework environment, use sig.init:

# Initialize the SigTech framework

import sigtech.framework as sig
env = sig.init()

In the example above, env points to the configured environment that sig.init creates.

Re-initialize the framework environment

By default, calling sig.init when the framework is already initialized has no effect in v8. To destroy the existing configured environment and initialize a new one, pass repeat_mode='reinit':

# Re-initialize the SigTech framework

import sigtech.framework as sig
env = sig.init()

# No effect on configured environment
env = sig.init()

# Destroys existing configured environment; initializes new one
env = sig.init(repeat_mode='reinit')

Configure the framework environment

You can change the framework environment configuration settings immediately after calling sig.init:

# Change framework environment config settings

import sigtech.framework as sig
import datetime as dtm

settings = [
    ('TM_TIMEZONE', 'Australia/Sydney'),
    ('TM_CALENDAR', 'SYDNEYB CALENDAR'),
    ('TM_INTRADAY_OUT_OF_HOURS', True),
]

env = sig.init()
for (setting, value) in settings:
    env[setting] = value

Environment property _quant_bridge replaced by quant_bridge#

The configured environment has a property that refers to the quant analytics library.

  • In v7, the configured environment’s quant library property was _quant_bridge.

  • In v8, the configured environment’s quant library property is quant_bridge. Using the v7 property name raises an error in v8.

Changes to default configured environment settings#

Version 8 of the SigTech framework changes the following default environment configuration settings:

Setting

Property name

v7 default

v8 default

Trading calendar

'TM_CALENDAR'

London Christmas

None

Ignore transaction costs

'IGNORE_T_COSTS'

False

True

Auto manage custom strategy margins

'AUTOMATIC_MARGIN_CLEANUP'

False

True

Single-stock strategy history start date

'DEFAULT_RS_START_DATE'

Jan 02, 2008

Jan 02, 2009

Trading calendar

The v7 framework set the trading calendar to the London Christmas calendar by default. The v8 framework does not set a trading calendar.

You can set a trading calendar immediately after you call sig.init. To set the trading calendar to the London Christmas calendar:

# Set a trading calendar

import sigtech.framework as sig
env = sig.init()
env['TM_CALENDAR'] = 'London,CHR CALENDAR'

Ignore transaction costs

The v7 framework assigned a transaction cost model and calculated transaction costs by default. The v8 framework also assigns a transaction cost model, but ignores transaction costs by default.

To calculate transaction costs for new and existing strategies in v8, enable transaction costs immediately after you call sig.init:

# Enable transaction costs

import sigtech.framework as sig
env = sig.init()
env['IGNORE_T_COSTS'] = False

Auto manage custom strategy margins

The v7 framework automatically managed end-of-day margin cleanup for SigTech building blocks. However, if you built a custom strategy that directly traded an instrument with margins, you needed to schedule margin cleanup yourself.

The v8 framework automatically manages end-of-day margin cleanup for all strategies. When building new custom strategies in v8, you no longer need to schedule margin cleanup.

If you are troubleshooting performance issues in a custom strategy, switching off automatic end-of-day margin cleanup might help in some cases.

To switch off automatic end-of-day margin cleanup for custom strategies:

# Switch off automatic end-of-day margin cleanup for custom strategies

import sigtech.framework as sig
env = sig.init()

env['AUTOMATIC_MARGIN_CLEANUP'] = False

Single-stock strategy history start date

When you retrieve a single stock strategy with sig.get_single_stock_strategy, the framework caps the start date of the strategy’s history to the DEFAULT_RS_START_DATE environment configuration setting.

The v7 framework set DEFAULT_RS_START_DATE to Jan 02, 2008. The v8 framework sets DEFAULT_RS_START_DATE to Jan 02, 2009. This change avoids possible conversion problems with older data.

You don’t need to change your code unless you want sig.get_single_stock_strategy to include data from before Jan 02, 2009.

If you want sig.get_single_stock_strategy to include data from before Jan 02, 2009, change the DEFAULT_RS_START_DATE environment configuration setting immediately after you initialize the framework.

For example, to set DEFAULT_RS_START_DATE to Jan 02, 2008:

# Set `DEFAULT_RS_START_DATE` to Jan 02, 2008

import sigtech.framework as sig
import datetime as dtm

env = sig.init()
env[sig.config.DEFAULT_RS_START_DATE] = dtm.date(2008, 1, 2)

Changes to the magnitude of Greek variables#

Greek variables indicate risk assumptions for options and swaptions.

SigTech framework v8 changes the magnitude of some Greek variables to follow market conventions. Modify your custom strategy classes where necessary to adjust for the changes.

Options#

For equity index options, commodity options, and FX options, the magnitudes of Greek variables have changed as follows:

Variable

v7 magnitude

v8 magnitude

Indicates

Vega

100%

1%

Option price sensitivity to change in underlying asset price volatility

Gamma

100%

1% of underlying asset price

Delta sensitivity to change in underlying asset price

Dollar Gamma

50% of underlying asset price (including pnl explain scaling factor of 0.5)

1% of underlying asset price

Dollar Delta sensitivity to change in underlying asset price

Swaptions#

For swaptions, the magnitudes of Greek variables have changed as follows:

Variable

v7 magnitude

v8 magnitude

Indicates

Vega

10,000bps

1bps

Swaption price sensitivity to change in underlying asset price volatility

Delta

10,000bps

1bps

Swaption price sensitivity to a change in swap rate

Gamma

10,000^2 bps

1bps

Delta sensitivity to a change in swap rate

New syntax for custom classes#

SigTech framework v8 introduces new type syntax and object instantiation hooks for custom classes that extend SigTech classes.

# Define a custom strategy in v8

from typing import Optional, List
from typing_extensions import Literal
from sigtech.framework.strategies.strategy import Strategy

class NewStyle(Strategy):
     __aliases__ = {'b': 'another_b'}

    a: Optional[int] = 100
    b: float = 3.0
    c: List[str]
    d: Literal['long', 'short'] = 'long'

Convert your existing custom classes to the v8 syntax, and use the updated v8 syntax when defining new custom classes.

Deprecations#

To improve the performance and quality of the framework codebase, v8 deprecates some classes, methods, and properties. This section describes how to update your code for v8.

{% hint style=”warning” %} Using deprecated functionality raises an error in v8.

Update your code to remove deprecated functionality and use the v8 equivalents in the following sections. {% endhint %}

Deprecations in sig.analytics#

In sig.analytics, v8 deprecates and replaces the following classes:

Module

Deprecated v7 class

Replacement v8 class

optimization.optimizer

FactorOptimizer

Optimizer

optimization.optimization_problem

FactorOptimizationProblem

OptimizationProblem

performance.performance_report

TsPerformance

PerformanceReport

performance.performance_report

CustomReport

PerformanceReport

Deprecations in sig.infra.calendar#

In sig.infra.calendar, v8 deprecates and replaces the following classes:

Module

Deprecated v7 class

Replacement v8 class

business_calendar

Calendar

CustomCalendar

calendar

Calendar

HolidayCalendar

Deprecations in sig.instruments#

Deprecated type-checking methods

In sig.instruments, v8 deprecates the following type-checking methods:

Module

Class

Method

base

Instrument

is_future

base

Instrument

is_synthetic_swap

base

Instrument

is_equity_swap

base

Instrument

is_bond_repo

base

Instrument

is_bond_swap

base

Instrument

is_ir_swap

base

Instrument

is_index_swap

base

Instrument

is_ir_bh_swap

base

Instrument

is_tr_swap

base

Instrument

is_bond

base

Instrument

is_fx_forward

base

Instrument

is_order

base

Instrument

is_equity_single_stock

base

Instrument

is_etf

bonds

BondBase

is_bond

bonds

GovernmentBondRepo

is_bond_repo

bonds

GovernmentBondSwap

is_bond_swap

fx_otc

FXForward

is_fx_forward

index_swap

IndexSwap

is_index_swap

ir_otc

InterestRateSwap

is_ir_swap

The deprecated type-checking methods are not replaced in v8. Instead, use the built-in Python function isinstance to check the type of an object:

# Use `isinstance` to check type of an object

import sigtech.framework as sig
from sigtech.framework.instruments import Instrument
from sigtech.framework.instruments.equities import EquityInstrument

env = sig.init()

obj = sig.obj.get('1000045.SINGLE_STOCK.TRADABLE')

print(isinstance(instr, Instrument))
print(isinstance(instr, EquityInstrument))

Other deprecated instruments methods

In sig.instruments, v8 also deprecates the following methods and properties:

Module

Deprecated v7 method or property

Replacement v8 method or property

base

ContractGroup.contract_product_type

ContractGroup.item_product_type

base

HistoricalFrameworkObject.underlying_str

HistoricalFrameworkObject.asset_description

fixes

IntradayFix.underlying_name

Not replaced

lme_otc

create_lme_forward

LMEUtils.create_lme_forward

options

CommodityFutureOption.underlying_name

Not replaced

options

OptionBase.pnl_breakdown

OptionBase.pnl_explain

Deprecations in sig.strategies#

Classes

In sig.strategies, v8 deprecates and replaces the following classes:

Module

Deprecated v7 class

Replacement v8 class

basket_strategies

DynamicGlobalBasket

BasketStrategy

fx_forward_rolling_strategy

FXForwardRollingStrategy

RollingFXForwardStrategy

fx_forward_rolling_strategy

DynamicFXForwardRollingStrategy

DynamicRollingFXForwardStrategy

Methods

In sig.strategies, v8 deprecates and replaces the following methods:

Module

Deprecated v7 method

Replacement v8 method

reinvestment_strategy

get_single_stock_strategy_name_parallel

get_single_stock_strategy

reinvestment_strategy

get_reinvestment_strategy

get_single_stock_strategy

rolling_bond_strategy

RollingBondStrategy.get_roll_schedule

RollingBondStrategy.rolling_schedule

Decorators

In sig.strategies, v8 deprecates and replaces the following decorators:

Module

Deprecated v7 decorator

Replacement v8 decorator

runner.metaflow.decorators.function_flow

FunctionFlow

FunctionJob

runner.metaflow.decorators.strategy_flow

StrategyFlow

StrategyJob

Deprecations in the Strategy class#

In sig.strategies, v8 deprecates the following methods in the strategy.Strategy class:

Module

Deprecated v7 method

Replacement v8 method

strategy

Strategy.clean_up_margin

Strategy.add_margin_cleanup

strategy

Strategy.get_object

sig.obj.get

{% hint style=”info” %} Note: You might not need to use Strategy.add_margin_cleanup.

By default, v8 automatically manages end-of-day margins in custom strategies. {% endhint %}

Strategy.analytics interface

In v8, the Strategy.analytics interface replaces the following deprecated methods:

  • Strategy.excess_return_history

  • Strategy.pnl_breakdown

  • Strategy.turnover

  • Strategy.intraday_turnover

  • Strategy.cash_turnover

  • Strategy.turnover_stats

  • Strategy.approximate_rounding_impact

  • Strategy.approximate_rounding_summary

  • Strategy.relative_attribution

  • Strategy.total_return_valuation_history

Strategy.inspect interface

In v8, the Strategy.inspect interface replaces the following deprecated methods:

  • Strategy.evaluate_trades

  • Strategy.evaluate_positions

  • Strategy.historic_positions

  • Strategy.display_holdings

  • Strategy.display_run_details

  • Strategy.positions_df

  • Strategy.weights_df

  • Strategy.cash_df

  • Strategy.bottom_positions_df

  • Strategy.bottom_cash_df

  • Strategy.timeline_data

  • Strategy.tree_df

Strategy.plot interface

In v8, the Strategy.plot interface replaces the following deprecated methods:

  • Strategy.interactive_tree_plot

  • Strategy.interactive_portfolio_table()

  • Strategy.interactive_timeline_plot()

  • Strategy.interactive_performance

In the Strategy.plot.performance method, the parameter inline is deprecated.

DailyStrategy replaces some deprecated functionality in Strategy

In v8, the DailyStrategy class replaces some deprecated functionality in the Strategy class.

To update your code for v8, extend DailyStrategy instead of Strategy, and replace the deprecated methods below with their v8 equivalents.

  • The following methods are deprecated in the Strategy class, but implemented in DailyStrategy:

    Deprecated v7 method

    Replacement v8 method

    Strategy.add_method

    DailyStrategy.add_method

    Strategy.add_position_target

    DailyStrategy.add_position_target

    Strategy.add_trade

    DailyStrategy.add_trade

    Strategy.add_break_point

    DailyStrategy.add_break_point

    Strategy.add_fx_spot_trade

    DailyStrategy.add_fx_spot_trade

    Strategy.size_date_from_decision_dt

    DailyStrategy.size_date_from_decision_dt

    Strategy.size_dt_from_date

    DailyStrategy.size_dt_from_date

    Strategy.size_date_from_date

    DailyStrategy.size_date_from_date

    Strategy._decision_time

    DailyStrategy._decision_time

    Strategy._decision_tzinfo

    DailyStrategy._decision_tzinfo

    Strategy.size_time

    DailyStrategy.size_time

    Strategy.size_tzinfo

    DailyStrategy.size_tzinfo

    Strategy.execution_time

    DailyStrategy.execution_time

    Strategy.execution_tzinfo

    DailyStrategy.execution_tzinfo

    Strategy._size_dt_from_decision_dt_

    DailyStrategy._size_dt_from_decision_dt_

    Strategy._instrument_execution_dt_from_datetime

    DailyStrategy._instrument_execution_dt_from_datetime

    Strategy.decision_dt_from_execution_dt

    DailyStrategy.decision_dt_from_execution_dt

    Strategy.decision_dt_from_date

    DailyStrategy.decision_dt_from_date

  • Use DailyStrategy.add_method instead of the following methods:

    • Strategy.add_method

    • Strategy.add_processor

    • Strategy.add_processor_with_priority

  • Use DailyStrategy.add_position_target instead of the following methods:

    • Strategy.add_position_target

    • Strategy.set_position

    • Strategy.set_weight

  • Use DailyStrategy.add_trade instead of the following methods:

    • Strategy.add_trade

    • Strategy.add_position

    • Strategy.ir_swap_trade

    • Strategy.tr_swap_trade

    • Strategy.index_swap_trade

    • Strategy.fx_forward_trade

    • Strategy.lme_forward_trade

    • Strategy.lme_spread_trade

    • Strategy.index_forward_trade

    • Strategy.brl_swap_trade

    • Strategy.credit_index_trade

    • Strategy.xccy_swap_trade

  • Use DailyStrategy.add_break_point instead of the following methods:

    • Strategy.add_break_point

    • Strategy.stop_processing

  • Use DailyStrategy.add_fx_spot_trade instead of the following methods:

    • Strategy.add_fx_spot_trade

    • Strategy.fx_spot_trade

Deprecations in other modules#

SigTech framework v8 also deprecates the following methods and properties:

Module

Deprecated method or property

Replacement method or property

sig.config.config

ConfiguredEnvironment._quant_bridge

ConfiguredEnvironment.quant_bridge

sig.infra.analytics.fx.cross

FXCross.is_flipped_cross

FXCross.is_flipped

sig.indices.tradable_index

IntradayInstrument.intraday_db_field

Not replaced

sig.signal.library.allocation

factor_optimized_allocations

optimized_allocations

sig.sig_master

SIGMasterBase.filter_to_last_corporate_event

SIGMasterBase.filter_to_last_pit_record