DOGSIGNAL
forensic swing signals · $DOG & BTC

The sauce

This is the exact math – every indicator, every score band, every threshold and weight, taken directly from the scoring engine. If you want the plain-language version instead, see the FAQ. This page exists so nothing here has to be taken on faith: you can check any reading on the homepage against the rule that produced it.

How a score is built Category weights Trend Momentum Futures Sentiment On-Chain Composite & stance BTC-beta check Confidence %
How a score is built, end to end
The five-step pipeline

Every run (every 4 hours) does the same five steps, for BTC and then $DOG:

  1. Fetch. Pull raw data from each live source (price candles, futures data, Fear & Greed, Google Trends, X posts, on-chain stats for $DOG). Anything that fails is recorded as a data limitation, not guessed at.
  2. Score each indicator. Every individual metric (e.g. "Price vs 200d SMA") is converted to an integer score from −2 to +2 using fixed threshold rules – shown in full below.
  3. Average into a category score. All indicator scores within a category (Trend, Momentum, Futures, Sentiment, on-chain for $DOG) are averaged and mildly amplified, producing one category score in [−2, +2].
  4. Weight and sum into a composite. Category scores are combined using the weights below into one composite number in [−1, +1].
  5. Apply hysteresis to get BUY/HOLD/SELL. The composite alone doesn't decide the stance – see Composite & stance for why.
Category weights
Exact weights, per asset

BTC has no on-chain data source available (see FAQ for why), so its weight is redistributed across the other four categories:

35%25%20%20%
TrendMomentumFuturesSentiment

$DOG gets a fifth category, shaving weight off the rest to make room:

30%20%15%15%20%
TrendMomentumFuturesSentimentOn-Chain

These weights are static constants in the scoring engine – they don't drift or self-tune. If a category has no usable data at all in a given run (every indicator inside it failed), that category is dropped from the weighted sum entirely and the remaining weights implicitly carry more of the composite for that one run – this is the coverage mechanism, also used in the confidence score below.

Trend – exact rules
Price vs 200-day SMA

Distance of current price from the 200-day simple moving average, as a percentage: dist = (price − SMA200) / SMA200.

ConditionScore
dist > 25%+2
dist > 5%+1
−5% ≤ dist ≤ 5%0 (hugging the mean, no edge)
dist < −5%−1
dist < −25%−2

Requires at least 210 days of daily history to compute at all; otherwise the whole Trend block reports as a data limitation.

50/200 SMA cross ("golden"/"death" cross)

Base score: +1 for a golden cross (50-day SMA above 200-day), −1 for a death cross (below).

Freshness multiplier: if the cross happened ≤30 days ago, the score is doubled to ±2 – a cross that just happened carries more information than one that happened months ago and has already been priced in.

Weekly 21 EMA slope

Rate of change of the weekly 21-period EMA over the last two weeks, expressed as a per-week percentage: slope = (EMA[t] − EMA[t−2]) / EMA[t−2] / 2.

ConditionScore
slope > 2%/wk+2
slope > 0.5%/wk+1
slope < −0.5%/wk−1
slope < −2%/wk−2

Needs at least 21 full weeks of history; otherwise reports as a data limitation rather than a guess.

Momentum – exact rules
Weekly RSI(14) – the primary momentum read
Weekly RSIScoreReasoning
≥ 72−2Historically overheated
55 – 72+1Bullish zone, not yet overheated
42 – 550Mid-range, no swing edge
28 – 42−1Weak zone
≤ 28+2Washed out – favors accumulation

Note this is not simple overbought/oversold: the 55–72 band scores positive (bullish continuation), and only ≥72 flips to contrarian negative. This reflects that momentum can stay strong for a while in a genuine trend before it becomes an overextension worth fading.

Daily RSI(14) – extremes only

Unlike the weekly read, daily RSI only scores at the extremes, since day-to-day noise isn't reliable on a swing-trading timeframe: ≥80 → −1, ≤22 → +1, otherwise 0.

MACD daily (12, 26, 9)

Scored on the sign of the histogram and whether it's expanding or contracting versus the previous reading:

HistogramDirectionScore
PositiveRising+1
PositiveFalling0
NegativeFalling−1
NegativeRising0
Futures – exact rules
Funding rate (perpetuals, per 8h)
Funding rateScoreReasoning
> 0.03%−2Longs heavily crowded, contrarian bearish
> 0.012%−1Long side paying up
−0.02% to 0.012%0Normal band, no crowding
< −0.02%+1Shorts crowded, contrarian bullish
Open interest (7d) vs price

Compares 7-day open-interest change against 7-day price change – the goal is telling new demand apart from pure leverage:

