> ## Documentation Index
> Fetch the complete documentation index at: https://docs.novosky.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Codebase layout, the three-file rule, strict training order, lane discipline, and the invariants that keep the live bot and backtester in sync.

## Repository layout

The repo is a Turborepo monorepo. The Python bot lives at the root; the website and shared design system are under `apps/` and `packages/`.

```
apps/
  website/               SvelteKit public website (@novosky/website)
    src/
      lib/components/    UI components (Navbar, Hero, MacWindow, …)
      routes/            SvelteKit routes + API endpoints
    svelte.config.js
    vite.config.ts
    package.json

packages/
  design/                Shared design system (@novosky/design)
    src/lib/tokens.css   @theme tokens + reusable component classes
    src/lib/components/  Base Svelte components (Button, MacWindow, …)
    tokens.css           Re-export shim for CSS imports
  configs/               Shared ESLint + Prettier configs (@novosky/configs)
    eslint.js            Base ESLint flat config (TS + prettier)
    eslint-svelte.js     Svelte ESLint extension
    prettier.js          Shared Prettier config

turbo.json               Turborepo task pipeline
package.json             Workspace root (yarn workspaces)
.yarnrc.yml              Yarn Berry — nodeLinker: node-modules

trading/
  bot.py                Main trading loop — all execution logic
  logger.py             Structured logging helpers
  supabase.py           Supabase write helpers
  telegram_commands.py  Telegram command handler

ml/
  feature_engineering.py   62 features + ATR-aware labeling
  ensemble_trainer.py      RF + XGB + LGB signal model training
  ensemble_predictor.py    Signal model inference (majority vote)
  position_trainer.py      Position model training (EXIT/HOLD/ADD)
  position_predictor.py    Position model inference
  sltp_trainer.py          Dynamic SL/TP LightGBM training
  sltp_predictor.py        Dynamic SL/TP inference
  risk_trainer.py          Risk multiplier LightGBM training
  risk_predictor.py        Risk inference: equity-state → [0.10, 1.25]
  model_trainer.py         Shared training utilities + ONNX export
  model_predictor.py       Shared inference base class
  data_preparation.py      Dataset loading + IS/OOS split
  calibration_check.py     Model calibration diagnostics
  news_features.py         News event feature computation
  shap_analysis.py         SHAP feature importance analysis
  hf_hub.py                Hugging Face Hub push / pull / tag
  tune/
    hyperparams.py         Optuna signal model tuning
    position.py            Optuna position model tuning

backtest/
  run.py                 Config-faithful bar-by-bar backtester

scripts/
  onboarding.py              First-time setup wizard (8-step)
  weekly_optimize.py         Autonomous 13-phase weekly pipeline
  retrain.py                 Standalone retrain dispatcher (all 4 models)
  sweep.py                   Unified config parameter sweep (signal + pos)
  optimize_loop.py           Iterative SHAP → tune → retrain → OOS loop
  config_sync.py             Config authority helpers (imported by other scripts)
  notify.py                  Send manual Telegram notification
  export_scalers.py          Export PKL scalers → JSON (required for Go binary)
  export_onnx_regression.py  Export risk/SLTP LGB .txt → .onnx (required for Go binary)
  pack_embedded.sh           Copy models + configs into internal/embedded/ for go:embed

models/
  model_compat.json      Feature hash + model paths — compatibility gate
  risk_metadata.json     Risk model metadata

config/
  brokers.json           Broker registry (symbol, spread, leverage, pip_value)

config.json              Runtime config (active broker, risk, SL/TP, filters)
ml_config.json           ML config (62 features, model paths, labeling params)
trading.py               Entry point — calls trading/bot.py
scripts/retrain.py       Training dispatcher — always trains all 4 models
backtest.py              Entry point — calls backtest/run.py

# Go binary (cmd/ and internal/)
cmd/
  novosky/main.go        Go binary entry point — signal handling, retry loop
  licgen/main.go         License generator (owner only — never shipped to customers)

internal/
  bot/bot.go             Main Go trading loop
  ml/                    ONNX predictors (ensemble, position, risk, sltp) + scalers
  embedded/              go:embed declarations — all model assets baked in at build time
    embed.go             //go:embed directives
    license.json         Placeholder ({}); overwritten by licgen before production build
    models/              Populated by pack_embedded.sh (gitignored)
  config/                config.json, ml_config.json, strategy_params.json loaders
  api/                   MT5 REST API client
  telegram/              Telegram command bot
  assistant/             AI assistant (OpenAI-compatible, tool-calling)
  license/               HMAC-SHA256 license validation
  supabase/              Supabase REST client
  logger/                Trade, signal, and daily CSV logger
```

