가상 수정

This commit is contained in:
Macbook
2026-05-25 16:02:52 +09:00
parent 3102169541
commit 182b82e990
18 changed files with 747 additions and 105 deletions
@@ -9,6 +9,7 @@ import {
pinCandleWatch,
type LiveConditionRowDto,
} from '../utils/backendApi';
import { formatIndicatorDisplayLabel } from '../utils/indicatorRegistry';
import {
extractVirtualConditions,
type VirtualConditionRow,
@@ -29,7 +30,26 @@ function rowFallbackKey(row: Pick<VirtualConditionRow, 'side' | 'timeframe' | 'i
}
function liveFallbackKey(r: LiveConditionRowDto): string {
return `${r.side}:${r.timeframe}:${r.indicatorType}:${r.conditionType}:${r.targetValue ?? ''}:${r.indicatorType}`;
const plotKey = r.plotKey ?? r.indicatorType;
return `${r.side}:${r.timeframe}:${r.indicatorType}:${r.conditionType}:${r.targetValue ?? ''}:${plotKey}`;
}
function liveRowToVirtual(r: LiveConditionRowDto): VirtualConditionRow & { currentValue: number | null } {
const plotKey = r.plotKey ?? r.indicatorType;
return {
id: r.id,
indicatorType: r.indicatorType,
displayName: formatIndicatorDisplayLabel(r.indicatorType),
conditionType: r.conditionType,
conditionLabel: r.conditionLabel,
targetValue: r.targetValue,
timeframe: r.timeframe,
side: r.side,
plotKey,
satisfied: r.satisfied,
thresholdLabel: r.thresholdLabel,
currentValue: r.currentValue,
};
}
function mergeRows(
@@ -44,26 +64,13 @@ function mergeRows(
}
if (base.length === 0) {
return live.map(r => ({
id: r.id,
indicatorType: r.indicatorType,
displayName: r.displayName,
conditionType: r.conditionType,
conditionLabel: r.conditionLabel,
targetValue: r.targetValue,
timeframe: r.timeframe,
side: r.side,
plotKey: r.indicatorType,
satisfied: r.satisfied,
thresholdLabel: r.thresholdLabel,
currentValue: r.currentValue,
}));
return live.map(liveRowToVirtual);
}
return base.map(row => {
const liveRow = liveById.get(row.id) ?? liveByKey.get(rowFallbackKey(row));
if (!liveRow) {
return { ...row, currentValue: null as number | null };
return { ...row, currentValue: null as number | null, satisfied: null };
}
return {
...row,
@@ -89,20 +96,20 @@ async function buildSnapshot(
market,
strategyId,
timeframe: [...new Set(baseRows.map(r => r.timeframe))].join(', '),
rows: baseRows.map(r => ({ ...r, currentValue: null })),
rows: baseRows.map(r => ({ ...r, currentValue: null, satisfied: null })),
updatedAt: Date.now(),
matchRate: 0,
};
}
const status = await fetchLiveConditionStatus(market, strategyId);
if (!status || status.market !== market) {
if (!status || status.market !== market || status.strategyId !== strategyId) {
if (baseRows.length === 0) return null;
return {
market,
strategyId,
timeframe: [...new Set(baseRows.map(r => r.timeframe))].join(', '),
rows: baseRows.map(r => ({ ...r, currentValue: null })),
rows: baseRows.map(r => ({ ...r, currentValue: null, satisfied: null })),
updatedAt: Date.now(),
matchRate: 0,
};
@@ -133,6 +140,7 @@ export function useVirtualIndicatorSnapshots(
const strategiesRef = useRef(strategies);
strategiesRef.current = strategies;
const pinnedRef = useRef<Set<string>>(new Set());
const refreshGenRef = useRef<Record<string, number>>({});
const targetsKey = targets.map(t => `${t.market}:${t.strategyId ?? ''}`).join('|');
const pinTargets = useCallback(async () => {
@@ -173,16 +181,17 @@ export function useVirtualIndicatorSnapshots(
const jobs = targets
.filter(t => t.strategyId != null)
.map(async t => {
const gen = (refreshGenRef.current[t.market] ?? 0) + 1;
refreshGenRef.current[t.market] = gen;
const strat = strats.find(s => s.id === t.strategyId);
const snap = await buildSnapshot(t.market, t.strategyId!, strat, running);
if (snap) {
setSnapshots(prev => ({ ...prev, [snap.market]: snap }));
}
if (!snap || refreshGenRef.current[t.market] !== gen) return snap;
if (snap.strategyId !== t.strategyId) return snap;
setSnapshots(prev => ({ ...prev, [snap.market]: snap }));
return snap;
});
await Promise.all(jobs);
// 제거된 종목 스냅샷 정리
const activeMarkets = new Set(targets.map(t => t.market));
setSnapshots(prev => {
const next = { ...prev };
@@ -201,6 +210,7 @@ export function useVirtualIndicatorSnapshots(
if (targets.length === 0) {
setSnapshots({});
pinnedRef.current.clear();
refreshGenRef.current = {};
return;
}
void refresh();