auto: 일일 백업 2026-06-20 02:00
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,116 @@ def _label(params: dict) -> str:
|
||||
return '·'.join(f'{short.get(k, k)}{v:g}' for k, v in params.items())
|
||||
|
||||
|
||||
def _philosophy_presets() -> list[dict]:
|
||||
"""철학별 라이브 비교군 프리셋.
|
||||
|
||||
기존 sweep은 같은 규칙의 강약 조절이 많아 보유 종목이 겹치기 쉬웠다. 이 프리셋은
|
||||
수급 기간, 애널 게이트, 시장 방어, 보유 종목 수, 진입 방식까지 같이 바꿔 라이브 행동을
|
||||
더 벌리는 용도다. 주문 모듈과 무관한 페이퍼 시뮬 전용 정의다.
|
||||
"""
|
||||
base = {
|
||||
'RSI_OVERBOUGHT': 75,
|
||||
'RSI_OVERSOLD': 20,
|
||||
'MAX_HOLD_DAYS': 20,
|
||||
'BEAR_ENTRY_MODE': 1,
|
||||
'TREND_SLOPE_GATE': 1,
|
||||
'MID_ARRAY_GATE': 1,
|
||||
'IMMEDIATE_ENTRY': 0,
|
||||
'AVERAGING_ENTRY': 0,
|
||||
'ENTRY_TRANCHES': 2,
|
||||
'SCALE_OUT_FRAC': 0.0,
|
||||
}
|
||||
|
||||
def p(name: str, strength: str, **params):
|
||||
merged = dict(base)
|
||||
merged.update(params)
|
||||
return {'name': f'{name}·{strength}', 'params': merged}
|
||||
|
||||
return [
|
||||
p('대형주 안정형', '보수', SMA_LONG=60, RR_RATIO=1.5, STOP_ATR_MULT=2.5,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=1.3, TURNOVER_BREAKOUT_MULT=1.2,
|
||||
TURNOVER_OVERHEAT_MULT=4.0, FLOW_DAYS=10, ANALYST_MIN_UPSIDE_PCT=3.0,
|
||||
MAX_POSITIONS=12, RISK_PER_TRADE_PCT=0.005, BEAR_ENTRY_MODE=0),
|
||||
p('대형주 안정형', '기본', SMA_LONG=60, RR_RATIO=2.0, STOP_ATR_MULT=2.2,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=1.5, TURNOVER_BREAKOUT_MULT=1.3,
|
||||
TURNOVER_OVERHEAT_MULT=4.0, FLOW_DAYS=7, ANALYST_MIN_UPSIDE_PCT=5.0,
|
||||
MAX_POSITIONS=10, RISK_PER_TRADE_PCT=0.0075, BEAR_ENTRY_MODE=1),
|
||||
p('대형주 안정형', '공격', SMA_LONG=20, RR_RATIO=2.0, STOP_ATR_MULT=2.0,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=1.5, TURNOVER_BREAKOUT_MULT=1.5,
|
||||
TURNOVER_OVERHEAT_MULT=4.5, FLOW_DAYS=5, ANALYST_MIN_UPSIDE_PCT=5.0,
|
||||
MAX_POSITIONS=8, RISK_PER_TRADE_PCT=0.01, BEAR_ENTRY_MODE=1),
|
||||
|
||||
p('수급 추종형', '보수', SMA_LONG=60, RR_RATIO=2.0, STOP_ATR_MULT=2.0,
|
||||
PULLBACK_ATR_MULT=1.5, VOLUME_BREAKOUT_MULT=1.3, TURNOVER_BREAKOUT_MULT=1.2,
|
||||
FLOW_DAYS=10, ANALYST_MIN_UPSIDE_PCT=0.0, MAX_POSITIONS=8,
|
||||
RISK_PER_TRADE_PCT=0.006, BEAR_ENTRY_MODE=0),
|
||||
p('수급 추종형', '기본', SMA_LONG=20, RR_RATIO=2.0, STOP_ATR_MULT=1.8,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=1.3, TURNOVER_BREAKOUT_MULT=1.3,
|
||||
FLOW_DAYS=5, ANALYST_MIN_UPSIDE_PCT=0.0, MAX_POSITIONS=8,
|
||||
RISK_PER_TRADE_PCT=0.01, BEAR_ENTRY_MODE=1),
|
||||
p('수급 추종형', '공격', SMA_LONG=10, RR_RATIO=2.5, STOP_ATR_MULT=1.5,
|
||||
PULLBACK_ATR_MULT=0.8, VOLUME_BREAKOUT_MULT=1.2, TURNOVER_BREAKOUT_MULT=1.2,
|
||||
FLOW_DAYS=3, ANALYST_MIN_UPSIDE_PCT=-5.0, MAX_POSITIONS=6,
|
||||
RISK_PER_TRADE_PCT=0.0125, BEAR_ENTRY_MODE=1, IMMEDIATE_ENTRY=1),
|
||||
|
||||
p('돌파 모멘텀형', '보수', SMA_LONG=60, BREAKOUT_LOOKBACK=40, RR_RATIO=3.0,
|
||||
STOP_ATR_MULT=1.7, PULLBACK_ATR_MULT=0.0, VOLUME_BREAKOUT_MULT=2.5,
|
||||
TURNOVER_BREAKOUT_MULT=2.0, TURNOVER_OVERHEAT_MULT=5.0, FLOW_DAYS=5,
|
||||
ANALYST_MIN_UPSIDE_PCT=5.0, MAX_POSITIONS=6, RISK_PER_TRADE_PCT=0.006,
|
||||
BEAR_ENTRY_MODE=0),
|
||||
p('돌파 모멘텀형', '기본', SMA_LONG=20, BREAKOUT_LOOKBACK=20, RR_RATIO=3.0,
|
||||
STOP_ATR_MULT=1.5, PULLBACK_ATR_MULT=0.0, VOLUME_BREAKOUT_MULT=2.0,
|
||||
TURNOVER_BREAKOUT_MULT=1.8, TURNOVER_OVERHEAT_MULT=5.0, FLOW_DAYS=5,
|
||||
ANALYST_MIN_UPSIDE_PCT=5.0, MAX_POSITIONS=6, RISK_PER_TRADE_PCT=0.01,
|
||||
BEAR_ENTRY_MODE=1),
|
||||
p('돌파 모멘텀형', '공격', SMA_LONG=10, BREAKOUT_LOOKBACK=10, RR_RATIO=3.0,
|
||||
STOP_ATR_MULT=1.3, PULLBACK_ATR_MULT=0.0, VOLUME_BREAKOUT_MULT=1.7,
|
||||
TURNOVER_BREAKOUT_MULT=1.5, TURNOVER_OVERHEAT_MULT=6.0, FLOW_DAYS=3,
|
||||
ANALYST_MIN_UPSIDE_PCT=0.0, MAX_POSITIONS=5, RISK_PER_TRADE_PCT=0.0125,
|
||||
BEAR_ENTRY_MODE=1, IMMEDIATE_ENTRY=1),
|
||||
|
||||
p('눌림 반등형', '보수', SMA_LONG=60, RR_RATIO=1.8, STOP_ATR_MULT=2.5,
|
||||
PULLBACK_ATR_MULT=1.5, VOLUME_BREAKOUT_MULT=1.5, TURNOVER_BREAKOUT_MULT=1.2,
|
||||
FLOW_DAYS=10, RSI_OVERSOLD=25, ANALYST_MIN_UPSIDE_PCT=5.0,
|
||||
MAX_POSITIONS=10, RISK_PER_TRADE_PCT=0.006, BEAR_ENTRY_MODE=0),
|
||||
p('눌림 반등형', '기본', SMA_LONG=20, RR_RATIO=2.0, STOP_ATR_MULT=2.2,
|
||||
PULLBACK_ATR_MULT=1.5, VOLUME_BREAKOUT_MULT=1.3, TURNOVER_BREAKOUT_MULT=1.2,
|
||||
FLOW_DAYS=5, RSI_OVERSOLD=30, ANALYST_MIN_UPSIDE_PCT=5.0,
|
||||
MAX_POSITIONS=8, RISK_PER_TRADE_PCT=0.01, BEAR_ENTRY_MODE=0),
|
||||
p('눌림 반등형', '공격', SMA_LONG=20, RR_RATIO=2.5, STOP_ATR_MULT=2.0,
|
||||
PULLBACK_ATR_MULT=2.0, VOLUME_BREAKOUT_MULT=1.2, TURNOVER_BREAKOUT_MULT=1.1,
|
||||
FLOW_DAYS=3, RSI_OVERSOLD=35, ANALYST_MIN_UPSIDE_PCT=0.0,
|
||||
MAX_POSITIONS=6, RISK_PER_TRADE_PCT=0.0125, BEAR_ENTRY_MODE=1),
|
||||
|
||||
p('소형 성장형', '보수', SMA_LONG=60, RR_RATIO=3.0, STOP_ATR_MULT=1.8,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=2.5, TURNOVER_BREAKOUT_MULT=2.0,
|
||||
TURNOVER_OVERHEAT_MULT=6.0, FLOW_DAYS=5, ANALYST_MIN_UPSIDE_PCT=10.0,
|
||||
MAX_POSITIONS=5, RISK_PER_TRADE_PCT=0.004, BEAR_ENTRY_MODE=0),
|
||||
p('소형 성장형', '기본', SMA_LONG=20, RR_RATIO=3.0, STOP_ATR_MULT=1.5,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=2.0, TURNOVER_BREAKOUT_MULT=1.8,
|
||||
TURNOVER_OVERHEAT_MULT=6.0, FLOW_DAYS=5, ANALYST_MIN_UPSIDE_PCT=10.0,
|
||||
MAX_POSITIONS=5, RISK_PER_TRADE_PCT=0.006, BEAR_ENTRY_MODE=1),
|
||||
p('소형 성장형', '공격', SMA_LONG=10, RR_RATIO=3.5, STOP_ATR_MULT=1.3,
|
||||
PULLBACK_ATR_MULT=0.8, VOLUME_BREAKOUT_MULT=1.7, TURNOVER_BREAKOUT_MULT=1.5,
|
||||
TURNOVER_OVERHEAT_MULT=7.0, FLOW_DAYS=3, ANALYST_MIN_UPSIDE_PCT=5.0,
|
||||
MAX_POSITIONS=4, RISK_PER_TRADE_PCT=0.008, BEAR_ENTRY_MODE=1,
|
||||
IMMEDIATE_ENTRY=1),
|
||||
|
||||
p('방어 현금형', '보수', SMA_LONG=60, RR_RATIO=1.5, STOP_ATR_MULT=2.5,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=2.5, TURNOVER_BREAKOUT_MULT=2.0,
|
||||
TURNOVER_OVERHEAT_MULT=4.0, FLOW_DAYS=10, ANALYST_MIN_UPSIDE_PCT=12.0,
|
||||
MAX_POSITIONS=4, RISK_PER_TRADE_PCT=0.003, BEAR_ENTRY_MODE=0),
|
||||
p('방어 현금형', '기본', SMA_LONG=60, RR_RATIO=2.0, STOP_ATR_MULT=2.2,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=2.0, TURNOVER_BREAKOUT_MULT=1.8,
|
||||
TURNOVER_OVERHEAT_MULT=4.5, FLOW_DAYS=7, ANALYST_MIN_UPSIDE_PCT=10.0,
|
||||
MAX_POSITIONS=5, RISK_PER_TRADE_PCT=0.005, BEAR_ENTRY_MODE=0),
|
||||
p('방어 현금형', '공격', SMA_LONG=20, RR_RATIO=2.0, STOP_ATR_MULT=2.0,
|
||||
PULLBACK_ATR_MULT=1.0, VOLUME_BREAKOUT_MULT=1.8, TURNOVER_BREAKOUT_MULT=1.5,
|
||||
TURNOVER_OVERHEAT_MULT=5.0, FLOW_DAYS=5, ANALYST_MIN_UPSIDE_PCT=8.0,
|
||||
MAX_POSITIONS=6, RISK_PER_TRADE_PCT=0.0075, BEAR_ENTRY_MODE=1),
|
||||
]
|
||||
|
||||
|
||||
def seed_from_sweep(n: int = 3) -> list[dict]:
|
||||
"""backtest_results.json 검증 상위 n개 → 변이로 등록 (기존 계좌는 유지)."""
|
||||
try:
|
||||
@@ -103,7 +213,7 @@ def sync_label_tops(results: dict) -> dict:
|
||||
'kept': len(current) - removed}
|
||||
|
||||
|
||||
def add_variant(params: dict) -> dict | None:
|
||||
def add_variant(params: dict, name: str | None = None) -> dict | None:
|
||||
"""단일 params 조합을 변이로 추가 (백테스트 행 → 비교군). 이미 있으면 None."""
|
||||
variants = load_variants()
|
||||
seen = {json.dumps(v['params'], sort_keys=True) for v in variants}
|
||||
@@ -111,12 +221,25 @@ def add_variant(params: dict) -> dict | None:
|
||||
return None
|
||||
nums = [int(v['id'][1:]) for v in variants if v['id'][1:].isdigit()]
|
||||
vid = f'v{(max(nums) + 1) if nums else 1}'
|
||||
v = {'id': vid, 'name': _label(params), 'params': params}
|
||||
v = {'id': vid, 'name': name or _label(params), 'params': params}
|
||||
variants.append(v)
|
||||
save_variants(variants)
|
||||
return v
|
||||
|
||||
|
||||
def add_philosophy_presets() -> dict:
|
||||
"""철학별 프리셋 18개를 비교군에 추가. 기존 계좌와 중복 조합은 유지."""
|
||||
added = []
|
||||
skipped = 0
|
||||
for preset in _philosophy_presets():
|
||||
v = add_variant(preset['params'], preset['name'])
|
||||
if v:
|
||||
added.append(v)
|
||||
else:
|
||||
skipped += 1
|
||||
return {'added': added, 'skipped': skipped, 'total': len(load_variants())}
|
||||
|
||||
|
||||
def remove_variant(vid: str):
|
||||
"""변이 1개 삭제 (정의 + 계좌)."""
|
||||
import shutil
|
||||
|
||||
Reference in New Issue
Block a user