Files
goldenChart/전략편집기 로직 및 동작흐름.md
T
2026-06-05 10:32:40 +09:00

26 KiB
Raw Blame History

전략편집기 로직 및 동작흐름

goldenChart 전략편집기(Strategy Editor) 의 화면 구성, 편집·저장 방식, 그리고 저장된 전략이 백엔드에서 매매 시그널(BUY/SELL)을 감지하기까지의 전체 흐름을 정리한 문서입니다.

관련 문서: 실시간 전략체크 구현.md — 실시간 ON/OFF, CANDLE_CLOSE / REALTIME_TICK 설정 및 STOMP 프로토콜


1. 개요

구분 설명
메뉴 strategy-editor (App.tsxStrategyEditorPage)
역할 매수·매도 조건을 논리 트리(DSL) 로 구성하고 gc_strategy 테이블에 저장
평가 엔진 백엔드 Ta4jStrategyDslToTa4jAdapter가 DSL JSON → Rule 변환
실시간 시그널 LiveStrategyEvaluator + BarBuilder / LiveStrategyScheduler
레거시 화면 StrategyPage (strategy) — 동일 API·DSL, UI만 구형 트리 편집기

전략편집기에서 저장하는 것은 조건 트리 JSON(buyCondition, sellCondition)이며, 노드 좌표·팔레트 사용자 정의 항목 등은 브라우저 localStorage에만 둘 수 있습니다.

1.1 아키텍처 원칙 (단일 평가 원천)

계층 역할
전략편집기 buy_condition_json / sell_condition_json 만 DB에 저장. 그래프·목록 빌더는 동일 DSL 공유, 표현만 다름
Logic Expression 저장된 DSL의 설명용 미리보기 — 별도 조건 컬럼 없음
flow_layout_json 캔버스 좌표·START 메타 등 UI — Ta4j 평가 입력이 아님 (DSL과 동기 저장)
백엔드 Ta4j로 유일한 BUY/SELL·조건 충족 평가
프론트 가상투자 UI GET /strategy/live-conditions 표시·일치율만. 프론트에서 조건 재평가하지 않음
가상 자동매매 백엔드 STOMP signal (BUY/SELL) 수신 시에만 모의 체결

1.2 봉 마감별 전략 체크 (스킵 방지)

  1. 업비트 틱 → BarBuilder.commitBar — 1m 확정 시 전략 DSL에 포함된 상위봉(3m·5m·10m·15m …)까지 전파
  2. 상위봉 마감BarCloseStrategyEvaluationService.onMaturedBarCloseStrategyConditionTimeframeService.usesTimeframe 이 true 인 분봉만 평가
  3. WS 갭 → CandleGapBackfillService REST 병합 후 evaluateRecentMaturedBarsAfterBackfill 로 병합 구간 마감봉 보정
  4. REALTIME_TICK 실행 방식은 추가로 LiveStrategyScheduler(3초)가 동일 DSL 분봉만 순회

예: 비트코인 전략 START에 3m,5m,10m,15m 이면 각 분봉 마감봉마다 백엔드 평가가 1회씩 실행되어야 하며, 평가 분봉은 DSL에 없는 1h 등에서는 실행되지 않음.


2. 화면 구성 (StrategyEditorPage)

2.1 레이아웃

┌─────────────────────────────────────────────────────────────────────────┐
│  BuilderPageShell — 제목: 전략편집기 / Strategy Builder                  │
├──────────────┬──────────────────────────────────────────┬───────────────┤
│  좌측 패널    │  중앙 편집 영역                           │  우측 패널     │
│  (리사이즈)   │                                          │  (리사이즈)    │
│              │  [매수] [매도] 탭                          │               │
│  전략 목록    │  [그래프 | 목록] 편집 모드                  │  지표 | 템플릿 │
│  새 전략      │  ┌────────────────────────────────────┐  │  팔레트       │
│  삭제        │  │ StrategyEditorCanvas (React Flow)   │  │  START/AND/  │
│  Import/     │  │  또는 StrategyListEditor            │  │  OR/NOT 칩    │
│  Export      │  └────────────────────────────────────┘  │  보조/복합    │
│              │  선택 노드 설정 바 (CondEditor)            │  지표 탭      │
├──────────────┴──────────────────────────────────────────┴───────────────┤
│  하단 터미널 — LogicExpressionPreview (논리 수식 미리보기)                  │
└─────────────────────────────────────────────────────────────────────────┘

