Portfolio LabKnowledgeSign inCreate account

Carry backtest: methodology for FX and bond carry

Advanced14 min read · updated 24 October 2026 · 5 sources

The carry backtest tests two strategies on monthly data, from the 1970s onwards depending on the currency and maturity: FX carry, i.e. buying high-yielding currencies and selling low-yielding ones, and bond carry along the yield curve. This methodology describes what the code of the Carry page calculates: data, forward rates, rules, costs, metrics and limitations. The idea and the research are covered in the article Carry trade.

Data: spot rates and interest rates

For each currency, the calculation needs two monthly series. The spot rate S is the last daily rate of the month in the base currency per unit of the currency. If that rate is more than 10 days before the month-end, the month is dropped, as is the current month. Before 1999, the euro is the Deutsche Mark; for the lira, the złoty, the forint, the Czech koruna, the rupiah and the shekel, the rates only begin in the 2000s. The interest rate i is a monthly average of short-term interest rates in % p.a.: first the 3-month interbank rate, where that is missing the overnight or short-term rate, and for the yen, in between the two, the rate on 3-month certificates of deposit. For the euro, German interest rates are used. The average for month t serves as an approximation for the rate at month-end t. All days of the average lie before t.

  • G10: US dollar, euro, yen, pound, Swiss franc, Australian and New Zealand dollar, Canadian dollar, Norwegian krone and Swedish krona.
  • G10 and emerging markets: eleven additional currencies (Mexican peso, real, rand, lira, Indian rupee, złoty, forint, Czech koruna, won, rupiah and shekel).
  • Not included: Singapore dollar (no suitable interest rate series), renminbi (managed exchange rate, capital controls) and rouble (no tradable rates since 2022). Individual currencies can be excluded, but the base cannot.

Forward rate and excess return per currency

Trading takes place via FX forwards to the next month-end. The code derives the forward rate F from covered interest parity, with interest accruing by calendar days: act/360, or act/365 for the pound, the Australian, New Zealand and Canadian dollars, the rand, the Indian rupee, the złoty, the won and the shekel.

F = S × (1 + i_b × Δt_b) / (1 + i_k × Δt_k); x_k = (1 + i_k × Δt_k) × S_k(t+1) / S_k(t) / (1 + i_b × Δt_b) − 1
S, F
spot and forward rate in the base currency per unit of currency k
i_k, i_b
interest rate of currency k and of the base at month-end t
Δt
calendar days to the next month-end / 360 or 365
x_k
excess return of a forward purchase of k in the following month over the money market of the base

The code splits x_k into the interest part d_k = (1 + i_k × Δt_k) / (1 + i_b × Δt_b) − 1, which is known when the forward is entered (forward discount), and the exchange rate part x_k − d_k = (1 + d_k) × (S_k(t+1) / S_k(t) − 1).

The rule: ranking by rate differential

At each month-end, the code ranks all available currencies by their rate differential i_k − i_b to the base. A currency is available if its exchange rate and interest rate exist at the month-end and an exchange rate exists at the next month-end. The base takes part in the ranking with a differential of 0, as in some carry indices. There are two types:

  • Long/Short (default): buy the n highest-yielding currencies and sell the n lowest-yielding ones, with each side totalling 100% (n = 3, permitted 1 to 5). If there are fewer than 2n currencies, each side takes half. If the base lands on one side, its share stays in the money market, and that side is then smaller.
  • Long only against the base: buy up to n currencies with the highest positive rate differential to the base. If there are fewer, the vacant slots stay in the money market with equal and rank weights; with weights by rate differential, the currencies bought share the full 100%.

Within a side, the weights are equal, by rank (n, n − 1, …, 1, normalised) or by rate differential: for long/short by the distance to the median of the differentials of all available currencies, for “long only” by the distance to the base. The portfolio is reweighted at each month-end. An example with hypothetical G10 interest rates, a US dollar base at 3.0% and n = 3: the Canadian dollar (2.75%), the Norwegian krone (2.5%) and the Swedish krona (2.0%) lie in the middle and are not traded; the median of the ten differentials is −0.375 percentage points.

