# RLXBT — Canonical Specification & AI Knowledge Base (v3.0)

<!-- SECTION: AI_CONTEXT -->
```json
{
  "product": "RLX Backtester (rlxbt)",
  "what_it_is": "A Rust quant backtesting + reinforcement-learning engine exposed to AI agents over MCP or REST. It is available as a visual native macOS app and a headless Docker Server Edition for Ubuntu.",
  "you_are": "An AI agent driving this engine on the user's behalf via MCP tools.",
  "transport": "MCP over SSE",
  "endpoint": "${RLXBT_BASE_URL}/api/mcp/sse (local default: http://127.0.0.1:8142/api/mcp/sse)",
  "server_agent_guide": "https://rlxbt.com/server-agent.md",
  "tool_count": 30,
  "signal_convention": "1 = Long, -1 = Short, 0 = Flat",
  "data_format": "OHLCV + timestamp (unix seconds) CSV, or binary .chunk/.fchunk",
  "do_not": "Do not assume a Python library, expose port 8142 publicly, request secrets in chat, give RLXBT exchange credentials, or assume RLXBT placed an order."
}
```
<!-- END_SECTION: AI_CONTEXT -->

> [!IMPORTANT]
> This document is the single source of truth for LLMs/agents using RLXBT. The
> product is an **agent-driven app**, not a Python library. You accomplish
> everything by calling the MCP tools below — never by writing engine code.

---

## 1. How to connect

The running desktop app or Server Edition serves an MCP server:
- **SSE endpoint:** `${RLXBT_BASE_URL}/api/mcp/sse` (local default: `http://127.0.0.1:8142/api/mcp/sse`)
- A stdio proxy binary (`rlx-mcp`) is also available for clients that need stdio.

Every tool is also a plain REST endpoint on the local engine (e.g. `POST /api/run-backtest`) if you cannot use MCP.

For Docker/Ubuntu, read https://rlxbt.com/server-agent.md first. Keep the API on
loopback/VPN/TLS and send `Authorization: Bearer ${RLXBT_API_KEY}` from secret
configuration. Never paste the license or API key into prompt history. Start each
session with `/api/health`, `/api/endpoints`, `/api/ai-instructions`, and
`/api/strategy-schema` instead of guessing the running engine's capabilities.

**Always call `get_ai_instructions` first** — it returns the system context plus the columns/indicators in the currently loaded dataset, so you build valid strategies.

---

## 2. The standard workflow

1. **Load data** → `load_dataset { path }`. Then `get_ai_instructions` / `get_dataset_info` to learn the available columns.
2. **Author a strategy** → `get_strategy_schema`, draft rules, then `validate_strategy` BEFORE running (catches syntax/compile errors).
3. **Backtest** → `ai_run_backtest { strategy_json }`. Every run is auto-archived as a report. Pull detail with `get_metrics`, `get_trades`, `get_equity_curve`.
4. **Stress-test (critical)** → `walk_forward` (out-of-sample; returns `wfe` = avg OOS / avg IS) and `monte_carlo` (returns `risk_of_ruin_pct`). A single backtest is NOT evidence of an edge.
5. **Optimize** (optional) → `optimize_exits` to sweep TP/SL/trailing.
6. **Reinforcement learning** (optional) → `rl_train` (single asset) or `rl_train_multi` (portfolio). Then `rl_predict` / `rl_predict_multi` for the current signal.
7. **Curate** → `list_reports`, `pin_report` the winners, `delete_report` the rest.

---

## 3. Tool catalog (30)

### Data
- `load_dataset { path, features_path?, intrabar_path? }` — load CSV or binary `.chunk` by path (mmap for 10GB+). `intrabar_path` adds higher-resolution bars for precise TP/SL.
- `get_dataset_info` — rows, time range, price range, column list.
- `get_features` — available indicator columns + values.
- `convert_dataset { input, output, features? }` — CSV → binary `.chunk` (bars) or `.fchunk` (features).

### Strategy authoring
- `get_strategy_schema` — the JSON schema for rules. Call before authoring.
- `generate_template { template_type? }` — starter `rules` or `graph` template.
- `validate_strategy { strategy_json }` — parse + compile with the engine's parser. Returns `{status: valid|error}`. ALWAYS run before backtesting.