스타일: strategyEditor.css, strategyEditorTheme.css

2.2 주요 UI 상태

State 타입 용도
signalTab 'buy' | 'sell' 매수/매도 조건 편집 대상
editorMode 'graph' | 'list' React Flow vs 목록 트리 (gc_se_editor_mode)
rightTab 'indicators' | 'templates' 지표 팔레트 vs 프리셋 템플릿
indicatorSubTab 'auxiliary' | 'composite' 단일 보조지표 vs 복합(2기간 교차)
buyCondition / sellCondition LogicNode | null 저장 대상 DSL 루트
buyLayout / sellLayout SignalFlowLayoutSnapshot 노드 좌표, 엣지, START 메타 (로컬 전용)
buyOrphans / sellOrphans LogicNode[] 그래프에서 분리된 고아 노드 (DB 미저장)
selectedId number | 'draft' 선택 전략 ID

2.3 중앙 편집 영역 동작

그래프 모드 (StrategyEditorCanvas)

  • React Flow 기반: StartNode, LogicGateNode(AND/OR/NOT), ConditionFlowNode
  • 팔레트에서 드래그 앤 드롭 → makeNode / mergeAtRoot로 트리에 삽입
  • START 노드에서 평가 분봉 선택 (1m ~ 1d)
  • START를 추가하면 다중 분기 (extraStartIds) — 저장 시 AND/OR + 여러 TIMEFRAME으로 직렬화
  • 노드 이동·연결 변경 시 saveStrategyFlowLayout → localStorage gc_se_flow_layout_v1

목록 모드 (StrategyListEditor)

  • 동일 DSL을 트리/섹션 UI로 편집
  • START 섹션별 분봉·조건 트리 관리

선택 노드 설정 (CondEditorstrategyEditorShared.tsx)

  • indicatorType, conditionType, leftField, rightField, period, 복합지표 기간 등
  • buildStrategyEditorDef()차트 보조지표 설정과 분리된 고정 기본 파라미터 사용

2.4 우측 팔레트

영역 내용
시작·논리 START, AND, OR, NOT (PaletteChip)
밴드·추세 MA, EMA, BOLLINGER, DONCHIAN, ICHIMOKU 등
보조지표 RSI, MACD, CCI, 신고가/신저가(NH_PRIOR/NL_PRIOR) 등 — se-palette-auxiliary-v1
복합지표 RSI+RSI, MACD+MACD 등 2기간 교차 — se-palette-composite-v1
템플릿 strategyPresets.ts — 터틀, 돈치안, 일목 등 원클릭 삽입

드래그 payload: application/json{ type, value, label, composite?, period?, ... }

2.5 하단 Logic Expression

LogicExpressionPreviewcollectEditorBranches / collectDslBranches로 분기별 수식 표시 예:

[5m] (RSI(9) CROSS_UP K_70 AND MACD CROSS_UP)
AND [1h] (ADX CROSS_UP K_25)

3. 전략 데이터 모델 (DSL)

3.1 핵심 타입 (strategyTypes.ts)

type LogicNodeType = 'AND' | 'OR' | 'NOT' | 'CONDITION' | 'TIMEFRAME';

interface ConditionDSL {
  indicatorType: string;      // RSI, MACD, DONCHIAN, NEW_HIGH, ...
  conditionType: string;      // GT, CROSS_UP, CROSS_DOWN, ...
  leftField?: string;         // RSI_VALUE, DC_UPPER_20, NH_PRIOR_9, ...
  rightField?: string;        // K_70, SIGNAL_LINE, DC_LOWER_10, ...
  period?: number;
  composite?: boolean;        // 복합지표 2기간 교차
  leftPeriod?, rightPeriod?;
  leftCandleType?, rightCandleType?;
  // ...
}

