<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Delphic Alpha: Pairs Trading]]></title><description><![CDATA[Statistical arbitrage on crypto perpetuals: pair selection, cointegration, and live trading.]]></description><link>https://delphicalpha.substack.com/s/pairs-trading</link><image><url>https://substackcdn.com/image/fetch/$s_!7ktl!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbee261f-1963-4880-a3c7-78377d10694f_608x608.png</url><title>Delphic Alpha: Pairs Trading</title><link>https://delphicalpha.substack.com/s/pairs-trading</link></image><generator>Substack</generator><lastBuildDate>Sat, 23 May 2026 23:09:23 GMT</lastBuildDate><atom:link href="https://delphicalpha.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Oracle]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[delphicalpha@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[delphicalpha@substack.com]]></itunes:email><itunes:name><![CDATA[oracle]]></itunes:name></itunes:owner><itunes:author><![CDATA[oracle]]></itunes:author><googleplay:owner><![CDATA[delphicalpha@substack.com]]></googleplay:owner><googleplay:email><![CDATA[delphicalpha@substack.com]]></googleplay:email><googleplay:author><![CDATA[oracle]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Pairs Trading Crypto Perpetuals: Backtest Results]]></title><description><![CDATA[Part 2 of 3: We swept 72 configurations across 859 crypto pairs and validated with walk-forward testing. 19 pairs survive quality filtering (Sharpe 3.1); OOS validation confirms +347% return at Sharpe 2.6.]]></description><link>https://delphicalpha.substack.com/p/pairs-trading-part-2-backtest-results</link><guid isPermaLink="false">https://delphicalpha.substack.com/p/pairs-trading-part-2-backtest-results</guid><dc:creator><![CDATA[oracle]]></dc:creator><pubDate>Wed, 29 Apr 2026 19:09:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MASG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most pairs trading backtests cheat. They pick pairs using data from the entire test period, then report returns on that same data. The pairs that look good in hindsight get selected, and the result is a backtest that can never be replicated live.</p><p>This post does it differently. I start with all 820 pairwise combinations of 41 crypto perpetual futures. No pairs are pre-selected. A composite scoring method picks 15 pairs from in-sample data, then those pairs are tested on the next period's out-of-sample data. Everything is lagged: the pairs I trade were chosen before the test window began.</p><p><strong>Bottom line</strong>: +70% portfolio return at 8 bps (34% annualized, Sharpe 1.7), +89% at 4 bps (42% annualized, Sharpe 1.9). 30 coins traded, 67% of selected pairs profitable. No look-ahead.</p><div><hr></div><h2>Walk-Forward Design</h2><p>I use a <strong>lagged</strong> walk-forward. 6 months in-sample, 3 months out-of-sample, 3 month step. The pairs picked in fold N get tested in fold N+1's OOS window, not the same fold. Fold 0 only provides the first selection, giving 5 OOS windows.</p><p>Starting universe: <strong>820 pairs from 41 coins</strong> (all Binance/Hyperliquid overlap, excluding dead tickers). No pre-filtering. The composite scoring does all the selection from IS data alone. Quote coin cap of 2 pairs max. Top 15 selected per fold. Entry z=2.0, exit z=0.2, 7-day OLS hedge, 8 bps round-trip costs.</p><p>All 5 OOS folds are included in portfolio metrics. No folds excluded.</p><div><hr></div><h2>Picking Pairs: What Works and What Doesn't</h2><p>The obvious approach is to pick pairs with the highest in-sample Sharpe. I tested 18 IS metrics as predictors of OOS Sharpe. None of them work. Best R-squared: 0.037.</p><p>But two things do carry forward: <strong>variance ratio</strong> (how mean-reverting the spread is) and <strong>skew</strong> (whether losses are fat-tailed). A composite of low VR, low skew, and improving recent Sharpe splits pairs into clear tiers:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MASG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MASG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 424w, https://substackcdn.com/image/fetch/$s_!MASG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 848w, https://substackcdn.com/image/fetch/$s_!MASG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!MASG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MASG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MASG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 424w, https://substackcdn.com/image/fetch/$s_!MASG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 848w, https://substackcdn.com/image/fetch/$s_!MASG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!MASG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee02b10-17fb-4834-8a5e-1fba1cc7c6c2_2373x1067.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yqjr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yqjr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 424w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 848w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 1272w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yqjr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yqjr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 424w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 848w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 1272w, https://substackcdn.com/image/fetch/$s_!yqjr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7068f07-66d2-4b76-9423-6b815b46e06d_1473x1169.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Bottom quintile: 58% hit rate, avg per-pair Sharpe 0.18. Top quintile: 82% hit rate, avg per-pair Sharpe 1.07. The score can't predict exactly how good a pair will be, but it clearly separates likely winners from likely losers. Note: these are individual pair Sharpes. The portfolio Sharpe is higher (~1.7) because running ~7 pairs simultaneously provides diversification.</p><p>I also tested other scoring methods: IS Sharpe alone (69% hit rate, worst fold negative), stability scoring with 3 overlapping sub-windows (best per-pair Sharpe but weakest fold barely breaks even), and VR alone (72% hit rate but most mean-reverting pairs aren't always the most profitable). The composite of 50% skew, 30% VR, 20% recency gave the most balanced results and is what I use below.</p><div><hr></div><h2>Results</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qouU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qouU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 424w, https://substackcdn.com/image/fetch/$s_!qouU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 848w, https://substackcdn.com/image/fetch/$s_!qouU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 1272w, https://substackcdn.com/image/fetch/$s_!qouU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qouU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qouU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 424w, https://substackcdn.com/image/fetch/$s_!qouU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 848w, https://substackcdn.com/image/fetch/$s_!qouU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 1272w, https://substackcdn.com/image/fetch/$s_!qouU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91ea3555-c228-4d57-bcd4-3b935a03b58d_2081x1030.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>At <strong>8 bps</strong> round-trip (taker fees): <strong>+70% portfolio return (34% annualized)</strong>, Sharpe 1.7, max drawdown -14%. At <strong>4 bps</strong> (maker fills): <strong>+89% portfolio return (42% annualized)</strong>, Sharpe 1.9, max drawdown -20%. ~7 concurrent positions, 30+ coins, all 5 folds included.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://delphicalpha.substack.com/p/pairs-trading-part-2-backtest-results?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://delphicalpha.substack.com/p/pairs-trading-part-2-backtest-results?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h3>Per-Fold Breakdown</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DjMy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DjMy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 424w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 848w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 1272w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DjMy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DjMy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 424w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 848w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 1272w, https://substackcdn.com/image/fetch/$s_!DjMy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e0a20b-ccbe-4330-b884-599d7b40a52f_2081x879.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>3 of 5 folds profitable. Fold 1 (-18% raw) and fold 3 (-4% raw) lose money. Fold 5 (Dec 2025 to Mar 2026) is the strongest at +213% raw.</p><h3>Which Pairs Survive?</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zcGh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zcGh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 424w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 848w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 1272w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zcGh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zcGh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 424w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 848w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 1272w, https://substackcdn.com/image/fetch/$s_!zcGh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9726280e-2e84-4c5c-aad9-b0f5a07e2282_1776x1030.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>DYDX/STRK</strong> (+43%), <strong>AVAX/WLD</strong> (+37%), <strong>NEAR/ORDI</strong> (+36%), <strong>DOT/DYDX</strong> (+33%) lead. 30 unique coins traded across all folds. No single pair dominates, pairs rotate fold to fold.</p><div><hr></div><h2>What Didn't Work</h2><p>Kalman filter (overtrades at 5-min), BTC regime filters (no link between BTC momentum and pair PnL), persistence filters (requiring pairs in consecutive IS top lists, too strict), nested IS validation (split IS in half, didn't improve hit rate), IS Sharpe as a ranking signal (zero correlation with OOS Sharpe).</p><div><hr></div><h2>Honest Assessment</h2><ul><li><p><strong>No pre-filtering</strong>: all 820 pairs compete in every fold. The composite scoring does all selection from IS data. No look-ahead.</p></li><li><p><strong>Fold 1 is weak</strong>: cold-start with limited IS history. Excluded from headline metrics.</p></li><li><p><strong>Fold 3 is near-flat</strong>: Jun to Sep 2025 is thin across every method I tested. The edge is regime-dependent.</p></li><li><p><strong>IS can't rank pairs</strong>: I can tell which pairs will make money but not which will make the most. Equal-weight is the right call.</p></li><li><p><strong>30 coins</strong>: the scoring naturally diversifies across coins without needing to hand-pick a universe.</p></li></ul><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://delphicalpha.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://delphicalpha.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Pairs Trading Crypto Perpetuals: The Methodology]]></title><description><![CDATA[Part 1 of 3 &#8212; Spread construction, hedge ratios, z-score signals, and PnL math]]></description><link>https://delphicalpha.substack.com/p/pairs-trading-crypto-perpetuals-the</link><guid isPermaLink="false">https://delphicalpha.substack.com/p/pairs-trading-crypto-perpetuals-the</guid><dc:creator><![CDATA[oracle]]></dc:creator><pubDate>Sat, 11 Apr 2026 15:20:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2cg7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128214; Part 1: The Methodology of the Pairs Trading Crypto Perpetuals series. Also read: <a href="https://delphicalpha.substack.com/p/pairs-trading-part-2-backtest-results">Part 2: Backtest Results</a></em></p><p>Pairs trading is statistical arbitrage on two correlated assets &#8212; you bet that their price relationship will revert to the mean. This post covers the math from scratch: how to construct the spread, estimate the hedge ratio, generate z-score signals, and compute PnL. We run this on crypto perpetual futures (Hyperliquid), where 24/7 markets and tight spreads make it a natural fit.</p><div><hr></div><h2>What Is Pairs Trading?</h2><p>The core idea is simple. Two assets that historically move together sometimes diverge. When they do, you short the one that went up relative to the other and go long the one that went down. When the relationship reverts, you close both legs and collect the difference.</p><p>It's one of the oldest systematic strategies &#8212; academic literature goes back to the 1980s at Morgan Stanley, and it remains a mainstay of equity stat arb desks. The appeal is that it's largely market-neutral: you don't need to predict whether crypto goes up or down, only whether two coins converge.</p><p>The hard parts are:</p><ul><li><p><strong>Pair selection</strong>: Most pairs don't mean-revert. Finding the ones that do is the entire game.</p></li><li><p><strong>Hedge ratio estimation</strong>: The relationship between two assets isn't static. You need a rolling estimate of how much of asset B to hold per unit of asset A.</p></li><li><p><strong>Signal timing</strong>: Mean-reversion is real, but it can take longer than your risk budget allows.</p></li></ul><p>Let's build the whole thing from first principles. Here's the full pipeline at a glance &#8212; each section below covers one stage:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2cg7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2cg7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2cg7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pipeline overview&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Pipeline overview" title="Pipeline overview" srcset="https://substackcdn.com/image/fetch/$s_!2cg7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2cg7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3175486-8c07-4f40-af79-436efd489d5a_2216x491.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h2>The Spread</h2><p>The fundamental quantity in pairs trading is the <em>spread</em> &#8212; a synthetic time series that measures the deviation between two assets from their equilibrium relationship.</p><p>We work in log-price space. For a pair with a "quote" coin and a "base" coin:</p><pre><code>spread_t = log(quote_t) - alpha_t - beta_t * log(base_t)</code></pre><p>Where:</p><ul><li><p><code>quote_t</code> and <code>base_t</code> are close prices at time t</p></li><li><p><code>beta_t</code> is the <strong>hedge ratio</strong> &#8212; how many dollars of base to hold per dollar of quote</p></li><li><p><code>alpha_t</code> is the intercept (absorbs level differences between the two log-price series)</p></li></ul><p>The spread is the residual from a <a href="https://delphicalpha.substack.com/p/regression-methods-every-quant-should">regression</a> of log(quote) on log(base). If the relationship is stable, this residual is stationary &#8212; it fluctuates around zero without trending away. That's exactly what we need for mean-reversion.</p><p>Why log prices? Two reasons:</p><ol><li><p>Returns compound multiplicatively, and log transforms make this additive</p></li><li><p>It handles the large price-level differences between coins (BTC at $60K vs DOGE at $0.15) naturally</p></li></ol><div><hr></div><h2>Rolling OLS Hedge Ratio</h2><p>The hedge ratio <code>beta</code> is the slope of the linear relationship between the two assets. We estimate it using ordinary least squares (OLS) regression on a rolling window.</p><p>At each bar t, we take the most recent <code>W</code> bars and fit:</p><pre><code>log(quote_i) = alpha + beta * log(base_i) + epsilon_i,   for i in [t-W, t)</code></pre><p>Then we compute the out-of-sample spread at bar t:</p><pre><code>spread_t = log(quote_t) - alpha - beta * log(base_t)</code></pre><p>Notice the window is <code>[t-W, t)</code> &#8212; we use bars <em>before</em> the current bar to estimate beta, then apply it to the current bar. This prevents look-ahead bias: the hedge ratio doesn't use information from the bar it's being applied to.</p><h3>Window Size</h3><p>We tested rolling windows of 5 days (1440 bars), 7 days (2016 bars), and 10 days (2880 bars) at 5-minute frequency as part of a systematic parameter sweep (details in Part 2). The 5-7 day range consistently outperformed the 10-day window.</p><p>The intuition:</p><ul><li><p><strong>Too short</strong> (1-2 days): The hedge ratio is noisy, whipping around on short-term moves. The spread becomes dominated by estimation error rather than genuine divergence.</p></li><li><p><strong>Too long</strong> (10+ days): The hedge ratio can't adapt to structural shifts in the relationship. In crypto, correlations change fast &#8212; longer windows dilute signal with stale data and increase drawdowns.</p></li><li><p><strong>5-7 days</strong> balances responsiveness and stability. The 5-day window (1440 bars) produced the highest risk-adjusted returns in our sweep, while the 7-day window (2016 bars) offered slightly lower volatility.</p></li></ul><h3>Implementation</h3><p>The rolling OLS is a simple loop. For each bar, we solve the normal equations:</p><pre><code>def rolling_ols_hedge(y: pd.Series, x: pd.Series, window: int):

    """Rolling OLS hedge ratio. y=log(quote), x=log(base)."""

    n = len(y)

    spread, beta = np.full(n, np.nan), np.full(n, np.nan)

    for t in range(window, n):

        y_win, x_win = y.values[t-window:t], x.values[t-window:t]

        X = np.column_stack([x_win, np.ones(window)])

        params, *_ = np.linalg.lstsq(X, y_win, rcond=None)

        beta[t], alpha = params[0], params[1]

        spread[t] = y.values[t] - alpha - beta[t] * x.values[t]  # out-of-sample

    return pd.Series(spread, index=y.index), pd.Series(beta, index=y.index)</code></pre><p>This is O(n * W) which isn't fast &#8212; for 2+ years of 5-minute data (200K+ bars) and a 2016-bar window, it takes a few seconds per pair. Good enough for backtesting; for live, we only compute the latest bar.</p><div><hr></div><h2>Z-Score: Normalising the Spread</h2><p>The raw spread has units that depend on the price levels. A spread of 0.01 might be huge for one pair and trivial for another. We normalise it into a z-score:</p><pre><code>z_t = (spread_t - mean) / std</code></pre><p>Where <code>mean</code> and <code>std</code> are computed on a rolling window of the spread.</p><h3>The Lagged Window Trick</h3><p>There's a subtlety. If we compute the rolling mean and std using bars <code>[t-L, t]</code> (including the current bar), the current bar's spread value leaks into its own normalisation. This creates a subtle form of look-ahead bias &#8212; the z-score is artificially pulled toward zero because the current observation influences its own mean and standard deviation.</p><p>The fix is to <strong>shift by one bar</strong>: compute rolling stats on <code>[t-L-1, t-1]</code>, then normalise the current bar against the <em>lagged</em> statistics.</p><pre><code>def compute_zscore(spread: pd.Series, lookback: int) -&gt; pd.Series:

    """Rolling z-score with lagged window (no look-ahead bias)."""

    lagged = spread.shift(1)

    roll_mean = lagged.rolling(lookback).mean()

    roll_std = lagged.rolling(lookback).std()

    return (spread - roll_mean) / roll_std</code></pre><p>We use a 2-day lookback (576 bars at 5-minute). This is much shorter than the hedge window, which makes sense &#8212; the hedge captures the slow-moving structural relationship, while the z-score captures short-term deviations from it.</p><div><hr></div><h2>Entry and Exit Rules</h2><p>With the z-score in hand, the trading rules are straightforward:</p><h3>Entry</h3><ul><li><p><strong>Long spread</strong> when <code>z &lt; -2.0</code> (spread is 2 standard deviations below normal &#8212; quote is cheap relative to base)</p></li><li><p><strong>Short spread</strong> when <code>z &gt; 2.0</code> (spread is 2 standard deviations above normal &#8212; quote is expensive relative to base)</p></li></ul><h3>Exit</h3><ul><li><p><strong>Close position</strong> when <code>|z| &lt; 0.3</code> (spread has reverted close enough to the mean)</p></li></ul><h3>Hold Constraints</h3><ul><li><p><strong>Minimum hold</strong>: 2 hours (24 bars at 5-min). Prevents whipsawing on noisy z-score oscillations around the threshold.</p></li><li><p><strong>Maximum hold / timeout</strong>: 3 days (864 bars). If the spread hasn't reverted after 3 days, close the position and take the loss. This is a crucial risk control &#8212; not all divergences revert, and holding indefinitely is how pairs traders blow up.</p></li></ul><h3>Why These Thresholds?</h3><p>We tested entry thresholds of 1.5, 2.0, and 2.5 alongside exit thresholds of 0.2 and 0.5 in a systematic sweep across 72 configurations (Part 2). The key findings:</p><ul><li><p><strong>Entry z = 2.0</strong> is the sweet spot. At 2.0, per-trade quality is highest and portfolio volatility is lowest across the sweep. At 1.5, you get more trades but noisier signals. At 2.5, you cut too many opportunities without improving risk-adjusted returns.</p></li><li><p><strong>Exit z = 0.2</strong> outperformed 0.5. The tighter exit captures more of the reversion on each round trip, producing fewer but higher-quality trades. Exit z = 0.5 leaves too much on the table &#8212; waiting for the spread to revert further means more trades timeout instead.</p></li></ul><p>The key insight: lower entry thresholds aren't inherently worse &#8212; they generate more signals, and the <em>filtering step</em> (selecting quality pairs, covered in Part 2) does the real work of separating signal from noise.</p><pre><code># Entry: z-score crosses threshold

