Agentic Trading Lab
Talk to agents, and test trading ideas. Try AI trading agents on real market data with no code required.
AI translation
Real-time crypto scanner for 3-Drive harmonic patterns with RSI divergence and Bollinger Band squeeze detection across top 100 tokens.
FinanceHTML · JavaScriptGitHub @CxL1247OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
I built a real-time crypto scanner that detects the 3-Drive harmonic pattern across the top 100 tokens using Coinbase data(Binance fallback). It scans 4H, 1H, and 30M timeframes and confirms reversals via RSI divergence. Setups are ranked by divergence strength with auto-refresh so the system runs continuously.
Taken from the repository README
Loading the full README.
Read the full README ↗A real-time crypto scanner across the top 100 tokens by market cap — pattern detection, live rankings, and order book reads, all in one page.
Detects four setups across 4H/1H/30M, continuously via auto-refresh, and reads the Trader XO trend state alongside them:
[@btc_charlie] Trader XO Macro Trend Scanner as configured on the author's chart: fast EMA 12 vs slow EMA 50 on close. Trend is Bull while fast > slow, Bear while below, and an arrow is the cross itself. Evaluated on closed candles only (the still-forming candle is dropped), so an arrow can't appear and then vanish. Shown per timeframe (4H / 1H / 30M) in the token popup with how long ago the current trend's arrow printed, the EMA spread, price vs EMA 200, and a chop warning when the trend has flipped 3+ times in the last 20 candles. The script's own default slow EMA is 25 — change XO_SLOW_EMA in src/detectors.js (or pass opts.slow) to match a different chart.Each signal gets a composite confidence score (support/resistance confluence, FVG confluence, volume confirmation at the formation candle, the token's own historical hit rate), trend-context filtering (flags lower-timeframe signals fighting the 4H trend), and weekend liquidity flagging.
Top 25 gainers/losers across 15m/30m/1h/4h windows. Price ticks live via WebSocket; the comparison window is recalculated against real wall-clock time on every render (not frozen at scan time), so it stays accurate no matter how long the tab's been open. Each token's candle-series price is cross-checked against its independently-sourced ticker price — anything that disagrees by more than 3% (a likely wrong-instrument match from an ambiguous ticker) is dropped rather than shown.
Every scanned token ranked by live RSI, 1H or 4H, sortable. Shown as a plain number with a mini position bar — no "overbought/oversold" labels. Includes market-wide summary stats (avg RSI, overbought/oversold counts, hottest token).
Real resting bid/ask depth per token — not leveraged positions, not predicted liquidation levels. Sums bid vs. ask notional within ±3% of price to derive an imbalance score, and surfaces the single largest resting order (the "wall") on each side, with its exact price and size. Two columns: strongest buy pressure vs. strongest sell pressure. Shows which exchange each row's data actually came from. Snapshot per scan cycle, not continuously streamed — full order book depth for ~100 tokens at once isn't practical to stream live.
Search any scanned token to open a floating popup combining Pattern, RSI, Range, and Order Book data for that one token in one place. Minimize to a summary pill, maximize to a larger panel, or close — price ticks live while open.
The journal's + log trade form is built to be quick rather than a wall of textboxes:
Every trade card has a ✎ edit button (next to ✕ delete). It swaps that card for the same form, pre-filled, right where the card was.
Dollar P&L (journal, Weekly Balance, Weekly Summary, CSV, the trade card) now includes real costs, not just the raw price move:
Two sections: Three Drives (the classic harmonic pattern signals, unrelated to anything below) and Weekly Summary. The standalone RSI + Order Book + Trend confluence scoring engine has been retired — the tab now pairs pattern signals with a read of your own trading, not a second signal generator.
A read of the Trading Journal, not a signal: figures and a bar chart for the current week's logged trades, always visible under Three Drives (no scan needed).
jTradePnL), so the numbers agree with the journal everywhere they're shown.Search, Alerts and Journal live in the top bar, so they're one click away. Press / anywhere (outside a text field or dialog) to jump to token search. The bell shows how many trend arrows have printed since you last opened Alerts. On narrow screens search collapses to an icon and the BTC/ETH prices drop to a second row; the ⋯ menu keeps the less-used settings (theme, market, range engine, auto-scan, hit rate).
When a Trader XO arrow prints on 4H or 1H (30M is opt-in), the app shows an in-app popup and, if you've enabled them, a desktop notification. No email involved. Configure under Alerts → Settings → Trend shifts, including a list of tokens to mute (or hit "mute" on any popup).
Log trades (entry/SL/TP/leverage, R-multiple, scale-outs) and open trades get a live-tracked floating widget showing real-time P&L against SL/TP, independent of the current scan universe. Auto-resolves against live candles when TP/SL is hit.
Candles are fetched directly from Binance and Bybit by the browser first. Both send permissive CORS on their public market-data endpoints, and a visitor's own IP is not subject to the cloud-range blocking that stops the serverless functions reaching them — so this both restores two sources that otherwise contribute nothing and removes a function invocation per fetch. If the direct calls fail for any reason (CORS, network, an unlisted symbol, a short payload) the proxy path below runs exactly as before.
Ticker and order book data, and any candle fetch the direct path could not serve, go through the proxy: KuCoin, OKX, Binance, and Bybit in parallel per request — whichever responds first wins. In practice, Binance and Bybit block requests from many cloud/serverless IP ranges (a documented, general restriction — not specific to any one region), so KuCoin is often the primary effective source on serverless deployments, with OKX as secondary. This is also why nothing in the app is hardcoded to a single exchange: if one gets blocked mid-scan, the others silently cover for it.
src/detectors.js, a dependency-free script shared by the page, the tests, and the signals endpointnetlify/functions/proxy.js) as a CORS proxy + exchange-race layer to the exchange APIsnetlify/functions/send-alert.js)ALERT_ALLOWED_RECIPIENTS), and refuses to send at all until that is configured/signals endpoint below exists to close that gapThe header carries an FRVP | V1 toggle. It picks which range engine the scanner uses, and persists per browser. FRVP is the default.
FRVP (range_frvp_v2) is a Fixed Range Volume Profile in the literal sense — the
profile is computed once and then frozen:
A Gann box is reported alongside every frozen range — 0 at VAH, 1 at VAL, so 0.5 is
the midpoint. A strong reclaim candle can close past 0.5, in which case
breakevenPassedAtEntry says so rather than the level being quietly dropped.
Because a profile can only be frozen once price has left the box, FRVP publishes fewer setups than V1 — every one it does publish has a completed structure behind it. Boxes that are still contained appear as a dashed FORMING badge with the provisional bounds and no value-area numbers; there is nothing to trade yet, and the badge says so.
V1 (detectRange) is the original: it profiles from the anchor to the current
candle and recomputes every scan, so its value area drifts as candles arrive. Kept on
the toggle so the two can be compared on the same charts.
Each engine has its own constants (RANGE_* and RANGE_V2_*), so tuning one never
moves the other.
FRVP uses 100 rows and a 90% value area, matching a real TradingView FRVP setup
(Row Size 100, Value Area Volume 90) rather than V1's 30 / 70%. Row size alone moves
the levels a long way, so this is not cosmetic: on the window below, V1's defaults put
VAH 28 USD lower.
Validated by inversion on ETHUSDT.P 1h (OKX). Searching every (P1, P2) pair over 300 real bars for the window that reproduces a labelled chart lands on an 88-bar window, 2026-08-21 17:00 → 2026-08-25 08:00:
| computed | labelled chart | delta | |
|---|---|---|---|
| VAH | 2531.85 | 2532 | −0.15 (−0.006%) |
| POC | 2427.91 | ~2430 | −2.09 |
| VAL | 2399.74 | ~2405.5 | −5.76 (3 rows of 1.94) |
The VAH agreement confirms both the distribution maths and the settings. The residual on POC and VAL is about 2–3 rows, which is the same order as two other known sources of noise: reading a level off a screenshot, and which exchange's volume is used (the same window off Binance instead of OKX moves POC and VAL by ~2 USD). It is therefore not treated as an algorithm difference — a pairwise value-area expansion was tried and moved VAL only 1.7 closer while selecting a different window, which is fitting to noise rather than evidence.
RANGE_V2_MAX_BARS is 120 because that labelled window is 88 bars; a 60-bar cap
rejected the very setup the engine exists to find.
Anchor selection is discretionary. P2 is chosen by eye on the chart, so the shelf rule
is an approximation of a judgement call, not a reproduction of it. For a specific window,
frvpFromAnchors(highs, lows, volumes, p1, p2) returns the profile for exactly those two
anchors — reachable over HTTP via the anchors field on the signals endpoint.
src/detectors.js holds the pure indicator and pattern math — RSI, EMA, Bollinger bandwidth,
swing/pivot detection, 3-Drive, FVGs, S/R levels, the volume profile and the range detector.
It touches no DOM, no network and no storage.
The page loads it before its inline script and every export lands on the global object, so call
sites read exactly as they always did. The same file is require()d by the tests and by the
signals function, which means there is one copy of the math rather than three that can drift.
POST /.netlify/functions/signals runs the detectors over a candle series you supply and returns
what they found. It is stateless, stores nothing, and makes no exchange calls of its own.
POST /.netlify/functions/signals
{ "symbol": "BTC", "tf": "ONE_HOUR", "candles": [{ "t":…, "o":…, "h":…, "l":…, "c":…, "v":… }, …] }
Send { "series": [ … ] } instead to analyse up to 25 at once; one bad series is reported in place
and does not fail the batch. Valid timeframes are SIX_HOUR (4H candles), ONE_HOUR and
THIRTY_MINUTE, and a series needs at least 40 candles — the same floor the scanner uses.
The caller supplies the candles on purpose. Binance and Bybit block many serverless IP ranges, so a scan-it-yourself endpoint would be both slow and partially blind, while a caller running elsewhere is not restricted.
Every response carries detectorVersion, a hash of the detector code and its thresholds as loaded.
Tune a constant and the hash changes, so recorded signals separate into clean cohorts instead of a
silently mixed sample — which is what makes an honest hit rate possible later.
Optional env: SIGNALS_TOKEN (required as x-signals-token when set) and APP_ORIGIN to narrow CORS.
No framework and no install — plain Node:
node test/detectors.js # detection math
node test/signals.js # signals endpoint
node test/security.js # proxy allowlist + alert hardening
node test/backtest-xo.js # the Trader XO edge lab below (offline — no network)
node test/backtest-donchian.js # the Donchian breakout edge lab (offline — no network)
node test/journal-edit.js # journal validation + edit rules (src/journal-edit.js)
node test/market-activity.js # quiet-market logic (src/market-activity.js)
node test/blacklist.js # token blacklist rules (src/blacklist.js)
scripts/backtest-xo.js is a standalone backtest for the Trader XO arrow, run locally on
your own machine (this repo's own dev/CI sandbox can't reach Binance):
node scripts/backtest-xo.js --symbol BTCUSDT --interval 1h --days 365
node scripts/backtest-xo.js --symbol ETHUSDT --interval 4h --days 730 --market spot
node scripts/backtest-xo.js --symbol SOLUSDT --interval 1h --days 180 --stopPct 1.5 --r 2 --out sol-1h.csv
It downloads real historical candles from Binance's public API, finds every arrow across
that history using calcEMA straight from src/detectors.js (zero drift from what the app
itself runs — detectTraderXO only ever reports the latest arrow, which is right for a live
app but useless for a backtest), and reports:
--stopPct / --r) — win rate and
expectancy in R if you mechanically traded every arrow.XO_CHOP_WINDOW/XO_CHOP_FLIPS) — the one
filter the live app already offers, so it's worth checking whether it actually helps.Pass --out results.csv to get every arrow and its outcome as a CSV, for the tool doing the same job the journal's own P&L math does. This is a mechanical simulation for research, not a full backtest engine — no fees, funding, or slippage (see the journal's own Fee/Funding settings for what those cost in this app), one position at a time, and a same-candle stop+target hit is scored as the stop (worst case, since intra-candle order isn't knowable from OHLC alone). It answers "does this signal have any edge at all", not "what would I have made".
scripts/backtest-donchian.js tests a channel breakout (a candle closes beyond the highest high
/ lowest low of the prior N candles) across many coins at once, run locally because this
repo's sandbox can't reach Binance. It exists to answer one question before any alert is built:
does this rule still have an edge after fees, slippage and funding?
node scripts/backtest-donchian.js --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,XRPUSDT --interval 4h --days 730
node scripts/backtest-donchian.js --symbols BTCUSDT,ETHUSDT,SOLUSDT --interval 1d --days 1460 --entry 20,55 --exit 10,20
node scripts/backtest-donchian.js --symbols BTCUSDT,ETHUSDT,SOLUSDT --out donchian-trades.csv
How it is built, and what to read in the output:
--atrMult x ATR at entry), not a fixed percentage, and the stop is checked
intrabar with gap-aware fills. Exit is the stop or a close back through the prior --exit-candle channel.--fee, --slip, --funding): round-trip cost divided by the stop
distance, so a tight stop visibly makes fees expensive. Slippage (0.02%) and funding (0.01% / 8h) are
assumptions; change them to match what you actually pay.--entry 10,20,55). Prefer settings whose neighbours also look fine; the single best cell is usually luck.--lev (default 14x), and the leverage that would keep liquidation twice as far as the stop.Limits worth remembering: coins move together, so pooled trades are not independent and the t-stat is
generous; entries and exits are at candle closes with no order-book model; and win rate is the wrong
number to judge a breakout system by (they win roughly a third of the time). The offline tests prove
the mechanics (no look-ahead, correct fills, correct cost math, squeeze parity with calcBBSqueeze)
and that the lab rejects a random walk while detecting real momentum. They cannot prove the rule works
on real markets. Only running it against real candles can.
Live prices come from Binance's WebSocket, opened directly from your browser. The scanner doesn't depend on
that: candles and the token list are fetched server-side by the Netlify proxy. So on a network where the browser
can't reach Binance (the console shows net::ERR_NAME_NOT_RESOLVED for stream.binance.com), the scan works but
the header would show "—" and the pill would never reach "live".
The app now picks a source by what the browser can actually reach:
live.live · gate. Subscriptions go out in small batches; if Gate refuses a batch because one coin
isn't listed (it doesn't say which), the batch is split in half until that coin is isolated and dropped. Any
other error is retried a few times and never blacklists a coin. The 24h change % stays at its scan value
(Gate's units aren't verified here).polling · 30s. It bridges until Gate delivers
its first tick, and stays on only for coins Gate doesn't list. It never overwrites a coin Gate is streaming.Binance is re-probed every 30s while a fallback is active and takes over again as soon as it connects (the Gate socket is closed). The floating open-trade cards use whichever source is active. The pill tooltip says which source is feeding prices and how many coins are on the slower path.
Not covered: features that open their own Binance connection, such as the live order-book depth in the token popup, still need Binance to be reachable.
A pill in the top bar (Market · normal / QUIET / ACTIVE) tells you whether trading is unusually thin right now, so you can size down or wait. When the market turns quiet you also get a toast and, if enabled in your alert settings, a desktop notification (and the alert sound, if you've turned that on). Leaving a lull only shows a quiet toast. Click the pill to refresh it.
How it decides (logic in src/market-activity.js, unit-tested in test/market-activity.js):
The thresholds are untested defaults, reasonable guesses, not calibrated on history. Expect to tune them
(MA_DEFAULTS in src/market-activity.js) after a few weeks of seeing how often it fires.
Mark tokens you've decided not to trade, with your reasons, and the app reminds you wherever the token shows up. A blacklisted token is flagged, never hidden: it still appears everywhere it normally would, so you see "I said no to this, and why" at the moment you'd otherwise be tempted.
BTCUSDT, btc-usdt and BTC/USDT all mean BTC).It changes nothing about detection: signals and alerts still fire for blacklisted tokens, they just carry the flag.
The list lives in this browser's local storage (clearing site data erases it, and it doesn't sync between devices).
Corrupt or hand-edited storage is cleaned on load instead of breaking the app. Rules live in src/blacklist.js.