fix: .env 미로드(ncue) fallback 및 B-1 운영 설정 정합
python-dotenv 없을 때 env_loader가 .env를 직접 파싱하도록 해 LIVE_TRADING_ENABLED=1이 dry-run으로 보이던 문제를 해결한다. 06 기동 시 로더·LIVE 상태를 출력하고, B-1 한도 검증·잔고 점검 스크립트를 추가한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -105,8 +105,8 @@ def check_config() -> list[str]:
|
||||
print(f" monitor_rules={[r['rule_id'] for r in rules]}")
|
||||
if not GT_SIGNAL_CAUSAL:
|
||||
issues.append("GT_SIGNAL_CAUSAL=0 — hybrid live sizing 비활성")
|
||||
if LIVE_TRADING_ENABLED:
|
||||
issues.append("LIVE_TRADING_ENABLED=1 — dry-run 점검 시 0 권장")
|
||||
if not LIVE_TRADING_ENABLED:
|
||||
issues.append("LIVE_TRADING_ENABLED=0 — 실전 운영 시 1 필요")
|
||||
if len(rules) != 2:
|
||||
issues.append(f"monitor_rules {len(rules)}개 (기대 2)")
|
||||
expected = {"buy_compound_tight", "sell_mtf_cross_all_tf"}
|
||||
@@ -118,27 +118,37 @@ def check_config() -> list[str]:
|
||||
|
||||
def check_capital_alignment() -> list[str]:
|
||||
"""
|
||||
초기 자금 40만 원 기준 원화 한도·알림 비율 점검 (100만 시대 ×0.4).
|
||||
초기 자금 40만 원 기준 원화 한도·알림 비율 점검.
|
||||
|
||||
LIVE_TRADING_ENABLED=1 → Phase B-1(운영), 0 → Phase C(dry-run).
|
||||
|
||||
Returns:
|
||||
불일치 시 이슈 문자열 목록.
|
||||
"""
|
||||
issues: list[str] = []
|
||||
_print_header("1b. 초기 자금·비율 (40만 원)")
|
||||
phase = "B-1 실전" if LIVE_TRADING_ENABLED else "C dry-run"
|
||||
_print_header(f"1b. 초기 자금·비율 (40만 원, {phase})")
|
||||
ic = int(GT_INITIAL_CASH_KRW)
|
||||
expected = {
|
||||
expected: dict[str, int] = {
|
||||
"GT_INITIAL_CASH_KRW": 400_000,
|
||||
"MONITOR_ALERT_KRW_AMOUNT": int(ic * 0.10),
|
||||
"LIVE_ORDER_KRW": int(ic * 0.10),
|
||||
"LIVE_DAILY_LOSS_LIMIT_KRW": int(ic * 0.05),
|
||||
"LIVE_DAILY_KRW_MAX": int(ic * 10),
|
||||
}
|
||||
if LIVE_TRADING_ENABLED:
|
||||
expected["LIVE_DAILY_LOSS_LIMIT_KRW"] = int(ic * 0.10)
|
||||
expected["LIVE_DAILY_KRW_MAX"] = ic
|
||||
expected["LIVE_MAX_TRADES_PER_DAY"] = 15
|
||||
else:
|
||||
expected["LIVE_DAILY_LOSS_LIMIT_KRW"] = int(ic * 0.05)
|
||||
expected["LIVE_DAILY_KRW_MAX"] = int(ic * 10)
|
||||
expected["LIVE_MAX_TRADES_PER_DAY"] = 999
|
||||
actual = {
|
||||
"GT_INITIAL_CASH_KRW": ic,
|
||||
"MONITOR_ALERT_KRW_AMOUNT": int(MONITOR_ALERT_KRW_AMOUNT),
|
||||
"LIVE_ORDER_KRW": int(LIVE_ORDER_KRW),
|
||||
"LIVE_DAILY_LOSS_LIMIT_KRW": int(LIVE_DAILY_LOSS_LIMIT_KRW),
|
||||
"LIVE_DAILY_KRW_MAX": int(LIVE_DAILY_KRW_MAX),
|
||||
"LIVE_MAX_TRADES_PER_DAY": int(LIVE_MAX_TRADES_PER_DAY),
|
||||
}
|
||||
for key, exp in expected.items():
|
||||
got = actual[key]
|
||||
@@ -147,13 +157,16 @@ def check_capital_alignment() -> list[str]:
|
||||
print(f" [{mark}] {key}={got:,} (기대 {exp:,})")
|
||||
if not ok:
|
||||
issues.append(f"{key}={got:,} ≠ 기대 {exp:,}")
|
||||
paper = PaperPortfolio.load()
|
||||
if int(paper.cash_krw) != ic and paper.qty < 1e-12:
|
||||
issues.append(
|
||||
f"paper 현금 ₩{paper.cash_krw:,.0f} ≠ 초기 ₩{ic:,} (보유 없을 때)"
|
||||
)
|
||||
elif int(getattr(paper, "initial_cash_krw", 0) or paper.cash_krw) != ic:
|
||||
print(f" [INFO] paper 운용 중 (cash=₩{paper.cash_krw:,.0f})")
|
||||
if not LIVE_TRADING_ENABLED:
|
||||
paper = PaperPortfolio.load()
|
||||
if int(paper.cash_krw) != ic and paper.qty < 1e-12:
|
||||
issues.append(
|
||||
f"paper 현금 ₩{paper.cash_krw:,.0f} ≠ 초기 ₩{ic:,} (보유 없을 때)"
|
||||
)
|
||||
elif int(getattr(paper, "initial_cash_krw", 0) or paper.cash_krw) != ic:
|
||||
print(f" [INFO] paper 운용 중 (cash=₩{paper.cash_krw:,.0f})")
|
||||
else:
|
||||
print(" [INFO] LIVE=1 — paper_portfolio 검사 생략 (실계좌·live_signal_history 사용)")
|
||||
return issues
|
||||
|
||||
|
||||
@@ -354,7 +367,7 @@ def main() -> int:
|
||||
print(f" WARN: {i}")
|
||||
print(" → 이슈 확인 후 Phase B(소액 파일럿) 진행")
|
||||
return 1
|
||||
print(" Phase A PASS — Phase B(소액 LIVE_TRADING_ENABLED=1) 준비 완료")
|
||||
print(" 운영 설정 PASS — 06_execute_live 실전 기동 가능")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user