An always-on Python trading bot for Bitget USDT-M futures, built on FastAPI. Runs a hedge-mode grid strategy — long and short positions open together from the same entry, each side pyramiding into its own profit independently (fully separate order size, step %, trailing stop, and activation settings per side), with a trailing stop per step and an account-level risk circuit breaker on top.
Market & account controls — symbol search, leverage, margin mode, hedge mode, and account-level risk limits:
Independent long/short strategy settings — every parameter (order size, step growth %, trailing stop %, activation %, optional entry trigger) is configured separately per side:
Live open steps & account stats — real-time PnL and trailing-stop status per step:
- Signed REST integration with an exchange API (HMAC-SHA256, Bitget V2)
- Async event loop design for a 24/7 trading process (FastAPI + asyncio)
- Separation of strategy logic (
strategy.py), execution (bitget_client.py), risk management (risk_manager.py), and orchestration (main.py) - A simulation mode that runs the full loop with no API keys, for safe demoing
main.py orchestrates the price loop + trading loop, wires everything together
bitget_client.py signed HTTP client for Bitget's V2 mix (futures) API
strategy.py pure functions: when to open a new grid step, when to trail-stop one
risk_manager.py account-level circuit breaker (max drawdown / daily loss limit)
storage.py atomic JSON persistence for bot state
web_panel.py FastAPI routes + simple API-key auth for the control panel
Grid/DCA risk. This strategy stacks additional entries against an
adverse price move (classic martingale-style grid). That is a deliberate,
documented risk, not an oversight — it is the reason risk_manager.py
exists: individual steps only trail-stop once activated, so the account-level
circuit breaker is the actual backstop against a runaway drawdown. Tune
max_drawdown_percent / daily_loss_limit_percent conservatively.
Simulation vs. demo vs. live. Three distinct modes:
- No API keys in
.env→ pure local simulation, no network calls to Bitget at all. - API keys +
BITGET_USE_DEMO=true→ real Bitget demo/paper trading account (uses thepaptradingheader, same host as live). - API keys +
BITGET_USE_DEMO=false→ real money. Treat this switch with respect.
State reconciliation. On startup, reconcile_positions_once() compares
local step-tracking state against the exchange's actual open positions and
logs a warning on mismatch — it does not auto-correct, since automatically
closing/opening positions to "fix" a mismatch is itself a risk decision that
should have a human in the loop.
strategy.py and risk_manager.py are pure functions/classes with no
network dependency, so they're fully unit-tested — no API keys, exchange
connection, or KYC needed to verify the trading logic:
python -m unittest discover -s tests -v
# or, if pytest is installed:
pytest tests/ -v32 tests covering: grid step creation, independent long/short max_steps and
step-growth bounds, trailing-stop activation and triggering (long + short),
optional entry-trigger gating (wait for price ≤/≥ before the first step), and
the risk manager's drawdown/daily-loss circuit breaker — including the "stays
halted until a human calls resume()" behavior.
pip install -r requirements.txt
cp .env.example .env # fill in your own keys — never commit .env
python main.pyControl panel: http://localhost:8000/panel
All state-changing endpoints require an X-API-KEY header matching
PANEL_API_KEY from .env.
This review focused on correctness and safety of the existing code. Still open, in rough priority order:
- Backtesting — replay historical candles through
strategy.pywith modeled fees/slippage/funding before trusting new parameters live. - Alerting — Telegram/Discord webhook on: risk halt, order failures, reconciliation mismatches, bot start/stop.
- Performance analytics — win rate, Sharpe, max drawdown computed from a persisted trade log (currently steps are discarded on close, not logged).
- WebSocket price feed — replace the 2s REST poll with Bitget's public ticker WebSocket channel for lower latency and fewer rate-limited calls.


