Files

289 lines
10 KiB
Markdown

# 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:**
```bash
# 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:**
```bash
cd ~/maxbot && git pull
sudo systemctl restart maxbot
```
**To see history:**
```bash
git log --oneline
```
**To revert a bad change:**
```bash
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