After looking at the Crypto ETF I decided to investigate slow, low-maintenance commodities, to see if a trend-following strategy could generate meaningful risk-adjusted returns when executed via UK quarterly spread bets. Quarterly bets are interesting structurally: no overnight financing drag (unlike daily-funded bets or CFDs), shorting is frictionless, and gains are CGT-free in the UK. The question was whether those structural advantages were enough to offset the wider spreads.

The answer, from the four pre-registered experiments I ran across progressively larger universes, is no. The trend effect plausibly exists at roughly the magnitude the academic literature claims and not accessible at a retail cost structure. This post is the write-up of how that conclusion was reached, and why I think the process of reaching it was ultimately more useful than the conclusion itself. It should be noted that this was preliminary tests and structural changes to methodology could offer different results.

The setup

The strategy is time-series momentum with a 12-month lookback: if a market is above where it was a year ago, go long; below, go short. Weekly rebalance, inverse-volatility sizing to a 10% portfolio vol target. No optimisation, no signal blending, no parameter fitting. The parameters were frozen as v0.1 before any results were run and never changed across four experiments.

The engine is a modular Python backtester with separate signal, sizing, and cost components. Costs are modelled as the quoted bid-ask spread paid on every entry and exit, sourced from IG Markets' observed median spreads per market. The backtester tracks gross and net equity curves separately so the cost drag is always visible.

All decision criteria were pre-registered in docs/PROJECT.md before results were run. This is a key element because the thresholds, the stopping rules, and the closure conditions were written down before I saw any results, therefore everything that follows is the application of those rules.

EXP-002: the original basket

Ten commodity markets: Gold, Silver, Copper, WTI, Brent, Natural Gas, Wheat, Corn, Coffee, Sugar. Yahoo Finance continuous futures, 21.5 years of history (2005-2026). Pre-registered bar: net Sharpe ≥ 0.3.

Result: net Sharpe 0.18 which was below the bar. Cost drag was 1.11% per year, which doesn't sound like much until you realise the gross CAGR was only about 2.5%.

The result came with a question mark: the 2022 calendar year was only modestly positive, when headline trend-following indices had their best year in a decade. Was the data wrong? That suspicion was reasonable to test, so rather than stopping immediately I conducted EXP-003.

EXP-003: is the data the problem?

EXP-003 was a head-to-head comparison: the same engine, markets, and cost assumptions, run on both Yahoo futures data and IG's own price history over the 2020-2023 overlap window. If the two sources disagreed materially then Yahoo was incorrect and EXP-002 was void.

Unsurprisingly, they agreed. Yearly net returns were within 0.3 percentage points across both sources: Sharpe was 0.15 (IG) versus 0.21 (Yahoo). The data was accurate and therefore the strategy itself, was marginal.

The low daily-return correlations (0.87-0.94) looked alarming at first but were explained by day-boundary offsets: IG's undated candles close at a different hour to US futures settlement, so a one-day timing shift decorrelates daily returns while leaving yearly sums nearly identical. WTI's correlation of 0.50 was April 2020: the Yahoo continuous contract printed negative prices while IG handled that episode differently, and pct_change through near-zero and negative prices shreds correlation statistics.

Section 6 criteria was applied: if below Sharpe 0.3 then stop. There would be no post-hoc parameter rescue because anything fitted to pass after the fact was curve-fitting by construction.

A data-layer bug was identifed during EXP-003 that's worth highlighting for the methodology; IG candle timestamps include Sunday sessions, and the cross-market join inflated the index to 2,494 rows over a 4-year window (reported as "years: 9.9"). This corrupted vol estimates and meant the 12-month lookback was actually only about five calendar months. This was discovered with a the sanity check: "years: 9.9" on data that could only span four. The fix normalised indices to calendar date, deduped, and filtered to weekdays only.

EXP-004: does breadth fix it?

