Statistics for Traders #22: Fisher's r-to-z on today's slot-1 US ISM Manufacturing × EURUSD sample — the 95% CI for r is [−0.42, −0.17] via Fisher, [−0.44, −0.17] naïve linear, 5% narrower and less symmetric
Pearson’s r isn’t asymptotically Normal. Its sampling distribution is skewed and bounded on (−1, +1). Fisher (1915) proposed z = arctanh(r) = 0.5·ln((1+r)/(1−r)), which is approximately Normal with SE = 1/sqrt(n−3), so a 95% CI for z is symmetric (z ± 1.96·SE) and back-transforming via tanh gives an asymmetric CI on r that respects the bounded support. Worked end-to-end on today’s slot-1 US ISM Manufacturing × EURUSD 15m sample (n=198): overall r = −0.30, Fisher CI [−0.425, −0.171].
This is the natural sequel to Stats #11 (correlation within a bucket, 2026-08-11), which introduced Pearson r and used Fisher r-to-z in passing to build a big_beat CI. Today the transform gets its own installment with the step-by-step derivation on a fresh sample.
The transform in one paragraph
Forward: z = arctanh(r) = 0.5·ln((1+r)/(1−r)). This maps r ∈ (−1, +1) to z ∈ (−∞, +∞), stretching the tails near ±1 and leaving small-r values near-linearly transformed. Sampling distribution: z ~ approximately Normal with mean arctanh(ρ) and variance 1/(n−3) under bivariate Normality of the underlying (X, Y) — an empirical adjustment Fisher himself introduced over the leading-order variance 1/(n−1). 95% CI for z: z ± 1.96 / sqrt(n−3). Back-transform: r_lo = tanh(z_lo), r_hi = tanh(z_hi). The r-space CI is asymmetric — that’s a feature, not a bug.
Worked example: overall r on ISM Mfg × EURUSD
Sample: all n = 198non-contaminated US ISM Manufacturing PMI releases with matched EURUSD 15m moves, from the today’s slot-1 post. Pearson r between surprise_z (input) and move_pips (output): r = −0.3036(US-macro-strong → EURUSD-down, as the 5-bucket walk predicts).
| Step | Formula | Value |
|---|---|---|
| 1. Sample size | n | 198 |
| 2. Sample r | cov(x,y)/(sd(x)·sd(y)) | −0.3036 |
| 3. Fisher z | 0.5·ln((1+r)/(1−r)) | −0.3135 |
| 4. SE(z) | 1/sqrt(n−3) = 1/sqrt(195) | 0.0716 |
| 5. z_lo, z_hi | z ± 1.96·SE | [−0.4538, −0.1731] |
| 6. r_lo = tanh(z_lo) | tanh(−0.4538) | −0.4250 |
| 7. r_hi = tanh(z_hi) | tanh(−0.1731) | −0.1714 |
| Fisher 95% CI on r | — | [−0.4250, −0.1714] |
| Naive linear CI | r ± 1.96·sqrt((1−r²)/(n−2)) | [−0.4370, −0.1702] |
| CI width comparison | Fisher / naive | 0.2536 / 0.2668 (5% narrower) |
At n=198 the two methods agree closely — Fisher CI [−0.425, −0.171] vs naive [−0.437, −0.170], a 5% Fisher-narrower gap. Same qualitative conclusion: the surprise/move correlation on ISM Mfg × EURUSD is negative and statistically distinguishable from zero at the 95% level. The Fisher CI wins on principle but the practical difference at n=198 is small.
![Two-panel horizontal chart. Left panel titled 'Overall n=198, r = -0.30': shows two 95% CI bars stacked vertically, one for Fisher method ([-0.425, -0.171], width 0.254) and one for naive linear method ([-0.437, -0.170], width 0.267). Both bars are entirely to the left of zero (in the negative r region). Bars are close but the Fisher bar is slightly narrower. Right panel titled 'Within big_beat bucket n=21, r = -0.23': shows two 95% CI bars, one for Fisher ([-0.60, +0.23]) and one for naive ([-0.67, +0.21]). Both bars CROSS ZERO (span from negative into positive r), so the correlation isn't distinguishable from zero at 95%. Fisher bar is slightly less symmetric than naive bar. Y-axis labeled 'r'. Coral vertical line at r=0 on both panels.](/insights/stats-for-traders-fisher-r-to-z/comparison.png)
Where Fisher and naive linear diverge: small n
At small n the Fisher asymmetry starts to matter. Within the big_beat bucket alone (n=21 of the 198-release sample), the internal correlation is r = −0.2275— small in magnitude, reflecting that the bucket labels have already absorbed most of the systematic (surprise_z, move_pips) linkage (per Stats #11’s original observation on CAD CPI × CADJPY).
| Bucket | n | r | Fisher CI | Includes 0? |
|---|---|---|---|---|
| Full sample | 198 | −0.30 | [−0.425, −0.171] | no |
| big_miss | 12 | −0.18 | [−0.682, +0.442] | yes |
| big_beat | 21 | −0.23 | [−0.600, +0.226] | yes |
Both tail buckets have wide Fisher CIs that cross zero. Big_miss (n=12) is especially wide — 1.12total width vs the full-sample’s 0.25. That’s the SE factor 1/sqrt(n−3) at work: at n=12, SE_z = 0.333; at n=198, SE_z = 0.072. Sample size doesn’t linearly translate into CI width — it does through a 1/sqrt(n) path.
The tail-bucket Fisher CIs are also visibly asymmetric — the lower endpoint (near −0.6, −0.7) is further from zero than the upper endpoint (near +0.2, +0.4). That’s the tanh back- transform doing exactly the job Fisher designed it for: the CI in z-space is symmetric around z_hat = arctanh(r_hat), but tanh compresses more toward the ±1 bounds than toward zero, so the r-space CI shows that compression as asymmetry.
Why n−3, not n−1?
Fisher (1915) derived the exact sampling distribution of r under bivariate Normality and observed that arctanh(r) has approximate variance 1/(n−1) at leading order. Fisher (1921) followed up with the empirical improvement to 1/(n−3), which holds up in Monte Carlo simulation at small n. The 2 extra degrees of freedom removed reflect the two location parameters (means of x and y) estimated before computing r. Use the n−3version — it’s the one that’s in every stats textbook and every implementation.
Non-Normality (thick tails, skew, outliers in the joint distribution) causes 1-3% CI under-coverage at n≈100, per the standard Monte Carlo results. That’s smaller than the Fisher-vs-naive gap at moderate n, so Fisher stays the default. If you care about exact 95% coverage at n<30, bootstrap the correlation using the machinery from Stats #12 (percentile bootstrap), Stats #14 (BCa), or Stats #15/#16 (stationary / Politis-White for autocorrelated series).
Cross-links and the queue
This installment sits alongside the correlation-family installments already published: Stats #11 (Pearson r within a bucket) introduced Fisher r-to-z in passing; Stats #10 (autocorrelation) is the special case of correlation between the same series at a lag; Stats #13 (information ratio) used Fisher-informed intuition to reason about bucket-filter strategies as regressions.
The ledger’s queued “Fisher r-to-z transformation as its own installment” item, flagged since Stats #11 on 2026-08-11 (11 days ago), is now cleared. Partial correlation (Pearson r controlling for a third variable), higher-order VAR-b prewhitening (Andrews-Monahan extension of Stats #20), and running-window b_opt (Stats #16 extension to check block-length stationarity) remain queued for future runs. Kernel- family arc completed at Stats #21 (Tukey-Hanning) is done.
Verification note
All numbers verified against live /api/v1/news-impact/releases pull on 2026-08-22. Pearson r computed in a scratch Python script (n=198 sample of surprise_z, move_pips pairs), Fisher z and back-transform computed to 4 decimal places. Chart rendered via a one-off script using scripts/insights-charts/svg.ts primitives. Cross-verified against numpy.corrcoef and scipy.stats implementations to 4 decimal places.