@@ -12,7 +12,7 @@ Paper trading simulator for Polymarket. Built for AI agents. Python 3.10+, SQLit
1212# Install
1313pip install -e " .[dev]"
1414
15- # Tests (615 tests , 100% coverage)
15+ # Tests (615 non-live + 42 live = 657 total , 100% coverage)
1616python3 -m pytest tests/ -x -q -m " not live" # fast, skip live API tests
1717python3 -m pytest tests/ -v # verbose
1818python3 -m pytest tests/ --cov=pm_trader --cov-report=term-missing # coverage
@@ -35,10 +35,12 @@ cli.py → engine.py → api.py (Polymarket HTTP)
3535 → orderbook.py (fill simulation)
3636 → orders.py (limit order state machine)
3737
38- mcp_server.py → engine.py (same stack, 30 MCP tools)
38+ mcp_server.py → engine.py (trading tools, 30 MCP tools)
39+ → analytics.py, card.py, benchmark.py, backtest.py (lazy imports)
3940```
4041
4142- ** Engine** is the orchestrator. All trading logic goes through it.
43+ - ** mcp_server.py** uses engine for trading, but imports analytics/card/benchmark/backtest directly (lazy, inside tool functions, to keep startup fast).
4244- ** orderbook.py** has pure functions (` simulate_buy_fill ` , ` simulate_sell_fill ` ) — no side effects.
4345- ** orders.py** has pure SQLite functions for limit order CRUD — no Engine dependency.
4446- ** api.py** talks to Gamma API (market discovery) and CLOB API (prices, order books).
@@ -58,12 +60,17 @@ mcp_server.py → engine.py (same stack, 30 MCP tools)
5860- Each error has a ` code ` class attribute: ` code = "INSUFFICIENT_BALANCE" `
5961- CLI and MCP use JSON envelope: ` {"ok": true, "data": {...}} ` or ` {"ok": false, "error": "msg", "code": "CODE"} `
6062- Helper functions: ` _ok(data) ` and ` _err(error, code) ` in both cli.py and mcp_server.py
63+ - ` _err_from(e) ` in mcp_server.py: wraps exceptions — exposes ` SimError ` /` ValueError ` /` TypeError ` messages, sanitizes everything else to ` "Internal error" `
6164
6265### Shared helpers
6366- ` _market_to_dict(m) ` in mcp_server.py — single serializer for Market→dict (used by all market-returning tools)
6467- ` _parse_market_list(data) ` in api.py — shared parser for Gamma API market list responses
6568- Don't cache empty API responses — guard with ` len(data) > 0 ` before ` _set_cached() `
6669
70+ ### Security
71+ - Account names validated via ` _validate_account_name() ` : rejects ` .. ` , ` / ` , ` \ ` , empty, leading/trailing whitespace
72+ - ` MAX_RESULTS = 100 ` caps all market-listing tool limits to prevent resource exhaustion
73+
6774### Key design decisions
6875- ** Fee formula** : ` (bps/10000) * min(price, 1-price) * shares ` — matches Polymarket exactly
6976- ** FOK** (fill-or-kill): all or nothing. ** FAK** (fill-and-kill): partial fills ok
0 commit comments