> ## 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.

# Go binary

> Build, distribute, and manage the compiled NOVOSKY binary. All ML models, configs, and the license are embedded at compile time — customers receive a single executable.

## Overview

The Go binary (`novosky_go`) is a compiled, dependency-free runtime of the NOVOSKY trading bot. It reads `config.json` and `.env` from disk at startup, but everything else — ML models, scalers, metadata, `ml_config.json`, `strategy_params.json`, and the license — is **baked into the binary** at build time.

**What customers receive:**

| File          | Description                                         |
| ------------- | --------------------------------------------------- |
| `novosky_go`  | The compiled binary (contains all models + license) |
| `config.json` | User-editable runtime configuration                 |
| `.env`        | Secrets and external service credentials            |

The repo includes `env.customer.example` as a minimal template for the customer `.env` — it only contains the fields a customer needs (MT5 API, Telegram, optional AI assistant). The developer `.env.example` contains additional fields for HF Hub, Supabase, GitHub, and other owner-only services.

No Python, no `models/` directory, no Hugging Face Hub, no pip install.

***

## Prerequisites

| Requirement                | Purpose                                     |
| -------------------------- | ------------------------------------------- |
| Go 1.24+                   | Build the binary                            |
| Python + trained models    | Required before packing (`make train`)      |
| `onnxruntime` pip package  | Auto-detects `libonnxruntime.so` at runtime |
| `onnxmltools` + `skl2onnx` | Export risk/SLTP models to ONNX             |

***

## Build flow

Every binary build follows the same two-step process.

<Steps>
  <Step title="Pack embedded assets">
    Copy model files, configs, and optionally the license into `internal/embedded/` for `//go:embed`:

    ```bash theme={null}
    bash scripts/pack_embedded.sh            # dev build (placeholder license)
    bash scripts/pack_embedded.sh --license  # production (copies license.json)
    ```

    This populates `internal/embedded/models/` with all `.onnx` and scaler JSON files, plus `ml_config.json` and `strategy_params.json`.
  </Step>

  <Step title="Build the binary">
    ```bash theme={null}
    # Dev build (no license key — license check skipped automatically)
    go build -o novosky_go ./cmd/novosky/

    # Production build (license key embedded at compile time)
    go build \
      -ldflags="-X github.com/mokatific/novosky/internal/license.masterKey=YOUR_SECRET" \
      -o novosky_go ./cmd/novosky/
    ```
  </Step>
</Steps>

***

## Running

```bash theme={null}
./novosky_go --dry      # dry-run — no real orders, logs only
./novosky_go            # live trading
./novosky_go --dir /path/to/config   # explicit directory for config.json and .env
```

The binary reads `config.json` and `.env` from the same directory as the executable by default, or from `--dir`.

***

## Embedded assets

Model files and configs are embedded at compile time using Go's `//go:embed`. The `scripts/pack_embedded.sh` script copies files from the repo into `internal/embedded/` before each build.

### What is embedded

| Embedded file                                 | Source                                       |
| --------------------------------------------- | -------------------------------------------- |
| `models/ensemble_rf/xgb/lgb.onnx`             | `models/` (auto-exported by trainer)         |
| `models/position_rf/xgb/lgb.onnx`             | `models/` (auto-exported by trainer)         |
| `models/risk_lgb.onnx`                        | `models/` (via `export_onnx_regression.py`)  |
| `models/sltp_sl_lgb.onnx`, `sltp_tp_lgb.onnx` | `models/` (via `export_onnx_regression.py`)  |
| `models/*_scaler.json`                        | `models/` (via `export_scalers.py`)          |
| `models/*_metadata.json`                      | `models/` (feature names, training metadata) |
| `ml_config.json`                              | Repo root                                    |
| `strategy_params.json`                        | Repo root                                    |
| `license.json`                                | Generated by `cmd/licgen`                    |

### What stays on disk (user-editable)

| File          | Why on disk                                         |
| ------------- | --------------------------------------------------- |
| `config.json` | User tunes risk profile, SL/TP, filters per account |
| `.env`        | Secrets (MT5 API token, Telegram, Supabase)         |