interface LogicNode {
  id: string;
  type: LogicNodeType;
  children?: LogicNode[];
  condition?: ConditionDSL;
  candleType?: string;        // TIMEFRAME 전용
}

3.2 DB/API 저장 형태 (GcStrategy)

컬럼 내용
buy_condition_json 매수(진입) 조건 루트 LogicNode
sell_condition_json 매도(청산) 조건 루트 LogicNode
name, description, enabled 메타

API: POST /api/strategiessaveStrategy() (backendApi.ts)

3.3 CONDITION 리프 예시

{
  "id": "n_abc123",
  "type": "CONDITION",
  "condition": {
    "indicatorType": "RSI",
    "conditionType": "CROSS_UP",
    "leftField": "RSI_VALUE",
    "rightField": "K_70",
    "period": 14
  }
}

3.4 논리 노드 예시

{
  "id": "n_and1",
  "type": "AND",
  "children": [
    { "type": "CONDITION", "condition": { "...": "RSI CROSS_UP" } },
    { "type": "CONDITION", "condition": { "...": "MACD CROSS_UP" } }
  ]
}

4. START · TIMEFRAME · 다중 분봉

편집기 UI의 START 노드는 DB에 그대로 저장되지 않습니다. strategyConditionSerde.ts가 저장/로드 시 변환합니다.

4.1 편집기 내부 상태 (EditorConditionState)

{
  root: LogicNode | null;              // 기본 START 분기의 조건 트리
  startMeta: { [startId]: { candleType } };
  extraStartIds: string[];             // 추가 START
  extraRoots: { [startId]: LogicNode };
  startCombineOp?: 'AND' | 'OR';       // 다중 START 결합
}
  • 기본 START ID: __strategy_start__
  • 추가 START: __strategy_start_{uuid}__

4.2 저장 시 인코딩 (encodeConditionForSave)

경우 저장 결과
조건 없음 null
단일 분기, 분봉 1m 루트 트리만 (TIMEFRAME 생략)
단일 분기, 분봉 5m { type: "TIMEFRAME", candleType: "5m", children: [root] }
다중 START { type: "AND"|"OR", children: [ TIMEFRAME×N ] }

4.3 로드 시 디코딩 (decodeConditionForEditor)

  • 최상위가 AND/OR이고 자식이 전부 TIMEFRAME → 다중 START로 복원
  • 최상위가 TIMEFRAME 단일 → 기본 START + 해당 분봉
  • 그 외 → 기본 1m START, 루트 = 전체 DSL

4.4 지원 분봉 (strategyStartNodes.ts)

1m, 3m, 5m, 10m, 15m, 30m, 1h, 4h, 1d


5. 지표·조건 종류

5.1 단일 보조지표

  • 팔레트 또는 템플릿에서 CONDITION 노드 생성
  • leftField / rightField — 지표 플롯 vs 상수(K_70) vs 다른 플롯(SIGNAL_LINE)
  • 기간은 period 또는 필드명 접미사 (RSI_VALUE_9)

5.2 복합지표 (compositeIndicators.ts)

동일 지표 두 기간 비교 — 예: RSI(9) 상향 돌파 RSI(20)

{
  "composite": true,
  "indicatorType": "RSI",
  "conditionType": "CROSS_UP",
  "leftField": "RSI_VALUE_9",
  "rightField": "RSI_VALUE_20",
  "leftPeriod": 9,
  "rightPeriod": 20
}

요소별 서로 다른 분봉(leftCandleType, rightCandleType)은 백엔드 buildCrossTimeframeCompositeRule로 처리 (라이브 + storage 필요).

5.3 신고가·신저가 (단일 지표)

  • NEW_HIGH / NEW_LOW + NH_PRIOR_N / NL_PRIOR_N
  • 의미: 직전 N봉 최고가/최저가 대비 종가 돌파/이탈 (당일 봉 제외)
  • 백엔드: PreviousValueIndicator(HighestValueIndicator(high, N), 1)

