Files
shuim 9fab4018d4 fix: 프로그램 검증 루프 7회차 — 리스크·주문·청산·인프라 결함 일괄 수정 + 거래 확대 결정 반영
하네스 규칙 검사 전역 위반 117→0, 회차별 검증(code-verifier opus 4도메인)으로 Critical/High 해소.

주문·리스크
- MDD 강제축소 반복 매도(종목별 완료 집합·재시도 상한·날짜 롤오버·잔고 오류 보류·epoch·장외 미주문)
- KIS 거부 FAILED 기록, 결과 불명(전송 후) 재전송 금지·PENDING, 미전송 실패만 재시도(msg_cd 분류)
- 국내 전량·손실 매도 시장가, 부분 익절 직전 현재가, 지정가만 미체결 취소(cancel_order_v2: TR 0013U·조직번호) + 0체결 롤백
- 누적 4%·현금·레버리지(신규분 포함)·사이클 내 매수 누적, 수동매수 공용 가드(buy_guards), 수동매도 DT 차감·락
- 가드 우회 엔드포인트 차단(/recommendations/auto-trade 위임, US /execute 매수 410·매도 가드)
- 매수 슬롯=성공 매수, 평가 상한·회전, 업무거부/계좌 쿨다운, 프로세스 내 in-flight 주문 중복 차단
데이트레이딩
- 진입·청산 shield, 청산 진행 중 표식(소유 토큰), 2단계 청산 체크, 결과 불명 → 보유 감소 판정·비DT 차감 상한
- 전일 포지션 재시도(일시 실패 미산정), 분할매도 영속, ORB 구간 손절, /cycle 락, 사이클 내 현금 차감, 체결 수량 보정
스윙
- 손절 공백(판정 예외 시 하드 바닥), 단일 손절 소스·범위 검증, 매도 직전 KIS 잔고 상한(min(주문가능,보유)−DT)
- 결과 불명 체결 대조·장부 반영, 대체가(나이·진입 이후·ATR 캐시), 분할 단계 기록, 국면 실패 fail-closed
- 듀얼 플레이북·서킷브레이커 게이트, 평균회귀 우선·듀얼 독립, 시간손절 거래일
- 거래 확대(사용자 결정, 백테스트 미검증): RSI 46/35 정본 경로, 모멘텀 v2 ON, SIDEWAYS ADX AND, 트레일링 1차 익절 후, 20일 시간손절 ON
인프라·보안
- 계좌·손익 GET 인증, 세션 is_active·관리자 경로, 서명키 파생, realip, WS 토큰 마스킹
- KIS 토큰 즉시 실패(sleep 제거)·무효 시 캐시 삭제, 주문 5xx+JSON 본문 반환
- db_worker 종료 drain(멱등 재실행·커밋 불명 격리·예산·밴 커밋), stop_grace 40s, Redis 타임아웃·volatile-lru, /health DLQ·캐시
- KRX 휴장일, py3.11 비호환 f-string 수정 + Jenkins 이미지 내 compileall·헬스 실패 시 빌드 실패
하네스: rules_check 에 PEP 701 f-string 검사, 마커(allow-*), deploy 스모크 401 기준
CLAUDE.md: 실제 동작·플래그·백로그(§8.5-27~38) 갱신

backend 1451 passed / hooks 112 passed / tsc ok / py3.9 compile 0 errors

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 12:01:31 +09:00
..

Realtime Module

WebSocket 기반 실시간 시세 수신 및 이벤트 처리 모듈

⚠️ 아래 "4. 실시간 전략 실행" 예제는 더 이상 동작하지 않습니다 (2026-09-27) 예제가 쓰는 app.strategy 패키지(strategy_manager, DayTradingStrategy)는 죽은 코드로 확인되어 삭제되었습니다. 현재 전략 실행 경로는 services/swing/scheduler.py 와 services/daytrading/scheduler.py 이며, 전략 로직은 services/mean_reversion_strategy.py, services/day_trading_strategy.py 에 있습니다. CLAUDE.md §2 참고.

모듈 구조

realtime/
├── __init__.py              # 모듈 내보내기
├── websocket_client.py     # KIS WebSocket 클라이언트
├── event_handler.py        # 이벤트 핸들러 관리자
├── market_scheduler.py     # 장 스케줄 관리
├── examples.py             # 사용 예시
└── README.md

사용 방법

1. 기본 WebSocket 연결

from app.realtime import KISWebSocketClient, event_handler, EventType
from app.realtime.websocket_client import create_websocket_client

# 핸들러 등록
async def on_price_update(event_data):
    print(f"{event_data['stock_code']}: {event_data['current_price']}원")

event_handler.register(EventType.PRICE_UPDATE, on_price_update)

# WebSocket 연결
ws_client = create_websocket_client()
await ws_client.connect()

# 종목 구독
await ws_client.subscribe_price("005930")  # 삼성전자

# 메시지 수신 시작
await ws_client.listen()

2. 이벤트 핸들러

from app.realtime import event_handler, EventType

# 특정 이벤트 핸들러
async def handle_price_update(event_data):
    stock_code = event_data['stock_code']
    price = event_data['current_price']
    print(f"{stock_code}: {price}원")

event_handler.register(EventType.PRICE_UPDATE, handle_price_update)

# 글로벌 핸들러 (모든 이벤트 수신)
async def global_handler(event_type, event_data):
    print(f"[이벤트] {event_type.value}: {event_data}")

event_handler.register_global(global_handler)

