Tutorial: FX carry strategy
This tutorial shows new SigTech users how to construct a systematic investment strategy, where the strategy involves a number of different FX forward contracts, and where the investment decision is based on the difference between relevant short term interest rates.
Access: to run the related Jupyter notebook, the appropriate data entitlements need to be in place for your organisation. To request access to SigTech's FX data, email
[email protected]
.When creating an investment strategy on the SigTech platform, the workflow follows these steps:
- 1.Set up the environment
- 2.Define the investment universe
- 3.Create the strategy
- 4.Construct the portfolio
- 5.Generate the performance report
Setting up your environment takes three steps:
- Import the relevant internal and external libraries
- Configure the environment parameters
- Initialise the environment
import sigtech.framework as sig
from sigtech.framework.infra.analytics.fx.fx_market import FXMarket
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.config.init();
In this step, you will define the currencies that will form the universe of the investment strategy.
Note: the currencies are traded against the US Dollar for simplicity, but the platform also allows for cross currency pairs to be traded.
ASSETS = ['AUD', 'CAD', 'CHF', 'EUR', 'GBP', 'JPY', 'NOK', 'NZD', 'SEK']
Define the relevant start date to be used when creating the strategy:
START_DATE = dtm.date(2010, 1, 4)
Get the currency pairs based on the previously defined constant
ASSETS
: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
}
Get the price time series for each currency pair below:
spot_rates = {
ccy: sig.obj.get(ticker).history()
for ccy, ticker in CCY_MAPPING.items()
}
This strategy is expressed using FX Forward contracts. When the investment universe contains forward contracts, it's important to handle the rolling of the contracts. As a given forward contract has a maturity date, it's crucial to systematically handle how the strategy trades in and out of forward contracts to maintain an exposure to the underlying asset.
The SigTech platform offers the
RollingFXForwardStrategy
class which allows easily handling of the rolling of forward contracts.In this tutorial, nine
RollingFXForwardStrategy
objects are created. The following function allows you to easily create these RollingFXForwardStrategy
objects by passing in a few parameters.The
RollingFXForwardStrategy
objects are instantiated using a few different parameters, such as forward_tenor
and long_currency
. Note: the
RollingFXForwardStrategy
objects assume a constant long exposure from start date to end date of the strategy.def create_rolling_fx_forwards(asset, start_date,
fwd_tenor='3M_IMM', base_ccy='USD'):
'''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
Using a dictionary comprehension, all of the previously defined currencies are passed into the following function, creating a
RollingFXForwardStrategy
object for each of the currencies against the US Dollar:Input
Output
fwd_universe = {
asset: create_rolling_fx_forwards(
asset=asset,
start_date=START_DATE,
) for asset in ASSETS
}
fwd_universe
{'AUD': 'AUD FWD STRATEGY',
'CAD': 'CAD FWD STRATEGY',
'CHF': 'CHF FWD STRATEGY',
'EUR': 'EUR FWD STRATEGY',
'GBP': 'GBP FWD STRATEGY',
'JPY': 'JPY FWD STRATEGY',
'NOK': 'NOK FWD STRATEGY',
'NZD': 'NZD FWD STRATEGY',
'SEK': 'SEK FWD STRATEGY'}
The following code block shows how each of the
RollingFXForwardStrategy
objects are performing over time:fwd_histories = pd.concat({
asset: sig.obj.get(fwd_universe[asset]).history()
for asset in ASSETS
}, axis=1)
fwd_histories.plot();

The strategy will take a long position in the currency pairs where the spot FX rate is trading at a discount in relation to the forward FX rate, and a short position in currency pairs that are trading at a premium in relation to the spot FX rate.
In the following code block the forward FX rates are being generated for the time period of the strategy:
def generate_fwd_rates(spot_dates, under, over, fx_market, forward_tenor='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 = 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()
}
The following code block generates a
-1
when the forward rate is below the spot rate, and a 1
when the forward rate is above the spot rate:signals_carry = pd.DataFrame(
{ccy: np.sign(fwd_rates[ccy] - spot_rates[ccy]) for ccy in ASSETS},
columns=ASSETS
)
signals_carry.tail()

To apply the strategy to the universe and combine all the assets into a portfolio, use the
SignalStrategy
class. Before you can use the
SignalStrategy
class, you need to convert the pandas DataFrame of signals into a signal object:signal_obj = sig.signal_library.from_ts(signals_carry)
You can now create a
SignalStrategy
object. There are numerous different parameters and alternatives that you can make use of, such as using different allocation functions between the assets in the strategy. 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'
)
Use the following code block to create a performance report that contains information on metrics, rolling performance charts and performance calendars.
There are a wide range of different performance views and reports available, depending on the specific use case.
sig.PerformanceReport(fx_carry_strat).report()



Last modified 1yr ago