5.4 돈치안·일목 등

  • DONCHIANDC_UPPER_N, DC_LOWER_N
  • ICHIMOKU → 구름/선행스팬 전용 conditionType (ABOVE_CLOUD, CLOUD_BREAK_UP, …)

6. 저장·로드 프로세스 (프론트엔드)

6.1 저장 (handleSave)

sequenceDiagram
  participant U as 사용자
  participant SE as StrategyEditorPage
  participant Serde as encodeConditionForSave
  participant API as POST /api/strategies
  participant DB as gc_strategy

  U->>SE: 저장 클릭
  SE->>Serde: buyEditorState / sellEditorState
  Serde-->>SE: buyCondition, sellCondition (LogicNode)
  SE->>API: saveStrategy({ name, buyCondition, sellCondition })
  API->>DB: JSON 컬럼 persist
  SE->>SE: persistFlowLayout(id) — localStorage만

검증:

  • 전략명 필수
  • 매수·매도 중 하나 이상 조건 필요
  • draft 저장 시 → DB ID 발급 후 migrateStrategyFlowLayout('draft' → id)

6.2 로드

  1. loadStrategies() — 서버 우선
  2. 실패 시 loadStratsLocal() (gc_strat_v2)
  3. 전략 선택 → decodeConditionForEditor(buy/sell) + loadStrategyFlowLayout(id)

6.3 localStorage vs DB

저장 내용 DB
gc_strategy (API) buy/sell JSON
gc_se_flow_layout_v1 노드 좌표, edge, startMeta, orphans
gc_strat_v2 전략 목록 캐시 (폴백)
se-palette-auxiliary-v1 사용자 보조지표 팔레트
se-palette-composite-v1 사용자 복합지표 팔레트
gc_se_editor_mode graph / list

Import/Export: strategyImportExport.ts — DSL + flowLayout + editorMode JSON 파일


7. 백엔드: DSL → Ta4j Rule

7.1 어댑터 (StrategyDslToTa4jAdapter)

진입: toRule(JsonNode dsl, RuleBuildContext ctx)

LogicNode.type 빌드 메서드 Ta4j
AND buildAndRule AndRule
OR buildOrRule OrRule
NOT buildNotRule NotRule
TIMEFRAME buildTimeframeRule 분기 BarSeries + CrossSeriesRule
CONDITION buildConditionRule 비교/교차 Rule

CONDITION conditionType 매핑 (요약):

conditionType Ta4j 개념
GT, LT, GTE, LTE, EQ, NEQ Over/Under/Equals
CROSS_UP, CROSS_DOWN CrossedUpIndicatorRule, CrossedDownIndicatorRule
SLOPE_UP, SLOPE_DOWN IsRisingRule, IsFallingRule
HOLD_N_DAYS N봉 연속 충족
일목 전용 구름/선행스팬 규칙

필드 해석: resolveField — OHLCV, K_* 상수, RSI/CCI/MACD/Donchian/NH_PRIOR/NL_PRIOR 등

지표 파라미터: DB indicator_settings + DSL_TO_REGISTRY 매핑

7.2 멀티 타임프레임 (라이브)

RuleBuildContextmarket, Ta4jStorage가 있으면:

  • TIMEFRAME.candleType에 맞는 시리즈를 storage에서 로드
  • 트리거 봉(예: 1m 마감) 인덱스에서 다른 분봉 시리즈 최신 봉CrossSeriesRule로 평가

백테스트는 단일 요청 BarSeries만 사용 → 교차 TF는 primary series fallback.

7.3 Strategy 조립 (LiveStrategyEvaluator.buildStrategy)

Rule entryRule = buildRule(buyConditionJson,  series, params, market, storage);
Rule exitRule  = buildRule(sellConditionJson, series, params, market, storage);
BaseStrategy strategy = new BaseStrategy(entryRule, exitRule);

캐시 키: market:candleType:strategyId


8. 백엔드: 데이터 수집 → 평가 트리거

8.1 캔들 파이프라인

