KIS Flow Agent US

미국 주식 — 장중 VWAP 돌파 단일전략 (Phase 2, WS 없이 REST 폴링)
연결 대기

오늘 리스크

보유 포지션

엔진 상태

상단 요약

매매 전략 요약
장중 VWAP 돌파 1종만 구현(종가 스윙은 다음 단계 과제). 진입 4단계 — L0 시장게이트(SPY 시가 대비 하회/패닉) → L2 VWAP 돌파(+0.3%) → L3 거래량서지 (직전 20분 평균×3.0) → L4 vol_power_proxy(§11, KR 프로그램순매수의 완전한 대체 아님 — 미검증 지표, 섀도우 기간 실측 필요). 청산은 KR판 "B안"과 동일 원리: EOD 강제청산(15:55 NY) → 고정손절 (−3%) → 고정익절(+2%, 전량) → VWAP 이탈(완결봉 기준). ATR 트레일·본전손절·부분익절 없음(§7 결론)
유니버스
매일 run.py universe 실행 시 거래소별 시가총액순위(KIS HHDFS76350100)로 베이스풀을 뽑고, PTP(원천징수 대상) 종목 제외 + 주간거래 가능여부 보강 후 시총 내림차순으로 저장. 이 화면의 감시 종목은 그중 상위 종목만 표시
누적 실현손익
orders 테이블의 체결 기록만으로 종목별 FIFO 매칭해 대시보드가 직접 근사 계산(별도 손익 원장이 없음 — 이 시스템은 분할매매를 하지 않는 게 원칙이라 FIFO 근사와 실제값이 대체로 일치할 것으로 기대되나, 수수료·세금은 반영되지 않은 세전 근사치)
총 매입금액 / 총 평가손익 / 총 수익률
보유 종목 전체 합산. 총 매입금액=평단가×수량의 합, 총 평가손익=(현재가−평단가)×수량의 합, 총 수익률=(누적 실현손익+총 평가손익)÷총 매입금액×100 — 계좌 실잔고/평가자산 API는 조회하지 않음(엔진의 폴링 주기와 겹쳐 API 레이트리밋을 유발할 수 있어 KR판과 같은 이유로 회피, price_snapshot에 남은 마지막 시세만 사용)
보유 / 오늘 진입 / 오늘 청산 / 감시
보유=현재 포지션 수/max_positions 설정값. 오늘 진입=당일(NY) 채택된 breakout 시그널 수. 오늘 청산=당일 발생한 청산 시그널(EOD/손절/익절/VWAP/ 킬스위치/강제매도) 합계. 감시=화면에 표시된 워치리스트 종목 수/오늘 유니버스 전체 종목 수

오늘 리스크

당일 손익 / 고점 대비 낙폭(MDD)
당일 실현손익(FIFO 근사) + 보유 종목 평가손익의 합을 엔진이 하트비트마다(포지션 폴링 주기, 기본 10초) 계산해 기록. 그날 고점 대비 얼마나 빠졌는지가 낙폭 — KR판과 동일 원리지만, 계좌 잔고 API를 새로 조회하지 않고 이미 갖고 있는 주문·시세 데이터만으로 근사한다는 점이 다름(세전, API 레이트리밋 회피)
킬스위치
낙폭이 risk.equity_base_usd(대시보드 설정값 참고 — 이 봇에 배정한 실제 자본으로 config.yaml에서 반드시 맞출 것) 대비 risk.daily_mdd_kill_pct (기본 3%)를 넘으면 그 시점에 한 번 발동. 발동 즉시 신규 진입을 전면 차단하고 보유 종목을 전량 강제청산(exit_kill)하며, 다음 NY 거래일이 시작될 때까지 계속 유지됨(재발동 없음, 리셋만)

보유 포지션 카드

