← 목록
한선씨 2026-08-01 18KB 읽기 18분

NT8 UltTripleSyncPro_v2 → 한선씨 이식 설계

2026-08-01. NinjaTrader 8용으로 실사용 중인 3TF 동조 전략의 신호 생성 로직을 맥 네이티브(한선씨/TOAU)로 이식하기 위한 설계·매핑·정직도 표기.
>
구현 산출물: /Users/ef/CrownyDoc/projects/kps-trading-tool/전략트리플싱크.한선 (컴파일 CROWNY_STRICT=1 경고 0 / 자체시험 21건 전건 PASS / 주문·실행 호출 0)

0. 원본 파일과 확보 범위

원본경로소스 확보
전략crowny-trading/ninjatrader/Strategies/UltTripleSyncPro_v2.cs (992줄)✅ 전문
SMC 오더블록 인디케이터UltSMCOrderBlocks_260503.zip → Indicators/UltSMCOrderBlocks.cs (332줄)✅ 전문
칼만 인디케이터UltKalmanV2_260430.zip → UltKalmanV2_260430.cs + .dll⚠️ .cs는 NinjaScript 생성 래퍼뿐, 실제 알고리즘은 DLL 안(비공개)
NT8 Add-Onninjatrader/CrownyAddon/CrownyAddon.cs (578줄)✅ 전문 — 신호 로직 없음(감시·리스크게이트·텔레그램·UI 전용)
따라서 이 이식에서 "확인됨"은 전략 결합식 + SMC 오더블록 전부, "미확인"은 칼만 내부 재귀식과 PP 산출식이다. 아래 §4에 미확인 항목만 따로 모았다.


1. 전략 골자 — 수식 수준

1.1 3 타임프레임 구성

TFNT8 데이터시리즈역할
TF1주 차트(BarsArray[0], 틱)트리거 — 칼만 상태전환 / 신규 OB
TF2AddDataSeries(Tick, 512)필터(스티키) — 칼만·OB 상태가 같은 방향이어야 통과
TF3AddDataSeries(Minute, 1)필터(스티키)
TF2/TF3는 각자의 OnBarUpdate 분기에서 상태만 갱신하고 즉시 return → 값이 다음 TF1 봉까지 유지(스티키)된다.

1.2 칼만 상태 전이 (원본 UpdateKalmanState, 992줄본 580–599)

입력: shortK0 = Values[1][0](단기 칼만 현재), shortK2 = Values[1][2](단기 2봉 전), longK0 = Values[0][0](장기 칼만 현재), isPPUp = Values[2][0] ≠ 0/NaN, isPPDown = Values[3][0] ≠ 0/NaN.

가드:  CurrentBar < 5              → 상태 갱신 안 함(직전 상태 유지)
가드:  shortK0/longK0 가 NaN 또는 0 → 갱신 안 함
trendUp := shortK0 > longK0

  trendUp ∧ (shortK0 > shortK2)   → 상태 = +1 (롱)
¬ trendUp ∧ (shortK0 < shortK2)   → 상태 = -1 (숏)
그 외:  isPPUp   → +1
        isPPDown → -1
        아니면   →  0 (중립)

주의: 두 주분기 어느 쪽도 아닐 때만 PP가 개입하는 폴백 구조다(PP가 주신호가 아님).

1.3 OB(오더블록) 상태 (원본 UpdateSMCState, 601–624) — TF2/TF3용

currBull := i=0..3 중 NearestBullOB_Bottom[i] > 0 인 최초값 (없으면 0)
currBear := i=0..3 중 NearestBearOB_Top[i]   > 0 인 최초값 (없으면 0)

상태 == 0 이면:  currBull>0 → +1,  아니면 currBear>0 → -1
newBull := currBull>0 ∧ currBull ≠ lastBull    → 참이면 상태 = +1
newBear := currBear>0 ∧ currBear ≠ lastBear    → 참이면 상태 = -1
currBull>0 → lastBull = currBull ;  currBear>0 → lastBear = currBear

즉 OB 상태는 한 번 켜지면 반대 신규 OB가 나올 때까지 유지되는 래치다(중립으로 되돌아가지 않음).

1.4 TF1 신규 OB 판정 (원본 795–808) — TF2/TF3와 규칙이 다름

scanBull := i=0..3 중 첫 양수 NearestBullOB_Bottom[i]
isNewBullOB := (lastBullOB_TF1 ≠ 0) ∧ (scanBull > 0) ∧ (scanBull ≠ lastBullOB_TF1)
(숏 대칭: scanBear / NearestBearOB_Top)

