FXRates#

class rateslib.fx.FXRates(fx_rates, settlement=NoInput.blank, base=NoInput.blank)#

Bases: object

Object to store and calculate FX rates for a consistent settlement date.

Parameters:
  • fx_rates (dict) – Dict whose keys are 6-character domestic-foreign currency pairs, and whose values are the relevant rates.

  • settlement (datetime, optional) – The settlement date for the FX rates.

  • base (str, optional) –

    The base currency (3-digit code). If not given defaults to either:

    • the base currency defined in defaults, if it is present in the list of currencies,

    • the first currency detected.

Notes

Note

When this class uses Dual numbers to represent sensitivities of values to certain FX rates the variable names are called “fx_domfor” where “dom” is a domestic currency and “for” is a foreign currency. See the examples contained in class methods for clarification.

Examples

An FX rates market of n currencies is completely defined by n-1 independent FX pairs.

Below we define an FX rates market in 4 currencies with 3 FX pairs,

In [1]: fxr = FXRates({"eurusd": 1.1, "gbpusd": 1.25, "usdjpy": 100})

In [2]: fxr.currencies
Out[2]: {'eur': 0, 'gbp': 1, 'usd': 2, 'jpy': 3}

In [3]: fxr.rate("gbpjpy")
Out[3]: <Dual: 125.000000, (fx_gbpusd, fx_eurusd, fx_usdjpy), [100.0, 0.0, 1.2]>

Ill defined FX markets will raise ValueError and are either overspecified,

In [4]: try:
   ...:     FXRates({"eurusd": 1.1, "gbpusd": 1.25, "usdjpy": 100, "gbpjpy": 125})
   ...: except ValueError as e:
   ...:     print(e)
   ...: 
`fx_rates` is overspecified: 4 currencies needs 3 FX pairs, not 4.

or are underspecified,

In [5]: try:
   ...:     FXRates({"eurusd": 1.1, "gbpjpy": 125})
   ...: except ValueError as e:
   ...:     print(e)
   ...: 
`fx_rates` is underspecified: 4 currencies needs 3 FX pairs, not 2.

or use redundant, co-dependent information,

In [6]: try:
   ...:     FXRates({"eurusd": 1.1, "usdeur": 0.90909, "gbpjpy": 125})
   ...: except ValueError as e:
   ...:     print(e)
   ...: 
FX rates cannot be solved because redundant information has been supplied.
Pairs and their reverse have been detected. Inspect 'eurusd,usdeur'
pairs#
Type:

list

settlement#
Type:

datetime

currencies#
Type:

dict

currencies_list#
Type:

list

q#
Type:

int

fx_rates#
Type:

dict

fx_vector#
Type:

ndarray

fx_array#
Type:

ndarray

Methods Summary

convert(value, domestic[, foreign, on_error])

Convert an amount of a domestic currency into a foreign currency.

convert_positions(array[, base])

Convert an array of currency cash positions into a single base currency.

copy()

from_json(fx_rates, **kwargs)

Load an FXRates object from a JSON string.

positions(value[, base])

Convert a base value with FX rate sensitivities into an array of cash positions.

rate(pair)

Return a specified FX rate for a given currency pair.

rates_table()

Return a DataFrame of all FX rates in the object.

restate(pairs[, keep_ad])

Create a new FXRates class using other (or fewer) currency pairs as majors.

to_json()

Convert FXRates object to a JSON string.

update([fx_rates])

Update all or some of the FX rates of the instance with new market data.

Methods Documentation

convert(value, domestic, foreign=NoInput.blank, on_error='ignore')#

Convert an amount of a domestic currency into a foreign currency.

Parameters:
  • value (float or Dual) – The amount of the domestic currency to convert.

  • domestic (str) – The domestic currency (3-digit code).

  • foreign (str, optional) – The foreign currency to convert to (3-digit code). Uses instance base if not given.

  • on_error (str in {"ignore", "warn", "raise"}) – The action taken if either domestic or foreign are not contained in the FX framework. “ignore” and “warn” will still return None.

Return type:

Dual or None

Examples

In [1]: fxr = FXRates({"usdnok": 8.0})

In [2]: fxr.convert(1000000, "nok", "usd")
Out[2]: <Dual: 125000.000000, (fx_usdnok), [-15625.0]>

In [3]: fxr.convert(1000000, "nok", "inr")  # <- returns None, "inr" not in fxr.
convert_positions(array, base=NoInput.blank)#

Convert an array of currency cash positions into a single base currency.

Parameters:
  • array (list, 1d ndarray of floats, or Series) – The cash positions to simultaneously convert in the base currency. Must be ordered by currency as defined in the attribute FXRates.currencies.

  • base (str, optional) – The currency to convert to (3-digit code). Uses instance base if not given.

Return type:

Dual

Examples

In [1]: fxr = FXRates({"usdnok": 8.0})

In [2]: fxr.currencies
Out[2]: {'usd': 0, 'nok': 1}

In [3]: fxr.convert_positions([0, 1000000], "usd")
Out[3]: <Dual: 125000.000000, (fx_usdnok), [-15625.0]>
copy()#
classmethod from_json(fx_rates, **kwargs)#

Load an FXRates object from a JSON string.

This is usually required if a saved or transmitted object is to be recovered from a database or API.

Parameters:

fx_rates (str) – The JSON string of the underlying FXRates object to be reconstructed.

Return type:

FXRates

Examples

In [1]: json = '{"fx_rates": {"eurusd": 1.05}, "settlement": null, "base": "eur"}'

In [2]: fxr = FXRates.from_json(json)

In [3]: fxr.rates_table()
Out[3]: 
     eur  usd
eur 1.00 1.05
usd 0.95 1.00
positions(value, base=NoInput.blank)#

