Framework v8 Latest#
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 parallelrisk_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])