lastBullOB_TF1 ≠ 0 조건 때문에 세션 최초 OB는 트리거가 되지 않는다(직전 기준값이 있어야 "갱신"으로 인정). 이식본도 그대로 재현했다.

1.5 진입 결합식 (원본 783–836) — 이식의 핵심

tf2_Long  := ¬use_tf2 ∨ ((¬TF2_UseKalman ∨ kState_TF2 == +1) ∧ (¬TF2_UseSMC ∨ obState_TF2 == +1))
tf3_Long  := (동형)
kalmanTurnedLong  := (kState_TF1 == +1) ∧ (prev_kState_TF1 ≠ +1)      // 봉 시작 시점 스냅샷과 비교
triggerLong := (TF1_UseKalman ∧ kalmanTurnedLong) ∨ (TF1_UseSMC ∧ isNewBullOB)

진입롱  ⟸ tf2_Long ∧ tf3_Long ∧ triggerLong
진입숏  ⟸ tf2_Short ∧ tf3_Short ∧ triggerShort     (롱이 우선 — else-if)

사유 문자열도 3분기 그대로: [TF1 칼만 + 롱 OB 갱신] / [TF1 칼만 롱 전환] / [TF1 롱 OB 갱신].

1.6 진입 전 통과해야 하는 게이트 (원본 739–781, 순서대로)

수동청산요청 없음IsStrategyEnabled¬일일한도도달¬하드킬존거래시간 내(현재봉시각 − 마지막청산시각) > EntryResumeSeconds(3초)포지션 플랫¬복구중(재연결 후 20봉).

이 게이트들은 운영 상태기계이지 신호가 아니다 → 이식 1단계 범위에서 제외(§3 매핑표 참조).

1.7 SMC 오더블록 산출 (UltSMCOrderBlocks.cs — 확인됨, 1:1 이식)

프랙탈(3봉 모드, 기본값)

isFractalHigh := High[1] > High[0] ∧ (High[2] < High[1] ∨ (High[2]==High[1] ∧ High[3]<High[2]))
isFractalLow  := Low[1]  < Low[0]  ∧ (Low[2]  > Low[1]  ∨ (Low[2]==Low[1]   ∧ Low[3] >Low[2]))
저장값 = High[1] / Low[1] (off=1), 최대 10개 FIFO

돌파 → OB 생성 (기준 BreakType=Close) 불(Bullish) OB는 프랙탈 고점을 종가가 상향 돌파할 때 만들어진다:

Close[0] > 프랙탈고값 이면:
  k = 0..99 (그리고 Time[k] ≥ 프랙탈시각):
      bullishGap := (Close[k+1] > High[k+2]) ∧ (Low[k] > High[k+2])   → gIdx = k+2   (마지막=가장 과거 갭이 남음)
      if Close[k] < Open[k] ∧ Low[k] < min  → idx = k, min = Low[k]   (구간 내 최저저가 음봉)
  FVG 필터(기본 ON): gIdx > 0 ∧ 0 ≤ idx-gIdx ≤ FvgDistance(3)
  OB: Top = Open[idx] (Body 모드) , Bottom = Low[idx] , IsBullish = true
베어 OB는 프랙탈 저점 하향 돌파 시 대칭(단 if(bearishGap && High[k]>max) gIdx=k+2 — 원본 베어 분기에만 High[k]>max 조건이 함께 붙어 있다. 이식본은 이 비대칭을 그대로 두지 않고 불 분기와 동일한 형태로 정규화했다 → §4-C 차이표 참조).

미티게이션 / 최근 OB

불 OB:  Low[0]  ≤ Top ∧ Low[0]  ≤ Bottom   → mitigated
베어 OB: High[0] ≥ Bottom ∧ High[0] ≥ Top   → mitigated
보유 상한 MaxOBs=30 초과 시 가장 오래된 것부터 제거
NearestBullOB_Bottom = 미티 안 된 불 OB 중 |Close[0] − Bottom| 최소인 것의 Bottom
NearestBearOB_Top    = 미티 안 된 베어 OB 중 |Close[0] − Top|    최소인 것의 Top


2. 한선씨 구현 구조

파일: kps-trading-tool/전략트리플싱크.한선 (11,852 큐브)

