feat: 프로젝트 개요 및 컴포넌트별 명세, 로드맵 등 문서 추가
This commit is contained in:
1
.obsidian/app.json
vendored
Normal file
1
.obsidian/app.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
.obsidian/appearance.json
vendored
Normal file
1
.obsidian/appearance.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
33
.obsidian/core-plugins.json
vendored
Normal file
33
.obsidian/core-plugins.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"footnotes": false,
|
||||||
|
"properties": true,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": true,
|
||||||
|
"bases": true,
|
||||||
|
"webviewer": false
|
||||||
|
}
|
||||||
198
.obsidian/workspace.json
vendored
Normal file
198
.obsidian/workspace.json
vendored
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "2368ff66953844f9",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "6495286b42a8bf9b",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "b9821d41e3b2938c",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "docs/01-overview.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "01-overview"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "2075a9d64fc12fa3",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "89fdefcb560ce022",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "8e1a145557d38a09",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"autoReveal": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-folder-closed",
|
||||||
|
"title": "파일 탐색기"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e8e754d9105c8a4b",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
},
|
||||||
|
"icon": "lucide-search",
|
||||||
|
"title": "검색"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "15dba3d38380203c",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {},
|
||||||
|
"icon": "lucide-bookmark",
|
||||||
|
"title": "북마크"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "7146911a3f689133",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "ab65bae9b04cd26f",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "3961c9ce54d34607",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"file": "docs/01-overview.md",
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-coming-in",
|
||||||
|
"title": "01-overview 의 백링크"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "380d358f7c71933e",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"file": "docs/01-overview.md",
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-going-out",
|
||||||
|
"title": "01-overview 의 나가는 링크"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "496a75e972ab4f2c",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-tags",
|
||||||
|
"title": "태그"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "913da9b646423c5e",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "all-properties",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-archive",
|
||||||
|
"title": "모든 속성"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ab0c0c2b8374c194",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {
|
||||||
|
"file": "docs/01-overview.md",
|
||||||
|
"followCursor": false,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-list",
|
||||||
|
"title": "01-overview 의 개요"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"switcher:빠른 전환기 열기": false,
|
||||||
|
"graph:그래프 뷰 열기": false,
|
||||||
|
"canvas:새 캔버스 만들기": false,
|
||||||
|
"daily-notes:오늘의 일일 노트 열기": false,
|
||||||
|
"templates:템플릿 삽입": false,
|
||||||
|
"command-palette:명령어 팔레트 열기": false,
|
||||||
|
"bases:새 베이스 생성하기": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "b9821d41e3b2938c",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"components/phase3/audit.md",
|
||||||
|
"docs/01-overview.md",
|
||||||
|
"components/phase2/analytics.md",
|
||||||
|
"components/phase1/mgmt.md",
|
||||||
|
"components/phase1/balance.md",
|
||||||
|
"specification.md",
|
||||||
|
"README.md",
|
||||||
|
"AGENTS.md",
|
||||||
|
"diagram.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
52
AGENTS.md
Normal file
52
AGENTS.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## 프로젝트 구조 및 모듈 구성
|
||||||
|
|
||||||
|
- `specification.md`는 컴포넌트 사양, 데이터 모델, TypeScript 스타일 인터페이스의 기준 문서입니다.
|
||||||
|
- `components/phase1/`, `components/phase2/`, `components/phase3/`에 단계별 컴포넌트 문서가 있습니다.
|
||||||
|
- Phase 1: `balance.md`, `mgmt.md`, `strategy.md`, `scheduler.md`, `data.md`, `risk.md`
|
||||||
|
- Phase 2: `analytics.md`, `monitor.md`
|
||||||
|
- Phase 3: `audit.md`, `simulation.md`
|
||||||
|
- `docs/`는 개요와 아키텍처 문서가 모여 있습니다(`01-overview.md`~`05-roadmap.md`).
|
||||||
|
- `diagram.md`에는 아키텍처 및 워크플로우를 설명하는 Mermaid 다이어그램이 있습니다.
|
||||||
|
|
||||||
|
이 저장소는 구현 코드가 없는 문서 중심 리포지토리입니다.
|
||||||
|
|
||||||
|
## 빌드, 테스트, 개발 명령
|
||||||
|
|
||||||
|
- 정의된 빌드/테스트 명령은 없습니다.
|
||||||
|
- 문서 변경 후 Markdown 미리보기나 Mermaid 뷰어로 확인하세요(예: `diagram.md`).
|
||||||
|
|
||||||
|
## 코딩 스타일 및 네이밍 규칙
|
||||||
|
|
||||||
|
- 문서 본문은 한국어를 기본으로 하며, 컴포넌트명과 인터페이스 식별자는 영어를 사용합니다.
|
||||||
|
- `specification.md`의 섹션 구조(책임, 주요 기능, 데이터 모델)를 유지하세요.
|
||||||
|
- 리스트, 코드 블록, Mermaid 블록은 Markdown 규칙을 따릅니다.
|
||||||
|
- 인터페이스 변경 시 관련 컴포넌트 문서의 타입 정의도 함께 업데이트합니다.
|
||||||
|
|
||||||
|
## 테스트 가이드
|
||||||
|
|
||||||
|
- 자동화된 테스트 프레임워크는 없습니다.
|
||||||
|
- 데이터 모델이나 워크플로우 변경 시 `specification.md`와 관련 컴포넌트 문서의 일관성을 함께 점검하세요.
|
||||||
|
|
||||||
|
## 커밋 및 PR 가이드
|
||||||
|
|
||||||
|
- Git 이력이 거의 없어 확정된 커밋 규칙은 없습니다.
|
||||||
|
- 커밋 메시지는 변경 내용을 구체적으로 작성하세요(예: "리스크 모델 필드 업데이트").
|
||||||
|
- PR에는 요약, 영향받는 파일, 다이어그램/워크플로우 변경 여부를 포함하세요.
|
||||||
|
|
||||||
|
## 아키텍처 및 워크플로우 정합성
|
||||||
|
|
||||||
|
- 실행 플로우(스케줄러 → 전략 → 리스크 → 주문)를 바꾸면 `docs/04-workflows.md`와 `diagram.md`를 함께 수정합니다.
|
||||||
|
- 컨테이너 기반 자산 격리, 리스크 우선 설계 등 핵심 원칙은 유지합니다.
|
||||||
|
- 다이어그램을 수정했다면 텍스트 설명도 동기화하세요.
|
||||||
|
|
||||||
|
## 문서 변경 체크리스트
|
||||||
|
|
||||||
|
- 데이터 모델 변경 시 `specification.md`와 관련 컴포넌트 문서를 모두 갱신합니다.
|
||||||
|
- Phase별 영향 범위를 확인하고 연동 문서를 함께 수정합니다.
|
||||||
|
- 외부 연동(브로커/데이터 소스) 가정이 바뀌면 `docs/02-architecture.md`도 점검합니다.
|
||||||
|
|
||||||
|
## 작업 전 확인
|
||||||
|
|
||||||
|
- `CLAUDE.md`에 있는 저장소 특성(문서 전용, 한국어 중심, 리스크 우선 설계)과 수정 가이드를 먼저 확인합니다.
|
||||||
166
CLAUDE.md
Normal file
166
CLAUDE.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Repository Overview
|
||||||
|
|
||||||
|
This is the specification repository for **QuantBench**, a quantitative trading platform for individual investors. It contains system architecture documentation, component specifications, and design diagrams but **no actual implementation code**.
|
||||||
|
|
||||||
|
The platform enables:
|
||||||
|
- Multi-account management with multiple brokers (한국투자증권, 삼성증권, 키움증권)
|
||||||
|
- Container-based asset isolation for running multiple strategies in parallel
|
||||||
|
- Strategy-based automated trading with backtesting
|
||||||
|
- Risk management and performance analytics
|
||||||
|
|
||||||
|
## System Architecture
|
||||||
|
|
||||||
|
### Three-Phase Development Approach
|
||||||
|
|
||||||
|
**Phase 1: MVP (Core Trading System)**
|
||||||
|
- `balance`: Broker API integration and account management
|
||||||
|
- `mgmt`: Virtual container management for asset isolation
|
||||||
|
- `strategy`: Strategy implementation, execution, and backtesting
|
||||||
|
- `scheduler`: Automated execution scheduling with approval workflows
|
||||||
|
- `risk`: Pre-trade risk validation and position monitoring
|
||||||
|
- `data`: Market data collection, storage, and quality management
|
||||||
|
|
||||||
|
**Phase 2: Production Ready**
|
||||||
|
- `analytics`: Performance measurement, attribution analysis, and reporting
|
||||||
|
- `monitor`: System health monitoring, anomaly detection, and alerting
|
||||||
|
|
||||||
|
**Phase 3: Enterprise Grade**
|
||||||
|
- `audit`: Immutable audit logging and compliance reporting
|
||||||
|
- `simulation`: Paper trading, scenario testing, and parameter optimization
|
||||||
|
|
||||||
|
### Key Architectural Concepts
|
||||||
|
|
||||||
|
**Container-Based Asset Isolation**: The core innovation is the virtual container system that allows multiple strategies to run independently within a single brokerage account. Each container has:
|
||||||
|
- Virtual balance tracking (isolated from other containers)
|
||||||
|
- Independent risk limits and constraints
|
||||||
|
- Dedicated strategy assignment
|
||||||
|
- Rebalancing schedules
|
||||||
|
|
||||||
|
**Strategy Execution Flow**:
|
||||||
|
```
|
||||||
|
scheduler trigger → mgmt (container info) → strategy (signal generation) →
|
||||||
|
data (market data) → risk (validation) → balance (order execution) →
|
||||||
|
mgmt (update positions) → analytics (performance calc) → monitor (alerts)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Risk Management Integration**: All orders pass through risk validation before execution, checking:
|
||||||
|
- Balance sufficiency
|
||||||
|
- Position size limits
|
||||||
|
- Concentration limits
|
||||||
|
- Value at Risk (VaR)
|
||||||
|
- Maximum drawdown
|
||||||
|
- Leverage limits
|
||||||
|
|
||||||
|
## Component Relationships
|
||||||
|
|
||||||
|
### Core Dependencies
|
||||||
|
- `scheduler` orchestrates execution by calling `mgmt`, `strategy`, `risk`, and `balance`
|
||||||
|
- `strategy` depends on `data` for market data and `risk` for validation
|
||||||
|
- `mgmt` manages virtual balances and coordinates with `balance` for actual positions
|
||||||
|
- `analytics` consumes data from `mgmt`, `balance`, and `data` for performance calculation
|
||||||
|
- `monitor` observes all components and triggers alerts
|
||||||
|
|
||||||
|
### Data Flow
|
||||||
|
- Real-time market data: Broker APIs → `data` → Redis cache → `strategy`/`monitor`
|
||||||
|
- Historical data: External providers → `data` → Time-series DB → `analytics`/backtesting
|
||||||
|
- Order flow: `strategy` signals → `risk` validation → `balance` execution → `mgmt` reconciliation
|
||||||
|
|
||||||
|
## Working with This Repository
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
- `specification.md`: Comprehensive component specifications with data models (44KB, Korean)
|
||||||
|
- `diagram.md`: Mermaid diagrams for architecture visualization
|
||||||
|
- `README.md`: Empty placeholder
|
||||||
|
|
||||||
|
### Understanding the Specifications
|
||||||
|
|
||||||
|
The `specification.md` file is structured with:
|
||||||
|
1. Component responsibilities and main functions
|
||||||
|
2. TypeScript interface definitions for data models
|
||||||
|
3. Function signatures with descriptions
|
||||||
|
4. Workflow examples showing component interactions
|
||||||
|
|
||||||
|
Each component section follows this pattern:
|
||||||
|
```
|
||||||
|
### Component Name (책임)
|
||||||
|
#### 주요 기능
|
||||||
|
- Function descriptions with signatures
|
||||||
|
**데이터 모델**
|
||||||
|
- TypeScript interfaces
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Design Patterns
|
||||||
|
|
||||||
|
**Broker Abstraction**: The `BrokerAdapter` interface in the `balance` component abstracts different broker APIs (한국투자증권, 삼성증권, 키움증권) behind a unified interface for portability.
|
||||||
|
|
||||||
|
**Strategy Interface**: All strategies must implement `StrategyInterface` with required methods:
|
||||||
|
- `initialize(context: StrategyContext)`
|
||||||
|
- `generateSignals(data: MarketData): Signal[]`
|
||||||
|
|
||||||
|
**Approval Workflow**: The scheduler supports both AUTO and APPROVAL_REQUIRED modes. In approval mode, execution waits for user confirmation before submitting orders.
|
||||||
|
|
||||||
|
**Immutable Audit Trail**: Phase 3 introduces hash-chained audit events with `previousHash` links to ensure tamper-proof logging.
|
||||||
|
|
||||||
|
## Important Considerations
|
||||||
|
|
||||||
|
### Multi-Language Documentation
|
||||||
|
All specifications are written in Korean. Component names and code interfaces use English, but descriptions, comments, and documentation are in Korean.
|
||||||
|
|
||||||
|
### No Implementation Code
|
||||||
|
This repository contains only specifications and diagrams. When discussing implementation:
|
||||||
|
- Reference the TypeScript interfaces defined in specifications
|
||||||
|
- Maintain consistency with the defined data models
|
||||||
|
- Follow the component interaction patterns described in workflows
|
||||||
|
|
||||||
|
### Risk-First Design
|
||||||
|
The architecture prioritizes safety:
|
||||||
|
- All orders must pass risk validation before execution
|
||||||
|
- Container-level constraints prevent over-allocation
|
||||||
|
- Reconciliation functions detect discrepancies between virtual and actual balances
|
||||||
|
- Stop-loss and take-profit mechanisms support automatic position closure
|
||||||
|
|
||||||
|
### Real-World Trading Constraints
|
||||||
|
The design accounts for practical trading considerations:
|
||||||
|
- Market hours and holidays (Korean exchanges)
|
||||||
|
- Commission and slippage modeling
|
||||||
|
- Order types (market, limit, stop)
|
||||||
|
- Partial fills and order status tracking
|
||||||
|
- Corporate actions (dividends, stock splits)
|
||||||
|
|
||||||
|
## Diagram Reference
|
||||||
|
|
||||||
|
The `diagram.md` file contains 10 Mermaid diagrams:
|
||||||
|
1. Overall system architecture (all phases)
|
||||||
|
2. Phase 1 component relationships
|
||||||
|
3. Phase-by-phase component structure
|
||||||
|
4. Strategy execution sequence diagram
|
||||||
|
5. Risk management flow
|
||||||
|
6. Data flow diagram
|
||||||
|
7. Container lifecycle state machine
|
||||||
|
8. Approval workflow
|
||||||
|
9. Monitoring and alerting system
|
||||||
|
10. Simulation environment structure
|
||||||
|
|
||||||
|
Use these diagrams to understand component interactions visually before making specification changes.
|
||||||
|
|
||||||
|
## Specification Modification Guidelines
|
||||||
|
|
||||||
|
When updating specifications:
|
||||||
|
|
||||||
|
1. **Maintain Interface Consistency**: Changes to data models should be reflected across all dependent components
|
||||||
|
2. **Update All Phases**: If a core data model changes, check impact across all three phases
|
||||||
|
3. **Preserve Type Safety**: Keep TypeScript interfaces complete with all required fields
|
||||||
|
4. **Document Workflows**: Update sequence descriptions when component interactions change
|
||||||
|
5. **Version Strategies**: Strategy changes should use the versioning system (`StrategyVersion`)
|
||||||
|
|
||||||
|
## Related Systems
|
||||||
|
|
||||||
|
The specifications reference external systems that must be integrated:
|
||||||
|
- Broker APIs: 한국투자증권, 삼성증권, 키움증권
|
||||||
|
- Data providers: Yahoo Finance, Alpha Vantage
|
||||||
|
- Infrastructure: PostgreSQL, Redis, Message Queue (Kafka/RabbitMQ), S3
|
||||||
|
- Notification channels: Email, SMS, Push, Slack
|
||||||
759
components/phase1/balance.md
Normal file
759
components/phase1/balance.md
Normal file
@@ -0,0 +1,759 @@
|
|||||||
|
# balance - 계좌 관리
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**balance** 컴포넌트는 증권사 API 통합 및 계좌 자산 관리를 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 증권사 API 인증 및 세션 관리
|
||||||
|
- 다중 계좌 등록/수정/삭제
|
||||||
|
- 계좌 잔고 및 포지션 조회
|
||||||
|
- 시장 시세 조회 (현재가, 호가, 과거 데이터)
|
||||||
|
- 주문 처리 (제출, 취소, 상태 조회)
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Balance[balance] --> Broker1[한국투자증권 API]
|
||||||
|
Balance --> Broker2[삼성증권 API]
|
||||||
|
Balance --> Broker3[키움증권 API]
|
||||||
|
|
||||||
|
Mgmt[mgmt] --> Balance
|
||||||
|
Scheduler[scheduler] --> Balance
|
||||||
|
Monitor[monitor] --> Balance
|
||||||
|
|
||||||
|
Balance --> DB[(Database)]
|
||||||
|
Balance --> Cache[(Redis Cache)]
|
||||||
|
|
||||||
|
style Balance fill:#00BCD4,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 계좌 연동 관리
|
||||||
|
|
||||||
|
#### 1.1 계좌 등록
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 새로운 증권사 계좌를 등록합니다
|
||||||
|
*/
|
||||||
|
async function registerAccount(params: {
|
||||||
|
brokerId: string // 증권사 식별자 (예: 'korea_investment')
|
||||||
|
accountNumber: string // 계좌 번호
|
||||||
|
accountName: string // 계좌 별칭
|
||||||
|
accountType: AccountType // 계좌 유형
|
||||||
|
credentials: { // 인증 정보
|
||||||
|
apiKey: string
|
||||||
|
apiSecret: string
|
||||||
|
accountPassword?: string
|
||||||
|
}
|
||||||
|
}): Promise<Account>
|
||||||
|
```
|
||||||
|
|
||||||
|
**처리 흐름**:
|
||||||
|
1. 증권사 식별자 검증
|
||||||
|
2. API 키 암호화 (AES-256)
|
||||||
|
3. 테스트 연결 수행 (인증 정보 유효성 검증)
|
||||||
|
4. 계좌 정보 데이터베이스 저장
|
||||||
|
5. 초기 잔고 조회
|
||||||
|
|
||||||
|
#### 1.2 API 키 암호화 저장
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* API 키를 AES-256으로 암호화하여 저장
|
||||||
|
*/
|
||||||
|
function encryptCredentials(credentials: {
|
||||||
|
apiKey: string
|
||||||
|
apiSecret: string
|
||||||
|
accountPassword?: string
|
||||||
|
}): EncryptedCredentials {
|
||||||
|
const iv = crypto.randomBytes(16)
|
||||||
|
const cipher = crypto.createCipheriv('aes-256-gcm', ENCRYPTION_KEY, iv)
|
||||||
|
|
||||||
|
const encrypted = Buffer.concat([
|
||||||
|
cipher.update(JSON.stringify(credentials), 'utf8'),
|
||||||
|
cipher.final()
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
encryptedData: encrypted.toString('base64'),
|
||||||
|
iv: iv.toString('base64'),
|
||||||
|
algorithm: 'aes-256-gcm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 자산 조회
|
||||||
|
|
||||||
|
#### 2.1 현재 잔고 조회
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 계좌의 현재 잔고를 조회합니다
|
||||||
|
*/
|
||||||
|
async function getCurrentBalance(accountId: string): Promise<Balance> {
|
||||||
|
const account = await getAccount(accountId)
|
||||||
|
const adapter = getBrokerAdapter(account.brokerId)
|
||||||
|
|
||||||
|
// 증권사 API 호출
|
||||||
|
const balance = await adapter.getBalance(account)
|
||||||
|
|
||||||
|
// 캐시 업데이트
|
||||||
|
await cache.set(`balance:${accountId}`, balance, 60) // 60초 TTL
|
||||||
|
|
||||||
|
return balance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**반환 데이터**:
|
||||||
|
```typescript
|
||||||
|
interface Balance {
|
||||||
|
accountId: string
|
||||||
|
cash: {
|
||||||
|
krw: number // 원화 잔고
|
||||||
|
usd: number // 달러 잔고 (해외 주식용)
|
||||||
|
}
|
||||||
|
positions: Position[] // 보유 종목
|
||||||
|
totalEquity: number // 총 자산 평가액
|
||||||
|
buyingPower: number // 매수 가능 금액
|
||||||
|
withdrawableCash: number // 출금 가능 금액
|
||||||
|
timestamp: Date // 조회 시점
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 포트폴리오 스냅샷
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 자산 클래스별 비중 및 종목별 손익률을 포함한 포트폴리오 스냅샷
|
||||||
|
*/
|
||||||
|
async function getPortfolioSnapshot(accountId: string): Promise<Portfolio> {
|
||||||
|
const balance = await getCurrentBalance(accountId)
|
||||||
|
|
||||||
|
// 자산 클래스별 비중 계산
|
||||||
|
const assetAllocation = calculateAssetAllocation(balance.positions)
|
||||||
|
|
||||||
|
// 종목별 손익률 계산
|
||||||
|
const positionsWithPnL = balance.positions.map(position => ({
|
||||||
|
...position,
|
||||||
|
unrealizedPnLPct: (position.unrealizedPnL / (position.averagePrice * position.quantity)) * 100
|
||||||
|
}))
|
||||||
|
|
||||||
|
return {
|
||||||
|
...balance,
|
||||||
|
assetAllocation,
|
||||||
|
positions: positionsWithPnL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 시세 조회
|
||||||
|
|
||||||
|
#### 3.1 현재가 조회
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 종목의 현재가 및 호가 정보를 조회합니다
|
||||||
|
*/
|
||||||
|
async function getCurrentPrice(symbol: string): Promise<Quote> {
|
||||||
|
// 캐시 우선 조회 (실시간 시세)
|
||||||
|
const cached = await cache.get(`quote:${symbol}`)
|
||||||
|
if (cached && Date.now() - cached.timestamp < 5000) { // 5초 이내 캐시
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
// 증권사 API 호출
|
||||||
|
const adapter = getBrokerAdapter('default')
|
||||||
|
const quote = await adapter.getQuote(symbol)
|
||||||
|
|
||||||
|
// 캐시 업데이트
|
||||||
|
await cache.set(`quote:${symbol}`, quote, 10) // 10초 TTL
|
||||||
|
|
||||||
|
return quote
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**반환 데이터**:
|
||||||
|
```typescript
|
||||||
|
interface Quote {
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
price: number // 현재가
|
||||||
|
change: number // 전일 대비 변동
|
||||||
|
changePct: number // 변동률 (%)
|
||||||
|
volume: number // 거래량
|
||||||
|
bidPrice: number // 매수 호가 1
|
||||||
|
askPrice: number // 매도 호가 1
|
||||||
|
bidSize: number // 매수 호가 수량
|
||||||
|
askSize: number // 매도 호가 수량
|
||||||
|
timestamp: Date // 시세 시간
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 과거 가격 조회
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 과거 가격 데이터를 조회합니다 (백테스트용)
|
||||||
|
*/
|
||||||
|
async function getHistoricalPrices(params: {
|
||||||
|
symbol: string
|
||||||
|
from: Date
|
||||||
|
to: Date
|
||||||
|
interval: Interval // '1d', '1w', '1M' 등
|
||||||
|
}): Promise<PriceBar[]> {
|
||||||
|
const adapter = getBrokerAdapter('default')
|
||||||
|
const prices = await adapter.getHistoricalPrices(params)
|
||||||
|
|
||||||
|
// 배당 및 액면분할 조정
|
||||||
|
const adjustedPrices = await adjustForCorporateActions(prices, params.symbol)
|
||||||
|
|
||||||
|
return adjustedPrices
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 주문 처리
|
||||||
|
|
||||||
|
#### 4.1 주문 제출
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 주문을 제출합니다
|
||||||
|
*/
|
||||||
|
async function placeOrder(order: Order): Promise<OrderResult> {
|
||||||
|
// 1. 주문 검증
|
||||||
|
await validateOrder(order)
|
||||||
|
|
||||||
|
// 2. 증권사 어댑터 선택
|
||||||
|
const account = await getAccount(order.accountId)
|
||||||
|
const adapter = getBrokerAdapter(account.brokerId)
|
||||||
|
|
||||||
|
// 3. 주문 제출
|
||||||
|
try {
|
||||||
|
const result = await adapter.submitOrder(order)
|
||||||
|
|
||||||
|
// 4. 주문 상태 저장
|
||||||
|
await saveOrderStatus(result)
|
||||||
|
|
||||||
|
// 5. 감사 로그 기록
|
||||||
|
await audit.logEvent({
|
||||||
|
eventType: 'ORDER',
|
||||||
|
action: 'CREATE',
|
||||||
|
entity: 'Order',
|
||||||
|
entityId: result.orderId!,
|
||||||
|
after: result
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// 에러 로깅
|
||||||
|
await logger.error('Order submission failed', { order, error })
|
||||||
|
|
||||||
|
// 알림 발송
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'EXECUTION',
|
||||||
|
severity: 'ERROR',
|
||||||
|
message: `주문 제출 실패: ${order.symbol} ${order.side} ${order.quantity}`,
|
||||||
|
metadata: { order, error }
|
||||||
|
})
|
||||||
|
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**주문 검증**:
|
||||||
|
```typescript
|
||||||
|
async function validateOrder(order: Order): Promise<void> {
|
||||||
|
// 계좌 존재 여부 확인
|
||||||
|
const account = await getAccount(order.accountId)
|
||||||
|
if (!account.isActive) {
|
||||||
|
throw new Error('계좌가 비활성 상태입니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 주문 수량 검증
|
||||||
|
if (order.quantity <= 0) {
|
||||||
|
throw new Error('주문 수량은 0보다 커야 합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 호가 단위 검증 (지정가 주문인 경우)
|
||||||
|
if (order.orderType === 'LIMIT' && order.price) {
|
||||||
|
validatePriceTick(order.price, order.symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 잔고 확인 (매수 주문인 경우)
|
||||||
|
if (order.side === 'BUY') {
|
||||||
|
const balance = await getCurrentBalance(order.accountId)
|
||||||
|
const requiredCash = order.quantity * (order.price || await getCurrentPrice(order.symbol).price)
|
||||||
|
|
||||||
|
if (balance.buyingPower < requiredCash) {
|
||||||
|
throw new Error('매수 가능 금액이 부족합니다')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2 주문 취소
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 미체결 주문을 취소합니다
|
||||||
|
*/
|
||||||
|
async function cancelOrder(orderId: string): Promise<boolean> {
|
||||||
|
// 1. 주문 정보 조회
|
||||||
|
const order = await getOrder(orderId)
|
||||||
|
|
||||||
|
if (!['PENDING', 'SUBMITTED', 'PARTIALLY_FILLED'].includes(order.status)) {
|
||||||
|
throw new Error(`취소 불가능한 주문 상태: ${order.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 증권사 어댑터로 취소 요청
|
||||||
|
const account = await getAccount(order.accountId)
|
||||||
|
const adapter = getBrokerAdapter(account.brokerId)
|
||||||
|
|
||||||
|
const success = await adapter.cancelOrder(orderId)
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// 3. 주문 상태 업데이트
|
||||||
|
await updateOrderStatus(orderId, 'CANCELLED')
|
||||||
|
|
||||||
|
// 4. 감사 로그 기록
|
||||||
|
await audit.logEvent({
|
||||||
|
eventType: 'ORDER',
|
||||||
|
action: 'CANCEL',
|
||||||
|
entity: 'Order',
|
||||||
|
entityId: orderId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.3 주문 상태 조회
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 주문의 현재 상태를 조회합니다
|
||||||
|
*/
|
||||||
|
async function getOrderStatus(orderId: string): Promise<OrderStatus> {
|
||||||
|
const order = await getOrder(orderId)
|
||||||
|
|
||||||
|
// 최종 상태가 아닌 경우 증권사 API에서 최신 상태 조회
|
||||||
|
if (!['FILLED', 'CANCELLED', 'REJECTED', 'EXPIRED'].includes(order.status)) {
|
||||||
|
const account = await getAccount(order.accountId)
|
||||||
|
const adapter = getBrokerAdapter(account.brokerId)
|
||||||
|
|
||||||
|
const latestStatus = await adapter.getOrderStatus(orderId)
|
||||||
|
|
||||||
|
// 상태가 변경된 경우 업데이트
|
||||||
|
if (latestStatus.status !== order.status) {
|
||||||
|
await updateOrderStatus(orderId, latestStatus.status, latestStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
return latestStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
orderId: order.orderId!,
|
||||||
|
status: order.status,
|
||||||
|
filledQuantity: order.filledQuantity,
|
||||||
|
averageFillPrice: order.averageFillPrice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 증권사 추상화 인터페이스
|
||||||
|
|
||||||
|
### BrokerAdapter 인터페이스
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 모든 증권사 어댑터가 구현해야 하는 인터페이스
|
||||||
|
*/
|
||||||
|
interface BrokerAdapter {
|
||||||
|
/**
|
||||||
|
* 증권사 API에 연결하고 세션을 생성합니다
|
||||||
|
*/
|
||||||
|
connect(credentials: Credentials): Promise<Session>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 계좌 잔고를 조회합니다
|
||||||
|
*/
|
||||||
|
getBalance(account: Account): Promise<Balance>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 종목의 현재 시세를 조회합니다
|
||||||
|
*/
|
||||||
|
getQuote(symbol: string): Promise<Quote>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 과거 가격 데이터를 조회합니다
|
||||||
|
*/
|
||||||
|
getHistoricalPrices(params: HistoricalPricesParams): Promise<PriceBar[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주문을 제출합니다
|
||||||
|
*/
|
||||||
|
submitOrder(order: Order): Promise<OrderResult>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주문을 취소합니다
|
||||||
|
*/
|
||||||
|
cancelOrder(orderId: string): Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주문 상태를 조회합니다
|
||||||
|
*/
|
||||||
|
getOrderStatus(orderId: string): Promise<OrderStatus>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 주문 이력을 조회합니다
|
||||||
|
*/
|
||||||
|
getOrderHistory(account: Account, from: Date, to: Date): Promise<Order[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 세션을 종료합니다
|
||||||
|
*/
|
||||||
|
disconnect(): Promise<void>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 구현 예시: 한국투자증권 Adapter
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class KoreaInvestmentAdapter implements BrokerAdapter {
|
||||||
|
private accessToken?: string
|
||||||
|
private tokenExpiry?: Date
|
||||||
|
|
||||||
|
async connect(credentials: Credentials): Promise<Session> {
|
||||||
|
// OAuth 토큰 발급
|
||||||
|
const response = await axios.post('https://openapi.koreainvestment.com/oauth2/token', {
|
||||||
|
grant_type: 'client_credentials',
|
||||||
|
appkey: credentials.apiKey,
|
||||||
|
appsecret: credentials.apiSecret
|
||||||
|
})
|
||||||
|
|
||||||
|
this.accessToken = response.data.access_token
|
||||||
|
this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000)
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessionId: response.data.access_token,
|
||||||
|
expiresAt: this.tokenExpiry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBalance(account: Account): Promise<Balance> {
|
||||||
|
await this.ensureConnected()
|
||||||
|
|
||||||
|
const response = await axios.get(
|
||||||
|
'https://openapi.koreainvestment.com/uapi/domestic-stock/v1/trading/inquire-balance',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${this.accessToken}`,
|
||||||
|
appkey: account.credentials.apiKey,
|
||||||
|
appsecret: account.credentials.apiSecret,
|
||||||
|
tr_id: 'TTTC8434R'
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
CANO: account.accountNumber.slice(0, 8),
|
||||||
|
ACNT_PRDT_CD: account.accountNumber.slice(8, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// API 응답을 공통 Balance 형식으로 변환
|
||||||
|
return this.transformBalance(response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitOrder(order: Order): Promise<OrderResult> {
|
||||||
|
await this.ensureConnected()
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
'https://openapi.koreainvestment.com/uapi/domestic-stock/v1/trading/order-cash',
|
||||||
|
{
|
||||||
|
CANO: order.accountId.slice(0, 8),
|
||||||
|
ACNT_PRDT_CD: order.accountId.slice(8, 10),
|
||||||
|
PDNO: order.symbol,
|
||||||
|
ORD_DVSN: order.orderType === 'MARKET' ? '01' : '00',
|
||||||
|
ORD_QTY: order.quantity.toString(),
|
||||||
|
ORD_UNPR: order.price?.toString() || '0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${this.accessToken}`,
|
||||||
|
tr_id: order.side === 'BUY' ? 'TTTC0802U' : 'TTTC0801U'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...order,
|
||||||
|
orderId: response.data.ODNO,
|
||||||
|
status: 'SUBMITTED',
|
||||||
|
submittedAt: new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ensureConnected(): Promise<void> {
|
||||||
|
if (!this.accessToken || !this.tokenExpiry || this.tokenExpiry < new Date()) {
|
||||||
|
throw new Error('세션이 만료되었습니다. 다시 연결하세요.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private transformBalance(apiResponse: any): Balance {
|
||||||
|
// 증권사 API 응답을 공통 형식으로 변환
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... 기타 메서드 구현
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
주요 데이터 모델은 [공통 데이터 모델](../../docs/03-data-models.md)을 참조하세요.
|
||||||
|
|
||||||
|
- [Account](../../docs/03-data-models.md#11-account-계좌)
|
||||||
|
- [Balance](../../docs/03-data-models.md#12-balance-잔고)
|
||||||
|
- [Position](../../docs/03-data-models.md#13-position-포지션)
|
||||||
|
- [Order](../../docs/03-data-models.md#41-order-주문)
|
||||||
|
- [Quote](../../docs/03-data-models.md#52-quote-현재가)
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
#### GET /api/accounts
|
||||||
|
계좌 목록 조회
|
||||||
|
|
||||||
|
**응답**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"id": "account-123",
|
||||||
|
"brokerId": "korea_investment",
|
||||||
|
"accountNumber": "1234567890",
|
||||||
|
"accountName": "메인 계좌",
|
||||||
|
"accountType": "STOCK",
|
||||||
|
"isActive": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### POST /api/accounts
|
||||||
|
계좌 등록
|
||||||
|
|
||||||
|
**요청**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"brokerId": "korea_investment",
|
||||||
|
"accountNumber": "1234567890",
|
||||||
|
"accountName": "메인 계좌",
|
||||||
|
"accountType": "STOCK",
|
||||||
|
"credentials": {
|
||||||
|
"apiKey": "...",
|
||||||
|
"apiSecret": "..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### GET /api/accounts/:accountId/balance
|
||||||
|
잔고 조회
|
||||||
|
|
||||||
|
**응답**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accountId": "account-123",
|
||||||
|
"cash": {
|
||||||
|
"krw": 5000000,
|
||||||
|
"usd": 0
|
||||||
|
},
|
||||||
|
"positions": [
|
||||||
|
{
|
||||||
|
"symbol": "005930",
|
||||||
|
"symbolName": "삼성전자",
|
||||||
|
"quantity": 100,
|
||||||
|
"averagePrice": 70000,
|
||||||
|
"currentPrice": 75000,
|
||||||
|
"marketValue": 7500000,
|
||||||
|
"unrealizedPnL": 500000,
|
||||||
|
"unrealizedPnLPct": 7.14
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalEquity": 12500000,
|
||||||
|
"buyingPower": 4800000,
|
||||||
|
"timestamp": "2024-01-15T09:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### POST /api/orders
|
||||||
|
주문 제출
|
||||||
|
|
||||||
|
**요청**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accountId": "account-123",
|
||||||
|
"symbol": "005930",
|
||||||
|
"side": "BUY",
|
||||||
|
"orderType": "LIMIT",
|
||||||
|
"quantity": 10,
|
||||||
|
"price": 74000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
### 1. 에러 처리 및 재시도
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 지수 백오프 재시도 로직
|
||||||
|
async function retryWithBackoff<T>(
|
||||||
|
fn: () => Promise<T>,
|
||||||
|
maxRetries: number = 3
|
||||||
|
): Promise<T> {
|
||||||
|
for (let i = 0; i < maxRetries; i++) {
|
||||||
|
try {
|
||||||
|
return await fn()
|
||||||
|
} catch (error) {
|
||||||
|
if (i === maxRetries - 1) throw error
|
||||||
|
|
||||||
|
// 재시도 가능한 에러인지 확인
|
||||||
|
if (!isRetryableError(error)) throw error
|
||||||
|
|
||||||
|
// 지수 백오프
|
||||||
|
const delay = Math.pow(2, i) * 1000
|
||||||
|
await sleep(delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Should not reach here')
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRetryableError(error: any): boolean {
|
||||||
|
// 네트워크 에러, 타임아웃, 5xx 에러 등
|
||||||
|
return (
|
||||||
|
error.code === 'ECONNRESET' ||
|
||||||
|
error.code === 'ETIMEDOUT' ||
|
||||||
|
(error.response?.status >= 500 && error.response?.status < 600)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Rate Limiting
|
||||||
|
|
||||||
|
증권사 API는 요청 제한이 있으므로 Rate Limiter 구현 필요:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class RateLimiter {
|
||||||
|
private queue: Array<() => Promise<any>> = []
|
||||||
|
private running: number = 0
|
||||||
|
private maxConcurrent: number
|
||||||
|
private minInterval: number
|
||||||
|
|
||||||
|
constructor(maxConcurrent: number = 5, minInterval: number = 100) {
|
||||||
|
this.maxConcurrent = maxConcurrent
|
||||||
|
this.minInterval = minInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute<T>(fn: () => Promise<T>): Promise<T> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.queue.push(async () => {
|
||||||
|
try {
|
||||||
|
const result = await fn()
|
||||||
|
resolve(result)
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.processQueue()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private async processQueue() {
|
||||||
|
if (this.running >= this.maxConcurrent || this.queue.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn = this.queue.shift()!
|
||||||
|
this.running++
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fn()
|
||||||
|
} finally {
|
||||||
|
this.running--
|
||||||
|
setTimeout(() => this.processQueue(), this.minInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 캐싱 전략
|
||||||
|
|
||||||
|
- **실시간 시세**: Redis에 5-10초 TTL로 캐싱
|
||||||
|
- **계좌 잔고**: 1분 TTL
|
||||||
|
- **주문 상태**: 캐싱 안함 (항상 최신 데이터)
|
||||||
|
|
||||||
|
### 4. 보안
|
||||||
|
|
||||||
|
- API 키는 절대 로그에 기록하지 않음
|
||||||
|
- 평문 API 키는 메모리에만 존재 (복호화 후 즉시 사용)
|
||||||
|
- HTTPS 필수
|
||||||
|
- API 키 로테이션 주기적 수행
|
||||||
|
|
||||||
|
## 테스트
|
||||||
|
|
||||||
|
### 단위 테스트 예시
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
describe('balance - placeOrder', () => {
|
||||||
|
it('should place a valid buy order', async () => {
|
||||||
|
const order = {
|
||||||
|
accountId: 'test-account',
|
||||||
|
symbol: 'TEST',
|
||||||
|
side: 'BUY',
|
||||||
|
orderType: 'LIMIT',
|
||||||
|
quantity: 10,
|
||||||
|
price: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await balance.placeOrder(order)
|
||||||
|
|
||||||
|
expect(result.orderId).toBeDefined()
|
||||||
|
expect(result.status).toBe('SUBMITTED')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should reject order with insufficient balance', async () => {
|
||||||
|
const order = {
|
||||||
|
accountId: 'test-account',
|
||||||
|
symbol: 'TEST',
|
||||||
|
side: 'BUY',
|
||||||
|
orderType: 'LIMIT',
|
||||||
|
quantity: 1000000,
|
||||||
|
price: 100000
|
||||||
|
}
|
||||||
|
|
||||||
|
await expect(balance.placeOrder(order)).rejects.toThrow('매수 가능 금액이 부족합니다')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](../../docs/01-overview.md)
|
||||||
|
- [전체 아키텍처](../../docs/02-architecture.md)
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
- [구현 로드맵](../../docs/05-roadmap.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [mgmt - 컨테이너 관리](./mgmt.md)
|
||||||
|
- [data - 데이터 관리](./data.md)
|
||||||
|
- [scheduler - 실행 스케줄러](./scheduler.md)
|
||||||
135
components/phase1/data.md
Normal file
135
components/phase1/data.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# data - 데이터 관리
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**data** 컴포넌트는 시계열 데이터 수집, 정제, 저장, 제공을 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 외부 데이터 소스 연동 및 수집 스케줄링
|
||||||
|
- 실시간 시세 스트리밍 및 캐시 업데이트
|
||||||
|
- 데이터 품질 검증/보정
|
||||||
|
- 백테스트 및 전략 실행을 위한 데이터 제공
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Data[data] --> Providers[Data Providers]
|
||||||
|
Data --> DB[(Time-series DB)]
|
||||||
|
Data --> Cache[(Redis Cache)]
|
||||||
|
|
||||||
|
Strategy[strategy] --> Data
|
||||||
|
Analytics[analytics] --> Data
|
||||||
|
Monitor[monitor] --> Data
|
||||||
|
|
||||||
|
style Data fill:#9C27B0,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 데이터 수집
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
collectMarketData(symbols: string[], from: Date, to: Date): void
|
||||||
|
updateRealTimeData(symbols: string[]): void
|
||||||
|
```
|
||||||
|
|
||||||
|
- 외부 제공자(Yahoo Finance, Alpha Vantage 등)에서 시세를 수집합니다.
|
||||||
|
- 증분 업데이트로 중복 수집을 방지합니다.
|
||||||
|
|
||||||
|
### 2. 데이터 제공
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getPriceHistory(symbol: string, from: Date, to: Date, interval: Interval): PriceBar[]
|
||||||
|
getLatestPrice(symbol: string): Price
|
||||||
|
getMultipleSymbols(symbols: string[], date: Date): Record<string, Price>
|
||||||
|
```
|
||||||
|
|
||||||
|
- 실시간 데이터는 캐시 우선으로 제공합니다.
|
||||||
|
|
||||||
|
### 3. 데이터 품질 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
validateData(symbol: string, from: Date, to: Date): ValidationReport
|
||||||
|
adjustForCorporateActions(symbol: string): void
|
||||||
|
fillMissingData(symbol: string, method: 'FORWARD_FILL' | 'INTERPOLATE'): void
|
||||||
|
```
|
||||||
|
|
||||||
|
- 결측치/이상치 탐지 및 보정 정책을 적용합니다.
|
||||||
|
|
||||||
|
### 4. 데이터 소스 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
addDataSource(source: DataSourceConfig): DataSource
|
||||||
|
syncDataSource(sourceId: string): SyncResult
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PriceBar {
|
||||||
|
symbol: string
|
||||||
|
timestamp: Date
|
||||||
|
open: number
|
||||||
|
high: number
|
||||||
|
low: number
|
||||||
|
close: number
|
||||||
|
volume: number
|
||||||
|
adjustedClose?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataSource {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
provider: 'BROKER' | 'YAHOO' | 'ALPHA_VANTAGE' | 'CUSTOM'
|
||||||
|
config: {
|
||||||
|
apiKey?: string
|
||||||
|
endpoint?: string
|
||||||
|
rateLimit?: number
|
||||||
|
}
|
||||||
|
coverage: {
|
||||||
|
symbols: string[]
|
||||||
|
intervals: string[]
|
||||||
|
delay: number
|
||||||
|
}
|
||||||
|
priority: number
|
||||||
|
isActive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ValidationReport {
|
||||||
|
symbol: string
|
||||||
|
period: { from: Date, to: Date }
|
||||||
|
issues: {
|
||||||
|
type: 'MISSING_DATA' | 'OUTLIER' | 'ZERO_VOLUME' | 'PRICE_GAP'
|
||||||
|
date: Date
|
||||||
|
description: string
|
||||||
|
severity: 'LOW' | 'MEDIUM' | 'HIGH'
|
||||||
|
}[]
|
||||||
|
completeness: number
|
||||||
|
quality: 'EXCELLENT' | 'GOOD' | 'FAIR' | 'POOR'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### GET /api/data/prices
|
||||||
|
가격 데이터 조회
|
||||||
|
|
||||||
|
### POST /api/data/sources
|
||||||
|
데이터 소스 추가
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 데이터 소스별 레이트 리밋을 준수합니다.
|
||||||
|
- 기업 이벤트(배당, 액면분할) 반영 규칙을 문서화합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [strategy - 전략 관리](./strategy.md)
|
||||||
|
- [analytics - 성과 분석](../phase2/analytics.md)
|
||||||
|
- [monitor - 모니터링](../phase2/monitor.md)
|
||||||
550
components/phase1/mgmt.md
Normal file
550
components/phase1/mgmt.md
Normal file
@@ -0,0 +1,550 @@
|
|||||||
|
# mgmt - 컨테이너 관리
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**mgmt** 컴포넌트는 가상 자산 컨테이너 생성 및 운영 관리를 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 컨테이너 생명주기 관리 (생성, 수정, 삭제, 활성화/비활성화)
|
||||||
|
- 가상 자산 격리 및 밸런스 관리
|
||||||
|
- 컨테이너 간 자산 이동
|
||||||
|
- 실제 계좌 vs 컨테이너 총합 일치성 검증 (Reconciliation)
|
||||||
|
|
||||||
|
### 핵심 개념
|
||||||
|
|
||||||
|
**컨테이너(Container)**는 하나의 실제 계좌 내에서 가상으로 분리된 자산 공간입니다.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "실제 계좌 (한국투자증권)"
|
||||||
|
Account[계좌 총 자산: 1억원]
|
||||||
|
|
||||||
|
subgraph "컨테이너 A"
|
||||||
|
A_Cash[현금: 500만원]
|
||||||
|
A_Stock[삼성전자: 2500만원]
|
||||||
|
A_Total[총 3000만원]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "컨테이너 B"
|
||||||
|
B_Cash[현금: 1000만원]
|
||||||
|
B_ETF[KODEX 200: 4000만원]
|
||||||
|
B_Total[총 5000만원]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "컨테이너 C"
|
||||||
|
C_Cash[현금: 2000만원]
|
||||||
|
C_Total[총 2000만원]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Account --> A_Total
|
||||||
|
Account --> B_Total
|
||||||
|
Account --> C_Total
|
||||||
|
|
||||||
|
style Account fill:#4CAF50,color:#fff
|
||||||
|
style A_Total fill:#2196F3,color:#fff
|
||||||
|
style B_Total fill:#2196F3,color:#fff
|
||||||
|
style C_Total fill:#2196F3,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Mgmt[mgmt] --> Balance[balance]
|
||||||
|
Mgmt --> Risk[risk]
|
||||||
|
Mgmt --> DB[(Database)]
|
||||||
|
|
||||||
|
Scheduler[scheduler] --> Mgmt
|
||||||
|
Analytics[analytics] --> Mgmt
|
||||||
|
Monitor[monitor] --> Mgmt
|
||||||
|
|
||||||
|
style Mgmt fill:#4CAF50,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 컨테이너 생명주기 관리
|
||||||
|
|
||||||
|
#### 1.1 컨테이너 생성
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 새로운 컨테이너를 생성합니다
|
||||||
|
*/
|
||||||
|
async function createContainer(params: {
|
||||||
|
accountId: string // 소속 계좌 ID
|
||||||
|
name: string // 컨테이너 이름
|
||||||
|
description?: string // 설명
|
||||||
|
initialAmount: number // 초기 할당 금액
|
||||||
|
cashReserve: number // 최소 현금 보유량
|
||||||
|
constraints: Constraints // 제약 조건
|
||||||
|
}): Promise<Container> {
|
||||||
|
// 1. 계좌 잔고 확인
|
||||||
|
const balance = await balance.getCurrentBalance(params.accountId)
|
||||||
|
|
||||||
|
// 2. 할당 가능 금액 검증
|
||||||
|
const allocatedSum = await getTotalAllocated(params.accountId)
|
||||||
|
if (allocatedSum + params.initialAmount > balance.totalEquity) {
|
||||||
|
throw new Error('할당 가능 금액을 초과합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 컨테이너 생성
|
||||||
|
const container = await db.containers.create({
|
||||||
|
...params,
|
||||||
|
status: 'ACTIVE',
|
||||||
|
allocation: {
|
||||||
|
initialAmount: params.initialAmount,
|
||||||
|
currentEquity: params.initialAmount,
|
||||||
|
cashReserve: params.cashReserve
|
||||||
|
},
|
||||||
|
createdAt: new Date()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. 초기 가상 잔고 생성
|
||||||
|
await createVirtualBalance(container.id, {
|
||||||
|
cash: params.initialAmount,
|
||||||
|
positions: []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 5. 감사 로그
|
||||||
|
await audit.logEvent({
|
||||||
|
eventType: 'CONFIG_CHANGE',
|
||||||
|
action: 'CREATE',
|
||||||
|
entity: 'Container',
|
||||||
|
entityId: container.id,
|
||||||
|
after: container
|
||||||
|
})
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 컨테이너 상태 관리
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Created: createContainer()
|
||||||
|
|
||||||
|
Created --> Active: activate()
|
||||||
|
Created --> [*]: delete()
|
||||||
|
|
||||||
|
Active --> Running: scheduler trigger
|
||||||
|
Active --> Paused: pause()
|
||||||
|
Active --> [*]: delete()
|
||||||
|
|
||||||
|
Running --> Active: execution complete
|
||||||
|
Running --> Error: execution failed
|
||||||
|
Running --> Paused: emergency stop
|
||||||
|
|
||||||
|
Paused --> Active: resume()
|
||||||
|
Paused --> [*]: delete()
|
||||||
|
|
||||||
|
Error --> Active: resolve & restart
|
||||||
|
Error --> Paused: manual intervention
|
||||||
|
Error --> [*]: delete()
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 컨테이너를 일시 정지합니다
|
||||||
|
*/
|
||||||
|
async function pauseContainer(containerId: string): Promise<void> {
|
||||||
|
const container = await getContainer(containerId)
|
||||||
|
|
||||||
|
if (container.status === 'ARCHIVED') {
|
||||||
|
throw new Error('삭제된 컨테이너는 일시 정지할 수 없습니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateContainerStatus(containerId, 'PAUSED')
|
||||||
|
|
||||||
|
// 실행 중인 스케줄 일시 정지
|
||||||
|
await scheduler.pauseSchedulesByContainer(containerId)
|
||||||
|
|
||||||
|
await audit.logEvent({
|
||||||
|
eventType: 'CONFIG_CHANGE',
|
||||||
|
action: 'UPDATE',
|
||||||
|
entity: 'Container',
|
||||||
|
entityId: containerId,
|
||||||
|
before: { status: container.status },
|
||||||
|
after: { status: 'PAUSED' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 가상 자산 격리
|
||||||
|
|
||||||
|
#### 2.1 가상 잔고 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 컨테이너의 가상 잔고를 조회합니다
|
||||||
|
*/
|
||||||
|
async function getContainerBalance(containerId: string): Promise<VirtualBalance> {
|
||||||
|
const virtualBalance = await db.virtualBalances.findOne({ containerId })
|
||||||
|
|
||||||
|
// 실시간 시세 반영
|
||||||
|
const updatedPositions = await Promise.all(
|
||||||
|
virtualBalance.positions.map(async (position) => {
|
||||||
|
const quote = await balance.getCurrentPrice(position.symbol)
|
||||||
|
return {
|
||||||
|
...position,
|
||||||
|
currentPrice: quote.price,
|
||||||
|
marketValue: position.quantity * quote.price,
|
||||||
|
unrealizedPnL: (quote.price - position.averagePrice) * position.quantity
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const totalValue = virtualBalance.cash + updatedPositions.reduce((sum, p) => sum + p.marketValue, 0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
containerId,
|
||||||
|
cash: virtualBalance.cash,
|
||||||
|
positions: updatedPositions,
|
||||||
|
totalValue,
|
||||||
|
availableCash: virtualBalance.cash,
|
||||||
|
allocatedValue: virtualBalance.allocatedValue,
|
||||||
|
timestamp: new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 포지션 업데이트
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 주문 체결 후 컨테이너 포지션을 업데이트합니다
|
||||||
|
*/
|
||||||
|
async function updatePosition(
|
||||||
|
containerId: string,
|
||||||
|
update: {
|
||||||
|
symbol: string
|
||||||
|
quantity: number // +: 매수, -: 매도
|
||||||
|
price: number
|
||||||
|
commission: number
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
|
const virtualBalance = await db.virtualBalances.findOne({ containerId })
|
||||||
|
|
||||||
|
if (update.quantity > 0) {
|
||||||
|
// 매수
|
||||||
|
const totalCost = update.quantity * update.price + update.commission
|
||||||
|
if (virtualBalance.cash < totalCost) {
|
||||||
|
throw new Error('가상 잔고가 부족합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualBalance.cash -= totalCost
|
||||||
|
|
||||||
|
// 기존 포지션 업데이트 또는 신규 추가
|
||||||
|
const existingPosition = virtualBalance.positions.find(p => p.symbol === update.symbol)
|
||||||
|
|
||||||
|
if (existingPosition) {
|
||||||
|
// 평균 매입가 재계산
|
||||||
|
const totalQuantity = existingPosition.quantity + update.quantity
|
||||||
|
const totalCost = existingPosition.averagePrice * existingPosition.quantity + update.price * update.quantity
|
||||||
|
existingPosition.averagePrice = totalCost / totalQuantity
|
||||||
|
existingPosition.quantity = totalQuantity
|
||||||
|
} else {
|
||||||
|
virtualBalance.positions.push({
|
||||||
|
symbol: update.symbol,
|
||||||
|
quantity: update.quantity,
|
||||||
|
averagePrice: update.price,
|
||||||
|
currentPrice: update.price,
|
||||||
|
marketValue: update.quantity * update.price,
|
||||||
|
unrealizedPnL: 0,
|
||||||
|
unrealizedPnLPct: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 매도
|
||||||
|
const position = virtualBalance.positions.find(p => p.symbol === update.symbol)
|
||||||
|
if (!position || position.quantity < Math.abs(update.quantity)) {
|
||||||
|
throw new Error('매도할 수량이 부족합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
const sellAmount = Math.abs(update.quantity) * update.price - update.commission
|
||||||
|
virtualBalance.cash += sellAmount
|
||||||
|
|
||||||
|
position.quantity += update.quantity // update.quantity는 음수
|
||||||
|
|
||||||
|
// 실현 손익 계산
|
||||||
|
const realizedPnL = (update.price - position.averagePrice) * Math.abs(update.quantity) - update.commission
|
||||||
|
|
||||||
|
// 포지션 완전 청산 시 제거
|
||||||
|
if (position.quantity === 0) {
|
||||||
|
virtualBalance.positions = virtualBalance.positions.filter(p => p.symbol !== update.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.virtualBalances.update({ containerId }, virtualBalance)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 컨테이너 간 자산 이동
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 컨테이너 간 현금을 이동합니다
|
||||||
|
*/
|
||||||
|
async function transferCash(params: {
|
||||||
|
fromContainerId: string
|
||||||
|
toContainerId: string
|
||||||
|
amount: number
|
||||||
|
reason?: string
|
||||||
|
}): Promise<Transfer> {
|
||||||
|
// 1. 출발 컨테이너 잔고 확인
|
||||||
|
const fromBalance = await getContainerBalance(params.fromContainerId)
|
||||||
|
if (fromBalance.availableCash < params.amount) {
|
||||||
|
throw new Error('이동 가능한 현금이 부족합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 두 컨테이너가 같은 계좌 소속인지 확인
|
||||||
|
const fromContainer = await getContainer(params.fromContainerId)
|
||||||
|
const toContainer = await getContainer(params.toContainerId)
|
||||||
|
|
||||||
|
if (fromContainer.accountId !== toContainer.accountId) {
|
||||||
|
throw new Error('같은 계좌 내 컨테이너 간에만 이동 가능합니다')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 트랜잭션으로 원자적 실행
|
||||||
|
await db.transaction(async (tx) => {
|
||||||
|
// 출발 컨테이너에서 차감
|
||||||
|
await tx.virtualBalances.update(
|
||||||
|
{ containerId: params.fromContainerId },
|
||||||
|
{ $inc: { cash: -params.amount } }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 도착 컨테이너에 추가
|
||||||
|
await tx.virtualBalances.update(
|
||||||
|
{ containerId: params.toContainerId },
|
||||||
|
{ $inc: { cash: params.amount } }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 이동 기록 생성
|
||||||
|
const transfer = await tx.transfers.create({
|
||||||
|
fromContainerId: params.fromContainerId,
|
||||||
|
toContainerId: params.toContainerId,
|
||||||
|
amount: params.amount,
|
||||||
|
reason: params.reason,
|
||||||
|
createdAt: new Date()
|
||||||
|
})
|
||||||
|
|
||||||
|
return transfer
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. 감사 로그
|
||||||
|
await audit.logEvent({
|
||||||
|
eventType: 'CONFIG_CHANGE',
|
||||||
|
action: 'TRANSFER',
|
||||||
|
entity: 'Transfer',
|
||||||
|
entityId: transfer.id,
|
||||||
|
metadata: params
|
||||||
|
})
|
||||||
|
|
||||||
|
return transfer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 밸런스 조정 (Reconciliation)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 실제 계좌 잔고와 컨테이너 총합이 일치하는지 검증합니다
|
||||||
|
*/
|
||||||
|
async function reconcileAssets(accountId: string): Promise<ReconciliationReport> {
|
||||||
|
// 1. 실제 계좌 잔고 조회
|
||||||
|
const actualBalance = await balance.getCurrentBalance(accountId)
|
||||||
|
|
||||||
|
// 2. 모든 컨테이너 잔고 합산
|
||||||
|
const containers = await getContainersByAccount(accountId)
|
||||||
|
const virtualBalances = await Promise.all(
|
||||||
|
containers.map(c => getContainerBalance(c.id))
|
||||||
|
)
|
||||||
|
|
||||||
|
const virtualTotal = {
|
||||||
|
cash: virtualBalances.reduce((sum, vb) => sum + vb.cash, 0),
|
||||||
|
positions: aggregatePositions(virtualBalances.map(vb => vb.positions))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 차이 검증
|
||||||
|
const cashDiscrepancy = actualBalance.cash.krw - virtualTotal.cash
|
||||||
|
const positionDiscrepancies = findPositionDiscrepancies(actualBalance.positions, virtualTotal.positions)
|
||||||
|
|
||||||
|
const isReconciled = Math.abs(cashDiscrepancy) < 100 && positionDiscrepancies.length === 0
|
||||||
|
|
||||||
|
const report: ReconciliationReport = {
|
||||||
|
accountId,
|
||||||
|
isReconciled,
|
||||||
|
actual: {
|
||||||
|
cash: actualBalance.cash.krw,
|
||||||
|
positions: actualBalance.positions
|
||||||
|
},
|
||||||
|
virtual: {
|
||||||
|
cash: virtualTotal.cash,
|
||||||
|
positions: virtualTotal.positions
|
||||||
|
},
|
||||||
|
discrepancies: {
|
||||||
|
cash: cashDiscrepancy,
|
||||||
|
positions: positionDiscrepancies
|
||||||
|
},
|
||||||
|
timestamp: new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 불일치 시 알림
|
||||||
|
if (!isReconciled) {
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'SYSTEM',
|
||||||
|
severity: 'ERROR',
|
||||||
|
message: `밸런스 불일치 감지: 계좌 ${accountId}`,
|
||||||
|
metadata: report
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return report
|
||||||
|
}
|
||||||
|
|
||||||
|
function aggregatePositions(positionGroups: Position[][]): Position[] {
|
||||||
|
const aggregated = new Map<string, Position>()
|
||||||
|
|
||||||
|
for (const positions of positionGroups) {
|
||||||
|
for (const position of positions) {
|
||||||
|
if (aggregated.has(position.symbol)) {
|
||||||
|
const existing = aggregated.get(position.symbol)!
|
||||||
|
existing.quantity += position.quantity
|
||||||
|
existing.marketValue += position.marketValue
|
||||||
|
} else {
|
||||||
|
aggregated.set(position.symbol, { ...position })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(aggregated.values())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
주요 데이터 모델:
|
||||||
|
- [Container](../../docs/03-data-models.md#21-container-컨테이너)
|
||||||
|
- [VirtualBalance](../../docs/03-data-models.md#22-virtualbalance-가상-잔고)
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### POST /api/containers
|
||||||
|
컨테이너 생성
|
||||||
|
|
||||||
|
**요청**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accountId": "account-123",
|
||||||
|
"name": "성장주 전략",
|
||||||
|
"initialAmount": 10000000,
|
||||||
|
"cashReserve": 1000000,
|
||||||
|
"constraints": {
|
||||||
|
"maxSinglePositionPct": 20,
|
||||||
|
"maxDrawdown": 15,
|
||||||
|
"allowedAssetClasses": ["STOCK"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /api/containers/:containerId
|
||||||
|
컨테이너 조회
|
||||||
|
|
||||||
|
**응답**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "container-456",
|
||||||
|
"accountId": "account-123",
|
||||||
|
"name": "성장주 전략",
|
||||||
|
"strategyId": "strategy-momentum",
|
||||||
|
"status": "ACTIVE",
|
||||||
|
"allocation": {
|
||||||
|
"initialAmount": 10000000,
|
||||||
|
"currentEquity": 10500000,
|
||||||
|
"cashReserve": 1000000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /api/containers/:containerId/balance
|
||||||
|
가상 잔고 조회
|
||||||
|
|
||||||
|
**응답**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"containerId": "container-456",
|
||||||
|
"cash": 3000000,
|
||||||
|
"positions": [
|
||||||
|
{
|
||||||
|
"symbol": "005930",
|
||||||
|
"quantity": 100,
|
||||||
|
"averagePrice": 70000,
|
||||||
|
"currentPrice": 75000,
|
||||||
|
"marketValue": 7500000,
|
||||||
|
"unrealizedPnL": 500000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalValue": 10500000,
|
||||||
|
"availableCash": 3000000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
### 1. 원자성 보장
|
||||||
|
|
||||||
|
컨테이너 간 자산 이동은 반드시 트랜잭션으로 처리하여 데이터 무결성을 보장해야 합니다.
|
||||||
|
|
||||||
|
### 2. 정기적인 Reconciliation
|
||||||
|
|
||||||
|
매일 장 마감 후 자동으로 Reconciliation 실행:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
scheduler.scheduleDaily('MARKET_CLOSE', async () => {
|
||||||
|
const accounts = await balance.getAllAccounts()
|
||||||
|
|
||||||
|
for (const account of accounts) {
|
||||||
|
const report = await mgmt.reconcileAssets(account.id)
|
||||||
|
|
||||||
|
if (!report.isReconciled) {
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'SYSTEM',
|
||||||
|
severity: 'CRITICAL',
|
||||||
|
message: `밸런스 불일치: ${account.accountName}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 컨테이너 삭제 시 주의사항
|
||||||
|
|
||||||
|
컨테이너 삭제 시 보유 포지션이 있다면 경고:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async function deleteContainer(containerId: string): Promise<void> {
|
||||||
|
const balance = await getContainerBalance(containerId)
|
||||||
|
|
||||||
|
if (balance.positions.length > 0) {
|
||||||
|
throw new Error('포지션이 남아있는 컨테이너는 삭제할 수 없습니다. 먼저 모든 포지션을 청산하세요.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARCHIVED 상태로 변경 (소프트 삭제)
|
||||||
|
await updateContainerStatus(containerId, 'ARCHIVED')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](../../docs/01-overview.md)
|
||||||
|
- [전체 아키텍처](../../docs/02-architecture.md)
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [balance - 계좌 관리](./balance.md)
|
||||||
|
- [strategy - 전략 관리](./strategy.md)
|
||||||
|
- [risk - 리스크 관리](./risk.md)
|
||||||
169
components/phase1/risk.md
Normal file
169
components/phase1/risk.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
# risk - 리스크 관리
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**risk** 컴포넌트는 사전 주문 검증과 포지션 리스크 모니터링을 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 주문 전 리스크 체크 (잔고, 포지션 한도, 레버리지)
|
||||||
|
- 포지션 리스크 지표 계산 (VaR, 베타, 집중도)
|
||||||
|
- 손절/익절 조건 관리 및 트리거 평가
|
||||||
|
- 리스크 한도 설정 및 위반 감지
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Risk[risk] --> Mgmt[mgmt]
|
||||||
|
Risk --> Balance[balance]
|
||||||
|
Risk --> Data[data]
|
||||||
|
Risk --> DB[(Database)]
|
||||||
|
|
||||||
|
Scheduler[scheduler] --> Risk
|
||||||
|
Monitor[monitor] --> Risk
|
||||||
|
|
||||||
|
style Risk fill:#E53935,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 사전 주문 검증
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
validateOrder(order: Order, container: Container): RiskCheckResult
|
||||||
|
validateOrderBatch(orders: Order[], container: Container): RiskCheckResult[]
|
||||||
|
```
|
||||||
|
|
||||||
|
- 잔고 충분성, 포지션 사이즈, 집중도, 레버리지를 검증합니다.
|
||||||
|
|
||||||
|
### 2. 포지션 리스크 모니터링
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
calculatePositionRisk(containerId: string): PositionRisk
|
||||||
|
checkRiskLimits(containerId: string): LimitViolation[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 손절/익절 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
setStopLoss(containerId: string, symbol: string, config: StopLossConfig): void
|
||||||
|
setTakeProfit(containerId: string, symbol: string, level: number): void
|
||||||
|
checkStopConditions(containerId: string): StopTrigger[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 리스크 한도 설정
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
setRiskLimits(containerId: string, limits: RiskLimits): void
|
||||||
|
getRiskProfile(containerId: string): RiskProfile
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 포트폴리오 리스크 분석
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
calculatePortfolioVaR(containerId: string, confidence: number, horizon: number): VaRResult
|
||||||
|
calculateCorrelationMatrix(containerId: string): CorrelationMatrix
|
||||||
|
stressTest(containerId: string, scenarios: Scenario[]): StressTestResult[]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface RiskLimits {
|
||||||
|
containerId: string
|
||||||
|
position: {
|
||||||
|
maxSinglePositionPct: number
|
||||||
|
maxSectorPct: number
|
||||||
|
maxTotalLeverage: number
|
||||||
|
}
|
||||||
|
loss: {
|
||||||
|
maxDailyLossPct: number
|
||||||
|
maxDrawdownPct: number
|
||||||
|
stopLossEnabled: boolean
|
||||||
|
}
|
||||||
|
exposure: {
|
||||||
|
maxLongExposure: number
|
||||||
|
maxShortExposure: number
|
||||||
|
maxGrossExposure: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RiskCheckResult {
|
||||||
|
passed: boolean
|
||||||
|
violations: {
|
||||||
|
rule: string
|
||||||
|
severity: 'BLOCKING' | 'WARNING'
|
||||||
|
message: string
|
||||||
|
currentValue: number
|
||||||
|
limitValue: number
|
||||||
|
}[]
|
||||||
|
recommendations?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PositionRisk {
|
||||||
|
containerId: string
|
||||||
|
positions: {
|
||||||
|
symbol: string
|
||||||
|
marketValue: number
|
||||||
|
weightPct: number
|
||||||
|
VaR95: number
|
||||||
|
beta: number
|
||||||
|
sector: string
|
||||||
|
}[]
|
||||||
|
portfolio: {
|
||||||
|
totalValue: number
|
||||||
|
totalVaR95: number
|
||||||
|
beta: number
|
||||||
|
correlationRisk: number
|
||||||
|
}
|
||||||
|
limits: {
|
||||||
|
type: string
|
||||||
|
current: number
|
||||||
|
limit: number
|
||||||
|
utilizationPct: number
|
||||||
|
}[]
|
||||||
|
calculatedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StopLossConfig {
|
||||||
|
type: 'FIXED' | 'TRAILING' | 'TIME_BASED'
|
||||||
|
fixedPrice?: number
|
||||||
|
fixedPct?: number
|
||||||
|
trailingPct?: number
|
||||||
|
holdingPeriodDays?: number
|
||||||
|
autoExecute: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VaRResult {
|
||||||
|
confidence: number
|
||||||
|
horizon: number
|
||||||
|
VaR: number
|
||||||
|
VaRPct: number
|
||||||
|
method: 'HISTORICAL' | 'PARAMETRIC' | 'MONTE_CARLO'
|
||||||
|
calculatedAt: Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### POST /api/risk/check
|
||||||
|
주문 리스크 체크
|
||||||
|
|
||||||
|
### GET /api/risk/containers/:containerId
|
||||||
|
리스크 프로필 조회
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 리스크 위반은 monitor 알림과 연동합니다.
|
||||||
|
- 한도 변경은 감사 로그로 추적합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [mgmt - 컨테이너 관리](./mgmt.md)
|
||||||
|
- [balance - 계좌 관리](./balance.md)
|
||||||
|
- [strategy - 전략 관리](./strategy.md)
|
||||||
149
components/phase1/scheduler.md
Normal file
149
components/phase1/scheduler.md
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
# scheduler - 실행 스케줄러
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**scheduler** 컴포넌트는 전략 실행 자동화, 리밸런싱, 승인 워크플로우를 관리합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 컨테이너별 실행 일정 관리
|
||||||
|
- 실행 트리거 및 리밸런싱 스케줄링
|
||||||
|
- 승인 요청 및 실행 흐름 제어
|
||||||
|
- 실행 이력 저장 및 알림
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Scheduler[scheduler] --> Mgmt[mgmt]
|
||||||
|
Scheduler --> Strategy[strategy]
|
||||||
|
Scheduler --> Risk[risk]
|
||||||
|
Scheduler --> Balance[balance]
|
||||||
|
Scheduler --> Monitor[monitor]
|
||||||
|
Scheduler --> DB[(Database)]
|
||||||
|
|
||||||
|
style Scheduler fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 스케줄 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
createSchedule(containerId: string, schedule: ScheduleConfig): Schedule
|
||||||
|
updateSchedule(scheduleId: string, config: Partial<ScheduleConfig>): Schedule
|
||||||
|
pauseSchedule(scheduleId: string): boolean
|
||||||
|
resumeSchedule(scheduleId: string): boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
- Cron/interval/이벤트 기반 트리거를 지원합니다.
|
||||||
|
- 시장 시간 및 휴일을 고려해 다음 실행 시점을 계산합니다.
|
||||||
|
|
||||||
|
### 2. 실행 트리거
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
executeStrategy(containerId: string, mode: 'AUTO' | 'MANUAL'): Execution
|
||||||
|
scheduleRebalancing(containerId: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
- 신호 생성 → 리스크 체크 → 주문 생성 → 승인 처리 순서로 실행합니다.
|
||||||
|
|
||||||
|
### 3. 승인 워크플로우
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
requestApproval(execution: Execution): ApprovalRequest
|
||||||
|
approveExecution(requestId: string, approved: boolean): boolean
|
||||||
|
autoExecuteWithNotification(execution: Execution): ExecutionResult
|
||||||
|
```
|
||||||
|
|
||||||
|
- 승인 모드에서는 예상 주문 내역과 비용을 사용자에게 제공합니다.
|
||||||
|
|
||||||
|
### 4. 실행 이력 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getExecutionHistory(containerId: string, from: Date): Execution[]
|
||||||
|
getExecutionDetail(executionId: string): ExecutionDetail
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Schedule {
|
||||||
|
id: string
|
||||||
|
containerId: string
|
||||||
|
trigger: {
|
||||||
|
type: 'CRON' | 'INTERVAL' | 'EVENT'
|
||||||
|
expression?: string
|
||||||
|
intervalMinutes?: number
|
||||||
|
event?: 'MARKET_OPEN' | 'MARKET_CLOSE'
|
||||||
|
}
|
||||||
|
executionMode: 'AUTO' | 'APPROVAL_REQUIRED'
|
||||||
|
constraints: {
|
||||||
|
marketHoursOnly: boolean
|
||||||
|
skipHolidays: boolean
|
||||||
|
minIntervalHours?: number
|
||||||
|
}
|
||||||
|
isActive: boolean
|
||||||
|
nextRun?: Date
|
||||||
|
lastRun?: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Execution {
|
||||||
|
id: string
|
||||||
|
containerId: string
|
||||||
|
strategyId: string
|
||||||
|
status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'RUNNING' | 'COMPLETED' | 'FAILED'
|
||||||
|
signals: Signal[]
|
||||||
|
plannedOrders: Order[]
|
||||||
|
executedOrders: Order[]
|
||||||
|
estimatedCost: {
|
||||||
|
commission: number
|
||||||
|
totalValue: number
|
||||||
|
}
|
||||||
|
approvalRequest?: ApprovalRequest
|
||||||
|
startedAt?: Date
|
||||||
|
completedAt?: Date
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApprovalRequest {
|
||||||
|
id: string
|
||||||
|
executionId: string
|
||||||
|
summary: {
|
||||||
|
numOrders: number
|
||||||
|
buyValue: number
|
||||||
|
sellValue: number
|
||||||
|
estimatedCommission: number
|
||||||
|
}
|
||||||
|
orders: Order[]
|
||||||
|
requestedAt: Date
|
||||||
|
expiresAt: Date
|
||||||
|
approvedAt?: Date
|
||||||
|
approvedBy?: string
|
||||||
|
decision?: 'APPROVED' | 'REJECTED'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### POST /api/schedules
|
||||||
|
스케줄 생성
|
||||||
|
|
||||||
|
### POST /api/executions/:executionId/approve
|
||||||
|
승인/거부 처리
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 승인 만료 처리 및 재요청 정책을 정의해야 합니다.
|
||||||
|
- 실행 실패 시 재시도/중단 기준을 명확히 둡니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [mgmt - 컨테이너 관리](./mgmt.md)
|
||||||
|
- [strategy - 전략 관리](./strategy.md)
|
||||||
|
- [risk - 리스크 관리](./risk.md)
|
||||||
|
- [balance - 계좌 관리](./balance.md)
|
||||||
177
components/phase1/strategy.md
Normal file
177
components/phase1/strategy.md
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# strategy - 전략 관리
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**strategy** 컴포넌트는 전략 등록, 버전 관리, 신호 생성, 백테스트를 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 전략 코드/메타데이터 등록 및 버전 관리
|
||||||
|
- 시장 데이터 기반 매매 신호 생성
|
||||||
|
- 신호를 주문으로 변환
|
||||||
|
- 백테스트 실행 및 성과 지표 계산
|
||||||
|
- 파라미터 관리 및 검증
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Strategy[strategy] --> Data[data]
|
||||||
|
Strategy --> Risk[risk]
|
||||||
|
Strategy --> DB[(Database)]
|
||||||
|
|
||||||
|
Scheduler[scheduler] --> Strategy
|
||||||
|
Analytics[analytics] --> Strategy
|
||||||
|
|
||||||
|
style Strategy fill:#2196F3,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 전략 등록 및 버전 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
registerStrategy(strategy: StrategyDefinition): Strategy
|
||||||
|
updateStrategy(id: string, version: StrategyVersion): Strategy
|
||||||
|
getStrategy(id: string, version?: string): Strategy
|
||||||
|
```
|
||||||
|
|
||||||
|
- 전략 코드와 파라미터 메타데이터를 저장합니다.
|
||||||
|
- 새 버전은 불변으로 보존하고 변경 이력을 추적합니다.
|
||||||
|
|
||||||
|
### 2. 전략 실행 엔진
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
calculateSignals(strategyId: string, marketData: MarketData): Signal[]
|
||||||
|
generateOrders(containerId: string, signals: Signal[]): Order[]
|
||||||
|
```
|
||||||
|
|
||||||
|
- 전략 신호를 생성하고 현재 포지션과 목표 포지션 차이로 주문을 계산합니다.
|
||||||
|
|
||||||
|
### 3. 백테스트
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
runBacktest(config: BacktestConfig): BacktestResult
|
||||||
|
calculateMetrics(backtestResult: BacktestResult): PerformanceMetrics
|
||||||
|
```
|
||||||
|
|
||||||
|
- 거래 비용과 슬리피지를 반영해 성과 지표를 산출합니다.
|
||||||
|
|
||||||
|
### 4. 파라미터 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getParameters(strategyId: string): Parameter[]
|
||||||
|
setParameters(strategyId: string, params: Record<string, any>): void
|
||||||
|
```
|
||||||
|
|
||||||
|
- 파라미터 타입/범위를 검증하고 실행 컨텍스트에 반영합니다.
|
||||||
|
|
||||||
|
### 전략 인터페이스
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface StrategyInterface {
|
||||||
|
initialize(context: StrategyContext): void
|
||||||
|
generateSignals(data: MarketData): Signal[]
|
||||||
|
|
||||||
|
onMarketOpen?(): void
|
||||||
|
onMarketClose?(): void
|
||||||
|
onOrderFilled?(order: Order): void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Strategy {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
category: 'ASSET_ALLOCATION' | 'MOMENTUM' | 'VALUE' | 'ARBITRAGE' | 'CUSTOM'
|
||||||
|
versions: StrategyVersion[]
|
||||||
|
currentVersion: string
|
||||||
|
parameters: Parameter[]
|
||||||
|
requiredData: string[]
|
||||||
|
createdBy: string
|
||||||
|
createdAt: Date
|
||||||
|
isPublic: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StrategyVersion {
|
||||||
|
version: string
|
||||||
|
code: string
|
||||||
|
changelog?: string
|
||||||
|
createdAt: Date
|
||||||
|
backtestResults?: BacktestResult[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Signal {
|
||||||
|
symbol: string
|
||||||
|
action: 'BUY' | 'SELL' | 'HOLD'
|
||||||
|
targetWeight?: number
|
||||||
|
targetQuantity?: number
|
||||||
|
reason?: string
|
||||||
|
confidence?: number
|
||||||
|
generatedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BacktestConfig {
|
||||||
|
strategyId: string
|
||||||
|
strategyVersion: string
|
||||||
|
startDate: Date
|
||||||
|
endDate: Date
|
||||||
|
initialCapital: number
|
||||||
|
universe: string[]
|
||||||
|
benchmark?: string
|
||||||
|
costs: {
|
||||||
|
commission: number
|
||||||
|
slippage: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BacktestResult {
|
||||||
|
strategyId: string
|
||||||
|
config: BacktestConfig
|
||||||
|
equity: {
|
||||||
|
date: Date
|
||||||
|
value: number
|
||||||
|
cash: number
|
||||||
|
positions: Record<string, number>
|
||||||
|
}[]
|
||||||
|
trades: {
|
||||||
|
date: Date
|
||||||
|
symbol: string
|
||||||
|
action: 'BUY' | 'SELL'
|
||||||
|
quantity: number
|
||||||
|
price: number
|
||||||
|
commission: number
|
||||||
|
}[]
|
||||||
|
metrics: PerformanceMetrics
|
||||||
|
runAt: Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### POST /api/strategies
|
||||||
|
전략 등록
|
||||||
|
|
||||||
|
### GET /api/strategies/:strategyId
|
||||||
|
전략 조회 (version 파라미터 지원)
|
||||||
|
|
||||||
|
### POST /api/strategies/:strategyId/backtests
|
||||||
|
백테스트 실행
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 전략 코드 저장 시 보안 검토 및 샌드박스 실행 환경을 고려합니다.
|
||||||
|
- 파라미터 변경은 감사 로그에 기록합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](../../docs/01-overview.md)
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [data - 데이터 관리](./data.md)
|
||||||
|
- [risk - 리스크 관리](./risk.md)
|
||||||
|
- [scheduler - 실행 스케줄러](./scheduler.md)
|
||||||
211
components/phase2/analytics.md
Normal file
211
components/phase2/analytics.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# analytics - 성과 분석 및 리포팅
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**analytics** 컴포넌트는 실거래 성과 측정, 귀속 분석, 리포팅을 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 기간별 수익률 및 리스크 지표 계산
|
||||||
|
- 귀속 분석(자산 배분, 종목 선택, 타이밍)
|
||||||
|
- 거래 분석 및 비용 추정
|
||||||
|
- 정기 리포트 생성 및 배포
|
||||||
|
- 벤치마크 대비 성과 비교
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Analytics[analytics] --> Mgmt[mgmt]
|
||||||
|
Analytics --> Balance[balance]
|
||||||
|
Analytics --> Data[data]
|
||||||
|
Analytics --> DB[(Database)]
|
||||||
|
|
||||||
|
Monitor[monitor] --> Analytics
|
||||||
|
|
||||||
|
style Analytics fill:#3F51B5,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 성과 측정
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
calculatePerformance(containerId: string, period: DateRange): PerformanceReport
|
||||||
|
getReturnsTimeseries(containerId: string, from: Date): TimeseriesData
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 귀속 분석
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
analyzeReturns(containerId: string, period: DateRange): AttributionReport
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 거래 분석
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
analyzeTrades(containerId: string, from: Date): TradeAnalysis
|
||||||
|
calculateTradingCosts(containerId: string, period: DateRange): CostAnalysis
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 리포트 생성
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
generateReport(containerId: string, type: ReportType, period: DateRange): Report
|
||||||
|
scheduleReport(config: ReportSchedule): void
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 벤치마크 비교
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
compareWithBenchmark(containerId: string, benchmarkSymbol: string, period: DateRange): ComparisonReport
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PerformanceReport {
|
||||||
|
containerId: string
|
||||||
|
period: DateRange
|
||||||
|
returns: {
|
||||||
|
total: number
|
||||||
|
annualized: number
|
||||||
|
daily: number
|
||||||
|
weekly: number
|
||||||
|
monthly: number
|
||||||
|
ytd: number
|
||||||
|
}
|
||||||
|
risk: {
|
||||||
|
volatility: number
|
||||||
|
sharpeRatio: number
|
||||||
|
sortinoRatio: number
|
||||||
|
maxDrawdown: number
|
||||||
|
calmarRatio: number
|
||||||
|
}
|
||||||
|
benchmark?: {
|
||||||
|
symbol: string
|
||||||
|
returns: number
|
||||||
|
excessReturn: number
|
||||||
|
beta: number
|
||||||
|
alpha: number
|
||||||
|
trackingError: number
|
||||||
|
informationRatio: number
|
||||||
|
}
|
||||||
|
generatedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AttributionReport {
|
||||||
|
containerId: string
|
||||||
|
period: DateRange
|
||||||
|
totalReturn: number
|
||||||
|
attribution: {
|
||||||
|
assetAllocation: number
|
||||||
|
stockSelection: number
|
||||||
|
timing: number
|
||||||
|
interaction: number
|
||||||
|
}
|
||||||
|
sectorContribution: {
|
||||||
|
sector: string
|
||||||
|
weight: number
|
||||||
|
return: number
|
||||||
|
contribution: number
|
||||||
|
}[]
|
||||||
|
topContributors: {
|
||||||
|
symbol: string
|
||||||
|
contribution: number
|
||||||
|
}[]
|
||||||
|
topDetractors: {
|
||||||
|
symbol: string
|
||||||
|
contribution: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TradeAnalysis {
|
||||||
|
containerId: string
|
||||||
|
period: DateRange
|
||||||
|
summary: {
|
||||||
|
totalTrades: number
|
||||||
|
winningTrades: number
|
||||||
|
losingTrades: number
|
||||||
|
winRate: number
|
||||||
|
avgWin: number
|
||||||
|
avgLoss: number
|
||||||
|
profitFactor: number
|
||||||
|
avgHoldingPeriod: number
|
||||||
|
turnoverRate: number
|
||||||
|
}
|
||||||
|
longestWinStreak: number
|
||||||
|
longestLossStreak: number
|
||||||
|
largestWin: {
|
||||||
|
symbol: string
|
||||||
|
return: number
|
||||||
|
date: Date
|
||||||
|
}
|
||||||
|
largestLoss: {
|
||||||
|
symbol: string
|
||||||
|
return: number
|
||||||
|
date: Date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CostAnalysis {
|
||||||
|
period: DateRange
|
||||||
|
costs: {
|
||||||
|
commission: number
|
||||||
|
estimatedSlippage: number
|
||||||
|
tax: number
|
||||||
|
other: number
|
||||||
|
total: number
|
||||||
|
}
|
||||||
|
impact: {
|
||||||
|
grossReturn: number
|
||||||
|
netReturn: number
|
||||||
|
costDrag: number
|
||||||
|
}
|
||||||
|
costByType: {
|
||||||
|
buy: number
|
||||||
|
sell: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Report {
|
||||||
|
id: string
|
||||||
|
containerId: string
|
||||||
|
type: ReportType
|
||||||
|
period: DateRange
|
||||||
|
sections: {
|
||||||
|
summary: PerformanceSummary
|
||||||
|
positions: CurrentPositions
|
||||||
|
trades: RecentTrades
|
||||||
|
performance: PerformanceCharts
|
||||||
|
attribution: AttributionAnalysis
|
||||||
|
risk: RiskMetrics
|
||||||
|
}
|
||||||
|
format: 'PDF' | 'HTML' | 'JSON'
|
||||||
|
fileUrl?: string
|
||||||
|
generatedAt: Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### GET /api/analytics/containers/:containerId/performance
|
||||||
|
성과 리포트 조회
|
||||||
|
|
||||||
|
### POST /api/analytics/containers/:containerId/reports
|
||||||
|
리포트 생성
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 성과 계산 시 배당/분할 조정 데이터를 일관되게 사용합니다.
|
||||||
|
- 리포트 생성은 비동기 작업으로 처리합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [공통 데이터 모델](../../docs/03-data-models.md)
|
||||||
|
- [구현 로드맵](../../docs/05-roadmap.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [data - 데이터 관리](../phase1/data.md)
|
||||||
|
- [monitor - 모니터링](./monitor.md)
|
||||||
|
- [risk - 리스크 관리](../phase1/risk.md)
|
||||||
209
components/phase2/monitor.md
Normal file
209
components/phase2/monitor.md
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# monitor - 모니터링 및 알림
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**monitor** 컴포넌트는 시스템 상태 감시, 이상 탐지, 알림 발송을 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 컴포넌트 헬스 체크 및 연결 상태 모니터링
|
||||||
|
- 이상 거래/리스크 이벤트 탐지
|
||||||
|
- 알림 규칙 관리 및 다채널 발송
|
||||||
|
- 대시보드용 실시간 지표 제공
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Monitor[monitor] --> Balance[balance]
|
||||||
|
Monitor --> Analytics[analytics]
|
||||||
|
Monitor --> Risk[risk]
|
||||||
|
Monitor --> DB[(Database)]
|
||||||
|
|
||||||
|
Scheduler[scheduler] --> Monitor
|
||||||
|
|
||||||
|
style Monitor fill:#009688,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 시스템 헬스 체크
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
checkSystemHealth(): HealthStatus
|
||||||
|
monitorApiConnections(): ConnectionStatus[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 이상 거래 탐지
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
detectAnomalies(containerId: string): Anomaly[]
|
||||||
|
checkMarketConditions(): MarketAlert[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 알림 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
sendAlert(alert: Alert): void
|
||||||
|
configureAlertRules(rules: AlertRule[]): void
|
||||||
|
getAlertHistory(from: Date, severity?: AlertSeverity): Alert[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 대시보드 데이터
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getDashboardData(): DashboardSnapshot
|
||||||
|
getRealtimeMetrics(containerId: string): RealtimeMetrics
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 성능 모니터링
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
trackLatency(operation: string, duration: number): void
|
||||||
|
logError(error: Error, context: any): void
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface HealthStatus {
|
||||||
|
overall: 'HEALTHY' | 'DEGRADED' | 'DOWN'
|
||||||
|
components: {
|
||||||
|
name: string
|
||||||
|
status: 'UP' | 'DOWN' | 'SLOW'
|
||||||
|
responseTime?: number
|
||||||
|
lastCheck: Date
|
||||||
|
message?: string
|
||||||
|
}[]
|
||||||
|
connections: {
|
||||||
|
broker: 'CONNECTED' | 'DISCONNECTED' | 'ERROR'
|
||||||
|
database: 'CONNECTED' | 'DISCONNECTED'
|
||||||
|
dataProviders: Record<string, 'CONNECTED' | 'DISCONNECTED'>
|
||||||
|
}
|
||||||
|
resources: {
|
||||||
|
cpuUsage: number
|
||||||
|
memoryUsage: number
|
||||||
|
diskUsage: number
|
||||||
|
}
|
||||||
|
checkedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Anomaly {
|
||||||
|
type: 'POSITION_SPIKE' | 'UNUSUAL_ORDER' | 'UNEXPECTED_FILL' | 'HIGH_IMPACT'
|
||||||
|
severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
||||||
|
containerId: string
|
||||||
|
description: string
|
||||||
|
details: {
|
||||||
|
expected?: any
|
||||||
|
actual: any
|
||||||
|
threshold?: any
|
||||||
|
}
|
||||||
|
detectedAt: Date
|
||||||
|
resolved: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Alert {
|
||||||
|
id: string
|
||||||
|
type: 'SYSTEM' | 'RISK' | 'EXECUTION' | 'PERFORMANCE' | 'ANOMALY'
|
||||||
|
severity: 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL'
|
||||||
|
title: string
|
||||||
|
message: string
|
||||||
|
source: string
|
||||||
|
containerId?: string
|
||||||
|
channels: ('EMAIL' | 'SMS' | 'PUSH' | 'SLACK')[]
|
||||||
|
sentAt?: Date
|
||||||
|
acknowledged: boolean
|
||||||
|
acknowledgedAt?: Date
|
||||||
|
acknowledgedBy?: string
|
||||||
|
createdAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AlertRule {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
condition: {
|
||||||
|
metric: string
|
||||||
|
operator: '>' | '<' | '=' | '>=' | '<='
|
||||||
|
threshold: number
|
||||||
|
}
|
||||||
|
severity: AlertSeverity
|
||||||
|
channels: AlertChannel[]
|
||||||
|
throttle: {
|
||||||
|
enabled: boolean
|
||||||
|
minIntervalMinutes: number
|
||||||
|
}
|
||||||
|
isActive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DashboardSnapshot {
|
||||||
|
accounts: {
|
||||||
|
accountId: string
|
||||||
|
totalEquity: number
|
||||||
|
cashBalance: number
|
||||||
|
todayPnL: number
|
||||||
|
todayReturn: number
|
||||||
|
}[]
|
||||||
|
containers: {
|
||||||
|
containerId: string
|
||||||
|
name: string
|
||||||
|
status: 'ACTIVE' | 'PAUSED'
|
||||||
|
equity: number
|
||||||
|
todayReturn: number
|
||||||
|
activeStrategy: string
|
||||||
|
lastRebalanced: Date
|
||||||
|
}[]
|
||||||
|
recentExecutions: {
|
||||||
|
executionId: string
|
||||||
|
containerId: string
|
||||||
|
status: string
|
||||||
|
completedAt: Date
|
||||||
|
}[]
|
||||||
|
activeAlerts: Alert[]
|
||||||
|
systemHealth: 'HEALTHY' | 'DEGRADED' | 'DOWN'
|
||||||
|
timestamp: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RealtimeMetrics {
|
||||||
|
containerId: string
|
||||||
|
current: {
|
||||||
|
equity: number
|
||||||
|
cash: number
|
||||||
|
positionsCount: number
|
||||||
|
}
|
||||||
|
today: {
|
||||||
|
pnl: number
|
||||||
|
return: number
|
||||||
|
tradesCount: number
|
||||||
|
}
|
||||||
|
risk: {
|
||||||
|
currentDrawdown: number
|
||||||
|
VaR95: number
|
||||||
|
leverage: number
|
||||||
|
}
|
||||||
|
updatedAt: Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### GET /api/monitor/health
|
||||||
|
헬스 체크 상태 조회
|
||||||
|
|
||||||
|
### GET /api/monitor/alerts
|
||||||
|
알림 이력 조회
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 알림 폭주를 방지하기 위해 스로틀 정책을 필수로 둡니다.
|
||||||
|
- 심각도 기준을 명확히 정의하고 대시보드에 반영합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
- [구현 로드맵](../../docs/05-roadmap.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [analytics - 성과 분석](./analytics.md)
|
||||||
|
- [risk - 리스크 관리](../phase1/risk.md)
|
||||||
|
- [balance - 계좌 관리](../phase1/balance.md)
|
||||||
165
components/phase3/audit.md
Normal file
165
components/phase3/audit.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# audit - 감사 및 로깅
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**audit** 컴포넌트는 불변 감사 로그와 규제 리포팅을 담당합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- 중요 이벤트 불변 저장 및 해시 체인 관리
|
||||||
|
- 변경 이력 추적 및 감사 추적 제공
|
||||||
|
- 규제 리포트 생성 및 데이터 экспорт
|
||||||
|
- 데이터 보존 정책 적용 및 무결성 검증
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Audit[audit] --> DB[(Database)]
|
||||||
|
Audit --> Storage[(Archive Storage)]
|
||||||
|
|
||||||
|
Balance[balance] --> Audit
|
||||||
|
Mgmt[mgmt] --> Audit
|
||||||
|
Strategy[strategy] --> Audit
|
||||||
|
Scheduler[scheduler] --> Audit
|
||||||
|
|
||||||
|
style Audit fill:#795548,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. 감사 로그 기록
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
logEvent(event: AuditEvent): void
|
||||||
|
logOrderActivity(order: Order, action: OrderAction): void
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 변경 이력 추적
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
trackConfigChange(entity: string, entityId: string, changes: any): void
|
||||||
|
getChangeHistory(entity: string, entityId: string): ChangeLog[]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 규제 리포팅
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
generateComplianceReport(type: ComplianceReportType, period: DateRange): ComplianceReport
|
||||||
|
exportAuditTrail(from: Date, to: Date, format: 'CSV' | 'JSON'): File
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 데이터 보존 정책
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
archiveOldData(cutoffDate: Date): ArchiveResult
|
||||||
|
retainCriticalData(dataType: string, retentionYears: number): void
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 무결성 검증
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
verifyAuditIntegrity(from: Date, to: Date): IntegrityReport
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface AuditEvent {
|
||||||
|
id: string
|
||||||
|
timestamp: Date
|
||||||
|
eventType: 'ORDER' | 'CONFIG_CHANGE' | 'EXECUTION' | 'LOGIN' | 'DATA_EXPORT'
|
||||||
|
action: string
|
||||||
|
userId?: string
|
||||||
|
containerId?: string
|
||||||
|
entity: string
|
||||||
|
entityId: string
|
||||||
|
before?: any
|
||||||
|
after?: any
|
||||||
|
metadata: {
|
||||||
|
ipAddress?: string
|
||||||
|
userAgent?: string
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
hash: string
|
||||||
|
previousHash?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChangeLog {
|
||||||
|
timestamp: Date
|
||||||
|
changedBy: string
|
||||||
|
field: string
|
||||||
|
oldValue: any
|
||||||
|
newValue: any
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ComplianceReport {
|
||||||
|
type: 'TRADE_HISTORY' | 'POSITION_STATEMENT' | 'UNUSUAL_ACTIVITY'
|
||||||
|
period: DateRange
|
||||||
|
trades: {
|
||||||
|
date: Date
|
||||||
|
orderId: string
|
||||||
|
symbol: string
|
||||||
|
side: 'BUY' | 'SELL'
|
||||||
|
quantity: number
|
||||||
|
price: number
|
||||||
|
value: number
|
||||||
|
}[]
|
||||||
|
positions: {
|
||||||
|
symbol: string
|
||||||
|
quantity: number
|
||||||
|
averagePrice: number
|
||||||
|
marketValue: number
|
||||||
|
unrealizedPnL: number
|
||||||
|
}[]
|
||||||
|
unusualActivities: {
|
||||||
|
date: Date
|
||||||
|
type: string
|
||||||
|
description: string
|
||||||
|
resolution: string
|
||||||
|
}[]
|
||||||
|
generatedAt: Date
|
||||||
|
certifiedBy?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IntegrityReport {
|
||||||
|
period: DateRange
|
||||||
|
totalEvents: number
|
||||||
|
verification: {
|
||||||
|
hashChainValid: boolean
|
||||||
|
noGaps: boolean
|
||||||
|
noModifications: boolean
|
||||||
|
}
|
||||||
|
issues: {
|
||||||
|
eventId: string
|
||||||
|
issue: string
|
||||||
|
severity: 'LOW' | 'HIGH'
|
||||||
|
}[]
|
||||||
|
overall: 'PASS' | 'FAIL'
|
||||||
|
verifiedAt: Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### GET /api/audit/events
|
||||||
|
감사 이벤트 조회
|
||||||
|
|
||||||
|
### POST /api/audit/reports
|
||||||
|
규제 리포트 생성
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 해시 체인 단절 방지 및 재생성 불가 정책을 문서화합니다.
|
||||||
|
- 민감 데이터 마스킹 규칙을 명확히 둡니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [구현 로드맵](../../docs/05-roadmap.md)
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [scheduler - 실행 스케줄러](../phase1/scheduler.md)
|
||||||
|
- [balance - 계좌 관리](../phase1/balance.md)
|
||||||
|
- [risk - 리스크 관리](../phase1/risk.md)
|
||||||
207
components/phase3/simulation.md
Normal file
207
components/phase3/simulation.md
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# simulation - 시뮬레이션 환경
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
**simulation** 컴포넌트는 Paper Trading, 시나리오 테스트, 파라미터 최적화를 제공하여 실전 전 검증을 지원합니다.
|
||||||
|
|
||||||
|
### 책임
|
||||||
|
|
||||||
|
- Paper Trading 계좌/주문 실행
|
||||||
|
- 전략 시뮬레이션 및 비교
|
||||||
|
- 파라미터 최적화 및 과최적화 검증
|
||||||
|
- 몬테카를로 및 스트레스 테스트
|
||||||
|
- 실계좌 전환 계획 생성
|
||||||
|
|
||||||
|
### 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
Simulation[simulation] --> Strategy[strategy]
|
||||||
|
Simulation --> Risk[risk]
|
||||||
|
Simulation --> Data[data]
|
||||||
|
Simulation --> Analytics[analytics]
|
||||||
|
Simulation --> DB[(Database)]
|
||||||
|
|
||||||
|
Audit[audit] --> Simulation
|
||||||
|
|
||||||
|
style Simulation fill:#607D8B,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
### 1. Paper Trading
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
createPaperAccount(config: PaperAccountConfig): PaperAccount
|
||||||
|
executePaperTrade(order: Order): PaperOrderResult
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 전략 시뮬레이션
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
runSimulation(config: SimulationConfig): SimulationResult
|
||||||
|
compareStrategies(strategyIds: string[], config: SimulationConfig): ComparisonResult
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 파라미터 최적화
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
optimizeParameters(strategyId: string, searchSpace: ParameterSpace): OptimizationResult
|
||||||
|
validateOptimization(result: OptimizationResult, outOfSampleData: MarketData): ValidationResult
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 시나리오 테스트
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
testScenario(containerId: string, scenario: Scenario): ScenarioResult
|
||||||
|
runMonteCarloSimulation(containerId: string, iterations: number): MonteCarloResult
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 전환 지원
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
promoteToProd(paperAccountId: string, realAccountId: string): MigrationPlan
|
||||||
|
cloneContainer(sourceId: string, targetAccountId: string): Container
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 모델
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PaperAccount {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
balance: {
|
||||||
|
initialCash: number
|
||||||
|
currentCash: number
|
||||||
|
positions: Position[]
|
||||||
|
totalEquity: number
|
||||||
|
}
|
||||||
|
settings: {
|
||||||
|
commissionModel: 'FIXED' | 'PERCENTAGE'
|
||||||
|
commissionRate: number
|
||||||
|
slippageModel: 'FIXED_BPS' | 'VOLUME_BASED'
|
||||||
|
slippageBps: number
|
||||||
|
}
|
||||||
|
isActive: boolean
|
||||||
|
createdAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimulationConfig {
|
||||||
|
strategyId: string
|
||||||
|
startDate: Date
|
||||||
|
endDate: Date
|
||||||
|
initialCapital: number
|
||||||
|
universe: string[]
|
||||||
|
costs: {
|
||||||
|
commission: number
|
||||||
|
slippage: number
|
||||||
|
tax: number
|
||||||
|
}
|
||||||
|
constraints: RiskLimits
|
||||||
|
rebalanceFrequency: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimulationResult {
|
||||||
|
config: SimulationConfig
|
||||||
|
performance: PerformanceMetrics
|
||||||
|
equity: {
|
||||||
|
date: Date
|
||||||
|
value: number
|
||||||
|
}[]
|
||||||
|
trades: {
|
||||||
|
date: Date
|
||||||
|
symbol: string
|
||||||
|
action: 'BUY' | 'SELL'
|
||||||
|
quantity: number
|
||||||
|
price: number
|
||||||
|
}[]
|
||||||
|
drawdowns: {
|
||||||
|
start: Date
|
||||||
|
end: Date
|
||||||
|
depth: number
|
||||||
|
recovery: number
|
||||||
|
}[]
|
||||||
|
completedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParameterSpace {
|
||||||
|
parameters: {
|
||||||
|
name: string
|
||||||
|
type: 'INTEGER' | 'FLOAT' | 'CATEGORICAL'
|
||||||
|
min?: number
|
||||||
|
max?: number
|
||||||
|
step?: number
|
||||||
|
values?: any[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptimizationResult {
|
||||||
|
strategyId: string
|
||||||
|
searchSpace: ParameterSpace
|
||||||
|
bestParameters: Record<string, any>
|
||||||
|
bestMetric: number
|
||||||
|
trials: {
|
||||||
|
parameters: Record<string, any>
|
||||||
|
metrics: PerformanceMetrics
|
||||||
|
}[]
|
||||||
|
optimizationTime: number
|
||||||
|
warnings: {
|
||||||
|
overfitting: boolean
|
||||||
|
insufficientData: boolean
|
||||||
|
unstableParameters: string[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MonteCarloResult {
|
||||||
|
iterations: number
|
||||||
|
returns: {
|
||||||
|
mean: number
|
||||||
|
median: number
|
||||||
|
std: number
|
||||||
|
percentiles: {
|
||||||
|
p5: number
|
||||||
|
p25: number
|
||||||
|
p75: number
|
||||||
|
p95: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drawdowns: {
|
||||||
|
mean: number
|
||||||
|
max: number
|
||||||
|
percentiles: {
|
||||||
|
p95: number
|
||||||
|
p99: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
probabilities: {
|
||||||
|
profit: number
|
||||||
|
loss10pct: number
|
||||||
|
loss20pct: number
|
||||||
|
}
|
||||||
|
distribution: number[]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 명세
|
||||||
|
|
||||||
|
### POST /api/simulation/run
|
||||||
|
시뮬레이션 실행
|
||||||
|
|
||||||
|
### POST /api/simulation/optimize
|
||||||
|
파라미터 최적화
|
||||||
|
|
||||||
|
## 구현 고려사항
|
||||||
|
|
||||||
|
- 과최적화 경고 기준을 명확히 정의합니다.
|
||||||
|
- Paper Trading과 실계좌 체결 차이를 리포트에 표시합니다.
|
||||||
|
|
||||||
|
## 관련 문서
|
||||||
|
|
||||||
|
- [구현 로드맵](../../docs/05-roadmap.md)
|
||||||
|
- [주요 워크플로우](../../docs/04-workflows.md)
|
||||||
|
|
||||||
|
### 관련 컴포넌트
|
||||||
|
- [strategy - 전략 관리](../phase1/strategy.md)
|
||||||
|
- [risk - 리스크 관리](../phase1/risk.md)
|
||||||
|
- [analytics - 성과 분석](../phase2/analytics.md)
|
||||||
|
- [audit - 감사 및 로깅](./audit.md)
|
||||||
616
diagram.md
Normal file
616
diagram.md
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
# QuantBench System Architecture - Mermaid Diagrams
|
||||||
|
|
||||||
|
## 1. 전체 시스템 아키텍처 (All Phases)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "User Layer"
|
||||||
|
UI[User Interface<br/>Web/Mobile/Desktop]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "API Layer"
|
||||||
|
Gateway[API Gateway<br/>Authentication & Rate Limiting]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 1 - Core Components"
|
||||||
|
Balance[balance<br/>계좌 관리]
|
||||||
|
Mgmt[mgmt<br/>컨테이너 관리]
|
||||||
|
Strategy[strategy<br/>전략 관리]
|
||||||
|
Scheduler[scheduler<br/>실행 스케줄러]
|
||||||
|
Risk[risk<br/>리스크 관리]
|
||||||
|
Data[data<br/>데이터 관리]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 2 - Production Ready"
|
||||||
|
Analytics[analytics<br/>성과 분석]
|
||||||
|
Monitor[monitor<br/>모니터링 & 알림]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 3 - Enterprise Grade"
|
||||||
|
Audit[audit<br/>감사 로깅]
|
||||||
|
Simulation[simulation<br/>시뮬레이션]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Infrastructure"
|
||||||
|
MQ[Message Queue<br/>Kafka/RabbitMQ]
|
||||||
|
DB[(Database<br/>PostgreSQL)]
|
||||||
|
Cache[(Cache<br/>Redis)]
|
||||||
|
Storage[(Object Storage<br/>S3)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "External Systems"
|
||||||
|
Broker1[한국투자증권 API]
|
||||||
|
Broker2[삼성증권 API]
|
||||||
|
Broker3[키움증권 API]
|
||||||
|
DataProvider[Data Providers<br/>Yahoo/Alpha Vantage]
|
||||||
|
end
|
||||||
|
|
||||||
|
UI --> Gateway
|
||||||
|
Gateway --> Mgmt
|
||||||
|
Gateway --> Strategy
|
||||||
|
Gateway --> Scheduler
|
||||||
|
Gateway --> Analytics
|
||||||
|
Gateway --> Monitor
|
||||||
|
Gateway --> Simulation
|
||||||
|
|
||||||
|
Scheduler --> Strategy
|
||||||
|
Scheduler --> Mgmt
|
||||||
|
Scheduler --> Risk
|
||||||
|
Scheduler --> Balance
|
||||||
|
|
||||||
|
Strategy --> Data
|
||||||
|
Strategy --> Risk
|
||||||
|
|
||||||
|
Mgmt --> Balance
|
||||||
|
Mgmt --> Risk
|
||||||
|
|
||||||
|
Analytics --> Mgmt
|
||||||
|
Analytics --> Data
|
||||||
|
|
||||||
|
Monitor --> Mgmt
|
||||||
|
Monitor --> Balance
|
||||||
|
Monitor --> Scheduler
|
||||||
|
|
||||||
|
Simulation --> Strategy
|
||||||
|
Simulation --> Data
|
||||||
|
Simulation --> Risk
|
||||||
|
|
||||||
|
Audit -.-> Mgmt
|
||||||
|
Audit -.-> Strategy
|
||||||
|
Audit -.-> Scheduler
|
||||||
|
Audit -.-> Balance
|
||||||
|
|
||||||
|
Balance --> Broker1
|
||||||
|
Balance --> Broker2
|
||||||
|
Balance --> Broker3
|
||||||
|
|
||||||
|
Data --> DataProvider
|
||||||
|
Data --> Broker1
|
||||||
|
|
||||||
|
Mgmt --> DB
|
||||||
|
Strategy --> DB
|
||||||
|
Analytics --> DB
|
||||||
|
Audit --> DB
|
||||||
|
|
||||||
|
Data --> Cache
|
||||||
|
Monitor --> Cache
|
||||||
|
|
||||||
|
Analytics --> Storage
|
||||||
|
Audit --> Storage
|
||||||
|
|
||||||
|
Scheduler --> MQ
|
||||||
|
Monitor --> MQ
|
||||||
|
|
||||||
|
style Balance fill:#e1f5ff
|
||||||
|
style Mgmt fill:#e1f5ff
|
||||||
|
style Strategy fill:#e1f5ff
|
||||||
|
style Scheduler fill:#e1f5ff
|
||||||
|
style Risk fill:#e1f5ff
|
||||||
|
style Data fill:#e1f5ff
|
||||||
|
|
||||||
|
style Analytics fill:#fff4e1
|
||||||
|
style Monitor fill:#fff4e1
|
||||||
|
|
||||||
|
style Audit fill:#f0e1ff
|
||||||
|
style Simulation fill:#f0e1ff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Phase 1 컴포넌트 관계도
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "Phase 1: MVP"
|
||||||
|
subgraph "Core Trading"
|
||||||
|
Mgmt[mgmt<br/>컨테이너 관리]
|
||||||
|
Strategy[strategy<br/>전략 엔진]
|
||||||
|
Scheduler[scheduler<br/>스케줄러]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Safety & Control"
|
||||||
|
Risk[risk<br/>리스크 관리]
|
||||||
|
Data[data<br/>데이터 수집]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Broker Integration"
|
||||||
|
Balance[balance<br/>계좌 연동]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Scheduler -->|1. 트리거| Strategy
|
||||||
|
Strategy -->|2. 신호 생성| Risk
|
||||||
|
Risk -->|3. 검증 통과| Scheduler
|
||||||
|
Scheduler -->|4. 주문 생성| Balance
|
||||||
|
Balance -->|5. 체결 결과| Mgmt
|
||||||
|
|
||||||
|
Strategy -->|시세 조회| Data
|
||||||
|
Risk -->|리스크 데이터| Data
|
||||||
|
Mgmt -->|자산 할당| Balance
|
||||||
|
|
||||||
|
style Mgmt fill:#4CAF50,color:#fff
|
||||||
|
style Strategy fill:#2196F3,color:#fff
|
||||||
|
style Scheduler fill:#FF9800,color:#fff
|
||||||
|
style Risk fill:#F44336,color:#fff
|
||||||
|
style Data fill:#9C27B0,color:#fff
|
||||||
|
style Balance fill:#00BCD4,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 전체 Phase별 구성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "Phase 3: Enterprise Grade"
|
||||||
|
P3_1[audit<br/>감사 추적]
|
||||||
|
P3_2[simulation<br/>Paper Trading]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 2: Production Ready"
|
||||||
|
P2_1[analytics<br/>성과 분석]
|
||||||
|
P2_2[monitor<br/>모니터링]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 1: MVP"
|
||||||
|
P1_1[balance<br/>계좌 관리]
|
||||||
|
P1_2[mgmt<br/>컨테이너]
|
||||||
|
P1_3[strategy<br/>전략]
|
||||||
|
P1_4[scheduler<br/>스케줄러]
|
||||||
|
P1_5[risk<br/>리스크]
|
||||||
|
P1_6[data<br/>데이터]
|
||||||
|
end
|
||||||
|
|
||||||
|
P1_1 --> P2_1
|
||||||
|
P1_2 --> P2_1
|
||||||
|
P1_3 --> P2_1
|
||||||
|
P1_6 --> P2_1
|
||||||
|
|
||||||
|
P1_1 --> P2_2
|
||||||
|
P1_2 --> P2_2
|
||||||
|
P1_4 --> P2_2
|
||||||
|
|
||||||
|
P2_1 --> P3_1
|
||||||
|
P1_4 --> P3_1
|
||||||
|
P1_1 --> P3_1
|
||||||
|
|
||||||
|
P1_3 --> P3_2
|
||||||
|
P1_6 --> P3_2
|
||||||
|
P1_5 --> P3_2
|
||||||
|
|
||||||
|
style P1_1 fill:#e3f2fd
|
||||||
|
style P1_2 fill:#e3f2fd
|
||||||
|
style P1_3 fill:#e3f2fd
|
||||||
|
style P1_4 fill:#e3f2fd
|
||||||
|
style P1_5 fill:#e3f2fd
|
||||||
|
style P1_6 fill:#e3f2fd
|
||||||
|
|
||||||
|
style P2_1 fill:#fff9c4
|
||||||
|
style P2_2 fill:#fff9c4
|
||||||
|
|
||||||
|
style P3_1 fill:#f3e5f5
|
||||||
|
style P3_2 fill:#f3e5f5
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 전략 실행 워크플로우 (Sequence Diagram)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant S as Scheduler
|
||||||
|
participant M as Mgmt
|
||||||
|
participant ST as Strategy
|
||||||
|
participant D as Data
|
||||||
|
participant R as Risk
|
||||||
|
participant B as Balance
|
||||||
|
participant A as Analytics
|
||||||
|
participant MO as Monitor
|
||||||
|
|
||||||
|
Note over S: 스케줄 트리거 발생
|
||||||
|
|
||||||
|
S->>M: 1. 컨테이너 정보 조회
|
||||||
|
M-->>S: 컨테이너 설정 & 현재 포지션
|
||||||
|
|
||||||
|
S->>ST: 2. 전략 실행 요청
|
||||||
|
ST->>D: 2.1 시장 데이터 조회
|
||||||
|
D-->>ST: 최신 시세 데이터
|
||||||
|
ST->>ST: 2.2 신호 생성
|
||||||
|
ST-->>S: 매매 신호 반환
|
||||||
|
|
||||||
|
S->>R: 3. 리스크 체크
|
||||||
|
R->>R: 3.1 포지션 사이즈 검증
|
||||||
|
R->>R: 3.2 VaR 계산
|
||||||
|
R->>R: 3.3 한도 확인
|
||||||
|
|
||||||
|
alt 리스크 체크 실패
|
||||||
|
R-->>S: 검증 실패
|
||||||
|
S->>MO: 알림 발송
|
||||||
|
MO-->>S: 알림 완료
|
||||||
|
Note over S: 실행 중단
|
||||||
|
else 리스크 체크 통과
|
||||||
|
R-->>S: 검증 통과
|
||||||
|
|
||||||
|
alt 승인 필요 모드
|
||||||
|
S->>S: 승인 요청 생성
|
||||||
|
S->>MO: 사용자에게 알림
|
||||||
|
Note over S: 사용자 승인 대기
|
||||||
|
S->>S: 승인 완료
|
||||||
|
end
|
||||||
|
|
||||||
|
S->>B: 4. 주문 제출
|
||||||
|
B->>B: 4.1 증권사 API 호출
|
||||||
|
B-->>S: 주문 접수 완료
|
||||||
|
|
||||||
|
Note over B: 체결 대기...
|
||||||
|
|
||||||
|
B->>B: 4.2 체결 확인
|
||||||
|
B->>M: 5. 포지션 업데이트
|
||||||
|
M->>M: 5.1 컨테이너 밸런스 갱신
|
||||||
|
|
||||||
|
M->>A: 6. 성과 계산 트리거
|
||||||
|
A->>A: 6.1 수익률 계산
|
||||||
|
A->>A: 6.2 리스크 지표 갱신
|
||||||
|
|
||||||
|
A->>MO: 7. 메트릭 업데이트
|
||||||
|
MO->>MO: 7.1 대시보드 갱신
|
||||||
|
MO->>MO: 7.2 이상 탐지
|
||||||
|
|
||||||
|
alt 이상 탐지 시
|
||||||
|
MO->>MO: 알림 발송
|
||||||
|
end
|
||||||
|
|
||||||
|
S->>S: 8. 실행 완료 기록
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 리스크 관리 플로우
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Start([주문 요청]) --> GetPosition[현재 포지션 조회]
|
||||||
|
GetPosition --> CalcNewPosition[신규 포지션 계산]
|
||||||
|
|
||||||
|
CalcNewPosition --> CheckBalance{잔고 충분?}
|
||||||
|
CheckBalance -->|No| Reject1[주문 거부:<br/>잔고 부족]
|
||||||
|
CheckBalance -->|Yes| CheckSize
|
||||||
|
|
||||||
|
CheckSize{포지션 사이즈<br/>한도 내?}
|
||||||
|
CheckSize -->|No| Reject2[주문 거부:<br/>사이즈 초과]
|
||||||
|
CheckSize -->|Yes| CheckConcentration
|
||||||
|
|
||||||
|
CheckConcentration{집중도<br/>한도 내?}
|
||||||
|
CheckConcentration -->|No| Reject3[주문 거부:<br/>집중도 초과]
|
||||||
|
CheckConcentration -->|Yes| CalcVaR
|
||||||
|
|
||||||
|
CalcVaR[VaR 계산]
|
||||||
|
CalcVaR --> CheckVaR{VaR<br/>한도 내?}
|
||||||
|
CheckVaR -->|No| Warning1[경고 발생<br/>계속 진행]
|
||||||
|
CheckVaR -->|Yes| CheckDrawdown
|
||||||
|
|
||||||
|
Warning1 --> CheckDrawdown
|
||||||
|
|
||||||
|
CheckDrawdown{최대 낙폭<br/>한도 내?}
|
||||||
|
CheckDrawdown -->|No| Reject4[주문 거부:<br/>MDD 초과]
|
||||||
|
CheckDrawdown -->|Yes| CheckLeverage
|
||||||
|
|
||||||
|
CheckLeverage{레버리지<br/>한도 내?}
|
||||||
|
CheckLeverage -->|No| Reject5[주문 거부:<br/>레버리지 초과]
|
||||||
|
CheckLeverage -->|Yes| Approve
|
||||||
|
|
||||||
|
Approve([검증 통과:<br/>주문 실행])
|
||||||
|
|
||||||
|
Reject1 --> Log[리스크 로그 기록]
|
||||||
|
Reject2 --> Log
|
||||||
|
Reject3 --> Log
|
||||||
|
Reject4 --> Log
|
||||||
|
Reject5 --> Log
|
||||||
|
|
||||||
|
Approve --> ExecuteOrder[주문 제출]
|
||||||
|
ExecuteOrder --> Monitor[실시간 모니터링]
|
||||||
|
|
||||||
|
Monitor --> CheckStop{손절/익절<br/>조건 충족?}
|
||||||
|
CheckStop -->|Yes| AutoClose[자동 청산]
|
||||||
|
CheckStop -->|No| Monitor
|
||||||
|
|
||||||
|
style Start fill:#4CAF50,color:#fff
|
||||||
|
style Approve fill:#4CAF50,color:#fff
|
||||||
|
style Reject1 fill:#F44336,color:#fff
|
||||||
|
style Reject2 fill:#F44336,color:#fff
|
||||||
|
style Reject3 fill:#F44336,color:#fff
|
||||||
|
style Reject4 fill:#F44336,color:#fff
|
||||||
|
style Reject5 fill:#F44336,color:#fff
|
||||||
|
style Warning1 fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 데이터 흐름도
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "External Sources"
|
||||||
|
Broker[증권사 API]
|
||||||
|
YahooAPI[Yahoo Finance]
|
||||||
|
AlphaAPI[Alpha Vantage]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Data Collection"
|
||||||
|
Collector[Data Collector]
|
||||||
|
RealTime[Real-time Stream]
|
||||||
|
Historical[Historical Fetch]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Data Processing"
|
||||||
|
Validator[Data Validator]
|
||||||
|
Adjuster[Corporate Action Adjuster]
|
||||||
|
QualityCheck[Quality Check]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Storage"
|
||||||
|
Cache[(Redis Cache<br/>실시간 시세)]
|
||||||
|
TimeSeries[(Time Series DB<br/>과거 데이터)]
|
||||||
|
Metadata[(Metadata DB<br/>종목 정보)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Consumers"
|
||||||
|
Strategy[Strategy Engine]
|
||||||
|
Backtest[Backtest Engine]
|
||||||
|
Analytics[Analytics]
|
||||||
|
Monitor[Monitor]
|
||||||
|
end
|
||||||
|
|
||||||
|
Broker --> RealTime
|
||||||
|
YahooAPI --> Historical
|
||||||
|
AlphaAPI --> Historical
|
||||||
|
|
||||||
|
RealTime --> Collector
|
||||||
|
Historical --> Collector
|
||||||
|
|
||||||
|
Collector --> Validator
|
||||||
|
Validator --> QualityCheck
|
||||||
|
QualityCheck -->|Pass| Adjuster
|
||||||
|
QualityCheck -->|Fail| Alert[Quality Alert]
|
||||||
|
|
||||||
|
Adjuster --> Cache
|
||||||
|
Adjuster --> TimeSeries
|
||||||
|
Adjuster --> Metadata
|
||||||
|
|
||||||
|
Cache --> Strategy
|
||||||
|
Cache --> Monitor
|
||||||
|
|
||||||
|
TimeSeries --> Backtest
|
||||||
|
TimeSeries --> Analytics
|
||||||
|
|
||||||
|
Metadata --> Strategy
|
||||||
|
|
||||||
|
style Cache fill:#FF6B6B,color:#fff
|
||||||
|
style TimeSeries fill:#4ECDC4,color:#fff
|
||||||
|
style Metadata fill:#45B7D1,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 컨테이너 생명주기
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Created: createContainer()
|
||||||
|
|
||||||
|
Created --> Active: activate()
|
||||||
|
Created --> [*]: delete()
|
||||||
|
|
||||||
|
Active --> Running: scheduler trigger
|
||||||
|
Active --> Paused: pause()
|
||||||
|
Active --> [*]: delete()
|
||||||
|
|
||||||
|
Running --> Active: execution complete
|
||||||
|
Running --> Error: execution failed
|
||||||
|
Running --> Paused: emergency stop
|
||||||
|
|
||||||
|
Paused --> Active: resume()
|
||||||
|
Paused --> [*]: delete()
|
||||||
|
|
||||||
|
Error --> Active: resolve & restart
|
||||||
|
Error --> Paused: manual intervention
|
||||||
|
Error --> [*]: delete()
|
||||||
|
|
||||||
|
state Running {
|
||||||
|
[*] --> GenerateSignals
|
||||||
|
GenerateSignals --> RiskCheck
|
||||||
|
RiskCheck --> PlaceOrders: pass
|
||||||
|
RiskCheck --> [*]: fail
|
||||||
|
PlaceOrders --> AwaitFill
|
||||||
|
AwaitFill --> UpdatePosition
|
||||||
|
UpdatePosition --> [*]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 승인 워크플로우
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Trigger[스케줄 트리거] --> GenerateSignals[신호 생성]
|
||||||
|
GenerateSignals --> RiskCheck[리스크 체크]
|
||||||
|
|
||||||
|
RiskCheck --> CheckMode{실행 모드}
|
||||||
|
|
||||||
|
CheckMode -->|AUTO| AutoExecute[자동 실행]
|
||||||
|
CheckMode -->|APPROVAL| CreateRequest
|
||||||
|
|
||||||
|
CreateRequest[승인 요청 생성]
|
||||||
|
CreateRequest --> SendNotification[알림 발송]
|
||||||
|
SendNotification --> WaitApproval[승인 대기]
|
||||||
|
|
||||||
|
WaitApproval --> CheckTimeout{타임아웃?}
|
||||||
|
CheckTimeout -->|Yes| Expired[요청 만료]
|
||||||
|
CheckTimeout -->|No| WaitApproval
|
||||||
|
|
||||||
|
WaitApproval --> UserDecision{사용자 결정}
|
||||||
|
|
||||||
|
UserDecision -->|승인| Execute[주문 실행]
|
||||||
|
UserDecision -->|거부| Rejected[실행 거부]
|
||||||
|
|
||||||
|
AutoExecute --> Execute
|
||||||
|
|
||||||
|
Execute --> PlaceOrders[주문 제출]
|
||||||
|
PlaceOrders --> Success{성공?}
|
||||||
|
|
||||||
|
Success -->|Yes| NotifySuccess[성공 알림]
|
||||||
|
Success -->|No| NotifyFail[실패 알림]
|
||||||
|
|
||||||
|
Rejected --> LogRejection[거부 로그]
|
||||||
|
Expired --> LogExpired[만료 로그]
|
||||||
|
|
||||||
|
NotifySuccess --> End([완료])
|
||||||
|
NotifyFail --> End
|
||||||
|
LogRejection --> End
|
||||||
|
LogExpired --> End
|
||||||
|
|
||||||
|
style Execute fill:#4CAF50,color:#fff
|
||||||
|
style Rejected fill:#F44336,color:#fff
|
||||||
|
style Expired fill:#FF9800,color:#fff
|
||||||
|
style AutoExecute fill:#2196F3,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 모니터링 & 알림 시스템
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "Data Sources"
|
||||||
|
Positions[포지션 데이터]
|
||||||
|
Orders[주문 데이터]
|
||||||
|
PnL[손익 데이터]
|
||||||
|
System[시스템 메트릭]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Monitoring Engine"
|
||||||
|
Collector[Metrics Collector]
|
||||||
|
Anomaly[Anomaly Detector]
|
||||||
|
Health[Health Checker]
|
||||||
|
Rules[Alert Rules Engine]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Alert Processing"
|
||||||
|
Evaluator[Alert Evaluator]
|
||||||
|
Throttle[Throttle Manager]
|
||||||
|
Router[Channel Router]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Notification Channels"
|
||||||
|
Email[Email]
|
||||||
|
SMS[SMS]
|
||||||
|
Push[Push Notification]
|
||||||
|
Slack[Slack]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Storage & Dashboard"
|
||||||
|
Metrics[(Metrics DB)]
|
||||||
|
Dashboard[Real-time Dashboard]
|
||||||
|
History[Alert History]
|
||||||
|
end
|
||||||
|
|
||||||
|
Positions --> Collector
|
||||||
|
Orders --> Collector
|
||||||
|
PnL --> Collector
|
||||||
|
System --> Collector
|
||||||
|
|
||||||
|
Collector --> Anomaly
|
||||||
|
Collector --> Health
|
||||||
|
Collector --> Rules
|
||||||
|
Collector --> Metrics
|
||||||
|
|
||||||
|
Anomaly --> Evaluator
|
||||||
|
Health --> Evaluator
|
||||||
|
Rules --> Evaluator
|
||||||
|
|
||||||
|
Evaluator --> Throttle
|
||||||
|
Throttle --> Router
|
||||||
|
|
||||||
|
Router --> Email
|
||||||
|
Router --> SMS
|
||||||
|
Router --> Push
|
||||||
|
Router --> Slack
|
||||||
|
|
||||||
|
Evaluator --> History
|
||||||
|
Metrics --> Dashboard
|
||||||
|
|
||||||
|
style Anomaly fill:#F44336,color:#fff
|
||||||
|
style Health fill:#4CAF50,color:#fff
|
||||||
|
style Rules fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Simulation 환경 구조
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "Real Environment"
|
||||||
|
RealAccount[실제 계좌]
|
||||||
|
RealBroker[증권사 API]
|
||||||
|
RealData[실시간 시세]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Simulation Environment"
|
||||||
|
PaperAccount[가상 계좌]
|
||||||
|
|
||||||
|
subgraph "Simulation Engine"
|
||||||
|
OrderSim[주문 시뮬레이터]
|
||||||
|
FillSim[체결 시뮬레이터]
|
||||||
|
Slippage[슬리피지 모델]
|
||||||
|
Commission[수수료 계산]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Test Scenarios"
|
||||||
|
Historical[과거 데이터 리플레이]
|
||||||
|
MonteCarlo[몬테카를로 시뮬레이션]
|
||||||
|
Stress[스트레스 테스트]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Shared Components"
|
||||||
|
Strategy[전략 엔진]
|
||||||
|
Risk[리스크 관리]
|
||||||
|
Analytics[성과 분석]
|
||||||
|
end
|
||||||
|
|
||||||
|
RealData --> Historical
|
||||||
|
RealData --> OrderSim
|
||||||
|
|
||||||
|
Strategy --> OrderSim
|
||||||
|
Strategy --> RealBroker
|
||||||
|
|
||||||
|
OrderSim --> FillSim
|
||||||
|
FillSim --> Slippage
|
||||||
|
Slippage --> Commission
|
||||||
|
Commission --> PaperAccount
|
||||||
|
|
||||||
|
Historical --> MonteCarlo
|
||||||
|
Historical --> Stress
|
||||||
|
|
||||||
|
PaperAccount --> Analytics
|
||||||
|
RealAccount --> Analytics
|
||||||
|
|
||||||
|
Risk --> OrderSim
|
||||||
|
Risk --> RealBroker
|
||||||
|
|
||||||
|
Analytics --> Validation{검증 통과?}
|
||||||
|
Validation -->|Yes| Promote[실계좌 전환]
|
||||||
|
Validation -->|No| Refine[전략 개선]
|
||||||
|
|
||||||
|
Promote --> RealAccount
|
||||||
|
Refine --> Strategy
|
||||||
|
|
||||||
|
style PaperAccount fill:#FFF9C4
|
||||||
|
style RealAccount fill:#C8E6C9
|
||||||
|
style Validation fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
279
docs/01-overview.md
Normal file
279
docs/01-overview.md
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
# QuantBench 시스템 개요
|
||||||
|
|
||||||
|
## 1. 프로젝트 소개
|
||||||
|
|
||||||
|
**QuantBench**는 개인 투자자를 위한 퀀트 트레이딩 플랫폼으로, 다중 계좌 관리, 전략 기반 자동매매, 리스크 관리, 성과 분석을 통합 제공합니다.
|
||||||
|
|
||||||
|
### 핵심 가치 제안
|
||||||
|
|
||||||
|
- **다중 계좌 통합 관리**: 한국투자증권, 삼성증권, 키움증권 등 여러 증권사 계좌를 하나의 플랫폼에서 관리
|
||||||
|
- **컨테이너 기반 자산 격리**: 하나의 계좌에서 여러 전략을 안전하게 병렬 운영
|
||||||
|
- **전략 자동화**: 백테스트부터 실전 운영까지 일관된 전략 실행 환경
|
||||||
|
- **리스크 우선 설계**: 사전 주문 검증 및 실시간 리스크 모니터링
|
||||||
|
- **투명한 성과 분석**: 실시간 성과 추적 및 귀속 분석
|
||||||
|
|
||||||
|
## 2. 주요 기능
|
||||||
|
|
||||||
|
### 2.1 계좌 및 자산 관리
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[투자자] --> B[QuantBench]
|
||||||
|
B --> C[한국투자증권]
|
||||||
|
B --> D[삼성증권]
|
||||||
|
B --> E[키움증권]
|
||||||
|
|
||||||
|
B --> F[컨테이너 1<br/>성장주 전략]
|
||||||
|
B --> G[컨테이너 2<br/>배당주 전략]
|
||||||
|
B --> H[컨테이너 3<br/>ETF 전략]
|
||||||
|
|
||||||
|
style F fill:#e3f2fd
|
||||||
|
style G fill:#e3f2fd
|
||||||
|
style H fill:#e3f2fd
|
||||||
|
```
|
||||||
|
|
||||||
|
- 여러 증권사 계좌 통합 관리
|
||||||
|
- 계좌 내 가상 컨테이너 생성으로 전략별 자산 격리
|
||||||
|
- 실시간 잔고 조회 및 포지션 추적
|
||||||
|
- 컨테이너 간 자산 이동 및 재배분
|
||||||
|
|
||||||
|
### 2.2 전략 실행
|
||||||
|
|
||||||
|
- **전략 등록 및 버전 관리**: 전략 코드 및 파라미터의 버전별 관리
|
||||||
|
- **백테스트**: 과거 데이터 기반 전략 검증 및 성과 분석
|
||||||
|
- **자동 실행**: 스케줄 기반 자동 매매 신호 생성 및 주문 실행
|
||||||
|
- **승인 워크플로우**: 자동 실행 또는 사용자 승인 후 실행 선택
|
||||||
|
|
||||||
|
### 2.3 리스크 관리
|
||||||
|
|
||||||
|
- **사전 주문 검증**: 모든 주문의 리스크 사전 체크
|
||||||
|
- **포지션 한도 관리**: 단일 종목, 섹터, 총 익스포저 제한
|
||||||
|
- **손절/익절 자동화**: 조건 기반 자동 청산
|
||||||
|
- **VaR 계산**: 포트폴리오 리스크 정량화
|
||||||
|
- **스트레스 테스트**: 극단 시나리오 대비
|
||||||
|
|
||||||
|
### 2.4 성과 분석 및 모니터링
|
||||||
|
|
||||||
|
- **실시간 성과 추적**: 수익률, 리스크 지표 실시간 업데이트
|
||||||
|
- **귀속 분석**: 수익 원천 분해 (자산 배분, 종목 선택, 타이밍)
|
||||||
|
- **벤치마크 비교**: 시장 지수 대비 성과 분석
|
||||||
|
- **이상 탐지**: 비정상 거래 및 리스크 이벤트 자동 감지
|
||||||
|
- **다채널 알림**: 이메일, SMS, 푸시, Slack 알림
|
||||||
|
|
||||||
|
## 3. 핵심 개념
|
||||||
|
|
||||||
|
### 3.1 컨테이너 (Container)
|
||||||
|
|
||||||
|
컨테이너는 **하나의 실제 계좌 내에서 가상으로 분리된 자산 공간**입니다.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "실제 계좌 (1억원)"
|
||||||
|
subgraph "컨테이너 A (3천만원)"
|
||||||
|
A1[현금: 500만원]
|
||||||
|
A2[삼성전자: 2500만원]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "컨테이너 B (5천만원)"
|
||||||
|
B1[현금: 1000만원]
|
||||||
|
B2[KODEX 200: 4000만원]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "컨테이너 C (2천만원)"
|
||||||
|
C1[현금: 2000만원]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
style A1 fill:#fff9c4
|
||||||
|
style A2 fill:#c8e6c9
|
||||||
|
style B1 fill:#fff9c4
|
||||||
|
style B2 fill:#c8e6c9
|
||||||
|
style C1 fill:#fff9c4
|
||||||
|
```
|
||||||
|
|
||||||
|
**특징**:
|
||||||
|
- 각 컨테이너는 독립적인 가상 잔고를 유지
|
||||||
|
- 하나의 컨테이너에 하나의 전략 할당
|
||||||
|
- 컨테이너별 독립적인 리스크 한도 설정
|
||||||
|
- 실제 계좌 잔고 = 모든 컨테이너 잔고의 합
|
||||||
|
|
||||||
|
**장점**:
|
||||||
|
- 전략 간 간섭 없이 병렬 운영
|
||||||
|
- 전략별 성과를 명확히 추적
|
||||||
|
- 리스크를 전략 단위로 통제
|
||||||
|
|
||||||
|
### 3.2 전략 (Strategy)
|
||||||
|
|
||||||
|
전략은 **매매 신호를 생성하는 알고리즘**입니다.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[시장 데이터] --> B[전략 엔진]
|
||||||
|
B --> C[매매 신호]
|
||||||
|
C --> D{리스크 체크}
|
||||||
|
D -->|통과| E[주문 실행]
|
||||||
|
D -->|실패| F[실행 중단]
|
||||||
|
|
||||||
|
style B fill:#2196f3,color:#fff
|
||||||
|
style D fill:#f44336,color:#fff
|
||||||
|
style E fill:#4caf50,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
**구성 요소**:
|
||||||
|
- **전략 코드**: 신호 생성 로직 구현
|
||||||
|
- **파라미터**: 전략 동작을 조정하는 변수들
|
||||||
|
- **버전**: 전략 수정 이력 관리
|
||||||
|
- **백테스트 결과**: 과거 성과 검증 데이터
|
||||||
|
|
||||||
|
**내장 전략 예시**:
|
||||||
|
- Bold Asset Allocation: 주식/채권 고정 비중 전략
|
||||||
|
- Momentum: 모멘텀 기반 종목 선택
|
||||||
|
- Value: 가치 지표 기반 매매
|
||||||
|
|
||||||
|
### 3.3 워크플로우 (Workflow)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant 스케줄러
|
||||||
|
participant 전략
|
||||||
|
participant 리스크
|
||||||
|
participant 증권사
|
||||||
|
participant 사용자
|
||||||
|
|
||||||
|
스케줄러->>전략: 신호 생성 요청
|
||||||
|
전략-->>스케줄러: 매매 신호
|
||||||
|
스케줄러->>리스크: 리스크 검증
|
||||||
|
|
||||||
|
alt 리스크 통과
|
||||||
|
리스크-->>스케줄러: 승인
|
||||||
|
|
||||||
|
alt 자동 실행 모드
|
||||||
|
스케줄러->>증권사: 주문 제출
|
||||||
|
else 승인 필요 모드
|
||||||
|
스케줄러->>사용자: 승인 요청
|
||||||
|
사용자-->>스케줄러: 승인
|
||||||
|
스케줄러->>증권사: 주문 제출
|
||||||
|
end
|
||||||
|
|
||||||
|
증권사-->>스케줄러: 체결 완료
|
||||||
|
else 리스크 실패
|
||||||
|
리스크-->>스케줄러: 거부
|
||||||
|
스케줄러->>사용자: 실패 알림
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 개발 단계
|
||||||
|
|
||||||
|
### Phase 1: MVP (3-4개월)
|
||||||
|
|
||||||
|
**목표**: 안전하게 전략을 실행하고 리스크를 통제할 수 있는 기본 시스템 구축
|
||||||
|
|
||||||
|
**핵심 컴포넌트**:
|
||||||
|
- `balance`: 증권사 API 연동 및 계좌 관리
|
||||||
|
- `mgmt`: 컨테이너 생명주기 관리
|
||||||
|
- `strategy`: 전략 실행 및 백테스트
|
||||||
|
- `scheduler`: 자동 실행 스케줄링
|
||||||
|
- `risk`: 사전 주문 검증
|
||||||
|
- `data`: 시장 데이터 수집 및 관리
|
||||||
|
|
||||||
|
**핵심 기능**:
|
||||||
|
- 1개 증권사 연동 (한국투자증권 우선)
|
||||||
|
- 기본 전략 실행 (Bold Asset Allocation)
|
||||||
|
- 주문 전 리스크 체크
|
||||||
|
- 수동 승인 워크플로우
|
||||||
|
|
||||||
|
### Phase 2: Production Ready (2-3개월)
|
||||||
|
|
||||||
|
**목표**: 실전 운영을 위한 모니터링, 분석, 알림 체계 구축
|
||||||
|
|
||||||
|
**추가 컴포넌트**:
|
||||||
|
- `analytics`: 성과 분석 및 리포팅
|
||||||
|
- `monitor`: 시스템 모니터링 및 알림
|
||||||
|
|
||||||
|
**핵심 기능**:
|
||||||
|
- 실시간 성과 대시보드
|
||||||
|
- 자동 리포트 생성 (일/주/월)
|
||||||
|
- 이상 거래 탐지
|
||||||
|
- 다채널 알림 시스템
|
||||||
|
|
||||||
|
### Phase 3: Enterprise Grade (2-3개월)
|
||||||
|
|
||||||
|
**목표**: 규제 대응, 감사 추적, 고급 시뮬레이션
|
||||||
|
|
||||||
|
**추가 컴포넌트**:
|
||||||
|
- `audit`: 불변 감사 로그
|
||||||
|
- `simulation`: Paper Trading 및 시뮬레이션
|
||||||
|
|
||||||
|
**핵심 기능**:
|
||||||
|
- 모든 거래의 감사 추적
|
||||||
|
- Paper Trading 환경
|
||||||
|
- 파라미터 최적화
|
||||||
|
- 스트레스 테스트
|
||||||
|
|
||||||
|
## 5. 기술 스택
|
||||||
|
|
||||||
|
### 백엔드
|
||||||
|
- **언어**: TypeScript/Node.js 또는 Python
|
||||||
|
- **데이터베이스**: PostgreSQL (관계형), TimescaleDB (시계열)
|
||||||
|
- **캐시**: Redis
|
||||||
|
- **메시지 큐**: Kafka 또는 RabbitMQ
|
||||||
|
- **스토리지**: AWS S3 또는 MinIO
|
||||||
|
|
||||||
|
### 프론트엔드
|
||||||
|
- **프레임워크**: React 또는 Next.js
|
||||||
|
- **차트**: TradingView, Chart.js
|
||||||
|
- **상태 관리**: Redux 또는 Zustand
|
||||||
|
|
||||||
|
### 인프라
|
||||||
|
- **컨테이너**: Docker
|
||||||
|
- **오케스트레이션**: Kubernetes (선택)
|
||||||
|
- **모니터링**: Prometheus + Grafana
|
||||||
|
- **로깅**: ELK Stack (Elasticsearch, Logstash, Kibana)
|
||||||
|
|
||||||
|
## 6. 비기능 요구사항
|
||||||
|
|
||||||
|
### 6.1 성능
|
||||||
|
- 주문 처리 지연시간: < 1초
|
||||||
|
- 백테스트 속도: 1년 데이터 < 10초
|
||||||
|
- 실시간 데이터 업데이트: < 5초
|
||||||
|
|
||||||
|
### 6.2 안정성
|
||||||
|
- 시스템 가용성: 99.9% (장중 시간 기준)
|
||||||
|
- 데이터 정합성: 100% (계좌 잔고 일치)
|
||||||
|
- 주문 실패 복구: 자동 재시도 및 알림
|
||||||
|
|
||||||
|
### 6.3 보안
|
||||||
|
- API 키 암호화 저장
|
||||||
|
- 통신 TLS 암호화
|
||||||
|
- 역할 기반 접근 제어 (RBAC)
|
||||||
|
- 감사 로그 불변성 보장
|
||||||
|
|
||||||
|
### 6.4 확장성
|
||||||
|
- 다중 증권사 지원 (플러그인 아키텍처)
|
||||||
|
- 수평 확장 가능한 데이터 처리
|
||||||
|
- 무제한 컨테이너/전략 생성
|
||||||
|
|
||||||
|
## 7. 관련 문서
|
||||||
|
|
||||||
|
- [전체 아키텍처](./02-architecture.md)
|
||||||
|
- [공통 데이터 모델](./03-data-models.md)
|
||||||
|
- [주요 워크플로우](./04-workflows.md)
|
||||||
|
- [구현 로드맵](./05-roadmap.md)
|
||||||
|
|
||||||
|
### 구성요소 상세 문서
|
||||||
|
|
||||||
|
**Phase 1**:
|
||||||
|
- [balance - 계좌 관리](../components/phase1/balance.md)
|
||||||
|
- [mgmt - 컨테이너 관리](../components/phase1/mgmt.md)
|
||||||
|
- [strategy - 전략 관리](../components/phase1/strategy.md)
|
||||||
|
- [scheduler - 실행 스케줄러](../components/phase1/scheduler.md)
|
||||||
|
- [risk - 리스크 관리](../components/phase1/risk.md)
|
||||||
|
- [data - 데이터 관리](../components/phase1/data.md)
|
||||||
|
|
||||||
|
**Phase 2**:
|
||||||
|
- [analytics - 성과 분석](../components/phase2/analytics.md)
|
||||||
|
- [monitor - 모니터링](../components/phase2/monitor.md)
|
||||||
|
|
||||||
|
**Phase 3**:
|
||||||
|
- [audit - 감사 로깅](../components/phase3/audit.md)
|
||||||
|
- [simulation - 시뮬레이션](../components/phase3/simulation.md)
|
||||||
592
docs/02-architecture.md
Normal file
592
docs/02-architecture.md
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
# QuantBench 시스템 아키텍처
|
||||||
|
|
||||||
|
## 1. 전체 시스템 구조
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "사용자 레이어"
|
||||||
|
UI[사용자 인터페이스<br/>Web/Mobile/Desktop]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "API 레이어"
|
||||||
|
Gateway[API Gateway<br/>인증 & Rate Limiting]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 1: 핵심 컴포넌트"
|
||||||
|
Balance[balance<br/>계좌 관리]
|
||||||
|
Mgmt[mgmt<br/>컨테이너 관리]
|
||||||
|
Strategy[strategy<br/>전략 관리]
|
||||||
|
Scheduler[scheduler<br/>실행 스케줄러]
|
||||||
|
Risk[risk<br/>리스크 관리]
|
||||||
|
Data[data<br/>데이터 관리]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 2: 프로덕션"
|
||||||
|
Analytics[analytics<br/>성과 분석]
|
||||||
|
Monitor[monitor<br/>모니터링 & 알림]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 3: 엔터프라이즈"
|
||||||
|
Audit[audit<br/>감사 로깅]
|
||||||
|
Simulation[simulation<br/>시뮬레이션]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "인프라"
|
||||||
|
MQ[Message Queue<br/>Kafka/RabbitMQ]
|
||||||
|
DB[(Database<br/>PostgreSQL)]
|
||||||
|
Cache[(Cache<br/>Redis)]
|
||||||
|
Storage[(Object Storage<br/>S3)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "외부 시스템"
|
||||||
|
Broker1[한국투자증권 API]
|
||||||
|
Broker2[삼성증권 API]
|
||||||
|
Broker3[키움증권 API]
|
||||||
|
DataProvider[데이터 제공자<br/>Yahoo/Alpha Vantage]
|
||||||
|
end
|
||||||
|
|
||||||
|
UI --> Gateway
|
||||||
|
Gateway --> Mgmt
|
||||||
|
Gateway --> Strategy
|
||||||
|
Gateway --> Scheduler
|
||||||
|
Gateway --> Analytics
|
||||||
|
Gateway --> Monitor
|
||||||
|
Gateway --> Simulation
|
||||||
|
|
||||||
|
Scheduler --> Strategy
|
||||||
|
Scheduler --> Mgmt
|
||||||
|
Scheduler --> Risk
|
||||||
|
Scheduler --> Balance
|
||||||
|
|
||||||
|
Strategy --> Data
|
||||||
|
Strategy --> Risk
|
||||||
|
|
||||||
|
Mgmt --> Balance
|
||||||
|
Mgmt --> Risk
|
||||||
|
|
||||||
|
Analytics --> Mgmt
|
||||||
|
Analytics --> Data
|
||||||
|
|
||||||
|
Monitor --> Mgmt
|
||||||
|
Monitor --> Balance
|
||||||
|
Monitor --> Scheduler
|
||||||
|
|
||||||
|
Simulation --> Strategy
|
||||||
|
Simulation --> Data
|
||||||
|
Simulation --> Risk
|
||||||
|
|
||||||
|
Audit -.-> Mgmt
|
||||||
|
Audit -.-> Strategy
|
||||||
|
Audit -.-> Scheduler
|
||||||
|
Audit -.-> Balance
|
||||||
|
|
||||||
|
Balance --> Broker1
|
||||||
|
Balance --> Broker2
|
||||||
|
Balance --> Broker3
|
||||||
|
|
||||||
|
Data --> DataProvider
|
||||||
|
Data --> Broker1
|
||||||
|
|
||||||
|
Mgmt --> DB
|
||||||
|
Strategy --> DB
|
||||||
|
Analytics --> DB
|
||||||
|
Audit --> DB
|
||||||
|
|
||||||
|
Data --> Cache
|
||||||
|
Monitor --> Cache
|
||||||
|
|
||||||
|
Analytics --> Storage
|
||||||
|
Audit --> Storage
|
||||||
|
|
||||||
|
Scheduler --> MQ
|
||||||
|
Monitor --> MQ
|
||||||
|
|
||||||
|
style Balance fill:#e1f5ff
|
||||||
|
style Mgmt fill:#e1f5ff
|
||||||
|
style Strategy fill:#e1f5ff
|
||||||
|
style Scheduler fill:#e1f5ff
|
||||||
|
style Risk fill:#e1f5ff
|
||||||
|
style Data fill:#e1f5ff
|
||||||
|
|
||||||
|
style Analytics fill:#fff4e1
|
||||||
|
style Monitor fill:#fff4e1
|
||||||
|
|
||||||
|
style Audit fill:#f0e1ff
|
||||||
|
style Simulation fill:#f0e1ff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 컴포넌트 개요
|
||||||
|
|
||||||
|
### 2.1 Phase 1: 핵심 컴포넌트
|
||||||
|
|
||||||
|
| 컴포넌트 | 책임 | 주요 기능 |
|
||||||
|
|---------|------|----------|
|
||||||
|
| **balance** | 증권사 API 통합 및 계좌 자산 관리 | 계좌 연동, 잔고 조회, 시세 조회, 주문 처리 |
|
||||||
|
| **mgmt** | 가상 자산 컨테이너 생성 및 운영 관리 | 컨테이너 생명주기, 자산 격리, 밸런스 조정 |
|
||||||
|
| **strategy** | 투자 전략 구현, 백테스트, 버전 관리 | 전략 등록, 신호 생성, 백테스트, 파라미터 관리 |
|
||||||
|
| **scheduler** | 전략 실행 자동화 및 리밸런싱 관리 | 스케줄 관리, 실행 트리거, 승인 워크플로우 |
|
||||||
|
| **risk** | 포지션 리스크 통제 및 사전 주문 검증 | 주문 검증, 리스크 모니터링, 손절/익절 |
|
||||||
|
| **data** | 시계열 데이터 수집, 저장, 제공 | 데이터 수집, 품질 관리, 데이터 제공 |
|
||||||
|
|
||||||
|
### 2.2 Phase 2: 프로덕션 컴포넌트
|
||||||
|
|
||||||
|
| 컴포넌트 | 책임 | 주요 기능 |
|
||||||
|
|---------|------|----------|
|
||||||
|
| **analytics** | 실거래 성과 측정 및 리포팅 | 성과 측정, 귀속 분석, 거래 분석, 리포트 생성 |
|
||||||
|
| **monitor** | 시스템 상태 감시 및 이상 탐지 | 헬스 체크, 이상 탐지, 알림 관리, 대시보드 |
|
||||||
|
|
||||||
|
### 2.3 Phase 3: 엔터프라이즈 컴포넌트
|
||||||
|
|
||||||
|
| 컴포넌트 | 책임 | 주요 기능 |
|
||||||
|
|---------|------|----------|
|
||||||
|
| **audit** | 불변 감사 로그 및 규제 리포팅 | 감사 로그, 변경 추적, 규제 리포팅, 무결성 검증 |
|
||||||
|
| **simulation** | 실전 배포 전 안전한 테스트 환경 제공 | Paper Trading, 시뮬레이션, 파라미터 최적화 |
|
||||||
|
|
||||||
|
## 3. 컴포넌트 상호작용
|
||||||
|
|
||||||
|
### 3.1 Phase 1 컴포넌트 관계도
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "Phase 1: MVP"
|
||||||
|
subgraph "핵심 거래"
|
||||||
|
Mgmt[mgmt<br/>컨테이너 관리]
|
||||||
|
Strategy[strategy<br/>전략 엔진]
|
||||||
|
Scheduler[scheduler<br/>스케줄러]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "안전성 & 통제"
|
||||||
|
Risk[risk<br/>리스크 관리]
|
||||||
|
Data[data<br/>데이터 수집]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "증권사 연동"
|
||||||
|
Balance[balance<br/>계좌 연동]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Scheduler -->|1. 트리거| Strategy
|
||||||
|
Strategy -->|2. 신호 생성| Risk
|
||||||
|
Risk -->|3. 검증 통과| Scheduler
|
||||||
|
Scheduler -->|4. 주문 생성| Balance
|
||||||
|
Balance -->|5. 체결 결과| Mgmt
|
||||||
|
|
||||||
|
Strategy -->|시세 조회| Data
|
||||||
|
Risk -->|리스크 데이터| Data
|
||||||
|
Mgmt -->|자산 할당| Balance
|
||||||
|
|
||||||
|
style Mgmt fill:#4CAF50,color:#fff
|
||||||
|
style Strategy fill:#2196F3,color:#fff
|
||||||
|
style Scheduler fill:#FF9800,color:#fff
|
||||||
|
style Risk fill:#F44336,color:#fff
|
||||||
|
style Data fill:#9C27B0,color:#fff
|
||||||
|
style Balance fill:#00BCD4,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Phase별 의존성
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "Phase 3: Enterprise"
|
||||||
|
P3_1[audit<br/>감사]
|
||||||
|
P3_2[simulation<br/>시뮬레이션]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 2: Production"
|
||||||
|
P2_1[analytics<br/>분석]
|
||||||
|
P2_2[monitor<br/>모니터링]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Phase 1: MVP"
|
||||||
|
P1_1[balance<br/>계좌]
|
||||||
|
P1_2[mgmt<br/>컨테이너]
|
||||||
|
P1_3[strategy<br/>전략]
|
||||||
|
P1_4[scheduler<br/>스케줄러]
|
||||||
|
P1_5[risk<br/>리스크]
|
||||||
|
P1_6[data<br/>데이터]
|
||||||
|
end
|
||||||
|
|
||||||
|
P1_1 --> P2_1
|
||||||
|
P1_2 --> P2_1
|
||||||
|
P1_3 --> P2_1
|
||||||
|
P1_6 --> P2_1
|
||||||
|
|
||||||
|
P1_1 --> P2_2
|
||||||
|
P1_2 --> P2_2
|
||||||
|
P1_4 --> P2_2
|
||||||
|
|
||||||
|
P2_1 --> P3_1
|
||||||
|
P1_4 --> P3_1
|
||||||
|
P1_1 --> P3_1
|
||||||
|
|
||||||
|
P1_3 --> P3_2
|
||||||
|
P1_6 --> P3_2
|
||||||
|
P1_5 --> P3_2
|
||||||
|
|
||||||
|
style P1_1 fill:#e3f2fd
|
||||||
|
style P1_2 fill:#e3f2fd
|
||||||
|
style P1_3 fill:#e3f2fd
|
||||||
|
style P1_4 fill:#e3f2fd
|
||||||
|
style P1_5 fill:#e3f2fd
|
||||||
|
style P1_6 fill:#e3f2fd
|
||||||
|
|
||||||
|
style P2_1 fill:#fff9c4
|
||||||
|
style P2_2 fill:#fff9c4
|
||||||
|
|
||||||
|
style P3_1 fill:#f3e5f5
|
||||||
|
style P3_2 fill:#f3e5f5
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 데이터 흐름
|
||||||
|
|
||||||
|
### 4.1 시장 데이터 흐름
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "외부 소스"
|
||||||
|
Broker[증권사 API]
|
||||||
|
Yahoo[Yahoo Finance]
|
||||||
|
Alpha[Alpha Vantage]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "데이터 수집"
|
||||||
|
Collector[Data Collector]
|
||||||
|
RealTime[실시간 스트림]
|
||||||
|
Historical[과거 데이터 수집]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "데이터 처리"
|
||||||
|
Validator[데이터 검증]
|
||||||
|
Adjuster[조정 처리]
|
||||||
|
QualityCheck[품질 체크]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "저장소"
|
||||||
|
Cache[(Redis<br/>실시간)]
|
||||||
|
TimeSeries[(TimescaleDB<br/>과거)]
|
||||||
|
Metadata[(Metadata<br/>종목 정보)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "소비자"
|
||||||
|
Strategy[전략 엔진]
|
||||||
|
Backtest[백테스트]
|
||||||
|
Analytics[분석]
|
||||||
|
Monitor[모니터]
|
||||||
|
end
|
||||||
|
|
||||||
|
Broker --> RealTime
|
||||||
|
Yahoo --> Historical
|
||||||
|
Alpha --> Historical
|
||||||
|
|
||||||
|
RealTime --> Collector
|
||||||
|
Historical --> Collector
|
||||||
|
|
||||||
|
Collector --> Validator
|
||||||
|
Validator --> QualityCheck
|
||||||
|
QualityCheck -->|통과| Adjuster
|
||||||
|
QualityCheck -->|실패| Alert[품질 알림]
|
||||||
|
|
||||||
|
Adjuster --> Cache
|
||||||
|
Adjuster --> TimeSeries
|
||||||
|
Adjuster --> Metadata
|
||||||
|
|
||||||
|
Cache --> Strategy
|
||||||
|
Cache --> Monitor
|
||||||
|
|
||||||
|
TimeSeries --> Backtest
|
||||||
|
TimeSeries --> Analytics
|
||||||
|
|
||||||
|
Metadata --> Strategy
|
||||||
|
|
||||||
|
style Cache fill:#FF6B6B,color:#fff
|
||||||
|
style TimeSeries fill:#4ECDC4,color:#fff
|
||||||
|
style Metadata fill:#45B7D1,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 주문 실행 흐름
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Start([스케줄 트리거]) --> GetContainer[컨테이너 정보 조회]
|
||||||
|
GetContainer --> GenerateSignals[신호 생성]
|
||||||
|
GenerateSignals --> GetMarketData[시장 데이터 조회]
|
||||||
|
GetMarketData --> Calculate[매매 신호 계산]
|
||||||
|
|
||||||
|
Calculate --> RiskCheck[리스크 검증]
|
||||||
|
|
||||||
|
RiskCheck --> CheckResult{검증 결과}
|
||||||
|
CheckResult -->|실패| SendAlert[실패 알림]
|
||||||
|
CheckResult -->|통과| CheckMode{실행 모드}
|
||||||
|
|
||||||
|
CheckMode -->|AUTO| ExecuteOrder
|
||||||
|
CheckMode -->|APPROVAL| RequestApproval[승인 요청]
|
||||||
|
RequestApproval --> WaitApproval[승인 대기]
|
||||||
|
WaitApproval --> ExecuteOrder[주문 실행]
|
||||||
|
|
||||||
|
ExecuteOrder --> SubmitToBroker[증권사에 주문 제출]
|
||||||
|
SubmitToBroker --> WaitFill[체결 대기]
|
||||||
|
WaitFill --> UpdatePosition[포지션 업데이트]
|
||||||
|
UpdatePosition --> Reconcile[밸런스 조정]
|
||||||
|
Reconcile --> CalcPerformance[성과 계산]
|
||||||
|
CalcPerformance --> CheckAnomaly[이상 탐지]
|
||||||
|
CheckAnomaly --> End([완료])
|
||||||
|
|
||||||
|
SendAlert --> End
|
||||||
|
|
||||||
|
style RiskCheck fill:#f44336,color:#fff
|
||||||
|
style ExecuteOrder fill:#4caf50,color:#fff
|
||||||
|
style CheckAnomaly fill:#ff9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 인프라 아키텍처
|
||||||
|
|
||||||
|
### 5.1 배포 구조
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "로드 밸런서"
|
||||||
|
LB[Load Balancer<br/>Nginx/ALB]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "애플리케이션 레이어"
|
||||||
|
API1[API Gateway 1]
|
||||||
|
API2[API Gateway 2]
|
||||||
|
|
||||||
|
Worker1[Worker 1<br/>scheduler/strategy]
|
||||||
|
Worker2[Worker 2<br/>analytics]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "데이터 레이어"
|
||||||
|
PG_Master[(PostgreSQL<br/>Primary)]
|
||||||
|
PG_Replica[(PostgreSQL<br/>Replica)]
|
||||||
|
|
||||||
|
Redis_Master[(Redis<br/>Primary)]
|
||||||
|
Redis_Replica[(Redis<br/>Replica)]
|
||||||
|
|
||||||
|
TS[(TimescaleDB<br/>시계열)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "메시지 큐"
|
||||||
|
Kafka[Kafka Cluster]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "스토리지"
|
||||||
|
S3[(S3<br/>리포트/백업)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "모니터링"
|
||||||
|
Prometheus[Prometheus]
|
||||||
|
Grafana[Grafana]
|
||||||
|
ELK[ELK Stack]
|
||||||
|
end
|
||||||
|
|
||||||
|
LB --> API1
|
||||||
|
LB --> API2
|
||||||
|
|
||||||
|
API1 --> Worker1
|
||||||
|
API2 --> Worker2
|
||||||
|
|
||||||
|
Worker1 --> PG_Master
|
||||||
|
Worker2 --> PG_Replica
|
||||||
|
|
||||||
|
Worker1 --> Redis_Master
|
||||||
|
Worker2 --> Redis_Replica
|
||||||
|
|
||||||
|
Worker1 --> TS
|
||||||
|
Worker2 --> TS
|
||||||
|
|
||||||
|
Worker1 --> Kafka
|
||||||
|
Worker2 --> Kafka
|
||||||
|
|
||||||
|
Worker1 --> S3
|
||||||
|
Worker2 --> S3
|
||||||
|
|
||||||
|
PG_Master -.->|복제| PG_Replica
|
||||||
|
Redis_Master -.->|복제| Redis_Replica
|
||||||
|
|
||||||
|
API1 --> Prometheus
|
||||||
|
Worker1 --> Prometheus
|
||||||
|
Prometheus --> Grafana
|
||||||
|
|
||||||
|
API1 --> ELK
|
||||||
|
Worker1 --> ELK
|
||||||
|
|
||||||
|
style PG_Master fill:#4CAF50,color:#fff
|
||||||
|
style Redis_Master fill:#FF6B6B,color:#fff
|
||||||
|
style Kafka fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 데이터베이스 스키마 분리
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "PostgreSQL"
|
||||||
|
subgraph "Core Schema"
|
||||||
|
Accounts[accounts<br/>계좌 정보]
|
||||||
|
Containers[containers<br/>컨테이너]
|
||||||
|
Strategies[strategies<br/>전략]
|
||||||
|
Orders[orders<br/>주문]
|
||||||
|
Positions[positions<br/>포지션]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Config Schema"
|
||||||
|
RiskLimits[risk_limits<br/>리스크 한도]
|
||||||
|
Schedules[schedules<br/>스케줄]
|
||||||
|
AlertRules[alert_rules<br/>알림 규칙]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Analytics Schema"
|
||||||
|
Performance[performance<br/>성과 데이터]
|
||||||
|
Reports[reports<br/>리포트]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Audit Schema"
|
||||||
|
AuditLogs[audit_logs<br/>감사 로그]
|
||||||
|
ChangeLogs[change_logs<br/>변경 이력]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "TimescaleDB"
|
||||||
|
PriceBars[price_bars<br/>가격 데이터]
|
||||||
|
Metrics[metrics<br/>메트릭]
|
||||||
|
Trades[trades<br/>거래 이력]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Redis"
|
||||||
|
RealtimePrices[실시간 시세]
|
||||||
|
SessionCache[세션 캐시]
|
||||||
|
RateLimits[Rate Limit]
|
||||||
|
end
|
||||||
|
|
||||||
|
Containers --> Accounts
|
||||||
|
Strategies --> Containers
|
||||||
|
Orders --> Containers
|
||||||
|
Positions --> Containers
|
||||||
|
|
||||||
|
RiskLimits --> Containers
|
||||||
|
Schedules --> Containers
|
||||||
|
|
||||||
|
Performance --> Containers
|
||||||
|
Reports --> Performance
|
||||||
|
|
||||||
|
AuditLogs --> Containers
|
||||||
|
ChangeLogs --> Containers
|
||||||
|
|
||||||
|
style Accounts fill:#e3f2fd
|
||||||
|
style Containers fill:#e3f2fd
|
||||||
|
style AuditLogs fill:#f3e5f5
|
||||||
|
style PriceBars fill:#fff9c4
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 보안 아키텍처
|
||||||
|
|
||||||
|
### 6.1 인증 및 권한
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
User[사용자] --> Auth[인증 서비스]
|
||||||
|
Auth --> JWT[JWT 토큰 발급]
|
||||||
|
JWT --> Gateway[API Gateway]
|
||||||
|
|
||||||
|
Gateway --> RBAC[권한 체크]
|
||||||
|
RBAC -->|관리자| AdminAPI[관리 API]
|
||||||
|
RBAC -->|일반 사용자| UserAPI[사용자 API]
|
||||||
|
RBAC -->|읽기 전용| ReadOnlyAPI[조회 API]
|
||||||
|
|
||||||
|
AdminAPI --> Services[백엔드 서비스]
|
||||||
|
UserAPI --> Services
|
||||||
|
ReadOnlyAPI --> Services
|
||||||
|
|
||||||
|
Services --> AuditLog[감사 로그]
|
||||||
|
|
||||||
|
style Auth fill:#4CAF50,color:#fff
|
||||||
|
style RBAC fill:#FF9800,color:#fff
|
||||||
|
style AuditLog fill:#F44336,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 API 키 관리
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
User[사용자] -->|API 키 입력| Encrypt[암호화]
|
||||||
|
Encrypt -->|AES-256| Store[(암호화 저장소)]
|
||||||
|
|
||||||
|
Scheduler[스케줄러] -->|필요 시| Decrypt[복호화]
|
||||||
|
Store -->|암호화된 데이터| Decrypt
|
||||||
|
Decrypt -->|평문 키| BrokerAPI[증권사 API]
|
||||||
|
|
||||||
|
BrokerAPI -->|응답| Scheduler
|
||||||
|
|
||||||
|
Note1[메모리에만 평문 존재]
|
||||||
|
Note2[로그에 절대 기록 안함]
|
||||||
|
|
||||||
|
style Encrypt fill:#4CAF50,color:#fff
|
||||||
|
style Store fill:#F44336,color:#fff
|
||||||
|
style Decrypt fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 확장성 고려사항
|
||||||
|
|
||||||
|
### 7.1 수평 확장
|
||||||
|
|
||||||
|
- **API Gateway**: 로드 밸런서를 통한 다중 인스턴스
|
||||||
|
- **Worker 프로세스**: 메시지 큐 기반 작업 분산
|
||||||
|
- **데이터베이스**: Read Replica를 통한 읽기 부하 분산
|
||||||
|
- **캐시**: Redis Cluster를 통한 분산 캐싱
|
||||||
|
|
||||||
|
### 7.2 증권사 플러그인 아키텍처
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph "Core"
|
||||||
|
BrokerInterface[BrokerAdapter<br/>인터페이스]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "플러그인"
|
||||||
|
KoreaInvestment[한국투자증권<br/>Adapter]
|
||||||
|
Samsung[삼성증권<br/>Adapter]
|
||||||
|
Kiwoom[키움증권<br/>Adapter]
|
||||||
|
Future[미래 증권사<br/>Adapter]
|
||||||
|
end
|
||||||
|
|
||||||
|
BrokerInterface -.->|구현| KoreaInvestment
|
||||||
|
BrokerInterface -.->|구현| Samsung
|
||||||
|
BrokerInterface -.->|구현| Kiwoom
|
||||||
|
BrokerInterface -.->|구현| Future
|
||||||
|
|
||||||
|
Balance[balance 컴포넌트] --> BrokerInterface
|
||||||
|
|
||||||
|
style BrokerInterface fill:#2196F3,color:#fff
|
||||||
|
style Future fill:#ddd
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 장애 복구
|
||||||
|
|
||||||
|
### 8.1 장애 시나리오 및 대응
|
||||||
|
|
||||||
|
| 시나리오 | 영향 | 복구 방안 |
|
||||||
|
|---------|------|----------|
|
||||||
|
| 증권사 API 장애 | 주문 실행 불가 | 자동 재시도 (지수 백오프), 수동 개입 알림 |
|
||||||
|
| 데이터베이스 장애 | 시스템 전체 중단 | Replica로 자동 Failover |
|
||||||
|
| 시장 데이터 지연 | 신호 생성 지연 | 캐시 데이터 활용, 타임아웃 처리 |
|
||||||
|
| Worker 프로세스 다운 | 특정 작업 중단 | 헬스 체크 실패 시 자동 재시작 |
|
||||||
|
| 메시지 큐 장애 | 비동기 작업 중단 | 메시지 영속화, 큐 복구 후 재처리 |
|
||||||
|
|
||||||
|
### 8.2 백업 전략
|
||||||
|
|
||||||
|
- **데이터베이스**: 일일 전체 백업 + 트랜잭션 로그 백업 (Point-in-Time Recovery)
|
||||||
|
- **설정**: Git 기반 버전 관리
|
||||||
|
- **감사 로그**: S3에 불변 저장 (법적 보존 기간 준수)
|
||||||
|
- **백테스트 결과**: 주요 결과만 장기 보관
|
||||||
|
|
||||||
|
## 9. 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](./01-overview.md)
|
||||||
|
- [공통 데이터 모델](./03-data-models.md)
|
||||||
|
- [주요 워크플로우](./04-workflows.md)
|
||||||
|
- [구현 로드맵](./05-roadmap.md)
|
||||||
|
|
||||||
|
### 구성요소 상세 문서
|
||||||
|
- [Phase 1 컴포넌트](../components/phase1/)
|
||||||
|
- [Phase 2 컴포넌트](../components/phase2/)
|
||||||
|
- [Phase 3 컴포넌트](../components/phase3/)
|
||||||
656
docs/03-data-models.md
Normal file
656
docs/03-data-models.md
Normal file
@@ -0,0 +1,656 @@
|
|||||||
|
# QuantBench 공통 데이터 모델
|
||||||
|
|
||||||
|
이 문서는 시스템 전반에서 사용되는 핵심 데이터 모델을 정의합니다.
|
||||||
|
|
||||||
|
## 1. 계좌 및 자산 관련
|
||||||
|
|
||||||
|
### 1.1 Account (계좌)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Account {
|
||||||
|
id: string // 계좌 고유 ID
|
||||||
|
brokerId: string // 증권사 식별자
|
||||||
|
accountNumber: string // 계좌 번호
|
||||||
|
accountName: string // 계좌 별칭
|
||||||
|
accountType: AccountType // 계좌 유형
|
||||||
|
credentials: EncryptedCredentials // 암호화된 인증 정보
|
||||||
|
isActive: boolean // 활성 상태
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
updatedAt: Date // 수정 일시
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountType = 'STOCK' | 'FUTURES' | 'FOREX'
|
||||||
|
|
||||||
|
interface EncryptedCredentials {
|
||||||
|
encryptedData: string // AES-256 암호화된 데이터
|
||||||
|
iv: string // 초기화 벡터
|
||||||
|
algorithm: string // 암호화 알고리즘
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 Balance (잔고)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Balance {
|
||||||
|
accountId: string // 계좌 ID
|
||||||
|
cash: CashBalance // 현금 잔고
|
||||||
|
positions: Position[] // 보유 포지션
|
||||||
|
totalEquity: number // 총 자산 평가액
|
||||||
|
buyingPower: number // 매수 가능 금액
|
||||||
|
withdrawableCash: number // 출금 가능 금액
|
||||||
|
timestamp: Date // 조회 시점
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CashBalance {
|
||||||
|
krw: number // 원화
|
||||||
|
usd: number // 달러
|
||||||
|
[currency: string]: number // 기타 통화
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 Position (포지션)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Position {
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
symbolName?: string // 종목명
|
||||||
|
quantity: number // 보유 수량
|
||||||
|
averagePrice: number // 평균 매입가
|
||||||
|
currentPrice: number // 현재가
|
||||||
|
marketValue: number // 평가 금액
|
||||||
|
unrealizedPnL: number // 평가 손익
|
||||||
|
unrealizedPnLPct: number // 평가 손익률 (%)
|
||||||
|
realizedPnL?: number // 실현 손익
|
||||||
|
updatedAt: Date // 업데이트 시점
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 컨테이너 관련
|
||||||
|
|
||||||
|
### 2.1 Container (컨테이너)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Container {
|
||||||
|
id: string // 컨테이너 ID
|
||||||
|
accountId: string // 소속 계좌 ID
|
||||||
|
name: string // 컨테이너 이름
|
||||||
|
description?: string // 설명
|
||||||
|
strategyId?: string // 연결된 전략 ID
|
||||||
|
|
||||||
|
allocation: Allocation // 자산 할당
|
||||||
|
constraints: Constraints // 제약 조건
|
||||||
|
rebalancing: RebalancingConfig // 리밸런싱 설정
|
||||||
|
|
||||||
|
status: ContainerStatus // 상태
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
updatedAt: Date // 수정 일시
|
||||||
|
lastRebalancedAt?: Date // 마지막 리밸런싱 일시
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Allocation {
|
||||||
|
initialAmount: number // 초기 할당 금액
|
||||||
|
currentEquity: number // 현재 총 자산
|
||||||
|
cashReserve: number // 최소 현금 보유량
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Constraints {
|
||||||
|
maxSinglePositionPct: number // 단일 종목 최대 비중 (%)
|
||||||
|
maxDrawdown: number // 최대 허용 낙폭 (%)
|
||||||
|
allowedAssetClasses: string[] // 투자 가능 자산군
|
||||||
|
maxLeverage?: number // 최대 레버리지 배수
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RebalancingConfig {
|
||||||
|
frequency: RebalancingFrequency
|
||||||
|
dayOfWeek?: number // WEEKLY인 경우 (1=월, 7=일)
|
||||||
|
dayOfMonth?: number // MONTHLY인 경우 (1-31)
|
||||||
|
autoExecute: boolean // 자동 실행 여부
|
||||||
|
}
|
||||||
|
|
||||||
|
type RebalancingFrequency = 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'QUARTERLY' | 'MANUAL'
|
||||||
|
type ContainerStatus = 'ACTIVE' | 'PAUSED' | 'ARCHIVED'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 VirtualBalance (가상 잔고)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface VirtualBalance {
|
||||||
|
containerId: string // 컨테이너 ID
|
||||||
|
cash: number // 현금
|
||||||
|
positions: Position[] // 보유 종목
|
||||||
|
totalValue: number // 총 가치
|
||||||
|
availableCash: number // 주문 가능 현금
|
||||||
|
allocatedValue: number // 할당받은 금액
|
||||||
|
timestamp: Date // 조회 시점
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 전략 관련
|
||||||
|
|
||||||
|
### 3.1 Strategy (전략)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Strategy {
|
||||||
|
id: string // 전략 ID
|
||||||
|
name: string // 전략 이름
|
||||||
|
description: string // 설명
|
||||||
|
category: StrategyCategory // 카테고리
|
||||||
|
|
||||||
|
versions: StrategyVersion[] // 버전 목록
|
||||||
|
currentVersion: string // 현재 버전
|
||||||
|
|
||||||
|
parameters: Parameter[] // 파라미터 정의
|
||||||
|
requiredData: string[] // 필요한 데이터 종류
|
||||||
|
|
||||||
|
createdBy: string // 작성자
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
updatedAt: Date // 수정 일시
|
||||||
|
isPublic: boolean // 공개 여부
|
||||||
|
}
|
||||||
|
|
||||||
|
type StrategyCategory =
|
||||||
|
| 'ASSET_ALLOCATION' // 자산 배분
|
||||||
|
| 'MOMENTUM' // 모멘텀
|
||||||
|
| 'VALUE' // 가치 투자
|
||||||
|
| 'MEAN_REVERSION' // 평균 회귀
|
||||||
|
| 'ARBITRAGE' // 차익 거래
|
||||||
|
| 'CUSTOM' // 사용자 정의
|
||||||
|
|
||||||
|
interface StrategyVersion {
|
||||||
|
version: string // 버전 번호 (예: "1.0.0")
|
||||||
|
code: string // 전략 구현 코드
|
||||||
|
changelog?: string // 변경 사항
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
backtestResults?: BacktestResult[] // 백테스트 결과
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Parameter {
|
||||||
|
name: string // 파라미터 이름
|
||||||
|
type: ParameterType // 데이터 타입
|
||||||
|
defaultValue: any // 기본값
|
||||||
|
description?: string // 설명
|
||||||
|
min?: number // 최소값 (숫자형)
|
||||||
|
max?: number // 최대값 (숫자형)
|
||||||
|
options?: string[] // 선택 옵션 (카테고리형)
|
||||||
|
required: boolean // 필수 여부
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParameterType = 'INTEGER' | 'FLOAT' | 'BOOLEAN' | 'STRING' | 'CATEGORICAL'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Signal (매매 신호)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Signal {
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
action: SignalAction // 행동
|
||||||
|
targetWeight?: number // 목표 비중 (0-1)
|
||||||
|
targetQuantity?: number // 목표 수량
|
||||||
|
reason?: string // 신호 발생 이유
|
||||||
|
confidence?: number // 신호 신뢰도 (0-1)
|
||||||
|
generatedAt: Date // 생성 시점
|
||||||
|
metadata?: Record<string, any> // 추가 메타데이터
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignalAction = 'BUY' | 'SELL' | 'HOLD'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 BacktestResult (백테스트 결과)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface BacktestResult {
|
||||||
|
id: string // 결과 ID
|
||||||
|
strategyId: string // 전략 ID
|
||||||
|
strategyVersion: string // 전략 버전
|
||||||
|
config: BacktestConfig // 설정
|
||||||
|
|
||||||
|
equity: EquityPoint[] // 자산 변화 시계열
|
||||||
|
trades: Trade[] // 거래 내역
|
||||||
|
metrics: PerformanceMetrics // 성과 지표
|
||||||
|
|
||||||
|
runAt: Date // 실행 일시
|
||||||
|
duration: number // 실행 시간 (초)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BacktestConfig {
|
||||||
|
startDate: Date // 시작일
|
||||||
|
endDate: Date // 종료일
|
||||||
|
initialCapital: number // 초기 자본
|
||||||
|
universe: string[] // 투자 대상 종목
|
||||||
|
benchmark?: string // 벤치마크 (예: 'KOSPI')
|
||||||
|
costs: TradingCosts // 거래 비용
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TradingCosts {
|
||||||
|
commission: number // 거래 수수료 (%)
|
||||||
|
slippage: number // 슬리피지 (bps)
|
||||||
|
tax?: number // 세금 (%)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EquityPoint {
|
||||||
|
date: Date // 날짜
|
||||||
|
value: number // 자산 가치
|
||||||
|
cash: number // 현금
|
||||||
|
positions: Record<string, number> // 보유 종목 (종목코드: 수량)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Trade {
|
||||||
|
date: Date // 거래 일시
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
action: 'BUY' | 'SELL' // 매수/매도
|
||||||
|
quantity: number // 수량
|
||||||
|
price: number // 체결 가격
|
||||||
|
commission: number // 수수료
|
||||||
|
slippage: number // 슬리피지
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 주문 관련
|
||||||
|
|
||||||
|
### 4.1 Order (주문)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Order {
|
||||||
|
orderId?: string // 주문 ID
|
||||||
|
accountId: string // 계좌 ID
|
||||||
|
containerId?: string // 컨테이너 ID (있는 경우)
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
side: OrderSide // 매수/매도
|
||||||
|
orderType: OrderType // 주문 유형
|
||||||
|
quantity: number // 주문 수량
|
||||||
|
price?: number // 지정가 (LIMIT인 경우)
|
||||||
|
stopPrice?: number // 스톱 가격 (STOP인 경우)
|
||||||
|
|
||||||
|
status: OrderStatus // 주문 상태
|
||||||
|
filledQuantity?: number // 체결 수량
|
||||||
|
averageFillPrice?: number // 평균 체결가
|
||||||
|
commission?: number // 수수료
|
||||||
|
|
||||||
|
submittedAt?: Date // 제출 일시
|
||||||
|
executedAt?: Date // 체결 일시
|
||||||
|
cancelledAt?: Date // 취소 일시
|
||||||
|
|
||||||
|
metadata?: Record<string, any> // 추가 메타데이터
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderSide = 'BUY' | 'SELL'
|
||||||
|
type OrderType = 'MARKET' | 'LIMIT' | 'STOP' | 'STOP_LIMIT'
|
||||||
|
type OrderStatus =
|
||||||
|
| 'PENDING' // 대기 중
|
||||||
|
| 'SUBMITTED' // 제출됨
|
||||||
|
| 'PARTIALLY_FILLED' // 부분 체결
|
||||||
|
| 'FILLED' // 완전 체결
|
||||||
|
| 'CANCELLED' // 취소됨
|
||||||
|
| 'REJECTED' // 거부됨
|
||||||
|
| 'EXPIRED' // 만료됨
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 시장 데이터 관련
|
||||||
|
|
||||||
|
### 5.1 PriceBar (가격 바)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PriceBar {
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
timestamp: Date // 시간
|
||||||
|
interval: Interval // 주기
|
||||||
|
open: number // 시가
|
||||||
|
high: number // 고가
|
||||||
|
low: number // 저가
|
||||||
|
close: number // 종가
|
||||||
|
volume: number // 거래량
|
||||||
|
adjustedClose?: number // 조정 종가
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interval = '1m' | '5m' | '15m' | '1h' | '4h' | '1d' | '1w' | '1M'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Quote (현재가)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Quote {
|
||||||
|
symbol: string // 종목 코드
|
||||||
|
price: number // 현재가
|
||||||
|
change: number // 전일 대비 변동
|
||||||
|
changePct: number // 변동률 (%)
|
||||||
|
volume: number // 거래량
|
||||||
|
bidPrice: number // 매수 호가
|
||||||
|
askPrice: number // 매도 호가
|
||||||
|
bidSize: number // 매수 호가 수량
|
||||||
|
askSize: number // 매도 호가 수량
|
||||||
|
timestamp: Date // 시세 시간
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 리스크 관련
|
||||||
|
|
||||||
|
### 6.1 RiskLimits (리스크 한도)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface RiskLimits {
|
||||||
|
containerId: string // 컨테이너 ID
|
||||||
|
|
||||||
|
position: PositionLimits // 포지션 한도
|
||||||
|
loss: LossLimits // 손실 한도
|
||||||
|
exposure: ExposureLimits // 익스포저 한도
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PositionLimits {
|
||||||
|
maxSinglePositionPct: number // 단일 종목 최대 비중 (%)
|
||||||
|
maxSectorPct: number // 단일 섹터 최대 비중 (%)
|
||||||
|
maxTotalLeverage: number // 최대 레버리지 배수
|
||||||
|
minPositionSize?: number // 최소 포지션 크기
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LossLimits {
|
||||||
|
maxDailyLossPct: number // 일일 최대 손실 (%)
|
||||||
|
maxDrawdownPct: number // 최대 낙폭 (%)
|
||||||
|
stopLossEnabled: boolean // 손절 활성화
|
||||||
|
takeProfitEnabled?: boolean // 익절 활성화
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExposureLimits {
|
||||||
|
maxLongExposure: number // 최대 롱 익스포저
|
||||||
|
maxShortExposure: number // 최대 숏 익스포저
|
||||||
|
maxGrossExposure: number // 최대 총 익스포저
|
||||||
|
maxNetExposure?: number // 최대 순 익스포저
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 RiskCheckResult (리스크 검증 결과)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface RiskCheckResult {
|
||||||
|
passed: boolean // 통과 여부
|
||||||
|
violations: RiskViolation[] // 위반 항목
|
||||||
|
recommendations?: string[] // 권장 사항
|
||||||
|
timestamp: Date // 검증 시점
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RiskViolation {
|
||||||
|
rule: string // 규칙 이름
|
||||||
|
severity: ViolationSeverity // 심각도
|
||||||
|
message: string // 메시지
|
||||||
|
currentValue: number // 현재 값
|
||||||
|
limitValue: number // 한도 값
|
||||||
|
}
|
||||||
|
|
||||||
|
type ViolationSeverity = 'BLOCKING' | 'WARNING' | 'INFO'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 스케줄 및 실행 관련
|
||||||
|
|
||||||
|
### 7.1 Schedule (스케줄)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Schedule {
|
||||||
|
id: string // 스케줄 ID
|
||||||
|
containerId: string // 컨테이너 ID
|
||||||
|
name: string // 스케줄 이름
|
||||||
|
|
||||||
|
trigger: ScheduleTrigger // 트리거 설정
|
||||||
|
executionMode: ExecutionMode // 실행 모드
|
||||||
|
constraints: ScheduleConstraints // 제약 조건
|
||||||
|
|
||||||
|
isActive: boolean // 활성 상태
|
||||||
|
nextRun?: Date // 다음 실행 시간
|
||||||
|
lastRun?: Date // 마지막 실행 시간
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScheduleTrigger {
|
||||||
|
type: TriggerType // 트리거 유형
|
||||||
|
expression?: string // Cron 표현식 (CRON인 경우)
|
||||||
|
intervalMinutes?: number // 주기 (INTERVAL인 경우)
|
||||||
|
event?: TriggerEvent // 이벤트 (EVENT인 경우)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TriggerType = 'CRON' | 'INTERVAL' | 'EVENT'
|
||||||
|
type TriggerEvent = 'MARKET_OPEN' | 'MARKET_CLOSE' | 'CUSTOM'
|
||||||
|
type ExecutionMode = 'AUTO' | 'APPROVAL_REQUIRED'
|
||||||
|
|
||||||
|
interface ScheduleConstraints {
|
||||||
|
marketHoursOnly: boolean // 장 시간만
|
||||||
|
skipHolidays: boolean // 휴일 건너뛰기
|
||||||
|
minIntervalHours?: number // 최소 실행 간격 (시간)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 Execution (실행)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Execution {
|
||||||
|
id: string // 실행 ID
|
||||||
|
containerId: string // 컨테이너 ID
|
||||||
|
strategyId: string // 전략 ID
|
||||||
|
scheduleId?: string // 스케줄 ID (자동 실행인 경우)
|
||||||
|
|
||||||
|
status: ExecutionStatus // 상태
|
||||||
|
signals: Signal[] // 생성된 신호
|
||||||
|
plannedOrders: Order[] // 계획된 주문
|
||||||
|
executedOrders: Order[] // 실행된 주문
|
||||||
|
|
||||||
|
estimatedCost: EstimatedCost // 예상 비용
|
||||||
|
approvalRequest?: ApprovalRequest // 승인 요청 (있는 경우)
|
||||||
|
|
||||||
|
startedAt?: Date // 시작 일시
|
||||||
|
completedAt?: Date // 완료 일시
|
||||||
|
error?: string // 에러 메시지
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionStatus =
|
||||||
|
| 'PENDING' // 대기
|
||||||
|
| 'APPROVED' // 승인됨
|
||||||
|
| 'REJECTED' // 거부됨
|
||||||
|
| 'RUNNING' // 실행 중
|
||||||
|
| 'COMPLETED' // 완료
|
||||||
|
| 'FAILED' // 실패
|
||||||
|
|
||||||
|
interface EstimatedCost {
|
||||||
|
commission: number // 예상 수수료
|
||||||
|
slippage: number // 예상 슬리피지
|
||||||
|
totalValue: number // 총 거래 금액
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApprovalRequest {
|
||||||
|
id: string // 요청 ID
|
||||||
|
executionId: string // 실행 ID
|
||||||
|
summary: ApprovalSummary // 요약
|
||||||
|
orders: Order[] // 주문 목록
|
||||||
|
requestedAt: Date // 요청 일시
|
||||||
|
expiresAt: Date // 만료 일시
|
||||||
|
approvedAt?: Date // 승인 일시
|
||||||
|
approvedBy?: string // 승인자
|
||||||
|
decision?: ApprovalDecision // 결정
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApprovalSummary {
|
||||||
|
numOrders: number // 주문 건수
|
||||||
|
buyValue: number // 매수 금액
|
||||||
|
sellValue: number // 매도 금액
|
||||||
|
estimatedCommission: number // 예상 수수료
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApprovalDecision = 'APPROVED' | 'REJECTED'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 성과 분석 관련
|
||||||
|
|
||||||
|
### 8.1 PerformanceMetrics (성과 지표)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PerformanceMetrics {
|
||||||
|
// 수익률
|
||||||
|
totalReturn: number // 총 수익률 (%)
|
||||||
|
cagr: number // 연평균 성장률 (%)
|
||||||
|
annualizedReturn: number // 연율화 수익률 (%)
|
||||||
|
|
||||||
|
// 리스크
|
||||||
|
volatility: number // 변동성 (%, 연율화)
|
||||||
|
maxDrawdown: number // 최대 낙폭 (%)
|
||||||
|
downsideDeviation: number // 하방 편차 (%)
|
||||||
|
|
||||||
|
// 리스크 조정 수익률
|
||||||
|
sharpeRatio: number // 샤프 비율
|
||||||
|
sortinoRatio: number // 소르티노 비율
|
||||||
|
calmarRatio: number // 칼마 비율
|
||||||
|
|
||||||
|
// 거래 지표
|
||||||
|
winRate: number // 승률 (%)
|
||||||
|
avgWin: number // 평균 수익 (%)
|
||||||
|
avgLoss: number // 평균 손실 (%)
|
||||||
|
profitFactor: number // 손익비
|
||||||
|
|
||||||
|
// 기타
|
||||||
|
tradingDays: number // 거래 일수
|
||||||
|
totalTrades: number // 총 거래 건수
|
||||||
|
turnover: number // 회전율 (연율화)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 모니터링 및 알림 관련
|
||||||
|
|
||||||
|
### 9.1 Alert (알림)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Alert {
|
||||||
|
id: string // 알림 ID
|
||||||
|
type: AlertType // 알림 유형
|
||||||
|
severity: AlertSeverity // 심각도
|
||||||
|
|
||||||
|
title: string // 제목
|
||||||
|
message: string // 내용
|
||||||
|
|
||||||
|
source: string // 발생 컴포넌트
|
||||||
|
containerId?: string // 컨테이너 ID (있는 경우)
|
||||||
|
accountId?: string // 계좌 ID (있는 경우)
|
||||||
|
|
||||||
|
channels: AlertChannel[] // 발송 채널
|
||||||
|
sentAt?: Date // 발송 일시
|
||||||
|
|
||||||
|
acknowledged: boolean // 확인 여부
|
||||||
|
acknowledgedAt?: Date // 확인 일시
|
||||||
|
acknowledgedBy?: string // 확인자
|
||||||
|
|
||||||
|
createdAt: Date // 생성 일시
|
||||||
|
metadata?: Record<string, any> // 추가 메타데이터
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlertType =
|
||||||
|
| 'SYSTEM' // 시스템
|
||||||
|
| 'RISK' // 리스크
|
||||||
|
| 'EXECUTION' // 실행
|
||||||
|
| 'PERFORMANCE' // 성과
|
||||||
|
| 'ANOMALY' // 이상
|
||||||
|
|
||||||
|
type AlertSeverity = 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL'
|
||||||
|
type AlertChannel = 'EMAIL' | 'SMS' | 'PUSH' | 'SLACK' | 'WEBHOOK'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. 감사 관련
|
||||||
|
|
||||||
|
### 10.1 AuditEvent (감사 이벤트)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface AuditEvent {
|
||||||
|
id: string // 이벤트 ID
|
||||||
|
timestamp: Date // 발생 시간
|
||||||
|
|
||||||
|
eventType: AuditEventType // 이벤트 유형
|
||||||
|
action: string // 행동 (CREATE, UPDATE, DELETE 등)
|
||||||
|
|
||||||
|
userId?: string // 사용자 ID
|
||||||
|
accountId?: string // 계좌 ID
|
||||||
|
containerId?: string // 컨테이너 ID
|
||||||
|
|
||||||
|
entity: string // 엔티티 타입
|
||||||
|
entityId: string // 엔티티 ID
|
||||||
|
|
||||||
|
before?: any // 변경 전 상태
|
||||||
|
after?: any // 변경 후 상태
|
||||||
|
|
||||||
|
metadata: AuditMetadata // 메타데이터
|
||||||
|
|
||||||
|
hash: string // 무결성 검증용 해시
|
||||||
|
previousHash?: string // 이전 이벤트 해시 (체인)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuditEventType =
|
||||||
|
| 'ORDER' // 주문
|
||||||
|
| 'CONFIG_CHANGE' // 설정 변경
|
||||||
|
| 'EXECUTION' // 실행
|
||||||
|
| 'LOGIN' // 로그인
|
||||||
|
| 'DATA_EXPORT' // 데이터 내보내기
|
||||||
|
| 'APPROVAL' // 승인
|
||||||
|
|
||||||
|
interface AuditMetadata {
|
||||||
|
ipAddress?: string // IP 주소
|
||||||
|
userAgent?: string // User Agent
|
||||||
|
reason?: string // 사유
|
||||||
|
source?: string // 출처
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 11. 데이터 관계도
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
Account ||--o{ Container : has
|
||||||
|
Account ||--o{ Balance : has
|
||||||
|
Container ||--o{ VirtualBalance : has
|
||||||
|
Container ||--o| Strategy : uses
|
||||||
|
Container ||--o{ Schedule : has
|
||||||
|
Container ||--o{ RiskLimits : has
|
||||||
|
Container ||--o{ Execution : has
|
||||||
|
|
||||||
|
Strategy ||--o{ StrategyVersion : has
|
||||||
|
Strategy ||--o{ BacktestResult : generates
|
||||||
|
|
||||||
|
Execution ||--o{ Signal : generates
|
||||||
|
Execution ||--o{ Order : creates
|
||||||
|
Execution ||--o| ApprovalRequest : requires
|
||||||
|
|
||||||
|
Order }o--|| Account : belongs_to
|
||||||
|
Order }o--o| Container : belongs_to
|
||||||
|
|
||||||
|
Balance ||--o{ Position : contains
|
||||||
|
VirtualBalance ||--o{ Position : contains
|
||||||
|
|
||||||
|
Container ||--o{ Alert : triggers
|
||||||
|
Execution ||--o{ AuditEvent : generates
|
||||||
|
Order ||--o{ AuditEvent : generates
|
||||||
|
|
||||||
|
Account {
|
||||||
|
string id PK
|
||||||
|
string brokerId
|
||||||
|
string accountNumber
|
||||||
|
AccountType accountType
|
||||||
|
}
|
||||||
|
|
||||||
|
Container {
|
||||||
|
string id PK
|
||||||
|
string accountId FK
|
||||||
|
string strategyId FK
|
||||||
|
ContainerStatus status
|
||||||
|
}
|
||||||
|
|
||||||
|
Strategy {
|
||||||
|
string id PK
|
||||||
|
string name
|
||||||
|
StrategyCategory category
|
||||||
|
}
|
||||||
|
|
||||||
|
Order {
|
||||||
|
string orderId PK
|
||||||
|
string accountId FK
|
||||||
|
string containerId FK
|
||||||
|
OrderStatus status
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 12. 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](./01-overview.md)
|
||||||
|
- [전체 아키텍처](./02-architecture.md)
|
||||||
|
- [주요 워크플로우](./04-workflows.md)
|
||||||
|
- [구현 로드맵](./05-roadmap.md)
|
||||||
695
docs/04-workflows.md
Normal file
695
docs/04-workflows.md
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
# QuantBench 주요 워크플로우
|
||||||
|
|
||||||
|
이 문서는 시스템의 핵심 워크플로우를 상세히 설명합니다.
|
||||||
|
|
||||||
|
## 1. 전략 실행 워크플로우
|
||||||
|
|
||||||
|
### 1.1 전체 흐름
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant S as Scheduler
|
||||||
|
participant M as Mgmt
|
||||||
|
participant ST as Strategy
|
||||||
|
participant D as Data
|
||||||
|
participant R as Risk
|
||||||
|
participant B as Balance
|
||||||
|
participant A as Analytics
|
||||||
|
participant MO as Monitor
|
||||||
|
|
||||||
|
Note over S: 스케줄 트리거 발생
|
||||||
|
|
||||||
|
S->>M: 1. 컨테이너 정보 조회
|
||||||
|
M-->>S: 컨테이너 설정 & 현재 포지션
|
||||||
|
|
||||||
|
S->>ST: 2. 전략 실행 요청
|
||||||
|
ST->>D: 2.1 시장 데이터 조회
|
||||||
|
D-->>ST: 최신 시세 데이터
|
||||||
|
ST->>ST: 2.2 신호 생성
|
||||||
|
ST-->>S: 매매 신호 반환
|
||||||
|
|
||||||
|
S->>R: 3. 리스크 체크
|
||||||
|
R->>R: 3.1 포지션 사이즈 검증
|
||||||
|
R->>R: 3.2 VaR 계산
|
||||||
|
R->>R: 3.3 한도 확인
|
||||||
|
|
||||||
|
alt 리스크 체크 실패
|
||||||
|
R-->>S: 검증 실패
|
||||||
|
S->>MO: 알림 발송
|
||||||
|
MO-->>S: 알림 완료
|
||||||
|
Note over S: 실행 중단
|
||||||
|
else 리스크 체크 통과
|
||||||
|
R-->>S: 검증 통과
|
||||||
|
|
||||||
|
alt 승인 필요 모드
|
||||||
|
S->>S: 승인 요청 생성
|
||||||
|
S->>MO: 사용자에게 알림
|
||||||
|
Note over S: 사용자 승인 대기
|
||||||
|
S->>S: 승인 완료
|
||||||
|
end
|
||||||
|
|
||||||
|
S->>B: 4. 주문 제출
|
||||||
|
B->>B: 4.1 증권사 API 호출
|
||||||
|
B-->>S: 주문 접수 완료
|
||||||
|
|
||||||
|
Note over B: 체결 대기...
|
||||||
|
|
||||||
|
B->>B: 4.2 체결 확인
|
||||||
|
B->>M: 5. 포지션 업데이트
|
||||||
|
M->>M: 5.1 컨테이너 밸런스 갱신
|
||||||
|
|
||||||
|
M->>A: 6. 성과 계산 트리거
|
||||||
|
A->>A: 6.1 수익률 계산
|
||||||
|
A->>A: 6.2 리스크 지표 갱신
|
||||||
|
|
||||||
|
A->>MO: 7. 메트릭 업데이트
|
||||||
|
MO->>MO: 7.1 대시보드 갱신
|
||||||
|
MO->>MO: 7.2 이상 탐지
|
||||||
|
|
||||||
|
alt 이상 탐지 시
|
||||||
|
MO->>MO: 알림 발송
|
||||||
|
end
|
||||||
|
|
||||||
|
S->>S: 8. 실행 완료 기록
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 상세 단계
|
||||||
|
|
||||||
|
#### 1단계: 스케줄 트리거
|
||||||
|
```typescript
|
||||||
|
// 스케줄러가 설정된 시간에 실행을 트리거
|
||||||
|
scheduler.onTrigger(schedule => {
|
||||||
|
const container = mgmt.getContainer(schedule.containerId)
|
||||||
|
const execution = scheduler.createExecution(container, schedule)
|
||||||
|
scheduler.executeStrategy(execution)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2단계: 신호 생성
|
||||||
|
```typescript
|
||||||
|
// 전략이 시장 데이터를 기반으로 신호 생성
|
||||||
|
const marketData = await data.getMarketData(container.strategyUniverse)
|
||||||
|
const signals = await strategy.generateSignals(marketData, container.parameters)
|
||||||
|
|
||||||
|
// 생성된 신호 예시
|
||||||
|
// [
|
||||||
|
// { symbol: 'AAPL', action: 'BUY', targetWeight: 0.3 },
|
||||||
|
// { symbol: 'GOOGL', action: 'SELL', targetWeight: 0 }
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3단계: 리스크 검증
|
||||||
|
```typescript
|
||||||
|
// 신호를 주문으로 변환
|
||||||
|
const plannedOrders = strategy.signalsToOrders(signals, container)
|
||||||
|
|
||||||
|
// 리스크 검증
|
||||||
|
const riskResult = await risk.validateOrders(plannedOrders, container)
|
||||||
|
|
||||||
|
if (!riskResult.passed) {
|
||||||
|
// 리스크 위반 시 실행 중단
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'RISK',
|
||||||
|
severity: 'ERROR',
|
||||||
|
message: `리스크 검증 실패: ${riskResult.violations}`,
|
||||||
|
containerId: container.id
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4단계: 주문 실행
|
||||||
|
```typescript
|
||||||
|
// 승인 필요 모드인 경우
|
||||||
|
if (schedule.executionMode === 'APPROVAL_REQUIRED') {
|
||||||
|
const approvalRequest = await scheduler.requestApproval(execution)
|
||||||
|
await monitor.sendNotification(approvalRequest)
|
||||||
|
|
||||||
|
// 승인 대기
|
||||||
|
const approved = await scheduler.waitForApproval(approvalRequest)
|
||||||
|
if (!approved) return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 주문 제출
|
||||||
|
const executedOrders = []
|
||||||
|
for (const order of plannedOrders) {
|
||||||
|
const result = await balance.placeOrder(order)
|
||||||
|
executedOrders.push(result)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5단계: 포지션 업데이트
|
||||||
|
```typescript
|
||||||
|
// 체결 완료 후 컨테이너 밸런스 업데이트
|
||||||
|
for (const order of executedOrders) {
|
||||||
|
if (order.status === 'FILLED') {
|
||||||
|
await mgmt.updatePosition(container.id, {
|
||||||
|
symbol: order.symbol,
|
||||||
|
quantity: order.side === 'BUY' ? order.filledQuantity : -order.filledQuantity,
|
||||||
|
price: order.averageFillPrice
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 밸런스 조정 (reconciliation)
|
||||||
|
await mgmt.reconcileContainer(container.id)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 리스크 관리 워크플로우
|
||||||
|
|
||||||
|
### 2.1 사전 주문 검증
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Start([주문 요청]) --> GetPosition[현재 포지션 조회]
|
||||||
|
GetPosition --> CalcNewPosition[신규 포지션 계산]
|
||||||
|
|
||||||
|
CalcNewPosition --> CheckBalance{잔고 충분?}
|
||||||
|
CheckBalance -->|No| Reject1[주문 거부:<br/>잔고 부족]
|
||||||
|
CheckBalance -->|Yes| CheckSize
|
||||||
|
|
||||||
|
CheckSize{포지션 사이즈<br/>한도 내?}
|
||||||
|
CheckSize -->|No| Reject2[주문 거부:<br/>사이즈 초과]
|
||||||
|
CheckSize -->|Yes| CheckConcentration
|
||||||
|
|
||||||
|
CheckConcentration{집중도<br/>한도 내?}
|
||||||
|
CheckConcentration -->|No| Reject3[주문 거부:<br/>집중도 초과]
|
||||||
|
CheckConcentration -->|Yes| CalcVaR
|
||||||
|
|
||||||
|
CalcVaR[VaR 계산]
|
||||||
|
CalcVaR --> CheckVaR{VaR<br/>한도 내?}
|
||||||
|
CheckVaR -->|No| Warning1[경고 발생<br/>계속 진행]
|
||||||
|
CheckVaR -->|Yes| CheckDrawdown
|
||||||
|
|
||||||
|
Warning1 --> CheckDrawdown
|
||||||
|
|
||||||
|
CheckDrawdown{최대 낙폭<br/>한도 내?}
|
||||||
|
CheckDrawdown -->|No| Reject4[주문 거부:<br/>MDD 초과]
|
||||||
|
CheckDrawdown -->|Yes| CheckLeverage
|
||||||
|
|
||||||
|
CheckLeverage{레버리지<br/>한도 내?}
|
||||||
|
CheckLeverage -->|No| Reject5[주문 거부:<br/>레버리지 초과]
|
||||||
|
CheckLeverage -->|Yes| Approve
|
||||||
|
|
||||||
|
Approve([검증 통과:<br/>주문 실행])
|
||||||
|
|
||||||
|
Reject1 --> Log[리스크 로그 기록]
|
||||||
|
Reject2 --> Log
|
||||||
|
Reject3 --> Log
|
||||||
|
Reject4 --> Log
|
||||||
|
Reject5 --> Log
|
||||||
|
|
||||||
|
Approve --> ExecuteOrder[주문 제출]
|
||||||
|
ExecuteOrder --> Monitor[실시간 모니터링]
|
||||||
|
|
||||||
|
Monitor --> CheckStop{손절/익절<br/>조건 충족?}
|
||||||
|
CheckStop -->|Yes| AutoClose[자동 청산]
|
||||||
|
CheckStop -->|No| Monitor
|
||||||
|
|
||||||
|
style Start fill:#4CAF50,color:#fff
|
||||||
|
style Approve fill:#4CAF50,color:#fff
|
||||||
|
style Reject1 fill:#F44336,color:#fff
|
||||||
|
style Reject2 fill:#F44336,color:#fff
|
||||||
|
style Reject3 fill:#F44336,color:#fff
|
||||||
|
style Reject4 fill:#F44336,color:#fff
|
||||||
|
style Reject5 fill:#F44336,color:#fff
|
||||||
|
style Warning1 fill:#FF9800,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 실시간 리스크 모니터링
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 실시간 포지션 모니터링
|
||||||
|
monitor.watchContainer(container.id, async (positions, marketData) => {
|
||||||
|
// 손절 조건 체크
|
||||||
|
for (const position of positions) {
|
||||||
|
const stopLoss = risk.getStopLoss(container.id, position.symbol)
|
||||||
|
if (stopLoss && position.unrealizedPnLPct <= -stopLoss.pct) {
|
||||||
|
// 손절 트리거
|
||||||
|
await scheduler.executeEmergencyClose(container.id, position.symbol)
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'RISK',
|
||||||
|
severity: 'WARNING',
|
||||||
|
message: `손절 실행: ${position.symbol} ${position.unrealizedPnLPct}%`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MDD 체크
|
||||||
|
const performance = await analytics.getCurrentPerformance(container.id)
|
||||||
|
const limits = await risk.getRiskLimits(container.id)
|
||||||
|
|
||||||
|
if (performance.currentDrawdown >= limits.loss.maxDrawdownPct) {
|
||||||
|
// 컨테이너 일시 정지
|
||||||
|
await mgmt.pauseContainer(container.id)
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'RISK',
|
||||||
|
severity: 'CRITICAL',
|
||||||
|
message: `최대 낙폭 초과: ${performance.currentDrawdown}%`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 승인 워크플로우
|
||||||
|
|
||||||
|
### 3.1 승인 요청 및 처리
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Trigger[스케줄 트리거] --> GenerateSignals[신호 생성]
|
||||||
|
GenerateSignals --> RiskCheck[리스크 체크]
|
||||||
|
|
||||||
|
RiskCheck --> CheckMode{실행 모드}
|
||||||
|
|
||||||
|
CheckMode -->|AUTO| AutoExecute[자동 실행]
|
||||||
|
CheckMode -->|APPROVAL| CreateRequest
|
||||||
|
|
||||||
|
CreateRequest[승인 요청 생성]
|
||||||
|
CreateRequest --> SendNotification[알림 발송]
|
||||||
|
SendNotification --> WaitApproval[승인 대기]
|
||||||
|
|
||||||
|
WaitApproval --> CheckTimeout{타임아웃?}
|
||||||
|
CheckTimeout -->|Yes| Expired[요청 만료]
|
||||||
|
CheckTimeout -->|No| WaitApproval
|
||||||
|
|
||||||
|
WaitApproval --> UserDecision{사용자 결정}
|
||||||
|
|
||||||
|
UserDecision -->|승인| Execute[주문 실행]
|
||||||
|
UserDecision -->|거부| Rejected[실행 거부]
|
||||||
|
|
||||||
|
AutoExecute --> Execute
|
||||||
|
|
||||||
|
Execute --> PlaceOrders[주문 제출]
|
||||||
|
PlaceOrders --> Success{성공?}
|
||||||
|
|
||||||
|
Success -->|Yes| NotifySuccess[성공 알림]
|
||||||
|
Success -->|No| NotifyFail[실패 알림]
|
||||||
|
|
||||||
|
Rejected --> LogRejection[거부 로그]
|
||||||
|
Expired --> LogExpired[만료 로그]
|
||||||
|
|
||||||
|
NotifySuccess --> End([완료])
|
||||||
|
NotifyFail --> End
|
||||||
|
LogRejection --> End
|
||||||
|
LogExpired --> End
|
||||||
|
|
||||||
|
style Execute fill:#4CAF50,color:#fff
|
||||||
|
style Rejected fill:#F44336,color:#fff
|
||||||
|
style Expired fill:#FF9800,color:#fff
|
||||||
|
style AutoExecute fill:#2196F3,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 승인 요청 생성
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async function createApprovalRequest(execution: Execution): Promise<ApprovalRequest> {
|
||||||
|
// 주문 요약 생성
|
||||||
|
const summary = {
|
||||||
|
numOrders: execution.plannedOrders.length,
|
||||||
|
buyValue: execution.plannedOrders
|
||||||
|
.filter(o => o.side === 'BUY')
|
||||||
|
.reduce((sum, o) => sum + o.quantity * o.price!, 0),
|
||||||
|
sellValue: execution.plannedOrders
|
||||||
|
.filter(o => o.side === 'SELL')
|
||||||
|
.reduce((sum, o) => sum + o.quantity * o.price!, 0),
|
||||||
|
estimatedCommission: execution.estimatedCost.commission
|
||||||
|
}
|
||||||
|
|
||||||
|
// 승인 요청 생성
|
||||||
|
const request = await scheduler.createApprovalRequest({
|
||||||
|
executionId: execution.id,
|
||||||
|
summary,
|
||||||
|
orders: execution.plannedOrders,
|
||||||
|
expiresAt: new Date(Date.now() + 30 * 60 * 1000) // 30분 후 만료
|
||||||
|
})
|
||||||
|
|
||||||
|
// 알림 발송
|
||||||
|
await monitor.sendNotification({
|
||||||
|
type: 'EXECUTION',
|
||||||
|
severity: 'INFO',
|
||||||
|
title: '주문 승인 요청',
|
||||||
|
message: `
|
||||||
|
${summary.numOrders}건의 주문이 대기 중입니다.
|
||||||
|
매수: ${summary.buyValue.toLocaleString()}원
|
||||||
|
매도: ${summary.sellValue.toLocaleString()}원
|
||||||
|
예상 수수료: ${summary.estimatedCommission.toLocaleString()}원
|
||||||
|
`,
|
||||||
|
channels: ['EMAIL', 'PUSH']
|
||||||
|
})
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 컨테이너 생명주기
|
||||||
|
|
||||||
|
### 4.1 상태 전이도
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Created: createContainer()
|
||||||
|
|
||||||
|
Created --> Active: activate()
|
||||||
|
Created --> [*]: delete()
|
||||||
|
|
||||||
|
Active --> Running: scheduler trigger
|
||||||
|
Active --> Paused: pause()
|
||||||
|
Active --> [*]: delete()
|
||||||
|
|
||||||
|
Running --> Active: execution complete
|
||||||
|
Running --> Error: execution failed
|
||||||
|
Running --> Paused: emergency stop
|
||||||
|
|
||||||
|
Paused --> Active: resume()
|
||||||
|
Paused --> [*]: delete()
|
||||||
|
|
||||||
|
Error --> Active: resolve & restart
|
||||||
|
Error --> Paused: manual intervention
|
||||||
|
Error --> [*]: delete()
|
||||||
|
|
||||||
|
state Running {
|
||||||
|
[*] --> GenerateSignals
|
||||||
|
GenerateSignals --> RiskCheck
|
||||||
|
RiskCheck --> PlaceOrders: pass
|
||||||
|
RiskCheck --> [*]: fail
|
||||||
|
PlaceOrders --> AwaitFill
|
||||||
|
AwaitFill --> UpdatePosition
|
||||||
|
UpdatePosition --> [*]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 컨테이너 생성 및 활성화
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. 컨테이너 생성
|
||||||
|
const container = await mgmt.createContainer({
|
||||||
|
accountId: 'account-123',
|
||||||
|
name: '성장주 전략',
|
||||||
|
allocation: {
|
||||||
|
initialAmount: 10000000, // 1천만원
|
||||||
|
cashReserve: 1000000 // 최소 100만원 현금 보유
|
||||||
|
},
|
||||||
|
constraints: {
|
||||||
|
maxSinglePositionPct: 20, // 단일 종목 최대 20%
|
||||||
|
maxDrawdown: 15, // 최대 낙폭 15%
|
||||||
|
allowedAssetClasses: ['STOCK']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2. 전략 할당
|
||||||
|
await mgmt.assignStrategy(container.id, 'strategy-momentum-v1')
|
||||||
|
|
||||||
|
// 3. 리스크 한도 설정
|
||||||
|
await risk.setRiskLimits(container.id, {
|
||||||
|
position: {
|
||||||
|
maxSinglePositionPct: 20,
|
||||||
|
maxSectorPct: 40,
|
||||||
|
maxTotalLeverage: 1.0
|
||||||
|
},
|
||||||
|
loss: {
|
||||||
|
maxDailyLossPct: 5,
|
||||||
|
maxDrawdownPct: 15,
|
||||||
|
stopLossEnabled: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. 스케줄 설정
|
||||||
|
await scheduler.createSchedule({
|
||||||
|
containerId: container.id,
|
||||||
|
trigger: {
|
||||||
|
type: 'CRON',
|
||||||
|
expression: '0 9 * * 1-5' // 평일 오전 9시
|
||||||
|
},
|
||||||
|
executionMode: 'APPROVAL_REQUIRED',
|
||||||
|
constraints: {
|
||||||
|
marketHoursOnly: true,
|
||||||
|
skipHolidays: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 5. 컨테이너 활성화
|
||||||
|
await mgmt.activateContainer(container.id)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 백테스트 워크플로우
|
||||||
|
|
||||||
|
### 5.1 백테스트 실행
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as 사용자
|
||||||
|
participant ST as Strategy
|
||||||
|
participant D as Data
|
||||||
|
participant BE as Backtest Engine
|
||||||
|
participant A as Analytics
|
||||||
|
|
||||||
|
U->>ST: 백테스트 요청
|
||||||
|
ST->>D: 과거 데이터 조회
|
||||||
|
D-->>ST: 시계열 데이터
|
||||||
|
|
||||||
|
ST->>BE: 백테스트 시작
|
||||||
|
|
||||||
|
loop 각 날짜마다
|
||||||
|
BE->>ST: 신호 생성
|
||||||
|
ST-->>BE: 매매 신호
|
||||||
|
BE->>BE: 가상 주문 체결
|
||||||
|
BE->>BE: 포트폴리오 업데이트
|
||||||
|
end
|
||||||
|
|
||||||
|
BE->>A: 성과 계산
|
||||||
|
A-->>BE: 성과 지표
|
||||||
|
|
||||||
|
BE-->>U: 백테스트 결과
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 백테스트 구현
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async function runBacktest(config: BacktestConfig): Promise<BacktestResult> {
|
||||||
|
// 1. 데이터 로드
|
||||||
|
const marketData = await data.getHistoricalPrices(
|
||||||
|
config.universe,
|
||||||
|
config.startDate,
|
||||||
|
config.endDate
|
||||||
|
)
|
||||||
|
|
||||||
|
// 2. 초기 상태 설정
|
||||||
|
let portfolio = {
|
||||||
|
cash: config.initialCapital,
|
||||||
|
positions: {} as Record<string, number>,
|
||||||
|
equity: [{ date: config.startDate, value: config.initialCapital }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const trades: Trade[] = []
|
||||||
|
|
||||||
|
// 3. 시뮬레이션 실행
|
||||||
|
for (const date of marketData.dates) {
|
||||||
|
// 신호 생성
|
||||||
|
const signals = await strategy.generateSignals(
|
||||||
|
marketData.getDataAsOf(date)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 주문 생성 및 체결
|
||||||
|
for (const signal of signals) {
|
||||||
|
if (signal.action === 'HOLD') continue
|
||||||
|
|
||||||
|
const price = marketData.getPrice(signal.symbol, date)
|
||||||
|
const quantity = calculateQuantity(signal, portfolio, price)
|
||||||
|
|
||||||
|
// 슬리피지 및 수수료 적용
|
||||||
|
const executionPrice = applySlippage(price, signal.action, config.costs.slippage)
|
||||||
|
const commission = executionPrice * quantity * config.costs.commission
|
||||||
|
|
||||||
|
// 포트폴리오 업데이트
|
||||||
|
if (signal.action === 'BUY') {
|
||||||
|
portfolio.cash -= executionPrice * quantity + commission
|
||||||
|
portfolio.positions[signal.symbol] = (portfolio.positions[signal.symbol] || 0) + quantity
|
||||||
|
} else {
|
||||||
|
portfolio.cash += executionPrice * quantity - commission
|
||||||
|
portfolio.positions[signal.symbol] -= quantity
|
||||||
|
}
|
||||||
|
|
||||||
|
// 거래 기록
|
||||||
|
trades.push({
|
||||||
|
date,
|
||||||
|
symbol: signal.symbol,
|
||||||
|
action: signal.action,
|
||||||
|
quantity,
|
||||||
|
price: executionPrice,
|
||||||
|
commission
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 일일 자산 가치 계산
|
||||||
|
const positionsValue = Object.entries(portfolio.positions)
|
||||||
|
.reduce((sum, [symbol, qty]) => {
|
||||||
|
return sum + qty * marketData.getPrice(symbol, date)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
portfolio.equity.push({
|
||||||
|
date,
|
||||||
|
value: portfolio.cash + positionsValue,
|
||||||
|
cash: portfolio.cash,
|
||||||
|
positions: { ...portfolio.positions }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 성과 지표 계산
|
||||||
|
const metrics = await analytics.calculateMetrics({
|
||||||
|
equity: portfolio.equity,
|
||||||
|
trades,
|
||||||
|
benchmark: config.benchmark
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: generateId(),
|
||||||
|
strategyId: config.strategyId,
|
||||||
|
config,
|
||||||
|
equity: portfolio.equity,
|
||||||
|
trades,
|
||||||
|
metrics,
|
||||||
|
runAt: new Date(),
|
||||||
|
duration: Date.now() - startTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 데이터 수집 워크플로우
|
||||||
|
|
||||||
|
### 6.1 데이터 수집 파이프라인
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "외부 소스"
|
||||||
|
Broker[증권사 API]
|
||||||
|
Yahoo[Yahoo Finance]
|
||||||
|
Alpha[Alpha Vantage]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "데이터 수집"
|
||||||
|
Collector[Data Collector]
|
||||||
|
RealTime[실시간 스트림]
|
||||||
|
Historical[과거 데이터 수집]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "데이터 처리"
|
||||||
|
Validator[데이터 검증]
|
||||||
|
Adjuster[조정 처리]
|
||||||
|
QualityCheck[품질 체크]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "저장소"
|
||||||
|
Cache[(Redis<br/>실시간)]
|
||||||
|
TimeSeries[(TimescaleDB<br/>과거)]
|
||||||
|
Metadata[(Metadata<br/>종목 정보)]
|
||||||
|
end
|
||||||
|
|
||||||
|
Broker --> RealTime
|
||||||
|
Yahoo --> Historical
|
||||||
|
Alpha --> Historical
|
||||||
|
|
||||||
|
RealTime --> Collector
|
||||||
|
Historical --> Collector
|
||||||
|
|
||||||
|
Collector --> Validator
|
||||||
|
Validator --> QualityCheck
|
||||||
|
QualityCheck -->|통과| Adjuster
|
||||||
|
QualityCheck -->|실패| Alert[품질 알림]
|
||||||
|
|
||||||
|
Adjuster --> Cache
|
||||||
|
Adjuster --> TimeSeries
|
||||||
|
Adjuster --> Metadata
|
||||||
|
|
||||||
|
style Cache fill:#FF6B6B,color:#fff
|
||||||
|
style TimeSeries fill:#4ECDC4,color:#fff
|
||||||
|
style Metadata fill:#45B7D1,color:#fff
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 데이터 품질 관리
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 데이터 수집 및 검증
|
||||||
|
async function collectAndValidateData(symbols: string[], date: Date) {
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
// 1. 데이터 수집
|
||||||
|
const rawData = await dataProvider.fetchPriceData(symbol, date)
|
||||||
|
|
||||||
|
// 2. 데이터 검증
|
||||||
|
const validationResult = await data.validateData(rawData)
|
||||||
|
|
||||||
|
if (!validationResult.isValid) {
|
||||||
|
// 품질 문제 감지
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'SYSTEM',
|
||||||
|
severity: 'WARNING',
|
||||||
|
message: `데이터 품질 문제: ${symbol} - ${validationResult.issues.join(', ')}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 결측치 보정 시도
|
||||||
|
if (validationResult.canFill) {
|
||||||
|
rawData = await data.fillMissingData(rawData, 'FORWARD_FILL')
|
||||||
|
} else {
|
||||||
|
continue // 보정 불가능하면 skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 기업 행동 조정 (배당, 액면분할 등)
|
||||||
|
const adjustedData = await data.adjustForCorporateActions(rawData, symbol)
|
||||||
|
|
||||||
|
// 4. 저장
|
||||||
|
await data.storePriceData(adjustedData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 성과 분석 워크플로우
|
||||||
|
|
||||||
|
### 7.1 일일 성과 계산
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 매일 장 마감 후 실행
|
||||||
|
scheduler.scheduleDaily('MARKET_CLOSE', async () => {
|
||||||
|
const containers = await mgmt.getActiveContainers()
|
||||||
|
|
||||||
|
for (const container of containers) {
|
||||||
|
// 1. 현재 포지션 평가
|
||||||
|
const positions = await mgmt.getPositions(container.id)
|
||||||
|
const marketData = await data.getLatestPrices(positions.map(p => p.symbol))
|
||||||
|
|
||||||
|
// 2. 일일 수익률 계산
|
||||||
|
const dailyReturn = await analytics.calculateDailyReturn(
|
||||||
|
container.id,
|
||||||
|
positions,
|
||||||
|
marketData
|
||||||
|
)
|
||||||
|
|
||||||
|
// 3. 누적 성과 업데이트
|
||||||
|
await analytics.updatePerformance(container.id, {
|
||||||
|
date: new Date(),
|
||||||
|
return: dailyReturn,
|
||||||
|
equity: positions.reduce((sum, p) => sum + p.marketValue, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. 리스크 지표 재계산
|
||||||
|
const riskMetrics = await analytics.calculateRiskMetrics(container.id)
|
||||||
|
|
||||||
|
// 5. 이상 탐지
|
||||||
|
if (dailyReturn < -5) { // 일일 손실 5% 초과
|
||||||
|
await monitor.sendAlert({
|
||||||
|
type: 'PERFORMANCE',
|
||||||
|
severity: 'WARNING',
|
||||||
|
message: `일일 손실 초과: ${container.name} ${dailyReturn.toFixed(2)}%`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](./01-overview.md)
|
||||||
|
- [전체 아키텍처](./02-architecture.md)
|
||||||
|
- [공통 데이터 모델](./03-data-models.md)
|
||||||
|
- [구현 로드맵](./05-roadmap.md)
|
||||||
513
docs/05-roadmap.md
Normal file
513
docs/05-roadmap.md
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
# QuantBench 구현 로드맵
|
||||||
|
|
||||||
|
## 1. 전체 일정 개요
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
gantt
|
||||||
|
title QuantBench 개발 일정
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
section Phase 1: MVP
|
||||||
|
프로젝트 설정 :p1_1, 2024-01-01, 2w
|
||||||
|
balance 구현 :p1_2, after p1_1, 4w
|
||||||
|
data 구현 :p1_3, after p1_1, 4w
|
||||||
|
mgmt 구현 :p1_4, after p1_2, 3w
|
||||||
|
strategy 구현 :p1_5, after p1_3, 4w
|
||||||
|
scheduler 구현 :p1_6, after p1_4, 3w
|
||||||
|
risk 구현 :p1_7, after p1_5, 3w
|
||||||
|
통합 테스트 :p1_8, after p1_6, 2w
|
||||||
|
|
||||||
|
section Phase 2: Production
|
||||||
|
analytics 구현 :p2_1, after p1_8, 4w
|
||||||
|
monitor 구현 :p2_2, after p1_8, 4w
|
||||||
|
대시보드 개발 :p2_3, after p2_1, 3w
|
||||||
|
통합 및 테스트 :p2_4, after p2_2, 2w
|
||||||
|
|
||||||
|
section Phase 3: Enterprise
|
||||||
|
audit 구현 :p3_1, after p2_4, 4w
|
||||||
|
simulation 구현 :p3_2, after p2_4, 4w
|
||||||
|
최종 통합 및 배포 :p3_3, after p3_1, 3w
|
||||||
|
```
|
||||||
|
|
||||||
|
### 전체 일정 요약
|
||||||
|
|
||||||
|
| Phase | 기간 | 주요 산출물 |
|
||||||
|
|-------|------|------------|
|
||||||
|
| **Phase 1: MVP** | 3-4개월 | 기본 거래 시스템 |
|
||||||
|
| **Phase 2: Production** | 2-3개월 | 모니터링 & 분석 |
|
||||||
|
| **Phase 3: Enterprise** | 2-3개월 | 감사 & 시뮬레이션 |
|
||||||
|
| **총 기간** | 7-10개월 | 완전한 퀀트 시스템 |
|
||||||
|
|
||||||
|
## 2. Phase 1: MVP (3-4개월)
|
||||||
|
|
||||||
|
### 목표
|
||||||
|
안전하게 전략을 실행하고 리스크를 통제할 수 있는 기본 시스템 구축
|
||||||
|
|
||||||
|
### 2.1 프로젝트 설정 (1-2주)
|
||||||
|
|
||||||
|
**작업 항목**:
|
||||||
|
- [ ] 레포지토리 구조 설정
|
||||||
|
- [ ] 개발 환경 구축 (Docker, Docker Compose)
|
||||||
|
- [ ] CI/CD 파이프라인 설정
|
||||||
|
- [ ] 코드 스타일 가이드 및 린팅 설정
|
||||||
|
- [ ] 데이터베이스 스키마 초기 설계
|
||||||
|
- [ ] API 인증/인가 구조 설계
|
||||||
|
|
||||||
|
**기술 스택 결정**:
|
||||||
|
- 백엔드: TypeScript + Node.js (또는 Python + FastAPI)
|
||||||
|
- 데이터베이스: PostgreSQL + TimescaleDB
|
||||||
|
- 캐시: Redis
|
||||||
|
- 메시지 큐: RabbitMQ (또는 Kafka)
|
||||||
|
|
||||||
|
### 2.2 Week 1-4: balance + data 기본 구현
|
||||||
|
|
||||||
|
#### balance 컴포넌트 (2-3주)
|
||||||
|
|
||||||
|
**우선순위 1: 한국투자증권 API 연동**
|
||||||
|
- [ ] BrokerAdapter 인터페이스 정의
|
||||||
|
- [ ] 한국투자증권 Adapter 구현
|
||||||
|
- [ ] 인증 및 세션 관리
|
||||||
|
- [ ] 계좌 잔고 조회
|
||||||
|
- [ ] 현재가 조회
|
||||||
|
- [ ] 주문 제출 (시장가, 지정가)
|
||||||
|
- [ ] 주문 상태 조회
|
||||||
|
- [ ] 주문 취소
|
||||||
|
- [ ] API 키 암호화 저장
|
||||||
|
- [ ] 에러 처리 및 재시도 로직
|
||||||
|
- [ ] 단위 테스트 작성
|
||||||
|
|
||||||
|
**우선순위 2: 계좌 관리 기능**
|
||||||
|
- [ ] 계좌 등록/수정/삭제 API
|
||||||
|
- [ ] 계좌 목록 조회
|
||||||
|
- [ ] 계좌 상태 관리
|
||||||
|
|
||||||
|
#### data 컴포넌트 (2-3주)
|
||||||
|
|
||||||
|
**우선순위 1: 데이터 수집**
|
||||||
|
- [ ] 데이터 소스 추상화 인터페이스
|
||||||
|
- [ ] Yahoo Finance 연동 (과거 데이터)
|
||||||
|
- [ ] 한국투자증권 API를 통한 실시간 시세 조회
|
||||||
|
- [ ] 데이터 검증 로직
|
||||||
|
- [ ] 결측치 탐지
|
||||||
|
- [ ] 이상치 탐지
|
||||||
|
- [ ] 데이터 연속성 체크
|
||||||
|
|
||||||
|
**우선순위 2: 데이터 저장**
|
||||||
|
- [ ] TimescaleDB 스키마 설계
|
||||||
|
- [ ] 가격 데이터 저장 (PriceBar)
|
||||||
|
- [ ] Redis 캐시 연동 (실시간 시세)
|
||||||
|
- [ ] 데이터 조회 API
|
||||||
|
- [ ] 과거 데이터 조회
|
||||||
|
- [ ] 최신 시세 조회
|
||||||
|
- [ ] 다중 종목 배치 조회
|
||||||
|
|
||||||
|
### 2.3 Week 5-8: mgmt + strategy 핵심 기능
|
||||||
|
|
||||||
|
#### mgmt 컴포넌트 (3주)
|
||||||
|
|
||||||
|
**우선순위 1: 컨테이너 생명주기**
|
||||||
|
- [ ] 컨테이너 생성/수정/삭제 API
|
||||||
|
- [ ] 가상 잔고 관리
|
||||||
|
- [ ] 초기 자산 할당
|
||||||
|
- [ ] 현금 및 포지션 추적
|
||||||
|
- [ ] 밸런스 조정 (reconciliation)
|
||||||
|
- [ ] 컨테이너 상태 관리 (ACTIVE/PAUSED/ARCHIVED)
|
||||||
|
|
||||||
|
**우선순위 2: 자산 관리**
|
||||||
|
- [ ] 컨테이너 간 자산 이동
|
||||||
|
- [ ] 실제 계좌 vs 가상 컨테이너 일치성 검증
|
||||||
|
- [ ] 컨테이너 조회 API
|
||||||
|
|
||||||
|
#### strategy 컴포넌트 (4주)
|
||||||
|
|
||||||
|
**우선순위 1: 전략 인터페이스**
|
||||||
|
- [ ] StrategyInterface 정의
|
||||||
|
- [ ] 전략 등록 및 관리 API
|
||||||
|
- [ ] 전략 버전 관리
|
||||||
|
- [ ] 파라미터 관리
|
||||||
|
|
||||||
|
**우선순위 2: 신호 생성**
|
||||||
|
- [ ] 신호 생성 엔진
|
||||||
|
- [ ] 신호를 주문으로 변환
|
||||||
|
- [ ] 내장 전략 구현: Bold Asset Allocation
|
||||||
|
- [ ] 고정 비중 자산 배분
|
||||||
|
- [ ] 리밸런싱 로직
|
||||||
|
|
||||||
|
**우선순위 3: 백테스트**
|
||||||
|
- [ ] 백테스트 엔진 구현
|
||||||
|
- [ ] 과거 데이터 기반 시뮬레이션
|
||||||
|
- [ ] 거래 비용 및 슬리피지 모델링
|
||||||
|
- [ ] 성과 지표 계산 (수익률, 샤프 비율, MDD 등)
|
||||||
|
|
||||||
|
### 2.4 Week 9-12: scheduler + risk
|
||||||
|
|
||||||
|
#### scheduler 컴포넌트 (3주)
|
||||||
|
|
||||||
|
**우선순위 1: 스케줄 관리**
|
||||||
|
- [ ] 스케줄 생성/수정/삭제 API
|
||||||
|
- [ ] Cron 기반 트리거
|
||||||
|
- [ ] 시장 시간 체크 (개장/마감)
|
||||||
|
- [ ] 휴일 감지 및 자동 스킵
|
||||||
|
|
||||||
|
**우선순위 2: 실행 관리**
|
||||||
|
- [ ] 실행 트리거 로직
|
||||||
|
- [ ] 전략 실행 오케스트레이션
|
||||||
|
- [ ] 컨테이너 정보 조회
|
||||||
|
- [ ] 신호 생성 요청
|
||||||
|
- [ ] 리스크 검증
|
||||||
|
- [ ] 주문 제출
|
||||||
|
- [ ] 실행 이력 관리
|
||||||
|
|
||||||
|
**우선순위 3: 승인 워크플로우**
|
||||||
|
- [ ] 승인 요청 생성
|
||||||
|
- [ ] 승인 대기 및 타임아웃 처리
|
||||||
|
- [ ] 승인/거부 처리
|
||||||
|
- [ ] 자동 실행 모드
|
||||||
|
|
||||||
|
#### risk 컴포넌트 (3주)
|
||||||
|
|
||||||
|
**우선순위 1: 사전 주문 검증**
|
||||||
|
- [ ] 잔고 충분성 체크
|
||||||
|
- [ ] 포지션 사이즈 한도 검증
|
||||||
|
- [ ] 집중도 리스크 체크 (단일 종목, 섹터)
|
||||||
|
- [ ] 레버리지 한도 검증
|
||||||
|
|
||||||
|
**우선순위 2: 리스크 한도 관리**
|
||||||
|
- [ ] 리스크 한도 설정 API
|
||||||
|
- [ ] 컨테이너별 한도 조회
|
||||||
|
|
||||||
|
**우선순위 3: 손절/익절**
|
||||||
|
- [ ] 손절 조건 설정
|
||||||
|
- [ ] 익절 조건 설정
|
||||||
|
- [ ] 자동 청산 트리거
|
||||||
|
|
||||||
|
### 2.5 Week 13-16: 통합 테스트 및 버그 수정
|
||||||
|
|
||||||
|
**통합 테스트**:
|
||||||
|
- [ ] 전체 워크플로우 End-to-End 테스트
|
||||||
|
- [ ] 컨테이너 생성 → 전략 할당 → 스케줄 설정 → 자동 실행
|
||||||
|
- [ ] 리스크 시나리오 테스트
|
||||||
|
- [ ] 잔고 부족 시나리오
|
||||||
|
- [ ] 리스크 한도 초과 시나리오
|
||||||
|
- [ ] 손절 트리거 시나리오
|
||||||
|
- [ ] 증권사 API 연동 테스트 (Paper Trading 계좌)
|
||||||
|
|
||||||
|
**버그 수정 및 개선**:
|
||||||
|
- [ ] 발견된 버그 수정
|
||||||
|
- [ ] 성능 최적화
|
||||||
|
- [ ] 에러 처리 개선
|
||||||
|
- [ ] 로깅 강화
|
||||||
|
|
||||||
|
**문서화**:
|
||||||
|
- [ ] API 문서 (Swagger/OpenAPI)
|
||||||
|
- [ ] 사용자 가이드
|
||||||
|
- [ ] 운영 매뉴얼
|
||||||
|
|
||||||
|
### Phase 1 완료 기준
|
||||||
|
|
||||||
|
- [ ] 한국투자증권 계좌 연동 완료
|
||||||
|
- [ ] 1개 이상의 전략 백테스트 성공
|
||||||
|
- [ ] Paper Trading 환경에서 자동 매매 성공
|
||||||
|
- [ ] 모든 리스크 체크 통과
|
||||||
|
- [ ] 전체 시스템 안정성 검증
|
||||||
|
|
||||||
|
## 3. Phase 2: Production Ready (2-3개월)
|
||||||
|
|
||||||
|
### 목표
|
||||||
|
실전 운영을 위한 모니터링, 분석, 알림 체계 구축
|
||||||
|
|
||||||
|
### 3.1 Week 1-4: analytics 구현
|
||||||
|
|
||||||
|
#### analytics 컴포넌트 (4주)
|
||||||
|
|
||||||
|
**우선순위 1: 성과 측정**
|
||||||
|
- [ ] 일일 수익률 계산
|
||||||
|
- [ ] 누적 수익률 추적
|
||||||
|
- [ ] 리스크 지표 계산
|
||||||
|
- [ ] 변동성 (Volatility)
|
||||||
|
- [ ] 샤프 비율 (Sharpe Ratio)
|
||||||
|
- [ ] 소르티노 비율 (Sortino Ratio)
|
||||||
|
- [ ] 최대 낙폭 (MDD)
|
||||||
|
|
||||||
|
**우선순위 2: 귀속 분석**
|
||||||
|
- [ ] 수익 원천 분해
|
||||||
|
- [ ] 자산 배분 효과
|
||||||
|
- [ ] 종목 선택 효과
|
||||||
|
- [ ] 타이밍 효과
|
||||||
|
- [ ] 섹터별 기여도 분석
|
||||||
|
- [ ] 종목별 기여도 분석
|
||||||
|
|
||||||
|
**우선순위 3: 거래 분석**
|
||||||
|
- [ ] 거래 통계 (승률, 손익비 등)
|
||||||
|
- [ ] 거래 비용 분석
|
||||||
|
- [ ] 회전율 계산
|
||||||
|
|
||||||
|
**우선순위 4: 리포트 생성**
|
||||||
|
- [ ] 일일/주간/월간 리포트 템플릿
|
||||||
|
- [ ] PDF 리포트 생성
|
||||||
|
- [ ] HTML 리포트 생성
|
||||||
|
- [ ] 이메일 자동 발송
|
||||||
|
|
||||||
|
### 3.2 Week 5-8: monitor 구현
|
||||||
|
|
||||||
|
#### monitor 컴포넌트 (4주)
|
||||||
|
|
||||||
|
**우선순위 1: 시스템 헬스 체크**
|
||||||
|
- [ ] 컴포넌트별 헬스 체크
|
||||||
|
- [ ] API 연결 상태 모니터링
|
||||||
|
- [ ] 데이터베이스 응답 시간 추적
|
||||||
|
- [ ] 리소스 사용률 모니터링 (CPU, 메모리)
|
||||||
|
|
||||||
|
**우선순위 2: 이상 탐지**
|
||||||
|
- [ ] 급격한 포지션 변화 감지
|
||||||
|
- [ ] 비정상 주문 탐지
|
||||||
|
- [ ] 시장 이상 조건 감지 (극심한 변동성, 유동성 부족)
|
||||||
|
|
||||||
|
**우선순위 3: 알림 시스템**
|
||||||
|
- [ ] 알림 규칙 엔진
|
||||||
|
- [ ] 다채널 알림 발송
|
||||||
|
- [ ] 이메일 (SendGrid/AWS SES)
|
||||||
|
- [ ] SMS (Twilio)
|
||||||
|
- [ ] 푸시 알림 (Firebase)
|
||||||
|
- [ ] Slack 웹훅
|
||||||
|
- [ ] 알림 이력 관리
|
||||||
|
- [ ] 알림 빈도 제한 (Throttling)
|
||||||
|
|
||||||
|
**우선순위 4: 대시보드 데이터**
|
||||||
|
- [ ] 실시간 메트릭 수집
|
||||||
|
- [ ] 대시보드 API
|
||||||
|
- [ ] WebSocket을 통한 실시간 업데이트
|
||||||
|
|
||||||
|
### 3.3 Week 9-12: 대시보드 개발 및 통합
|
||||||
|
|
||||||
|
**프론트엔드 개발** (3주):
|
||||||
|
- [ ] 프로젝트 설정 (React + TypeScript)
|
||||||
|
- [ ] 주요 화면 개발
|
||||||
|
- [ ] 대시보드 홈 (전체 계좌 요약)
|
||||||
|
- [ ] 컨테이너 상세 (포지션, 성과, 차트)
|
||||||
|
- [ ] 전략 관리 (등록, 수정, 백테스트 실행)
|
||||||
|
- [ ] 주문 승인 화면
|
||||||
|
- [ ] 알림 센터
|
||||||
|
- [ ] 설정 화면
|
||||||
|
- [ ] 차트 컴포넌트 (TradingView, Chart.js)
|
||||||
|
- [ ] 실시간 업데이트 (WebSocket)
|
||||||
|
|
||||||
|
**통합 및 테스트** (2주):
|
||||||
|
- [ ] 프론트엔드-백엔드 통합
|
||||||
|
- [ ] E2E 테스트
|
||||||
|
- [ ] 성능 테스트
|
||||||
|
- [ ] 사용자 시나리오 테스트
|
||||||
|
|
||||||
|
### Phase 2 완료 기준
|
||||||
|
|
||||||
|
- [ ] 실시간 대시보드 동작
|
||||||
|
- [ ] 자동 리포트 생성 및 발송
|
||||||
|
- [ ] 알림 시스템 정상 작동
|
||||||
|
- [ ] 이상 탐지 시나리오 검증
|
||||||
|
- [ ] 사용자 인수 테스트 통과
|
||||||
|
|
||||||
|
## 4. Phase 3: Enterprise Grade (2-3개월)
|
||||||
|
|
||||||
|
### 목표
|
||||||
|
규제 대응, 감사 추적, 고급 시뮬레이션
|
||||||
|
|
||||||
|
### 4.1 Week 1-4: audit 구현
|
||||||
|
|
||||||
|
#### audit 컴포넌트 (4주)
|
||||||
|
|
||||||
|
**우선순위 1: 감사 로그**
|
||||||
|
- [ ] 감사 이벤트 정의
|
||||||
|
- [ ] 불변 로그 저장 (Append-Only)
|
||||||
|
- [ ] 해시 체인 구현 (무결성 보장)
|
||||||
|
- [ ] 주요 이벤트 자동 기록
|
||||||
|
- [ ] 주문 생성/취소/체결
|
||||||
|
- [ ] 설정 변경
|
||||||
|
- [ ] 승인/거부
|
||||||
|
- [ ] 로그인
|
||||||
|
|
||||||
|
**우선순위 2: 변경 추적**
|
||||||
|
- [ ] 엔티티별 변경 이력
|
||||||
|
- [ ] Before/After 스냅샷
|
||||||
|
- [ ] 변경 사유 기록
|
||||||
|
|
||||||
|
**우선순위 3: 규제 리포팅**
|
||||||
|
- [ ] 거래 내역 보고서
|
||||||
|
- [ ] 포지션 명세서
|
||||||
|
- [ ] 이상 거래 보고서
|
||||||
|
- [ ] CSV/JSON 내보내기
|
||||||
|
|
||||||
|
**우선순위 4: 무결성 검증**
|
||||||
|
- [ ] 감사 로그 무결성 체크
|
||||||
|
- [ ] 해시 체인 검증
|
||||||
|
- [ ] 주기적 무결성 검사 스케줄
|
||||||
|
|
||||||
|
### 4.2 Week 5-8: simulation 구현
|
||||||
|
|
||||||
|
#### simulation 컴포넌트 (4주)
|
||||||
|
|
||||||
|
**우선순위 1: Paper Trading**
|
||||||
|
- [ ] 가상 계좌 생성
|
||||||
|
- [ ] 가상 주문 체결 엔진
|
||||||
|
- [ ] 실시간 호가 기반 체결 시뮬레이션
|
||||||
|
- [ ] 슬리피지 모델링
|
||||||
|
- [ ] 수수료 계산
|
||||||
|
- [ ] 가상 포트폴리오 관리
|
||||||
|
|
||||||
|
**우선순위 2: 시뮬레이션 환경**
|
||||||
|
- [ ] 과거 데이터 리플레이
|
||||||
|
- [ ] 다중 시나리오 테스트
|
||||||
|
- [ ] 스트레스 테스트
|
||||||
|
- [ ] 극단 변동성 시나리오
|
||||||
|
- [ ] 유동성 부족 시나리오
|
||||||
|
- [ ] 블랙스완 이벤트
|
||||||
|
|
||||||
|
**우선순위 3: 파라미터 최적화**
|
||||||
|
- [ ] 그리드 서치
|
||||||
|
- [ ] 랜덤 서치
|
||||||
|
- [ ] 베이지안 최적화 (선택)
|
||||||
|
- [ ] Walk-Forward 분석
|
||||||
|
- [ ] 과최적화 검증
|
||||||
|
|
||||||
|
**우선순위 4: 실계좌 전환**
|
||||||
|
- [ ] Paper → Real 전환 검증
|
||||||
|
- [ ] 설정 복제 및 검증
|
||||||
|
- [ ] 점진적 자산 이전
|
||||||
|
|
||||||
|
### 4.3 Week 9-12: 최종 통합 및 배포
|
||||||
|
|
||||||
|
**보안 강화** (2주):
|
||||||
|
- [ ] 침투 테스트 (Penetration Testing)
|
||||||
|
- [ ] API 키 관리 강화
|
||||||
|
- [ ] 역할 기반 접근 제어 (RBAC) 세밀화
|
||||||
|
- [ ] 감사 로그 접근 제어
|
||||||
|
|
||||||
|
**성능 최적화** (1주):
|
||||||
|
- [ ] 데이터베이스 쿼리 최적화
|
||||||
|
- [ ] 캐싱 전략 개선
|
||||||
|
- [ ] API 응답 시간 최적화
|
||||||
|
- [ ] 부하 테스트
|
||||||
|
|
||||||
|
**배포 준비** (2주):
|
||||||
|
- [ ] 프로덕션 환경 설정
|
||||||
|
- [ ] 데이터베이스 마이그레이션 스크립트
|
||||||
|
- [ ] 백업 및 복구 절차 수립
|
||||||
|
- [ ] 모니터링 및 알림 설정 (Prometheus, Grafana)
|
||||||
|
- [ ] 장애 복구 계획 (DR Plan)
|
||||||
|
- [ ] 운영 문서 작성
|
||||||
|
|
||||||
|
**최종 검증** (1주):
|
||||||
|
- [ ] 전체 시스템 통합 테스트
|
||||||
|
- [ ] 보안 검증
|
||||||
|
- [ ] 성능 검증
|
||||||
|
- [ ] 사용자 인수 테스트 (UAT)
|
||||||
|
|
||||||
|
### Phase 3 완료 기준
|
||||||
|
|
||||||
|
- [ ] 모든 거래가 감사 로그에 기록됨
|
||||||
|
- [ ] Paper Trading 환경 정상 작동
|
||||||
|
- [ ] 파라미터 최적화 기능 검증
|
||||||
|
- [ ] 보안 감사 통과
|
||||||
|
- [ ] 프로덕션 배포 완료
|
||||||
|
|
||||||
|
## 5. 마일스톤
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
timeline
|
||||||
|
title QuantBench 주요 마일스톤
|
||||||
|
section Phase 1
|
||||||
|
M1.1 : 증권사 API 연동 완료
|
||||||
|
M1.2 : 첫 백테스트 성공
|
||||||
|
M1.3 : Paper Trading 자동매매 성공
|
||||||
|
M1.4 : Phase 1 완료
|
||||||
|
section Phase 2
|
||||||
|
M2.1 : 실시간 대시보드 런칭
|
||||||
|
M2.2 : 자동 리포트 시스템 가동
|
||||||
|
M2.3 : Phase 2 완료
|
||||||
|
section Phase 3
|
||||||
|
M3.1 : 감사 시스템 가동
|
||||||
|
M3.2 : Paper Trading 환경 오픈
|
||||||
|
M3.3 : 프로덕션 배포
|
||||||
|
```
|
||||||
|
|
||||||
|
| 마일스톤 | 예상 일정 | 주요 산출물 |
|
||||||
|
|---------|----------|------------|
|
||||||
|
| **M1.1** | 1개월차 | 한국투자증권 API 연동, 데이터 수집 |
|
||||||
|
| **M1.2** | 2개월차 | Bold Asset Allocation 전략 백테스트 성공 |
|
||||||
|
| **M1.3** | 3개월차 | Paper Trading 환경에서 자동매매 |
|
||||||
|
| **M1.4** | 4개월차 | Phase 1 완료 (MVP) |
|
||||||
|
| **M2.1** | 5개월차 | 실시간 대시보드 |
|
||||||
|
| **M2.2** | 6개월차 | 자동 리포트 시스템 |
|
||||||
|
| **M2.3** | 7개월차 | Phase 2 완료 (Production Ready) |
|
||||||
|
| **M3.1** | 8개월차 | 감사 시스템 |
|
||||||
|
| **M3.2** | 9개월차 | Paper Trading 플랫폼 |
|
||||||
|
| **M3.3** | 10개월차 | 프로덕션 배포 완료 |
|
||||||
|
|
||||||
|
## 6. 리스크 및 대응 방안
|
||||||
|
|
||||||
|
| 리스크 | 영향 | 확률 | 대응 방안 |
|
||||||
|
|-------|------|------|----------|
|
||||||
|
| 증권사 API 변경 | 높음 | 중간 | 추상화 레이어 강화, 다중 증권사 지원 |
|
||||||
|
| 데이터 품질 문제 | 중간 | 높음 | 데이터 검증 강화, 다중 데이터 소스 |
|
||||||
|
| 성능 병목 | 중간 | 중간 | 초기부터 부하 테스트, 확장 가능 아키텍처 |
|
||||||
|
| 보안 취약점 | 높음 | 낮음 | 정기 보안 감사, 침투 테스트 |
|
||||||
|
| 일정 지연 | 중간 | 높음 | 애자일 방식, 2주 단위 스프린트, 우선순위 조정 |
|
||||||
|
| 규제 변경 | 중간 | 낮음 | 감사 로그 강화, 유연한 설계 |
|
||||||
|
|
||||||
|
## 7. 추가 고려사항
|
||||||
|
|
||||||
|
### 7.1 다중 증권사 지원 계획
|
||||||
|
|
||||||
|
**Phase 1.5 (선택)**: 삼성증권 또는 키움증권 추가 연동
|
||||||
|
- 예상 기간: 2-3주
|
||||||
|
- BrokerAdapter 패턴 검증
|
||||||
|
- 다중 계좌 통합 관리 테스트
|
||||||
|
|
||||||
|
### 7.2 고급 전략 추가
|
||||||
|
|
||||||
|
**Phase 2.5 (선택)**: 추가 전략 구현
|
||||||
|
- Momentum 전략
|
||||||
|
- Value 전략
|
||||||
|
- Mean Reversion 전략
|
||||||
|
- 각 전략당 2-3주 소요
|
||||||
|
|
||||||
|
### 7.3 글로벌 시장 지원
|
||||||
|
|
||||||
|
**Phase 4 (선택)**: 미국 주식 시장 지원
|
||||||
|
- Interactive Brokers API 연동
|
||||||
|
- 시간대 처리 (타임존)
|
||||||
|
- 환율 처리
|
||||||
|
- 예상 기간: 2-3개월
|
||||||
|
|
||||||
|
## 8. 성공 지표 (KPI)
|
||||||
|
|
||||||
|
### Phase 1 완료 시
|
||||||
|
|
||||||
|
- [ ] 시스템 가동률: 95% 이상
|
||||||
|
- [ ] API 응답 시간: 평균 < 500ms
|
||||||
|
- [ ] 주문 처리 성공률: 99% 이상
|
||||||
|
- [ ] 백테스트 정확도: 실제 거래 대비 ±1% 이내
|
||||||
|
|
||||||
|
### Phase 2 완료 시
|
||||||
|
|
||||||
|
- [ ] 시스템 가동률: 99% 이상
|
||||||
|
- [ ] 알림 발송 성공률: 99.5% 이상
|
||||||
|
- [ ] 리포트 생성 시간: < 10초
|
||||||
|
- [ ] 대시보드 로딩 시간: < 2초
|
||||||
|
|
||||||
|
### Phase 3 완료 시
|
||||||
|
|
||||||
|
- [ ] 시스템 가동률: 99.9% 이상
|
||||||
|
- [ ] 감사 로그 무결성: 100%
|
||||||
|
- [ ] Paper Trading 정확도: 실거래 대비 ±0.5% 이내
|
||||||
|
- [ ] 보안 취약점: 0건 (Critical/High)
|
||||||
|
|
||||||
|
## 9. 관련 문서
|
||||||
|
|
||||||
|
- [시스템 개요](./01-overview.md)
|
||||||
|
- [전체 아키텍처](./02-architecture.md)
|
||||||
|
- [공통 데이터 모델](./03-data-models.md)
|
||||||
|
- [주요 워크플로우](./04-workflows.md)
|
||||||
|
|
||||||
|
### 구성요소 상세 문서
|
||||||
|
- [Phase 1 컴포넌트](../components/phase1/)
|
||||||
|
- [Phase 2 컴포넌트](../components/phase2/)
|
||||||
|
- [Phase 3 컴포넌트](../components/phase3/)
|
||||||
1855
specification.md
Normal file
1855
specification.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user