Convert a base value with FX rate sensitivities into an array of cash positions.

Parameters:
  • value (float or Dual) – The amount expressed in base currency to convert to cash positions.

  • base (str, optional) – The base currency in which value is given (3-digit code). If not given assumes the base of the object.

Return type:

Series

Examples

In [1]: fxr = FXRates({"usdnok": 8.0})

In [2]: fxr.positions(Dual(125000, ["fx_usdnok"], [-15625]), "usd")
Out[2]: 
usd         0.00
nok   1000000.00
dtype: float64

In [3]: fxr.positions(100, base="nok")
Out[3]: 
usd     0.00
nok   100.00
dtype: float64
rate(pair)#

Return a specified FX rate for a given currency pair.

Parameters:

pair (str) – The FX pair in usual domestic:foreign convention (6 digit code).

Return type:

Dual

Examples

In [1]: fxr = FXRates({"usdeur": 2.0, "usdgbp": 2.5})

In [2]: fxr.rate("eurgbp")
Out[2]: <Dual: 1.250000, (fx_usdeur, fx_usdgbp), [-0.6, 0.5]>
rates_table()#

Return a DataFrame of all FX rates in the object.

Return type:

DataFrame

restate(pairs, keep_ad=False)#

Create a new FXRates class using other (or fewer) currency pairs as majors.

Parameters:
  • pairs (list of str) – The new currency pairs with which to define the FXRates class.

  • keep_ad (bool, optional) – Keep the original derivative exposures defined by Dual, instead of redefinition. It is advised against setting this to True, it is mainly used internally.

Return type:

FXRates

Notes

This will redefine the pairs to which delta risks are expressed in Dual outputs.

If pairs match the existing object and keep_ad is requested then the existing object is returned unchanged as new copy.

Examples

Re-expressing an FXRates class with new majors, to which Dual sensitivities are measured.

In [1]: fxr = FXRates({"eurgbp": 0.9, "gbpjpy": 125, "usdjpy": 100})

In [2]: fxr.convert(100, "gbp", "usd")
Out[2]: <Dual: 125.000000, (fx_gbpjpy, fx_eurgbp, fx_usdjpy), [1.0, 0.0, -1.2]>

In [3]: fxr2 = fxr.restate(["eurusd", "gbpusd", "usdjpy"])

In [4]: fxr2.convert(100, "gbp", "usd")
Out[4]: <Dual: 125.000000, (fx_gbpusd, fx_eurusd, fx_usdjpy), [100.0, 0.0, 0.0]>

Extracting an FXRates subset from a larger object.

In [5]: fxr = FXRates({"eurgbp": 0.9, "gbpjpy": 125, "usdjpy": 100, "audusd": 0.85})

In [6]: fxr2 = fxr.restate({"eurusd", "gbpusd"})

In [7]: fxr2.rates_table()
Out[7]: 
     eur  gbp  usd
eur 1.00 0.90 1.12
gbp 1.11 1.00 1.25
usd 0.89 0.80 1.00
to_json()#

Convert FXRates object to a JSON string.

This is usually a precursor to storing objects in a database, or transmitting via an API across platforms, e.g. webservers or to Excel, for example.

Return type:

str

Examples

In [1]: fxr = FXRates({"eurusd": 1.05}, base="EUR")

In [2]: fxr.to_json()
Out[2]: '{"fx_rates": {"eurusd": 1.05}, "settlement": null, "base": "eur"}'
update(fx_rates=NoInput.blank)#

Update all or some of the FX rates of the instance with new market data.

Parameters:

fx_rates (dict, optional) – Dict whose keys are 6-character domestic-foreign currency pairs and which are present in FXRates.pairs, and whose values are the relevant rates to update.

Return type:

None

Notes

Warning

Rateslib is an object-oriented library that uses complex associations. It is best practice to create objects and any associations and then use the update methods to push new market data to them. Recreating objects with new data will break object-oriented associations and possibly lead to undetected market data based pricing errors.

Suppose an FXRates class has been instantiated and resides in memory.

In [1]: fxr = FXRates({"eurusd": 1.05, "gbpusd": 1.25}, settlement=dt(2022, 1, 3), base="usd")

In [2]: id(fxr)
Out[2]: 140215481919568

This object may be linked to others, probably an FXForwards class. It can be updated with some new market data. This will preserve its memory id and association with other objects (however, any linked objects should also be updated to cascade new calculations).

In [3]: linked_obj = fxr

In [4]: fxr.update({"eurusd": 1.06})

In [5]: id(fxr)  # <- SAME as above
Out[5]: 140215481919568

In [6]: linked_obj.rate("eurusd")
Out[6]: <Dual: 1.060000, (fx_gbpusd, fx_eurusd), [0.0, 1.0]>

Do not do the following because overwriting a variable name will not eliminate the previous object from memory. Linked objects will still refer to the previous FXRates class still in memory.

In [7]: fxr = FXRates({"eurusd": 1.05}, settlement=dt(2022, 1, 3), base="usd")

In [8]: id(fxr)  # <- NEW memory id, linked objects still associated with old fxr in memory
Out[8]: 140215480015696

In [9]: linked_obj.rate("eurusd")  # will NOT return rate from the new `fxr` object
Out[9]: <Dual: 1.060000, (fx_gbpusd, fx_eurusd), [0.0, 1.0]>

Examples

In [10]: fxr = FXRates({"usdeur": 0.9, "eurnok": 8.5})

In [11]: fxr.rate("usdnok")
Out[11]: <Dual: 7.650000, (fx_eurnok, fx_usdeur), [0.9, 8.5]>

In [12]: fxr.update({"usdeur": 1.0})

In [13]: fxr.rate("usdnok")
Out[13]: <Dual: 8.500000, (fx_usdeur, fx_eurnok), [8.5, 1.0]>