corr
Answered against 22 years of US equities and 12 years of US options data and published with the query that produced it. This result is stored as of 2026-10-01, from do-volume-indicators-predict-anything.
| ticker | trailing_corr | forward_corr | session_count |
|---|---|---|---|
| SPY | 0.84 | -0.16 | 2596 |
| HD | 0.8 | 0 | 2596 |
| JPM | 0.8 | -0.1 | 2596 |
| PEP | 0.78 | -0.14 | 2596 |
| XOM | 0.78 | -0.01 | 2596 |
| MCD | 0.76 | 0.01 | 2596 |
| KO | 0.74 | -0.15 | 2596 |
| MSFT | 0.74 | -0.14 | 2596 |
| PG | 0.69 | -0.09 | 2596 |
| JNJ | 0.59 | -0.04 | 2596 |
- Rows × columns
- 10 × 4
- Computed
- Completeness
- No missing values
- Source
- US exchange, SIP and OPRA market data
- Licence
- Strasmore terms · free, no signup
What each column holds
| Column | Type | Range | Notes |
|---|---|---|---|
ticker |
text | 10 distinct values (HD, JNJ, JPM…) | |
trailing_corr |
number | 0.59 to 0.84 | |
forward_corr |
number | -0.16 to 0.01 | |
session_count |
number | every row is 2,596 | count |
Computed from Strasmore's warehouse of US exchange, SIP and OPRA market data. Equity prices are delayed; options greeks and implied volatility are end-of-day. This result is stored, not recomputed on load — it is exactly the numbers that were returned on , and the query below is what returned them.
Run it yourself
This is the exact query behind the result above. Change a ticker, a date or a column and run it against the warehouse — no account, no key. The no-signup tier is smaller than the one this page was computed on; a query that reaches past it comes back saying which plan runs it.
WITH
bars AS
(
SELECT
ticker,
date,
max(toFloat64(close)) AS close,
max(toFloat64(volume)) AS volume
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('MSFT', 'SPY', 'KO', 'JNJ', 'JPM', 'XOM', 'PG', 'PEP', 'MCD', 'HD')
AND date >= '2016-01-04'
AND date <= '2026-06-30'
GROUP BY ticker, date
),
stepped AS
(
SELECT
ticker,
date,
close,
volume,
lagInFrame(close, 1) OVER (PARTITION BY ticker ORDER BY date ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM bars
),
cumulative AS
(
SELECT
ticker,
date,
close,
sum(if(prev_close = 0, 0, if(close > prev_close, volume, if(close < prev_close, -volume, 0))))
OVER (PARTITION BY ticker ORDER BY date ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS obv,
row_number() OVER (PARTITION BY ticker ORDER BY date ASC) AS bar_no
FROM stepped
),
deltas AS
(
SELECT
ticker,
close,
bar_no,
obv - lagInFrame(obv, 20) OVER (PARTITION BY ticker ORDER BY date ASC ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS obv_change,
lagInFrame(close, 20) OVER (PARTITION BY ticker ORDER BY date ASC ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS close_back,
leadInFrame(close, 20) OVER (PARTITION BY ticker ORDER BY date ASC ROWS BETWEEN CURRENT ROW AND 20 FOLLOWING) AS close_fwd
FROM cumulative
)
SELECT
ticker,
round(corr(obv_change, 100 * (close / close_back - 1)), 2) AS trailing_corr,
round(corr(obv_change, 100 * (close_fwd / close - 1)), 2) AS forward_corr,
count() AS session_count
FROM deltas
WHERE bar_no > 21
AND close_back > 0
AND close_fwd > 0
GROUP BY ticker
ORDER BY trailing_corr DESC
Work with this data in your AI assistant
Opens ready to query, with this page's data. Free, no account.