Skip to main content
Glama
ankitjha67

Quant Desk TradingView MCP

by ankitjha67
README.md
# Quant Desk — TradingView MCP

**A systematic multi-strategy analysis engine that follows your TradingView chart.**

Reads whatever chart you have open, fetches that instrument's history from free public
sources, evaluates **358 published quantitative models** against it, and produces one
auditable verdict with a confidence score and a concrete position size.

Runs entirely on your machine. No TradingView subscription, no market-data vendor, no paid
API. Works on the **free TradingView tier**.

```bash
python start.py
```

---

## What it does

| | |
|---|---|
| **358 models** across 16 categories, every one with a paper citation | ~1s full scan |
| **233 independent families** — the honest unit of diversification | family-weighted consensus |
| **Confidence engine** — 8 components, hard vetoes, empirical calibration | 0–100 score |
| **Position sizing** — capital 1,000 → 1,000,000, risk-first | refuses rather than guesses |
| **Vectorised backtest** with walk-forward validation | 358 models in ~2.5s |
| **Pine Script v6 export** for all 174 price-only models | numerically verified |
| **Any LLM provider** via one saved key | 14 providers, zero dependencies |

## The design principle

**A model that cannot run honestly reports unavailable rather than degrading to a price
proxy and voting anyway.**

142 of the 358 models need an options chain, fundamentals, a peer universe, order-book
depth, on-chain or news data. Without that feed they stand down. Every screen shows
*"N voting of M available of 358 in library"* — never "358 models agree".

22 models approximate their published method from substituted data. Each is labelled a
**proxy**, states exactly what was substituted, and counts for 40% of a vote.

### Why family weighting

Counting BUY votes treats 30 moving-average variants as 30 independent opinions. Under
that scheme whichever style is most numerous wins every vote, and *adding models makes the
bias worse*. Models sharing a `family` split one family's vote.

---

## Quick start

```bash
git clone https://github.com/ankitjha67/TradingView-MCP.git
cd TradingView-MCP
python start.py
```

`start.py` checks Python, installs what's missing, verifies the engine loads, detects any
IDE (Antigravity, VS Code, Cursor, Windsurf, Claude Desktop, Zed) and offers to wire up MCP,
then launches the dashboard. No IDE found means the dashboard, which needs none.

Non-technical walkthrough: **[EASY_SETUP_GUIDE.md](EASY_SETUP_GUIDE.md)**

## Interfaces

**The monitor follows your chart. Nothing else.** It analyses the symbol and interval you
have open and reports on that instrument — if the reading is neutral, "stand aside" is the
answer, not a prompt to go looking elsewhere.

Scanning a wider universe is a **separate, explicitly-invoked tool**
(`tools/scan_universe.py`). It is never run as part of monitoring.

| Interface | Command | Scope |
|---|---|---|
| **Live monitor** | `./run_monitor.sh` · `run_monitor.bat` | your open chart only |
| Streamlit dashboard | `python start.py` | one symbol at a time |
| Universe scan | `python tools/scan_universe.py --capital 50000` | 51 instruments, opt-in |
| Pine export | `python tools/emit_pine.py --symbol AAPL --interval 1d` | one symbol |
| Verify Pine | `python tools/verify_pine.py --symbol SPY --bars 2500` | all 174 translations |
| MCP server | auto-configured into detected IDEs | on request |

### Keeping the monitor alive

`run_monitor.sh` (macOS/Linux) and `run_monitor.bat` (Windows) set `PYTHONPATH` and run the
monitor detached from the shell that launched it. Both accept the same flags:

```bash
./run_monitor.sh --capital 50000 --currency INR --risk 1.0
```

It rewrites `tv_active_chart.md` and `tv_active_chart.json` at every bar close, and follows
you automatically when you switch symbol or interval.

## Monitoring cadence

Re-analysis is aligned to the **close of the bar on your chart's interval** — every minute
on a 1m chart, every 15 minutes on 15m, daily on daily. Changing symbol or interval
re-analyses immediately. Stale feeds (weekends, closed markets) are detected, labelled and
backed off rather than re-reported as live.

Models read the last *closed* bar; re-running mid-bar re-reads a forming candle, so the
signal flickers then settles. One stable reading per bar is what you act on.