함수역할
칼만1차채움(관측, 개수, Q, R, 출력)1차원 칼만 — 정수 스케일. 재호출 안전(호출자 버퍼)
칼만1차(관측, Q, R)스펙 시그니처 래퍼. 공유 버퍼 칼만출력 반환
ATR채움 / PP채움ATR(10) 정수 SMA + 피벗포인트 밴드 → 버퍼PP ∈ {+1,0,-1}
칼만상태판정(봉배열)§1.2 전이식 그대로 → [현재상태, 직전봉상태]
오더블록탐지(봉배열)§1.7 전체 + §1.3/§1.4 → [OB상태, 신규불, 신규베어, 최근불바텀, 최근베어탑, 활성OB수]
TF필터(봉배열, 기간)기간>1이면 OHLC 리샘플 후 → [칼만상태, OB상태]
트리플결합(k1,k1직전,신규불,신규베어,k2,ob2,k3,ob3)§1.5 결합식 (순수 함수)
트리플싱크판정(TF1봉,TF2봉,TF3봉)위를 엮은 최종 판정 → [행동, 방향, 사유, 발화]
파라미터 블록(파일 상단 집약): 칼만Q단=40 · 칼만Q장=6 · 칼만R=1000 · PP피벗기간=2 · PPATR기간=10 · PPATR팩터백=300 · OB룩백=100 · OB최대유지=30 · FVG필터=1 · FVG거리=3 · OB스캔깊이=3 · TF1/2/3기간 · 쿨다운초=3

정수 전용(float 금지) 설계

  • 가격은 정수 틱. 칼만 내부 상태는 ×1000 밀리스케일 정수.
  • 칼만 이득 K는 ×1000 고정소수점: K = Pp*1000/(Pp+R), x += K*(z−x)/1000, P = (1000−K)*Pp/1000.
  • crownyc 나눗셈은 자연반올림(floor 아님)이므로 전 구간을 자체 나누기(a,b) 절단 나눗셈 헬퍼로 통과시킨다(부호 분리 후 보정 루프).
  • 중간곱 최대치는 5e8 수준 → 3^24 오버플로 및 2.147e9 문자열핸들 충돌지대 모두 회피.

회피한 VM 함정 (실제로 물렸거나 예방한 것)

  • 함수 반환 배열/지역 배열 재사용 함정 → 결과는 전부 최상위 사전할당 전역 버퍼 + 설정()으로 처리.
  • 그리고 안에서 사용자 함수 2회 이상 인라인 호출 → 봉 접근값을 전부 변수 선캡처 후 비교.
  • 배열 1023칸 상한 → 봉배열 평탄 4필드 구성으로 최대 200봉(=800칸)으로 명시 제한.
  • 루프 카운터는 bare 증가(i = i + 1), 비교식 변수 대입 금지, 주석은 파일 헤더에만.
  • 자체시험은 env SELFTEST=1 게이트 — 가져오기 시 오염되지 않음.

3. NT8 의존 요소 → 한선씨 대체 1:1 매핑

#NT8 요소정체한선씨 대체상태
1UltKalmanV2 Values[0]/[1]장기/단기 칼만 라인칼만1차채움(…, 칼만Q장/칼만Q단, 칼만R, …)⚠️ 근사
2UltKalmanV2 Values[2]/[3]PP 상승/하락 라인PP채움() — 피벗(2) + ATR(10)×3.0 밴드⚠️ 근사
3UltSMCOrderBlocks.NearestBullOB_Bottom/BearOB_Top최근접 미티 안 된 OB오더블록탐지() 전체 이식✅ 확인
4AddDataSeries(Tick,512) / (Minute,1)상위 TF 시리즈TF필터(봉배열, 기간) + 봉묶기() OHLC 리샘플✅ 등가(단 §4-D)
5ATR 내장인디케이터ATR채움() — TR max 3식 + 정수 SMA✅ 확인(단 NT8 ATR 기본은 Wilder EMA → §4-B)
6CurrentBar / Time[i] / High[i] 역인덱스바 접근정인덱스 평탄배열 + 봉고/봉저/봉시/봉종✅ 등가
7EnterLong/EnterShort/SetStopLoss/SetProfitTarget주문이식 안 함(판정만) — 상위 실행기 책임의도적 제외
8Position/Account/GetRealizedPnL/일일한도계좌·리스크기존 자산 kps_상태기계.한선·kps_사이징.한선·kps_라이브락_엣지.한선재사용 예정
9Watchdog·연결복구·Heartbeat·텔레그램·WPF UI운영 안전장치kps_허브.한선·세션감시.한선·폰푸시채널.한선 계열범위 밖
10세션시간/하드킬/일일리셋(시·분 정수 비교)스케줄 게이트kps_상태기계.한선 가드 슬롯으로 흡수범위 밖

4. 미확인 / 근사 구현 목록 (정직 표기)