CurrencyRateDifferentialequalby rankby rate differential
New Zealand dollar5.5%+2.533.3%50.0%46.9%
Australian dollar4.5%+1.533.3%33.3%30.6%
Pound4.0%+1.033.3%16.7%22.4%
Euro1.5%−1.5−33.3%−16.7%−19.5%
Swiss franc0.5%−2.5−33.3%−33.3%−36.8%
Yen0.1%−2.9−33.3%−50.0%−43.7%
Rate advantage of the positions3.97% p.a.4.45% p.a.4.34% p.a.

The rate advantage is the weighted rate differential Σ w_k × (i_k − i_b); the page shows it for the positions of the following month. With the euro as base, the euro itself is among the three lowest-yielding currencies: only the yen and the Swiss franc are then short, with 33.3% each, 66.7% in total.

Leverage, volatility target and crash filter

The code multiplies the weights w by a factor h. Without targeting, h is the leverage (default 1, permitted 0.1 to 5). With a volatility target (1 to 40% p.a., 8% suggested when switched on; see target volatility), the following applies:

h(t) = min(target / σ̂(t); leverage limit); σ̂(t) = standard deviation of the last 36 monthly returns of the unmanaged overlay up to t × √12
unmanaged overlay
Σ w_k × x_k with the weights of the rule, without leverage, filter and costs
leverage limit
the leverage you set; with the default of 1, targeting can only reduce the risk
warm-up
σ̂ needs at least 12 monthly returns; before that, h = min(1; leverage limit)

σ̂(t) uses only returns up to month-end t, and h(t) applies to the month after, so there is no look-ahead to later data. With a target of 8% and a leverage limit of 2, h = 0.8 at σ̂ = 10%, h = 1.6 at 5%, and at 3% the limit applies with h = 2.

The crash filter sets the following month flat (all weights 0, the money stays in the money market) if a stress measure is above its threshold at month-end. You can choose between the VIX (default 30, permitted 10 to 90; from 1990, before that its predecessor VXO from 1986) and FX volatility: the average across the G10 currencies of the annualised standard deviation of their daily log exchange rate changes against the US dollar over the past month (default 12%, permitted 2 to 50%; at least 10 daily rates per currency and 3 currencies). Before a series begins, the page does not filter and reports how many months are affected. The idea draws on Brunnermeier et al. (2008), who link carry losses to falling risk appetite and funding liquidity, and on Menkhoff et al. (2012):

“high interest rate currencies are negatively related to innovations in global FX volatility”
Menkhoff et al. (2012)

Costs and total return

R(t+1) = money market of the base + Σ_k W_k(t) × x_k(t+1) − costs; W = h × w (0 when filtered); costs = cost rate × Σ_k |W_k(t) − W_k(t−1)|
money market of the base
i_b × Δt_b: the capital sits in the money market, and the forwards come on top (overlay)
cost rate
per unit of notional traded, default 3 basis points (permitted 0 to 100)
costs
are incurred at the time of the decision and reduce the following month's return; the initial entry counts, while rolling the forwards is assumed to be free

The page breaks down each monthly return into money market, rate differential (Σ W × d), exchange rate change (Σ W × (x − d)) and costs, and shows the totals over time and per calendar year.

Bond carry: coupon and roll-down

For bonds, the code uses constant-maturity yields at month-end: US Treasuries (tenors of 3 and 6 months and 1, 2, 3, 5, 7, 10, 20 and 30 years) and German federal securities (yields with an annual coupon for 1 to 10, 15, 20, 25 and 30 years). As in Koijen et al. (2018), carry is the return if prices stay unchanged, which here means an unchanged yield curve. Each maturity n is modelled as a par bond whose coupon equals the yield y, with f coupons per year (USA 2, Germany 1):

D = (1 − v^N) / y, v = 1 / (1 + y / f), N = f × n; expected return = y_n × Δt + D × (y_n − y_{n−Δt})
D
modified duration of the par bond (D = n at y = 0)
y_n × Δt
carry in the narrow sense: the month's coupon, Δt = days / 365.25
D × (y_n − y_{n−Δt})
roll-down: price gain when, with an unchanged curve, the bond slides to the yield of the maturity that is Δt shorter; y_{n−Δt} is interpolated linearly between the tenors and held flat below the shortest one

