Add complete Ouroboros trading system with TDD test suite
Some checks failed
CI / test (push) Has been cancelled

Implement the full autonomous trading agent architecture:
- KIS broker with async API, token refresh, leaky bucket rate limiter, and hash key signing
- Gemini-powered decision engine with JSON parsing and confidence threshold enforcement
- Risk manager with circuit breaker (-3% P&L) and fat finger protection (30% cap)
- Evolution engine for self-improving strategy generation via failure analysis
- 35 passing tests written TDD-first covering risk, broker, and brain modules
- CI/CD pipeline, Docker multi-stage build, and AI agent context docs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-04 02:08:48 +09:00
parent 9d9945822a
commit d1750af80f
27 changed files with 1842 additions and 0 deletions

44
src/config.py Normal file
View File

@@ -0,0 +1,44 @@
"""Strictly typed configuration loaded from environment variables."""
from __future__ import annotations
from pydantic import Field
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""Application settings — loaded from .env or environment variables."""
# KIS Open API
KIS_APP_KEY: str
KIS_APP_SECRET: str
KIS_ACCOUNT_NO: str # format: "XXXXXXXX-XX"
KIS_BASE_URL: str = "https://openapivts.koreainvestment.com:9443"
# Google Gemini
GEMINI_API_KEY: str
GEMINI_MODEL: str = "gemini-pro"
# Risk Management
CIRCUIT_BREAKER_PCT: float = Field(default=-3.0, le=0.0)
FAT_FINGER_PCT: float = Field(default=30.0, gt=0.0, le=100.0)
CONFIDENCE_THRESHOLD: int = Field(default=80, ge=0, le=100)
# Database
DB_PATH: str = "data/trade_logs.db"
# Rate Limiting (requests per second for KIS API)
RATE_LIMIT_RPS: float = 10.0
# Trading mode
MODE: str = Field(default="paper", pattern="^(paper|live)$")
model_config = {"env_file": ".env", "env_file_encoding": "utf-8"}
@property
def account_number(self) -> str:
return self.KIS_ACCOUNT_NO.split("-")[0]
@property
def account_product_code(self) -> str:
return self.KIS_ACCOUNT_NO.split("-")[1]