Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ Target-weight 60영업일 pilot manifest: `--readiness-audit`는 운영 리포

Generic paper entry도 동일한 실행 경계 원칙을 따른다. `main.py --mode paper`, scheduler auto-entry, fixed-quantity paper BUY 모두 preflight status와 runtime state를 주문 생성 전에 확인하고, 확인 실패는 fail-closed로 차단한다. blocked runtime에서 pilot authorization이 활성화되어도 `check_pilot_entry()`를 다시 통과해야 하며, SELL/exit 경로는 포지션 정리를 위해 계속 허용한다. pilot evidence freshness는 달력일이 아니라 주말과 한국장 휴장일을 제외한 영업일 기준으로 계산합니다.

Target-weight pilot 승인/재시도 보강: `tools/paper_pilot_control.py --enable`은 pilot auth를 쓰기 전에 target-weight readiness audit을 다시 실행해 운영자가 요청한 cap이 현재 plan, launch readiness, 유동성 preflight, 비용 반영 pre-trade risk를 만족하는지 검증합니다. 유동성 diagnostics가 없으면 fail-closed로 차단하고, 이미 주문이 완료된 same-candidate/trade-day 세션은 `--allow-rerun`을 줘도 재실행하지 않습니다. `--allow-rerun`은 부분 실행이나 중단된 세션 복구용으로만 사용합니다.
Target-weight pilot 승인/재시도 보강: `tools/paper_pilot_control.py --enable`은 `target_weight_*` 후보의 pilot auth를 쓰기 전에 target-weight readiness audit을 다시 실행해 운영자가 요청한 cap이 현재 plan, launch readiness, 유동성 preflight, 비용 반영 pre-trade risk를 만족하는지 검증합니다. 유동성 diagnostics가 없으면 fail-closed로 차단하고, 이미 주문이 완료된 same-candidate/trade-day 세션은 `--allow-rerun`을 줘도 재실행하지 않습니다. `--allow-rerun`은 부분 실행이나 중단된 세션 복구용으로만 사용합니다.

Target-weight 실행 차단 기록: `--execute`가 pilot cap validation에서 막히면 주문·체결·증거 수집 없이 session JSON artifact에 차단 사유를 남깁니다. runtime pilot session은 쓰지 않아 cap을 고친 뒤 같은 거래일 계획을 다시 점검할 수 있습니다.

Expand Down
2 changes: 1 addition & 1 deletion docs/PROJECT_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ full paper 신규 BUY는 preflight status artifact와 runtime state가 모두
| ✅ **target-weight 60영업일 pilot manifest 추가** | `tools/target_weight_rotation_pilot.py --readiness-audit`가 60영업일 `pilot_paper` 증거 누적 기준, 추천 cap, 차단 사유, 실행 명령을 담은 `target_weight_paper_experiment_manifest_*.json`을 함께 생성한다. `reports/paper_experiment_manifest.json`에도 기존 scoring 실험과 별도 target-weight capped paper pilot 기준을 기록해 운영 흐름을 분리한다 |
| ✅ **target-weight daily ops summary 추가** | `tools/target_weight_rotation_pilot.py --daily-ops-summary`가 readiness audit, 60영업일 pilot evidence 진행률, 유동성/pre-trade risk 상태, 다음 운영 명령을 `target_weight_daily_ops_summary_*.json/.md`로 묶어 남긴다. 주문·증거·pilot session을 쓰지 않는 no-order summary라 장전/장마감 운영 확인에 안전하게 사용할 수 있다 |
| ✅ **pilot freshness 영업일 기준 보정** | `check_pilot_entry()`와 launch readiness가 evidence stale 여부를 달력일이 아니라 한국장 영업일 기준으로 계산한다. 긴 주말·휴장일 이후 정상적인 paper/pilot 흐름이 불필요하게 차단되지 않도록 `evidence_stale_unit=business_days`를 함께 남긴다 |
| ✅ **target-weight pilot enable guard 추가** | `tools/paper_pilot_control.py --enable`이 target-weight 후보를 승인할 때 pilot auth 기록 전에 readiness audit을 재실행하고, 운영자가 요청한 cap이 현재 plan/launch readiness/유동성 preflight/비용 반영 pre-trade risk를 만족할 때만 승인한다. stale plan이나 추천 cap 미충족 상태에서 auth만 먼저 열리는 경로를 차단한다 |
| ✅ **target-weight pilot enable guard 추가** | `tools/paper_pilot_control.py --enable`이 `target_weight_*` 후보를 승인할 때 pilot auth 기록 전에 readiness audit을 재실행하고, 운영자가 요청한 cap이 현재 plan/launch readiness/유동성 preflight/비용 반영 pre-trade risk를 만족할 때만 승인한다. stale plan이나 추천 cap 미충족 상태에서 auth만 먼저 열리는 경로를 차단한다 |
| ✅ **target-weight cap validation artifact 추가** | `--execute`가 pilot cap validation에서 막혀도 예외로 조기 종료하지 않고 session JSON artifact에 차단 사유, skipped orders, evidence block reason을 남긴다. 주문/체결/증거 수집/runtime pilot session 저장은 하지 않아 cap 조정 후 재점검할 수 있다 |
| ✅ **target-weight promotion proof guard 추가** | promotion package와 live gate가 target-weight 계열 전략의 promotable day를 일반 `execution_backed=True` record로 인정하지 않는다. `pilot_paper`/authorized record가 target-weight plan/execution proof를 포함하고 liquidity/pre-trade/order/fill/position complete와 plan/execution params hash 일치를 만족한 날만 승격 카운트에 포함한다 |
| ✅ **target-weight proof consistency guard 추가** | target-weight promotion evidence는 record date와 plan trade day가 일치해야 하며, 60영업일 verified pilot evidence 전체가 하나의 params hash로 고정되어야 한다. live gate는 paper evidence의 target-weight params hash와 canonical `strategy_specs.params_hash`가 다르면 실전 전환을 차단한다 |
Expand Down
68 changes: 68 additions & 0 deletions tests/test_target_weight_paper_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,74 @@ def fake_run_pilot_readiness_audit(**kwargs):
assert result["audit"]["cap_preview"]["allowed"] is True