OI changePrice change (7d)ScoreReasoning
> +3%> +2%+1Rising OI with rising price – real demand
> +5%|change| < 2%−1Leverage building without price follow-through
< −5%> +2%−1Price up on falling OI – weak short-covering rally

Since no exchange publishes a ready-made OI history for the $DOG contract, this history is self-tracked from periodic Kraken snapshots stored in Cloudflare KV – it takes ~7 days after first deploy to fully populate, and shows as a data limitation until then.

Long/short account ratio

> 2.5 → −1 (retail heavily long-tilted, contrarian caution) · < 0.7 → +1 (retail net short, contrarian support) · otherwise 0.

Sentiment – exact rules
Crypto Fear & Greed Index

Contrarian, graded in two tiers. The ±1 bands anchor to alternative.me's own published "Extreme" labels (≥75 greed, ≤25 fear); the ±2 tail is reserved for readings the index only reaches a handful of times a year:

Fear & GreedScoreReasoning
≥ 90−2Deep Extreme Greed – rare distribution-zone reading
78 – 89−1Extreme Greed, contrarian caution
23 – 770No contrarian edge
11 – 22+1Extreme Fear, contrarian support
≤ 10+2Deep Extreme Fear – rare accumulation-zone reading

The extreme-tier cutoffs (90 / 10) are a judgment call – chosen as "meaningfully deeper into the extreme than the standard label," calibrated to where the index actually spends its time, rather than round numbers that would fire too rarely to matter.

Google search trends

Two numbers per keyword: the current index level (0–100 scale) and percent vs. the 90-day average.

ConditionScoreReasoning
index ≥ 85−1Search interest near peak – retail euphoria, contrarian
vs-avg > +15% and index < 70+1Rising from a modest base – early interest, not euphoria
vs-avg < −15%−1 if "buy-intent" query, else 0Only queries tagged buy-intent score fading interest as bearish; generic terms don't

$DOG tracks the keyword "DOG bitcoin" (disambiguates the token from the animal); BTC tracks "bitcoin". Google's official Trends API remains limited alpha as of mid-2026, so this runs through Apify's scraper Actor on a ~24h refresh cycle rather than live per-run – see the FAQ for why that's an acceptable tradeoff at swing-trade timeframes.

X (Twitter) live sentiment sample

Recent posts are pulled via GetXAPI and classified with a keyword lexicon – deliberately simple and auditable rather than a black-box model, so every score is traceable to the words that produced it. Two hard rules in the classifier, both added after a real false-positive:

  • The asset's own name is stripped before classification, so a post merely naming "DOG•GO•TO•THE•MOON" doesn't get counted as bullish from the word "moon" alone.
  • All keyword matches use word boundaries, not substrings – so "path"/"death"/"math" don't false-match "ath", "follower" doesn't false-match "lower", etc.

Net ratio is computed as (bull − bear) / (bull + bear) among posts that expressed any direction at all:

ConditionScore
Fewer than 5 directional posts in the sample0 – too few to score, shown not counted
Net ratio ≥ 50% bullish−1 (euphoric, contrarian)
Net ratio > 15% bullish+1
−15% to +15%0 – balanced chatter
Net ratio > 15% bearish−1
Net ratio ≥ 50% bearish+1 (capitulation, contrarian)
CoinMarketCap community sentiment (7d momentum)

CoinMarketCap shows a bullish/bearish community vote on each coin's page. We read it (without casting a vote) and track it, but score it differently from the other rows, for a specific reason: these are lifetime-cumulative tallies, not a fresh daily reading. $DOG sits around 91% bullish across 300k+ votes accumulated over its whole existence – nearly every coin skews permanently bullish because the people who vote are holders. So the absolute level is close to meaningless as a signal; a fixed "euphoria" cutoff would just mark the coin contrarian-bearish forever.

Instead, we score the 7-day momentum of the bullish share – how the crowd's conviction is changing, not where it sits. Since CMC exposes only a live cumulative number and no history, we build our own series in KV (one snapshot per run), the same way we do for futures open interest and holder count. Until ~7 days of snapshots exist, the row shows the current level for context but is not counted:

7-day change in bullish shareScoreReasoning
≥ +1.5 percentage points−1Crowd turning more euphoric – contrarian caution
−1.5 to +1.5 pp0No directional shift
≤ −1.5 pp+1Crowd cooling – contrarian support

This uses CMC's undocumented internal endpoint (the same call their own site makes). Being undocumented, it can change or start blocking without notice – the same fragility as our Google Trends source – so it degrades to a labeled "data limitation" row the moment it breaks, never a fabricated reading. The ±1.5pp threshold is a judgment call and may be recalibrated once real movement data accumulates.

