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 of defaults.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 value leg2_payment_lag has a value of NoInput.inherit meaning its value will be obtained from the value of payment_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 and amortization 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