When the feed goes stale — weekend, closed market, halted symbol — the monitor says so and
switches to a fixed 10-minute re-check so it picks up the reopen promptly, rather than
sitting on the interval's own cadence and going blind for a full day.

## Data

Free public sources, tried in order: **Binance** (crypto) → **Yahoo Finance** → **Stooq**.
Eleven intervals from 1-minute to monthly. Crypto, US and international equities, indices,
forex, commodities.

TradingView is used only to observe *which symbol and interval you are looking at* — no
TradingView data API is called, which is why the free plan suffices.

## Confidence engine

| Component | Weight | Question |
|---|---:|---|
| Family diversity | 20% | How many *independent ideas* agree |
| Conviction | 18% | Signal strength |
| Agreement | 18% | How one-sided the vote is |
| Concordance | 14% | Do structurally opposed categories agree |
| Regime alignment | 12% | Are agreeing models suited to conditions |
| Signal stability | 8% | Persistent, or flipped on this bar |
| Data quality | 6% | Coverage, depth, proxy share |
| Reward geometry | 4% | Does the target clear transaction costs |

**Hard vetoes** override any score: neutral consensus, agreement below 55%, fewer than 4
independent families, target move below 2× round-trip cost, turnover too thin to fill,
or an *inverted historical calibration* on that instrument.

**Empirical calibration** measures what the score has actually been worth: it buckets past
bars by signal strength and reports realised forward returns. Sometimes the answer is
*"has NOT reliably tracked forward returns here"* — and that becomes a veto.

## Position sizing

```
quantity = (capital × risk% × confidence_multiplier) ÷ (entry − stop)
```

Sizing from the **stop distance** holds risk constant across instruments. Then constrained
by lot granularity (crypto fractional, whole shares, NIFTY 75 / BANKNIFTY 15, forex micro
lots), exchange minimum order value, exposure cap, and available margin.

When a trade can't be taken it **refuses with the exact remedy** — *"Tradeable at ₹638,545
capital or 6.39% risk per trade"* — rather than silently falling back to a minimum position
that would exceed your stated risk limit.

## Pine Script export

All **174** price-only models export to Pine v6, plus a family-weighted consensus
indicator. Every translation is checked against an independent re-implementation of Pine
semantics — verified across equities, ETFs, gold and crypto on multiple intervals.

Models that cannot be faithfully translated (feed-dependent, or online training loops with
no Pine equivalent) are **not approximated**; they're listed with the reason.

## Documentation

| File | Contents |
|---|---|
| [EASY_SETUP_GUIDE.md](EASY_SETUP_GUIDE.md) | Non-technical install, start to finish |
| [STRATEGY_CATALOG.md](STRATEGY_CATALOG.md) | All 358 models, citations, data requirements |
| [PRD.md](PRD.md) | Requirements and honest status |
| [CONTEXT.md](CONTEXT.md) | Architecture — read before changing `core/quant/` |
| [walkthrough.md](walkthrough.md) | What was rebuilt and why |

---

---

## Agent desk (second opinion)

