Defaults#
Argument input management#
The rateslib.default
module is provided to give the user global control over a lot of
parameters that are set by default when the user provides no input to those arguments.
Since financial instrument specification usually contains a large number of parameters (for
example a cross-currency basis swap (XCS
) has around 50
possible arguments to initialise the swap with), argument management is a key part of the
design philosophy of rateslib.
The easiest way to construct conventional instruments is to use the spec
argument (detailed
below)
In [1]: from rateslib import XCS, dt
In [2]: xcs = XCS(
...: effective=dt(2022, 1, 1),
...: termination="10Y",
...: spec="gbpusd_xcs"
...: )
...:
In [3]: xcs.kwargs
Out[3]:
{'effective': datetime.datetime(2022, 1, 1, 0, 0),
'termination': '10Y',
'frequency': 'q',
'stub': 'shortfront',
'front_stub': <NoInput.blank: 0>,
'back_stub': <NoInput.blank: 0>,
'roll': <NoInput.blank: 0>,
'eom': False,
'modifier': 'mf',
'calendar': 'ldn,nyc',
'payment_lag': 2,
'notional': 1000000.0,
'currency': 'gbp',
'amortization': <NoInput.blank: 0>,
'convention': 'act365f',
'leg2_effective': datetime.datetime(2022, 1, 1, 0, 0),
'leg2_termination': '10Y',
'leg2_frequency': 'q',
'leg2_stub': 'shortfront',
'leg2_front_stub': <NoInput.blank: 0>,
'leg2_back_stub': <NoInput.blank: 0>,
'leg2_roll': <NoInput.blank: 0>,
'leg2_eom': False,
'leg2_modifier': 'mf',
'leg2_calendar': 'ldn,nyc',
'leg2_payment_lag': 2,
'leg2_notional': -1000000.0,
'leg2_currency': 'usd',
'leg2_amortization': <NoInput.blank: 0>,
'leg2_convention': 'act360',
'spread_compound_method': 'none_simple',
'fixing_method': 'rfr_payment_delay',
'leg2_spread_compound_method': 'none_simple',
'leg2_fixing_method': 'rfr_payment_delay',
'initial_exchange': True,
'final_exchange': True,
'leg2_initial_exchange': True,
'leg2_final_exchange': True,
'payment_lag_exchange': 0,
'leg2_payment_lag_exchange': 0,
'fixed': False,
'leg2_fixed': False,
'leg2_mtm': True,
'float_spread': <NoInput.blank: 0>,
'fixings': <NoInput.blank: 0>,
'method_param': <NoInput.blank: 0>,
'leg2_float_spread': <NoInput.blank: 0>,
'leg2_fixings': <NoInput.blank: 0>,
'leg2_method_param': <NoInput.blank: 0>,
'leg2_alt_currency': 'gbp',
'leg2_alt_notional': -1000000.0,
'leg2_fx_fixings': <NoInput.blank: 0>}
The NoInput argument#
Warning
When an argument is not provided this actually assumes a defined datatype in
rateslib called NoInput
. Never use None as an entry to
an argument, this will typically create downstream errors. It is better to omit the argument
entry entirely and let rateslib control the NoInput value.
There are 3 types of NoInput
that work behind the scenes:
NoInput.blank: this specifies the user has provided no input for this argument and if there is a default value that will be used instead. For example, not providing a
convention
will result in the value ofdefaults.convention
being used.NoInput.inherit: this specifies that the user has provided no input for this argument and its value will be inherited from the equivalent attribute on
leg1
. For example the valueleg2_payment_lag
has a value of NoInput.inherit meaning its value will be obtained from the value ofpayment_lag
whether that is taken by default or set by a user.NoInput.negate: this is similar to NoInput.inherit except it negates the value. This is useful for
notional
andamortization
when 2 legs commonly take opposite values.
In the below code snippet one can observe how these NoInputs are operating in the initialisation of a swap to infer what a user might expect when just inputting a small subset of parameters.
In [4]: from rateslib import IRS
In [5]: irs = IRS(
...: effective=dt(2000, 1, 1),
...: termination="1Y",
...: frequency="S",
...: payment_lag=4,
...: notional=50e6,
...: amortization=10e6
...: )
...:
In [6]: irs.leg1.schedule.frequency
Out[6]: 'S'
In [7]: irs.leg1.schedule.payment_lag
Out[7]: 4
In [8]: irs.leg1.notional
Out[8]: 50000000.0
In [9]: irs.leg1.amortization
Out[9]: 10000000.0
In [10]: irs.leg2.schedule.frequency # <- Inherited
Out[10]: 'S'
In [11]: irs.leg2.schedule.payment_lag # <- Inherited
Out[11]: 4
In [12]: irs.leg2.notional # <- Inherited with negate
Out[12]: -50000000.0
In [13]: irs.leg2.amortization # <- Inherited with negate
Out[13]: -10000000.0
Defaults#
The defaults
object is a global instance of the Defaults
class.
Its purpose is to provide necessary values when a user does not supply inputs. In the above
swap the user provided no convention
, modifier
or currency
. These have been set
by default.
In [14]: irs.leg1.schedule.modifier
Out[14]: 'MF'
In [15]: irs.leg1.convention
Out[15]: 'ACT360'
In [16]: irs.leg1.currency
Out[16]: 'usd'
The defaults values can be seen by calling its print()
method.
In [17]: from rateslib import defaults
In [18]: print(defaults.print())
Scheduling:
stub: SHORTFRONT
stub_length: SHORT
modifier: MF
eom: False
eval_mode: swaps_align
frequency_months: {'M': 1, 'B': 2, 'Q': 3, 'T': 4, 'S': 6, 'A': 12, 'Z': 100000000.0}
Instruments:
convention: ACT360
payment_lag: 2
payment_lag_exchange: 0
payment_lag_specific: {'IRS': 2, 'STIRFuture': 0, 'IIRS': 2, 'ZCS': 2, 'ZCIS': 0, 'FXSwap': 0, 'SBS': 2, 'Swap': 2, 'XCS': 2, 'FixedRateBond': 0, 'IndexFixedRateBond': 0, 'FloatRateNote': 0, 'Bill': 0, 'FRA': 0}
notional: 1000000.0
fixing_method: rfr_payment_delay
fixing_method_param: {'rfr_payment_delay': 0, 'rfr_observation_shift': 2, 'rfr_lockout': 2, 'rfr_lookback': 2, 'rfr_payment_delay_avg': 0, 'rfr_observation_shift_avg': 2, 'rfr_lockout_avg': 2, 'rfr_lookback_avg': 2, 'ibor': 2}
spread_compound_method: none_simple
base_currency: usd
Curves:
interpolation: {'Curve': 'log_linear', 'LineCurve': 'linear', 'IndexCurve': 'linear_index'}
endpoints: natural
multi_csa_steps: [2, 5, 10, 20, 30, 50, 77, 81, 86, 91, 96, 103, 110, 119, 128, 140, 153, 169, 188, 212, 242, 281, 332, 401, 498, 636, 835, 1104, 1407, 1646, 1766, 1808, 1821, 1824, 1825]
Solver:
algorithm: levenberg_marquardt
tag: v
curve_not_in_solver: ignore
Miscellaneous:
headers: {'type': 'Type', 'stub_type': 'Period', 'u_acc_start': 'Unadj Acc Start', 'u_acc_end': 'Unadj Acc End', 'a_acc_start': 'Acc Start', 'a_acc_end': 'Acc End', 'payment': 'Payment', 'convention': 'Convention', 'dcf': 'DCF', 'df': 'DF', 'notional': 'Notional', 'currency': 'Ccy', 'rate': 'Rate', 'spread': 'Spread', 'npv': 'NPV', 'cashflow': 'Cashflow', 'fx': 'FX Rate', 'npv_fx': 'NPV Ccy', 'real_cashflow': 'Real Cashflow', 'index_value': 'Index Val', 'index_ratio': 'Index Ratio', 'index_base': 'Index Base', 'collateral': 'Collateral'}
no_fx_fixings_for_xcs: warn
pool: 1
These values can also be set:
In [19]: defaults.convention = "ACT365F"
In [20]: defaults.base_currency = "gbp"
In [21]: irs = IRS(effective=dt(2022, 1, 1), termination="1Y", frequency="A")
In [22]: irs.leg1.convention # <- uses new default value
Out[22]: 'ACT365F'
In [23]: irs.leg1.currency # <- uses new default value
Out[23]: 'gbp'
In [24]: defaults.reset_defaults() # <- reverse the changes.
Market conventions and the spec
argument#
To provide maximal flexibility a number of market conventions have already been pre-added to
rateslib. For an Instrument that allows the spec
(specification) argument a host of
arguments will be pre-populated. The list of instrument specifications defined can
be seen by printing as below.
Note that some of these are aliases, for example “sofr” and “usd_irs” are the same, as are
“usd_gb” and “ust”.
In [25]: print(defaults.spec.keys())
dict_keys(['usd_irs', 'gbp_irs', 'eur_irs', 'eur_irs3', 'eur_irs6', 'eur_irs1', 'sek_irs', 'sek_irs3', 'nok_irs', 'nok_irs3', 'nok_irs6', 'chf_irs', 'eur_fra3', 'eur_fra6', 'sek_fra3', 'eur_sbs36', 'eurusd_xcs', 'gbpusd_xcs', 'eurgbp_xcs', 'eur_zcis', 'gbp_zcis', 'usd_zcis', 'gbp_zcs', 'sek_iirs', 'usd_gb', 'usd_gbb', 'gbp_gb', 'gbp_gbi', 'cad_gb', 'sek_gb', 'sek_gbb', 'usd_frn5', 'usd_stir', 'usd_stir1', 'eur_stir', 'eur_stir1', 'eur_stir3', 'gbp_stir', 'test', 'sofr', 'ust', 'ustb', 'ukt', 'ukti', 'gilt', 'cadgb', 'sgb', 'sgbb', 'sofr3mf', 'sofr1mf', 'sonia3mf', 'estr1mf', 'estr3mf', 'euribor3mf'])
The individual parameters of an instrument can then be seen, as below for an example USD SOFR IRS, with:
In [26]: defaults.spec["usd_irs"]
Out[26]:
{'frequency': 'a',
'stub': 'shortfront',
'eom': False,
'modifier': 'mf',
'calendar': 'nyc',
'payment_lag': 2,
'currency': 'usd',
'convention': 'act360',
'leg2_frequency': 'a',
'leg2_stub': 'shortfront',
'leg2_eom': False,
'leg2_modifier': 'mf',
'leg2_calendar': 'nyc',
'leg2_payment_lag': 2,
'leg2_currency': 'usd',
'leg2_convention': 'act360',
'leg2_spread_compound_method': 'none_simple',
'leg2_fixing_method': 'rfr_payment_delay'}
Warning
When using the spec
argument, arguments which might normally inherit might be defined
specifically, and will no longer inherit. If overwriting an instrument that has been directly
specified, ensure to overwrite both legs.
We can change the frequency on the XCS defined in the initial example. Since leg2_frequency
was explicitly defined by the spec
then it will no longer inherit.
In [27]: xcs = XCS(
....: effective=dt(2022, 1, 1),
....: termination="10Y",
....: frequency="S",
....: spec="gbpusd_xcs",
....: ) # `leg2_frequency` will NOT be inherited as "S", it will be "Q" as defined by the `spec`
....:
In [28]: xcs.kwargs
Out[28]:
{'effective': datetime.datetime(2022, 1, 1, 0, 0),
'termination': '10Y',
'frequency': 'S',
'stub': 'shortfront',
'front_stub': <NoInput.blank: 0>,
'back_stub': <NoInput.blank: 0>,
'roll': <NoInput.blank: 0>,
'eom': False,
'modifier': 'mf',
'calendar': 'ldn,nyc',
'payment_lag': 2,
'notional': 1000000.0,
'currency': 'gbp',
'amortization': <NoInput.blank: 0>,
'convention': 'act365f',
'leg2_effective': datetime.datetime(2022, 1, 1, 0, 0),
'leg2_termination': '10Y',
'leg2_frequency': 'q',
'leg2_stub': 'shortfront',
'leg2_front_stub': <NoInput.blank: 0>,
'leg2_back_stub': <NoInput.blank: 0>,
'leg2_roll': <NoInput.blank: 0>,
'leg2_eom': False,
'leg2_modifier': 'mf',
'leg2_calendar': 'ldn,nyc',
'leg2_payment_lag': 2,
'leg2_notional': -1000000.0,
'leg2_currency': 'usd',
'leg2_amortization': <NoInput.blank: 0>,
'leg2_convention': 'act360',
'spread_compound_method': 'none_simple',
'fixing_method': 'rfr_payment_delay',
'leg2_spread_compound_method': 'none_simple',
'leg2_fixing_method': 'rfr_payment_delay',
'initial_exchange': True,
'final_exchange': True,
'leg2_initial_exchange': True,
'leg2_final_exchange': True,
'payment_lag_exchange': 0,
'leg2_payment_lag_exchange': 0,
'fixed': False,
'leg2_fixed': False,
'leg2_mtm': True,
'float_spread': <NoInput.blank: 0>,
'fixings': <NoInput.blank: 0>,
'method_param': <NoInput.blank: 0>,
'leg2_float_spread': <NoInput.blank: 0>,
'leg2_fixings': <NoInput.blank: 0>,
'leg2_method_param': <NoInput.blank: 0>,
'leg2_alt_currency': 'gbp',
'leg2_alt_notional': -1000000.0,
'leg2_fx_fixings': <NoInput.blank: 0>}
Values that are shown here as NoInput are populated when the individual legs are instantiated and the values will then be set by default. For example we have that,
In [29]: xcs.leg1.schedule.roll
Out[29]: 1