ls증권 히스토리 구독 넣음
This commit is contained in:
@@ -52,8 +52,10 @@ def resolve_prev_trading_day_open(
|
||||
"""
|
||||
from kis_trader.utils.env import get_env_int
|
||||
|
||||
# 전일 시가로 인정할 최대 HHMM (기본 09:10 — 그 이후만 있으면 장시작 시가 미확정)
|
||||
open_hm_max = max(900, int(get_env_int("MOMENTUM_PREV_DAY_OPEN_HM_MAX", 910)))
|
||||
# 전일 시가로 인정할 최대 HHMM.
|
||||
# 기본 1000: 저유동 종목이 09:14 첫체결만 있어도 시가로 인정.
|
||||
# (구 910은 월요 갭 후 전일 오전 봉이 얇으면 전부 '전일시가없음'으로 매수 불가)
|
||||
open_hm_max = max(900, int(get_env_int("MOMENTUM_PREV_DAY_OPEN_HM_MAX", 1000)))
|
||||
|
||||
prev_day: Optional[str] = None
|
||||
prev_open: Optional[float] = None
|
||||
@@ -256,7 +258,18 @@ def eval_momentum_hts_buy_at_index(
|
||||
cl = float(c.get("close", 0) or 0)
|
||||
hi = float(c.get("high", cl) or cl)
|
||||
|
||||
if hm < time_start_hm or hm >= time_end_hm:
|
||||
# 해외 US: params._session_wrap_midnight 로 자정 넘김 RTH 허용 (국내는 기존과 동일)
|
||||
from kis_trader.utils.session_hm import hm_in_trading_window
|
||||
_wrap = bool(params.get("_session_wrap_midnight"))
|
||||
if not hm_in_trading_window(hm, time_start_hm, time_end_hm, wrap_midnight=_wrap):
|
||||
# 국내는 장중 루프에서 흔한 silent skip. 해외는 세션 키 오설정 디버깅용으로 탈락 표기.
|
||||
if str(params.get("market") or "").strip().upper() == "US":
|
||||
return (
|
||||
"탈락-시간외",
|
||||
"hm=%04d not in %d~%d (wrap=%s)"
|
||||
% (hm, time_start_hm, time_end_hm, _wrap),
|
||||
None,
|
||||
)
|
||||
return (None, None, None)
|
||||
|
||||
if use_defense and cl < min_price:
|
||||
@@ -275,8 +288,49 @@ def eval_momentum_hts_buy_at_index(
|
||||
prev_open = resolve_prev_trading_day_open(candles, i, day)
|
||||
|
||||
# kiwoom momentum SCAN — E∧F∧H∧I 이미 통과, TRIGGER 는 타이밍·호가·휩쏘만
|
||||
# ※ 해외(US)는 HTS SCAN 이 없으므로 skip_hts 숏컷으로 매 봉 시그널 내면 안 됨
|
||||
# → V4 추격 패턴(돌파 OR 눌림재돌파) + RSI 하한.
|
||||
if skip_hts:
|
||||
sig_hts: Dict[str, Any] = {
|
||||
is_us = str(params.get("market") or "").strip().upper() == "US"
|
||||
if is_us:
|
||||
from kis_trader.engine.momentum_chase_patterns import eval_momentum_chase_pattern
|
||||
ok_pat, pat_name, metrics = eval_momentum_chase_pattern(candles, i, params)
|
||||
if not ok_pat:
|
||||
return (
|
||||
"탈락-패턴",
|
||||
"추격패턴 미충족 (%s) close=%.4f" % (pat_name or "?", cl),
|
||||
None,
|
||||
)
|
||||
rsi_val: Optional[float] = None
|
||||
if compute_rsi_series_fn is not None:
|
||||
closes = [float(x["close"]) for x in candles]
|
||||
ic = params.get("_indicator_cache")
|
||||
if ic is not None and hasattr(ic, "rsi_at"):
|
||||
rsi_val = ic.rsi_at(i, rsi_period)
|
||||
else:
|
||||
rsis = compute_rsi_series_fn(closes, rsi_period)
|
||||
rsi_val = rsis[i] if i < len(rsis) else None
|
||||
if rsi_val is None:
|
||||
return ("탈락-RSI없음", "RSI 미계산", None)
|
||||
if rsi_val < rsi_min:
|
||||
return ("탈락-RSI약함", "RSI=%.1f < %.0f" % (rsi_val, rsi_min), None)
|
||||
use_rsi_max = _to_bool(params.get("use_rsi_max_filter"), False)
|
||||
if use_rsi_max and rsi_val > rsi_max:
|
||||
return ("탈락-RSI과열", "RSI=%.1f > %.0f" % (rsi_val, rsi_max), None)
|
||||
sig_hts: Dict[str, Any] = {
|
||||
"signal": True,
|
||||
"mode": "us_momentum_chase",
|
||||
"pattern": pat_name or "chase",
|
||||
"signal_candle_time": c.get("candle_time"),
|
||||
"prev_day_open": prev_open,
|
||||
}
|
||||
if metrics:
|
||||
sig_hts.update(metrics)
|
||||
if rsi_val is not None:
|
||||
sig_hts["rsi"] = rsi_val
|
||||
return (None, None, sig_hts)
|
||||
|
||||
sig_hts = {
|
||||
"signal": True,
|
||||
"mode": "momentum_hts",
|
||||
"pattern": "momentum_hts_scan",
|
||||
|
||||
Reference in New Issue
Block a user