### Monorepo commands

```bash theme={null}
yarn dev               # dev server for all apps
yarn dev:website       # website only
yarn build:website     # production build (website)
yarn check:website     # svelte-check (website)
yarn lint              # ESLint all packages
yarn format            # Prettier all packages
```

***

## The three-file rule

Any ML feature change touches exactly three files:

1. **`ml/feature_engineering.py`** — add the feature computation
2. **`ml_config.json` → `features` array** — add the name in the correct position
3. **Retrain all 4 models** — Signal, Position, SLTP, Risk (in that order)

Changing any one without the others breaks inference. The `models/model_compat.json` file stores a hash of the feature list. On startup, `EnsemblePredictor` verifies the hash against the current `ml_config.json`. A mismatch raises `ModelCompatibilityError` immediately.

***

## Strict training order

Models must always be trained in this order:

```
Signal → Position → SLTP → Risk
```

| Model    | Depends on                               |
| -------- | ---------------------------------------- |
| Signal   | Nothing (first)                          |
| Position | Signal model paths (saved to disk)       |
| SLTP     | Signal + position models (saved to disk) |
| Risk     | Completed backtest using SLTP models     |

Training out of order produces either import errors or silent data contamination in the Risk model's training labels.

***

## Backtester / live parity

`backtest/run.py` must always mirror `trading/bot.py`. Every change to execution logic in the bot must be reflected in the backtester, and vice versa.

Key parity invariants:

* Same feature engineering (`ml/feature_engineering.py`)
* Same model inference chain (calibrated pkl → ONNX → raw pkl)
* Same position sizing formula
* Same equity-aware SL cap
* Same circuit breakers and gates
* Same position model evaluation timing

If these diverge, backtest scores become unreliable as live performance predictors.

***

## Lane discipline

The codebase has two clearly separated lanes:

| Lane             | Who                        | What                                               |
| ---------------- | -------------------------- | -------------------------------------------------- |
| Client/user lane | Trader on their machine    | Pull approved models, run `trading.py`             |
| Developer lane   | Developer on their machine | Retrain, optimize, validate OOS, publish to HF Hub |

Clients should never retrain. The live trading host should stay simple — it does not need a GPU or the full ML dependency stack (just `pip install -r requirements.txt` is fine).

***

***

## Go binary — embedded asset system

The Go binary uses Go's `//go:embed` directive to bake all ML models, scalers, and configs into the compiled binary at build time. The `scripts/pack_embedded.sh` script copies the necessary files into `internal/embedded/` before each build.

```
internal/embedded/
  embed.go              //go:embed declarations
  license.json          Placeholder in git; replaced before production build
  models/               Populated by pack_embedded.sh (gitignored)
    ensemble_rf.onnx    ← copied from models/
    ensemble_xgb.onnx
    ensemble_lgb.onnx
    position_rf.onnx
    ...
    ensemble_scaler.json
    ...
  ml_config.json        Copied from repo root
  strategy_params.json  Copied from repo root
```

Because everything is embedded, customers do not need a `models/` directory, Hugging Face Hub access, or any Python tooling. See [Go binary](/developer/go-binary) for the full build and license reference.

***

## Config files

Two config files govern all behavior:

| File             | What it controls                                              | Tracked in git |
| ---------------- | ------------------------------------------------------------- | -------------- |
| `config.json`    | Runtime params: symbol, risk, SL/TP, profile, filters, broker | Yes            |
| `ml_config.json` | Features, model paths, labeling, training params              | Yes            |

Both are committed to git. When `weekly_optimize.py` updates `config.json`, the change appears in git history. This makes every optimization run fully auditable.