A. 칼만 재귀식 — 미확인, 근사 구현

  • 아는 것: 호출 시그니처 UltKalmanV2(bars, shortLen=50, longLen=120, candleColor=true, pivotPeriod=2, atrFactor=3.0, atrPeriod=10, showKalmanLines, showPPLines). DLL 문자열에서 확인한 플롯/속성 라벨: 1. Short Length, 2. Long Length, 1. PP Pivot Period, 2. PP ATR Factor, 3. PP ATR Period, 플롯 4개(0=장기,1=단기,2/3=PP), 내부 cacheATR 사용.
  • 모르는 것: 프로세스잡음 Q·측정잡음 R을 shortLen/longLen에서 어떻게 유도하는지, 상수속도(위치+속도 2상태) 모델인지 상수위치(1상태)인지, 관측이 Close인지 HL2/Typical인지.
  • 근사 방식: 관측 = 종가, 모델 = 1상태 상수위치 칼만, R 고정(1000)에 Q만 단기/장기로 나눠 반응속도를 벌린다(Q단=40, Q장=6). 정상상태 이득은 K ≈ (√(Q²+4QR) − Q)/(2R) 꼴로 수렴 — 길이 파라미터 대신 Q/R 비가 평활 강도를 정한다.
  • 한계: 두 라인의 교차 시점·기울기 반응이 원본과 봉 단위로 어긋날 수 있다. 즉 kalmanTurnedLong 발생 봉이 원본과 다를 수 있고, 이는 진입 시점 차이로 직결된다. Q단/Q장은 백테스트로 원본 상태열에 맞춰 캘리브레이션해야 하는 값이지 검증된 값이 아니다.
  • 해소 방법(권장 순): ① NT8에서 두 칼만 라인을 CSV로 export → 같은 봉 입력으로 이식본과 상태열 일치율 측정 → Q 그리드 탐색 ② 그래도 안 맞으면 DLL IL 디컴파일 검토 ③ 원저자 소스 확보.

B. PP(피벗포인트) 라인 — 미확인, 근사 구현

  • 아는 것: 파라미터가 PivotPeriod=2, AtrFactor=3.0, AtrPeriod=10이고 상승/하락 두 플롯으로 나온다는 것. → 통칭 Pivot Point SuperTrend 계열로 보이나 확정 불가.
  • 근사 방식: 피벗고/피벗저(좌우 2봉 엄격 극값) 발생 시 중심선 center = (center*2 + pivot)/3, 밴드 center ± ATR(10)*3.0, 종가가 상단 초과=상승/하단 미만=하락, 그 외 직전 방향 유지.
  • 한계: 중심선 갱신 규칙(2:1 가중)과 방향 플립 조건은 관례를 채택한 것이며 원본과 같다는 근거가 없다. 다만 §1.2대로 PP는 폴백 경로에서만 쓰이므로 영향 범위는 칼만 라인보다 작다.

C. SMC 베어 분기 비대칭 — 원본과 의도적으로 다르게 한 1곳

원본 C#의 불 분기는 if (bullishGap) gIdx = k+2;인데 베어 분기만 if (bearishGap && High[k] > max) gIdx = k+2;High[k] > max가 덧붙어 있다(불 분기엔 대응 조건 없음). 원저자 오타로 보이나 확증 불가 → 이식본은 양 방향을 대칭으로 정규화했다. 원본 거동을 100% 재현해야 한다면 이 한 줄을 되살려야 한다.

D. 타임프레임 리샘플 — 구조적 근사

원본 TF2는 512틱 봉, TF3는 1분봉으로 NT8이 직접 만든다. 이식본 TF필터(봉,기간)는 기본 시리즈를 N개씩 묶는 고정배수 리샘플이라, 틱봉↔시간봉 경계가 원본과 정확히 일치하지 않는다. 실전 정합을 원하면 TF2/TF3 봉을 데이터 소스에서 각각 별도로 공급(트리플싱크판정에 이미 3개 봉배열을 따로 받도록 설계)하는 쪽이 정답이고, TF필터(…, 기간)는 단일 소스만 있을 때의 보조 경로다.

E. 미이식(의도적) — 신호가 아닌 것

주문 실행, SL/TP 300틱, 일일 손실 $900/목표 $1200, 세션·하드킬 시간창, 3초 쿨다운(파라미터만 보유), Watchdog/Heartbeat/연결복구, 텔레그램, WPF UI, 프랍 일일 리셋.


5. 자체시험 (21/21 PASS)

bashcd /Users/ef/CrownyOS/crownyc
CROWNY_STRICT=1 ./hanseonc_high /Users/ef/CrownyDoc/projects/kps-trading-tool/전략트리플싱크.한선 > /tmp/tsync.toau
env SELFTEST=1 ./crownyc run /tmp/tsync.toau

