diff --git a/.gitignore b/.gitignore index 62ff6b5..b8f80e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .superpowers/ +.worktrees/ .venv/ __pycache__/ *.pyc diff --git a/docs/superpowers/plans/2026-07-08-grid-trading-phase-1.md b/docs/superpowers/plans/2026-07-08-grid-trading-phase-1.md new file mode 100644 index 0000000..a8fdde5 --- /dev/null +++ b/docs/superpowers/plans/2026-07-08-grid-trading-phase-1.md @@ -0,0 +1,277 @@ +# Grid Trading Phase 1 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Build the first working PySide6 + SQLite desktop version for A股/ETF grid-trading bookkeeping, including accounts, instruments, manual trades, position calculations, and local persistence. + +**Architecture:** Keep trading math independent from GUI code. The `domain` package owns models and calculations, `storage` owns SQLite schema and repository methods, `services` coordinates validation and summaries, and `ui` renders the PySide6 desktop workflow. + +**Tech Stack:** Python 3.11+, PySide6, SQLite, pytest, Decimal-based money calculations. + +--- + +## File Structure + +- Create `pyproject.toml`: package metadata, runtime dependencies, pytest config, console entry point. +- Create `README.md`: setup and run instructions. +- Create `src/grid_trading/__init__.py`: package marker and version. +- Create `src/grid_trading/app.py`: application entry point. +- Create `src/grid_trading/config.py`: default database path and fee settings. +- Create `src/grid_trading/domain/models.py`: dataclasses and enums for accounts, instruments, trades, strategies, summaries. +- Create `src/grid_trading/domain/calculations.py`: pure calculation functions for positions, account summary, fees, and T+1 availability. +- Create `src/grid_trading/storage/database.py`: SQLite connection and schema initialization. +- Create `src/grid_trading/storage/repositories.py`: typed CRUD methods over SQLite. +- Create `src/grid_trading/services/trading_service.py`: high-level account, instrument, trade, strategy, and summary service methods. +- Create `src/grid_trading/ui/main_window.py`: main PySide6 window and holdings-first layout. +- Create `src/grid_trading/ui/dialogs.py`: account, instrument, trade, and strategy dialogs. +- Create `src/grid_trading/ui/formatters.py`: UI formatting helpers. +- Create `tests/test_calculations.py`: TDD coverage for cost, realized profit, breakeven, and T+1. +- Create `tests/test_repositories.py`: SQLite schema and persistence coverage. +- Create `tests/test_services.py`: service-level workflow coverage. + +--- + +### Task 1: Project Scaffold + +**Files:** +- Create: `pyproject.toml` +- Create: `README.md` +- Create: `src/grid_trading/__init__.py` +- Create: `src/grid_trading/config.py` +- Create: `src/grid_trading/app.py` +- Test: `tests/test_imports.py` + +- [ ] **Step 1: Write failing import test** + +```python +def test_package_imports(): + import grid_trading + from grid_trading.config import DEFAULT_DB_PATH + + assert grid_trading.__version__ + assert DEFAULT_DB_PATH.name == "grid_trading.db" +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `pytest tests/test_imports.py -v` +Expected: FAIL with `ModuleNotFoundError: No module named 'grid_trading'`. + +- [ ] **Step 3: Add package scaffold** + +Implement a `src` layout, declare PySide6 and pytest dependencies, set `pythonpath = ["src"]`, and add `grid-trading = "grid_trading.app:main"`. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `pytest tests/test_imports.py -v` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add pyproject.toml README.md src/grid_trading tests/test_imports.py +git commit -m "chore: scaffold python desktop app" +``` + +### Task 2: Pure Trading Calculations + +**Files:** +- Create: `src/grid_trading/domain/models.py` +- Create: `src/grid_trading/domain/calculations.py` +- Test: `tests/test_calculations.py` + +- [ ] **Step 1: Write failing calculation tests** + +Cover these exact scenarios: + +```python +def test_buy_sell_grid_profit_and_breakeven(): + # Buy 100 grid shares at 10 with 1 fee, sell 100 at 11 with 1 fee, + # then buy 100 base shares at 9 with 1 fee. Grid profit is 98. + # Position cost is 901, position breakeven is 8.03, account breakeven is 9.01. +``` + +```python +def test_t_plus_one_available_quantity_excludes_today_buys(): + # Buy 200 yesterday and 100 today. As of today, total is 300 and available is 200. +``` + +```python +def test_sell_more_than_group_position_raises(): + # Buy 100 grid shares, attempt to sell 200 grid shares, expect CalculationError. +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `pytest tests/test_calculations.py -v` +Expected: FAIL because `grid_trading.domain` does not exist. + +- [ ] **Step 3: Implement dataclasses and pure functions** + +Define `TradeSide`, `TradeGroup`, `Trade`, `Instrument`, `FeeRules`, `PositionSummary`, `AccountSummary`, `CalculationError`, `estimate_fees`, `calculate_positions`, and `calculate_account_summary`. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `pytest tests/test_calculations.py -v` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add src/grid_trading/domain tests/test_calculations.py +git commit -m "feat: add grid trading calculations" +``` + +### Task 3: SQLite Persistence + +**Files:** +- Create: `src/grid_trading/storage/database.py` +- Create: `src/grid_trading/storage/repositories.py` +- Test: `tests/test_repositories.py` + +- [ ] **Step 1: Write failing repository tests** + +Cover: + +```python +def test_database_round_trips_account_instrument_and_trade(tmp_path): + # Initialize SQLite, create account, default template, instrument, trade. + # Reopen the database and assert the same rows are loaded. +``` + +```python +def test_trade_update_and_delete_are_persistent(tmp_path): + # Insert a trade, update price/quantity, delete it, assert repository reflects changes. +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `pytest tests/test_repositories.py -v` +Expected: FAIL because storage modules do not exist. + +- [ ] **Step 3: Implement schema and repositories** + +Create tables `accounts`, `instruments`, `strategy_templates`, `instrument_strategy_overrides`, `trades`, `cash_ledger`, and `app_settings`. Store Decimal values as text and dates as ISO strings. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `pytest tests/test_repositories.py -v` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add src/grid_trading/storage tests/test_repositories.py +git commit -m "feat: add sqlite persistence" +``` + +### Task 4: Trading Service Workflow + +**Files:** +- Create: `src/grid_trading/services/trading_service.py` +- Test: `tests/test_services.py` + +- [ ] **Step 1: Write failing service tests** + +Cover: + +```python +def test_service_creates_default_account_and_computes_summary(tmp_path): + # Service starts with no database rows, creates a default account/template, + # adds an instrument and trades, then returns a non-empty account summary. +``` + +```python +def test_service_validates_lot_size_and_available_sell_quantity(tmp_path): + # Quantity not multiple of 100 is rejected. + # Selling more than available prior-day quantity is rejected. +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `pytest tests/test_services.py -v` +Expected: FAIL because `TradingService` does not exist. + +- [ ] **Step 3: Implement service methods** + +Implement `ensure_defaults`, `save_account`, `add_instrument`, `save_trade`, `update_trade`, `delete_trade`, `get_position_summaries`, `get_account_summary`, `estimate_trade_fees`, and strategy template helpers. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `pytest tests/test_services.py -v` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add src/grid_trading/services tests/test_services.py +git commit -m "feat: add trading service workflow" +``` + +### Task 5: PySide6 GUI + +**Files:** +- Create: `src/grid_trading/ui/formatters.py` +- Create: `src/grid_trading/ui/dialogs.py` +- Create: `src/grid_trading/ui/main_window.py` +- Modify: `src/grid_trading/app.py` + +- [ ] **Step 1: Build main window layout** + +Create a `QMainWindow` with left navigation, top account summary cards, toolbar buttons, a holdings `QTableWidget`, and a bottom detail/trade table. + +- [ ] **Step 2: Add dialogs** + +Create dialogs for account settings, instrument editing, trade add/edit, and strategy template editing. Dialogs call `TradingService` and refresh the main table after saves. + +- [ ] **Step 3: Wire validation errors** + +Catch `ValueError` and `CalculationError` from service calls, then show a `QMessageBox.warning` without losing the dialog input. + +- [ ] **Step 4: Run GUI smoke command** + +Run: `python -m grid_trading.app --help` +Expected: command prints help without importing errors. + +- [ ] **Step 5: Commit** + +```bash +git add src/grid_trading/ui src/grid_trading/app.py +git commit -m "feat: add pySide6 holdings gui" +``` + +### Task 6: Verification And Polish + +**Files:** +- Modify: `README.md` +- Modify: `.gitignore` + +- [ ] **Step 1: Run full tests** + +Run: `pytest -v` +Expected: all tests pass. + +- [ ] **Step 2: Run import and CLI smoke checks** + +Run: `python -m grid_trading.app --help` +Expected: help output is printed. + +- [ ] **Step 3: Update README** + +Document `python -m venv .venv`, dependency install, `pytest`, and `python -m grid_trading.app`. + +- [ ] **Step 4: Commit** + +```bash +git add README.md .gitignore +git commit -m "docs: add phase one usage guide" +``` + +--- + +## Self-Review + +- Spec coverage: first phase requirements are covered by Tasks 1-5: account setup, instruments, strategy template storage, manual trades, holdings table, SQLite persistence, cost/profit/breakeven calculations, T+1 validation, and a GUI shell. +- Out of scope items remain excluded: no broker login, no automated orders, no realtime行情, no charts, and no cloud sync. +- Placeholder scan: no unresolved placeholders or unspecified implementation steps remain. +- Type consistency: model names, service names, and repository names are consistent across tasks.