121 lines
5.1 KiB
Python
121 lines
5.1 KiB
Python
"""
|
|
ws_price_validation: KIS 틱 vs 키움 틱 빈도(age) 비교
|
|
kis_age_ms = 마지막 KIS 시세가 얼마나 오래됐나 (낮을수록 더 자주 옴)
|
|
kiwoom_age_ms = 마지막 키움 시세가 얼마나 오래됐나
|
|
"""
|
|
import sys
|
|
sys.path.insert(0, "/home/hoon/kis_bot")
|
|
from database import TradeDB
|
|
|
|
db = TradeDB()
|
|
ts_from = "2026-08-07 09:00:00"
|
|
|
|
try:
|
|
print(f"\n{'='*65}")
|
|
print(f" KIS 시세 vs 키움 시세 틱 빈도 비교 (ws_price_validation)")
|
|
print(f"{'='*65}")
|
|
print(f" ※ age_ms = 마지막 시세 수신 후 경과 시간(ms)")
|
|
print(f" 낮을수록 더 자주(빠르게) 틱이 오는 것\n")
|
|
|
|
# 전체 평균 비교
|
|
r = db.conn.execute(
|
|
"SELECT "
|
|
" COUNT(*) as total, "
|
|
" SUM(kis_age_ms IS NOT NULL) as kis_cnt, "
|
|
" SUM(kiwoom_age_ms IS NOT NULL) as kw_cnt, "
|
|
" AVG(kis_age_ms) as avg_kis, "
|
|
" AVG(kiwoom_age_ms) as avg_kw, "
|
|
" MIN(kis_age_ms) as min_kis, "
|
|
" MIN(kiwoom_age_ms) as min_kw, "
|
|
" MAX(kis_age_ms) as max_kis, "
|
|
" MAX(kiwoom_age_ms) as max_kw "
|
|
"FROM ws_price_validation "
|
|
"WHERE ts >= %s AND (kis_age_ms IS NOT NULL OR kiwoom_age_ms IS NOT NULL)",
|
|
(ts_from,)
|
|
).fetchone()
|
|
d = dict(r)
|
|
|
|
total = d["total"] or 0
|
|
kis_cnt = int(d["kis_cnt"] or 0)
|
|
kw_cnt = int(d["kw_cnt"] or 0)
|
|
avg_kis = d["avg_kis"] or 0
|
|
avg_kw = d["avg_kw"] or 0
|
|
|
|
print(f"[ 전체 집계 (9시 이후) ]")
|
|
print(f" 총 비교 이벤트 : {total:,}건")
|
|
print(f" KIS 시세 있는 건 : {kis_cnt:,}건 ({kis_cnt/total*100:.1f}%)")
|
|
print(f" 키움 시세 있는 건: {kw_cnt:,}건 ({kw_cnt/total*100:.1f}%)")
|
|
|
|
print(f"\n[ 시세 나이(age) 비교 — 낮을수록 빠른 틱 ]")
|
|
print(f" {'구분':<12} | {'평균 age(ms)':>12} | {'최소(ms)':>9} | {'최대(ms)':>9}")
|
|
print(f" {'-'*52}")
|
|
print(f" {'KIS':<12} | {avg_kis:>12.0f} | {d['min_kis'] or 0:>9.0f} | {d['max_kis'] or 0:>9.0f}")
|
|
print(f" {'키움':<12} | {avg_kw:>12.0f} | {d['min_kw'] or 0:>9.0f} | {d['max_kw'] or 0:>9.0f}")
|
|
|
|
if avg_kis > 0 and avg_kw > 0:
|
|
ratio = avg_kw / avg_kis
|
|
faster = "KIS" if avg_kis < avg_kw else "키움"
|
|
print(f"\n 비율 (키움age / KIS age): {ratio:.2f}배")
|
|
print(f" → {faster}가 더 자주 틱이 옵니다!")
|
|
if ratio >= 4:
|
|
print(f" ✅ KIS가 키움보다 약 {ratio:.1f}배 빠름 → KIS로 시세 구독 전환 권장!")
|
|
elif ratio >= 2:
|
|
print(f" ⚠️ KIS가 약 {ratio:.1f}배 빠름 → 전환 고려할 수준")
|
|
elif ratio >= 0.8:
|
|
print(f" ➡️ KIS/키움 거의 동등 ({ratio:.1f}배) → 굳이 전환 불필요")
|
|
else:
|
|
print(f" ❌ 키움이 더 빠름 → KIS 전환 불필요")
|
|
|
|
# 두 값이 모두 있는 케이스만 정밀 비교
|
|
print(f"\n[ 양측 모두 있는 케이스만 비교 ]")
|
|
r2 = db.conn.execute(
|
|
"SELECT COUNT(*) as cnt, "
|
|
"AVG(kis_age_ms) avg_kis, AVG(kiwoom_age_ms) avg_kw, "
|
|
"AVG(kiwoom_age_ms - kis_age_ms) as avg_diff "
|
|
"FROM ws_price_validation "
|
|
"WHERE ts >= %s AND kis_age_ms IS NOT NULL AND kiwoom_age_ms IS NOT NULL",
|
|
(ts_from,)
|
|
).fetchone()
|
|
d2 = dict(r2)
|
|
cnt2 = d2.get("cnt") or 0
|
|
avg_diff = d2.get("avg_diff") or 0
|
|
print(f" 양측 동시 존재 : {cnt2:,}건")
|
|
print(f" KIS 평균 age : {d2.get('avg_kis') or 0:.0f}ms")
|
|
print(f" 키움 평균 age : {d2.get('avg_kw') or 0:.0f}ms")
|
|
print(f" 차이 (키움-KIS) : {avg_diff:+.0f}ms ({'KIS가 더 빠름' if avg_diff > 0 else '키움이 더 빠름'})")
|
|
|
|
# 종목별 KIS vs 키움 상위 5종목
|
|
print(f"\n[ 종목별 평균 age 비교 상위 10 ]")
|
|
rows = db.conn.execute(
|
|
"SELECT code, "
|
|
"AVG(kis_age_ms) avg_kis, AVG(kiwoom_age_ms) avg_kw, COUNT(*) cnt "
|
|
"FROM ws_price_validation "
|
|
"WHERE ts >= %s AND kis_age_ms IS NOT NULL AND kiwoom_age_ms IS NOT NULL "
|
|
"GROUP BY code HAVING cnt >= 10 "
|
|
"ORDER BY cnt DESC LIMIT 10",
|
|
(ts_from,)
|
|
).fetchall()
|
|
print(f" {'종목':<10} | {'KIS(ms)':>7} | {'키움(ms)':>7} | {'차이(ms)':>8} | {'건수':>5}")
|
|
print(f" {'-'*50}")
|
|
for row in rows:
|
|
d3 = dict(row)
|
|
diff = (d3.get("avg_kw") or 0) - (d3.get("avg_kis") or 0)
|
|
print(f" {d3['code']:<10} | {d3.get('avg_kis') or 0:>7.0f} | {d3.get('avg_kw') or 0:>7.0f} | {diff:>+8.0f} | {d3['cnt']:>5}")
|
|
|
|
# 결론
|
|
print(f"\n{'='*65}")
|
|
print(f" 결론 및 시세 구독 전환 권고")
|
|
print(f"{'='*65}")
|
|
if avg_kis > 0 and avg_kw > 0:
|
|
ratio = avg_kw / avg_kis
|
|
if ratio >= 2:
|
|
print(f" ✅ KIS 시세가 키움보다 평균 {ratio:.1f}배 빠름")
|
|
print(f" → KIS WebSocket으로 시세 구독 전환을 권장합니다!")
|
|
print(f" → 특히 스캘핑·돌파 전략의 타점 정밀도가 올라갑니다.")
|
|
else:
|
|
print(f" ➡️ KIS({avg_kis:.0f}ms) vs 키움({avg_kw:.0f}ms): 차이 {ratio:.1f}배 수준")
|
|
print(f" → 굳이 시세 구독을 전환할 만큼 압도적 차이는 아닙니다.")
|
|
|
|
finally:
|
|
db.close()
|