Qtick
Sign in

Trend & technicals

How QTick calculates the 11 metrics in this group — the real method named, then translated: what it tells you, how it is computed, and where it breaks down. None of these is a trigger to act.

RSI-14

How it's calculated

For each of the last 14 trading sessions, we split the close-to-close move into a gain or a loss (a down day counts as a zero gain, an up day as a zero loss). We average those 14 gains and 14 losses separately, divide them (avg_gain / avg_loss = RS), then compute 100 − 100/(1+RS). It's one fresh 14-day window with no smoothing carried forward from prior days, and it needs at least 15 closes to produce a value. Source: `backend/app/services/stock_analysis/data_provider.py:956-970` (`_rsi_14`), which sets `snap.rsi_14` at `data_provider.py:499` on a `TickerSnapshot`. That snapshot is upserted into `IntelTickerSnapshot.rsi_14` by `persist_ticker_snapshot()` (`backend/app/services/stock_analysis/service.py:731`), surfaced for display at `backend/app/qtick/services/ticker_service.py:2235`, and mapped to the frontend at `qtick/frontend/src/lib/data/map/technicals.ts:23`.

How it affects judgement

RSI-14 tells you how stretched the tape is, not whether the fundamentals changed. An extreme reading (above 70 or below 30) sharpens your timing question — does the thesis still hold at this price velocity? A reading above 70 adds friction to a long case (momentum-chasers are already in); below 30 weakens the near-term bear case (the tape is already pricing in the pain). Neither extreme is decisive alone — pair it with volume and the 50/200 MA structure before forming a view.

What the current value signifies

Above 70: the stock has gained on most of the last two weeks — price is stretched above recent norms, and mean-reversion pressure often builds. Below 30: losses have dominated — the tape is compressed, often a sign of near-term exhaustion of sellers. The 40-60 band is normal drift. QTick labels 55+ "firm," 45- "soft," and uses 70/30 as the outer band cells and 60/40 as the secondary bands (`TraderTape.tsx`).

Range

Fixed 0-100. Theoretical extremes: 0 (every day a loss), 100 (every day a gain, or avg_loss == 0 — the code returns 100.0 in that branch). Practical range: most large-caps oscillate 30-70. Sub-30 and above-70 are the conventionally watched zones. Penny/crypto cohorts use a wider overbought threshold of 75 (vs. 70 for normal stocks) because their tape is noisier — see `tactical_state.py:191-193`.

The catch

Our stock-page RSI uses a plain 14-day simple average (`data_provider._rsi_14`), not Wilder's exponential smoothing used in charting platforms and our own tactical engine (`_wilder_rsi` in `tactical_state.py`). The simple version is slightly more reactive and will differ numerically from Bloomberg/TradingView RSI for the same ticker.

MACD

How it's calculated

Two helpers in data_provider.py do the work. `_ema` (lines 973-978) runs a recursive EMA with k=2/(period+1), seeded from the first close. `_macd` (lines 981-993) needs at least 35 daily closes, then: EMA12 minus EMA26 = the MACD line; EMA9 of that line = the signal; line minus signal = the histogram (all rounded to 4 decimals). The three values are stored on the snapshot as macd_line/macd_signal/macd_histogram. The frontend mapper (technicals.ts:27-33) passes them through unchanged, with a null fallback when absent.

How it affects judgement

When the MACD line sits above its signal line and the histogram is widening, short-term momentum is accelerating ahead of the longer-term trend — context that can support a bullish read. A line crossing below signal, or a shrinking histogram, weakens that read. Stale or choppy readings — the line hugging signal for weeks — add little either way.

What the current value signifies

Compare the MACD line to its signal line, not to zero alone. A line clearly above signal (positive, widening histogram) means recent momentum is outpacing the longer trend. Near-zero, or line below signal, means momentum is flat or fading. The absolute number matters less than its direction and its distance from signal.

Range

Unbounded, and it scales with price level. A $10 stock might show MACD of plus or minus 0.10; a $500 stock plus or minus 5. Histogram near zero = momentum neutral; growing magnitude = a strengthening trend in either direction. There are no fixed overbought/oversold thresholds the way RSI has.

The catch

Because it is price-scaled, you cannot compare raw MACD values across stocks, or even across time for the same stock after a large price move. It also lags: both EMAs are backward-looking, so it confirms trends rather than predicting reversals. One implementation detail: the EMA seeds from the raw first close rather than an SMA seed, so with only the minimum ~35 bars the EMA26 has barely converged and the earliest snapshots run noisier than a full-history MACD.

Bollinger bands

How it's calculated

