Nepse Decode · Chart & signals · rule-based, no black boxes

Signal Systems Methodology

Backtest numbers are produced by tools/build-signals.js; the three signal pages are built by tools/build-signal-pages.js (the sole source of truth for those pages); the Live forward record on each page is rendered from live_track_record in the signal JSON, rewritten daily after close by tools/track-live-signals.py. This page states every rule, formula, and assumption exactly as coded, so any figure can be traced and reproduced. Educational research — not investment advice. Past performance does not predict future results.

1. Data

2. Data sanitisation

The feed contains bars with impossible OHLC — e.g. NBL on 2013-05-09 printed open 532 against a 143–145 traded range (an unadjusted corporate-action open). Such bars corrupt ATR, stops, and the corporate-action detector, so:

  1. Bars with non-positive OHLC, high < low, or malformed dates are dropped; dates de-duplicated.
  2. If open or close falls outside the bar's own [low, high], it is clamped into the range. Every repair is counted and published (bars_repaired).

3. Corporate-action adjustment

NEPSE enforces a ±10% daily circuit, so an overnight gap beyond ±10% is a bonus/split/rights adjustment, not a real move. On the sanitised series, if open / prevClose is outside [0.90, 1.10], all prior bars are reverse-adjusted: prices × ratio, volume ÷ ratio, turnover unchanged. No new entries are taken on the adjustment bar itself. Adjustment count is published.

Honest limitation: the factor is inferred from price continuity, not from the official corporate-action record — the engine's largest known error source.

4. Indicators (all causal — bar i uses data up to i only)

5. Entry rules

Entries are taken at the signal day's close. One position per symbol; max 10 concurrent positions. All systems require 20-day average turnover above Rs 10 lakh.

Momentum — Donchian-50 breakout + trend filter

Trend Relay — SMA20/SMA50 golden cross + volume

Reversal — oversold bounce

6. Exits, stops, targets

7. Position sizing and costs

8. How each statistic is calculated

Let V0 = Rs 1 Cr, Vf = final portfolio value (cash + open positions at last close − exit costs), T = 2.15 years (the published backtest window, filled from the live data below).

FigureFormula
Total return %(Vf − V0) / V0 × 100
CAGR %(Vf / V0)^(1/T) − 1, ×100
Capital multipleVf / V0
Win rate %winning closed trades ÷ all closed trades × 100 (win = net P&L > 0)
Profit factorΣ winning Rs ÷ |Σ losing Rs|
Avg win / loss %mean Rs P&L of winners (losers) ÷ mean entry notional × 100
Avg holding daysmean holding days (entry day = 0)
Max drawdown %deepest peak-to-trough fall of the weekly marked-to-market equity curve
Sharpe / Sortinomean / downside-deviation of weekly portfolio returns × √52
Benchmark CAGRNEPSE index buy & hold over the same window
Alpha %/yrsystem CAGR − benchmark CAGR

The equity curve marks the full portfolio to market weekly (cash + open positions − exit costs). Alerts are positions still open at the dataset's last date. The ledger lists every closed trade with entry/exit prices, stop, targets, exit reason, Rs and % P&L, and holding days (most recent 500 in the download).

9. Known limitations

  1. Corporate-action factors are inferred, not official.
  2. Fixed Rs 10L notional understates what compounding would show.
  3. Cash dividends are not received.
  4. Entries at the signal day's close assume the close is tradable; only the 0.5% cost models friction.
  5. One realised history — regimes change; nothing here predicts the future.
Reproducibility: node tools/build-signals.js --no-fetch rebuilds the published JSONs from the checked-in cache — every stat above recomputes exactly (only generated_at changes).

10. Live forward record — paper trades from real alerts

Each signal page also carries a Live forward record: a forward paper-trade ledger built from real alerts, not from the backtest.

Data: daily NEPSE OHLCV, corporate-action adjusted. …. Educational only — not investment advice.