전략평가 로직 개선
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* useLiveStrategyMarkers
|
||||
*
|
||||
* STOMP WebSocket 으로 /sub/charts/{market}/{candleType} 구독:
|
||||
* STOMP WebSocket 으로 두 가지 채널을 구독한다:
|
||||
*
|
||||
* 1. /sub/charts/{market}/{candleType} — 차트 캔들 스트림 내 signal 필드 (하위 호환)
|
||||
* 2. /sub/signals/user/{userId} — [항목5] 시그널 전용 미션 크리티컬 채널
|
||||
* (로그인 시 userId, 비로그인 시 /sub/signals/device/{deviceId})
|
||||
*
|
||||
* - signal 필드(BUY/SELL) 수신 시 마커 누적 (종목별)
|
||||
* - 동일 종목·타임스탬프·시그널 중복 방지
|
||||
* - activeMarket 차트에만 마커 렌더링, 알림 팝업은 모든 모니터링 종목에 대해 발생
|
||||
@@ -9,7 +14,7 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { parseStompJson } from '../utils/stompMessage';
|
||||
import { subscribeStompTopic } from '../utils/stompChartBroker';
|
||||
import { signalBelongsToCurrentSession } from '../utils/tradeSignalOwnership';
|
||||
import { signalBelongsToCurrentSession, getCurrentSignalSession } from '../utils/tradeSignalOwnership';
|
||||
|
||||
export interface LiveMarker {
|
||||
time: number;
|
||||
@@ -129,7 +134,8 @@ export function useLiveStrategyMarkers({
|
||||
? subscriptions
|
||||
: markets.map(m => ({ market: m, candleType }));
|
||||
|
||||
const unsubs = subs.map(({ market, candleType: ct }) => {
|
||||
// 차트 캔들 스트림 구독 (하위 호환 — 차트 마커용)
|
||||
const chartUnsubs = subs.map(({ market, candleType: ct }) => {
|
||||
const topic = `/sub/charts/${market}/${ct}`;
|
||||
return subscribeStompTopic(topic, msg => {
|
||||
const data = parseStompJson<{
|
||||
@@ -156,8 +162,45 @@ export function useLiveStrategyMarkers({
|
||||
});
|
||||
});
|
||||
|
||||
// [항목5] 시그널 전용 토픽 구독 — 차트 스트림 병목과 독립된 미션 크리티컬 채널
|
||||
const { userId: sessionUserId, deviceId: sessionDeviceId } = getCurrentSignalSession();
|
||||
const signalTopic = sessionUserId != null
|
||||
? `/sub/signals/user/${sessionUserId}`
|
||||
: sessionDeviceId
|
||||
? `/sub/signals/device/${sessionDeviceId}`
|
||||
: null;
|
||||
|
||||
const signalUnsub = signalTopic
|
||||
? subscribeStompTopic(signalTopic, msg => {
|
||||
const data = parseStompJson<{
|
||||
market?: string;
|
||||
candleType?: string;
|
||||
strategyId?: number | null;
|
||||
signalType?: string;
|
||||
price?: number;
|
||||
candleTime?: number;
|
||||
executionType?: string | null;
|
||||
timestamp?: number;
|
||||
}>(msg);
|
||||
if (!data?.signalType || data.signalType === 'NONE') return;
|
||||
if (!data.market) return;
|
||||
// 전용 토픽은 이미 사용자 전용 채널이므로 소유자 검증 불필요
|
||||
const ct = data.candleType ?? candleType;
|
||||
pushMarker(data.market, ct, {
|
||||
time: data.candleTime ?? Math.floor((data.timestamp ?? Date.now()) / 1000),
|
||||
close: data.price ?? 0,
|
||||
signal: data.signalType,
|
||||
strategyId: data.strategyId,
|
||||
userId: sessionUserId,
|
||||
deviceId: sessionDeviceId ?? undefined,
|
||||
executionType: data.executionType,
|
||||
});
|
||||
})
|
||||
: () => {};
|
||||
|
||||
return () => {
|
||||
unsubs.forEach(u => u());
|
||||
chartUnsubs.forEach(u => u());
|
||||
signalUnsub();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [marketsKey, subsKey, candleType, enabled]);
|
||||
|
||||
Reference in New Issue
Block a user