Working with Fixings#

The rateslib defaults object lazy loads fixings from CSV files. These files are stored in the rateslib package files under the directory ‘data’. Due to static packaging and licencing issues rateslib cannot be distributed with accurate and upto date RFR or IBOR fixings.

As an example, a small selection of SOFR fixings which are used in some examples within, rateslib documentation are shown below along with the source directory.

In [1]: defaults.fixings.directory
Out[1]: '/home/docs/checkouts/readthedocs.org/user_builds/rateslib/checkouts/latest/rateslib/data'

In [2]: defaults.fixings["usd_rfr"]  # an available alias is 'fixings["sofr"]'
Out[2]: 
reference_date
2018-04-02   1.80
2018-04-03   1.83
2018-04-04   1.74
2018-04-05   1.75
2018-04-06   1.75
             ... 
2023-07-26   5.06
2023-07-27   5.31
2023-07-28   5.30
2023-07-31   5.31
2023-08-01   5.31
Name: rate, Length: 1333, dtype: float64

It is possible to overwrite these CSV files (provided the template structure is maintained) or to set a new directory and place new CSV files there. Due to lazy loading, this should be done before calling any fixing Series, and all files should be stored in the same folder with the required naming convention.

First we obtain (or create) new fixing for the SEK 3M STIBOR index, and save it to CSV file in the current working directory.

In [3]: df = DataFrame(
   ...:     data=[1.21, 2.75],
   ...:     index=Index(["02-01-2023", "03-01-2023"], name="reference_date"),
   ...:     columns=["rate"]
   ...: )
   ...: 

In [4]: print(df)
                rate
reference_date      
02-01-2023      1.21
03-01-2023      2.75

In [5]: df.to_csv("sek_ibor_3m.csv")  # Save the DataFrame and create a CSV file

Next we set the directory of the defaults.fixings object and load the fixings.

In [6]: import os

In [7]: defaults.fixings.directory = os.getcwd()

In [8]: defaults.fixings["sek_ibor_3m"]
Out[8]: 
reference_date
2023-01-02   1.21
2023-01-03   2.75
Name: rate, dtype: float64

These fixings are entirely user defined in their construction and naming convention. If an attempt is made to call a fixing series that doesn’t exist the user is met with the instructive error.

In [9]: try:
   ...:     defaults.fixings["arbitrary_index"]
   ...: except ValueError as e:
   ...:     print(e)
   ...: 
Fixing data for the index 'arbitrary_index' has been attempted, but there is no file:
'arbitrary_index.csv' located in the search directory: '/home/docs/checkouts/readthedocs.org/user_builds/rateslib/checkouts/latest/docs/source'
Create a CSV file in the directory with the above name and the exact template structure:
###################
reference_date,rate
26-08-2023,5.6152
27-08-2023,5.6335
##################
For further info see 'Working with Fixings' in the documentation cookbook.

Constructing Instruments with fixings#

These fixings can then be passed to Instrument constructors. For STIBOR the index lag is 2 business days so the fixing for the below IRS effective as of 4th January is taken as the value published on the reference date 2nd January.

In [10]: irs = IRS(
   ....:     effective=dt(2023, 1, 4),
   ....:     termination="6M",
   ....:     spec="sek_irs3",
   ....:     leg2_fixings=defaults.fixings["sek_ibor_3m"],
   ....:     fixed_rate=2.00,
   ....: )
   ....: 

In [11]: curve = Curve({dt(2023, 1, 3): 1.0, dt(2024, 1, 3): 0.97})

In [12]: irs.cashflows(curve)
Out[12]: 
               Type   Period  Ccy  Acc Start    Acc End    Payment Convention  DCF    Notional   DF Collateral  Rate  Spread  Cashflow      NPV  FX Rate  NPV Ccy
leg1 0  FixedPeriod     Stub  SEK 2023-01-04 2023-07-04 2023-07-04     30e360 0.50  1000000.00 0.98       None  2.00     NaN -10000.00 -9849.27     1.00 -9849.27
leg2 0  FloatPeriod  Regular  SEK 2023-01-04 2023-04-04 2023-04-04     act360 0.25 -1000000.00 0.99       None  1.21    0.00   3025.00  3002.12     1.00  3002.12
     1  FloatPeriod  Regular  SEK 2023-04-04 2023-07-04 2023-07-04     act360 0.25 -1000000.00 0.98       None  3.06    0.00   7728.72  7612.22     1.00  7612.22

