60 lines
2.4 KiB
TypeScript
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;
|
|
}
|