전략평가 화면 수정

This commit is contained in:
Macbook
2026-06-12 18:13:25 +09:00
parent b560b9de5c
commit a3f0584e72
13 changed files with 742 additions and 106 deletions
+33 -36
View File
@@ -13,50 +13,47 @@ function liveFallbackKey(r: LiveConditionRowDto): string {
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 normalizeConditionRow({
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,
});
}
export function mergeRows(
base: VirtualConditionRow[],
live: LiveConditionRowDto[],
): Array<VirtualConditionRow & { currentValue: number | null }> {
const liveById = new Map<string, LiveConditionRowDto>();
const liveByKey = new Map<string, LiveConditionRowDto>();
for (const r of live) {
liveById.set(r.id, r);
liveByKey.set(liveFallbackKey(r), r);
if (live.length === 0) {
return base.map(row => normalizeConditionRow({ ...row, currentValue: null, satisfied: null }));
}
if (base.length === 0) {
return live.map(liveRowToVirtual);
}
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>();
return base.map(row => {
const liveRow = liveById.get(row.id) ?? liveByKey.get(rowFallbackKey(row));
if (!liveRow) {
return normalizeConditionRow({ ...row, currentValue: null, satisfied: null });
}
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({
...row,
satisfied: liveRow.satisfied,
thresholdLabel: liveRow.thresholdLabel,
currentValue: liveRow.currentValue,
targetValue: liveRow.targetValue ?? row.targetValue,
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;
}