← Back to Plugins
Tools

Trading Agent

reachanihere By reachanihere 👁 58 views ▲ 0 votes

Autonomous paper-trading OpenClaw plugin for Trading 212 Practice (mean reversion + LLM judge, asymmetric daily band)

GitHub

Install

npm install
npm

Configuration Example

tickers:
  - AAPL
  - MSFT
  - NVDA
  - GOOGL
  - AMZN

README

# trading-agent

An autonomous paper-trading OpenClaw plugin for Trading 212 Practice. Runs continuously during NYSE hours, decides trades from a rule-based strategy, has them sanity-checked by an LLM judge, and executes through hard-coded risk caps. Logs every cycle to SQLite.

> **This is paper trading.** No real money is moved. The goal is to *measure* whether a simple agentic strategy can hit a +1%/day target over many sessions โ€” not to make money.

---

## The "soul"

The agent's behavior is governed by an **asymmetric daily P&L band**:

```
Downside:   hard stop at -0.5%      โ†’ flatten + halt for the day
Upside:     no ceiling              โ†’ let winners compound
Target:     +1% by EOD              โ†’ measured, not enforced
Trailing:   once peak โ‰ฅ +1%, stop ratchets to break-even (0%)
            once peak โ‰ฅ +2%, stop trails at (peak - 1%)
```

So a successful day ends โ‰ฅ +1%. A bad day ends at -0.5%. A great day can end at +5% with the trailing stop quietly protecting the floor along the way.

Why asymmetric: large-cap stocks routinely swing 0.5โ€“1% intraday in either direction. Capping the upside would cut off the only way the math works.

---

## Architecture

```
NYSE-aware daemon โ”€โ”€ every 30s โ”€โ”€โ”
                                  โ–ผ
              โ”Œโ”€โ”€โ”€ Strategy (pure code, e.g., mean reversion) โ”€โ”€โ”€ candidate signals
              โ”‚                                โ–ผ
              โ”‚                    โ”Œโ”€โ”€โ”€ News (cached headlines)
              โ”‚                    โ””โ”€โ”€โ”€ LLM judge (Opus 4.7 1M)  โ”€โ”€ decisions (APPROVE/REJECT/SHRINK)
              โ”‚                                โ–ผ
              โ”‚              RiskGuard (caps + asymmetric band)  โ”€โ”€ hard-clamped orders
              โ”‚                                โ–ผ
              โ””โ”€โ”€โ”€โ”€โ”€โ”€ Trading 212 Practice (market orders) โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                                                  โ–ผ
                                                          SQLite ledger
                                                          (every cycle, every decision, every fill)
```

Key boundary rules:

| Module | Responsibility | I/O? |
|---|---|---|
| `strategy/*` | Pure: `(prices, positions) โ†’ signals` | None |
| `riskGuard` | Pure: enforces caps + band | None |
| `judge/*` | Calls LLM, validates JSON | LLM only |
| `trading212Client` | Account / quotes / orders | T212 only |
| `news/headlines` | Fetch + cache | OpenClaw `web_search` only |
| `ledger` | Write every cycle/order/fill | SQLite only |

The LLM **cannot bypass risk caps**. Its output is JSON; RiskGuard runs after and clamps. It also cannot smuggle in non-whitelisted tickers โ€” strategies only see whitelisted prices, and RiskGuard rejects any order whose ticker isn't in the whitelist.

---

## Quick start

### 1. Prerequisites

- Node.js 22+ (24 recommended; uses built-in `node:sqlite`)
- An OpenClaw install
- A Trading 212 account (Practice mode is enough โ€” no funding required)

### 2. Install

```bash
git clone https://github.com/<you>/trading-agent.git
cd trading-agent
npm install
npm run build
```

### 3. Get a T212 Practice API key

1. Open the Trading 212 app or web client.
2. Switch the account to **Practice** mode.
3. Settings โ†’ API โ†’ generate a key.
4. Set it as an environment variable:

   ```powershell
   $env:T212_API_KEY = "your-practice-key"
   ```

   On macOS/Linux:

   ```bash
   export T212_API_KEY="your-practice-key"
   ```

### Trading 212 Public API reference

Trading 212's Public API v0 is currently beta and is available at:

| Environment | Base URL |
|---|---|
| Demo / paper trading | `https://demo.trading212.com/api/v0` |
| Live / real money | `https://live.trading212.com/api/v0` |

Do not commit API credentials. For manual `curl` calls, keep the key and secret in environment variables:

```bash
export T212_API_KEY="your-api-key"
export T212_API_SECRET="your-api-secret"
```

PowerShell:

```powershell
$env:T212_API_KEY = "your-api-key"
$env:T212_API_SECRET = "your-api-secret"
```

The official API uses HTTP Basic auth, with the API key as the username and the API secret as the password:

```bash
curl -s -u "$T212_API_KEY:$T212_API_SECRET" \
  "https://demo.trading212.com/api/v0/equity/account/summary"
```

#### Pies API lookup

The Pies endpoints are deprecated by Trading 212, but still documented and operational. The safe read-only flow is:

```bash
# 1. List pies for the account.
curl -s -u "$T212_API_KEY:$T212_API_SECRET" \
  "https://live.trading212.com/api/v0/equity/pies"

# 2. Fetch detailed holdings/settings for a returned pie id.
curl -s -u "$T212_API_KEY:$T212_API_SECRET" \
  "https://live.trading212.com/api/v0/equity/pies/<PIE_ID>"
```

In the manual lookup that informed this README, the only authenticated account calls used were:

| Method | Endpoint | Purpose |
|---|---|---|
| GET | `/api/v0/equity/pies` | List all pies for the account |
| GET | `/api/v0/equity/pies/{id}` | Fetch detailed instruments/settings for each returned pie |

