# 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[주문 거부:
잔고 부족] CheckBalance -->|Yes| CheckSize CheckSize{포지션 사이즈
한도 내?} CheckSize -->|No| Reject2[주문 거부:
사이즈 초과] CheckSize -->|Yes| CheckConcentration CheckConcentration{집중도
한도 내?} CheckConcentration -->|No| Reject3[주문 거부:
집중도 초과] CheckConcentration -->|Yes| CalcVaR CalcVaR[VaR 계산] CalcVaR --> CheckVaR{VaR
한도 내?} CheckVaR -->|No| Warning1[경고 발생
계속 진행] CheckVaR -->|Yes| CheckDrawdown Warning1 --> CheckDrawdown CheckDrawdown{최대 낙폭
한도 내?} CheckDrawdown -->|No| Reject4[주문 거부:
MDD 초과] CheckDrawdown -->|Yes| CheckLeverage CheckLeverage{레버리지
한도 내?} CheckLeverage -->|No| Reject5[주문 거부:
레버리지 초과] CheckLeverage -->|Yes| Approve Approve([검증 통과:
주문 실행]) Reject1 --> Log[리스크 로그 기록] Reject2 --> Log Reject3 --> Log Reject4 --> Log Reject5 --> Log Approve --> ExecuteOrder[주문 제출] ExecuteOrder --> Monitor[실시간 모니터링] Monitor --> CheckStop{손절/익절
조건 충족?} 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 { // 주문 요약 생성 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 { // 1. 데이터 로드 const marketData = await data.getHistoricalPrices( config.universe, config.startDate, config.endDate ) // 2. 초기 상태 설정 let portfolio = { cash: config.initialCapital, positions: {} as Record, 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
실시간)] TimeSeries[(TimescaleDB
과거)] Metadata[(Metadata
종목 정보)] 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)