Skip to content

Commit de6efe2

Browse files
authored
Merge pull request #449 from easygap/fix/basket-capital-resolution
fix: 바스켓 계정 자본 중앙 해석 — 주문 리스크 가드 분모 오류 수복
2 parents 36daf33 + 16fc640 commit de6efe2

2 files changed

Lines changed: 73 additions & 3 deletions

File tree

core/portfolio_manager.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,31 @@ def __init__(self, config: Config = None, account_key: str = "", initial_capital
5454
if initial_capital is not None:
5555
self.initial_capital = float(initial_capital)
5656
else:
57-
self.initial_capital = self.config.risk_params.get(
58-
"position_sizing", {}
59-
).get("initial_capital", 10000000)
57+
# 바스켓 계정(basket_rebalance:<name>)은 baskets.yaml의 바스켓별 자본이
58+
# 진실이다 — account_key만으로 이 계정을 여는 모든 경로(주문 리스크 가드
59+
# 등)가 전역 자본(10M)으로 폴백하면 분모가 틀어져, 소액 바스켓(예: 30만
60+
# kr_pocket)에서 MDD·일일 손실 한도가 사실상 무력화된다(#426이 평가기는
61+
# 고쳤지만 이 폴백은 남아 있었다 — 6차 점검 E2E에서 실측). 중앙 해석으로
62+
# 현재·미래 호출부를 일괄 커버한다. 해석 실패 시 기존 폴백 유지.
63+
resolved = None
64+
if (self.account_key or "").startswith("basket_rebalance:"):
65+
try:
66+
from core.basket_rebalancer import BasketRebalancer
67+
68+
_basket = self.account_key.split(":", 1)[1]
69+
_cap = (
70+
BasketRebalancer._load_baskets_config().get(_basket) or {}
71+
).get("initial_capital")
72+
resolved = float(_cap) if _cap is not None else None
73+
except Exception as exc:
74+
logger.debug("바스켓 자본 해석 실패(전역 폴백): {}", exc)
75+
self.initial_capital = (
76+
resolved
77+
if resolved is not None
78+
else self.config.risk_params.get(
79+
"position_sizing", {}
80+
).get("initial_capital", 10000000)
81+
)
6082
self._is_live = self.config.trading.get("mode", "paper") == "live"
6183

6284
# Peak value 복구: DB 스냅샷에서 이전 세션의 peak을 가져와 MDD 연속성 유지

tests/test_cash_flows.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,54 @@ def _pm(monkeypatch, account, initial=300_000, cash_delta=0.0, deposits=0.0,
101101
return pm
102102

103103

104+
class TestBasketCapitalResolution:
105+
"""바스켓 계정 키만으로 PM을 열어도 baskets.yaml 자본이 분모여야 한다.
106+
107+
6차 점검 E2E 실측: 주문 리스크 가드(_drawdown_pre_order_check)가 account_key만으로
108+
PM을 열어 전역 10M 폴백 → 30만 pocket의 손실 한도가 사실상 무력화되던 결함.
109+
"""
110+
111+
def test_basket_key_resolves_basket_capital(self, monkeypatch):
112+
import core.portfolio_manager as pm_mod
113+
114+
monkeypatch.setattr(pm_mod, "get_latest_peak_value", lambda account_key="": None)
115+
from unittest.mock import patch
116+
with patch(
117+
"core.basket_rebalancer.BasketRebalancer._load_baskets_config",
118+
return_value={"kr_pocket": {"initial_capital": 300_000}},
119+
):
120+
pm = PortfolioManager(account_key="basket_rebalance:kr_pocket")
121+
assert pm.initial_capital == 300_000
122+
123+
def test_unknown_basket_falls_back_to_global(self, monkeypatch):
124+
import core.portfolio_manager as pm_mod
125+
126+
monkeypatch.setattr(pm_mod, "get_latest_peak_value", lambda account_key="": None)
127+
from unittest.mock import patch
128+
with patch(
129+
"core.basket_rebalancer.BasketRebalancer._load_baskets_config",
130+
return_value={},
131+
):
132+
pm = PortfolioManager(account_key="basket_rebalance:no_such")
133+
assert pm.initial_capital >= 1_000_000 # 전역 폴백(설정값)
134+
135+
def test_non_basket_key_unchanged(self, monkeypatch):
136+
import core.portfolio_manager as pm_mod
137+
138+
monkeypatch.setattr(pm_mod, "get_latest_peak_value", lambda account_key="": None)
139+
pm = PortfolioManager(account_key="scoring")
140+
assert pm.initial_capital >= 1_000_000 # 기존 동작 그대로
141+
142+
def test_explicit_capital_still_wins(self, monkeypatch):
143+
import core.portfolio_manager as pm_mod
144+
145+
monkeypatch.setattr(pm_mod, "get_latest_peak_value", lambda account_key="": None)
146+
pm = PortfolioManager(
147+
account_key="basket_rebalance:kr_pocket", initial_capital=777,
148+
)
149+
assert pm.initial_capital == 777
150+
151+
104152
class TestSummaryWithDeposits:
105153
def test_no_flows_keeps_legacy_formula(self, monkeypatch):
106154
# 입금 0건: 총평가/초기자본 그대로 (하위 호환)

0 commit comments

Comments
 (0)