fix: 적립금이 매수로 전환되지 못하던 다섯 개 차단 해소 - #457
Merged
Merged
Conversation
kr_pocket에 첫 적립금 10만원을 기록하고 다음 사이클을 사본에서 돌려 봤더니 매수가 한 건도 나가지 않았다. 개별 주식용 전역 파라미터가 ETF 2종 바스켓의 설계를 차례로 막고 있었다. 하나를 풀면 다음 게 걸리는 식으로 다섯 개였다. 단일 종목 20% 상한 vs 선언 47.5% → '단일 종목 비중 20% 초과' 전체 투자 70% 상한 vs 선언 95% 최소 현금 20% vs 선언 5% → '최소 현금 비중 20% 미만' 업종 비중(KRX) ETF는 업종 코드 없음 → '업종 매핑 없음' 실적 발표일 필터 ETF는 실적일 없음 → '실적일 조회 불가' 다섯 개 다 fail-closed라 증상은 '매수 0건'과 '배치율 미달'로만 나타났다. 원인은 어디에도 안 보였다. kr_pocket이 7/10 이후 한 주도 못 산 이유가 이것이다. 전역값은 재량 매매용 안전판이다. 목표 비중을 명시로 선언한 주문에는 그 선언에서 파생한 상한으로 바꿔 단다. 없애는 게 아니다 — 어떤 경우에도 목표 + 드리프트 임계값을 넘길 수 없고, 위임은 weight_policy_managed 주문에만 적용된다. 노출 상한 (max_position / max_investment / min_cash): 리밸런서가 자기 비중표에서 계산해 넘긴다. 종목 상한은 (목표 + 드리프트) × 주식비중, 투자 상한은 주식비중 + 배치 밴드, 현금 하한은 바스켓이 선언한 값 (effective_stock_fraction과 같은 해석 규칙). 비중표에 없는 종목은 위임하지 않는다. 업종·실적 필터 (core/instrument_classes.py 신설): 이 둘은 '개별 기업'으로만 의미가 있는 검사다. 지수 ETF는 그 자체가 여러 업종에 걸친 묶음이고, 금리 파킹 ETF는 주식도 아니다. 종목별 면제 목록을 두 곳에 따로 만들면 갈라지므로 instrument_classes.non_company_symbols 한 곳에 두고 둘 다 참조한다. 면제는 이 두 검사뿐 — 노출 상한·유동성·갭·현금·거래중단은 그대로다. 개별 주식의 업종 매핑 누락은 계속 fail-closed다(테스트로 고정). 검증(운영 DB 사본, 실제 실행 경로): kr_pocket 배치율 58.0% → 73.1%, 357870 1주 체결 kr_diversified_hold 배치율 54.9% → 59.8%, 012330 1주 체결 (회귀 없음) 입금 후 TWR -4.93% — 입금이 수익으로 잡히지 않는다 CI 환경 재현(config/settings.yaml 치우고 실행): 1966개 통과.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
배경
kr_pocket 첫 적립금 10만원을 기록하고, 다음 사이클이 그 현금을 어떻게 흡수하는지 운영 DB 사본에서 미리 돌려 봤다. 매수가 한 건도 안 나갔다.
개별 주식용으로 만든 전역 파라미터가 ETF 2종 바스켓의 설계를 차례로 막고 있었다. 하나를 풀면 다음 게 걸리는 식으로 다섯 개였다.
max_position_ratio20%max_investment_ratio70%min_cash_ratio20%max_sector_ratio+sector_map_strictskip_earnings_days3다섯 개 다 fail-closed라 증상은 '매수 0건'과 '배치율 미달'로만 나타났다. 원인은 어디에도 안 보였다. kr_pocket이 7/10 이후 한 주도 못 산 게 이것 때문이다.
접근
전역값은 재량 매매용 안전판이다. 목표 비중을 명시로 선언한 주문에는 그 선언에서 파생한 상한으로 바꿔 단다. 없애는 게 아니라 위임이다.
weight_policy_managed주문에만 적용된다. 비중표에 없는 종목은 전역 상한을 그대로 쓴다같은 성격의 위임을 이미 두 번 했다. 쌍별 상관 거부권(#456)과 단타 손절 기준이 그것이고, 이번이 세 번째다.
docs/OPERATING_PRINCIPLES.md원칙 3에 적어 둔 패턴이 실제로 또 나왔다.1. 노출 상한 위임
리밸런서가 자기 비중표에서 계산해 executor로 넘긴다.
kr_diversified_hold로 검산하면 종목 상한이
(11.1% + 8%) × 60% = 11.5%로 전역 20%보다 더 조인다. 위임이 곧 완화는 아니다.2. 업종·실적 필터 —
core/instrument_classes.py신설이 둘은 개별 기업으로만 의미가 있는 검사다. 지수 ETF는 그 자체가 여러 업종에 걸친 묶음이고, 금리 파킹 ETF는 주식도 아니다. KRX 업종 코드도 실적 발표일도 DART 기업코드도 없다.
면제 목록을 업종 쪽과 실적 쪽에 따로 만들면 갈라지므로
instrument_classes.non_company_symbols한 곳에 두고 둘 다 참조하게 했다.개별 주식의 업종 매핑 누락은 계속 fail-closed다. 테스트로 고정해 뒀다.
검증
운영 DB 사본에 실제 실행 경로를 태웠다.
CI 환경 재현 —
config/settings.yaml을 치우고 전체 스위트 실행: 1966개 통과.남은 것
_execute_buy_quantity_impl의 1회 손실 예산이 아직 전역 -3% 손절로 계산된다. 트랙 정책을 넣으면 슬롯이 예산을 넘어 재동결되므로 목표비중 주문에는 별도 기준이 필요하다(#456에서 이미 기록해 둔 항목).