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.
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
orforeign
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:
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:
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 thebase
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:
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:
Notes
This will redefine the pairs to which delta risks are expressed in
Dual
outputs.If
pairs
match the existing object andkeep_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]>