### Backtesting & analytics
- `ai_run_backtest { strategy_json }` — run a backtest; auto-archives a report.
- `get_dashboard_data` — full last result (metrics + equity + trade stats).
- `get_metrics` — total return, Sharpe, Sortino, max drawdown, profit factor, …
- `get_trades { side?, limit?, offset? }` — trade list.
- `get_equity_curve`, `get_drawdown_curve`, `get_monthly_returns`, `get_graph`.

### Robustness & optimization
- `walk_forward { strategy_json, train_size?, test_size?, step_size?, anchored? }` — OOS cross-validation; `wfe` ~1 robust, ≪1 overfit.
- `monte_carlo { strategy_json, iterations? }` — bootstrap trades; `risk_of_ruin_pct`, return/drawdown percentiles, VaR/CVaR.
- `optimize_exits { entry_rules, exit_rules, tp_range, sl_range, ts_range }` — best exit parameters.

### Reports (curation)
- `list_reports`, `save_report`, `open_report { id }`, `pin_report { id, pinned, name? }`, `delete_report { id }`, `clear_unpinned_reports`.

### Reinforcement learning
- `rl_train { episodes?, window_size?, reward_type?, train_split?, lr?, gamma?, seed? }` — train a DQN on the loaded data. Auto-saves the model as a report (`kind=rl`), returns `report_id`, IS/OOS metrics, reward curve, and action distribution. `reward_type ∈ portfolio|log|sharpe|calmar|risk`.
- `rl_predict { id, bars? }` — current signal (long/short/flat) + confidence from the model's latest window, or an inline `bars` batch.
- `rl_train_multi { symbols:[{name,path}], … }` — portfolio DQN across up to 4 symbols.
- `rl_predict_multi { id, symbols? }` — per-symbol signal; reads each symbol's saved path if `symbols` omitted.

### App control
- `get_ai_instructions` — system prompt + current dataset columns. Call first.
- `execute_ui_action { action }` — steer the app the user watches: `switch_mode_dashboard|reports|rl`, `refresh_data`, `export_report`, `scroll_to_<section>`.

---

## 4. Invariants (follow strictly)

### 4.1 Data schema
CSV columns, in order: `timestamp` (unix seconds), `open`, `high`, `low`, `close`, `volume`, then any indicator columns (e.g. `RSI_14`, `BB_Upper`, `BB_Lower`). The first column is always the timestamp.

### 4.2 Strategy rules JSON
Two accepted shapes:
```json
// Simple (expression strings)
{ "entry_long": "RSI_14 < 35 || close < BB_Lower",
  "exit_long":  "RSI_14 > 55 || close > BB_Upper",
  "entry_short":"RSI_14 > 70", "exit_short":"RSI_14 < 45" }

// List-based (dashboard shape)
{ "entry_rules": [{ "condition": "RSI_14 < 30", "direction": 1 }],
  "exit_rules":  [{ "condition": "RSI_14 > 55", "direction": 0 }],
  "take_profit": 100.0, "stop_loss": 50.0 }
```
- `direction`: 1 = Long, -1 = Short, 0 = exit either side.
- Conditions are expressions over dataset columns with `&&`, `||`, `<`, `>`, `==`, and helpers like `cross_over(a, b)`. Only reference columns that exist (check `get_features`).

### 4.3 Signal state
Position state is `1` (Long), `-1` (Short), `0` (Flat). A change in target signal closes the current position and may open a new one.

---

## 5. Operating rules (do this)

1. **Orient first.** Call `get_ai_instructions`; only use indicator columns that actually exist in the loaded dataset. Referencing a missing column (e.g. `EMA_26` when it isn't there) silently yields zero trades.
2. **Validate before running.** `validate_strategy` → fix errors → `ai_run_backtest`.
3. **Never trust a single backtest.** Always confirm with `walk_forward` (look at `wfe` and OOS return) and `monte_carlo` (look at `risk_of_ruin_pct`). Report the OOS result, not the in-sample one.
4. **RL needs enough training.** Few episodes produce degenerate policies (e.g. always-long). Use ≥50 episodes, inspect the returned `actions` distribution (long/flat/short) and the IS-vs-OOS gap before trusting a model. Prefer `train_split` < 1.0 so there is a held-out test.
5. **Curate.** Pin robust runs, delete the rest — the user runs hundreds.
6. **Be honest about uncertainty.** Surface overfitting (OOS ≪ IS) and high risk of ruin instead of presenting a strategy as a sure thing.

---

## END OF SPECIFICATION