No order, create, update, duplicate, or delete endpoint was used.

#### Documented Trading 212 endpoints

| Method | Endpoint | Notes |
|---|---|---|
| GET | `/api/v0/equity/account/summary` | Account cash/investment summary |
| GET | `/api/v0/equity/metadata/exchanges` | Exchange metadata |
| GET | `/api/v0/equity/metadata/instruments` | Tradable instruments |
| GET | `/api/v0/equity/orders` | Pending orders |
| GET | `/api/v0/equity/orders/{id}` | Pending order by id |
| DELETE | `/api/v0/equity/orders/{id}` | Cancel pending order |
| POST | `/api/v0/equity/orders/limit` | Place limit order |
| POST | `/api/v0/equity/orders/market` | Place market order |
| POST | `/api/v0/equity/orders/stop` | Place stop order |
| POST | `/api/v0/equity/orders/stop_limit` | Place stop-limit order |
| GET | `/api/v0/equity/positions` | Open positions |
| GET | `/api/v0/equity/history/dividends` | Dividend history |
| GET | `/api/v0/equity/history/exports` | List generated CSV reports |
| POST | `/api/v0/equity/history/exports` | Request CSV report generation |
| GET | `/api/v0/equity/history/orders` | Historical orders |
| GET | `/api/v0/equity/history/transactions` | Account transactions |
| GET | `/api/v0/equity/pies` | List pies; deprecated |
| GET | `/api/v0/equity/pies/{id}` | Pie details; deprecated |
| POST | `/api/v0/equity/pies` | Create pie; deprecated |
| POST | `/api/v0/equity/pies/{id}` | Update pie; deprecated |
| DELETE | `/api/v0/equity/pies/{id}` | Delete pie; deprecated |
| POST | `/api/v0/equity/pies/{id}/duplicate` | Duplicate pie; deprecated |

### 4. Create runtime config

The plugin reads from `~/.openclaw/trading-agent/`:

```bash
mkdir -p ~/.openclaw/trading-agent
cp config.example.yaml ~/.openclaw/trading-agent/config.yaml
cp tickers.example.yaml ~/.openclaw/trading-agent/tickers.yaml
```

Edit `tickers.yaml` to your whitelist:

```yaml
tickers:
  - AAPL
  - MSFT
  - NVDA
  - GOOGL
  - AMZN
```

(Default `config.yaml` is sensible; tweak only if you want to.)

### 5. Install into OpenClaw

This is a real OpenClaw plugin โ€” it uses `definePluginEntry` from `openclaw/plugin-sdk/plugin-entry`, registers four tools (`trading_start`, `trading_stop`, `trading_status`, `trading_flatten`), and auto-starts the daemon on OpenClaw boot if a config file is present.

Install the local build into your OpenClaw install:

```bash
openclaw plugins install ./
```

(Run from the repo root; `openclaw plugins install <path>` reads `package.json` `openclaw.extensions` to find the plugin entry.)

After install, restart OpenClaw. The agent boots automatically because `openclaw.plugin.json` declares `"activation": { "onStartup": true }` โ€” but only if `~/.openclaw/trading-agent/config.yaml` exists. If it's missing, the plugin loads but the daemon stays idle until you call `trading_start`.

### 6. Talk to the agent from chat

Once installed, ask OpenClaw via any configured channel (Telegram, WhatsApp, etc.):

- **"What's my trading P&L today?"** โ†’ calls `trading_status`
- **"Stop the trading agent"** โ†’ calls `trading_stop`
- **"Flatten my trading positions"** โ†’ calls `trading_flatten`
- **"Start the trading agent"** โ†’ calls `trading_start`

The LLM in the loop (the **judge**, not the channel agent) is invoked via OpenClaw's local gateway โ€” the plugin reads `gateway.auth.token` from `~/.openclaw/openclaw.json` and POSTs to `http://127.0.0.1:18789/v1/chat/completions` with `x-openclaw-model: <cfg.llm.model>`.

---

## Configuration reference

`~/.openclaw/trading-agent/config.yaml`:

```yaml
mode: paper                      # 'paper' or 'live' โ€” live requires explicit confirmation, currently refused
strategy: meanReversion          # meanReversion | momentum | dualMA
tick_seconds: 30                 # daemon loop interval

# Risk caps
max_position_pct: 20             # max % of equity in any single ticker
max_concurrent_positions: 5      # cap on open positions
cash_buffer_pct: 10              # never go below 10% cash

# Daily band โ€” the "soul" parameters
daily_loss_stop_pct: -0.5        # hard downside stop (% of equity)
daily_profit_floor_pct: 1.0      # KPI / target โ€” measured, not enforced
trailing_protection:
  break_even_at: 1.0             # peak โ‰ฅ +1% โ†’ stop ratchets to 0%
  trail_distance_at: 2.0         # peak โ‰ฅ +2% โ†’ stop = peak - 1%

# Order behavior
order_type: market               # T212 Practice supports market only
allow_shorting: false
allow_leverage: false

# News input to the LLM judge
news:
  enabled: true
  refresh_seconds: 300           # cache TTL per ticker
  max_headlines_per_ticker: 5

# LLM judge
llm:
  model: copilot/claude-opus-4.7-1m-internal
  max_tokens: 4000
  json_retry_count: 1            # retries on malformed JSON; then REJECT-all fallback

# Broker
trading212:
  base_url: https://demo.trading212.com/api/v0
  api_key_env: T212_API_KEY      # name of env var holding the key

# Reporting
report_channel: telegram         # OpenClaw channel for EOD summary
```

---

## How the daily band works (worked example)

Start of day, equit

... (truncated)
tools

Comments

Sign in to leave a comment

Loading comments...