flowchart LR
  UWS[Upbit WebSocket 틱]
  MTP[MarketTickProcessor]
  BB[BarBuilder]
  TS[Ta4jStorage BarSeries]

  UWS --> MTP --> BB --> TS
  • 동일 분: updateLastBar (진행 중 봉 갱신)
  • 분 변경: commitBar → 확정봉 + 상위봉(3m~1d) 집계

8.2 어떤 분봉을 평가할지

StrategyConditionTimeframeService:

  • 전략 DSL을 walk하여 TIMEFRAME 노드의 candleType 수집
  • usesTimeframe(strategyId, candleType) — 해당 봉 마감/스케줄에서만 평가

LiveStrategyTimeframeService는 UI/설정용 gc_live_strategy_settings.candle_type resolve (가상투자 카드 시간봉 드롭다운 등).


9. 시그널 감지 프로세스

9.1 전제: 실시간 전략 설정 (GcLiveStrategySettings)

필드 의미
isLiveCheck true/false 실시간 체크 ON
executionType CANDLE_CLOSE / REALTIME_TICK 평가 타이밍
strategyId FK 사용할 GcStrategy
positionMode LONG_ONLY / SIGNAL_ONLY 포지션 추적 방식
candleType 1m1d 설정/UI 기본 분봉

가상투자·설정 화면에서 PUT /api/strategy/settings로 반영.

9.2 시그널 판정 (StrategySignalDeterminer)

positionMode BUY SELL
LONG_ONLY strategy.shouldEnter(index, record) strategy.shouldExit(index, record)
SIGNAL_ONLY entryRule.isSatisfied(index) exitRule.isSatisfied(index)

LONG_ONLY는 evaluator가 가상 TradingRecord를 캐시해 중복 진입 방지.

결과: "BUY" | "SELL" | "NONE"

9.3 방식 A — 봉 마감 직후 (CANDLE_CLOSE)

트리거: BarBuilder.commitBar()evaluateStrategyOnBarClose()

조건 (각 설정 행):

  1. isLiveCheck == true
  2. executionType == CANDLE_CLOSE
  3. usesTimeframe(strategyId, candleType)
  4. Ta4jStorage에 해당 분봉 데이터 존재

평가: LiveStrategyEvaluator.evaluateCandleClose(market, candleType, maturedIndex)

  • 확정된 직전 봉 인덱스에서 1회 판정

9.4 방식 B — 실시간 틱 (REALTIME_TICK)

트리거: LiveStrategyScheduler3초 주기 (@Scheduled)

조건: executionType == REALTIME_TICK 등 동일

평가: evaluateSettingRealtimeTick(setting, market, candleType)

  • currentIndex = series.getEndIndex()진행 중(provisional) 봉
  • 중복 방지: 동일 (market, candleType:strategyId)에서 같은 index에 이미 시그널 냈으면 skip
  • Rule 캐시 완전 우회: 매 평가마다 신규 Rule 인스턴스 빌드 (evaluateWithFreshRules)
    • Ta4j CachedIndicator stale 캐시 원천 차단
    • triggerRulesCache 복합 연산(remove→put) 스레드 안전성 문제 제거
  • 멀티 TF: useConfirmedOnly=false — 비트리거 상위봉 현재 진행 중인 봉 기준 평가

9.5 보완 — 마감 직후 REALTIME 재평가

봉 마감 시 → evaluateSettingRealtimeAtClose(setting, market, candleType, maturedIndex)

  • 봉 마감 시점의 교차(CROSS) 를 3초 스케줄러가 놓치는 경우 대비
  • useConfirmedOnly=true — 확정봉 인덱스 기준 + 상위봉도 확정봉 사용
  • Rule 캐시 우회

9.6 평가 흐름 (단일 종목·단일 시점)

