Skip to content

App Architecture

JJong-03 edited this page Mar 13, 2026 · 6 revisions

애플리케이션 아키텍처 (App Architecture)

1. Evolution: Sync → Async

Phase 0 (Sync, Day 3)

Client → Web (Flask) → engine.py 직접 호출 → 동기 응답

Phase 3 (Async, Current)

Client → Web (Flask) → JobLauncher → K8s Job (Worker) → MySQL → Web (status polling)

전환의 핵심: 엔진 코드를 한 줄도 수정하지 않고 실행 모델만 교체했다.


2. Web↔Worker Responsibility Boundary

Responsibility Web (Flask Deployment) Worker (K8s Job)
Request validation, input sanitization O
run_id issuance (UUID4) O
PENDING insert to MySQL O
K8s Job 생성 (BatchV1Api) O
Backtest engine 실행 O
Adapter 파생 데이터 생성 (metrics, charts) O
Result persistence → MySQL O
RUNNING / SUCCEEDED / FAILED 상태 전이 O
Status/result 조회 (/status/<run_id>) O
성공 Job 삭제 O
Response rendering (JSON/HTML) O

Invariants:

  • Web은 stateless — 로컬 파일 I/O 없음, stdout/stderr 로깅만 사용
  • Worker는 ephemeral — 단일 백테스트 실행 후 종료. 재시도는 K8s backoffLimit로 관리
  • MySQL이 결과의 source of truth — Web과 Worker 모두 MySQL을 통해서만 결과를 교환

상태 전이 규칙 및 Job 생명주기 → Execution Lifecycle


3. JobLauncher Abstraction

                     ┌─ LocalSubprocessLauncher (dev/test)
JobLauncher (ABC) ───┤
                     └─ KubernetesJobLauncher (production)

환경변수 JOB_LAUNCHER_MODE로 전환:

  • local → subprocess 기반 mock (Docker/K8s 없이 로컬 테스트)
  • kuberneteskubernetes.client.BatchV1Api 호출

Why 추상화?

이유 설명
Testability 단위 테스트에서 K8s 의존성 없이 백테스트 파이프라인 전체를 검증 가능
Local/Cluster parity 개발자가 docker compose up으로 로컬에서 동일한 흐름을 실행
관심사 분리 Web은 "어떻게 실행하는가"를 몰라도 됨. launcher 교체만으로 실행 환경 전환

4. Module Structure

stock_backtest/
├── app.py              # Web 진입점 (Controller)
├── worker.py           # K8s Job Worker 진입점
├── extensions.py       # SQLAlchemy instance (순환 import 방지)
├── models.py           # ORM model (Strategy preset, BacktestResult)
├── adapters/
│   └── adapter.py      # Post-processing: 파생 metrics, charts 생성
├── backtest/
│   ├── engine.py       # Core engine (IMMUTABLE — 수정 금지)
│   └── metrics.py      # PerformanceMetrics
├── rules/              # Trading rule library
│   ├── base_rule.py    # BaseRule, Signal, RuleMetadata
│   └── technical_rules.py  # RSI, MACD, RSI+MACD, etc.
└── scripts/
    ├── config.py       # 환경변수 기반 설정
    └── logger_config.py # Structured logging (stdout/stderr)

5. Adapter Layer (Post-Processing)

Adapter는 엔진 출력으로부터 파생 데이터를 생성하는 계층이다. 엔진 코드를 수정하지 않고 UI에 필요한 추가 지표와 차트를 제공한다 (Rule 1 준수).

Adapter에서 허용되는 작업

  • equity_curve → drawdown_curve 유도
  • equity_curve + trades → portfolio_curve 유도
  • trades → win_rate, profit_factor, exposure_pct 계산
  • Matplotlib Agg → Base64 PNG 차트 생성
  • Timestamp ISO8601 포맷팅

Adapter에서 금지되는 작업

  • Signal 생성 로직 수정
  • Trade 실행 규칙 변경
  • 엔진 내부 공식(Sharpe, returns) 재계산

저장 vs 파생 경계 → Reproducibility


6. Strategy Presets vs Rules

혼동 방지를 위한 용어 정의:

개념 위치 역할
Rule rules/ 거래 로직 구현 (RSI, MACD 등). Immutable core의 일부.
Strategy Preset models.py (ORM) 사용자가 저장한 UI 파라미터 조합. 로직을 정의하지 않는다.
  • rule_type (예: "RSI") + params → 실행 로직을 결정
  • rule_id (예: "RSI_14_30_70") → 추적/로깅용 헬퍼 slug (실행에 영향 없음)

용어 상세 정의 → Glossary


7. Dependency Direction (모듈 의존 방향)

모듈 간 의존은 단방향이다. 하위 계층이 상위 계층을 import하지 않는다.

graph TD
    APP["app.py<br/>(Web Controller)"]
    WORKER["worker.py<br/>(Job Entrypoint)"]
    MODELS["models.py<br/>(ORM)"]
    EXT["extensions.py<br/>(SQLAlchemy instance)"]
    ADAPTER["adapters/adapter.py<br/>(Post-processing)"]
    ENGINE["backtest/engine.py<br/>(IMMUTABLE)"]
    RULES["rules/<br/>(Trading Rules)"]
    SCRIPTS["scripts/config.py<br/>scripts/logger_config.py"]

    APP --> MODELS
    APP --> ADAPTER
    APP --> EXT
    APP --> SCRIPTS
    WORKER --> ENGINE
    WORKER --> ADAPTER
    WORKER --> RULES
    WORKER --> SCRIPTS
    MODELS --> EXT
    ADAPTER --> ENGINE

    classDef immutable fill:#f5f5f5,stroke:#999,stroke-width:2px,stroke-dasharray: 5 5
    class ENGINE immutable
Loading

규칙:

  • app.pymodels, adapters, extensions 의존 허용
  • worker.pyengine, adapters, rules 의존 허용
  • models.pyextensions.py만 의존 (역방향 금지)
  • extensions.py어떤 모듈도 import하지 않음 — 순환 import 방지를 위한 독립 모듈
  • backtest/engine.py수정 금지 (Rule 1, 점선 표시)
  • adapters/engine 출력만 참조 (엔진 내부 로직 접근 금지)

See Also


Navigation

← Previous Archive Next →
Infra Architecture Home Execution-Lifecycle

Clone this wiki locally