### Model format

| Model group         | Input name      | Output name(s)               | Type           |
| ------------------- | --------------- | ---------------------------- | -------------- |
| Ensemble / Position | `"X"`           | `"label"`, `"probabilities"` | Classification |
| Risk / SLTP         | `"float_input"` | `"variable"` (shape `[1,1]`) | Regression     |

<Note>
  The `leaves` library is not used — it only supports LightGBM format v3, and trained models are v4. All models are converted to ONNX for Go inference.
</Note>

***

## ONNX runtime library

The binary loads `libonnxruntime.so` dynamically at startup.

### Bundle into the binary (recommended for distribution)

Use the `--bundle-ort` flag and `bundle_ort` build tag to embed `libonnxruntime.so` directly into the binary (\~22 MB extra). Customers need zero external files:

```bash theme={null}
bash scripts/pack_embedded.sh --license --bundle-ort
go build -tags bundle_ort \
  -ldflags="-X github.com/mokatific/novosky/internal/license.masterKey=YOUR_SECRET" \
  -o novosky_go ./cmd/novosky/
```

`pack_embedded.sh --bundle-ort` auto-discovers the `.so` from the Python `onnxruntime` pip package. Override with `ONNXRUNTIME_LIB=/path/to/libonnxruntime.so` if needed.

### Standard build (unbundled)

In standard builds (no `bundle_ort` tag), the binary searches at startup:

1. `ONNXRUNTIME_LIB` environment variable
2. Same directory as the binary (`libonnxruntime.so` next to `novosky_go`)
3. System `LD_LIBRARY_PATH`
4. Python's `onnxruntime` pip package (auto-glob, dev convenience)

For distributing a standard binary, ship `libonnxruntime.so` next to `novosky_go`, or set `ONNXRUNTIME_LIB` in the customer's `.env`.

***

## License system

The license controls which MT5 account numbers can trade and until when. It is embedded in the binary at build time — customers cannot inspect or modify it.

### How it works

1. Owner creates an `accounts.json` with MT5 account numbers and expiry dates
2. Owner runs `licgen` to produce a signed `license.json`
3. Owner runs `pack_embedded.sh --license` to embed it
4. Owner builds `novosky_go` with the production key
5. Customer receives `novosky_go` — the license is inside the binary

### License format

```json theme={null}
{
  "key": "NOVA-2026-XYZ",
  "accounts": {
    "123456": { "start": "2026-05-13", "end": "2026-08-13" },
    "1234567": { "start": "2026-05-13", "end": "2027-05-13" }
  },
  "signature": "<hmac-sha256-hex>"
}
```

The HMAC-SHA256 signature covers `key` + all account entries (sorted). Any edit to dates or accounts invalidates the signature — customers cannot extend their own license.

Omit `"end"` for an account entry to make it never expire.

### Generating a license

```bash theme={null}
# 1. Build licgen with the production key
SECRET="your-secret-here"
go build \
  -ldflags="-X github.com/mokatific/novosky/internal/license.masterKey=$SECRET" \
  -o licgen ./cmd/licgen/

# 2. Create accounts.json (keep private — never ship this file)
cat > accounts.json <<'EOF'
{
  "123456":  {"start": "2026-05-13", "end": "2026-08-13"},
  "1234567": {"start": "2026-05-13", "end": "2027-05-13"}
}
EOF

# 3. Generate signed license.json
./licgen -key "NOVA-2026-XYZ" -f accounts.json -o license.json
```

The `licgen` output:

```
license.json written → license.json
Key: NOVA-2026-XYZ
Accounts (2):
  123456   2026-05-13 → 2026-08-13
  1234567  2026-05-13 → 2027-05-13
```

### License expiry behavior

When a customer's license expires, the bot refuses to start:

```
license for account 123456 expired on 2026-08-13 — renew at novosky.app
```

To renew: generate a new `license.json` with updated dates, run `pack_embedded.sh --license`, rebuild, and send the customer a new binary.

### Dev builds

