refactor: split CLAUDE.md into focused documentation structure
Some checks failed
CI / test (pull_request) Has been cancelled
Some checks failed
CI / test (pull_request) Has been cancelled
- Restructure docs into topic-specific files to minimize context - Create docs/workflow.md (Git + Agent workflow) - Create docs/commands.md (Common failures + build commands) - Create docs/architecture.md (System design + data flow) - Create docs/testing.md (Test structure + guidelines) - Rewrite CLAUDE.md as concise hub with links to detailed docs - Update .gitignore to exclude data/ directory Benefits: - Reduced context size for AI assistants - Faster reference lookups - Better maintainability - Topic-focused documentation Closes #13 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
191
docs/architecture.md
Normal file
191
docs/architecture.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# System Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
Self-evolving AI trading agent for global stock markets via KIS (Korea Investment & Securities) API. The main loop in `src/main.py` orchestrates four components in a 60-second cycle per stock across multiple markets.
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Broker (`src/broker/`)
|
||||
|
||||
**KISBroker** (`kis_api.py`) — Async KIS API client for domestic Korean market
|
||||
|
||||
- Automatic OAuth token refresh (valid for 24 hours)
|
||||
- Leaky-bucket rate limiter (10 requests per second)
|
||||
- POST body hash-key signing for order authentication
|
||||
- Custom SSL context with disabled hostname verification for VTS (virtual trading) endpoint due to known certificate mismatch
|
||||
|
||||
**OverseasBroker** (`overseas.py`) — KIS overseas stock API wrapper
|
||||
|
||||
- Reuses KISBroker infrastructure (session, token, rate limiter) via composition
|
||||
- Supports 9 global markets: US (NASDAQ/NYSE/AMEX), Japan, Hong Kong, China (Shanghai/Shenzhen), Vietnam (Hanoi/HCM)
|
||||
- Different API endpoints for overseas price/balance/order operations
|
||||
|
||||
**Market Schedule** (`src/markets/schedule.py`) — Timezone-aware market management
|
||||
|
||||
- `MarketInfo` dataclass with timezone, trading hours, lunch breaks
|
||||
- Automatic DST handling via `zoneinfo.ZoneInfo`
|
||||
- `is_market_open()` checks weekends, trading hours, lunch breaks
|
||||
- `get_open_markets()` returns currently active markets
|
||||
- `get_next_market_open()` finds next market to open and when
|
||||
|
||||
### 2. Brain (`src/brain/gemini_client.py`)
|
||||
|
||||
**GeminiClient** — AI decision engine powered by Google Gemini
|
||||
|
||||
- Constructs structured prompts from market data
|
||||
- Parses JSON responses into `TradeDecision` objects (`action`, `confidence`, `rationale`)
|
||||
- Forces HOLD when confidence < threshold (default 80)
|
||||
- Falls back to safe HOLD on any parse/API error
|
||||
- Handles markdown-wrapped JSON, malformed responses, invalid actions
|
||||
|
||||
### 3. Risk Manager (`src/core/risk_manager.py`)
|
||||
|
||||
**RiskManager** — Safety circuit breaker and order validation
|
||||
|
||||
⚠️ **READ-ONLY by policy** (see [`docs/agents.md`](./agents.md))
|
||||
|
||||
- **Circuit Breaker**: Halts all trading via `SystemExit` when daily P&L drops below -3.0%
|
||||
- Threshold may only be made stricter, never relaxed
|
||||
- Calculated as `(total_eval - purchase_total) / purchase_total * 100`
|
||||
- **Fat-Finger Protection**: Rejects orders exceeding 30% of available cash
|
||||
- Must always be enforced, cannot be disabled
|
||||
|
||||
### 4. Evolution (`src/evolution/optimizer.py`)
|
||||
|
||||
**StrategyOptimizer** — Self-improvement loop
|
||||
|
||||
- Analyzes high-confidence losing trades from SQLite
|
||||
- Asks Gemini to generate new `BaseStrategy` subclasses
|
||||
- Validates generated strategies by running full pytest suite
|
||||
- Simulates PR creation for human review
|
||||
- Only activates strategies that pass all tests
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Main Loop (60s cycle per stock, per market) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Market Schedule Check │
|
||||
│ - Get open markets │
|
||||
│ - Filter by enabled markets │
|
||||
│ - Wait if all closed │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Broker: Fetch Market Data │
|
||||
│ - Domestic: orderbook + balance │
|
||||
│ - Overseas: price + balance │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Calculate P&L │
|
||||
│ pnl_pct = (eval - cost) / cost │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Brain: Get Decision │
|
||||
│ - Build prompt with market data │
|
||||
│ - Call Gemini API │
|
||||
│ - Parse JSON response │
|
||||
│ - Return TradeDecision │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Risk Manager: Validate Order │
|
||||
│ - Check circuit breaker │
|
||||
│ - Check fat-finger limit │
|
||||
│ - Raise if validation fails │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Broker: Execute Order │
|
||||
│ - Domestic: send_order() │
|
||||
│ - Overseas: send_overseas_order() │
|
||||
└──────────────────┬────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Database: Log Trade │
|
||||
│ - SQLite (data/trades.db) │
|
||||
│ - Track: action, confidence, │
|
||||
│ rationale, market, exchange │
|
||||
└───────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
**SQLite** (`src/db.py`)
|
||||
|
||||
```sql
|
||||
CREATE TABLE trades (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TEXT NOT NULL,
|
||||
stock_code TEXT NOT NULL,
|
||||
action TEXT NOT NULL, -- BUY | SELL | HOLD
|
||||
confidence INTEGER NOT NULL, -- 0-100
|
||||
rationale TEXT,
|
||||
quantity INTEGER,
|
||||
price REAL,
|
||||
pnl REAL DEFAULT 0.0,
|
||||
market TEXT DEFAULT 'KR', -- KR | US_NASDAQ | JP | etc.
|
||||
exchange_code TEXT DEFAULT 'KRX' -- KRX | NASD | NYSE | etc.
|
||||
);
|
||||
```
|
||||
|
||||
Auto-migration: Adds `market` and `exchange_code` columns if missing for backward compatibility.
|
||||
|
||||
## Configuration
|
||||
|
||||
**Pydantic Settings** (`src/config.py`)
|
||||
|
||||
Loaded from `.env` file:
|
||||
|
||||
```bash
|
||||
# Required
|
||||
KIS_APP_KEY=your_app_key
|
||||
KIS_APP_SECRET=your_app_secret
|
||||
KIS_ACCOUNT_NO=XXXXXXXX-XX
|
||||
GEMINI_API_KEY=your_gemini_key
|
||||
|
||||
# Optional
|
||||
MODE=paper # paper | live
|
||||
DB_PATH=data/trades.db
|
||||
CONFIDENCE_THRESHOLD=80
|
||||
MAX_LOSS_PCT=3.0
|
||||
MAX_ORDER_PCT=30.0
|
||||
ENABLED_MARKETS=KR,US_NASDAQ # Comma-separated market codes
|
||||
```
|
||||
|
||||
Tests use in-memory SQLite (`DB_PATH=":memory:"`) and dummy credentials via `tests/conftest.py`.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Connection Errors (Broker API)
|
||||
- Retry with exponential backoff (2^attempt seconds)
|
||||
- Max 3 retries per stock
|
||||
- After exhaustion, skip stock and continue with next
|
||||
|
||||
### API Quota Errors (Gemini)
|
||||
- Return safe HOLD decision with confidence=0
|
||||
- Log error but don't crash
|
||||
- Agent continues trading on next cycle
|
||||
|
||||
### Circuit Breaker Tripped
|
||||
- Immediately halt via `SystemExit`
|
||||
- Log critical message
|
||||
- Requires manual intervention to restart
|
||||
|
||||
### Market Closed
|
||||
- Wait until next market opens
|
||||
- Use `get_next_market_open()` to calculate wait time
|
||||
- Sleep until market open time
|
||||
Reference in New Issue
Block a user