fix: VI 1h 매핑 실증 반영 — active=해제시각(1224) 유무로 판정
2026-06-12 사이드카 날 VI 폭주(~1,000건) 실증 결과:
- 9068은 발동/해제가 아니라 VI 종류(1=정적, 2=동적, 3=동적+정적)
→ 구 매핑은 동적 VI를 통째로 무시하고, 해제 이벤트도 active로 덮어썼음
- 발동 이벤트는 1224(해제시각)='000000', 해제 이벤트는 시각이 참
→ active = release_time in ('','000000') 으로 교체, 1223 발동시각 추가 저장
- 1h는 구독 무관 시장 전역 broadcast임을 확인 (주석 기록)
- 실증용 raw 로그 제거 (폭주 날 ~2,000줄 — 역할 완료)
- 토스트: 발동시각 표시 추가, '000000'은 해제 표시 생략
- TTL 백스톱(_vi_expired 180s)은 해제 메시지 유실 대비로 유지
라이브 검증: 002780 동적 VI 발동(09:09:08) → active=True 정상 포착
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9464,7 +9464,8 @@ window.openPinModal = openPinModal;
|
|||||||
if(v.trigger_price) L.push('발동가: '+Number(v.trigger_price).toLocaleString()+'원');
|
if(v.trigger_price) L.push('발동가: '+Number(v.trigger_price).toLocaleString()+'원');
|
||||||
if(v.trigger_pct!=null&&v.trigger_pct!==0) L.push('발동 등락률: '+(v.trigger_pct>=0?'+':'')+v.trigger_pct+'%');
|
if(v.trigger_pct!=null&&v.trigger_pct!==0) L.push('발동 등락률: '+(v.trigger_pct>=0?'+':'')+v.trigger_pct+'%');
|
||||||
if(v.count) L.push('당일 발동: '+v.count+'회');
|
if(v.count) L.push('당일 발동: '+v.count+'회');
|
||||||
if(v.release_time) L.push('해제 예정: '+_fmtViTime(v.release_time));
|
if(v.trigger_time&&v.trigger_time!=='000000') L.push('발동시각: '+_fmtViTime(v.trigger_time));
|
||||||
|
if(v.release_time&&v.release_time!=='000000') L.push('해제: '+_fmtViTime(v.release_time));
|
||||||
head=L.join('\n')+'\n\n─────\n';
|
head=L.join('\n')+'\n\n─────\n';
|
||||||
}
|
}
|
||||||
var desc='⚡VI (변동성완화장치)\n\n주가가 짧은 시간에 급변하면 약 2분간\n단일가매매로 전환해 과열을 식히는 장치예요.\n\n• 동적VI: 직전 체결가 대비\n• 정적VI: 당일 기준가 대비\n(코스피200 3%·그 외 6% 등에서 발동)';
|
var desc='⚡VI (변동성완화장치)\n\n주가가 짧은 시간에 급변하면 약 2분간\n단일가매매로 전환해 과열을 식히는 장치예요.\n\n• 동적VI: 직전 체결가 대비\n• 정적VI: 당일 기준가 대비\n(코스피200 3%·그 외 6% 등에서 발동)';
|
||||||
|
|||||||
@@ -349,19 +349,22 @@ class RealtimeHub:
|
|||||||
'ts': datetime.now(KST).isoformat(),
|
'ts': datetime.now(KST).isoformat(),
|
||||||
}
|
}
|
||||||
elif typ == '1h': # VI 발동/해제
|
elif typ == '1h': # VI 발동/해제
|
||||||
# active 판정: 9068 VI발동구분. 해제시각(1224) 유무와 함께 실증 확인 예정(A단계).
|
# 매핑 실증 완료 (2026-06-12 사이드카 날 VI 폭주 ~1,000건 관찰):
|
||||||
# 실증 로그 — VI는 드물어 부담 없음. 2026-06-11 관찰: 발동 후 해제 1h가 안 오고
|
# - 9068 = VI 종류 (1=정적, 2=동적, 3=동적+정적) — 발동/해제 구분 아님
|
||||||
# 1224(해제시각)가 발동시각과 동일 → 읽기 시점 TTL 만료(_vi_expired)로 방어 중.
|
# - 1223 = 발동시각, 1224 = 해제시각. 발동 이벤트는 1224='000000', 해제 이벤트는 시각이 참
|
||||||
print(f'[1h raw] {code} {vals}', file=sys.stderr, flush=True)
|
# - 1h는 구독 무관 시장 전역 broadcast (모든 종목 VI가 들어옴)
|
||||||
|
# 해제 메시지 유실 대비 백스톱으로 읽기 시점 TTL(_vi_expired)은 유지.
|
||||||
kind_raw = (vals.get('9068') or '').strip()
|
kind_raw = (vals.get('9068') or '').strip()
|
||||||
|
release_t = (vals.get('1224') or '').strip()
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self._vi[code] = {
|
self._vi[code] = {
|
||||||
'active': kind_raw not in ('', '0', '2'), # ⚠️ 매핑 실증 확인 필요
|
'active': release_t in ('', '000000'), # 해제시각 없음 = 발동 중
|
||||||
'vi_gubun': kind_raw,
|
'vi_gubun': kind_raw, # VI 종류 (1정적/2동적/3동적+정적)
|
||||||
'apply_kind': (vals.get('1225') or '').strip(), # 정적/동적/동적+정적
|
'apply_kind': (vals.get('1225') or '').strip(), # 정적/동적/동적+정적
|
||||||
'trigger_price': _abs_int(vals.get('1221')),
|
'trigger_price': _abs_int(vals.get('1221')),
|
||||||
'trigger_pct': kc._to_float(vals.get('1489')),
|
'trigger_pct': kc._to_float(vals.get('1489')),
|
||||||
'release_time': (vals.get('1224') or '').strip(),
|
'trigger_time': (vals.get('1223') or '').strip(),
|
||||||
|
'release_time': release_t,
|
||||||
'direction': (vals.get('9069') or '').strip(),
|
'direction': (vals.get('9069') or '').strip(),
|
||||||
'count': kc._to_int(vals.get('1490')), # 당일 VI 발동 횟수
|
'count': kc._to_int(vals.get('1490')), # 당일 VI 발동 횟수
|
||||||
'ts': datetime.now(KST).isoformat(),
|
'ts': datetime.now(KST).isoformat(),
|
||||||
|
|||||||
Reference in New Issue
Block a user