In dev builds (no `-ldflags` key), license validation is skipped automatically. The placeholder `license.json` (`{}`) committed to git is harmless — the bypass happens before the file is even read.

***

## Post-retrain workflow

After `make train` or `python scripts/retrain.py`:

<Steps>
  <Step title="Export scalers and regression models">
    ```bash theme={null}
    python scripts/export_scalers.py          # PKL scalers → JSON
    python scripts/export_onnx_regression.py  # risk/SLTP .txt boosters → .onnx
    ```
  </Step>

  <Step title="Re-pack embedded assets">
    ```bash theme={null}
    bash scripts/pack_embedded.sh             # dev
    bash scripts/pack_embedded.sh --license   # production (with license.json)
    ```
  </Step>

  <Step title="Rebuild binary">
    ```bash theme={null}
    go build -o novosky_go ./cmd/novosky/
    # or with production key:
    go build -ldflags="..." -o novosky_go ./cmd/novosky/
    ```
  </Step>

  <Step title="Verify">
    ```bash theme={null}
    ./novosky_go --dry
    ```
  </Step>
</Steps>

<Note>
  Ensemble and position ONNX files are auto-exported by the Python trainer. You only need to manually run the two export scripts for the risk and SLTP regression models.
</Note>

***

## Telegram commands

The Go binary supports the same Telegram commands as the Python bot:

| Command           | Description                                     |
| ----------------- | ----------------------------------------------- |
| `/status`         | Account balance, equity, daily P/L              |
| `/positions`      | Open positions with ticket, direction, lot, P/L |
| `/pnl`            | Weekly P/L summary                              |
| `/news`           | USD economic calendar (medium/high impact)      |
| `/latency`        | Broker API round-trip latency                   |
| `/pause`          | Block new trade entries                         |
| `/resume`         | Re-enable trading                               |
| `/close <ticket>` | Close one position by ticket number             |
| `/closeall`       | Close all open positions                        |
| `/closeprofit`    | Close all positions in profit                   |
| `/closeloss`      | Close all positions at a loss                   |
| `/help`           | Show all commands                               |

Free-text messages (not commands) are routed to the AI assistant if `assistant.enabled` is set in `config.json`.

***

## AI assistant

The AI assistant is an OpenAI-compatible tool-calling agent configured via `.env`. It can query account status, list positions, close trades, fetch news, and run MT5 API calls directly.

```env theme={null}
AI_BASE_URL=https://models.github.ai/inference   # or OPENAI_BASE_URL
AI_API_KEY=your_api_key                          # or OPENAI_API_KEY or GITHUB_TOKEN
```

If `AI_BASE_URL` is not set, it defaults to GitHub Models. The model can be overridden per-account in `config.json`:

```json theme={null}
"assistant": { "enabled": true, "model": "gpt-4o" }
```

***

## Source layout

| Path                                | Purpose                                                     |
| ----------------------------------- | ----------------------------------------------------------- |
| `cmd/novosky/main.go`               | Entry point — signal handling, retry loop                   |
| `cmd/licgen/main.go`                | License generator (owner only, never shipped)               |
| `internal/bot/bot.go`               | Main trading loop                                           |
| `internal/ml/`                      | ONNX ensemble, position, risk, SLTP predictors              |
| `internal/embedded/embed.go`        | `//go:embed` declarations for all model assets              |
| `internal/config/`                  | config.json, ml\_config.json, strategy\_params.json loaders |
| `internal/api/`                     | MT5 REST API client                                         |
| `internal/telegram/`                | Telegram command bot                                        |
| `internal/assistant/`               | AI assistant (OpenAI-compatible, tool-calling)              |
| `internal/license/`                 | HMAC-SHA256 license validation                              |
| `internal/supabase/`                | Supabase REST client                                        |
| `internal/logger/`                  | Trade, signal, and daily CSV logger                         |
| `scripts/pack_embedded.sh`          | Copy models + configs into `internal/embedded/`             |
| `scripts/export_scalers.py`         | Export PKL scalers → JSON                                   |
| `scripts/export_onnx_regression.py` | Export risk/SLTP LGB → ONNX                                 |