# 핸들러 해제
event_handler.unregister(EventType.PRICE_UPDATE, handle_price_update)

3. 장 스케줄러

from app.realtime import market_scheduler, MarketStatus

# 현재 장 상태 확인
status = market_scheduler.get_current_status()
print(f"현재 장 상태: {status}")

# 장 개장 여부
if market_scheduler.is_market_open():
    print("장 개장 중")

# 다음 장 시작까지 남은 시간
seconds = market_scheduler.get_seconds_until_market_open()
print(f"장 시작까지 {seconds}초 남음")

# 콜백 등록
async def on_market_open():
    print("🔔 장 시작!")
    # WebSocket 연결, 구독 등

async def on_market_close():
    print("🔕 장 종료!")
    # WebSocket 연결 해제

market_scheduler.register_callbacks(
    on_open=on_market_open,
    on_close=on_market_close
)

# 스케줄러 실행
await market_scheduler.run()

4. 실시간 전략 실행

from app.realtime import event_handler, EventType
from app.strategy import strategy_manager
from app.trading import order_manager, market_data_provider

# 핸들러: 실시간 시세 → 전략 실행 → 주문
async def on_price_update(event_data):
    stock_code = event_data['stock_code']
    current_price = event_data['current_price']
    
    # 시장 데이터 구성
    market_data = {
        "current_price": current_price,
        "minute_chart": await market_data_provider.get_minute_chart(stock_code),
    }
    
    # 전략 실행
    signal = await strategy_manager.run_strategy(
        "DayTrading",
        stock_code=stock_code,
        market_data=market_data
    )
    
    # 신호 발생 시 주문
    if signal:
        await order_manager.place_order(
            stock_code=signal.stock_code,
            order_type=signal.signal_type.value,
            quantity=10,
            price=signal.price
        )

event_handler.register(EventType.PRICE_UPDATE, on_price_update)

5. 전체 시스템 통합

import asyncio
from app.realtime import event_handler, EventType, market_scheduler
from app.realtime.websocket_client import create_websocket_client
from app.strategy import strategy_manager
from app.strategy.strategies import DayTradingStrategy
from app.trading import order_manager, market_data_provider

# 1. 전략 등록
strategy = DayTradingStrategy()
strategy_manager.register_strategy(strategy)

# 2. 이벤트 핸들러
async def on_price_update(event_data):
    # ... 전략 실행 로직
    pass

event_handler.register(EventType.PRICE_UPDATE, on_price_update)

# 3. 장 스케줄러
ws_client = None

async def on_market_open():
    global ws_client
    ws_client = create_websocket_client()
    await ws_client.connect()
    
    # 관심 종목 구독
    for code in ["005930", "000660"]:
        await ws_client.subscribe_price(code)
    
    asyncio.create_task(ws_client.listen())

async def on_market_close():
    if ws_client:
        await ws_client.disconnect()

market_scheduler.register_callbacks(
    on_open=on_market_open,
    on_close=on_market_close
)

# 4. 실행
await market_scheduler.run()

주요 기능

KISWebSocketClient

  • ✅ KIS API WebSocket 연결
  • ✅ 실시간 현재가/호가 수신
  • ✅ 체결 데이터 수신
  • ✅ 종목 구독/구독해제
  • ✅ 자동 재연결
  • ✅ 이벤트 기반 데이터 전달

EventHandler

  • ✅ 7가지 이벤트 타입
    • PRICE_UPDATE: 현재가 업데이트
    • ORDERBOOK_UPDATE: 호가 업데이트
    • EXECUTION: 체결 발생
    • ORDER_CONFIRM: 주문 확인
    • ERROR: 에러
    • CONNECTED: 연결
    • DISCONNECTED: 연결 해제
  • ✅ 타입별 핸들러 등록
  • ✅ 글로벌 핸들러 (모든 이벤트)
  • ✅ 비동기 핸들러 실행
  • ✅ 에러 핸들링

MarketScheduler

  • ✅ 4가지 장 상태
    • PRE_MARKET: 장 전 (08:00~09:00)
    • MARKET_OPEN: 정규장 (09:00~15:30)
    • AFTER_MARKET: 장 후 (15:30~18:00)
    • MARKET_CLOSED: 휴장
  • ✅ 장 시작/종료 콜백
  • ✅ 남은 시간 계산
  • ✅ 자동 상태 감지

이벤트 데이터 구조

PRICE_UPDATE

{
    "stock_code": "005930",
    "stock_name": "삼성전자",
    "current_price": 75000,
    "change_rate": 1.5,
    "volume": 1000000,
    "timestamp": datetime(...)
}

EXECUTION

{
    "order_id": "0000123456",
    "stock_code": "005930",
    "executed_price": 75000,
    "executed_quantity": 10,
    "timestamp": datetime(...)
}

설치 요구사항

pip install websockets

사용 예시 파일

상세한 예시는 examples.py 참고:

  • 기본 실시간 시세 수신
  • 실시간 전략 실행
  • 장 스케줄러 활용
  • 전체 시스템 통합

Phase 3 완료 체크리스트

  • realtime/websocket_client.py 생성
  • realtime/event_handler.py 생성
  • realtime/market_scheduler.py 생성
  • realtime/examples.py 생성
  • README 문서 작성

다음 단계

  • 기존 WebSocket 코드 마이그레이션
  • API 엔드포인트 통합
  • 프론트엔드 WebSocket 연결

작성일: 2026-03-06
작성자: 서영우