if position == 0:

    if z &lt; -entry_zscore:    position = 1   # long spread

    elif z &gt; entry_zscore:   position = -1  # short spread

# Exit: z-score reverts toward zero, or timeout

if position != 0 and bars_held &gt;= min_hold:

    if abs(z) &lt; exit_zscore or bars_held &gt;= max_hold:

        close_position()</code></pre><div><hr></div><h2>PnL Calculation</h2><p>When you trade a pairs position, you have two legs. The PnL depends on the returns of both legs and the hedge ratio at entry.</p><p><strong>Long spread</strong> means: buy the quote coin, sell <code>beta</code> dollars of the base coin. The reverse for short spread.</p><p>The return on the spread position is:</p><pre><code>raw_return = direction * (quote_return - beta_entry * base_return)</code></pre><p>But we need to normalise by the capital at risk. Both legs use capital: $1 on the quote leg and <code>|beta|</code> dollars on the base leg. Total capital = <code>1 + |beta|</code>.</p><p>After normalising and subtracting transaction costs:</p><pre><code>pnl = direction * (quote_ret - beta * base_ret) / (1 + |beta|) - txcost</code></pre><p>We use a transaction cost of <strong>8 basis points</strong> (0.08%) round-trip, which covers taker fees on both legs for opening and closing. On Hyperliquid, taker fees are typically 2.5 bps per side, so 4 legs &#215; 2.5 bps = 10 bps &#8212; we use 8 bps as a reasonable average accounting for occasional maker fills.</p><pre><code>quote_ret = quote_price_exit / quote_price_entry - 1.0

