9.4 KiB
MAXBOT — Full Context Prompt
Paste this at the start of any new conversation to restore full context.
Git repository
- Gitea:
http://minimax.lan:3000/george/maxbot.git - Server:
~/maxbotonportainer.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
- Bot places limit buy orders BELOW current price at regular intervals
- When TSLA dips, orders fill automatically
- Each position has a take profit set to return exactly £1.00 (0.2 shares) or £0.50 (0.1 shares)
- 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)
- Positions close automatically at take profit
- 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:
- All existing open positions
- 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:
- Survival check first (always, against full 60% simulation)
- Spacing tightens second (only when 60% survival passes at tighter spacing)
- 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:
- ACCOUNT — equity, margin, positions, deposits
- SURVIVAL — max safe %, progress to 60%, auto-update status
- GRID — current spacing/depth, next upgrade status (survival-gated)
- TSLA PERFORMANCE — trades, profit, fees, monthly trend (from Jan 2024)
- 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)
- Telegram alerts — fills, closures, margin warnings
- Auto survival threshold stepping already done
- Claude AI integration — consult Claude on edge cases
- Web dashboard — browser view of positions, grid, P&L
- ProQuant-style backtester — test strategies against TSLA history (data already in history.db, S&P500/NASDAQ planned as context)
- 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