The realised monthly return is R ≈ y_n(t) × Δt − D × Δy + ½ × C × Δy² with Δy = y_{n−Δt}(t+1) − y_n(t) and the convexity C of the par bond. If the curve stays the same, Δy is exactly the roll-down; if it shifts, the change in yields is added.

MaturityYieldDurationRoll-down p.a.Expected p.a.Per unit of duration p.a.
1 year2.50%0.980.20%2.70%0.30%
2 years3.00%1.930.96%3.96%0.81%
5 years3.50%4.550.68%4.18%0.39%
10 years4.00%8.180.82%4.82%0.30%
20 years4.40%13.210.53%4.93%0.19%
30 years4.50%16.370.16%4.66%0.14%

Bonds: choice of maturities

  • Highest carry (default): the k maturities (default 1, permitted 1 to 3) with the highest score, each weighted L / k (L = leverage). The score is either the expected return in absolute terms (default) or the excess return per unit of duration, i.e. (expected return − money market return of the past month, so without look-ahead) / D. On the example curve, 20 years wins in absolute terms with 4.93% p.a., and 2 years wins per unit of duration with 0.81% p.a.
  • Duration-neutral long/short between two maturities (default 2 and 10 years): both sides with 5 years of duration, i.e. a weight of L × 5 / D. The maturity with the higher excess return per unit of duration is long, the other is short. This gives a steepener if the short maturity is long, otherwise a flattener (duration-neutral). In the example: long 2 years with 5 / 1.93 = 259.4%, short 10 years with 5 / 8.18 = −61.2%; expected return 4.98% p.a., of which 2.58 percentage points are above the money market.

A maturity can only be selected if its yield is available at the month-end and at the next month-end. The total return is R = money market + Σ_n W_n × (R_n − money market) − costs, with 2 basis points (permitted 0 to 100) per unit of notional traded Σ |W(t) − W(t−1)|. With long/short or leverage above 1, the position is financed via the money market, at the money market rate. The money market is represented by 3-month Treasury bills (USD) or overnight money (EUR: €STR, before that EONIA, before that overnight money in Frankfurt).

Comparisons and metrics

All series start with 10,000 in the base currency, and income is reinvested. For FX carry, the comparisons are an equally weighted basket of all available foreign currencies against the base (leverage 1, same costs) and the money market of the base. With the dollar as base, the basket is the dollar factor of Lustig et al. (2011). For bond carry, they are fixed 2 and 10 years, all selectable maturities equally weighted, and the money market. The metrics are calculated as in the backtest, with the money market of the base as the risk-free rate. In addition:

  • Positions for the following month: interest rate, differential, rank and weight per currency, or yield, duration, carry, roll-down and weight per maturity.
  • Relationship: correlation and beta of the excess returns with US equities, world equities and the basket (FX), or with 10 years and the equally weighted mix (bonds), from 24 common months, plus the strategy's average month in the comparison's weakest 10% of months.
  • Weakest months: the 10 worst months with the exchange rate part or yield change and the positions; also turnover and costs p.a., average long and short totals, the share of flat months and average leverage or average duration.

Defaults and permitted ranges

SettingDefaultPermitted
Base currency / universeUSD / G10USD or EUR / G10 or G10 and emerging markets
Type / currencies per sideLong/Short / 3Long/Short or long only / 1 to 5
Weightingequalequal, by rank, by rate differential
Leverage or leverage limit10.1 to 5
Volatility targetoff1 to 40% p.a.
Costs FX / bonds3 / 2 basis points0 to 100 basis points
Crash filteroffVIX 10 to 90 (30) or FX volatility 2 to 50% (12%)
Startas early as possible (FX March 1973 at the earliest)from 1973 to two years ago
Bonds: market / type / measureUS / highest carry / absoluteUS or DE / long/short / per unit of duration
Bonds: maturities1 maturity; 2 against 10 years1 to 3; two maturities, the shorter one first

A backtest needs at least 25 months. For FX carry, only months count in which the base has an interest rate and at least 2n (long/short) or n + 1 currencies including the base are available. For bond carry, 2 and 10 years and at least four maturities must be available.

