Update tracker, leaderboard, docs, and overlay leaderboard
Additional tracker/leaderboard updates, overlay leaderboard, and documentation improvements. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>main
parent
2aba6418e6
commit
a81b3a6ac4
@ -0,0 +1,540 @@
|
||||
# Public SQS Calculation
|
||||
|
||||
이 문서는 tracker가 최종 public `SQS`를 어떻게 계산하는지, 그리고 왜
|
||||
split-only 점수와 final leaderboard 점수가 다를 수 있는지를 정리한다.
|
||||
|
||||
2026-03-26부터 기본 leaderboard는 **public `SQS v4`**를 쓴다.
|
||||
|
||||
- `SQS v4`: `SQS v3` + common-window capital-growth blend
|
||||
- `sqs_v3_score`: deployment/WFV-first primary rank
|
||||
- `stress_sqs_score`: 예전 public score. stress OOT quality를 추가 패널티로 곱한 legacy score
|
||||
- overlay entry는 split/WFV 기반 `SQS v4` 대신 **overlay 전용 official score**를 쓴다.
|
||||
|
||||
핵심 결론부터 말하면:
|
||||
|
||||
- `test split`만으로 나오는 `sqs_v2_score`는 final public `SQS`가 아니다.
|
||||
- final public `SQS v4`의 backbone은 아래 6개다.
|
||||
- `train` split
|
||||
- `valid` split
|
||||
- `test` split
|
||||
- walk-forward summary
|
||||
- main robustness summary
|
||||
- repaired out-of-time robustness summary
|
||||
- 여기에 comparable `common-window summary`가 있으면 `v4`가 계산되고,
|
||||
없으면 `v3`로 fallback된다.
|
||||
- 다만 `stress_sqs_score`도 같이 계산해 registry에 남긴다.
|
||||
|
||||
## 1. 어디서 계산되나
|
||||
|
||||
최종 public `SQS v4` 계산 진입점은
|
||||
[`compute_public_sqs`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L482)
|
||||
이고, 실제 계산은 [`compute_public_sqs_v4`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1180)가 한다.
|
||||
|
||||
legacy stress-adjusted score는
|
||||
[`compute_public_sqs_v2`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1067)
|
||||
가 그대로 유지한다.
|
||||
|
||||
`v4` backbone인 `v3` 계산은
|
||||
[`compute_public_sqs_v3`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1126)
|
||||
에 남아 있다.
|
||||
|
||||
public leaderboard / registry rebuild도 같은 함수를 쓴다:
|
||||
|
||||
- [`rebuild_registry`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1808)
|
||||
|
||||
즉, 수동 계산과 leaderboard 계산은 같은 코드 경로를 따라야 한다.
|
||||
|
||||
## 1.5 Overlay는 어떻게 공식 점수화되나
|
||||
|
||||
overlay는 train/valid/test/WFV 구조가 없으므로 single-book `SQS v4`를 그대로 쓸 수 없다.
|
||||
|
||||
대신 아래 두 summary를 붙여서 공식 점수를 계산한다.
|
||||
|
||||
- `overlay_common_window_summary`
|
||||
- `overlay_stress_window_summary`
|
||||
|
||||
계산 함수는:
|
||||
|
||||
- [`compute_overlay_public_sqs`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1356)
|
||||
- [`compute_overlay_stress_sqs`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1381)
|
||||
|
||||
공식 overlay 점수는:
|
||||
|
||||
```text
|
||||
overlay_window_score * overlay_stress_gate
|
||||
```
|
||||
|
||||
legacy overlay stress 점수는:
|
||||
|
||||
```text
|
||||
overlay_window_score * overlay_stress_gate * overlay_quality_factor
|
||||
```
|
||||
|
||||
즉 overlay도 stress window는 ranking 보조가 아니라 **공식 통과 게이트**에 가깝게 다룬다.
|
||||
|
||||
추가 원칙:
|
||||
|
||||
- overlay official score는 spec의 `books[].equity_csv`를 **frozen input**으로 본다.
|
||||
- [`fithia2 paper backtest --overlay`](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/paper_trader/cli.py)도 같은 frozen `equity_csv`를 우선 replay해야 한다.
|
||||
- 그래서 overlay leaderboard 숫자와 paper overlay 숫자가 다르면 먼저
|
||||
`equity_csv`, `regime_source`, `start_date`, `end_date`가 같은지 확인한다.
|
||||
- stress OOT overlay는 full-window csv를 재사용하면 안 된다.
|
||||
OOT 전용 `equity_csv`와 OOT snapshot `regime_source.snapshot_dir`를 같이 고정해야 한다.
|
||||
|
||||
## 2. 흔한 오해
|
||||
|
||||
### `sqs_v2_score`는 final public `SQS`가 아니다
|
||||
|
||||
`journal/improvement_journal.jsonl`에 들어가는 `sqs_v2_score`는
|
||||
`test split` 하나만 보고 계산한 split-level quality 점수다.
|
||||
|
||||
이 값은 아래 함수에서 나온다:
|
||||
|
||||
- [`compute_sqs_v2`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L178)
|
||||
|
||||
반면 final public `SQS v4`의 backbone인 `SQS v3`는:
|
||||
|
||||
- `RQS`
|
||||
- `WFQS v2`
|
||||
- deployment gate
|
||||
- main robustness gate
|
||||
- OOT robustness gate
|
||||
- OOT quality factor
|
||||
- activity factor
|
||||
|
||||
를 모두 반영한 값이다.
|
||||
|
||||
그래서 `sqs_v2_score=90.7`인데 public `SQS=54.7` 같은 일이 정상적으로 발생할 수 있다.
|
||||
|
||||
## 2.5 왜 `v3`로 바뀌었나
|
||||
|
||||
기존 public score는:
|
||||
|
||||
```text
|
||||
base_score * main_rb_gate * oot_gate * oot_quality_factor * activity_factor
|
||||
```
|
||||
|
||||
였다. 이 구조는 stress OOT를
|
||||
|
||||
- eligibility gate로 한 번 쓰고
|
||||
- quality penalty로 한 번 더 써서
|
||||
|
||||
최근/실전 적합도가 강한 전략을 과하게 깎을 수 있었다.
|
||||
|
||||
`SQS v3`는 다음처럼 바꿨다.
|
||||
|
||||
```text
|
||||
base_score * main_rb_gate * oot_gate * activity_factor
|
||||
```
|
||||
|
||||
즉 stress OOT는 **통과 여부를 확인하는 safety layer**로 남기고,
|
||||
연속 quality 패널티는 primary ranking에서 제거했다.
|
||||
|
||||
대신 예전 점수는 `stress_sqs_score`로 registry에 그대로 남긴다.
|
||||
|
||||
## 2.6 왜 `v4`로 바뀌었나
|
||||
|
||||
`v3`는 deployment/WFV/stress gate는 잘 반영했지만,
|
||||
연속 운용 구간에서의 복리 수익과 자본 효율을 직접 보지 못했다.
|
||||
|
||||
그래서 `v4`는 comparable common-window run이 있는 경우에 한해
|
||||
아래처럼 `v3`와 `common_window_score`를 섞는다.
|
||||
|
||||
```text
|
||||
final_v4 = v3_score * 0.80 + common_window_score * 0.20
|
||||
```
|
||||
|
||||
여기서 `common_window_score`는 같은 연속 기간, 같은 초기 자본으로 돌린 run의:
|
||||
|
||||
- total return
|
||||
- profit factor
|
||||
- Sharpe
|
||||
- max drawdown
|
||||
- return on gross exposure
|
||||
- capital velocity
|
||||
|
||||
를 합성한 값이다.
|
||||
|
||||
중요한 점:
|
||||
|
||||
- common-window summary가 없으면 `v4`는 억지 추정을 하지 않고 `v3`로 fallback한다.
|
||||
- 즉 현재 leaderboard는 `v4 + partial backfill`일 수 있다.
|
||||
- 상위권끼리 공정 비교하려면 같은 common-window가 붙어 있어야 한다.
|
||||
|
||||
### validation stack 중 하나라도 없으면 public `SQS`는 `None`
|
||||
|
||||
아래 세 개 중 하나라도 빠지면 public `SQS`는 계산되지 않는다.
|
||||
|
||||
- walk-forward
|
||||
- main robustness
|
||||
- out-of-time robustness
|
||||
|
||||
이 경우 함수는 숫자 대신 `None`을 주고, breakdown에 missing reason을 넣는다.
|
||||
|
||||
예:
|
||||
|
||||
```python
|
||||
score, breakdown, source = compute_public_sqs(...)
|
||||
# score == None
|
||||
# source == "pending_validation"
|
||||
# breakdown == {"requires_out_of_time_robustness": 1.0}
|
||||
```
|
||||
|
||||
## 3. 입력 산출물 경로
|
||||
|
||||
표준 경로는 아래다.
|
||||
|
||||
### Walk-Forward
|
||||
|
||||
[`runs/<experiment>_wfv/walk_forward/walk_forward_summary.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
|
||||
### Main Robustness
|
||||
|
||||
[`runs/<experiment>_rm/robustness_matrix/robustness_matrix_summary.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
|
||||
### OOT Robustness
|
||||
|
||||
[`runs/<experiment>_oot_rm/robustness_matrix/robustness_matrix_summary.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
|
||||
journal에 attach된 경우엔 file path가 없어도 journal entry만으로 rebuild가 가능하다.
|
||||
다만 디버그와 재현을 위해서는 run file도 남아 있는 쪽이 낫다.
|
||||
|
||||
## 4. 실제 계산 순서
|
||||
|
||||
public `SQS v4`는 아래 순서로 계산된다.
|
||||
|
||||
### 4.1 RQS 계산
|
||||
|
||||
split 3개에서
|
||||
[`compute_rqs`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L852)
|
||||
를 계산한다.
|
||||
|
||||
### 4.2 WFV 기반 `WFQS v2`
|
||||
|
||||
walk-forward summary에서
|
||||
[`compute_wfqs_v2`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L890)
|
||||
를 계산한다.
|
||||
|
||||
### 4.3 Deployment gate를 반영한 base score
|
||||
|
||||
코드 그대로 쓰면:
|
||||
|
||||
```text
|
||||
base_score = (RQS * 0.45 + WFQS_v2 * 0.55) * deployment_gate
|
||||
```
|
||||
|
||||
deployment gate는 아래 4개 통과 개수로 정해진다.
|
||||
|
||||
- WFV positive fold rate >= 70%
|
||||
- WFV median return >= 5%
|
||||
- WFV worst return >= -5%
|
||||
- WFV mean train-test gap <= 35%
|
||||
|
||||
통과 개수별 factor:
|
||||
|
||||
- 4개: `1.00`
|
||||
- 3개: `0.85`
|
||||
- 2개: `0.65`
|
||||
- 1개: `0.40`
|
||||
- 0개: `0.20`
|
||||
|
||||
### 4.4 Main robustness gate
|
||||
|
||||
[`compute_robustness_gate`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1124)
|
||||
를 곱한다.
|
||||
|
||||
기준:
|
||||
|
||||
- overall positive window rate >= 65%
|
||||
- 63d median >= 3%
|
||||
- 252d median >= 8%
|
||||
- overall worst return >= -12%
|
||||
|
||||
factor는 deployment gate와 같은 `1.00 / 0.85 / 0.65 / 0.40 / 0.20` 구조다.
|
||||
|
||||
### 4.5 OOT robustness gate
|
||||
|
||||
[`compute_oot_robustness_gate`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1175)
|
||||
를 곱한다.
|
||||
|
||||
OOT는 스트레스 테스트라 threshold가 조금 느슨하다.
|
||||
|
||||
- 63d+ positive rate >= 50%
|
||||
- 63d median >= 0.5%
|
||||
- 252d median >= 3%
|
||||
- worst return >= -15%
|
||||
|
||||
### 4.6 OOT quality는 보조지표
|
||||
|
||||
[`compute_oot_robustness_quality`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1261)
|
||||
로 `0~100` quality를 계산한다.
|
||||
|
||||
`SQS v3`/`v4`에서는 이 값을 **랭킹 점수에 곱하지 않는다.**
|
||||
대신 registry breakdown과 `stress_sqs_score`에서만 사용한다.
|
||||
|
||||
### 4.7 Activity factor
|
||||
|
||||
마지막으로
|
||||
[`_public_activity_factor`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L658)
|
||||
를 곱한다.
|
||||
|
||||
이 단계 때문에:
|
||||
|
||||
- replacement 전략
|
||||
- 지나치게 trade 수가 적은 rotation 전략
|
||||
|
||||
은 split/WFV가 좋아도 public 점수가 낮아질 수 있다.
|
||||
|
||||
### 4.8 Common-window blend
|
||||
|
||||
common-window summary가 있으면
|
||||
[`compute_common_window_score`](/Users/yirugi/mycloud/personal/workspace/fithia2/libs/backtest/tracker.py#L1278)
|
||||
로 capital-growth score를 계산한 뒤:
|
||||
|
||||
```text
|
||||
final_v4 = v3_score * 0.80 + common_window_score * 0.20
|
||||
```
|
||||
|
||||
를 적용한다.
|
||||
|
||||
common-window summary가 없으면:
|
||||
|
||||
- final score는 `v3_score`
|
||||
- source는 `v4_fallback_v3_missing_common_window`
|
||||
|
||||
으로 남는다.
|
||||
|
||||
## 5. `return_max_long_v6new.29` / `v6new.28` 같은 사례를 어떻게 읽어야 하나
|
||||
|
||||
`v6new.29`는 split/WFV/deployment도 강하고,
|
||||
common-window capital-growth가 특히 강한 전형적인 케이스다.
|
||||
|
||||
- `SQS v4`에서는 이 전략이 더 높은 순위를 받는다.
|
||||
- `stress_sqs_score`는 여전히 낮아서 stress 취약성은 숨겨지지 않는다.
|
||||
|
||||
`v6new.28`은 다른 방향의 예시다.
|
||||
|
||||
### 5.1 왜 헷갈렸나
|
||||
|
||||
journal에는 아래 값이 이미 있었다.
|
||||
|
||||
- `sqs_v2_score = 90.7`
|
||||
- `rqs_score = 83.5`
|
||||
- `wfqs_v2_score = 48.6`
|
||||
|
||||
그런데 final public `SQS`는 비어 있었다.
|
||||
|
||||
이유는 간단했다.
|
||||
|
||||
- walk-forward 있음
|
||||
- main robustness 있음
|
||||
- OOT robustness 없음
|
||||
|
||||
즉 tracker 기준으로는 아직 `pending_validation`이었다.
|
||||
|
||||
실제로:
|
||||
|
||||
```python
|
||||
score, breakdown, source = compute_public_sqs(...)
|
||||
```
|
||||
|
||||
결과는:
|
||||
|
||||
- `score = None`
|
||||
- `source = "pending_validation"`
|
||||
- `breakdown = {"requires_out_of_time_robustness": 1.0}`
|
||||
|
||||
였다.
|
||||
|
||||
### 5.2 OOT를 붙인 뒤 최종 계산
|
||||
|
||||
OOT run:
|
||||
|
||||
- [robustness_matrix_summary.json](/Users/yirugi/mycloud/personal/workspace/fithia2/runs/return_max_long_v6new.28_oot_rm/robustness_matrix/robustness_matrix_summary.json)
|
||||
|
||||
OOT 주요 수치:
|
||||
|
||||
- overall positive `90.0%`
|
||||
- overall worst `-4.59%`
|
||||
- `63d median 11.8%`
|
||||
- `252d median 72.07%`
|
||||
|
||||
최종 계산 결과:
|
||||
|
||||
- `RQS = 83.5`
|
||||
- `WFQS v2 = 48.6`
|
||||
- public `SQS = 54.7`
|
||||
- source = `v2_deployment+robustness+oot`
|
||||
|
||||
이 케이스에서는:
|
||||
|
||||
- deployment gate = `0.85`
|
||||
- main robustness gate = `1.0`
|
||||
- OOT gate = `1.0`
|
||||
- OOT quality factor = `1.0`
|
||||
- activity factor = `1.0`
|
||||
|
||||
라서 실질적으로:
|
||||
|
||||
```text
|
||||
base_score = (83.5 * 0.45 + 48.6 * 0.55) * 0.85 = 54.7
|
||||
final_public_sqs = 54.7
|
||||
```
|
||||
|
||||
즉 `90.7`이 틀린 값이 아니라,
|
||||
**그 값은 public `SQS`가 아니라 split-only `sqs_v2_score`였다**가 정확한 설명이다.
|
||||
|
||||
## 6. 권장 계산 절차
|
||||
|
||||
### 6.1 validation run 만들기
|
||||
|
||||
```bash
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--walk-forward \
|
||||
--wf-train-days 504 \
|
||||
--wf-test-days 63 \
|
||||
--wf-step-days 63 \
|
||||
--output-root runs/<experiment>_wfv
|
||||
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--robustness-matrix \
|
||||
--rm-horizons 21,63,126,252,504 \
|
||||
--rm-step-days 21 \
|
||||
--output-root runs/<experiment>_rm
|
||||
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--snapshot-id <oot_snapshot_id> \
|
||||
--robustness-matrix \
|
||||
--rm-horizons 21,63,126,252 \
|
||||
--rm-step-days 21 \
|
||||
--output-root runs/<experiment>_oot_rm
|
||||
```
|
||||
|
||||
### 6.2 journal에 attach
|
||||
|
||||
```bash
|
||||
python apps/tracker/cli.py attach-wfv \
|
||||
--journal-dir journal \
|
||||
<experiment> \
|
||||
--summary runs/<experiment>_wfv/walk_forward/walk_forward_summary.json
|
||||
|
||||
python apps/tracker/cli.py attach-robustness \
|
||||
--journal-dir journal \
|
||||
<experiment> \
|
||||
--summary runs/<experiment>_rm/robustness_matrix/robustness_matrix_summary.json
|
||||
|
||||
python apps/tracker/cli.py attach-oot-robustness \
|
||||
--journal-dir journal \
|
||||
<experiment> \
|
||||
--summary runs/<experiment>_oot_rm/robustness_matrix/robustness_matrix_summary.json
|
||||
```
|
||||
|
||||
### 6.3 Python으로 직접 계산
|
||||
|
||||
```python
|
||||
import json
|
||||
from pathlib import Path
|
||||
from libs.backtest.domain import SplitResult, WalkForwardSummary, RobustnessMatrixSummary
|
||||
from libs.backtest.tracker import compute_public_sqs
|
||||
|
||||
entry = ... # journal entry dict
|
||||
|
||||
train = SplitResult(**entry["results"]["train"])
|
||||
valid = SplitResult(**entry["results"]["valid"])
|
||||
test = SplitResult(**entry["results"]["test"])
|
||||
wfv = WalkForwardSummary(**entry["walk_forward_summary"])
|
||||
rm = RobustnessMatrixSummary(**entry["robustness_matrix_summary"])
|
||||
oot = RobustnessMatrixSummary(**entry["out_of_time_robustness_summary"])
|
||||
|
||||
score, breakdown, source = compute_public_sqs(
|
||||
train,
|
||||
valid,
|
||||
test,
|
||||
walk_forward_summary=wfv,
|
||||
robustness_matrix_summary=rm,
|
||||
out_of_time_robustness_summary=oot,
|
||||
)
|
||||
print(score, source, breakdown)
|
||||
```
|
||||
|
||||
### 6.4 Common-window attach
|
||||
|
||||
common-window는 같은 기간과 같은 초기 자본으로 맞춰서 별도로 붙인다.
|
||||
|
||||
권장 원칙:
|
||||
|
||||
- contenders끼리는 같은 `start_date / end_date`를 쓴다
|
||||
- initial equity도 같게 맞춘다
|
||||
- partial backfill 상태에선 `v4`와 `v3 fallback`이 섞일 수 있음을 인지한다
|
||||
|
||||
attach는 tracker CLI 또는 Python helper로 한다.
|
||||
요약만 붙어 있으면 registry rebuild가 가능하다.
|
||||
|
||||
## 7. 디버그 체크리스트
|
||||
|
||||
### score가 `None`이면
|
||||
|
||||
아래를 먼저 본다.
|
||||
|
||||
- `walk_forward_summary` 존재 여부
|
||||
- `robustness_matrix_summary` 존재 여부
|
||||
- `out_of_time_robustness_summary` 존재 여부
|
||||
|
||||
### `sqs_v2_score`는 큰데 public `SQS`가 낮으면
|
||||
|
||||
아래를 본다.
|
||||
|
||||
- `wfqs_v2_score`
|
||||
- deployment gate
|
||||
- robustness gate
|
||||
- OOT gate / OOT quality factor
|
||||
- activity factor
|
||||
- common-window summary 존재 여부와 comparable window 설정
|
||||
|
||||
특히 rotation / low-activity 전략은 activity factor 때문에 public 점수가 크게 깎일 수 있다.
|
||||
|
||||
반대로 연속 구간 복리 수익이 강한 전략은 `v4` common-window가 붙으면 더 올라갈 수 있다.
|
||||
|
||||
### registry와 수동 계산이 다르면
|
||||
|
||||
아래를 본다.
|
||||
|
||||
- journal entry에 attach가 실제로 되었는가
|
||||
- registry가 rebuild 되었는가
|
||||
- 같은 experiment 이름의 중복 journal entry 중 최신 exact match가 선택되었는가
|
||||
- common-window가 일부 전략에만 backfill된 partial 상태가 아닌가
|
||||
|
||||
### run 숫자가 leaderboard/journal과 다르면
|
||||
|
||||
점수 계산식보다 먼저 snapshot provenance를 본다.
|
||||
|
||||
- run dir의 [`snapshot_manifest.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
- run dir의 [`snapshot_fingerprint.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
- `snapshot_manifest.json`의 `export_enrichments`가 다르면 같은 snapshot id 계열이라도 직접 비교 대상으로 섞지 않는다.
|
||||
|
||||
여기서 특히 아래를 본다.
|
||||
|
||||
- `dataset_snapshot_id`
|
||||
- `source_manifest_path`
|
||||
- `snapshot_dir_name`
|
||||
- `manifest_snapshot_id`
|
||||
- `snapshot_id_matches_manifest`
|
||||
- `output_dir_matches_manifest`
|
||||
|
||||
둘 중 하나라도 `false`면,
|
||||
같은 snapshot id 아래 다른 내용이 덮어써졌거나 잘못 복사된 manifest일 수 있다.
|
||||
이 경우 점수 비교 전에 snapshot provenance부터 정리해야 한다.
|
||||
|
||||
## 8. 운영 원칙
|
||||
|
||||
- split-only `sqs_v2_score`를 final public `SQS`로 말하지 않는다.
|
||||
- leaderboard 숫자는 반드시 `compute_public_sqs()` 경로로만 확인한다.
|
||||
- OOT가 빠진 후보는 “점수 미계산”이지 “점수 0”이 아니다.
|
||||
- journal과 registry가 다르면 journal + tracker 함수가 source of truth다.
|
||||
- `v4` 비교는 comparable common-window가 붙은 후보끼리 우선 본다.
|
||||
@ -0,0 +1,422 @@
|
||||
# Strategy Research Workflow And Handoff
|
||||
|
||||
이 문서는 `return-max long` 전략 연구를 여러 AI 에이전트가 이어서 하더라도
|
||||
같은 실수를 반복하지 않도록 하기 위한 운영 기준이다.
|
||||
|
||||
가장 중요한 배경은 과거 `v797_v793_epam_rklb_alk_combo` 누락 사례와,
|
||||
그 뒤에 드러난 `disabled named micro contamination`, `repaired OOT snapshot` 문제다.
|
||||
이 문서는 그런 실수와 재오염을 다시 만들지 않기 위한 운영 규칙을 정의한다.
|
||||
|
||||
## 1. Source Of Truth
|
||||
|
||||
전략 연구의 source of truth는 아래 순서로 본다.
|
||||
|
||||
1. [`configs/experiments`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments)
|
||||
2. [`journal/improvement_journal.jsonl`](/Users/yirugi/mycloud/personal/workspace/fithia2/journal/improvement_journal.jsonl)
|
||||
3. [`journal/experiment_registry.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/journal/experiment_registry.json)
|
||||
4. [`runs/`](/Users/yirugi/mycloud/personal/workspace/fithia2/runs)
|
||||
|
||||
원칙:
|
||||
|
||||
- `runs/`는 실험 산출물 저장소다. 단독으로는 정식 전략 정의가 아니다.
|
||||
- `journal`은 평가 기록이다. 정식 전략 정의를 대신하지 않는다.
|
||||
- 실제로 다시 돌릴 수 있는 전략 정의는 반드시 `configs/experiments/*.json`에 있어야 한다.
|
||||
- run 비교가 안 맞으면 `runs/<run_id>/snapshot_manifest.json`, `snapshot_fingerprint.json`을 먼저 본다.
|
||||
- `snapshot_manifest.json`의 `export_enrichments`가 다르면 같은 base snapshot name이라도 다른 dataset으로 본다.
|
||||
|
||||
## 2. 용어 정의
|
||||
|
||||
### Scratch Candidate
|
||||
|
||||
임시 탐색용 manifest.
|
||||
|
||||
- `/tmp/*.json` 또는 배치용 임시 경로에 둘 수 있다.
|
||||
- 빠른 조합 탐색과 train scan에는 허용한다.
|
||||
- 이 상태로는 leaderboard/journal의 최종 후보가 될 수 없다.
|
||||
|
||||
### Official Experiment
|
||||
|
||||
정식 manifest가 있고 full-split 결과까지 있는 실험.
|
||||
|
||||
필수 조건:
|
||||
|
||||
1. [`configs/experiments`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments)에 `.json` 파일이 있다.
|
||||
2. 파일명 stem과 `experiment_name`이 같다.
|
||||
3. `train / valid / test` full split 결과가 있다.
|
||||
4. journal entry가 있다.
|
||||
|
||||
### Deploy Candidate
|
||||
|
||||
실전 승격을 검토할 수 있는 실험.
|
||||
|
||||
Official Experiment 조건에 더해:
|
||||
|
||||
1. walk-forward summary가 있다.
|
||||
2. robustness matrix summary가 있다.
|
||||
3. repaired out-of-time robustness summary가 있다.
|
||||
4. public `SQS`가 계산돼 있다.
|
||||
|
||||
### Archived Overfit Branch
|
||||
|
||||
다음 조건 중 하나라도 만족하면 기본 workflow에서 archive 대상으로 본다.
|
||||
|
||||
- manifest의 `strategy_engines[].engine_id` 중 하나라도 `exact`를 포함
|
||||
- manifest에 named micro engine이 존재함
|
||||
- `enabled: false`여도 contamination으로 본다.
|
||||
- symbol/date-specific pocket을 누적해 funded trade set을 직접 외우는 구조
|
||||
|
||||
이 계열은 연구 참고용으로만 남기고, 기본 leaderboard와 실전 후보군에서는 제외한다.
|
||||
|
||||
## 2.1 버전 규칙
|
||||
|
||||
- 기존 `return_max_long_v326` 같은 historical 전략은 **의미상 `v0.326`** 으로 취급한다.
|
||||
- 과거 journal/manifest 파일명을 전부 물리적으로 바꾸지는 않는다. 재현성과 참조 무결성 때문이다.
|
||||
- 새 clean lineage는 **`v1.1`부터 시작**한다.
|
||||
- lineage 시작점은 `v1.1`이지만, 문서 작성 시점의 active clean baseline은
|
||||
[`return_max_long_v1.51.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.51.json) 이다.
|
||||
- 이후 새 실험은 `v1.52`, `v1.53` 식으로 올린다.
|
||||
|
||||
## 3. 정식 승격 기준
|
||||
|
||||
다음 중 하나에 해당하면 scratch를 official로 승격한다.
|
||||
|
||||
- full-split에서 현재 baseline을 이겼다.
|
||||
- leaderboard에 올릴 가치가 있다.
|
||||
- 다음 세션에서도 다시 이어서 연구할 가능성이 높다.
|
||||
- WFV/robustness까지 붙일 대상이다.
|
||||
|
||||
즉, "의미 있는 winner"는 반드시 repo manifest로 옮긴다.
|
||||
|
||||
## 4. 금지 규칙
|
||||
|
||||
아래는 금지한다.
|
||||
|
||||
- scratch manifest 상태로 journal만 기록하는 것
|
||||
- `experiment_name`과 다른 파일명으로 공식 manifest를 저장하는 것
|
||||
- leaderboard 상위 전략이 `configs/experiments`에 없는 상태로 남는 것
|
||||
- WFV/robustness가 붙은 전략의 summary 경로를 journal에 연결하지 않는 것
|
||||
|
||||
## 5. 표준 연구 흐름
|
||||
|
||||
현재 active clean baseline은 [`return_max_long_v1.51.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.51.json) 이다.
|
||||
이 전략은 old `v1.12` 계열에서 disabled named micro를 물리적으로 제거한 clean replacement다.
|
||||
즉, 지금부터의 baseline 해석은 "계보의 시작"과 "현재 active baseline"을 구분해야 한다.
|
||||
|
||||
### Step 1. Baseline 선택
|
||||
|
||||
- 기준 전략은 반드시 [`configs/experiments`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments) 안의 manifest여야 한다.
|
||||
- baseline 이름은 journal entry와 동일하게 사용한다.
|
||||
- paper backtest와 research backtester는 같은 snapshot을 써야 비교가 된다.
|
||||
경로 해석 우선순위는 `settings.parquet_dir` 다음 `data/datasets/snapshots`다.
|
||||
|
||||
### Step 2. Scratch 탐색
|
||||
|
||||
- `/tmp`에 scratch manifest를 만들고 배치 탐색을 돌릴 수 있다.
|
||||
- 이 단계에서는 train-only scan이나 fast full-split batch를 허용한다.
|
||||
- 아직 journal 최종 기록 대상은 아니다.
|
||||
|
||||
### Step 3. Winner 확정
|
||||
|
||||
scratch 후보가 baseline을 이기면 먼저 repo에 정식 manifest를 만든다.
|
||||
|
||||
권장 순서:
|
||||
|
||||
1. `configs/experiments/<experiment_name>.json` 생성
|
||||
2. 해당 파일로 다시 full split 실행
|
||||
3. 그 뒤에 journal 기록
|
||||
|
||||
### Step 4. Journal 기록
|
||||
|
||||
정식 manifest 기준으로만 기록한다.
|
||||
|
||||
필수 확인:
|
||||
|
||||
- `experiment_name == manifest filename stem`
|
||||
- `train / valid / test` 결과가 모두 존재
|
||||
- hypothesis / config_delta / verdict가 비어 있지 않음
|
||||
|
||||
### Step 5. WFV / Robustness
|
||||
|
||||
deploy 후보는 아래를 붙인다.
|
||||
|
||||
- walk-forward validation
|
||||
- robustness matrix
|
||||
- repaired out-of-time robustness
|
||||
- 현재 기준 snapshot은
|
||||
[`midlarge-liquid-long-v1-oot-2020-2021`](/Users/yirugi/mycloud/personal/workspace/fithia2/data/datasets/snapshots/midlarge-liquid-long-v1-oot-2020-2021/manifest.json)
|
||||
|
||||
그리고 tracker에 attach한다.
|
||||
|
||||
### Step 6. Leaderboard 갱신
|
||||
|
||||
정식 manifest + journal + WFV/robustness attach까지 끝난 뒤에 leaderboard를 본다.
|
||||
|
||||
public `SQS` 계산 상세와 디버그 절차는
|
||||
[`docs/public_sqs_calculation.md`](/Users/yirugi/mycloud/personal/workspace/fithia2/docs/public_sqs_calculation.md)
|
||||
를 본다.
|
||||
|
||||
## 6. 세션 종료 전 체크리스트
|
||||
|
||||
세션을 끝내기 전에 아래를 확인한다.
|
||||
|
||||
1. 오늘 새 winner가 scratch만 있고 repo manifest가 없는가
|
||||
2. journal에 기록한 실험명이 실제 `configs/experiments/<name>.json`과 대응하는가
|
||||
3. deploy 후보인데 WFV/robustness attach가 빠진 것이 없는가
|
||||
4. deploy 후보인데 repaired OOT attach가 빠진 것이 없는가
|
||||
5. leaderboard 상단 전략 중 repo manifest가 없는 것이 없는가
|
||||
6. default leaderboard에 named micro manifest가 보이지 않는가
|
||||
7. 새로 만든 run의 `snapshot_fingerprint.json`에서 manifest mismatch가 없는가
|
||||
|
||||
하나라도 `yes`면 세션 종료 전에 정리한다.
|
||||
|
||||
## 7. 권장 명령 흐름
|
||||
|
||||
### Full Split
|
||||
|
||||
```bash
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--output-root runs/<experiment>_fullsplit
|
||||
```
|
||||
|
||||
### Walk-Forward
|
||||
|
||||
```bash
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--walk-forward \
|
||||
--wf-train-days 504 \
|
||||
--wf-test-days 63 \
|
||||
--wf-step-days 63 \
|
||||
--output-root runs/<experiment>_wfv
|
||||
```
|
||||
|
||||
### Robustness Matrix
|
||||
|
||||
```bash
|
||||
python apps/backtester/run.py \
|
||||
--manifest configs/experiments/<experiment>.json \
|
||||
--snapshot-dir data/datasets/snapshots \
|
||||
--robustness-matrix \
|
||||
--rm-horizons 21,63,126,252,504 \
|
||||
--rm-step-days 21 \
|
||||
--output-root runs/<experiment>_rm
|
||||
```
|
||||
|
||||
### Attach Summaries
|
||||
|
||||
```bash
|
||||
python apps/tracker/cli.py attach-wfv \
|
||||
--journal-dir journal \
|
||||
<experiment_name> \
|
||||
--summary runs/<experiment>_wfv/walk_forward/walk_forward_summary.json
|
||||
|
||||
python apps/tracker/cli.py attach-robustness \
|
||||
--journal-dir journal \
|
||||
<experiment_name> \
|
||||
--summary runs/<experiment>_rm/robustness_matrix/robustness_matrix_summary.json
|
||||
|
||||
python apps/tracker/cli.py attach-oot-robustness \
|
||||
--journal-dir journal \
|
||||
<experiment_name> \
|
||||
--summary runs/<experiment>_oot_rm/robustness_matrix/robustness_matrix_summary.json
|
||||
```
|
||||
|
||||
### Book Overlay Evaluation
|
||||
|
||||
single-book manifest를 억지로 섞지 말고, 별도 book을 각각 먼저 고정 기간으로 돌린 뒤
|
||||
overlay를 따로 평가한다.
|
||||
|
||||
1. 같은 기간, 같은 초기 자본으로 각 book의 equity curve를 만든다.
|
||||
2. [`configs/overlays`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/overlays) 아래 spec에
|
||||
regime별 자본 배분을 적는다.
|
||||
3. [`apps/tools/evaluate_book_overlay.py`](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/tools/evaluate_book_overlay.py)로
|
||||
overlay equity와 summary를 만든다.
|
||||
4. full-window spec/summary와 stress-window spec/summary를 모두 만든 뒤
|
||||
[`apps/tracker/cli.py`](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/tracker/cli.py)
|
||||
`record-overlay`로 공식 journal/leaderboard에 등록한다.
|
||||
|
||||
주의:
|
||||
|
||||
- overlay spec의 `books[].equity_csv`는 **재현 기준 입력**이다.
|
||||
- 공식 평가와 [`fithia2 paper backtest --overlay`](/Users/yirugi/mycloud/personal/workspace/fithia2/apps/paper_trader/cli.py)는
|
||||
둘 다 이 frozen curve를 우선 replay해야 한다.
|
||||
- OOT overlay는 full-window csv를 재사용하면 안 된다.
|
||||
`runs/book_overlay_oot_inputs/...`처럼 OOT 전용 book curve를 따로 만든다.
|
||||
- `regime_source.snapshot_dir`가 explicit snapshot directory라면 evaluator는 그 디렉터리를 그대로 merged load해야 한다.
|
||||
|
||||
예시:
|
||||
|
||||
```bash
|
||||
fithia2 paper backtest \
|
||||
--config configs/experiments/return_max_long_v6.221.json \
|
||||
--config configs/experiments/return_max_long_v6new.54.json \
|
||||
--capital 10000 \
|
||||
--start 2022-03-03 \
|
||||
--end 2026-03-13 \
|
||||
--output runs/book_overlay_v1_inputs \
|
||||
--no-trades
|
||||
|
||||
python apps/tools/evaluate_book_overlay.py \
|
||||
--spec configs/overlays/return_book_overlay_v1.json \
|
||||
--output-dir runs/return_book_overlay_v1_eval
|
||||
|
||||
python apps/tracker/cli.py record-overlay \
|
||||
--spec configs/overlays/return_book_overlay_v3.json \
|
||||
--summary runs/return_book_overlay_v3_eval/overlay_summary.json \
|
||||
--stress-spec configs/overlays/return_book_overlay_v3_oot.json \
|
||||
--stress-summary runs/return_book_overlay_v3_oot_eval/overlay_summary.json \
|
||||
--hypothesis "Official overlay candidate"
|
||||
```
|
||||
|
||||
## 8. 빠른 무결성 점검
|
||||
|
||||
journal entry와 manifest 대응을 확인하려면:
|
||||
|
||||
```bash
|
||||
python - <<'PY'
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
cfg = Path("configs/experiments")
|
||||
missing = []
|
||||
for line in Path("journal/improvement_journal.jsonl").read_text().splitlines():
|
||||
if not line.strip():
|
||||
continue
|
||||
obj = json.loads(line)
|
||||
name = obj.get("experiment_name")
|
||||
if name and not (cfg / f"{name}.json").exists():
|
||||
missing.append(name)
|
||||
|
||||
print("missing", len(missing))
|
||||
for name in missing[-20:]:
|
||||
print(name)
|
||||
PY
|
||||
```
|
||||
|
||||
이 출력은 항상 `0`이어야 한다.
|
||||
|
||||
### Snapshot Provenance 점검
|
||||
|
||||
run 결과가 journal/leaderboard 숫자와 다르면 아래 두 파일을 먼저 본다.
|
||||
|
||||
- `runs/<run_id>/snapshot_manifest.json`
|
||||
- `runs/<run_id>/snapshot_fingerprint.json`
|
||||
- 특히 `snapshot_manifest.json`의 `feature_version`, `export_enrichments`, `created_at_utc`를 같이 본다.
|
||||
|
||||
핵심 필드:
|
||||
|
||||
- `dataset_snapshot_id`
|
||||
- `source_manifest_path`
|
||||
- `snapshot_dir_name`
|
||||
- `manifest_snapshot_id`
|
||||
- `snapshot_id_matches_manifest`
|
||||
- `output_dir_matches_manifest`
|
||||
|
||||
`snapshot_id_matches_manifest=false` 또는 `output_dir_matches_manifest=false`면
|
||||
같은 snapshot id 아래 다른 내용이 덮어써졌거나, 잘못 복사된 manifest일 수 있다.
|
||||
이 상태에서 성능 비교를 계속하면 안 된다.
|
||||
|
||||
## 9. 다른 에이전트에게 넘길 때 남겨야 할 것
|
||||
|
||||
handoff에는 최소 아래를 포함한다.
|
||||
|
||||
- 현재 active baseline manifest 경로
|
||||
- 현재 raw-return winner와 deploy winner
|
||||
- 마지막으로 유효했던 개선 축
|
||||
- 실패한 축 3~5개
|
||||
- 아직 scratch 상태인 강한 후보가 있으면 그 manifest 경로
|
||||
- 진행 중인 WFV / robustness 실행 경로
|
||||
|
||||
즉, "무엇이 최고였는가"보다 "무엇이 먹혔고 무엇이 죽었는가"를 남겨야 한다.
|
||||
|
||||
## 10. 운영 교훈
|
||||
|
||||
### 10.1 Disabled Named Micro도 오염이다
|
||||
|
||||
manifest에 named micro engine이 남아 있으면 `enabled: false`여도 clean 전략으로 보지 않는다.
|
||||
실제로 old `v1.10~v1.13`은 disabled named micro가 남아 있었고,
|
||||
이 때문에 현재 clean replacement로 [`return_max_long_v1.51.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.51.json),
|
||||
[`return_max_long_v1.52.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.52.json) 을 분리했다.
|
||||
|
||||
### 10.2 OOT는 최적화 목표가 아니라 품질 계층이다
|
||||
|
||||
`2020~2021` repaired OOT는 점수를 올리기 위한 최적화 목표가 아니라,
|
||||
현재 전략이 특정 시기 구조에만 맞는지 확인하는 추가 품질 계층이다.
|
||||
OOT를 보고 규칙을 직접 맞추기 시작하면 그 순간 또 오염된다.
|
||||
|
||||
### 10.3 Snapshot 결함부터 의심한다
|
||||
|
||||
OOT가 전부 `0 trade`로 보이면 전략 탓만 하지 말고 snapshot 자체를 먼저 점검한다.
|
||||
실제로 symbol 기반 export에서 `market_cap_proxy`, `exchange_proxy`가 비어 있던 버그가 있었고,
|
||||
이를 고친 뒤에야 repaired OOT가 의미 있는 비교 지표가 됐다.
|
||||
|
||||
### 10.4 Paper Backtest stale 판정은 manifest 나이가 아니라 coverage로 본다
|
||||
|
||||
`fithia2 paper backtest`는 snapshot이 오래됐다는 이유만으로 refresh하면 안 된다.
|
||||
실제로는 기존 snapshot이 충분한 날짜 범위를 이미 덮고 있을 수 있다.
|
||||
|
||||
현재 원칙:
|
||||
|
||||
- stale 여부는 parquet `event_date` coverage로 판단한다
|
||||
- snapshot 경로는 `settings.parquet_dir`를 먼저 보고, 없으면 `data/datasets/snapshots`를 본다
|
||||
- refresh가 실패해도 기존 snapshot이 requested period를 덮으면 그대로 사용한다
|
||||
|
||||
즉 "manifest created_at이 오래됐다"는 이유만으로 refresh를 강제하면 안 된다.
|
||||
|
||||
### 10.5 Screener 장애 fallback은 local-only여야 한다
|
||||
|
||||
snapshot export 중 live screener가 `500`으로 죽을 수 있다.
|
||||
이때 조용히 다른 remote endpoint로 넘어가면, 시점마다 다른 값이 섞여 재현성이 깨진다.
|
||||
|
||||
현재 원칙:
|
||||
|
||||
- universe screener가 실패하면 우선 기존 local snapshot metadata를 deterministic하게 재사용한다
|
||||
- local fallback조차 없으면 export는 그대로 실패시킨다
|
||||
- 임의의 remote fallback으로 조용히 성공시키지 않는다
|
||||
|
||||
즉 장애 대응보다 재현성을 우선한다.
|
||||
|
||||
## 11. 현재 상태
|
||||
|
||||
문서 작성 시점의 active clean 후보는 아래다.
|
||||
|
||||
1. [`return_max_long_v1.51.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.51.json)
|
||||
2. [`return_max_long_v1.52.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.52.json)
|
||||
3. [`return_max_long_v1.53.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.53.json)
|
||||
|
||||
현재 baseline은 `v1.51`이다.
|
||||
|
||||
- full split `+37.9 / +35.3 / +42.7`
|
||||
- WFV mean `+11.10%`, gap `29.67%`
|
||||
- repaired OOT positive window rate `48.7%`
|
||||
|
||||
최근 실패한 축:
|
||||
|
||||
- [`return_max_long_v1.53.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.53.json)
|
||||
- raw return은 좋아졌지만 WFV gap/OOT가 나빠져 탈락
|
||||
- [`return_max_long_v1.55.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.55.json)
|
||||
- test는 좋아졌지만 repaired OOT가 크게 악화
|
||||
- [`return_max_long_v1.56.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.56.json),
|
||||
[`return_max_long_v1.57.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.57.json),
|
||||
[`return_max_long_v1.58.json`](/Users/yirugi/mycloud/personal/workspace/fithia2/configs/experiments/return_max_long_v1.58.json)
|
||||
- general-only 미세조정이었지만 no-op 또는 후퇴
|
||||
|
||||
## 12. 현재 예외
|
||||
|
||||
현재 문서 작성 시점의 active known exception은 없다.
|
||||
|
||||
과거 `v797_v793_epam_rklb_alk_combo` 누락은 이미 역사적 교훈으로만 남기고,
|
||||
현재 workflow에선 `journal ↔ manifest parity`와 auto-sync 규칙으로 막는다.
|
||||
|
||||
## 13. 운영 원칙 요약
|
||||
|
||||
- scratch는 빠르게, official은 엄격하게 관리한다.
|
||||
- journal에 적을 정도면 manifest도 repo에 있어야 한다.
|
||||
- leaderboard 상단 전략은 반드시 재현 가능해야 한다.
|
||||
- deploy 후보는 full split만으로 끝내지 않고 WFV/robustness/repaired OOT까지 붙인다.
|
||||
- named micro는 disabled여도 clean 전략에 남겨두지 않는다.
|
||||
- 세션 종료 전 `journal ↔ manifest` parity를 확인한다.
|
||||
- snapshot provenance가 틀리면 점수 논쟁보다 먼저 metadata부터 고친다.
|
||||
@ -0,0 +1,21 @@
|
||||
# Overlay Strategy Leaderboard
|
||||
_Updated: 2026-03-27T03:16:32.096793+00:00_
|
||||
|
||||
_This board is separate from the default single-book leaderboard. Overlay rows are book-of-books evaluations and are not directly comparable to single-book `SQS` rows._
|
||||
|
||||
_`SQS` here is overlay official SQS: common-window overlay score with a stress OOT gate. `T.*` columns are common-window overlay metrics._
|
||||
|
||||
| # | Overlay | SQS | [T]Ret% | [T]Ann% | [T]DD% | Stress Ret% | Stress DD% | Stress Sharpe | Date |
|
||||
|---|---------|-----|----------|----------|--------|-------------|------------|---------------|------|
|
||||
| 1 | return_book_overlay_v3 | 90.2 | +175.6 | +28.6 | 4.5 | +6.0 | 5.4 | +0.67 | 2026-03-26 |
|
||||
| 2 | return_book_overlay_v3b | 87.7 | +169.5 | +27.9 | 5.0 | +7.4 | 5.8 | +0.80 | 2026-03-26 |
|
||||
|
||||
## Recent Overlay Entries
|
||||
### IMP-0738 (2026-03-26) — return_book_overlay_v3b
|
||||
Hypothesis: Balanced overlay variant with 50/50 neutral allocation between v6.221 and v6new.54.
|
||||
Verdict: **UNKNOWN** (SQS 87.7)
|
||||
|
||||
### IMP-0737 (2026-03-26) — return_book_overlay_v3
|
||||
Hypothesis: Book-of-books overlay using v6.221 as stress fallback and v6new.54 as normal-regime book.
|
||||
Verdict: **UNKNOWN** (SQS 90.2)
|
||||
|
||||
Loading…
Reference in New Issue