Currency portfolios
Cross-Sectional Currency Momentum
Original implementation of a cross-sectional momentum family: rank currencies by prior returns and hold winners against losers, with conservative execution rules.
- Category
- Currency portfolios
- Timeframes
- D1 (monthly portfolio rebalance)
- Pairs
- AUD, CAD, CHF, EUR, GBP, JPY, NOK, NZD and SEK versus USD
- Test status
- EA v1.01 function tested; full-cost performance unverified

How the rule works
Cross-sectional momentum compares currencies with one another; it can hold a relative winner even if that currency has fallen against USD. USD/JPY must be inverted before ranking yen returns, or the sign is wrong. Equal long/short notional removes the initial dollar imbalance, but currency correlations, financing and discrete lot sizes still affect realized risk. Sudden reversals of recent winners are a characteristic loss scenario.
Setup
- Use a fixed universe of AUD, CAD, CHF, EUR, GBP, JPY, NOK, NZD and SEK versus USD. Normalize every spot quote to Q = USD per one unit of foreign currency; invert USD/foreign quotes before computing returns. Synchronize closing observations at 17:00 America/New_York using a historical broker-offset schedule. Require 300 common, valid daily observations and at least six eligible currencies.
- At the last completed New York trading day of each month, freeze the ranking. Define t as that completed close. Ties are resolved alphabetically by ISO currency code. Set n=floor(number eligible/3), and select the highest n and lowest n currencies. Submit the rebalance at 08:00 Europe/London on the next common trading day, using then-executable prices.
- Rank by R60=Q[t]/Q[t−60]−1, including only information from completed t. The 60-interval lookback needs 61 closes. This spot-price variant is not the total/excess-return construction of every published momentum study.
Indicators
- 60-trading-day normalized spot return Q[t]/Q[t−60]−1
- 60 daily log returns for per-currency volatility and the sample covariance matrix
- Historical broker financing for implementation costs; not part of the spot rank
Long entry
- At next liquid-session open, buy each winner/USD or sell USD/winner as needed to create long winner exposure.
Short entry
- At the same time, sell each loser/USD or buy USD/loser to create short loser exposure.
Stop loss
- There is no guaranteed per-leg price SL. At each completed New York daily close, value portfolio NAV after costs. If NAV/NAV_at_month_start−1 <= −0.06, request liquidation of every tradable leg at the next executable quote and remain in cash until the next monthly decision. This is a 6% month-to-date loss trigger, not a maximum drawdown guarantee; gaps and untradeable quotes can make losses larger.
Exit
- At the next monthly rebalance, close legs no longer selected and adjust surviving notionals to the newly computed weights. Roll forward contracts on their stated settlement/maturity schedule using actual executable quotes. The signal does not justify allowing an expiring contract to settle accidentally.
- If a required quote is missing, initiate no new portfolio. Existing exposure remains a recorded risk until an executable quote becomes available; request exit then. Never fill a suspended market at its last stale price or pretend it could be force-closed after a fixed number of days.
Risk and position size
- Compute individual volatilities from 60 daily log returns. Within each selected tail, normalize inverse-volatility weights to +0.5 for the long side and −0.5 for the short side. If any volatility is zero or inputs are missing, do not initiate the portfolio. Let w be this signed weight vector and Σ the 60-day sample covariance matrix. Annualized portfolio volatility = sqrt(252 × wᵀΣw).
- Multiply every weight by k=min(0.08/portfolio volatility, 1.5/sum(abs(w)), 0.2/max(abs(w))). Thus volatility is a target ceiling of 8% rather than a guaranteed risk level; gross exposure is at most 150% of NAV and each currency at most 20%. Convert notionals to executable lot/contract sizes by rounding down and recheck caps.
Costs and execution
- Include bid/ask on every entry, reduction and roll, commissions, financing or forward points, and account-currency valuation. Do not splice spot returns, forward excess returns and broker swaps into one unexplained series. Forward quotes, calendars and historical funding must be independently available; an MT5 spot screenshot does not supply them.
When the method can fail
- Exclude pegged, capital-controlled, or persistently non-tradable currencies. This requires synchronized, survivorship-aware data, not retail chart snapshots.
Worked example
- Hypothetical six-currency R60 ranks are +5%, +3%, +1%, −1%, −2% and −4%. Long the two strongest and short the two weakest. With identical volatilities, base weights are +0.25,+0.25,−0.25,−0.25; if base portfolio volatility is 10%, k=min(0.08/0.10,1.50/1,0.20/0.25)=0.8. Final gross is 80% of NAV. These invented returns explain the rule and are not a backtest.
Monthly family research and remaining test gap
The exact portfolio specification above remains incompletely tested. Public Internet data now supports the separate monthly family analysis below. A positive research result is not a pass for the strategy on this page.
Source: Adrien Verdelhan’s public MIT workbook, country-level monthly exchange-rate changes and interest-rate differences. Research window: 1984-03-30–2020-04-30; 434 calendar months including cash periods. The universe uses the nine named G10 currencies where observations are available, with at least six eligible currencies.
| Assumed cost | Months | Annualized net | Monthly profit factor | Max drawdown | Later-half annualized |
|---|---|---|---|---|---|
| 5 bp × turnover | 434 | -0.12% | 0.99 | 23.72% | -1.04% |
| 10 bp × turnover | 434 | -0.56% | 0.90 | 29.77% | -1.51% |
| 20 bp × turnover | 434 | -1.42% | 0.75 | 45.82% | -2.45% |
The reproducible monthly variant uses three-month momentum/volatility, lagged monthly interest differences for carry, top and bottom thirds, inverse-volatility weights capped at 20% per leg, and cash for rejected legs. Carry plus trend retains carry-selected legs only when their three-month trend agrees. Costs apply to absolute weight turnover, including closing to cash and final liquidation. Signals never use next-month prices or their availability.
Missing from this dataset: daily synchronized spot and forward levels, maturity and executable bid/ask, London 08:00 fills, NY 17:00 decision prices, daily volatility controls and the stated monthly loss-trigger exits. These cannot be reconstructed reliably from monthly returns. Historical interest differences are a funding proxy; they are not an executable forward quote.
MIT source and research datasets · Download full monthly results, units and data audit · Download reproduction code and source manifest
Execution and research protocol
- A spot chart illustrates one currency only. It cannot show cross-sectional ranks, contemporaneous forwards, portfolio weights or actual trading costs. Obtain synchronized historical inputs for every constituent before testing this rule.
- Freeze signals using information available at the decision timestamp. Convert all exchange rates to the stated quote convention before calculating returns and covariance. Record missing observations, executable bid/ask, forward maturity, interest, rolls and each cash allocation.
- Validate the full portfolio out of sample, including transaction costs and historical funding. The monthly loss threshold is an exit trigger, not a guaranteed maximum loss: quotes can gap or become unavailable. This rule has no claimed verified portfolio performance.
Adapt and test your version
- Treat these inputs as a reproducible starting specification. Choose a currency pair, session and holding period that match the time you can monitor the market, then record any changes to indicator periods, thresholds, stop distance or exits as a new version.
- Change one hypothesis at a time. Reserve a later period and additional pairs for evaluation before looking at their results. Include your account’s actual trading and financing costs, compare small parameter changes, and forward-test on demo. A selected profitable window does not validate the strategy or its modified version.
Reproduce the chart in MT5
- Display a D1 spot chart for one portfolio currency with month boundaries marked. This is price context only: the ranking, financing and covariance calculations require a separate synchronized multi-currency dataset. The chart is not evidence that a portfolio entry passed those tests.
Sources
- Currency Momentum Strategies — Academic currency-momentum family evidence and limits to arbitrage.
- Drivers of carry and currency momentum — Difference between momentum and carry, transaction costs and downside risk.
EA28 v1.01: spot execution, download and native test
Function tested; profitability after costs is not established. This MT5 Expert Advisor implements the spot-momentum variant below. It does not trade or roll forward contracts. The general article, its monthly academic-family analysis and this executable variant have different execution assumptions; their results must be kept separate.
Download EA28 v1.01 for MT5 (EX5, source, presets and rules) · Download test status and evidence hashes (JSON) · Read the full execution contract and every input (Markdown)
Signal, entry and size
On synchronized completed D1 history, normalize prices to USD per foreign currency, inverting USD-base pairs. Require at least six eligible currencies and 300 common daily observations. Rank the 60-interval spot return, using 61 closes, and select the highest and lowest thirds; ties use currency-code order. Long the relative winners and short the relative losers, translating direction correctly for inverted pairs.
Use 60 daily log returns for sample volatility and covariance. Start each selected tail with inverse-volatility weights totalling +0.5 and −0.5, then scale all weights to satisfy the 8% annualized volatility target, 150% gross-exposure cap and 20% per-currency cap. These are model targets, not guaranteed realized risk. Convert USD notionals using contract sizes and round lots down. Native margin checks limit the initial plan to 90% of equity and the remaining entries to 90% of available free margin.
After the monthly decision, the EA closes all of its previous positions before opening the new basket. Entries use executable ask for buys and bid for sells during London 08:00–16:00 on the first common trading day; a fill exactly at 08:00 is not promised. An initial quote, minimum-lot or margin veto waits within that window. A failure after staged entry begins requests liquidation; a missed deadline also takes the cash path.
Exits, stop loss and operational limits
No per-position SL or TP is placed. The daily loss trigger compares executable-side New York close NAV, including booked swap, against equity saved immediately after the monthly basket finishes opening. A decline of 6% or more requests liquidation. It is not a guaranteed 6% loss cap: gaps, missing quotes and delayed execution can cause larger losses.
This check requires a host tick and enough synchronized common history; missing daily data can delay it. The EA requires exclusive ownership of a dedicated USD account. Foreign positions or pending orders suspend its tick processing before its risk and liquidation logic. Do not mix it with another EA or manual positions. Rejected or partial staged entries, invalid NAV marks and storage failures also select cash/liquidation when processing is available. Actual terminal crashes and interrupted state writes are not yet independently validated.
What the exact production test showed
The downloadable EX5 compiled with zero errors and warnings and ran unchanged in MT5 Strategy Tester on genuine bid/ask ticks. The interval was 1 April–1 June 2024 exclusive in broker time, with a D1 host, USD10,000 starting balance and 1:100 leverage. Seven majors were available: EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD, NZDUSD and USDCAD. NOK and SEK were configured but unavailable. Approved decision dates and documented data exclusions were respected; earlier warmup can contain disclosed gaps.
- Eight entries reconciled to four ordinary monthly-rebalance closes and four forced tester-end closes. Forced end-of-window closes are not natural strategy exits.
- Price result: +USD62.15. Booked native swap: +USD1.87, with historical funding accuracy unverified. Native commission: USD0. Final balance: USD10,064.02.
- No added commission or slippage model was used in that direct-binary case. Its positive result is therefore a bounded functionality observation, not a profitable-strategy qualification.
- The separate February and February–March research pilots returned −USD28.37 and −USD14.49 after their declared USD3.50 per lot per side fee overlay and unverified swap. These overlapping runs cannot be combined with each other or the production run.
- A separate stale-checkpoint recovery control closed the same four existing positions without additional entries. It was an in-process recovery test, not an actual terminal crash or a performance test.
The production report and native log reconcile orders, fills, positions and cash. This case does not independently export every internal ranking/weight input, per-request return code or magic number. Broader multi-period performance, realistic historical financing and cost sensitivity remain to be established before any profitability claim.
Reproduce the tested variant
Install the folder from the ZIP in the terminal data directory and load a supplied tester preset. Use a USD tester account, D1 host, real ticks for every constituent and the required New York-close broker clock: UTC+2 winter and UTC+3 under the US daylight-saving schedule. PortfolioDedicatedAccount=true is required even in Strategy Tester; PortfolioEnableDemoTrading=false remains the preset default. Real accounts are rejected by the source guard.
The standard-symbol preset needs your own verified broker mapping and history. The .TFQ1 preset matches our custom test symbols; downloading the EA does not import history into MT5. Keep all nine ordered mapping slots, including unavailable NOK/SEK slots; at least six currencies must have synchronized eligible history. EA28 does not require the forward CSV used by the separate carry EAs. Every input, default and limitation is documented in the linked execution contract.