Data gaps and notes

  • Carried-forward interest rates: if an interest rate series ends no more than 2 months before the latest month of all series (usually a publication lag), its last value continues to apply. If it ends earlier, the next interest rate series takes over. The page names the currencies affected.
  • Later currencies: a currency only enters the selection once both its exchange rate and its interest rate are available; the page shows from when.
  • Gaps in the base interest rate: in that case, the page only calculates the most recent section without gaps.
  • Rate jumps: if an exchange rate changes by more than 40% (log) in a month, the page flags this as a data check (devaluation or data error).
  • Bonds: if a maturity has no yield, it cannot be selected in that month; for US Treasuries, 20 years is missing from 1987 to 1993, and 30 years is disregarded from 18 February 2002 to 9 February 2006. German federal bonds have no tenor below 1 year (US Treasuries before September 1981): the roll-down of the one-year bond is then 0. If a fixed comparison maturity has no yield, that month is held in the money market.

Limitations

  • Approximated forward rates: they are derived from monthly averages of short-term interest rates, not from traded forward rates. Deviations from covered interest parity, as described by Du et al. (2018), and bid-ask spreads on forwards are not captured.
  • Monthly data: the page only sees crashes within a month at the month-end; stop-loss rules cannot be modelled.
  • No further costs: no financing and collateral costs beyond the money market, no taxes, no trading restrictions in emerging markets.
  • Par bonds instead of real bonds: constant-maturity yields are smoothed curve points; real bonds have different coupons, liquidity and financing costs.
  • Today's universe: the list of currencies is fixed as of today. Currencies that were abolished or became untradable are missing from the past.

Frequently asked questions

Where do the forward rates come from?

From covered interest parity: forward rate = spot rate × (1 + base interest rate × Δt) / (1 + currency interest rate × Δt), using monthly averages of short-term interest rates. The page does not use traded forward rates.

Why does the base currency take part in the ranking?

Because it is a currency like any other. If the dollar itself is among the lowest-yielding currencies, a short position in dollars against dollars would be meaningless: its share stays in the money market, and the short side is smaller than 100%.

Does volatility targeting look into the future?

No. The factor for the next month uses only monthly returns up to the current month-end, at most the last 36. In the first 12 months, a leverage of 1 or the lower leverage limit applies.

What does duration-neutral mean?

The long and short sides each have 5 years of duration. A parallel shift in the yield curve affects both sides roughly equally and cancels out; what remains is the bet on the steepness of the curve, plus carry and roll-down.

Why does the sum of the contributions differ from the annual return?

The contributions from money market, rate differential, exchange rate change and costs are simply added up month by month, whereas the annual return is compounded. With large monthly returns, the difference becomes visible.

Literature

  1. Brunnermeier, Markus K.; Nagel, Stefan; Pedersen, Lasse H. (2008): Carry Trades and Currency Crashes. NBER Macroeconomics Annual 23 (1), pp. 313–348. doi:10.1086/593088
  2. Du, Wenxin; Tepper, Alexander; Verdelhan, Adrien (2018): Deviations from Covered Interest Rate Parity. The Journal of Finance 73 (3), pp. 915–957. doi:10.1111/jofi.12620
  3. Koijen, Ralph S. J.; Moskowitz, Tobias J.; Pedersen, Lasse Heje; Vrugt, Evert B. (2018): Carry. Journal of Financial Economics 127 (2), pp. 197–225. doi:10.1016/j.jfineco.2017.11.002
  4. Lustig, Hanno; Roussanov, Nikolai; Verdelhan, Adrien (2011): Common Risk Factors in Currency Markets. Review of Financial Studies 24 (11), pp. 3731–3777. doi:10.1093/rfs/hhr068
  5. Menkhoff, Lukas; Sarno, Lucio; Schmeling, Maik; Schrimpf, Andreas (2012): Carry Trades and Global Foreign Exchange Volatility. The Journal of Finance 67 (2), pp. 681–718. doi:10.1111/j.1540-6261.2012.01728.x

Full bibliography

This page describes how Portfolio Lab calculates; past results are not a forecast. All terms in the glossary.