# ORB Gainers Strategy Development And Validation

이 문서는 현재 ORB 전략 중 `gainers_leader` 계열을 어떻게 개발하고 검증하는지 정리한 운영 문서다.

목표는 단순하다.

- `Yahoo Finance Top Gainers`처럼 당일 비정상 강세 종목을 시스템적으로 잡는다.
- 장 초반 ORB 구조를 쓰되, 실제 edge는 `압축 후 확장`이 아니라 `same-day attention / catalyst / abnormal volume`에서 찾는다.
- 연구 helper 결과와 공식 `run.py` 결과가 항상 같도록 검증한다.

이 문서는 “어떤 아이디어를 어떻게 실험하고”, “무엇을 official truth로 보고”, “어떤 함정을 피해야 하는지”를 남들이 그대로 따라할 수 있게 쓰였다.

## 1. 전략 의도

현재 `ORB Gainers`의 철학은 아래와 같다.

1. 당일 강한 종목을 찾는다.
   - 단순 compression setup보다 `당일 갭`, `초반 거래량`, `프리마켓 거래대금`이 중요하다.
2. 09:35 이후의 ORB 구조를 이용해 진입한다.
   - 첫 5분 봉 방향과 breakout 구조는 유지한다.
3. 같은 날 관심이 몰린 종목만 남긴다.
   - 명시적 뉴스 데이터가 없으므로 `premarket dollar volume`을 `same-day catalyst proxy`로 쓴다.
4. 검증은 `2026 Q1`을 1차 test window로 본다.
   - 이 기간은 최근 구조를 반영하면서도 30일보다 충분히 길다.

## 2. 현재 공식 전략

공식 전략 파일:

- [orb_gainers.yaml](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/intraday/strategies/orb_gainers.yaml)

현재 공식 파라미터의 핵심:

- `engine_family: gainers_leader`
- `entry_direction: long_only`
- `orb_minutes: 5`
- `sim_bar_minutes: 5`
- `order_timeout_minutes: 45`
- `min_price: 10`
- `min_avg_dollar_volume: 25,000,000`
- `min_atr_14: 0.50`
- `min_rvol: 1.2`
- `min_abs_gap_pct: 0.02`
- `min_premarket_dollar_vol: 1,500,000`
- `max_gap_pct: null`
- `max_candidates: 12`
- `max_candidates_per_sector: 2`
- `min_candidates_to_trade: 1`
- `weight_rvol/gap/dollar_vol/premarket = 0.40 / 0.20 / 0.05 / 0.35`
- `atr_stop_multiplier: 0.5`
- `breakeven_at_r: 1.0`
- `trailing_at_r: 3.0`
- `trailing_stop_atr_multiplier: 0.3`
- `compound_returns: false`

왜 이렇게 바뀌었는가:

- 예전 `compression_breakout`은 원래 의도와 맞지 않았다.
- `0.10 ATR` stop은 너무 타이트해서 거의 바로 stop-out 됐다.
- `premarket dollar volume`을 강하게 쓰는 것이 Q1에서 가장 잘 작동했다.

## 3. Source Of Truth

ORB 개발에서 source of truth는 아래 순서다.

1. 공식 전략 config
   - [orb_gainers.yaml](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/intraday/strategies/orb_gainers.yaml)
2. 공식 단일 백테스트 실행기
   - [apps/intraday_bt/run.py](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/intraday_bt/run.py)
3. 연구 helper / lab
   - [apps/intraday_bt/orb_research.py](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/intraday_bt/orb_research.py)
   - [apps/intraday_bt/lab.py](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/intraday_bt/lab.py)
4. 실험 결과물
   - `runs/intraday_orb/...`

중요:

- helper/lab은 빠른 연구용이다.
- 최종 성과와 전략 등록 판단은 반드시 `apps.intraday_bt.run`으로 다시 확인한다.

## 4. 현재 검증 기준

### Primary Test

현재 primary test window는:

- `2026-01-02 ~ 2026-03-31`

이 기간은 Q1 구간이며, 현재 ORB gainers 전략 개선은 이 구간을 기준으로 한다.

### Secondary Sanity Check

추가 sanity check는:

- `--days 30` 최근 30거래일

이유:

