Files
goldenChart/frontend/src/utils/strategyEvaluationMerge.ts
T
2026-06-12 18:13:25 +09:00

60 lines
2.4 KiB
TypeScript

/** live-conditions 행 ↔ 전략 DSL 행 병합 (useVirtualIndicatorSnapshots 와 동일) */
import type { LiveConditionRowDto } from './backendApi';
import { formatIndicatorDisplayLabel } from './indicatorRegistry';
import { normalizeConditionRow } from './virtualSignalMetrics';
import type { VirtualConditionRow } from './virtualStrategyConditions';
function rowFallbackKey(row: Pick<VirtualConditionRow, 'side' | 'timeframe' | 'indicatorType' | 'conditionType' | 'targetValue' | 'plotKey'>): string {
return `${row.side}:${row.timeframe}:${row.indicatorType}:${row.conditionType}:${row.targetValue ?? ''}:${row.plotKey}`;
}
function liveFallbackKey(r: LiveConditionRowDto): string {
const plotKey = r.plotKey ?? r.indicatorType;
return `${r.side}:${r.timeframe}:${r.indicatorType}:${r.conditionType}:${r.targetValue ?? ''}:${plotKey}`;
}
export function mergeRows(
base: VirtualConditionRow[],
live: LiveConditionRowDto[],
): Array<VirtualConditionRow & { currentValue: number | null }> {
if (live.length === 0) {
return base.map(row => normalizeConditionRow({ ...row, currentValue: null, satisfied: null }));
}
const baseById = new Map(base.map(r => [r.id, r]));
const baseByKey = new Map(base.map(r => [rowFallbackKey(r), r]));
const matchedBaseIds = new Set<string>();
const merged = live.map(lr => {
const baseRow = baseById.get(lr.id) ?? baseByKey.get(liveFallbackKey(lr));
if (baseRow) matchedBaseIds.add(baseRow.id);
const plotKey = lr.plotKey ?? lr.indicatorType;
return normalizeConditionRow({
id: lr.id,
indicatorType: lr.indicatorType,
displayName: baseRow?.displayName ?? formatIndicatorDisplayLabel(lr.indicatorType),
conditionType: lr.conditionType,
conditionLabel: lr.conditionLabel ?? baseRow?.conditionLabel ?? lr.conditionType,
targetValue: lr.targetValue ?? baseRow?.targetValue ?? null,
timeframe: lr.timeframe,
side: lr.side as 'buy' | 'sell',
plotKey,
satisfied: lr.satisfied,
thresholdLabel: lr.thresholdLabel ?? baseRow?.thresholdLabel,
currentValue: lr.currentValue,
});
});
for (const row of base) {
if (matchedBaseIds.has(row.id)) continue;
const hasLive = live.some(
lr => lr.id === row.id || liveFallbackKey(lr) === rowFallbackKey(row),
);
if (!hasLive) {
merged.push(normalizeConditionRow({ ...row, currentValue: null, satisfied: null }));
}
}
return merged;
}