base_ret  = base_price_exit  / base_price_entry - 1.0

raw_spread_ret = direction * (quote_ret - beta_entry * base_ret)

pnl = raw_spread_ret / (1.0 + abs(beta_entry)) - transaction_cost</code></pre><h3>Dollar PnL</h3><p>To convert from return to dollars: multiply by the notional per leg. If you deploy $500 per leg, and the normalised PnL on a trade is 0.3% (0.003), your dollar PnL is <code>$500 * 0.003 * (1 + |beta|) &#8776; $3</code>.</p><div><hr></div><h2>Quality Metrics: Is This Pair Actually Mean-Reverting?</h2><p>Not every pair of correlated assets mean-reverts. Some are cointegrated (good), some are just correlated but drift apart over time (bad). We use two metrics to distinguish them.</p><h3>Variance Ratio</h3><p>The variance ratio test compares the variance of k-bar returns to 1-bar returns:</p><pre><code>VR(k) = Var(spread[t] - spread[t-k]) / (k * Var(spread[t] - spread[t-1]))</code></pre><p>The interpretation is:</p><ul><li><p><strong>VR &lt; 1</strong>: Mean-reverting. Long-horizon variance is <em>less</em> than what you'd expect from a random walk. Returns at different lags partially cancel each other out &#8212; what goes up tends to come back down.</p></li><li><p><strong>VR = 1</strong>: Random walk. No predictable pattern.</p></li><li><p><strong>VR &gt; 1</strong>: Trending. Long-horizon variance exceeds the random walk prediction. Divergences tend to persist.</p></li></ul><p>For pairs trading, we want VR well below 1. Our top pairs typically show VR in the 0.65-0.85 range with a lag of 50 bars.</p><pre><code>def variance_ratio(series, lag=50):

    returns = np.diff(series)

    var_1 = np.var(returns)

    var_k = np.var(series[lag:] - series[:-lag]) / lag

    return var_k / var_1</code></pre><h3>Ornstein-Uhlenbeck Half-Life</h3><p>The OU process is the continuous-time model for mean reversion:</p><pre><code>d(spread) = theta * (mu - spread) * dt + sigma * dW</code></pre><p>Where <code>theta</code> is the speed of mean reversion. The half-life &#8212; time for the spread to revert halfway to the mean &#8212; is <code>ln(2) / theta</code>.</p><p>We estimate theta from an AR(1) regression on the spread:</p><pre><code>spread[t] = mu + rho * spread[t-1] + noise

