Framework v9#
New to v9?
See Guide to v9.0 for help with updating your code.
v9.5#
Improvements#
Rolling strategies: Improved consistency across rolling strategy classes with RollingStrategyBase
class#
Previously, certain methods were only available for RollingFuturesStrategy
, but not for other rolling strategy classes.
To improve consistency between rolling strategy classes, RollingStrategyBase
base class has been created. It contains the same attributes and methods that are shared between all its subclasses.
The rolling_schedule
method and specialized rolling_table
property have now been implemented in all rolling strategy classes, including:
RollingSwapStrategy
RollingOptionStrategy
RollingBondStrategy
RollingCreditIndexStrategy
RollingStructureBasketStrategy
RollingFXForwardStrategy
RollingOptionsStrategyBase
RFPriceIndex
rolling_schedule
returns the roll schedule, while rolling_table
returns the strategy’s rolling table as a pandas DataFrame.
Code example:
import datetime as dtm
import sigtech.framework as sig
sig.init()
rc = sig.RollingOptionStrategy(
currency="USD",
start_date=dtm.date(2018, 1, 4),
end_date=dtm.date(2019, 1, 4),
group_name="USDJPY OTC OPTION GROUP",
option_type="Call",
maturity="3M",
rolling_frequencies=["1M"],
strike_type="SPOT",
strike="ATM+10%",
)
_rolling_schedule = rc.rolling_schedule())
_rolling_table = rc.rolling_table
Rolling options strategy: Added scaling to strategy cash#
Previously, RollingOptionStrategy
would trade one option or one option strategy by default, regardless of how much initial_cash
was held.
To improve the behavior of the RollingOptionStrategy
class, cash needs to be taken into consideration to size the number of options. To enable this, two new additions have been introduced:
New
target_type
("PVAsProportionOfNAV"
) enables the sizing of the number of options depending on the net asset value (NAV), rather than a fixed amount of present value (PV).New parameter
greek_neutral_nav_scale
enables the sizing of the number of delta-neutral structures that the strategy would hold. This also fixes the issue of when the target_type is a Greek (e.g. `target_type=’Delta’).
As a result, RollingOptionStrategy
now sizes the number of options using the cash.
Code example to test PVAsProportionOfNAV
:
rc = sig.RollingOptionStrategy(
currency='USD',
start_date=dtm.date(2018, 1, 4),
end_date=dtm.date(2018, 6, 4),
group_name=g,
option_type='Call',
maturity='3M',
rolling_frequencies=['1M'],
strike_type='SPOT',
strike='ATM',
target_type='PVAsProportionOfNAV',
target_quantity=1,
)
rc.history()
Code example to test greek_neutral_nav_scale
:
butterfly = sig.RollingButterflyOptionsStrategy(
start_date=dtm.date(2018, 1, 4),
end_date=dtm.date(2019, 7, 4),
initial_cash=1000,
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='Delta',
target_quantity=0,
greek_neutral_nav_scale=1
)
butterfly.history()
Options: metrics
method returns vega weighted implied volatility#
Previously when calling the metrics
method on an options strategy, it would return the sum of all Greeks, as well as the average implied volatility of the options held.
To improve the output, a ‘Vega Weighted Implied Volatility’ column is now added to any metrics
method output. This is particularly useful for portfolios holding options with different expiries.
Code example:
import datetime as dtm
import sigtech.framework as sig
import datetime as dtm
sig.init()
d = dtm.date(2020, 2, 24)
group = sig.obj.get('EURUSD OTC OPTION GROUP')
def basket(strategy, dt, positions, **additional_parameters):
size_date = strategy.size_date_from_decision_dt(dt)
call = group.get_option(start_date=size_date, option_type='Call', strike=0.25, strike_type='Delta', maturity='3M')
put = group.get_option(start_date=size_date, option_type='Put', strike=-0.25, strike_type='Delta', maturity='3M')
return {call:1, put:-100}
strat = sig.DynamicOptionsStrategy(
currency='GBP',
start_date=d,
rolling_frequencies=['1M'],
group_name=group.name,
basket_creation_method=basket,
initial_cash=0,
total_return=False,
t0_option_selection=True,
close_out_at_roll=True,
target_quantity=100,
target_type='Vega',
net_target_quantity=False,
data_points=['NEW_YORK_1700']
)
strat.metrics()
Options: Improved calculations by adding net_target_quantity
flag variable to get net Greeks in option strategies#
Previously, the greeks
and metrics
methods for option strategies would only take the sum of all Greeks in an options strategy.
greeks
and metrics
methods for option strategies now match the net_target_quantity
flag. You can choose whether to net Greeks or not by setting the net_target_quantity
variable:
If set to
True
, the sum of values is calculatedIf set to
False
, the sum of absolute values is calculated
Code example:
import datetime as dtm
import sigtech.framework as sig
import datetime as dtm
sig.init()
d = dtm.date(2020, 2, 24)
group = sig.obj.get('EURUSD OTC OPTION GROUP')
def basket(strategy, dt, positions, **additional_parameters):
size_date = strategy.size_date_from_decision_dt(dt)
call = group.get_option(start_date=size_date, option_type='Call', strike=0.25, strike_type='Delta', maturity='3M')
put = group.get_option(start_date=size_date, option_type='Put', strike=-0.25, strike_type='Delta', maturity='3M')
return {call:1, put:-1}
strat = sig.DynamicOptionsStrategy(
currency='USD',
start_date=d,
end_date=dtm.date(2020, 3, 30),
rolling_frequencies=['1BD'],
group_name=group.name,
basket_creation_method=basket,
initial_cash=0,
total_return=False,
t0_option_selection=True,
close_out_at_roll=True,
target_quantity=100,
target_type='Vega',
net_target_quantity=False
)
strat.greeks(dollar_greeks=True, net_greeks=False)
New features#
New methods available for obtaining volatility series#
Added new methods to get historical butterfly volatility, at-the-money volatility, and volatility for a given tenor and delta for equity. You can use these to get a volatility series for certain delta on the volatility surface.
The following code blocks demonstrate the different methods for getting volatility series:
import sigtech.framework as sig
sig.init()
vs = sig.obj.get('SPX INDEX VOLSURFACE')
Get 1Y tenor 50 delta risk reversal:
vs.risk_reversal(tenor='1Y', delta=50).plot()
Get 1Y tenor 50 delta butterfly:
vs.butterfly(tenor='1Y', delta=50).plot()
Get 1Y tenor at-the-money volatility:
vs.atm_vols_for_tenor('1Y').plot()
Get 1Y tenor 25 delta call volatility:
vs.vols_for_tenor(delta=25, tenor='1Y')
Get 1Y tenor 25 delta put volatility:
vs.vols_for_tenor(delta=-25, tenor='1Y')
FX: Implemented volatility and forward curve shifts for FX#
When implementing volatility or forward curve shifts for FX, the change_type
parameter can now be set to either of the following arguments:
'RETURN'
: Percentage change'DIFF'
: Absolute value change
The following code blocks demonstrate a volatility curve shift:
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
import datetime as dtm
sig.init()
### VOL CURVE SHIFT ###
vol_curve_ticker = 'EURUSD VOLSURFACE'
Shift volatility curve to at-the-money (ATM) strike of 1.25:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): 1.25},
change_type='PRICE',
)
sig.obj.get(vol_curve_ticker).history()
Shift volatility curve horizontally by 0.1 to the right, so new_ATM_strike = old_ATM_strike + 0.1:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): 0.1},
change_type='DIFF',
)
sig.obj.get(vol_curve_ticker).history()
Shift volatility curve horizontally by 2% of spot price to the left, so new_ATM_strike = old_ATM_strike - (2% * spot)
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): -0.02},
change_type='RETURN',
)
sig.obj.get(vol_curve_ticker).history()
Forward curve shifts also take an additional overwrite_type
parameter:
'POINT'
: Single value overwrite'FLAT'
: Overwrite all tenor values'PARALLEL'
: Overwrite all tenors and keep absolute difference between them'RATIO'
: Overwrite all tenors and keep relative difference between tenors
The following code blocks demonstrate a forward curve shift:
### FWD CURVE SHIFT ###
fwd_curve_ticker = 'EURUSD FORWARD RATE CURVE'
Overwrite only 3 Feb 2009 tenor to 1.0:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2009, 2, 3): 1.0},
change_type='PRICE',
overwrite_type='POINT'
)
sig.obj.get(fwd_curve_ticker).history()
Shift all tenor values by 0.098 upwards from 3 Feb 2009 onwards:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2009, 2, 3): 0.098},
change_type='DIFF',
overwrite_type='PARALLEL'
)
sig.obj.get(fwd_curve_ticker).history()
Overwrite all tenor values on 3 Feb 2009 to 4 Jan 2005 original value +9%:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2009, 2, 3): 0.09},
change_type='RETURN',
overwrite_type='FLAT'
)
sig.obj.get(fwd_curve_ticker).history()
Overwrite 3 Feb 2009 to 0.97 and adjust all other tenors on 3 Feb 2009 to keep the relative difference between tenors:
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2009, 2, 3): 0.97},
change_type='PRICE',
overwrite_type='RATIO'
)
sig.obj.get(fwd_curve_ticker).history()
v9.4#
Improvements#
data_dict
and data_dict_group
methods return all object attributes#
data_dict
and data_dict_group
methods can be used on any framework object to return a dictionary of available attributes for that object. This makes it easier for you to see the required parameters of a building block, as it provides a clearer idea of the available functionality.
data_dict
method now accepts three arguments: include_private
, include_optional
, and include_inherited
. You can use this method on every framework object to return a dictionary containing static data and the required fields needed by the class constructor. By default, optional and inherited attributes are included.
Code example:
sig.obj.get('SPX INDEX').data_dict(include_optional=False)
New method data_dict_group
has been added. You can also use the method on any framework object to return the static data in a dictionary. The attributes are grouped by attribute group type: AttrGroup.OPTIONAL
, AttrGroup.INHERITED
, and AttrGroup.PRIVATE
.
Code example:
from sigtech.framework.infra.objects.dtypes import AttrGroup
sig.obj.get('SPX INDEX').data_dict_group(AttrGroup.INHERITED)
New features#
otr_series
: Added country-dependent tenors#
Country-dependent bond tenors have been introduced to on-the-run (OTR) series, making them more flexible.
otr_series
can be used to select specific OTR bonds from each country. Code example to test:
import sigtech.framework as sig
sig.init()
sig.obj.get('BE GOVT BOND GROUP').otr_series('8Y')
Below is a dictionary of the available tenors for the new otr_series
:
bond_dict = {
'US':['2Y','3Y','5Y','7Y','10Y', '20Y', '30Y'],
'GB':['3Y','5Y','7Y','10Y', '30Y'],
'JP':['2Y','3Y','5Y','10Y', '20Y', '30Y', '40Y'],
'DE':['2Y','5Y','7Y','10Y', '30Y'],
'FR':['3Y','5Y', '10Y', '30Y'],
'IT':['2Y','3Y','5Y','7Y','10Y', '30Y'],
'CA':['2Y','5Y','10Y','30Y'],
'ES':['3Y','5Y','7Y','10Y', '15Y', '30Y'],
'BE':['5Y','8Y','10Y', '20Y', '30Y'],
'SE':['10Y'],
'NO':['10Y'],
}
Strategies can now take objects instead of strings as parameters#
Added a new input field that allows you to pass either strategy objects or strategy object names when building a strategy. As a result, you can now pass the strategy object directly, instead of having to use the strategy string name (constituent_names
).
This feature is available with the following strategy classes:
BasketStrategy
DeltaHedgingStrategy
FeeStrategy
FXForwardHedgingStrategy
The code example below shows a basket strategy that takes objects instead of string names:
from sigtech.framework.default_strategy_objects.rolling_futures import es_index_front, bo_comdty_f_0
import sigtech.framework as sig
env = sig.init(log_level='WARNING')
basket = sig.BasketStrategy(
constituents=[es_index_front(), bo_comdty_f_0()],
weights=[0.6, 0.4],
rebalance_frequency='EOM',
)
basket_2.history()
Fixes#
Used contract names in
RollSchedule.get_first_valid_series_contract
.Set
net_target_quantity=False
for target_typePV
,SpotNotional
andSpotNotionalAsProportionOfNAV
.More accurate error messages.
Fixed
ReinvestmentStrategy
bug when single stock is delisted.Fixed
RFPriceIndex
andRollingFutureStrategy
price_series
bug when no roll-out contracts.Reordered dates in
DynamicOptionStrategy
dependencies.
Single stocks: Created cash_index
for MXN, EAD, DKK and IND currencies#
Previously when building reinvestment strategies using single stocks, there would be a warning saying the cash index was missing. The following currencies experienced this issue: MXN, EAD, DKK, IND.
cash_index
has now been configured for those currencies. Code example to test:
ss = sig.obj.get('7146413.SINGLE_STOCK.TRADABLE')
test = sig.ReinvestmentStrategy(
currency=ss.currency,
underlyer=ss.name,
start_date=dtm.date(2018, 1, 1),
)
test.history()
v9.3#
Improvements#
Improved swap_details
method for cross currency swaps#
More details have been added to the swap_details
method for cross currency swaps. As a result, this matches the cash flow view of Bloomberg, improves usability in line with industry standards, and enables better understanding of the pricing.
For example, the ability to display results as a dataframe using the as_df
feature has been added, making cross currency swaps more consistent with other swaps instruments on the SigTech platform.
import datetime as dtm
import numpy as np
import pandas as pd
import sigtech.framework as sig
env = sig.init()
swap = sig.CrossCurrencySwap(
currency="USD",
pay_currency="EUR",
tenor=dtm.date(2025, 7, 5),
pay_notional=1000000,
trade_date=dtm.date(2021, 7, 5),
swap_type='FloatFloat',
use_notional_reset=True,
)
swap.swap_details(as_df=True)
Options: Added volatility and forward curve shift for absolute and relative change in equity index options#
When implementing volatility or forward curve shifts for equity index options, the change_type
parameter can now be set to either of the following arguments:
RETURN
: Percentage change
DIFF
: Absolute value change
The following code examples explore volatility curve shift. Run each code block in a separate cell and reinitialize the environment for each example:
Shift volatility curve to at-the-money (ATM) strike of 799:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2005, 1, 3): 799.0},
change_type="PRICE",
)
sig.obj.get(vol_curve_ticker).history()
Shift volatility curve horizontally by 50 to the right, so new_ATM_strike = old_ATM_strike + 50:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2005, 1, 3): 50.0},
change_type="DIFF",
)
sig.obj.get(vol_curve_ticker).history()
Shift vol curve horizontally by 2% of spot price to the left, so new_ATM_strike = old_ATM_strike - (2% * spot):
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2005, 1, 3): -0.02},
change_type="RETURN",
)
sig.obj.get(vol_curve_ticker).history()
For forward curve shift, you can also set the overwrite_type
parameter with any of the following arguments:
POINT
: Overwrite single valueFLAT
: Overwrite all tenor valuesPARALLEL
: Overwrite all tenors and keep absolute difference between tenorsRATIO
: Overwrite all tenors and keep relative difference between tenors
The code blocks below explore forward curve shift.
Overwrite only 04 Jan 2005 tenor to 600:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2005, 1, 4): 600.0},
change_type="PRICE",
overwrite_type="POINT"
)
sig.obj.get(fwd_curve_ticker).history()
Shift all tenor values by 95 upwards from 04 Jan 2005 onwards:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2005, 1, 4): 95.0},
change_type="DIFF",
overwrite_type="PARALLEL"
)
sig.obj.get(fwd_curve_ticker).history()
Overwrite all tenor values on 04 Jan 2005 to 04 Jan 2005 original value +5%:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2005, 1, 4): 0.05},
change_type="RETURN",
overwrite_type="FLAT"
)
sig.obj.get(fwd_curve_ticker).history()
Overwrite 04 Jan 2005 to 300 and adjust all other tenors on 04 Jan 2005 to keep the relative difference between tenors:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_curve_modifier(
instruments=[fwd_curve_ticker],
overwrites={dtm.date(2005, 1, 4): 300.0},
change_type="PRICE",
overwrite_type="RATIO"
)
sig.obj.get(fwd_curve_ticker).history()
Options: Added volatility curve shift for FX options#
FX options now support volatility curve shifts. As a result, you can now use the simulation adapter (SimAdapter
) to simulate shocks on FX options by changing the underlying spot value.
Code examples below—run each code block in a separate cell and reinitialize the environment each time.
Shift volatility curve to at-the-money (ATM) strike of 1.25:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): 1.25},
change_type="PRICE",
)
sig.obj.get(vol_curve_ticker).history()
Shift volatility curve horizontally by 0.1 to the right, so new_ATM_strike = old_ATM_strike + 0.1:
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): 0.1},
change_type="DIFF",
)
sig.obj.get(vol_curve_ticker).history()
Shift volatility curve horizontally by 1% of spot price to the left, so new_ATM_strike = old_ATM_strike - (1% * spot):
import datetime as dtm
import sigtech.framework as sig
from sigtech.framework.infra.data_adapter.simulations.simulation_adapter import SimAdapter
env = sig.init(repeat_mode="reinit")
vol_curve_ticker = "SPX INDEX VOLSURFACE"
fwd_curve_ticker = "SPX INDEX FORWARD RATE CURVE"
sim_adapter = SimAdapter()
sim_adapter.push_to_data_service()
sim_adapter.add_overwrite_vol_curve_modifier(
instruments=[vol_curve_ticker],
overwrites={dtm.date(2009, 3, 2): -0.01},
change_type="RETURN",
)
sig.obj.get(vol_curve_ticker).history()
v9.2#
New features#
Options: Added risk_scenario
function for single options and option strategies#
Simulate spot and implied volatility changes for both single options and option strategies. Shift spot prices over the entire duration of a single option or strategy, or a single day.
Code examples below—run each code block as a separate cell:
import datetime as dtm
import sigtech.framework as sig
env = sig.init()
group = sig.obj.get("USDJPY OTC OPTION GROUP")
Risk scenario for single option:
opt = group.get_option(
start_date=dtm.date(2023, 1, 2),
strike_type="Delta",
strike=0.5,
maturity=dtm.date(2023, 4, 3),
option_type="Call",
)
# shift spot by +5% and calculate change in greeks
opt.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=True)
# shift spot by +5% and calculate new greeks
opt.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=False)
# shift vol by +5 vol points and calculate change in greeks
opt.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=True)
# shift vol by +5 vol points and calculate new greeks
opt.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=False)
Risk scenario for option strategy:
bf = 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",
strike_type="SPOT",
strike_1="ATM",
strike_2="ATM+3%",
strike_3="ATM+5%",
option_type="Call",
direction="long",
)
# shift spot by +5% and calculate change in greeks
bf.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=True)
# shift spot by +5% and calculate new greeks
bf.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=False)
# shift vol by +5 vol points and calculate change in greeks
bf.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=True)
# shift vol by +5 vol points and calculate new greeks
bf.risk_scenario(
shift_type="spot",
shift_bps=500,
delta_from_base=False)
Options: Added risk matrix for single options#
Single options are now more sensitive to spot or implied volatility changes.
With the .risk_matrix
function, users can simulate price shocks by shifting either spot or volatility (shift_type
). This function calculates the change in Greeks and P&L (profit and loss explained), enabling users to observe the effect of spot or implied volatility changes on single options.
Code examples—run each code block in a separate cell:
import datetime as dtm
import sigtech.framework as sig
env = sig.init()
group = sig.obj.get("EURUSD OTC OPTION GROUP")
opt = group.get_option(
start_date=dtm.date(2023, 1, 2),
strike_type="Delta",
strike=0.5,
maturity=dtm.date(2023, 4, 3),
option_type="Call",
)
# shift spot from -5% to +5% and calculate change in greeks
opt.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="spot",
num_steps=5,
max_shift_bps=500,
delta_from_base=True)
# shift spot from -5% to +5% and calculate new greeks
opt.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="spot",
num_steps=5,
max_shift_bps=500,
delta_from_base=False)
# shift vol from -5 vol points to +5 vol points and calculate change in greeks
opt.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="vol",
num_steps=5,
max_shift_bps=500,
delta_from_base=True)
# shift spot from -5 vol points to +5 vol points and calculate new greeks
opt.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="vol",
num_steps=5,
max_shift_bps=500,
delta_from_base=False)
Options: Added risk matrix for option strategies#
Options strategies are now more sensitive to spot or implied volatility changes.
With the .risk_matrix
function, users can simulate price shocks by shifting either spot or volatility (shift_type
). This function calculates the change in Greeks and P&L (profit and loss explained), enabling users to observe the effect of spot or implied volatility changes on option strategies.
Code examples—run each code block in a separate cell:
import datetime as dtm
import sigtech.framework as sig
env = sig.init()
group = sig.obj.get("USDJPY OTC OPTION GROUP")
bf = 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",
strike_type="SPOT",
strike_1="ATM",
strike_2="ATM+3%",
strike_3="ATM+5%",
option_type="Call",
direction="long",
)
bf.history().tail()
# shift spot from -5% to +5% and calculate change in greeks
bf.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="spot",
num_steps=5,
max_shift_bps=500,
delta_from_base=True)
# shift spot from -5% to +5% and calculate new greeks
bf.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="spot",
num_steps=5,
max_shift_bps=500,
delta_from_base=False)
# shift vol from -5 vol points to +5 vol points and calculate change in greeks
bf.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="vol",
num_steps=5,
max_shift_bps=500,
delta_from_base=True)
# shift vol from -5 vol points to +5 vol points and calculate new greeks
bf.risk_matrix(
value_date=dtm.date(2023, 1, 2),
shift_type="vol",
num_steps=5,
max_shift_bps=500,
delta_from_base=False)
Futures: New parameter roll_on_calendar_days
added to rolling rules#
You can now choose to roll on calendar days instead of business days when using the RollingFutureStrategy
and RFPriceIndex
classes. For example, you could choose to roll on the 20th of every month instead of the 20th business day.
When the roll_on_calendar_days
parameter is set to True
, the monthly_roll_days
are taken as calendar days rather than business days.
Roll all contracts on the 20th calendar day of the month:
import datetime as dtm
import sigtech.framework as sig
env = sig.init()
rfs = sig.RollingFutureStrategy(
start_date=dtm.date(2018, 10, 23),
contract_code="NG",
contract_sector="COMDTY",
rolling_rule="f_0",
roll_on_calendar_days=True,
monthly_roll_days="20,20",
total_return=False,
)
rfs.rolling_table
Improvements#
Futures: Added calculation_start_date
method to RFPriceIndex
#
Previously, users could create a RollingFutureStrategy
without a start date, but not a RFPriceIndex
. By adding a calculation_start_date
method to the RFPriceIndex
class, users no longer need to provide a start_date
.
This ensures more consistent behavior between RollingFutureStrategy
and RFPriceIndex
.
Code example:
rfs = sig.RFPriceIndex(
currency="USD",
contract_code="ES",
contract_sector="INDEX",
rolling_rule="front",
front_offset="-3,-2"
)
rfs.history().tail()
Bug fixes#
Futures: Added holidays
property to all futures instruments#
The holidays
property, which contains a list of holiday calendars, has been added to futures classes. Previously it was missing, causing an error when calling .history
with a futures class.
Code example:
sig.obj.get("ESH24 INDEX").holidays
Futures: Added rounded_units
parameter to historic_positions
and evaluate_positions
methods#
Previously, the historic_positions
method would return an error, as it would call the evaluate_trades
method without setting the new rounded_units
parameter.
To solve this problem, the rounded_units
parameter has been added to the methods. Set rounded_units
to False
to obtain a more precise result.
Code example:
import datetime as dtm
import sigtech.framework as sig
rfs = sig.RollingFutureStrategy(
currency='USD',
start_date=dtm.date(2023, 1, 1),
end_date=dtm.date(2024, 1, 1),
contract_code='ES',
contract_sector='INDEX',
rolling_rule='front',
front_offset='-6,-5'
)
rfs.inspect.historic_positions("TOP_ORDER_PTS", rounded_units=False)
Discounting and forecasting curves: Added new methods to calculate any forward and zero rate#
New forward_rate
and zero_rate
methods for discounting and forecasting curves let users get forward rate and zero rates:
Code examples—run each code block in a separate cell:
import sigtech.framework as sig
from sigtech.framework.instruments.ir_otc import IRSwapMarket
import datetime as dtm
env = sig.init()
Get USD discounting curve:
discounting_curve = sig.obj.get(IRSwapMarket.discounting_curve_name("USD")
discounting_curve
Get forward rate:
discounting_curve.forward_rate(
effective_date=dtm.date(2024, 3, 13),
start_date=dtm.date(2024, 3, 22),
end_date=dtm.date(2024, 3, 28))
Get zero rate:
discounting_curve.zero_rate(
effective_date=dtm.date(2024, 3, 13),
end_date=dtm.date(2024, 3, 28))
v9.1#
New features#
All asset classes now support volatility plot_surface
method#
Added support for plot surface
for equity and commodity asset classes. Previously, this method was only available with FX. smile
and vol_term_structure
methods have also been added for FX, equity and commodities.
Each plot function should be run in a separate cell. Code example:
import sigtech.framework as sig
import datetime as dtm
sig.init()
# plot vol surface dor EURUSD
vs_fx = sig.obj.get("EURUSD VOLSURFACE")
vs_fx.plot_surface(d=vs_fx.history_dates_actual()[-1], z_name="Vol")
# plot EURUSD smile for 5Y tenor
vs_fx.smile(d=vs_fx.history_dates_actual()[-1], tenor="5Y").plot()
# plot EURUSD vol term structure for 25 delta call
vs_fx.vol_term_structure(d=vs_fx.history_dates_actual()[-1], delta="25C").plot()
# plot surface for SPX INDEX
vs_spx = sig.obj.get("SPX INDEX VOLSURFACE")
vs_spx.plot_surface(d=vs_spx.history_dates_actual()[-1])
# plot SPX INDEX smile for expiry 21 Jun 2024
vs_spx.smile(d=vs_spx.history_dates_actual()[-1], expiry=dtm.date(2024, 6, 21)).plot()
# plot SPX INDEX vol term structure for 100% moneyness
vs_spx.vol_term_structure(d=vs_spx.history_dates_actual()[-1], moneyness=100).plot()
Average backtest statistics available for multiple strategy runs#
Users can run multiple strategies at the same time and view the results all at once. The generated performance report shows average backtest statistics across all strategies, allowing for easy comparison.
Code example:
import sigtech.framework as sig
import datetime as dtm
from sigtech.framework.analytics.performance.performance_report import View
sig.init()
irs_1 = sig.InterestRateSwap(
currency="USD",
trade_date=dtm.date(2022, 4, 6),
start_date=dtm.date(2022, 4, 8),
tenor="5Y",
)
irs_2 = sig.InterestRateSwap(
currency="USD",
trade_date=dtm.date(2022, 4, 6),
start_date=dtm.date(2022, 4, 8),
tenor="1Y",
)
report = sig.PerformanceReport([irs_1, irs_2], views=[View.SUMMARY_MULTIPLE_CCY])
report.report()
Dependency updates#
Upgraded QuantLib to 1.34#
QuantLib
Python package has been upgraded to version 1.34. Changes include:
Prevented
Calendar::advance
from returning the business end of month (instead of the calendar end) whenendOfMonth
istrue
andconvention
isUnadjusted
.Added good Friday holiday for SOFR fixing.
Properly restricted Sao Paulo city holiday to years before 2022. Updated holidays for 2023 and 2024 in calendars for India, Thailand, Singapore and South Africa.
Fixed past payment dates and added support for OIS in
LinearTsrPricer
. Swaptions can now take an OIS as underlying. So far, onlyBlackSwaptionEngine
manages OIS explicitly; other engines might work and return approximated values.More methods in
MakeOIS
andMakeVanillaSwap
.More methods in the
BondFunctions
class now support either clean or dirty prices.Previously, the
basisPointValue
andyieldValueBasisPoint
methods inBondFunctions
didn’t always manage the settlement date correctly; this is now fixed.Fixed calculation of year fraction under Actual/365 Canadian convention in
FuturesRateHelper
.Fixed settlement date calculation in cross-currency basis-swap rate helpers in some cases.
For more information, refer to [QuantLib’s 1.34 release notes] (https://github.com/lballabio/QuantLib/releases/tag/v1.34).
Bug fixes#
Removed greek values for maturity date to prevent
NaN
or0.000
values being returned.Improved the error message returned when no dates are available in
strategy_dt_list
.inspect.display_sizing_calculation
method now works for all strategies, not just futures.Changed rolling adjustments for
RollingFutureStrategy
andRollingFutureFXHedgedStrategy
to bypass non-existing contracts.Fixed error loading data history for
KE COMDTY
by overriding the default rolling future parameters.Fixed strategy to catch error when first contract history is empty and
start_date
is not specified.Set default values
net_target_quantity
andforce_target_quantity
asTrue
inset_option_positions
, while an error is raised iftarget_quantity
cannot be achieved.Fixed bug with
CUSTOM_DATA_SOURCE_CONFIG
for multiple data providers.Created dynamically-generated new monthly schedules for rolling rules based on
front_table
.plot_surface
can now be displayed onmatplotlib
v3.8, successfully plotting a graph.Adjusted timeline widget visuals for better viewing in dark mode.
Removed requirement for
currency
field inSingleBondStrategy
.Fixed memory leak after using
object.clear_cache
. After clearing the object cache, users should still be able to access the object.Strike type checks in option groups are now case-insensitive.
v9.0#
Please see Guide to v9 for release notes and a full guide to version 9.0 of the SigTech framework.