Files
goldenChart/백테스팅 시그널 동작방식.md
2026-05-23 15:11:48 +09:00

4.2 KiB

🤖 Cursor AI 전용: 포지션 종속성 선택 기능 구현 요청 프롬프트 🎯 구현 목표 (Goal) 매매 전략 실행 및 백테스팅 엔진 가동 시, "매도 시그널이 발생했을 때 이전 매수 기록(포지션)이 있어야만 실행할 것인가"에 대한 제약 조건을 유저가 직접 제어할 수 있도록 시스템을 확장합니다. 유저의 설정에 따라 Ta4j의 엄격한 포지션 검증 로직을 타거나, 혹은 순수 지표 조건 매칭 분기로 우회 구동되도록 구현해 주세요.

🛠️ 1. 요구사항 명세 및 정책 (Requirements) ① 설정 화면 UI 항목 추가 (Frontend) 매매 시그널 발생 조건 제어 (라디오 버튼 또는 셀렉트 박스):

  1. 보유 자산 기준 매매 (Long-Only 모드): 기존에 매수한 이력(Open Position)이 완벽히 존재할 때만 매도 시그널 허용.

  2. 순수 기술 지표 기준 매매 (Signal-Only 모드): 이전 매수 이력 존재 여부와 완전히 무관하게, 기술적 지표 규칙만 만족하면 매도 시그널을 즉시 허용.

② 백엔드 전략 평가 코어 제어 정책 (Backend Logic) 유저가 선택한 옵션값은 데이터베이스(UserStrategySettings)에 저장되며, 실시간 감시 엔진 및 과거 데이터 백테스팅 중계기(HistoricalDataService) 연산 시 공통 분기 조건으로 사용됩니다.

[Mode 1] LONG_ONLY (보유 자산 기준 매매) 처리 프로토콜:

Ta4j의 표준 strategy.shouldExit(index, tradingRecord) 형식을 그대로 유지합니다.

내부적으로 TradingRecord에 현재 열려 있는 포지션이 없다면 매도 조건을 만족하더라도 시그널을 내보내지 않습니다.

[Mode 2] SIGNAL_ONLY (순수 기술 지표 기준 매매) 처리 프로토콜:

Ta4j Strategy 객체의 포지션 검증을 우회하기 위해, 내부 Rule 인스턴스를 직접 추출하여 판단합니다.

매수 판단 시: strategy.getEntryRule().isSatisfied(index) 호출

매도 판단 시: strategy.getExitRule().isSatisfied(index) 호출 ➔ 이전 매수 기록 유무와 무관하게 지표 수식만 맞으면 무조건 매도("SELL") 시그널 확정

💾 2. 데이터 구조 및 인터페이스 설계 (Data Struct) ① [PUT] /api/strategy/settings (기존 설정 API 데이터 구조 확장) JSON { "market": "KRW-BTC", "isLiveCheck": true, "executionType": "CANDLE_CLOSE", "positionMode": "SIGNAL_ONLY" // "LONG_ONLY" (방식1) 또는 "SIGNAL_ONLY" (방식2) 추가 } ② API 반영처 명시 이 positionMode 옵션은 아래 두 가지 비즈니스 로직 내부의 시그널 판정 구간에 반드시 녹아들어야 합니다.

HistoricalDataService: 차트 초기 로딩 및 과거 스크롤 시, 과거 캔들 배열 각각에 "BUY"/"SELL"을 태깅하여 넘겨주는 백테스팅 로직 부문.

LiveStrategyEvaluator: 3초 스케줄러 또는 봉 마감 이벤트 발생 시, 실시간 STOMP 패킷의 signal 필드에 값을 주입하는 실시간 감시 로직 부문.

💻 3. 백엔드 참고 가이드 코드 (Reference Code for AI) Java @Component @RequiredArgsConstructor public class StrategySignalDeterminer {

/**
 * 유저 설정 정보(positionMode)에 따라 포지션 제약 유무를 분기하여 시그널을 결정하는 코어 메서드
 */
public String determineSignal(Strategy strategy, BarSeries series, TradingRecord tradingRecord, int index, String positionMode) {
    
    // 1. 보유 자산 기준 매매 (Long-Only) -> Ta4j 표준 엄격 모드
    if ("LONG_ONLY".equals(positionMode)) {
        if (strategy.shouldEnter(index, tradingRecord)) {
            return "BUY";
        }
        if (strategy.shouldExit(index, tradingRecord)) {
            return "SELL";
        }
        return "NONE";
    }
    
    // 2. 순수 기술 지표 기준 매매 (Signal-Only) -> 포지션 락 우회 모드
    if ("SIGNAL_ONLY".equals(positionMode)) {
        boolean isEntrySatisfied = strategy.getEntryRule().isSatisfied(index);
        boolean isExitSatisfied = strategy.getExitRule().isSatisfied(index);
        
        if (isEntrySatisfied) return "BUY";
        if (isExitSatisfied) return "SELL";
        return "NONE";
    }
    
    return "NONE";
}

}