- Q1만 좋고 최근 30일에서 activity가 0이면 전략이 죽은 상태일 수 있다.
- 반대로 최근 30일만 좋고 Q1 전체가 약하면 과적합 가능성이 높다.

## 5. 현재 공식 성과

공식 `run.py` 기준 최신 결과:

### Q1 공식 검증

- 결과 파일:
  [intraday_20260415_204341_9d8e4fee.json](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/intraday_orb/intraday_20260415_204341_9d8e4fee.json)
- 기간:
  `2026-01-02 ~ 2026-03-31`
- 결과:
  - `+6.96%`
  - `407 trades`
  - `Sharpe 2.05`
  - `Max drawdown -3.92%`

### 최근 30일 공식 검증

- 결과 파일:
  [intraday_20260415_204456_60bdfe03.json](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/intraday_orb/intraday_20260415_204456_60bdfe03.json)
- 기간:
  `2026-03-04 ~ 2026-04-15`
- 결과:
  - `+4.05%`
  - `211 trades`
  - `Sharpe 2.15`
  - `30/30 days with trades`

## 6. 개발 루프

현재 ORB gainers 개발은 아래 순서로 한다.

### Step 1. 아이디어를 전략 언어로 번역

질문:

- “당일 리더를 찾는가?”
- “뉴스/촉매 proxy가 들어갔는가?”
- “큰 갭을 오히려 막고 있지 않은가?”
- “activity를 죽이는 규칙이 없는가?”

현재 유효했던 아이디어:

- `premarket dollar volume`을 `same-day catalyst proxy`로 사용
- `gap + rvol + premarket attention` 랭킹
- `0.5 ATR stop + 3R ATR trail`

### Step 2. Helper로 좁은 실험

빠른 실험은 `orb_research.py`의 research snapshot / tape cache를 재사용한다.

핵심은:

- full raw intraday를 매번 다시 읽지 않는다.
- 같은 Q1 구간을 여러 파라미터로 빠르게 비교한다.

최근 Q1 비교 결과 파일:

- [focus2](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/intraday_orb/lab/quick_real_202404_202603_gainers_q1_focus2.json)
- [focus3](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/intraday_orb/lab/quick_real_202404_202603_gainers_q1_focus3.json)
- [focus4](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/intraday_orb/lab/quick_real_202404_202603_gainers_q1_focus4.json)

이 단계의 목적은:

- 최고의 parameter cluster를 빠르게 찾는 것
- official result를 확정하는 것이 아님

### Step 3. Official `run.py` 재검증

helper에서 좋아 보여도 반드시 `run.py`로 다시 확인한다.

예시:

```bash
.venv/bin/python3 -m apps.intraday_bt.run \
  --config configs/intraday/strategies/orb_gainers.yaml \
  --start 2026-01-02 \
  --end 2026-03-31
```

최근 30일 sanity:

```bash
.venv/bin/python3 -m apps.intraday_bt.run \
  --config configs/intraday/strategies/orb_gainers.yaml \
  --days 30
```

### Step 4. 결과가 맞으면 config 업데이트

official result까지 확인된 뒤에만 전략 파일을 바꾼다.

## 7. 꼭 체크해야 할 함정

### 7.1 Helper와 `run.py` 결과가 다를 수 있다

실제로 한 번 발생했다.

원인:

- `run.py` 경로가 `ticker_sectors`를 ORB simulator에 넘기지 않아서
  `max_candidates_per_sector`가 공식 백테스트에서 무시되고 있었다.
- helper는 sector cap을 적용하고, official run은 적용하지 않아
  결과가 크게 어긋났다.

수정 위치:

- [apps/intraday_bt/run.py](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/intraday_bt/run.py)

원칙:

- helper에서 좋은 결과가 나오면 official run으로 trade count부터 먼저 맞춰본다.

### 7.2 `min_candidates_to_trade`는 activity를 쉽게 0으로 만든다

예전 compression 전략이 최근 30일 `0 trades`였던 직접 원인 중 하나다.

원칙:

- gainers 계열에서는 기본적으로 `min_candidates_to_trade = 1`부터 시작한다.

### 7.3 `max_gap_pct`는 gainers 전략과 상충할 수 있다

top gainers 전략은 본질적으로 큰 움직임을 잡는 전략이다.

원칙:

- gainers 계열에서는 `max_gap_pct`를 보통 `null`로 두고,
- 대신 `min_abs_gap_pct`와 `min_premarket_dollar_vol`로 품질을 걸러낸다.