theta = -ln(rho)

half_life = ln(2) / theta</code></pre><p>A half-life of 200-300 bars (17-25 hours at 5-min) is typical for our best pairs. This tells you roughly how long to expect a trade to last. Pairs with very long half-lives (500+ bars) are technically mean-reverting but too slow to trade profitably at 5-minute frequency &#8212; the transaction costs eat the small, slow convergence.</p><div><hr></div><h2>Kalman Filter Hedge: The Advanced Alternative</h2><p>Rolling OLS has a weakness: it gives equal weight to all observations in the window and zero weight to everything outside it. This creates discontinuities when old observations drop out of the window.</p><p>A Kalman filter offers a smoother alternative. It models the hedge ratio as a time-varying state and updates it incrementally with each new observation:</p><pre><code>def kalman_hedge(y, x, delta=1e-4, Ve=1e-3):

    """Kalman filter hedge. State=[beta, alpha], spread=innovation."""

    theta, P, Q = np.zeros(2), np.eye(2), delta * np.eye(2)

    for t in range(n):

        F = np.array([x[t], 1.0])

        e = y[t] - F @ theta           # innovation = spread

        K = (P @ F) / (F @ P @ F + Ve) # Kalman gain

        theta = theta + K * e           # state update

        P = P - np.outer(K, F) @ P + Q

        spread[t], beta[t] = e, theta[0]</code></pre><p>The <code>delta</code> parameter controls how fast the hedge ratio can change. Small delta (1e-5) = slow adaptation, smooth beta. Large delta (1e-3) = fast adaptation, noisier beta.</p><p>In theory, the Kalman filter should outperform rolling OLS on pairs where the hedge ratio genuinely shifts over time. In practice, our parameter sweep told a very different story.</p><div><hr></div><h2>Putting It All Together</h2><p>Here's the detailed signal pipeline for a single pair, with optimal parameters from the 72-configuration sweep:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ntg4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ntg4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ntg4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Detailed signal pipeline&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Detailed signal pipeline" title="Detailed signal pipeline" srcset="https://substackcdn.com/image/fetch/$s_!ntg4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ntg4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd56f865-1f19-496b-8e61-b732e1786def_1466x2852.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h2>What Could Go Wrong</h2><p>This methodology has clear failure modes:</p><ol><li><p><strong>Structural breaks</strong>: The correlation between two assets can break permanently (e.g., a protocol fork, regulatory event, or delisting). The spread diverges and never reverts. The 3-day timeout limits damage but doesn't prevent it entirely.</p></li></ol><ol><li><p><strong>Crowding</strong>: If many traders run the same pairs strategy on the same pairs, the mean-reversion signal gets arbitraged away. This is less of a concern in crypto (the market is still fragmented) but worth monitoring.</p></li></ol><ol><li><p><strong>Transaction costs</strong>: Each trade has a cost floor. Pairs with small average PnL per trade can be profitable in backtests with optimistic cost assumptions and unprofitable in reality.</p></li></ol><ol><li><p><strong>Execution slippage</strong>: You need to fill both legs simultaneously. If one leg fills and the other doesn't (or fills at a worse price), you're running unhedged directional risk. More on this in Part 3.</p></li></ol><p>The next post covers walk-forward validation: we select the best pairs from each period and test them on the next, answering whether the edge survives a strict forward test.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://delphicalpha.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://delphicalpha.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h3>Related Articles</h3><ul><li><p><a href="https://delphicalpha.substack.com/p/reference-guides-cointegration-and">Reference Guides - Cointegration and Pairs Trading</a> &#8212; Mathematical foundations of pairs trading</p></li><li><p><a href="https://delphicalpha.substack.com/p/regression-methods-every-quant-should">Regression Methods Every Quant Should Know: Math, Insights, and Debugging</a> &#8212; OLS to quantile regression, with quant applications</p></li></ul>]]></content:encoded></item></channel></rss>