케이스
칼만 수렴상승 시계열 40봉 → 상태 +1 / 하락 40봉 → −1 / 평탄 40봉 → 0 / 칼만1차 재호출 안전성
OB 탐지합성 불 OB(프랙탈고 돌파+FVG) → 바텀 90·상태 +1·활성 1 / 가격 미러링한 베어 케이스 → 탑 210·상태 −1 / OB 없는 평탄 → 0
TF 필터기간1(상승)=+1 / 기간4 리샘플(하락)=−1 / 기간2(평탄) OB=0
트리플 결합롱 진입·숏 진입·TF3 차단·칼만 전환 없음 차단·신규불OB 단독 트리거·전중립 대기
통합트리플싱크판정 실봉 3종 입력 정상 판정
★ OB 테스트 제작 중 발견: 처음 만든 합성 봉은 원본 C# 로직으로도 FVG 필터에 걸려 OB가 생기지 않는 케이스였다(gIdx는 루프에서 가장 오래된 갭으로 덮어써지므로 idx ≥ gIdx가 성립해야 한다). 테스트를 코드에 맞춘 게 아니라 원본 조건을 만족하도록 봉을 다시 설계해서 통과시켰다.


6. 재사용한 기존 한선씨 자산

자산재사용 형태
crowny-trader/한선씨/kps/kps_상태기계.한선일일한도·트레일링DD·쿨다운·연승 트리거 = 원본의 운영 게이트(§1.6) 대체처. 신규 구현 안 함
kps_사이징.한선계약수 캡(원본 TradeQuantity 고정 1 대체)
kps_라이브락_엣지.한선실자본 진입 차단 — 이 이식본이 판정만 하고 주문을 안 하는 이유와 정확히 같은 원칙
kps_장세분류.한선TF2/TF3 필터의 상위 개념(장세) 태깅 — 백테스트 시 조건부 승률 분해에 사용
kps_nt8매핑.한선NT8 CSV/이벤트 → 저널행. 백테스트 데이터 공급 경로로 그대로 활용 가능
코딩 관례위 모듈들의 "코드=산술 / 셀코어=선언적 게이트" 분업, 절단 나눗셈 클램프 관례 답습
신규 작성은 칼만·PP·SMC OB·3TF 결합 4가지뿐이다(기존 KPS 도구에 없던 영역).


7. 다음 단계 — 필요한 것

  1. 백테스트 데이터 요건 (최우선)
- 형식: 시각,시가,고가,저가,종가 (가격은 정수 틱 환산 — 소수 금지). 3개 파일(TF1 틱봉 / TF2 512틱봉 / TF3 1분봉)을 각각 받는 것이 정합상 최선(§4-D). - 기간: 최소 3개월, 세션시간(07:05–18:55) 포함. 심볼은 실거래 대상(ES/NQ 등) 1종부터. - 한선씨 측 제약: 배열 1023칸 → 1회 판정 입력 200봉. 긴 구간은 슬라이딩 윈도우로 공급하는 러너가 별도로 필요하다.
  1. 칼만 캘리브레이션 데이터 — NT8에서 UltKalmanV2 4개 플롯값을 봉별로 CSV export. 이게 있어야 §4-A의 "근사"를 "정합 측정된 근사"로 승격할 수 있다. 없으면 Q단/Q장은 계속 추정치다.
  2. 슬라이딩 윈도우 백테스트 러너(.한선) — 봉 스트림 → 200봉 윈도우 → 트리플싱크판정 → 신호 로그 PSV. 여기에 §1.6 운영 게이트(kps_상태기계)를 결선.
  3. 원본 대조 리포트 — 같은 구간에서 NT8 전략 로그의 진입 시각 목록 vs 이식본 발화 시각 목록의 일치율. 이 수치가 나오기 전에는 "이식 완료"가 아니라 "이식 초안"이다.
  4. 결정 사항 확인 필요(사장님) — §4-C 베어 분기 비대칭을 원본 그대로 둘지, 정규화된 현재 이식본을 정본으로 할지.

8. 안전 선언

  • 이 파일과 산출물에는 주문·체결·계좌·네트워크 호출이 하나도 없다(순수 판정).
  • 포트 9847 · 9848 · 9853 · 9857 · 9869 무접촉. 기존 라이브 파일 수정 0건(신규 2파일만 생성).
  • 실자본 적용은 kps_라이브락_엣지.한선의 3조건(엣지 실증·사이징 평탄화·약관 확인)이 여전히 선행 조건이다.