### 7.4 `0.10 ATR` stop은 지나치게 타이트할 수 있다

실제 Q1 비교에서:

- `0.10 ATR`은 매우 나빴다.
- `0.50 ATR` 쪽이 명확히 우세했다.

원칙:

- gainers 계열은 `0.10 ATR`을 baseline으로 두지 않는다.

## 8. 어떤 축을 우선 튜닝할 것인가

가장 효율적인 튜닝 순서:

1. `min_premarket_dollar_vol`
2. ranking weights
   - `weight_rvol`
   - `weight_gap`
   - `weight_premarket_dollar_vol`
3. `atr_stop_multiplier`
4. `trailing_at_r`
5. `trailing_stop_atr_multiplier`
6. `max_candidates`
7. `max_candidates_per_sector`

현재까지는:

- `premarket dollar volume`이 가장 큰 설명력을 보였다.

## 9. Cache / Snapshot 구조

ORB 개발 속도를 위해 아래 캐시를 사용한다.

- raw daily cache:
  [data/cache/daily](/Users/yirugi/mycloud/personal/workspace/fithia2/data/cache/daily)
- raw intraday cache:
  [data/cache/intraday](/Users/yirugi/mycloud/personal/workspace/fithia2/data/cache/intraday)
- research snapshot:
  [data/cache/orb_research](/Users/yirugi/mycloud/personal/workspace/fithia2/data/cache/orb_research)
- period metrics cache:
  [data/cache/orb_eval](/Users/yirugi/mycloud/personal/workspace/fithia2/data/cache/orb_eval)
- prepared tape cache:
  [data/cache/orb_tape](/Users/yirugi/mycloud/personal/workspace/fithia2/data/cache/orb_tape)

운영 원칙:

- helper 실험은 snapshot/tape를 적극 활용한다.
- official truth는 여전히 `run.py` 결과다.

## 10. 권장 검증 명령

### 코드/회귀 검증

```bash
python -m py_compile \
  apps/intraday_bt/run.py \
  apps/intraday_bt/lab.py \
  libs/intraday/orb_simulator.py

pytest -q \
  tests/unit/intraday/test_run_helpers.py \
  tests/unit/intraday/test_orb_lab.py \
  tests/unit/intraday/test_orb_simulator.py
```

### Q1 공식 백테스트

```bash
.venv/bin/python3 -m apps.intraday_bt.run \
  --config configs/intraday/strategies/orb_gainers.yaml \
  --start 2026-01-02 \
  --end 2026-03-31
```

### 최근 30일 sanity

```bash
.venv/bin/python3 -m apps.intraday_bt.run \
  --config configs/intraday/strategies/orb_gainers.yaml \
  --days 30
```

### Quick lab

```bash
python -u -m apps.intraday_bt.lab \
  --config configs/intraday/strategies/orb_gainers.yaml \
  --quick \
  --beam-width 2 \
  --output-dir runs/intraday_orb/lab/quick_orb_gainers
```

주의:

- lab 결과가 좋으면 반드시 `run.py`로 다시 확인한다.

## 11. 다음 개발자가 해야 할 일

다음 사람이 이어받으면 아래 순서로 하면 된다.

1. 공식 config를 읽는다.
   - [orb_gainers.yaml](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/intraday/strategies/orb_gainers.yaml)
2. Q1 official run을 먼저 돌린다.
3. 최근 30일 sanity를 확인한다.
4. 개선 아이디어는 먼저 helper로 좁게 비교한다.
5. helper winner를 official `run.py`로 검증한다.
6. trade count / return / sharpe가 helper와 공식 run에서 비슷한지 확인한다.
7. 일치하면 config를 업데이트한다.

## 12. 현재 상태 요약

현재 결론은 이렇다.

- `compression`보다 `gainers_leader`가 전략 의도에 맞다.
- `premarket dollar volume`은 매우 중요한 품질 필터다.
- `0.5 ATR stop + 3R ATR trail`이 지금까지는 가장 실전적이다.
- helper와 official run 차이는 반드시 의심하고 검증해야 한다.
- 현재 공식 `ORB Gainers`는:
  - Q1 `+6.96%`
  - 최근 30일 `+4.05%`
  - activity도 충분히 나온다.
