거래 빠르게 안티에서 병신만든거 커서로
feat: Implement backtest source management and enhance candle data handling Changes: - Introduced a new function `_apply_backtest_source_env_from_request` to manage the environment variables for candle, tick, and order book sources based on incoming requests. - Added a teardown function `_teardown_backtest_source_env` to ensure that environment variables do not persist between requests, enhancing the stability of the backtesting environment. - Refactored existing code to utilize the new source management functions, improving code readability and maintainability. - Added new utility functions in `bt_candle_source.py` for fetching and managing candle data, ensuring consistency with live trading data sources. Impact: - These changes improve the flexibility and reliability of the backtesting framework, allowing for better management of data sources and reducing the risk of cross-request contamination.
This commit is contained in:
@@ -215,8 +215,24 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
"OFF(기본) = KIS가 키움과 동일한 후보 40종목을 전부 수신하여 DB에 저장 | "
|
||||
"ON = KIS가 현재 내가 사고 있는 종목만 수신 (KIS ID 한도 아낄 때)"
|
||||
)),
|
||||
_f("WS_SUBSCRIBE_SPILL", "📡 구독초과/실패 즉시 벤더 spill", "bool", default=True,
|
||||
hint=(
|
||||
"ON(기본)=한도초과·구독실패·해당 WS 미연결 시 대기 없이 다음 벤더로 구독 "
|
||||
"(틱/호가 체인 기본: LIVE_* 1차 → 상대 → ls 3차 RAM). "
|
||||
"OFF=예전처럼 거절/패스. 기존 LIVE_TICK/OB_PROVIDER 값은 바꾸지 않음."
|
||||
)),
|
||||
_f("WS_TICK_SUBSCRIBE_CHAIN", "📡 틱 구독 spill 체인(csv)", "text", default="",
|
||||
hint="비우면 LIVE_TICK_PROVIDER→나머지→ls. 예: kiwoom,kis,ls"),
|
||||
_f("WS_OB_SUBSCRIBE_CHAIN", "📡 호가 구독 spill 체인(csv)", "text", default="",
|
||||
hint="비우면 LIVE_OB_PROVIDER→나머지→ls(3차 RAM). 예: kis,kiwoom,ls"),
|
||||
_f("LS_WS_ENABLED", "📡 LS WS 기동 (재시작 필요)", "bool", default=False,
|
||||
hint=(
|
||||
"ON = LS증권 실시간 WS 기동 — 구독 spill 3차·영구구독 RAM 백업용. "
|
||||
"OFF(기본)=VALIDATION/조건이력/ls_condition 전략이 있을 때만 기동. "
|
||||
"키: env_config LS_APP_KEY_REAL / LS_APP_SECRET_REAL 필요."
|
||||
)),
|
||||
_f("KIS_APP_KEY_OB_REAL", "🔑 KIS 실전 호가 전용 앱키 (선택)", "text",
|
||||
hint="한투 40종목 구독 한도 우회를 위한 2번째 실전 앱키. 미입력 시 기존 앱키로 호가까지 공용 구독합니다."),
|
||||
hint="호가 전용 2번째 실전 앱키(시세 키와 역할 분리). 미입력 시 메인 세션+SAVE 플래그 현행. spill 틱용 아님."),
|
||||
_f("KIS_APP_SECRET_OB_REAL", "🔑 KIS 실전 호가 전용 시크릿 (선택)", "text",
|
||||
hint="호가 전용 2번째 실전 시크릿키."),
|
||||
_f("KIS_APP_KEY_OB_MOCK", "🔑 KIS 모의 호가 전용 앱키 (선택)", "text",
|
||||
@@ -229,10 +245,11 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
},
|
||||
{
|
||||
"id": "ws_trigger_global",
|
||||
"title": "⚡ 매수 판단 필터 설정 (실시간 WS 기반)",
|
||||
"title": "💾 TRIGGER 스냅샷 저장 (분석용 · 매수 차단 아님)",
|
||||
"hint": (
|
||||
"매수 타이밍을 결정할 때 호가·프로그램 데이터를 어떻게 사용할지 설정. "
|
||||
"모든 데이터는 실시간 메모리(RAM)에서 직접 읽으므로 딜레이 없음."
|
||||
"매수 검토 순간을 DB에 기록할지 설정. "
|
||||
"여기 ON/OFF는 주문을 막지 않습니다. "
|
||||
"진입 차단은 아래 「진입 호가필터」「프로그램 매매 필터」「휩쏘」를 보세요."
|
||||
),
|
||||
"fields": [
|
||||
_f(
|
||||
@@ -242,7 +259,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
default=True,
|
||||
hint=(
|
||||
"ON = 기관·외국인 프로그램 매매 흐름을 메모리에 저장 | "
|
||||
"OFF = 프로그램 매매 필터 사용 불가"
|
||||
"OFF = 프로그램 매매 필터·수집 불가"
|
||||
),
|
||||
),
|
||||
_f(
|
||||
@@ -252,7 +269,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
default=True,
|
||||
hint=(
|
||||
"ON = 매수 검토할 때 호가·프로그램 스냅샷을 DB에 기록 (분석·디버깅용) | "
|
||||
"OFF = 아래 모든 저장 비활성 (DB 용량 아낄 때)"
|
||||
"OFF = 아래 모든 저장 비활성 (DB 용량 아낄 때) · 매수 차단과 무관"
|
||||
),
|
||||
),
|
||||
|
||||
@@ -273,7 +290,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
default=True,
|
||||
hint=(
|
||||
"ON = 매수 검토 순간 호가창(10호가 잔량 등) 스냅샷도 DB에 저장 | "
|
||||
"→ 매수/거절 당시의 호가 상태 정밀 분석용 (용량 주의)"
|
||||
"→ 분석용 (용량 주의) · 진입 호가필터 ON/OFF와 별개"
|
||||
),
|
||||
),
|
||||
_f(
|
||||
@@ -283,7 +300,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
default=True,
|
||||
hint=(
|
||||
"ON = 매수 검토 순간 프로그램 매매 스냅샷도 DB에 저장 | "
|
||||
"→ 호가 저장과 동일 개념, 프로그램 필터 분석용"
|
||||
"→ 분석용 · 프로그램 필터 차단 스위치와 별개"
|
||||
),
|
||||
),
|
||||
_f(
|
||||
@@ -296,24 +313,35 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
"평소엔 OFF 권장, 변경 후 봇 재시작 필요"
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "program_entry_filter",
|
||||
"title": "🚫 프로그램 매매 필터 (진입 차단)",
|
||||
"hint": (
|
||||
"기관·외국인 프로그램 수급이 나쁠 때 매수를 막는 스위치. "
|
||||
"진입 호가필터·휩쏘·EXIT_OB(매도 호가)와 전부 별개."
|
||||
),
|
||||
"fields": [
|
||||
_f(
|
||||
"PROGRAM_FILTER_ENABLED",
|
||||
"🚫 프로그램 매매 필터 (매수 차단)",
|
||||
"bool",
|
||||
default=True,
|
||||
hint=(
|
||||
"ON = 프로그램 매매 흐름이 나쁠 때 매수를 차단 (기본 ON) | "
|
||||
"OFF = 프로그램 매매 무시하고 그냥 매수"
|
||||
"ON = 프로그램 매매 흐름이 나쁠 때 매수를 차단 | "
|
||||
"OFF = 프로그램 수급 무시하고 매수 허용"
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "ws_whipsaw_global",
|
||||
"title": "🌊 휩쏘 필터 (가짜 상승 차단)",
|
||||
"title": "🌊 휩쏘 필터 (진입 차단 · 틱 급락→급반등)",
|
||||
"hint": (
|
||||
"매수 신호가 떴는데 직전에 급락이 있었으면 가짜 신호(휩쏘)로 판단해서 차단. "
|
||||
"예: 30초 안에 0.3% 이상 뚝 떨어졌다가 올라온 종목은 패스."
|
||||
"호가창이 아니라 최근 틱/미니봉 가격 패턴으로 가짜 급반등을 차단. "
|
||||
"예: 30초 안에 0.3% 이상 뚝 떨어졌다가 올라온 종목은 패스. "
|
||||
"진입 호가필터(스프레드·잔량)·프로그램 필터와 다름."
|
||||
),
|
||||
"fields": [
|
||||
_f(
|
||||
@@ -429,44 +457,49 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
ob_fields.extend([
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_FILTER_ENABLED",
|
||||
f"{lbl} 호가필터 ON",
|
||||
f"{lbl} 진입 호가필터 ON (매수 차단)",
|
||||
"bool",
|
||||
default=OB_DEFAULT_FILTER_ENABLED,
|
||||
hint="ON=스프레드·잔량비·얇은호가·매도벽으로 매수 차단 · OFF=저장만",
|
||||
hint=(
|
||||
"ON=스프레드·잔량비·얇은호가·매도벽으로 매수 차단 | "
|
||||
"OFF=진입은 안 막음(수치 보관만). "
|
||||
"EXIT_OB/STOP_OB(매도 호가익절·손절)와 무관 · 휩쏘·프로그램 필터와도 무관"
|
||||
),
|
||||
),
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_MAX_SPREAD_PCT",
|
||||
f"{lbl} 스프레드상한(%)",
|
||||
"float",
|
||||
default=OB_DEFAULT_MAX_SPREAD_PCT,
|
||||
hint="0.45=0.45% · 그리드 max_spread_pct 앵커",
|
||||
hint="진입 필터용 · 0.45=0.45% · 그리드 max_spread_pct 앵커",
|
||||
),
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_MIN_BID_ASK_RATIO",
|
||||
f"{lbl} 매수/매도잔량비 하한",
|
||||
"float",
|
||||
default=OB_DEFAULT_MIN_BID_ASK_RATIO,
|
||||
hint="그리드 min_bid_ask_ratio",
|
||||
hint="진입 필터용 · 그리드 min_bid_ask_ratio",
|
||||
),
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_ENTRY_ASK_MAX_MULT",
|
||||
f"{lbl} 매도벽 허용배수",
|
||||
"float",
|
||||
default=OB_DEFAULT_ENTRY_ASK_MAX_MULT,
|
||||
hint="필요수량×N · 그리드 ask_max_mult",
|
||||
hint="진입 필터용 · 필요수량×N · 그리드 ask_max_mult",
|
||||
),
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_ENTRY_BID_DEPTH_MULT",
|
||||
f"{lbl} 매수호가깊이 배수",
|
||||
"float",
|
||||
default=OB_DEFAULT_ENTRY_BID_DEPTH_MULT,
|
||||
hint="얇은호가 탈락 · 필요수량×N",
|
||||
hint="진입 필터용 · 얇은호가 탈락 · 필요수량×N",
|
||||
),
|
||||
_f(
|
||||
f"{pfx}_ORDERBOOK_ENTRY_BID_LEVELS",
|
||||
f"{lbl} 호가단계(N호가)",
|
||||
"int",
|
||||
default=OB_DEFAULT_ENTRY_BID_LEVELS,
|
||||
hint="진입 필터용 · N호가 잔량 합산",
|
||||
),
|
||||
])
|
||||
if pfx == "BREAKOUT":
|
||||
@@ -476,15 +509,17 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
"돌파 매도벽 상한(주)",
|
||||
"int",
|
||||
default=OB_DEFAULT_ASK_WALL_MAX_QTY,
|
||||
hint="그리드 ask_wall_max_qty",
|
||||
hint="진입 필터용 · 그리드 ask_wall_max_qty",
|
||||
),
|
||||
)
|
||||
groups.append({
|
||||
"id": "orderbook_strategy",
|
||||
"title": "호가필터 — 전략별 (수치)",
|
||||
"title": "🚫 진입 호가필터 (매수 차단) — 전략별",
|
||||
"hint": (
|
||||
"글로벌 ORDERBOOK_MAX_SPREAD_PCT 등 폐기 · "
|
||||
"파람서치 apply-best ↔ *_ORDERBOOK_* 정합"
|
||||
"호가창 스프레드·잔량·벽으로 매수만 막음. "
|
||||
"끄면(OFF) 진입 차단만 해제 · 매도 쪽 EXIT_OB/STOP_OB는 아래 "
|
||||
"「매도 호가익절·손절」카드에서 따로 킴/끔. "
|
||||
"휩쏘(틱 패턴)·프로그램 필터와도 별개."
|
||||
),
|
||||
"fields": ob_fields,
|
||||
})
|
||||
@@ -698,9 +733,11 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
)
|
||||
groups.append({
|
||||
"id": "whipsaw_strategy",
|
||||
"title": "휩쏘 — 전략별 ON/OFF",
|
||||
"title": "휩쏘 — 전략별 ON/OFF (진입 차단)",
|
||||
"hint": (
|
||||
"각 전략별로 휩쏘 필터를 켤지 끌지 결정합니다. (글로벌 휩쏘 필터 수치 상속)"
|
||||
"전략별 휩쏘(틱 급락→급반등) 진입 차단 ON/OFF. "
|
||||
"수치는 위 「휩쏘 필터」 글로벌. "
|
||||
"진입 호가필터·프로그램 필터·EXIT_OB와 별개."
|
||||
),
|
||||
"fields": ws_fields,
|
||||
})
|
||||
@@ -1019,6 +1056,27 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
_f("STRATEGY_LOOP_SLEEP_MIN", "루프 끝 sleep 최소(초)", "float", default=0.1,
|
||||
hint="한 바퀴 끝 대기 · WS 구독 캐시 폴링 · 0.1=실매 반응 빠르게"),
|
||||
_f("STRATEGY_LOOP_SLEEP_MAX", "루프 끝 sleep 최대(초)", "float", default=0.1),
|
||||
_f("LOOP_PROFILE_ENABLED", "루프 숙제 ms 계측", "bool", default=False,
|
||||
hint="ON=한 바퀴 단계별·락 wait/hold·check_buy 합/max 로그 · 병목 확정용 · 기본 OFF"),
|
||||
_f("LOOP_PROFILE_EVERY_N", "계측 샘플 주기(바퀴)", "int", default=1,
|
||||
hint="N바퀴마다 1회 상세 로그 · 1=매바퀴 · 로그 폭주 시 5~10"),
|
||||
_f("LOOP_PROFILE_LOG_PATH", "계측 로그 파일", "str", default="logs/loop_profile.log",
|
||||
hint="상대경로=레포루트 기준 · 비우면 전략 logger INFO 만"),
|
||||
_f("CHECK_BUY_PROF_MIN_MS", "check_buy 상세 로그 하한(ms)", "int", default=500,
|
||||
hint="이 ms 이상인 check_buy 만 [CHECK_BUY_PROF] 단계별 기록 · LOOP_PROFILE_ENABLED 필요"),
|
||||
_f("HOLDINGS_DB_SYNC_INTERVAL_SEC", "보유 DB sync 안전망(초)", "int", default=60,
|
||||
hint="루프마다 get_active_trades 대신 N초마다만 · 매수/매도 체결은 RAM 즉시 · "
|
||||
"0=매루프(레거시) · 재시작·지정가체결은 강제 sync"),
|
||||
_f("TODAY_TRADES_CACHE_TTL_SEC", "당일거래 RAM TTL(초)", "float", default=1.0,
|
||||
hint="check_buy·일일한도 가드 공유 · N초 내 DB 재조회 생략 · 체결 시 즉시 무효화 · 0=매번 DB"),
|
||||
_f("STRATEGY_ENV_CACHE_TTL_SEC", "전략설정 RAM TTL(초)", "float", default=1.0,
|
||||
hint="config_* reload 매루프 SELECT 완화 · 기본 1초 · 웹 저장 시 즉시 무효화 · "
|
||||
"유니버스/봉 분슬롯과 무관(임계값만)"),
|
||||
_f("UNIVERSE_SLOT_CACHE_TTL_SEC", "유니버스슬롯 RAM TTL(초)", "float", default=1.0,
|
||||
hint="history∩후보 정합 ON 유지 · 같은 슬롯키면 N초 RAM · 슬롯 바뀌면 즉시 DB 재조회"),
|
||||
_f("UNIVERSE_SLOT_FLIGHT_WAIT_SEC", "유니버스슬롯 flight대기(초)", "float", default=5.0,
|
||||
hint="TTL 만료 시 같은 키 DB SELECT 1회(single-flight) · 대기자 Event 상한 · "
|
||||
"분슬롯 freeze 아님"),
|
||||
_f("TICK_SELL_ENABLED", "틱매도(공통)", "bool", default=False,
|
||||
hint="ON=WS 현재가 갱신마다 매도검사(백테 틱청산에 근접) · OFF=루프(~0.1초)만 · "
|
||||
"전략별 *_TICK_SELL_ENABLED 가 비어있지 않으면 그쪽 우선 · 기본 OFF"),
|
||||
@@ -1133,14 +1191,18 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
|
||||
groups.append({
|
||||
"id": "breakout_exit",
|
||||
"title": "Optuna 청산 파라미터 (돌파)",
|
||||
"hint": "AI(Optuna)가 최적값을 찾아내는 수익/손실구간 호가매도 파라미터 모음입니다.",
|
||||
"title": "📉 매도 호가익절·손절 (EXIT_OB/STOP_OB) — 돌파",
|
||||
"hint": (
|
||||
"보유 중 청산만. 진입 호가필터(*_ORDERBOOK_FILTER_ENABLED)를 꺼도 "
|
||||
"여기 ON이면 익절/손절 호가매도는 그대로 동작. "
|
||||
"꼬리·스캘프는 스위치 없음."
|
||||
),
|
||||
"fields": [
|
||||
_f("BREAKOUT_MAX_HOLD_BARS", "최대보유(분)", "int", default=0,
|
||||
hint="0=OFF · 진입 후 N분 경과 시 max_hold 청산"),
|
||||
_f("BREAKOUT_EXIT_OB_ENABLED", "수익구간 호가매도 ON", "bool", default=False,
|
||||
_f("BREAKOUT_EXIT_OB_ENABLED", "수익구간 호가매도 ON (익절)", "bool", default=False,
|
||||
danger=True,
|
||||
hint="[주의] 꼬리잡기/스캘핑(히트앤런 단타)은 필요 없어서 스위치가 없습니다. ON=이득+매수잔량 붕괴 시 즉시 탈출"),
|
||||
hint="진입 필터와 무관 · ON=이득+매수잔량 붕괴 시 즉시 탈출"),
|
||||
_f("BREAKOUT_EXIT_OB_RATIO_MIN", "수익구간 OR_MA 임계", "float", default=0.4,
|
||||
hint="매수잔량/매도잔량 MA 미만이면 붕괴 · 예: 0.4"),
|
||||
_f("BREAKOUT_EXIT_OB_MA_WINDOW", "수익구간 OR MA 창", "int", default=5,
|
||||
@@ -1151,7 +1213,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
hint="보유 분(1분봉≈1) 미달이면 미발동"),
|
||||
_f("BREAKOUT_STOP_OB_ENABLED", "손절호가 ON", "bool", default=False,
|
||||
danger=True,
|
||||
hint="[주의] 꼬리잡기/스캘핑(히트앤런 단타)은 필요 없어서 스위치가 없습니다. ON=손해+매수잔량 붕괴 시 하드손절 전 미리 탈출"),
|
||||
hint="진입 필터와 무관 · ON=손해+매수잔량 붕괴 시 하드손절 전 미리 탈출"),
|
||||
_f("BREAKOUT_STOP_OB_RATIO_MIN", "손절호가 OR_MA 임계", "float", default=0.4,
|
||||
hint="손실구간 OR_MA 임계"),
|
||||
_f("BREAKOUT_STOP_OB_MA_WINDOW", "손절호가 OR MA 창", "int", default=5,
|
||||
@@ -1165,12 +1227,15 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
|
||||
groups.append({
|
||||
"id": "momentum_exit",
|
||||
"title": "Optuna 청산 파라미터 (모멘텀)",
|
||||
"hint": "AI(Optuna)가 최적값을 찾아내는 수익/손실구간 호가매도 파라미터 모음입니다.",
|
||||
"title": "📉 매도 호가익절·손절 (EXIT_OB/STOP_OB) — 모멘텀",
|
||||
"hint": (
|
||||
"보유 중 청산만. 진입 호가필터를 꺼도 여기 ON이면 그대로 동작. "
|
||||
"돌파 카드와 동일 개념 · 꼬리·스캘프 없음."
|
||||
),
|
||||
"fields": [
|
||||
_f("MOMENTUM_EXIT_OB_ENABLED", "수익구간 호가매도 ON", "bool", default=False,
|
||||
_f("MOMENTUM_EXIT_OB_ENABLED", "수익구간 호가매도 ON (익절)", "bool", default=False,
|
||||
danger=True,
|
||||
hint="[주의] 꼬리잡기/스캘핑(히트앤런 단타)은 필요 없어서 스위치가 없습니다. ON=이득+매수잔량 붕괴 시 즉시 탈출"),
|
||||
hint="진입 필터와 무관 · ON=이득+매수잔량 붕괴 시 즉시 탈출"),
|
||||
_f("MOMENTUM_EXIT_OB_RATIO_MIN", "수익구간 OR_MA 임계", "float", default=0.4,
|
||||
hint="매수잔량/매도잔량 MA 미만이면 붕괴 · 예: 0.4"),
|
||||
_f("MOMENTUM_EXIT_OB_MA_WINDOW", "수익구간 OR MA 창", "int", default=5,
|
||||
@@ -1181,7 +1246,7 @@ def build_live_config_groups() -> List[GroupDef]:
|
||||
hint="보유 분(1분봉≈1) 미달이면 미발동"),
|
||||
_f("MOMENTUM_STOP_OB_ENABLED", "손절호가 ON", "bool", default=False,
|
||||
danger=True,
|
||||
hint="[주의] 꼬리잡기/스캘핑(히트앤런 단타)은 필요 없어서 스위치가 없습니다. ON=손해+매수잔량 붕괴 시 하드손절 전 미리 탈출"),
|
||||
hint="진입 필터와 무관 · ON=손해+매수잔량 붕괴 시 하드손절 전 미리 탈출"),
|
||||
_f("MOMENTUM_STOP_OB_RATIO_MIN", "손절호가 OR_MA 임계", "float", default=0.4,
|
||||
hint="총사÷총팔 MA 미만이면 붕괴 · 예: 0.4"),
|
||||
_f("MOMENTUM_STOP_OB_MA_WINDOW", "손절호가 OR MA 창", "int", default=5,
|
||||
|
||||
Reference in New Issue
Block a user