The engine's rule is that an LLM explains what the models found and never originates a
signal. **[TauricResearch/TradingAgents](https://github.com/TauricResearch/TradingAgents)**
is the opposite: a team of LLM agents — fundamentals, news, sentiment and technical
analysts, then a bull/bear debate and a three-way risk review — argues its way to a
BUY/SELL/HOLD.

Both hold at once, because the desk is wired as a *second reader*, not a voter:

| | |
|---|---|
| Sets direction | never — `compute_consensus` is untouched |
| Changes the confidence score | never |
| Sizes a position | never — sizing stays with the calibrated engine |
| Disagrees with the models | adds a caution, which **halves** position size |
| Agrees | says so, changes nothing |

Measured on AAPL daily: consensus BUY +0.166, score 57.1, grade C in every case; size
×0.325 with no desk, with an absent desk, and with an agreeing desk — and ×0.163 with a
disagreeing one. Direction and score never moved.

**Why include it at all.** Every run reports ~142 of 358 models standing down for
*"missing data feed"* — options chains, fundamentals, on-chain, news, sentiment. Those are
exactly the inputs TradingAgents has. It is not a better price model; it reads a different
part of the problem, and the one thing it is trusted to do is make you take less when it
sees something the price series cannot show.

### It runs in its own virtualenv, deliberately

`tradingagents` resolves **pandas 3.0.5**; this engine is 21 modules and 358 models on
**pandas 2.3.3**, and `pyproject.toml` sets no upper bound — so a plain `pip install`
silently upgrades pandas underneath the library. The install also pulls chainlit, redis,
textual and ~40 opentelemetry instrumentation packages.

So the desk lives in `.venv-agents/` and is reached over a subprocess with JSON on the
wire. Each side keeps the dependency tree it wants; the cost is one process spawn per
debate, which already takes minutes.

```bash
python tools/setup_agent_desk.py          # create the venv and install
python tools/setup_agent_desk.py --check  # status, changes nothing
```

It reuses whatever LLM provider is configured in Settings — including NVIDIA NIM, which
`tradingagents` does not name but reaches as an OpenAI-compatible endpoint.

### Cadence and cost

A debate is many model calls over several minutes, and this engine re-analyses at every
bar close. So a verdict is **cached per (ticker, trading date)** and never started
automatically — the Live Signal tab has a button. News and fundamentals do not change
between two 1-minute bars, which is the resolution the debate actually reads at. Once run,
every refresh that day reuses it, including the monitor.

---

## Statistical significance

Every backtest reports a **t-statistic** beside its Sharpe:

```
t = annualised Sharpe x sqrt(years observed)
```

A Sharpe on its own says very little. 1,500 one-minute bars is six trading days, and
over six days a Sharpe of 8 carries t ≈ 1.0 — indistinguishable from luck. The engine
now says so instead of ranking it first.

The convention and the 1.96 threshold come from the replication catalogue in
**[paperswithbacktest/awesome-systematic-trading](https://github.com/paperswithbacktest/awesome-systematic-trading)**,
which publishes both figures for 1,687 replicated papers and notes plainly that half of
them fail the bar. The identity was verified against all 61 of its published rows before
being trusted here (largest deviation 0.12, pure rounding) — and is re-verified by
`tools/sync_replication_catalogue.py`, which stores the table locally as JSON and warns
if upstream ever changes convention.

```bash
python tools/sync_replication_catalogue.py            # refresh the catalogue
python tools/sync_replication_catalogue.py --compare  # scale against our library
```

### What it changes

`compare_strategies` reports `significant` and `significantly_losing` next to the
ranking, the Backtest Lab shows a t-stat column and warns when nothing clears the bar,
and the performance report adds a caveat when the headline Sharpe is undetermined.

Measured on real data at the time of writing:

| | window | ranked | clear t ≥ 1.96 | significantly losing | best t |
|---|---|---|---|---|---|
| SBIN 1m | 0.015 yr | 174 | **0** | 157 | −0.01 |
| AAPL 1d | 5.95 yr | 183 | **0** | 18 | 1.42 |

Not one model in the library clears significance on either instrument, and on the
1-minute chart 157 of 174 are significantly *negative*. That is the point of measuring
it: the top row of a Sharpe-sorted table reads like a discovery, and usually is not.

For scale, across the catalogue's 61 published replications the best Sharpe is **3.39**
and the median **1.06** — each measured over 16+ years. A model here reporting Sharpe 8
over six days is not four times better than the best replicated paper in the set.

---

## Research reading (not a data feed)

A panel in Live Signal and a CLI for reading public news and pages about the instrument
you are looking at, routed via
**[Panniantong/Agent-Reach](https://github.com/Panniantong/Agent-Reach)**.

```bash
python tools/research.py --doctor            # what this machine can read
python tools/research.py                     # news for the open chart
python tools/research.py --url https://...   # read one public page
```

**It deliberately does not feed the models, and cannot.** Every voting model implements
`score(f) -> pd.Series` over the whole frame — that historical path is what the
backtester replays, what the confidence engine calibrates, and what earns a t-statistic.
A web read returns what a page says *now*; there is no way to ask it what was being said
on each of the previous 1,499 bars. A model fed this way could fill the last element of
the series and nothing else, so it could never be backtested or clear the significance
bar. Marking `DataNeed.NEWS` satisfied on that basis would flip ten sentiment models to
"voting" while leaving them unverifiable — the exact failure the `DataNeed` enum exists
to prevent.

A test asserts nothing under `core/quant/` imports it, so the separation is enforced
rather than promised. `core/research.py` sits outside the engine for the same reason.

### Zero-configuration sources only

Agent-Reach tags each channel with a tier. Tier 0 needs no configuration; tier 1 and
above work only through a personal logged-in session or exported cookies — its own notes
say Reddit's anonymous API is blocked and only the logged-in route remains. Driving those
from an unattended monitor would mean acting on your accounts against the platforms'
terms, so the ceiling is enforced in code (`MAX_TIER = 0`), not left to a docstring.

| | channels | here |
|---|---|---|
| tier 0 — no config | web (Jina Reader), rss, github, youtube, v2ex, exa_search | **used** |
| tier 1+ — session or cookies | reddit, twitter, xueqiu, bilibili, xiaohongshu, instagram, facebook, linkedin | refused |

> **Note on installing it.** `pip install agent-reach` fetches a *different* project —
> PyPI's package of that name is `jgalea/agent-reach`, unrelated to this one. Install
> from source: `pip install git+https://github.com/Panniantong/Agent-Reach`.

### If you want social data properly

The honest route is to record these readings forward into a dated archive and wait for
history to accumulate — not to backfill from a live endpoint, whose results are ranked by
today's engagement and silently omit whatever has since been deleted. That is survivorship
bias baked into the input, and a backtest built on it would be worse than no backtest.

## Credits

This project builds on **[atilaahmettaner/tradingview-mcp](https://github.com/atilaahmettaner/tradingview-mcp)**
by Ahmet Taner Atila, which provides the MCP server, TradingView screener and scanner
services, exchange symbol lists, and the news/sentiment integrations. Licensed MIT; the
original copyright is preserved in [LICENSE](LICENSE).

The `core/quant/` engine — strategy library, consensus, confidence, sizing, backtester,
Pine export and their verification — is added on top.

Category coverage for macro, rates, commodity carry and options income follows the family
layout of **[alphakit](https://github.com/ankitjha67/alphakit)**.

The agent desk wraps **[TauricResearch/TradingAgents](https://github.com/TauricResearch/TradingAgents)**
by Tauric Research, run unmodified in its own environment and consulted as a second
opinion.

The Sharpe significance standard, and the replication figures used to calibrate
against it, come from **[paperswithbacktest/awesome-systematic-trading](https://github.com/paperswithbacktest/awesome-systematic-trading)**.

Research reading is routed through **[Panniantong/Agent-Reach](https://github.com/Panniantong/Agent-Reach)**
by Panniantong, restricted to its zero-configuration channels.

## Licence

MIT — see [LICENSE](LICENSE). Original work © 2025 Ahmet Taner Atila.

---

**Not investment advice.** Model output is research output. The backtester routinely shows
most models failing to beat buy-and-hold, and the calibration check sometimes reports that
a high score has been worth nothing on a given instrument. Those results are displayed, not
hidden. Never risk money you cannot afford to lose.

TDQS

B3.4/5.0

Scored across 38 tools

Disambiguation3/5

Several tools overlap in purpose (e.g., egx_sector_scan vs egx_sector_scanner, bollinger_scan vs rating_filter, multiple volume/candle scanners, and several analysis variants like coin_analysis, multi_timeframe_analysis, combined_analysis, multi_agent_analysis). Descriptions offer explicit cross-references and clarify the intended use for many pairs, but boundaries remain fuzzy for a large set. An agent could still misselect without careful reading.

Naming Consistency3/5

All names use snake_case, but the pattern is not fully predictable: some are prefixed by domain (egx_, futures_, stock_), others are generic, and suffixes vary (scan, scanner, screener, analysis). A single get_ prefix appears, and near-duplicate names like egx_sector_scan and egx_sector_scanner break consistency. Still readable overall.

Tool Count2/5

38 tools is excessive for a single server, exceeding the 25+ threshold and risking tool overload. While the broad trading domain (crypto, stocks, EGX, futures, options, news, backtesting) explains some breadth, many tools are overlapping scanners or analysis variants that could be consolidated. The count makes selection unnecessarily difficult.

Completeness4/5

Coverage spans technical indicators, screeners, news sentiment, backtesting, options, futures, and market overviews, forming a broad trading analysis toolkit. Some gaps exist (e.g., dedicated historical OHLCV retrieval, portfolio/watchlist management), but core workflows appear well supported. Minor missing operations are workaroundable.

Maintenance

ActivityActive
ResponsivenessNo issues