def test_target_weight_pilot_control_enable_guard_covers_non_default_target_weight(monkeypatch, tmp_path):
from tools.paper_pilot_control import _target_weight_enable_guard

calls = {}

def fake_run_pilot_readiness_audit(**kwargs):
calls["audit"] = kwargs
return {
"audit": {
"ready_for_cap_approval": True,
"blocking_reasons": [],
"cap_preview": {
"allowed": True,
"reason": "proposed pilot caps satisfied",
},
},
"artifact_path": tmp_path / "audit.json",
"report_path": tmp_path / "audit.md",
}

monkeypatch.setattr(
"tools.target_weight_rotation_pilot.run_pilot_readiness_audit",
fake_run_pilot_readiness_audit,
)
args = SimpleNamespace(
strategy="target_weight_rotation_next_candidate",
valid_from="2026-04-10",
max_orders=3,
max_positions=4,
max_notional=1_500_000,
max_exposure=4_000_000,
)

result = _target_weight_enable_guard(args)

assert result["audit"]["cap_preview"]["allowed"] is True
assert calls["audit"]["candidate_id"] == "target_weight_rotation_next_candidate"
assert calls["audit"]["as_of_date"] == "2026-04-10"
assert calls["audit"]["preview_caps"] == {
"max_orders_per_day": 3,
"max_concurrent_positions": 4,
"max_notional_per_trade": 1_500_000,
"max_gross_exposure": 4_000_000,
}


def test_target_weight_pilot_control_enable_guard_skips_non_target_weight(monkeypatch):
from tools.paper_pilot_control import _target_weight_enable_guard

def fail_audit(**kwargs):
pytest.fail("non target-weight strategy must not run target-weight audit")

monkeypatch.setattr(
"tools.target_weight_rotation_pilot.run_pilot_readiness_audit",
fail_audit,
)
args = SimpleNamespace(
strategy="scoring",
valid_from="2026-04-10",
max_orders=2,
max_positions=2,
max_notional=1_000_000,
max_exposure=3_000_000,
)

assert _target_weight_enable_guard(args) is None


def test_paper_pilot_control_enable_stops_before_auth_when_target_weight_guard_fails(
monkeypatch,
capsys,
Expand Down
4 changes: 1 addition & 3 deletions tools/paper_pilot_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ def run_enable(args):


def _target_weight_enable_guard(args):
from core.target_weight_rotation import DEFAULT_TARGET_WEIGHT_CANDIDATE_ID

if args.strategy != DEFAULT_TARGET_WEIGHT_CANDIDATE_ID:
if not str(args.strategy).startswith("target_weight_"):
return None

from tools.target_weight_rotation_pilot import build_preview_caps, run_pilot_readiness_audit
Expand Down
Loading