flowchart TD
  A[트리거: 봉 마감 또는 3초 틱]
  B{isLiveCheck?}
  C{usesTimeframe?}
  D1[CANDLE_CLOSE: evaluate - 캐시 사용 - useConfirmedOnly=true]
  D2[REALTIME_TICK: evaluateWithFreshRules - 캐시 우회 - useConfirmedOnly=false]
  E[buildTriggerRules - DSL to Ta4j with CrossSeriesRule]
  F[StrategySignalDeterminer.determineSignal]
  G{결과}
  H[설정별 독립 publishStrategySignal]
  I[NONE - 종료]

  A --> B
  B -->|false| I
  B -->|true| C
  C -->|false| I
  C -->|CANDLE_CLOSE| D1
  C -->|REALTIME_TICK| D2
  D1 --> E --> F --> G
  D2 --> E
  G -->|BUY/SELL| H
  G -->|NONE| I

주의: BarCloseStrategyEvaluationService / LiveStrategyScheduler설정별 독립 루프로 멀티 전략 시그널을 각각 발행한다. evaluateCandleClose(market), evaluateRealtimeTick(market) 마켓 단위 API 는 첫 non-NONE 만 반환하므로 실시간 시그널 발행 경로에서 사용 금지 (@Deprecated).


10. 시그널 발행·후처리

10.1 STOMP WebSocket

토픽: /sub/charts/{market}/{candleType}
엔드포인트: ws://host/ws/trading (SockJS)

페이로드 (CandleBarDto): OHLCV + 지표값 + signal: "BUY" | "SELL" | null

{
  "t": 1779229260,
  "o": 92080000.0,
  "c": 92050000.0,
  "signal": "BUY"
}

별도 “시그널 전용” 토픽은 없음 — 차트 캔들 스트림에 시그널 필드로 포함.

10.2 DB·알림·주문

단계 클래스
DB 저장 TradeSignalService.saveGcTradeSignal
FCM FcmPushService
주문 큐 OrderExecutionQueue.submitSignal (deviceId 있을 때)

10.3 프론트 차트 반영

  • STOMP 구독 → 캔들 수신 시 signal 필드로 마커(setMarkers) 표시
  • LiveSignalNotifier, 차트 슬롯 등

11. 조건 현황 API (시그널과 별개)

용도: 가상투자 카드, 모니터링 UI — “지금 각 조건이 얼마나 충족됐는지”

항목 내용
API GET /api/strategy/live-conditions?market=&strategyId=
구현 LiveConditionStatusService
방식 buy/sell JSON의 각 CONDITION 리프를 개별 Rule로 평가
matchRate 충족 리프 수 / 평가 가능 리프 수 (전체 AND/OR 트리 충족과 다름)

실제 BUY/SELL 발화는 §9 경로만 사용.


12. 백테스트 vs 실시간

항목 백테스트 (BacktestingService) 실시간 (LiveStrategyEvaluator)
BarSeries 요청 bars로 일회성 생성 Ta4jStorage 실시간 누적
멀티 TF DSL에서 상위봉 타입 추출 → 집계 시리즈 생성 (→ seriesOverrides) Ta4jStorage 다중 시리즈
adapter toRule(dsl, series, params, seriesOverrides) (백테스트 멀티 TF) toRule(..., market, storage)
CrossSeriesRule 타임스탬프 기반 룩업 (isBacktest=true) getEndIndex() 또는 endIndex-1
스캔 전 구간 0..barCount-1 단일 index (마감 or provisional)
청산 DSL sell + 손절/익절/트레일링 OR 합성 DSL sell (+ 리스크 모니터 별도)
출력 BacktestResponse.signals, gc_backtest_result STOMP + gc_trade_signal
멀티 TF storage 없으면 단일 시리즈 fallback TIMEFRAME / 교차 TF 지원

백테스트도 동일 DSL·동일 어댑터를 사용하므로, 편집기에서 저장한 전략이 백테스트와 라이브에서 같은 의미로 해석됩니다 (데이터·타이밍 차이는 있음).


13. 전략 사용 경로 (편집기 이후)

