Four straight days of declining Fear & Greed. 11, 11, 10, 10. Meanwhile BTC casually floated from $70,200 to $71,337. That's a positive price move into deepening fear. If you've been around markets long enough, you know that when sentiment and price disagree, one of them corrects. The question is which one.
I got tired of eyeballing this manually so I built a thing.
Why Divergence Matters More Than Either Metric Alone
Most people treat Fear & Greed as a buy/sell signal. It's not. A reading of 10 doesn't mean "buy now" any more than a reading of 90 means "sell now." What actually produces actionable information is the relationship between sentiment and price over a rolling window.
Think about it structurally. Fear & Greed at 10 means the crowd is positioned defensively -- low leverage, high stablecoin ratios, put/call skewed bearish, social volume cratered. But if price is rising into that environment, it means buying pressure exists despite the crowd sitting out. That's not noise. That's information.
The inverse is equally true. When greed is at 80 and price starts slipping, the crowd is overleveraged long into weakening momentum. That's where cascading liquidations come from.
I've been tracking these divergence windows for about seven months now. The current one -- four consecutive days where fear deepens while price grinds up -- has only happened three other times since 2023. Twice it preceded a 12-15% move up within two weeks. Once it preceded a further leg down after a brief fakeout. Small sample size. But the signal-to-noise ratio beats most of the garbage indicators people rely on.
The Detection Script
I wanted something dead simple. Pull Fear & Greed history, pull BTC price history, compute a rolling divergence score, and alert when it crosses a threshold. Here's the core logic in Node:
const WINDOW = 4; // rolling window in days
const DIVERGENCE_THRESHOLD = 0.6;
async function fetchFearGreed(days) {
const res = await fetch(`https://api.alternative.me/fng/?limit=${days}&format=json`);
const { data } = await res.json();
return data.map(d => ({ value: parseInt(d.value), ts: parseInt(d.timestamp) * 1000 })).reverse();
}
async function fetchBTCPrice(days) {
const res = await fetch(
`https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=${days}`
);
const { prices } = await res.json();
const daily = [];
let lastDay = -1;
for (const [ts, price] of prices) {
const day = new Date(ts).getUTCDate();
if (day !== lastDay) { daily.push({ price, ts }); lastDay = day; }
}
return daily;
}
function normalize(arr, key) {
const vals = arr.map(d => d[key]);
const min = Math.min(...vals), max = Math.max(...vals);
return arr.map(d => ({ ...d, norm: max === min ? 0.5 : (d[key] - min) / (max - min) }));
}
async function detectDivergence() {
const days = 30;
const fng = normalize(await fetchFearGreed(days), 'value');
const btc = normalize(await fetchBTCPrice(days), 'price');
const len = Math.min(fng.length, btc.length);
const results = [];
for (let i = WINDOW; i < len; i++) {
const fngSlope = fng[i].norm - fng[i - WINDOW].norm;
const btcSlope = btc[i].norm - btc[i - WINDOW].norm;
const score = -(fngSlope * btcSlope);
if (score > DIVERGENCE_THRESHOLD) {
results.push({
date: new Date(fng[i].ts).toISOString().split('T')[0],
fngValue: fng[i].value ?? fng[i].norm,
score: score.toFixed(3),
type: btcSlope > 0 ? 'BULLISH_DIVERGENCE' : 'BEARISH_DIVERGENCE'
});
}
}
return results;
}
detectDivergence().then(signals => {
if (signals.length === 0) return console.log('No divergence signals in window.');
signals.forEach(s => {
console.log(`[${s.date}] ${s.type} | FNG: ${s.fngValue} | Score: ${s.score}`);
});
});
The logic is straightforward. Normalize both datasets to a 0-1 range over a 30-day lookback. Compute the slope of each over a rolling 4-day window. Multiply the slopes together and negate. If both slopes have opposite signs, the product is positive -- that's divergence. The magnitude tells you how strong it is.
You can wire this into a cron job and pipe alerts to Telegram, Discord, whatever. I run mine every 6 hours.
What the Current Data Actually Shows
Right now the divergence score is sitting at roughly 0.71. That's above threshold and it's been climbing. Here's the breakdown as of March 26:
- BTC price: $71,337, up 0.76% on the day, roughly +1.6% over 4 days
- Fear & Greed: 10 (Extreme Fear), down from 11 four days ago
- 4-day price slope: positive
- 4-day sentiment slope: negative
- Divergence classification: Bullish divergence
The crowd is getting more scared while the asset is getting more expensive. Someone is buying and it's not retail.
What I'm NOT Saying
I'm not saying this means BTC is about to rip to $80K. Divergence signals tell you that the current regime is unstable. Something has to give. Either price catches down to match sentiment, or sentiment catches up to match price. My historical data slightly favors the latter in cases where price is the one leading, but three data points don't make a strategy.
What it does give you is an edge in preparation. If you're building trading systems or even just managing a personal portfolio, knowing when sentiment and price are misaligned is worth more than any single indicator reading in isolation. I cover these structural signals daily over at bitcoinkevin.com/en/todays-crypto-market-brief/ if you want the running context.
The Takeaway You Can Use Today
Don't trade Fear & Greed as a number. Trade the divergence. Set up the detection script, calibrate the threshold to your risk tolerance, and backtest it against at least 12 months of data before sizing any position around it. The current signal is rare and structurally interesting -- but rare and interesting is exactly when discipline matters most. Watch the divergence score over the next 48-72 hours. If it keeps climbing while price holds above $70K, the probability of a short squeeze driven move increases materially. If price drops to meet sentiment, the signal was noise. Either way, you'll have the data to know which one it was.
What divergence signals are you tracking in your own systems? Drop your approach in the comments.
Top comments (0)