# MarketPulse Engine

The reference implementation of the MarketPulse blueprint's detection layer —
**docs [01](../docs/01-architecture.md), [02](../docs/02-patterns-price-structure.md)
and [03](../docs/03-indicators.md)** turned into working code.

- **Zero dependencies.** Plain ES modules with JSDoc types.
- **Runs everywhere.** The same files run in the browser (see [`../lab.html`](../lab.html))
  and in Node (`node --test`). No build step, no bundler.
- **Pure & testable.** Indicators and detectors are pure functions — same input,
  same output — so backtest and live share one code path.

> ⚠️ Reference/education code. Paper only. Not investment advice. The delivery
> (doc 04), live execution (doc 05) and risk (doc 06) layers need a backend and
> are specified, not shipped here — except the in-memory `paperBroker` stub.

---

## Layout

```
engine/
├── types.js          Candle / Signal factories, signalId, rewardRisk
├── indicators.js     SMA EMA RSI MACD ATR Bollinger Stochastic ADX OBV VWAP
│                     Donchian Keltner CCI Williams%R ROC MFI PSAR + crossUp/Down
├── swings.js         pivot (fractal) detection for structural patterns
├── detectors/        28 detectors, one Detector contract
│   ├── ma.js         golden/death cross, EMA pullback, price cross
│   ├── osc.js        RSI, MACD, Stochastic, CCI, Williams %R, MFI, ROC
│   ├── vol.js        Bollinger bounce & squeeze, Donchian breakout, volume spike
│   ├── trend.js      ADX/DMI cross, Supertrend flip, Parabolic SAR flip
│   ├── candles.js    engulfing, hammer/shooting-star, morning/evening star
│   ├── chart.js      double top / double bottom (measured-move targets)
│   └── harmonic.js   generic XABCD engine + Gartley/Bat/Butterfly/Crab/Deep Crab + ABCD
├── engine.js         IndicatorBook (memoised) + runEngine / evaluateLast
├── strategy.js       simpleEntries + confluenceEntries (N detectors agree)
├── risk.js           position sizing + pre-trade risk gate + kill switch (docs/06)
├── backtest.js       event-driven backtester + metrics (docs/07 milestone 5)
├── paper-broker.js   in-memory idempotent paper OMS (docs/05)
├── sample-data.js    deterministic generators (randomWalk, gartleyBullish, …)
├── index.js          public barrel
└── test/             node:test suites (46 tests)
```

Every detector implements the same contract, so adding a pattern never touches
the engine, the alerts, or the broker:

```js
{ id, timeframes, warmup, params, detect(ctx) => Signal[] }
// ctx = { symbol, tf, candles, ind, params } — emit for the LAST bar only
```

---

## Quick start

**Node**

```js
import { runEngine, allDetectors, randomWalk } from "./marketpulse/engine/index.js";

const candles = randomWalk({ bars: 300, seed: 42 });
const signals = runEngine(candles, allDetectors, { cooldown: 6 });
console.log(signals.length, "signals");
```

**Detect + size + paper-fill (the whole pipeline)**

```js
import { runEngine, harmonicDetectors, gartleyBullish,
         paperBroker, clientOrderId } from "./marketpulse/engine/index.js";

const candles = gartleyBullish();
const [sig] = runEngine(candles, harmonicDetectors);      // a bullish Gartley
const broker = paperBroker({ startingEquity: 100_000 });

const stop = Math.abs(sig.suggested.entry - sig.suggested.stop);
const qty  = Math.floor(100_000 * 0.01 / stop);           // 1% risk (docs/06)
const coid = clientOrderId({ signalId: sig.id, account: "paper",
                             side: "buy", qty, ts: sig.ts });

broker.submit({ coid, symbol: sig.symbol, side: "buy",
                qty, price: sig.suggested.entry, ts: sig.ts });
broker.submit({ coid, /* …same… */ });                    // idempotent: no double-fill
console.log(broker.account());
```

**Backtest a strategy (no look-ahead)**

```js
import { backtest, allDetectors, confluenceEntries,
         randomWalk } from "./marketpulse/engine/index.js";

const candles = randomWalk({ bars: 400, seed: 5, drift: 0.0016 });
const res = backtest(candles, {
  detectors: allDetectors,
  cooldown: 6,
  riskPct: 0.01,                                   // 1% risk per trade
  selectEntries: (sigs) =>                          // confluence, not one indicator
    confluenceEntries(sigs, { require: ["osc.rsi", "osc.macd"], withinBars: 5 }),
});
console.log(res.metrics);   // { trades, winRatePct, totalReturnPct, profitFactor,
                            //   expectancy, maxDrawdownPct, sharpe, finalEquity }
```

**Browser** — open [`../lab.html`](../lab.html) (or serve the repo and visit
`/marketpulse/lab.html`). It runs the detectors **and the backtester** live
(equity curve + metrics). ES modules require `http(s)://`, not `file://`.

---

## Tests

```bash
npm run test:engine          # from the repo root
# or:
node --test "marketpulse/engine/test/*.test.js"
```

46 tests cover: indicator correctness (SMA/EMA/RSI vs known Wilder values,
ATR/Bollinger/MACD identities, cross detection), detector behaviour on planted
fixtures (a Gartley fires exactly once; random data produces none; golden cross,
RSI reclaim, volume spike and engulfing fire in the right context with valid
long/short geometry), the paper broker (deterministic `clientOrderId`,
idempotent submit, realised/unrealised P&L), risk (constant-currency sizing,
every gate limit, kill switch), strategy (confluence windows/sides/cooldown),
and the backtester (planted-Gartley win, aligned equity curve, finite metrics,
risk scaling P&L).

---

## What's implemented vs specified

| Layer | Status |
|-------|--------|
| Indicators (doc 03 §0) | ✅ coded + tested |
| Detectors — MA, oscillators, volatility/volume, **trend**, candlestick, **chart**, harmonic | ✅ 28 coded + tested |
| Detectors — full chart set (H&S, triangles…), Cypher/Shark/3-Drives | 📄 specified (docs 02–03) |
| Engine loop / backtest path | ✅ `runEngine` + `backtest` (no look-ahead) |
| Paper OMS + idempotency (doc 05) | ✅ `paperBroker` stub |
| Strategy confluence (doc 06 §2) | ✅ `simpleEntries` / `confluenceEntries` |
| Position sizing + risk gate + kill switch (doc 06) | ✅ `risk.js` (coded + tested) |
| Backtester + metrics (doc 07 M5) | ✅ `backtest.js` (equity curve, win%, PF, maxDD, Sharpe) |
| Alerts: web/mobile/email/WhatsApp/Telegram (doc 04) | 📄 specified (needs backend) |
| Live broker adapters (doc 05) | 📄 specified (needs backend) |

Next milestones are in [`../docs/07-claude-build-prompts.md`](../docs/07-claude-build-prompts.md).