flowchart TB
  SE[전략편집기 저장]
  DB[(gc_strategy)]
  SE --> DB

  DB --> BT[백테스팅 화면]
  DB --> LIVE[실시간 전략 설정]
  DB --> VT[가상투자 카드]

  LIVE --> LSS[gc_live_strategy_settings]
  LSS --> EVAL[LiveStrategyEvaluator]
  VT --> LC[live-conditions API]

  EVAL --> STOMP[STOMP signal]
  EVAL --> TSIG[gc_trade_signal]
  1. 전략편집기 — DSL 작성·저장
  2. 설정 / 가상투자 — 종목별 strategyId, executionType, positionMode, 평가 분봉
  3. 백테스트 — 과거 봉으로 전 구간 시뮬레이션
  4. 라이브 — Upbit 틱 → Ta4j → 시그널 → STOMP·DB·(자동매매)

14. 주요 소스 파일

프론트엔드

경로 역할
frontend/src/components/StrategyEditorPage.tsx 전략편집기 메인
frontend/src/components/strategyEditor/StrategyEditorCanvas.tsx React Flow 캔버스
frontend/src/components/strategyEditor/StrategyListEditor.tsx 목록 편집기
frontend/src/components/strategyEditor/LogicExpressionPreview.tsx 논리 수식 미리보기
frontend/src/utils/strategyTypes.ts DSL 타입·조건 상수
frontend/src/utils/strategyConditionSerde.ts START↔TIMEFRAME 직렬화
frontend/src/utils/strategyEditorShared.tsx CondEditor, 트리 조작, DEF
frontend/src/utils/strategyEditorLayoutStorage.ts Flow 레이아웃 localStorage
frontend/src/utils/compositeIndicators.ts 복합지표 정의
frontend/src/utils/strategyStartNodes.ts 분봉·START 상수
frontend/src/utils/strategyPresets.ts 템플릿
frontend/src/utils/backendApi.ts saveStrategy, loadStrategies

백엔드

경로 역할
backend/.../entity/GcStrategy.java 전략 엔티티
backend/.../entity/GcLiveStrategySettings.java 실시간 설정
backend/.../service/StrategyDslToTa4jAdapter.java DSL → Rule
backend/.../service/LiveStrategyEvaluator.java 실시간 평가
backend/.../service/StrategySignalDeterminer.java BUY/SELL 판정
backend/.../service/BacktestingService.java 백테스트
backend/.../service/LiveConditionStatusService.java 조건 현황 API
backend/.../service/StrategyConditionTimeframeService.java DSL 분봉 수집
backend/.../websocket/BarBuilder.java 봉 조립·마감 시 평가 트리거
backend/.../service/BarCloseStrategyEvaluationService.java 봉 마감 전략 평가 단일 진입점
backend/.../websocket/LiveStrategyScheduler.java 3초 REALTIME_TICK
backend/.../websocket/TradingWebSocketBroker.java STOMP 발행
backend/.../storage/Ta4jStorage.java BarSeries 저장소

15. 핵심 체크리스트 (디버깅용)

  1. 저장 DSLencodeConditionForSave 후 JSON에 TIMEFRAME / AND+TIMEFRAME 구조가 의도대로인가?
  2. 분봉 — 조건 리프의 timeframe vs TIMEFRAME 래핑 candleType 일치 여부
  3. 실시간 ONisLiveCheck, strategyId 연결
  4. 실행 방식CANDLE_CLOSE vs REALTIME_TICK
  5. 데이터Ta4jStorage.exists(market, candleType), warm-up(pinCandleWatch)
  6. 포지션 모드LONG_ONLY에서 이미 포지션일 때 BUY 무시
  7. STOMP — 구독 토픽 /sub/charts/{market}/{candleType} 와 평가 분봉 일치
  8. UI 현황 vs 시그널live-conditions matchRate ≠ 실제 BUY/SELL 발화 조건 (UI는 리프별 Rule, 시그널은 트리 전체)
  9. 마감봉 평가BarCloseStrategyEvaluationService + DSL usesTimeframe 게이트; 갭은 CandleGapBackfillService 후 보정
  10. 프론트 평가 금지 — 가상투자 일치율·자동매매는 백엔드 API/STOMP 만 사용

문서 작성 기준: goldenChart 저장소 프론트/백엔드 소스 구조. API·클래스명은 변경될 수 있으므로 구현 확인 시 §14 파일 목록을 참고하세요.