(Vantage, NAS100.r)
나스닥100 CFD 5분봉에서 종가가 VWAP 3시그마 밖으로 나가면 반대 방향으로 들어가는 평균회귀 EA입니다. 의뢰인이 트레이딩뷰에서 보던 VWAP과 같은 값이어야 했고, 세션은 한국 시간 07:00에 시작해야 했습니다. 2026년 9월 초 납품, 데모 계좌에서 3일 실매매를 돌려 검증했습니다. 그 첫날 신호가 두 번 떴는데 둘 다 진입이 안 됐습니다. 그 얘기부터 합니다.
| 항목 | 규칙 |
|---|---|
| 진입 | M5 봉 마감 종가가 VWAP +3σ 이상이면 숏, −3σ 이하면 롱, 시장가. 고가·저가 터치는 신호가 아닙니다 |
| 익절 | 진입가에서 1σ 라인까지 거리의 90% (모드 ①) 또는 1σ~2σ 사이 90% 지점 (모드 ②) — input 선택 |
| 손절 | TP 거리와 1:1 대칭 |
| 재진입 | 보유 중 같은 신호가 또 나오면 기존 청산 후 신규 진입. 항상 1포지션 |
| 쿨다운 | 손절 후 그 방향만 60분 진입 금지. 반대 방향은 즉시 가능 |
| VWAP | 세션 앵커 VWAP + 거래량가중 표준편차(E[x²]−E[x]²). 트레이딩뷰 내장 VWAP과 같은 공식 |
TP/SL은 서버 측 포지션 속성으로 걸어 두고, 모든 조정값(랏·TP%·쿨다운·스프레드 한도)은 input과 온차트 패널 양쪽에서 바꿀 수 있습니다. 전략 테스터에서는 패널을 못 만지니 input이 단일 진실 소스이고, 라이브에서는 패널 변경값을 영속화하되 속성창에서 바꾼 값이 우선하도록 맞췄습니다.
3σ 신호가 두 번 떴고 텔레그램으로는 "진입 실패(봉 내 미체결)"만 왔습니다. 계좌에는 아무 주문도 없었습니다. EA 자체 로그를 열어 보니 이렇게 찍혀 있었습니다.
2026.09.01 16:35:00 [INFO] 📍 숏 신호 — 종가 … / +3.0σ …
2026.09.01 16:35:00 [WARN] 스프레드 180pt > 한도 100pt — 진입 보류 (봉 내 재시도)
스프레드 한도 기본값을 100포인트로 잡았는데, 그 계좌의 NAS100 평시 스프레드가 180포인트였습니다. 아시아 세션엔 1,000포인트 구간도 있었습니다.
FX 감각으로 지수 CFD의 포인트 스케일을 잡은 게 원인입니다(NAS100 1.8 인덱스 포인트 = 180 포인트).
한도를 300으로 올리고 .set 파일도 맞췄습니다. 알림에는 "스프레드가 한도보다 넓어 보류됨"처럼 사유를 붙였습니다.
차단 사유를 전부 로그로 남기는 설계 덕에 5분 만에 끝난 진단입니다.
이후 검증 사흘 동안 실제로 남은 로그 일부입니다(손익 수치는 지웠습니다).
2026.09.03 06:20:00 [INFO] 📍 숏 신호 — 종가 29204.86 / +3.0σ 29203.10 (VWAP 29152.56, σ 16.85, 64봉)
2026.09.03 06:20:00 [INFO] 🟢 진입 숏(매도) 1.00랏 @ 29204.11 | TP 29172.88 / SL 29235.34 (모드0, 90%)
2026.09.03 08:01:44 [INFO] ✅ 익절 청산 숏 @ 29172.88
2026.09.03 16:45:00 [INFO] 📍 숏 신호 — 종가 29322.82 / +3.0σ 29299.37 (VWAP 29163.30, σ 45.36, 189봉)
2026.09.03 16:45:00 [INFO] 재진입 신호 — 기존 포지션 청산
2026.09.03 16:45:00 [WARN] 스프레드 1000pt > 한도 300pt — 진입 보류 (봉 내 재시도)
2026.09.03 16:45:02 [INFO] 🟢 진입 숏(매도) 1.00랏 @ 29318.57 | TP 29219.65 / SL 29417.49
의뢰인은 KST 07:00에 VWAP을 리셋하고 09:00부터 매매하길 원했습니다. 브로커 서버 시각은 보통 GMT+2/+3이고 서머타임에 따라 바뀝니다.
라이브에서는 TimeTradeServer() − TimeGMT()를 30분 단위로 반올림해 실측하면 서머타임이 자동 반영됩니다.
문제는 전략 테스터입니다. 테스터에서는 GMT가 서버 시각으로 시뮬레이트돼 실측이 안 됩니다. 그래서 동절기 오프셋 + 미국/유럽 서머타임 규칙으로 계산하는 경로를 따로 두었습니다.
KST는 서머타임이 없으니 모든 경계를 UTC로 환산합니다(KST 07:00 = 전일 UTC 22:00). 백테스트에서도 세션 앵커가 정확히 KST 07:00에 찍히는 걸 확인했습니다.
VWAP 값이 맞는지는 EA로 EA를 검증하면 자기 검증이라, 같은 공식을 파이썬으로 따로 구현해 트레이딩뷰 / EA 패널 / 파이썬 셋을 대조했습니다. 신호 봉의 VWAP·σ·−3σ·종가가 소수 둘째 자리까지 일치했습니다.
납품 전에 독립 리뷰어 세 명(명세 적합성 / API 오용 / 상태머신 엣지)을 병렬로 돌리고 수정 후 한 번 더 돌렸습니다. 2라운드에서 1라운드 수정이 만든 회귀를 잡았습니다.
OnInit 시점엔 M5 시계열이 아직 동기화되지 않아 iClose가 0을 줄 수 있습니다. TP 계산 실패를 "구조적 이상"과 구분하지 않고 청산으로 처리하고 있었습니다. 반환값을 성공 / 데이터 미준비 / 구조적 이상 셋으로 나눠, 미준비면 다음 틱 재시도, 이상일 때만 청산합니다.OnTick 끝에 "이 EA 포지션에 TP/SL이 비어 있으면 현재 밴드로 회수"하는 감시 루프 하나를 두었습니다. 리뷰에서 나온 결함 넷이 이 하나로 해결됐습니다.DEAL_REASON_SL을 스캔해 실제 체결 시각 기준으로 쿨다운을 재구성합니다. 신호 게이트 직전에 다시 확인합니다.EXPERT라 SL 필터에 안 걸려 쿨다운이 시작되지 않았습니다. 쿨다운이 가장 필요한 급변 구간에서 빠지는 회귀. 즉시청산 분기에서 쿨다운을 직접 세팅하도록.진입 16건, 청산 15건, TP 자동 청산 3건, MT5 저널 오류 0건. 기계 검증으로 KST 07~09시 진입 0건, 동시 2포지션 0건, 재진입 12쌍 정상, TP/SL 거리비 1.000을 확인했습니다. 손익은 공개하지 않습니다. 사흘은 전략을 평가할 기간이 아니라 프로그램이 명세대로 움직이는지 볼 기간입니다.
.ex5 + .mq5 소스 + Include 5종(SessionClock · VwapEngine · TradeManager · Panel · Telegram) + .set 프리셋verify_vwap.py), 전략 불변조건 기계 검사(ref_check.py)
트레이딩뷰에서 보던 지표를 MT5에서 같은 값으로 쓰고 싶으신 분이 많습니다. 그것부터 맞춥니다.
알고랩이 24시간 빠르게 답변드립니다.