A 20-day simple moving average of split- and dividend-adjusted closes (yfinance auto_adjust=True) is the midline. Upper and lower bands sit exactly 2 population standard deviations (ddof=0) above and below that midline. A companion z-score, (price − mean20) / std20, measures how many σ the last (nightly-recomputed) adjusted close sits from the 20-day mean. Recomputed nightly and stored in intel_technical_factors.

How it affects judgement

A z-score near ±2 strengthens a mean-reversion read — historically, outer-band touches have shown a tendency to revert, but that's a population base rate, not a forecast for this name. A z-score near 0 removes the volatility-stretch argument entirely. A band squeeze — both bands narrowing toward each other — points to volatility compression that often precedes a larger move, but gives no directional clue on its own. Pairs naturally with volume and RSI to assess whether a stretch is confirmed or exhausted.

What the current value signifies

Price at the upper band (z ≈ +2) means the last (nightly-recomputed) adjusted close sits roughly 2 standard deviations above its 20-day average — stretched high by recent-history standards. Price at the lower band (z ≈ −2) is the mirror. Price near the midline (z near 0) is statistically unremarkable. A very narrow band width signals a volatility low — the market is coiling.

Range

Upper and lower bands are price-denominated (e.g. $148 – $162 for a $155 stock) so they have no fixed numerical range. The z-score that accompanies them is the unit-free measure: roughly −3 to +3 in normal markets, with values beyond ±2 occurring only about 5% of trading days under the normal-distribution base rate (the 2σ rule; real returns are fat-tailed, so treat it as an idealization). Band width (upper − lower) contracts near vol lows and expands in high-vol regimes with no hard cap.

The catch

The 20-day window is short — a single gap or earnings spike inflates σ and makes the bands appear wide for the next 20 sessions, masking subsequent genuine stretches until the event rolls off.

VWAP 20 / VWAP 50

How it's calculated

For each of the past 20 (or 50) daily bars, we compute typical price = (High + Low + Close) / 3, multiply by that day's volume, sum both totals, then divide: Σ(typical × volume) / Σ(volume). The result is a volume-weighted average price over that window — not the intraday session-anchored VWAP traders quote on a live feed.

How it affects judgement

Price sitting above both lines means the average share over the last 20 and 50 days changed hands cheaper than today — the window's cost basis sits below current price. When the 20 crosses below the 50, that picture shifts and the cost basis is no longer rising under price. Neither line predicts direction; they describe where the crowd's cost basis sits relative to where price is now.

What the current value signifies

Compare the displayed VWAP to the current price. If price is above VWAP 20, most buyers over the past month are in profit relative to their average cost. If price is below VWAP 50, the majority of buyers over the past quarter are underwater relative to their cost basis.

Range

These are price-denominated, so the scale matches the stock's price. What matters is the gap: price / VWAP − 1. A 0–2% spread is tight and common; 5–10% is a meaningful divergence; beyond 15% is extended and unusual. No fixed floor or ceiling.

The catch

This is a daily-bar approximation — each bar contributes one typical-price point, not tick-level trade data. A single high-volume day (earnings, index addition) can pull the VWAP sharply and make it less representative of the broader trading period.

Typical daily move

How it's calculated

Each day's true range = max(high−low, |high−prev_close|, |low−prev_close|) — the third and fourth terms capture overnight gaps. We take a plain 14-day arithmetic average of those true ranges and report the result in dollars.

How it affects judgement

Calibrates how much noise a one-day move actually carries. A $2 move in a stock with $0.30 ATR is signal; the same $2 in a $4 ATR stock is routine. Weakens any case built on a single session's action.

What the current value signifies

The dollar amount the stock typically traverses over a full day. Compare it to the price: a $1 ATR on a $10 stock (10%) is high volatility; the same $1 on a $200 stock (0.5%) is quiet.

Range

Always ≥ 0. Mega-caps: $0.50–$5. Mid-caps: $0.30–$3. Small or volatile names: $1–$15+. Penny stocks or crisis regimes spike far higher. No upper bound.

The catch

It's a plain 14-bar average, not Wilder's smoothed EMA. So one extreme outlier day inflates the reading at full weight for 14 bars, then drops out abruptly on day 15 rather than fading gradually.

Support & resistance

How it's calculated

From the prior trading day's high (H), low (L), and close (C): the pivot P = (H + L + C) / 3. R1 = 2P − L and S1 = 2P − H. The outer levels extend the same arithmetic: R2 = P + (H − L), S2 = P − (H − L), R3 = H + 2(P − L), S3 = L − 2(H − P). These are standard classic (floor-trader) pivots. Every value is rounded to two decimal places.

How it affects judgement

