FX Carry Strategy
Contents
FX Carry Strategy#
Understand this code: Read our step-by-step explanation of this notebook: guided walkthrough.
Restricted data: You will only have access to the data used in this notebook if your organisation has specifically purchased it. To check your current data access, view Data. If you would like to access more data, please contact sales@sigtech.com.
Changes will not be saved: Edits made to SigTech’s example notebooks like this will only persist for the duration of your session. When you restart the research environment, this notebook will have been restored to its original state, and any changes you have made will have been lost. To make permanent changes, copy and paste the content to a new notebook in one of your workspaces.
Environment#
[ ]:
import sigtech.framework as sig
import datetime as dtm
import pandas as pd
import numpy as np
import seaborn as sns
sns.set(rc = {'figure.figsize': (18, 6)})
env = sig.init(env_date=dtm.date(2024, 2, 22), log_level = 'ERROR');
Define the investment universe#
[ ]:
ASSETS = ['AUD', 'CAD', 'CHF', 'EUR', 'GBP', 'JPY', 'NOK', 'NZD', 'SEK']
[ ]:
START_DATE = dtm.date(2010, 1, 4)
[ ]:
fx_cross=env.fx_cross
def ccy_mapping(ccy):
if fx_cross.is_flipped('USD', ccy):
return f'USD{ccy} CURNCY'
else:
return f'{ccy}USD CURNCY'
[ ]:
CCY_MAPPING = {
ccy: ccy_mapping(ccy) for ccy in ASSETS
}
[ ]:
spot_rates = {
ccy: sig.obj.get(ticker).history()
for ccy, ticker in CCY_MAPPING.items()
}
[ ]:
def create_rolling_fx_forwards(
asset: str,
start_date: dtm.date,
fwd_tenor: str = "3M_IMM",
base_ccy: str = "USD",
) -> str:
'''Creates RollingFXForwardStrategy objects and returns the name of the object.'''
rfxfs = sig.RollingFXForwardStrategy(
# Long currency
long_currency = asset,
# Short currency
currency = base_ccy,
# Tenor of forward
forward_tenor = fwd_tenor,
# Start date of strategy
start_date = start_date,
# Name of strategy
ticker = f'{asset} FWD'
)
return rfxfs.name
[ ]:
fwd_universe = {
asset: create_rolling_fx_forwards(
asset=asset,
start_date=START_DATE,
) for asset in ASSETS
}
fwd_universe
[ ]:
fwd_histories = pd.concat({asset: sig.obj.get(fwd_universe[asset]).history() for asset in ASSETS}, axis=1)
fwd_histories.plot();
Create the strategy#
[ ]:
def generate_fwd_rates(spot_dates, under: str, over: str, fx_market, forward_tenor: str = '3M'):
maturities = [fx_market.fx_forward_date(over, under, date, forward_tenor) for date in spot_dates]
return fx_market.calculate_forward_rate_batch(over, under, spot_dates, maturities)
[ ]:
fx_market = sig.FXMarket.instance()
fwd_rates = {
ccy: pd.Series(generate_fwd_rates(
spot_rates[ccy].index,
over=CCY_MAPPING[ccy][:3],
under=CCY_MAPPING[ccy][3:6],
fx_market=fx_market
), index=spot_rates[ccy].index)
for ccy, ticker in CCY_MAPPING.items()
}
[ ]:
signals_carry = pd.DataFrame(
{ccy: np.sign(fwd_rates[ccy]-spot_rates[ccy]) for ccy in ASSETS},
columns=ASSETS
)
signals_carry.tail()
[ ]:
signal_obj = sig.signal_library.from_ts(signals_carry)
Construct the portfolio#
[ ]:
fx_carry_strat = sig.SignalStrategy(
# Start date of strategy
start_date=START_DATE,
# Base currency for strategy
currency='USD',
# Reference to signal object
signal_name=signal_obj.name,
# Rebalance frequency of the strategy
rebalance_frequency='3M',
# Allocation function used between constituents
# in strategy
allocation_function=sig.signal_library.allocation.equally_weighted,
# Mapping constituent in signals to the relevant
# RollingFutureStrategy objects
instrument_mapping=fwd_universe,
# Name of strategy
ticker=f'FX Carry'
)
Generate the performance report#
[ ]:
sig.PerformanceReport(fx_carry_strat.history()).report()