# Backtest Architecture

## 1. 목적

Phase 4의 백테스터는 **Phase 3에서 생성된 canonical feature dataset**을 입력으로 받아,
**event-driven continuation 전략**을 시뮬레이션하고, 포트폴리오/리스크 규칙을 반영한 뒤,
정량 결과와 리포트를 산출하는 엔진입니다.

이 엔진은 “가격만 넣고 대충 수익률 계산”하는 수준이 아니라, 다음을 반드시 만족해야 합니다.

- point-in-time only
- session-aware event alignment
- deterministic execution
- reproducible experiment runs
- 동일 전략을 다른 horizon / regime split에 재사용 가능

## 2. 입력 계층

백테스터 입력은 아래 5개 레이어로 나뉩니다.

### 2.1 Event snapshot

Phase 3의 `canonical_event_record` + feature snapshot.
필수 필드:

- `event_id`
- `symbol`
- `issuer_cik`
- `event_type`
- `event_timestamp_et`
- `availability_timestamp_et`
- `reaction_session_date`
- `entry_eligibility_date`
- `event_score_components`
- `attention_score_components`
- `final_candidate_score`

### 2.2 Market bars

일봉은 필수, 분봉은 선택입니다.
무료 데이터 제약상 v1의 기준 execution은 **next open / next close / stop-on-daily-bar approximation**입니다.
필수 필드:

- `trade_date`
- `symbol`
- `open`
- `high`
- `low`
- `close`
- `volume`
- `vwap_optional`
- `adjustment_factor`

### 2.3 Instrument master

필수 필드:

- `symbol`
- `asset_type`
- `listing_exchange`
- `sector`
- `industry`
- `is_tradable`
- `first_seen_date`
- `last_seen_date`

### 2.4 Regime data

필수 필드:

- `trade_date`
- `spy_trend_state`
- `qqq_trend_state`
- `vix_level`
- `macro_regime`

### 2.5 Experiment config

전략, risk model, sizing model, slippage model, universe filter를 정의하는 manifest.

## 3. 출력 계층

### 3.1 Trade blotter

모든 체결/부분청산/최종청산을 row-level로 저장합니다.
필수 필드:

- `run_id`
- `trade_id`
- `position_id`
- `symbol`
- `entry_date`
- `entry_price`
- `exit_date`
- `exit_price`
- `shares`
- `gross_pnl`
- `net_pnl`
- `exit_reason`
- `holding_days`

### 3.2 Position timeline

일자별 포지션 평가, 노출, MFE/MAE, stop distance.

### 3.3 Daily equity curve

일자별 자산곡선과 drawdown.

### 3.4 Metrics report

- CAGR-like annualized return
- average trade return
- expectancy
- hit rate
- payoff ratio
- max drawdown
- profit factor
- turnover
- avg holding period
- exposure
- sector concentration
- regime-by-regime performance

### 3.5 Attribution report

- by event type
- by guidance direction
- by sector
- by score bucket
- by attention overlay bucket

## 4. 서비스 경계

### 4.1 Snapshot reader

입력 데이터셋에서 **시점상 이용 가능한 feature만** 읽어옵니다.
이 계층은 절대 미래 row를 읽으면 안 됩니다.

### 4.2 Candidate selector

특정 날짜의 후보 종목을 정렬하고 상위 N개를 선택합니다.

### 4.3 Portfolio allocator

동시보유 수, 섹터 제한, 현금 제한, per-trade risk budget을 반영합니다.

### 4.4 Execution simulator

진입/청산 주문을 체결 가격으로 변환합니다.

### 4.5 Report writer

실험 결과를 표준 포맷으로 저장합니다.

## 5. 실행 흐름

```text
experiment manifest
→ dataset snapshot resolve
→ calendar iteration by trade date
→ candidate selection for date D
→ eligibility filter
→ ranking / tie-break
→ portfolio allocation
→ entry fill simulation
→ open position management
→ exit checks
→ pnl / exposure update
→ end-of-day ledger snapshot
→ final metrics / artifacts write
```

## 6. 날짜/시간 처리 원칙

### 6.1 세션 경계

- 미국 동부시간(ET) 기준으로 판단합니다.
- premarket / regular / after-hours를 구분합니다.
- event timestamp가 장후면 reaction session은 다음 거래일입니다.
- event timestamp가 장중이면 reaction session은 당일이지만, feature availability timestamp를 반드시 확인합니다.

### 6.2 entry eligibility

기본 전략은 **reaction day 종료 후 점수 확정 → 다음 거래일 진입**입니다.
따라서 entry date는 최소한 reaction day + 1 trading session입니다.

### 6.3 split/dividend adjustment

가격계열은 조정값을 명시적으로 사용합니다.
단, 체결 시뮬레이션과 리포트는 같은 조정 기준을 사용해야 합니다.

## 7. bias 방지 원칙

- future-adjusted universe 금지
- delisted symbol 제거 금지
- 나중에 정리된 event timestamp 사용 금지
- later corrected filing 내용으로 과거 시점 feature overwrite 금지
- final labels가 feature generation 단계에 들어가는 것 금지

## 8. backtest engine의 최소 클래스 경계

추천 Python 경계:

- `BacktestRunner`
- `MarketCalendar`
- `SnapshotStore`
- `CandidateSelector`
- `PortfolioAllocator`
- `ExecutionSimulator`
- `PositionManager`
- `MetricsEngine`
- `ArtifactWriter`

각 클래스는 side-effect를 최소화하고 deterministic 해야 합니다.