Look at where the current price sits: between S1 and R1 (inside the prior day's projected range), above R1 (trading past the first resistance level), or testing S1 from above (sitting on the first support level). A narrow S1-to-R1 band means yesterday was a quiet, compressed day; a wide one means yesterday was volatile. None of this shifts the net signal on its own — read it alongside volume and trend direction.

What the current value signifies

Price above P means the stock is trading above its prior-day pivot; price below P means it is trading below it. If the current price is within a few percent of R1 or S1, that level is close enough to be worth watching for a reaction. A price far outside the R3/S3 band has moved well beyond what the prior day's range projects. These same levels are reused downstream: R1 is taken as the technical target and S1 as the technical stop (ticker_service.py:3684-3685).

Range

P, R1, S1 and the outer levels are dollar prices, so they scale with the stock. The spread R1 − S1 equals the prior day's high-minus-low range exactly, since R1 − S1 = (2P − L) − (2P − H) = H − L by construction — it is an algebraic identity, not an approximation. R3 and S3 are the widest projections and are rarely reached without a news catalyst. A useful distance gauge is the gap from the current price to the nearest level as a percent of price, or in units of that prior-day range.

The catch

These are single-day levels recalculated each morning from yesterday's bar. They reset daily and carry no memory of multi-day structure, so they miss longer-term support and resistance zones entirely.

Exhaustion count

How it's calculated

Each day, we count how many consecutive trailing bars had close > close-4-bars-ago (upside) or close < close-4-bars-ago (downside), walking back from today, capped at 9. Stored as signed `td_setup`; the page shows the absolute count plus direction.

How it affects judgement

A count near 9 tells you the one-way run is stretched by DeMark's definition — momentum may be tiring. It doesn't confirm a reversal, but it raises the bar for adding to a position in the same direction and can sharpen your entry timing on the opposite thesis.

What the current value signifies

1–4: early in a directional sequence, nothing unusual. 5–8: the run is accumulating; watch whether each new bar still clears the close from four bars back. 9 (max): the "Setup complete" reading — the trend has met DeMark's exhaustion condition and the framework flags it as stretched.

Range

0 to 9 (capped). 0 means no directional run today — either the closes are mixed, today's close exactly equals the close four bars back, or there isn't yet five bars of history. Direction is shown separately as "up" or "down". Most tickers sit between 1 and 5 on any given day; 9 is the capped maximum and the only value DeMark treats as a completed setup.

The catch

The counter resets if even one bar breaks the pattern, so a noisy stock can repeatedly reach 8 and reset without ever completing the 9 — the count alone doesn't tell you how many failed attempts preceded it.

Golden / death cross

How it's calculated

The nightly technical engine (recompute_technical_factors.py:514-522) takes the simple mean of the last 50 and last 200 split-adjusted daily closes from intel_daily_bars (`def sma(k): return float(c[-k:].mean())`). The frontend computes the cross gap itself: gap% = (sma50/sma200 - 1) x 100 (TraderTape.tsx:28; PriceChart.tsx:117-119). Positive gap means "Golden cross," negative means "Death cross." A "forming" label fires when |gap| < 1.6% (PriceChart.tsx:126), and detectCrosses (PriceChart.tsx:98-108) flags the actual crossover bar (prev<=0 && cur>0). The backend regime label itself is set in data_provider.py:533-534 (`snap.sma_cross = 'golden_cross' if snap.sma_50 > snap.sma_200 else 'death_cross'`, duplicated in recompute_chart_patterns.py:533-535), while the SMA gap percentage is computed only in the frontend. The chart-patterns nightly engine (recompute_chart_patterns.py:489-506) separately records the actual crossover day as an event with confidence 0.65 and level=sma200.

How it affects judgement

A golden cross tells you the 50-day trend has climbed above the 200-day trend — the stock's recent path is running ahead of its long-run average. That can corroborate a bullish case built on fundamentals, but only as corroboration: crosses lag, because both averages are built from past closes and are already backward-looking. A death cross in a stock you're otherwise constructive on is a friction point — it narrows the pool of momentum-driven participants and trend-following systems. The UI surfaces a golden-cross forward-win rate of 61.2% over 63 days (outcome.ts:107); the corresponding death-cross rate is not computed in the repo, so there is no symmetric figure to cite. Neither state tells you what caused the move or whether it will continue.

What the current value signifies

If the label reads "Golden cross," the 50-day average sits above the 200-day — the stock's medium-term trend is above its long-run baseline, a state most systematic and trend strategies read as constructive. "Death cross" means the reverse: the medium-term average has dropped below the long-run level, a state many quant screens flag as negative. "Forming" (gap within 1.6%) means the two averages are converging — the regime could flip within days on a move in either direction. The gap percentage shown (e.g., "50d +4.3%") tells you how entrenched the current regime is: a gap of plus or minus 10%+ is a deep, durable trend; plus or minus 1-2% is fragile and close to flipping.

Range

Categorical output: "Golden cross," "Death cross," or "[Golden/Death] cross forming." The underlying gap (sma50/sma200 - 1) x 100 has no fixed floor or ceiling. In calm large-cap markets, gaps of plus or minus 3-8% are typical. During extended bull runs (e.g., NVDA 2023-24) or crashes (e.g., March 2020), gaps of plus or minus 20-40% are observed. The "forming" zone is defined in code as |gap| < 1.6% (PriceChart.tsx:126).

The catch

Both averages are built from the same past closes, so a cross always confirms a trend that already happened — it cannot lead a turn. A stock can spend months in a death cross while grinding higher, or flash a golden cross right before a reversal. The 61.2% / 63-day figure in the UI (outcome.ts:107) is a population average; individual names, sectors, and market regimes vary widely, and the code does not define what outcome threshold "61.2%" measures.

EMA 9

How it's calculated

A 9-period exponential moving average of split-adjusted daily closes — like an SMA but weighting the most recent closes more (smoothing 2/(9+1)). Would run in the same nightly techfactors engine as our existing EMA 12/26/50.

How it affects judgement

A fast short-term trend reference. In an uptrend, price repeatedly pulling back to and holding the 9-EMA corroborates the trend is intact — it confirms what price is already doing, it's not a trigger.

Current value

This metric’s live data pipeline is under review — the method above describes how it is intended to be calculated, but the current displayed value may not yet reflect that formula. Treat it as in progress, not a finished number.

Range

Tracks the share price (a dollar level), always near recent closes; reacts faster than the 12/26/50 EMAs we already show.

The catch

Whippy on its own — flips on small moves. On daily bars it spans ~2 weeks; the *intraday* 9-EMA day-traders use needs intraday data we don't serve.

EMA 20

How it's calculated

A 20-period EMA of daily closes (same engine). Reacts faster than our SMA-20, which weights all 20 days equally.

How it affects judgement

A short-to-medium trend reference, often a firmer floor than the 9-EMA. A pullback that holds the 20-EMA while volume fades suggests selling pressure is easing — corroboration, not a buy call.

Current value

This metric’s live data pipeline is under review — the method above describes how it is intended to be calculated, but the current displayed value may not yet reflect that formula. Treat it as in progress, not a finished number.

Range

Tracks price; sits between the faster 9-EMA and the slower 50-EMA.

The catch

Reactive and lagging; we already show SMA-20 and EMA-12/26/50, so this is mainly for the retail audience that watches the 20-EMA specifically.

Stochastic RSI

How it's calculated

The stochastic formula applied to RSI instead of price — (RSI − lowest RSI) / (highest RSI − lowest RSI) over a 14-period window, scaled 0–100, then smoothed into a fast %K and a slow %D line. Same engine as our RSI-14.

How it affects judgement

A more sensitive overbought/oversold gauge than plain RSI; %K crossing up through %D from below 20 is the "momentum turning up from oversold" read — context for timing, never a buy trigger.

Current value

This metric’s live data pipeline is under review — the method above describes how it is intended to be calculated, but the current displayed value may not yet reflect that formula. Treat it as in progress, not a finished number.

Range

0–100 (the %K/%D lines); spends more time pinned at the extremes than RSI-14 because it's an oscillator built on top of another oscillator.

The catch

Its sensitivity cuts both ways — earlier reads but far more false ones than RSI-14; reactive by construction. > **Not addable honestly without intraday data:** the *session* VWAP and intraday 9-EMA the review describes reset each day and need an intraday feed (our intraday bars are a cold domain, unwired; true tape needs a paid feed). Ship the daily-bar versions above; don't fake an intraday VWAP. > **The "putting it all together" confluence setup is NOT a metric — and must not ship as a fired signal.** "When several factors align, the probability improves" is an unvalidated edge claim. Either present it as an observational *conditions-present checklist* (no probability language, like our bottom-zone checklist) or backtest it on our bars (non-overlapping, survivorship-clean) first — only a result that clears the bar earns any "probability improves" copy. See `STOCK_PAGE_VALUE_CATALOG.md` §4f.

See these metrics live on a stock dossier

QTick shows cited data and code-computed models for self-directed research. Nothing here is a recommendation, solicitation, or investment advice. Where a metric’s live data pipeline is under review, its method is described but its current value is withheld rather than shown as reliable.