청산 트랙 (막대)
고정 손절가·진입가·고정 익절가 위치와 현재가(점)를 한 줄에 표시. KR판과 달리 ATR 트레일·최고가 기준선이 없음(§7 결론 — 미국판은 단순 고정 브래킷만 사용). 점이 빨간 구간에 가까울수록 손절에 가까움
매입금액 / 평가손익
매입금액=평단가×수량, 평가손익=(현재가−평단가)×수량 — 상단 "평가금액"(현재가×수량)과 별개로 실제 손익 규모를 달러로 바로 확인 가능
VWAP 이탈 재트리거 방지
당일 VWAP 이탈 청산이 한 번 시도되면 같은 포지션에 다시 걸리지 않도록 표시(partials에 "vwap" 마킹) — 실제로는 이 시스템이 전량 청산 원칙이라 재트리거 방지 자체가 사실상 작동할 일이 드묾
강제매도 버튼
누르면 확인창 후 manual_exit_requests 테이블에 요청을 적재만 함 — 대시보드가 직접 주문을 내지 않고, 엔진 프로세스가 다음 판단주기(최대 position_poll_interval_sec, 기본 10초)에 읽어서 다른 모든 조건보다 우선해 실제로 청산(exit_manual)을 실행. dry_run이면 여기서도 실주문은 안 나가고 기록만 됨(oms_us.py의 dry_run 게이트가 이 경로에도 동일하게 적용)

엔진 상태 카드

하트비트
엔진 메인 루프가 마지막으로 정상 순회한 시각. 3분 이상 없으면 "정지"로 표시 (엔진 프로세스가 죽었거나 예외로 멈췄을 가능성 — 대시보드는 별도 프로세스라 계속 뜸, fail-open)
유니버스
오늘 run.py universe가 실행되어 DB에 유니버스가 저장됐는지
시장 게이트(SPY)
L0 필터의 실시간 상태 — SPY가 시가 대비 하회(버퍼 0.15%) 또는 전일比 패닉 문턱(−0.8%) 이하면 "차단 중"(신규 진입 안 함). 엔진 하트비트 주기마다 갱신되며, 엔진이 정지 상태면 이 값도 갱신되지 않음(하트비트 시각 참고)
워치리스트 로드
엔진이 메모리에 들고 있는 감시종목 수(engine_state, 하트비트 때 기록) — 2026-09-19부터 NY 거래일이 바뀔 때마다 그날 유니버스로 자동 재로드됨(예전엔 엔진 시작 시 1회만 로드하고 거래일이 바뀌어도 재로드하지 않던 제한이 있었음). DB 유니버스 개수와 계속 다르면 엔진이 재시작되지 않고 있다는 뜻

매도 종류 (시그널/주문에 표시)

고정 익절 / 고정 손절
+2%에서 전량 익절, −3%에서 전량 손절(고정값, ATR·본전방어· 트레일 전혀 없음 — 사이징도 이 고정폭을 기준으로 계산돼 서로 어긋나지 않음). 미검증 임시값
VWAP 이탈
당일 진입 종목의 완결된 1분봉 종가가 거래량가중평균가×0.997 아래로 마감하면 지정가 매도(시장가 전환 없음 — §7 결론상 이 시스템은 시장가 주문을 아예 쓰지 않음)
장마감 청산(EOD)
뉴욕시간 15:55 도달 시 다른 조건보다 우선해서 보유 종목 전량 강제청산 — 오버나잇 리스크를 원천 차단
일중 MDD 킬스위치
당일 손익이 고점 대비 기준치 이상 빠지면 계좌 단위로 발동해 보유 종목 전량 강제청산(위 "오늘 리스크" 참고) — 개별 종목 조건과 무관하게 발동
대시보드 강제매도
사용자가 포지션 카드의 강제매도 버튼을 눌러 수동으로 요청한 청산 — 다른 모든 조건보다 우선 처리됨

알려진 제한 사항

vol_power_proxy 미검증
L4 조건에 쓰이는 이 지표는 KR판 "프로그램 순매수"의 완전한 대체가 아닌 새로 설계된 근사치 — 섀도우 운영 기간 실측으로 유효성을 검증해야 함(§11). 이건 코드로 "적용"할 수 있는 항목이 아니라, 실제 시장 데이터가 쌓여야 판단 가능한 부분
일중 MDD 계산은 계좌 실잔고 기준이 아님
API 레이트리밋 회피 때문에(§8, KR판과 동일 이유) 계좌 잔고를 직접 조회하지 않고 orders 테이블 FIFO 근사 + 보유종목 평가손익만으로 계산함 — 수수료·세금·배당 등은 반영 안 된 근사치. 실제 계좌 손익과는 소폭 차이가 날 수 있음
equity_base_usd는 사용자가 직접 설정해야 함
이 봇에 실제로 배정한 자본을 config.yaml의 risk.equity_base_usd에 반드시 맞출 것 — 기본값(10000)은 예시일 뿐이라, 실제 배정액과 다르면 킬스위치 발동 시점(MDD %)이 부정확해짐