You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5.5 KiB

Simulation Engine Design

1. 엔진 목적

이 엔진은 candidate snapshot을 받아 실제 포트폴리오 성과로 연결하는 시뮬레이터입니다. 핵심은 단순 수익률 계산이 아니라 거래 가능 시점, 포트폴리오 제약, 체결 근사, 청산 로직을 반영하는 것입니다.

2. 기본 실행 단위

기본 실행 단위는 거래일 단위입니다.

매 거래일마다 아래 순서를 수행합니다.

  1. 전일 종료 시점에 생성된 candidate 조회
  2. 당일 진입 가능한 종목만 필터링
  3. 포트폴리오 제약 반영 후 진입 대상 결정
  4. 당일 시초가 체결 시뮬레이션
  5. 기존 포지션에 대해 손절/익절/시간청산 평가
  6. 일말 평가금액, 노출, drawdown 갱신

3. signal 시점 정의

3.1 Event timestamp

문서가 실제 시장에 이용 가능해진 시점.

3.2 Availability timestamp

feature snapshot이 전략에 사용 가능한 시점. 예: reaction day 종가를 사용하는 전략이라면 availability는 reaction day close 이후입니다.

3.3 Decision date

전략이 매수 여부를 결정한 날짜.

3.4 Execution date

실제 진입을 시뮬레이션한 거래일. 기본값은 next open입니다.

4. 진입 로직

v1 기본 진입 규칙:

  • 후보는 decision_date = reaction_session_date
  • execution_date = next_trading_day
  • 진입 가격은 execution_date open
  • open이 없으면 거래정지/누락 처리 후 skip

4.1 ranking

  • final_candidate_score 내림차순
  • 동점이면 liquidity_score 우선
  • 그래도 동점이면 symbol 오름차순으로 deterministic tie-break

4.2 eligibility filters

  • 유니버스 필터 통과
  • 최소 가격 조건 통과
  • 유동성 조건 통과
  • 이미 동일 종목 포지션 보유 중이면 중복 진입 금지
  • 같은 issuer에 같은 이벤트 cluster 중복 진입 금지

5. 체결 근사 모델

5.1 Entry fill model

기본:

  • price = next session open
  • slippage = bps + liquidity penalty
  • actual fill = open * (1 + slippage_bps/10000)

롱 기준 slippage는 양수입니다.

5.2 Exit fill model

지원 exit types:

  • take profit partial
  • stop loss
  • trailing exit by previous day low breach (daily approximation)
  • time exit at close of holding day N
  • regime forced exit

5.3 Stop handling on daily bars

무료 데이터 제약상 intraday exact path는 없으므로, daily bar 기반 근사 원칙을 고정합니다.

권장 규칙:

  • stop price가 당일 low 이하이면 stop triggered로 간주
  • take-profit과 stop이 같은 날 동시에 충족되면 보수적 우선순위를 사용
  • 보수적 기본값: long position은 stop이 먼저 체결된 것으로 간주

이 우선순위는 config로 바꿀 수 있으나 기본값은 보수적으로 둡니다.

6. 포지션 생명주기

PLANNED
→ ENTERED
→ PARTIALLY_EXITED(optional)
→ OPEN
→ EXIT_PENDING(optional for close exits)
→ CLOSED
→ ARCHIVED

필수 상태 필드:

  • position_id
  • symbol
  • entry_date
  • entry_price
  • initial_stop
  • profit_target_1
  • current_stop
  • shares_open
  • days_held
  • exit_reason

7. 시간청산 규칙

기본 전략은 1~5일 보유를 전제로 하므로 아래 rule set을 지원합니다.

  • max_holding_days = 3 또는 5
  • close_on_day_n_close = true
  • weak_close_count_exit = 2 optional
  • no_follow_through_exit = true optional

v1에서는 필수 규칙을 최소화합니다.

8. partial exit 규칙

예시 기본값:

  • +1.5R 도달 시 50% 청산
  • 잔여분은 trailing rule 또는 time exit

partial exit는 일별 bar 근사로 구현합니다. 동일 bar에서 partial target과 stop이 동시에 걸릴 수 있으므로, 우선순위 규칙을 명시적으로 config화해야 합니다.

9. 수수료/슬리피지

무료 데이터 환경에서는 보수적인 비용 가정이 중요합니다.

기본 파라미터 예시:

  • commission_per_share = 0.0 또는 broker-specific
  • min_commission = 0
  • slippage_bps_base = 5
  • slippage_bps_low_liquidity_penalty = 5~20
  • gap risk adjustment optional

v1에서는 모델 복잡도보다 일관된 보수성이 중요합니다.

10. 누락/결측 처리

다음 상황에서는 기본적으로 no-trade 또는 forced skip입니다.

  • execution_date open missing
  • non-tradable flag
  • corporate action mismatch
  • feature snapshot missing critical field
  • duplicate event cluster

모든 skip은 이유 코드와 함께 로그/리포트에 남겨야 합니다.

11. 주요 함수 시그니처 권장안

run_experiment(manifest_path: str) -> ExperimentResult
load_snapshot(snapshot_id: str) -> SnapshotBundle
select_candidates(date: str, snapshot: SnapshotBundle, config: BacktestConfig) -> list[Candidate]
allocate_portfolio(date: str, candidates: list[Candidate], portfolio_state: PortfolioState, config: BacktestConfig) -> list[PlannedOrder]
simulate_entries(date: str, planned_orders: list[PlannedOrder], market_bars: MarketBars, config: BacktestConfig) -> list[FilledEntry]
update_positions(date: str, positions: list[OpenPosition], market_bars: MarketBars, config: BacktestConfig) -> PositionUpdateResult
compute_metrics(run_id: str, blotter: pd.DataFrame, equity_curve: pd.DataFrame) -> MetricsBundle

12. deterministic 요구사항

  • 동일 manifest + 동일 snapshot + 동일 코드 버전이면 결과가 같아야 합니다.
  • 랜덤 tie-break 금지
  • floating rounding 정책 고정
  • timezone handling 고정
  • price lookup fallback 순서 고정