On-Chain ($DOG only) – exact rules
MVRV ratio

Market value vs. realized value – roughly, current price divided by the aggregate cost basis of all holders. Same contrarian-at-extremes logic as Fear & Greed:

MVRVScoreReasoning
< 0.4+2Deeply below fair value – strong accumulation zone historically
0.4 – 0.8+1Below aggregate cost basis
0.8 – 2.00Near fair value
2.0 – 3.5−1Elevated above typical fair-value range
> 3.5−2Extreme unrealized gains – historically precedes distribution

Sourced from dogdata.xyz's own Bitcoin Core + Ord full node – not a third-party estimate.

Supply in profit

Percent of circulating supply currently above its cost basis: <15% → +1 (widespread capitulation, contrarian bullish) · >90% → −1 (broad euphoria, contrarian bearish) · otherwise 0.

Holder count, 7-day trend

>+1% → +1 (healthy accumulation/adoption) · <−1% → −1 (base shrinking) · otherwise 0. This is not contrarian – a growing holder base is read as a straightforwardly positive signal, unlike the other on-chain metrics.

Composite score & the BUY/HOLD/SELL stance
From category scores to one composite number

Step 1 – category score. Each category's indicator scores are averaged, then mildly amplified by ×1.4 and clamped to [−2, +2], so a category where every indicator agrees can reach the full ±2 even though no single indicator did:

category_score = clamp(average(indicator_scores) × 1.4, −2, +2)

Step 2 – weighted composite. Category scores are combined using the weights from above, then normalized down to a [−1, +1] range:

composite = Σ(weight × category_score) / Σ(weight) / 2

Categories with zero usable indicators (every one failed) are dropped from both the numerator and denominator – they don't drag the score toward zero, they're excluded entirely, same principle as individual data-limitation rows.

Why the stance doesn't just flip the moment composite crosses zero

This is hysteresis – the same principle a thermostat uses so it doesn't click on and off every time the temperature wobbles by half a degree. Two constants control it:

ENTER = 0.60Composite must exceed this magnitude to enter BUY or SELL from HOLD
EXIT_BUFFER = 0.15Once in BUY/SELL, composite must fall back below ENTER − EXIT_BUFFER = 0.45 before dropping to HOLD

So a stance change requires crossing ±0.60, and once changed, requires falling back past 0.45 (not just 0.60 again) to leave – the 0.15 gap is a deliberate dead zone that stops the signal from chattering back and forth around a single threshold. A hard reversal (BUY straight to SELL) is still allowed in one step if the composite swings from above +0.60 to below −0.60 in a single run.

BTC-beta check ($DOG only)
Exact rule

$DOG is a Bitcoin Rune – it tends to move with BTC's broader trend, and Rune tokens historically get dragged down hard in BTC downtrends regardless of their own fundamentals. This check runs after $DOG's own composite is computed, using whichever BTC composite is already sitting in the data store from BTC's own run in the same cycle:

if (dog_composite > 0 and btc_composite < −0.30):
  dog_composite −= 0.30
  // logged as "BTC-beta penalty applied"

In plain terms: if $DOG's own evidence says bullish while BTC is clearly trending down, $DOG's score gets docked a flat 0.30 – sometimes enough on its own to pull a marginal BUY back down to HOLD, given the hysteresis thresholds above. It only fires in one direction (penalizing DOG-bullish-against-BTC-bearish) – there's currently no symmetric bonus for DOG-bearish-while-BTC-bullish or symmetric penalty the other way.

If BTC hasn't computed yet in the same cycle (a cold-start edge case, since BTC always runs first), this check is skipped entirely and logged as "no BTC signal in store yet" rather than blocking $DOG's run.

Worth knowing: the −0.30 penalty size and the −0.30 BTC trigger threshold are fixed constants chosen by judgment, not backtested or derived from a formula. If you want to press on why those particular numbers, that's the honest answer.

Confidence % – exact formula
Three ingredients, weighted
confidence = round(100 × (0.40 × agreement + 0.35 × strength + 0.25 × coverage))
TermMeaning
agreementFraction of scored categories whose sign matches the composite's sign (a category scoring exactly 0 always counts as agreeing)
strengthmin(|composite| / 1.2, 1) – how far the composite sits from zero, capped at 1
coverageFraction of categories that had at least one usable indicator this run (vs. failing entirely)

Agreement carries the most weight deliberately – a confident-looking composite built from categories pulling in different directions is treated as less trustworthy than a smaller composite where everything actually points the same way.

← plain-language FAQ  ·  back to the live signals →