Files

10 KiB

MAXBOT — Full Context Prompt

Paste this at the start of any new conversation to restore full context.


Instructions for Claude

When you read this file, you are fully caught up on the bot's logic, strategy, and current state. Do not ask questions already answered here.

IMPORTANT — keep this file current: At the end of any conversation where a major change, new feature, or significant decision was made, update this CONTEXT.md to reflect it. Provide the updated file for George to commit alongside the code changes. A good rule of thumb: if it would be confusing to a future Claude reading this cold, update it.


Git repository

  • Gitea: http://minimax.lan:3000/george/maxbot.git
  • Server: ~/maxbot on portainer.local (user: george)
  • Branch: main

Workflow for every change:

# On Ubuntu server after updating files
cd ~/maxbot
git add -A
git commit -m "Short description of what changed"
git push

To pull latest on server:

cd ~/maxbot && git pull
sudo systemctl restart maxbot

To see history:

git log --oneline

To revert a bad change:

git revert HEAD        # undo last commit
sudo systemctl restart maxbot

What this is

A live grid trading bot running on Ubuntu server (portainer.local), trading TSLA CFDs on Capital.com. Written in Python, running as a systemd service. Account owner: George, UK retail account, GBP, 5:1 leverage (20% margin).


Project structure

~/maxbot/
  bot.py          — main entry point, loop, startup audit, CLI
  config.py       — ALL settings (edit this for day-to-day changes)
  client.py       — Capital.com REST API calls
  state.py        — account state snapshot, field access helpers
  calculator.py   — grid maths, survival check, tier lookups
  grid.py         — order management logic (gap-filling, TP rules, dip mode)
  actions.py      — dry/confirm/live action handler with visible logging
  calibration.py  — startup calibration report, history sync
  fetch_history.py — fetches full Capital.com transaction history to SQLite
  data/history.db — SQLite: all trades, swaps, deposits from Jan 2021
  logs/
    bot.log        — full detail every loop
    actions.log    — actions only (orders placed/cancelled/TP changes)
    calibration.log — startup calibration reports
    fetch_history.log

The trading strategy

Instrument: TSLA CFD on Capital.com (UK retail, GBP account) Type: Grid / mean-reversion dip buying

  1. Bot places limit buy orders BELOW current price at regular intervals
  2. When TSLA dips, orders fill automatically
  3. Each position has a take profit set to return exactly £1.00 (0.2 shares) or £0.50 (0.1 shares)
  4. Take profit is set as an ABSOLUTE PRICE LEVEL (not amount/distance) Formula: tp_pct = (profit_gbp * gbpusd / size) / entry_price tp_price = entry_price * (1 + tp_pct)
  5. Positions close automatically at take profit
  6. Strategy works as long as TSLA doesn't drop catastrophically and long-term price grows

Position sizes:

  • 0.2 shares: below SIZE_SMALL_THRESHOLD (highest_open * 0.95)
  • 0.1 shares: within top 5% of highest open price (expensive overnight)

Profit targets (configurable in config.py):

  • TP_PROFIT_LARGE = 1.00 (£1.00 for 0.2 share positions)
  • TP_PROFIT_SMALL = 0.50 (£0.50 for 0.1 share positions)

Grid logic

Anchor: Grid starts just below the LOWEST OPEN POSITION (not current price). This prevents churn from minute-to-minute price movements. Grid only shifts when a position actually fills.

Normal mode (price within 25% of highest open):

  • Anchor = lowest open position
  • Grid fills below anchor, queue_depth orders maintained

Dip mode (price dropped 25%+ from highest open):

  • Lowest open position has TP DISABLED (manual close only)
  • Anchor = second lowest open position (lowest with TP)
  • Grid fills below anchor
  • Also fills gaps between no-TP position and anchor if spacing fits
  • No orders placed at or above anchor or no-TP position

Grid floor: Always fixed at 60% drop from highest open position. Floor = highest_open * 0.40. Never changes regardless of other settings.

Queue depth: Always maintain exactly QUEUE_DEPTH pending orders in the grid window. Scan for gaps anywhere (not just bottom) and fill them. Cancel orders outside the window.


Bottom-two position rule

Only activates when price drops 25%+ from highest open:

  • Lowest open position → TP DISABLED (manual close, holds for max recovery)
  • Second lowest → TP ENABLED at standard level
  • When new lower position opens → re-evaluate bottom two

Survival system (CRITICAL — everything depends on this)

The survival check simulates a FULL 60% drop from highest open position.

It does NOT just check current orders. It simulates:

  1. All existing open positions
  2. ALL grid levels from lowest existing down to floor (no depth cap) — because in a real crash, every level fills on the way down

Formula:

  • Floor = highest_open * 0.40
  • For each level: margin = price * size * 0.20 / gbpusd
  • For each level: unrealised_loss = (floor - price) * size / gbpusd
  • equity_at_floor = current_equity + sum(unrealised_losses)
  • margin_level_at_floor = equity_at_floor / total_margin * 100
  • SAFE if margin_level_at_floor >= 50% (Capital.com closeout threshold)

