Quant BuffetRelax, Not Over Thinking

Developed Markets Currency Carry Trade Using Forward Discount

Log in to collect

Academic paper

Countercyclical Currency Risk Premia

AuthorsHanno N. Lustig; Nikolai Roussanov; Adrien Verdelhan

Institute
  • National Bureau of Economic Research
  • ?National Bureau of Economic Research (NBER)
  • ?Stanford Graduate School of Business
  • University of Pennsylvania
  • ?University of Pennsylvania - The Wharton School
  • Massachusetts Institute of Technology
  • ?Massachusetts Institute of Technology (MIT) - Sloan School of Management

Strategy in a nutshell

The investment universe consists of currencies from developed countries (the Euro area, Australia, Canada, Denmark, Japan, New Zealand, Norway, Sweden, Switzerland, and the United Kingdom). The average forward discount (AFD) is calculated for this basket of currencies (each currency has an equal weight). The average 3-month rate could be used instead of the AFD in the calculation. The AFD is then compared to the 3-month US Treasury rate. The investor goes long on the US dollar and goes short on the basket of currencies if the 3-month US Treasury rate is higher than the AFD. The investor goes short on the US dollar and long on the basket of currencies if the 3-month US Treasury rate is lower than the AFD. The portfolio is rebalanced monthly.

Economic rationale

Academic research shows that the dollar carries trade captures the US-specific compensation for bearing the US as well as global risk, while the global carry trade captures the compensation for global risk exposure, which is common to all countries. The average forward discount of the dollar against a basket of developed country currencies is a strong predictor of excess returns. US investors expect to be compensated more for bearing that risk during recessions when US interest rates are low. This risk premium could be called the dollar risk premium. By implementing the dollar carry trade, he pockets this dollar risk premium when the US risk price is high.

Backtest performance

Annualised return5.6%
Volatility8.53%
Beta0.057
Sharpe ratio-0.37
Sortino ratio-0.443
Maximum drawdown31.7%
Win rate52%

Full Python code

import data_tools
import numpy as np
from AlgoLib import *
from typing import Dict

class DollarCarryTrade(XXX):

def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)

self.leverage:int = 2

# Source: https://fred.stlouisfed.org/series/IR3TIB01AUM156N
self.symbols:Dict[str, str] = {
    "CME_AD1" : "IR3TIB01AUM156N",   # Australian Dollar Futures, Continuous Contract #1
    "CME_BP1" : "LIOR3MUKM",         # British Pound Futures, Continuous Contract #1
    "CME_CD1" : "IR3TIB01CAM156N",   # Canadian Dollar Futures, Continuous Contract #1
    "CME_EC1" : "IR3TIB01EZM156N",   # Euro FX Futures, Continuous Contract #1
    "CME_JY1" : "IR3TIB01JPM156N",   # Japanese Yen Futures, Continuous Contract #1
    "CME_MP1" : "IR3TIB01MXM156N",   # Mexican Peso Futures, Continuous Contract #1
    "CME_NE1" : "IR3TIB01NZM156N",   # New Zealand Dollar Futures, Continuous Contract #1
    "CME_SF1" : "IR3TIB01CHM156N"    # Swiss Franc Futures, Continuous Contract #1
}
                        
for symbol in self.symbols:
    data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily)
    data.SetFeeModel(data_tools.CustomFeeModel())
    data.SetLeverage(self.leverage)

    # Interbank rate data.
    cash_rate_symbol = self.symbols[symbol]
    self.AddData(data_tools.InterestRate3M, cash_rate_symbol, Resolution.Daily)

self.treasury_rate:Symbol = self.AddData(data_tools.InterestRate3M, 'IR3TIB01USM156N', Resolution.Daily).Symbol
    
def OnData(self, data:Slice) -> None:
ir_last_update_date:Dict[str, datetime.date] = data_tools.InterestRate3M.get_last_update_date()
qp_futures_last_update_date:Dict[str, datetime.date] = data_tools.QuantpediaFutures.get_last_update_date()

fd:Dict[str, float] = {}
for future_symbol, cash_rate_symbol in self.symbols.items():
    if self.Securities[cash_rate_symbol].GetLastData() and ir_last_update_date[cash_rate_symbol] > self.Time.date():
        if cash_rate_symbol in data and data[cash_rate_symbol]:
            if qp_futures_last_update_date[future_symbol] > self.Time.date():
                cash_rate:float = data[cash_rate_symbol].Value
                
                # Update cash rate only once a month.
                fd[future_symbol] = cash_rate

if len(fd) == 0:
    if self.Securities[self.treasury_rate].GetLastData() and ir_last_update_date[self.treasury_rate.Value] <= self.Time.date():
        self.Liquidate()
    return

afd:float = np.mean([x[1] for x in fd.items()])

treasuries_3m_rate:float = self.Securities[self.treasury_rate].Price

count:int = len(self.symbols)
if treasuries_3m_rate > afd:
    # Long on the US dollar and goes short on the basket of currencies.
    for symbol in self.symbols:
        if symbol in data and data[symbol]:
            self.SetHoldings(symbol, -1 / count)
else:
    # Short on the US dollar and long on the basket of currencies.
    for symbol in self.symbols:
        if symbol in data and data[symbol]:
            self.SetHoldings(symbol, 1 / count)