The hypothesis was that adding more commodity markets would improve diversification (the √N argument) and lift the net Sharpe. The universe grew to 22 markets: the original 10 plus Platinum, Palladium, Gasoline, Heating Oil, the soy complex, Cotton, Cocoa, Live Cattle, Lean Hogs, and Feeder Cattle. The pre-registered bar was raised to 0.40 (higher than EXP-002's 0.3, to account for the fact that this was a second attempt on the same thesis).

Result: net Sharpe 0.04. The breadth hypothesis was cleanly falsified. Backed-out gross Sharpe was approximately 0.35, essentially identical to EXP-002's 0.34. The twelve added markets contributed approximately zero gross improvement; the √N diversification benefit was fully offset by weaker individual trend performance in the additions.

Costs then sank the net: drag more than doubled, from 1.11% to 2.48% per year. The structural cause was the inverse-volatility sizing: it allocates the same risk to Palladium and Feeder Cattle at 50 basis points as to Gold at 6 basis points, so a quarter of the book churns through the most expensive markets. A cost-aware risk budget would fix this, but that's a design change; under the pre-registered rules, it would be a parameter rescue and was not permitted.

EXP-005: what about other asset classes?

The final experiment tested whether the problem was commodities rather than trend-following itself. The universe grew to 37 markets: the 22 commodities plus equity index futures (S&P 500, Nasdaq 100, Dow, Russell 2000, Nikkei 225), US treasury futures (2y, 5y, 10y, 30y), and FX futures (EUR, GBP, JPY, AUD, CAD, CHF). Pre-registered bars: net Sharpe ≥ 0.50 full-sample AND ≥ 0.00 post-2015. A pre-registered closure clause: fail either criterion and the trend-following thesis closes entirely, with no EXP-006 permitted in any asset class.

Results: net Sharpe 0.13 full-sample, −0.01 post-2015. Both criteria failed and so the closure clause triggered.

What the numbers actually say

The most useful finding emerged from backing out the costs across all three main experiments:

ExperimentMarketsNet SharpeCost drag (%/yr)Gross SharpeBar
EXP-00210 commodities0.181.11~0.340.30
EXP-00422 commodities0.042.48~0.350.40
EXP-00537 multi-asset0.132.73~0.430.50

Gross Sharpe improved with breadth: 0.34 → 0.35 → 0.43. The best gross (0.43) sits inside the professional CTA range of 0.4-0.5 reported by managers like SG Trend. The trend effect behaves roughly as the literature says it should. But net Sharpe went 0.18 → 0.04 → 0.13, because every extra market brought turnover priced at retail spreads. The pros aren't necessarily running a smarter strategy; they simply pay a tenth of the friction.

One prediction was explicitly falsified and logged during the project; before running EXP-005, I predicted that cost drag would fall as the universe grew, because financial markets (equities, bonds, FX) have tighter spreads than commodities. Cost drag rose from 2.48% to 2.73% per year. The prediction was wrong because total turnover increased and commodities still dominated the risk budget. Noting when your own predictions fail is part of the discipline; it's easy to log the wins and forget the misses.

Rising bars

The decision bars rose with each experiment: 0.30 → 0.40 → 0.50 and this was intentional. Each successive universe attempt is a form of multiple testing: if you run enough experiments, one will pass a fixed bar by luck. Raising the bar at each attempt is a crude but effective correction. It also reflects a genuine increase in prior scepticism: if the thesis failed on 10 markets, you should need stronger evidence from 22, not weaker.

The bars were written down before I saw the results, and they were applied as written even when the results were disappointing, which is the point of pre-registration. The temptation after EXP-002 was to try a faster lookback, or blend signals, or tweak the vol target. All of those are parameter rescue: fitting to pass after the fact. The rules exist to prevent exactly that, and they worked because they were written before there was anything to rescue.

The takeaway

The project's headline finding is structural, not strategic: retail spread-bet cost drag (~2.7% per year at the widest universe) consumes essentially all of the gross trend-following edge. The effect is real and is there trading is not accessible at a retail cost structure. This is consistent with what practitioners actually profit from in quarterly spread bets: structural advantages (tax treatment, financing cost avoidance) rather than predictive alpha.

Three things I'd do differently. First, raise the decision bar from the start rather than beginning at 0.3 and escalating. A single pre-registered bar of 0.5 with a cost-drag decomposition would have been cleaner than four experiments with rising thresholds. Second, build the cost-drag decomposition into the engine from day one rather than backing it out after the fact; the gross/net split is the most diagnostic metric in the whole project and it was a mid-project addition. Third, run the data quality audit before any modelling. The IG timestamp bug and the zero-range early-history problem in the volatility project both taught the same lesson: clean data first, double check the data, then model second.