goldenChat base source add
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package com.goldenchart.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.ta4j.core.Rule;
|
||||
import org.ta4j.core.Strategy;
|
||||
import org.ta4j.core.TradingRecord;
|
||||
|
||||
/**
|
||||
* 포지션 종속성 선택에 따른 매매 시그널 판정 코어 컴포넌트.
|
||||
*
|
||||
* <h3>모드 설명</h3>
|
||||
* <ul>
|
||||
* <li><b>LONG_ONLY</b> — Ta4j 표준 엄격 모드.
|
||||
* {@code strategy.shouldEnter/shouldExit} 를 사용하므로,
|
||||
* TradingRecord 에 열린 포지션이 없으면 매도 시그널을 내보내지 않는다.</li>
|
||||
* <li><b>SIGNAL_ONLY</b> — 포지션 락 우회 모드.
|
||||
* 내부 Rule 인스턴스를 직접 호출({@code rule.isSatisfied(index)})하므로,
|
||||
* 이전 매수 기록 여부와 무관하게 지표 수식만 충족되면 시그널을 확정한다.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class StrategySignalDeterminer {
|
||||
|
||||
/**
|
||||
* positionMode 에 따라 포지션 제약 유무를 분기하여 시그널을 결정한다.
|
||||
*
|
||||
* @param strategy Ta4j Strategy (entryRule / exitRule 포함)
|
||||
* @param tradingRecord 현재 TradingRecord 상태 (LONG_ONLY 모드에서 참조)
|
||||
* @param index BarSeries 인덱스
|
||||
* @param positionMode "LONG_ONLY" | "SIGNAL_ONLY" (null → LONG_ONLY 기본 적용)
|
||||
* @return "BUY" | "SELL" | "NONE"
|
||||
*/
|
||||
public String determineSignal(Strategy strategy, TradingRecord tradingRecord,
|
||||
int index, String positionMode) {
|
||||
try {
|
||||
if ("SIGNAL_ONLY".equals(positionMode)) {
|
||||
return determineSignalOnly(strategy, index);
|
||||
}
|
||||
// LONG_ONLY (기본)
|
||||
return determineLongOnly(strategy, tradingRecord, index);
|
||||
} catch (Exception e) {
|
||||
log.warn("[SignalDeterminer] 시그널 판정 오류 idx={} mode={}: {}", index, positionMode, e.getMessage());
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
// ── 보조 오버로드: Rule[] 직접 전달 (LiveStrategyEvaluator 호환) ─────────────
|
||||
|
||||
/**
|
||||
* Rule 배열을 직접 받아 positionMode 에 따라 시그널 판정.
|
||||
* entryRule = rules[0], exitRule = rules[1]
|
||||
*/
|
||||
public String determineSignalFromRules(Rule entryRule, Rule exitRule,
|
||||
TradingRecord tradingRecord,
|
||||
int index, String positionMode) {
|
||||
try {
|
||||
if ("SIGNAL_ONLY".equals(positionMode)) {
|
||||
boolean enterOk = entryRule != null && entryRule.isSatisfied(index);
|
||||
boolean exitOk = exitRule != null && exitRule.isSatisfied(index);
|
||||
if (enterOk) return "BUY";
|
||||
if (exitOk) return "SELL";
|
||||
return "NONE";
|
||||
}
|
||||
// LONG_ONLY — tradingRecord 를 이용한 엄격 모드
|
||||
boolean enterOk = entryRule != null && entryRule.isSatisfied(index, tradingRecord);
|
||||
boolean exitOk = exitRule != null && exitRule.isSatisfied(index, tradingRecord);
|
||||
if (enterOk) return "BUY";
|
||||
if (exitOk) return "SELL";
|
||||
return "NONE";
|
||||
} catch (Exception e) {
|
||||
log.warn("[SignalDeterminer] Rule 판정 오류 idx={} mode={}: {}", index, positionMode, e.getMessage());
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
// ── Private ───────────────────────────────────────────────────────────────
|
||||
|
||||
private String determineLongOnly(Strategy strategy, TradingRecord record, int index) {
|
||||
if (strategy.shouldEnter(index, record)) return "BUY";
|
||||
if (strategy.shouldExit(index, record)) return "SELL";
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
private String determineSignalOnly(Strategy strategy, int index) {
|
||||
if (strategy.getEntryRule().isSatisfied(index)) return "BUY";
|
||||
if (strategy.getExitRule().isSatisfied(index)) return "SELL";
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user