Capital.com margin stages:

  • 100%: normal

  • ≤100%: warning 1 — bot stops placing orders
  • ≤75%: warning 2 — urgent
  • ≤50%: auto closeout — Capital.com closes positions

SURVIVAL_DROP_PCT in config.py: This is the bot's operational setting. It auto-steps (30→35→40→45→50→55→60%) as equity grows. It does NOT control grid depth — the grid always goes to 60% floor regardless. SURVIVAL_DROP_PCT is used to gate order placement in the main loop.

Auto-update: Calibration checks max safe % each startup. If account can survive a higher milestone, config.py is auto-updated.


Grid tier upgrades (survival-gated)

ORDER OF OPERATIONS — strictly enforced:

  1. Survival check first (always, against full 60% simulation)
  2. Spacing tightens second (only when 60% survival passes at tighter spacing)
  3. Depth increases third (only after spacing tightened AND 60% survival passes)

Spacing tiers (config.py SPACING_TIERS):

  • £600: 1.5% (base)
  • £800: 1.2% (only if 60% survival passes at 1.2%)
  • £1100: 1.0%
  • £1500: 0.8%

Queue depth tiers (config.py QUEUE_TIERS):

  • (£600, 10 orders, requires 1.5% spacing)
  • (£900, 12 orders, requires 1.2% spacing first)
  • (£1200, 15 orders, requires 1.0% spacing first)
  • (£1500, 18 orders, requires 0.8% spacing first)

Depth NEVER increases until spacing has already tightened to required level. Spacing NEVER tightens until full 60% drop simulation passes.


Calibration report (runs every startup)

Sections in logic order:

  1. ACCOUNT — equity, margin, positions, deposits
  2. SURVIVAL — max safe %, progress to 60%, auto-update status
  3. GRID — current spacing/depth, next upgrade status (survival-gated)
  4. TSLA PERFORMANCE — trades, profit, fees, monthly trend (from Jan 2024)
  5. MILESTONES — £1k, £10k, £100k, £1M with ETA based on real profit rate

Deposit detection: auto-detects weekly average from Capital.com history (last 12 weeks, needs 3+ deposits). Falls back to WEEKLY_DEPOSIT_GBP in config.py.

History sync: fetch_history.py runs incrementally on every startup, fetching only new days since last run. Uses /history/transactions endpoint. 3 second delay to avoid Capital.com session rate limit (429).


Operating modes

python3 bot.py --mode dryrun    # reads everything, prints what it would do, no actions
python3 bot.py --mode confirm   # asks y/n before every action
python3 bot.py --mode live      # fully autonomous

Service: systemd, auto-restart, credentials in ~/maxbot/.env


Capital.com API notes

  • Field names (verified against live API): Orders: workingOrderData.orderLevel, orderSize, dealId Positions: position.level, position.size, position.profitLevel, position.dealId Account: accounts[].balance.balance (equity), .deposit (funds), .available Price: snapshot.bid, snapshot.offer
  • Session tokens expire after 10 minutes, refresh at 9 minutes
  • Rate limit: 1 request per 0.1s for order operations
  • POST /session: 1 request/second limit
  • TP is sent as profitLevel (absolute price), displays as "Price level" in UI
  • No custom order tags/references available in API

Current state (as of May 27 2026)

  • Equity: ~£664
  • Highest open position: $450.02
  • Max safe survival: 40% drop
  • SURVIVAL_DROP_PCT: 40%
  • Grid: 1.5% spacing, 10 orders, FROZEN until 60% survival met
  • Account open: Jan 28 2021
  • Current strategy start: Jan 2024
  • Trades (Jan 2024+): 407, profit £484, fees -£74, net £409
  • Blended daily rate: £2.67/day
  • Next milestone: £1,000 equity (~126 days at current rate)
  • Weekly deposits: none detected yet (last deposit May 26 2026)

Planned future features (not yet built)

  1. Telegram alerts — fills, closures, margin warnings
  2. Auto survival threshold stepping already done
  3. Claude AI integration — consult Claude on edge cases
  4. Web dashboard — browser view of positions, grid, P&L
  5. ProQuant-style backtester — test strategies against TSLA history (data already in history.db, S&P500/NASDAQ planned as context)
  6. US100 and S&P500 as secondary instruments (future)

Key design decisions made

  • Grid floor FIXED at 60% — never changes, decoupled from SURVIVAL_DROP_PCT
  • TP as price level % of entry (not fixed dollar, not fixed % of current price)
  • Grid anchored to lowest OPEN POSITION (not current price) — prevents churn
  • Survival always simulates FULL grid to floor (no depth cap) — honest
  • Spacing frozen until 60% survival passes — safety before profit frequency
  • Depth requires spacing first — correct order of operations
  • History uses /history/transactions not /history/activity (richer data)
  • Deposits filtered from Jan 1 2024 onwards (new strategy era)
  • SURVIVAL_DROP_PCT auto-steps in config.py via calibration — no manual edits