In [13]: irs.leg2.fixings_table(curve)
Out[13]: 
             notional   dcf  rates
obs_dates                         
2023-01-02 1000000.00  None   1.21
2023-04-02 1000000.00  None   3.06

Using fx fixings in multi-currency Instruments#

XCS typically require MTM payments based on FX fixings. However, the first FX fixing is usually agreed at trade time as the prevailing FX rate at the instant of execution. This poses a challenge to the initial construction of these Instruments.

Rateslib handles this by allowing a 2-tuple as an input to fx_fixings. The first entry is assigned to the first period and the latter entry is the FX fixings Series.

Consider the example below.

In [14]: df = DataFrame(
   ....:     data=[1.19, 1.21, 1.24],
   ....:     index=Index(["17-01-2023", "17-04-2023", "17-07-2023"], name="reference_date"),
   ....:     columns=["rate"]
   ....: )
   ....: 

In [15]: print(df)
                rate
reference_date      
17-01-2023      1.19
17-04-2023      1.21
17-07-2023      1.24

In [16]: df.to_csv("gbpusd.csv")  # Save the DataFrame and create a CSV file
In [17]: xcs = XCS(
   ....:     effective=dt(2023, 1, 15),
   ....:     termination="9M",
   ....:     spec="gbpusd_xcs",
   ....:     fx_fixings=(1.20, defaults.fixings["gbpusd"]),
   ....: )
   ....: 

In [18]: xcs.cashflows(curves=curve, fx=1.25)  # arguments here used as a placeholder to display values.
Out[18]: 
               Type    Period  Ccy  Acc Start    Acc End    Payment Convention  DCF    Notional   DF  Rate  Spread    Cashflow         NPV  FX Rate     NPV Ccy Collateral
leg1 0     Cashflow  Exchange  GBP        NaT        NaT 2023-01-17       None  NaN -1000000.00 1.00   NaN     NaN  1000000.00   998832.38     1.25  1248540.48       None
     1  FloatPeriod   Regular  GBP 2023-01-17 2023-04-17 2023-04-19    act365f 0.25  1000000.00 0.99  3.12    6.44    -7697.66    -7629.87     1.25    -9537.34       None
     2  FloatPeriod   Regular  GBP 2023-04-17 2023-07-17 2023-07-19    act365f 0.25  1000000.00 0.98  3.12    6.44    -7783.51    -7656.60     1.25    -9570.75       None
     3  FloatPeriod   Regular  GBP 2023-07-17 2023-10-16 2023-10-18    act365f 0.25  1000000.00 0.98  3.12    6.44    -7783.51    -7598.67     1.25    -9498.34       None
     4     Cashflow  Exchange  GBP        NaT        NaT 2023-10-16       None  NaN  1000000.00 0.98   NaN     NaN -1000000.00  -976415.89     1.25 -1220519.86       None
leg2 0     Cashflow  Exchange  USD        NaT        NaT 2023-01-17       None  NaN  1200000.00 1.00  1.20     NaN -1200000.00 -1198598.86     1.25 -1498248.58       None
     1  FloatPeriod   Regular  USD 2023-01-17 2023-04-17 2023-04-19     act360 0.25 -1200000.00 0.99  3.06    0.00     9172.16     9091.39     1.25    11364.23       None
     2     Cashflow       Mtm  USD        NaT        NaT 2023-04-17       None  NaN    10000.00 0.99  1.21     NaN   -10000.00    -9913.59     1.25   -12391.98       None
     3  FloatPeriod   Regular  USD 2023-04-17 2023-07-17 2023-07-19     act360 0.25 -1210000.00 0.98  3.06    0.00     9351.75     9199.27     1.25    11499.08       None
     4     Cashflow       Mtm  USD        NaT        NaT 2023-07-17       None  NaN    30000.00 0.98  1.24     NaN   -30000.00   -29515.77     1.25   -36894.71       None
     5  FloatPeriod   Regular  USD 2023-07-17 2023-10-16 2023-10-18     act360 0.25 -1240000.00 0.98  3.06    0.00     9583.61     9356.03     1.25    11695.04       None
     6     Cashflow  Exchange  USD        NaT        NaT 2023-10-16       None  NaN -1240000.00 0.98  1.24     NaN  1240000.00  1210755.70     1.25  1513444.63       None

Note how the rate for initial exchange is 1.20 (and not 1.19) and the MTM payments are 1.21 and 1.24, as expected.