가상 수정

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
+58 -14
View File
@@ -9,9 +9,23 @@ export type ConditionStatus = 'match' | 'pending' | 'nomatch' | 'unknown';
export interface ConditionMetric {
row: VirtualConditionRow & { currentValue: number | null };
status: ConditionStatus;
/** 조건 매칭율 0~100 */
matchRate: number;
/** @deprecated matchRate 와 동일 — 하위 호환 */
progress: number | null;
}
export type HeatTier = 'nomatch' | 'pending' | 'match';
/** Heatmap 색상 — Mismatch(빨강) · Pending(오렌지) · Match(푸른색) */
export function resolveHeatTier(matchRate: number, status: ConditionStatus): HeatTier {
if (status === 'match' || matchRate >= 100) return 'match';
if (status === 'pending') return 'pending';
if (status === 'nomatch') return 'nomatch';
if (matchRate >= 45) return 'pending';
return 'nomatch';
}
export type TrafficLightState = 'red' | 'yellow' | 'blue';
const PENDING_PROGRESS = 72;
@@ -53,6 +67,35 @@ export function computeConditionProgress(
}
}
const CROSS_CONDITION_TYPES = new Set([
'CROSS_UP', 'CROSS_DOWN', 'SLOPE_UP', 'SLOPE_DOWN',
]);
/** 조건별 매칭율 (0~100) — 백엔드 Ta4j satisfied 우선 */
export function computeConditionMatchRate(
row: VirtualConditionRow & { currentValue: number | null },
): number {
if (row.satisfied === true) return 100;
if (row.satisfied === false) {
if (CROSS_CONDITION_TYPES.has(row.conditionType)) return 0;
const progress = computeConditionProgress(
row.conditionType,
row.currentValue,
row.targetValue,
);
if (progress == null) return 0;
return Math.min(99, Math.max(0, Math.round(progress)));
}
if (row.currentValue == null) return 0;
const progress = computeConditionProgress(
row.conditionType,
row.currentValue,
row.targetValue,
);
if (progress == null) return 0;
return Math.min(99, Math.max(0, Math.round(progress)));
}
export function getConditionStatus(
conditionType: string,
current: number | null,
@@ -61,6 +104,7 @@ export function getConditionStatus(
): ConditionStatus {
if (satisfied === true) return 'match';
if (satisfied === false) {
if (CROSS_CONDITION_TYPES.has(conditionType)) return 'nomatch';
const progress = computeConditionProgress(conditionType, current, target);
if (progress != null && progress >= PENDING_PROGRESS) return 'pending';
return 'nomatch';
@@ -105,20 +149,20 @@ export function formatStrategyThreshold(
export function buildConditionMetrics(
rows: Array<VirtualConditionRow & { currentValue: number | null }>,
): ConditionMetric[] {
return rows.map(row => ({
row,
status: getConditionStatus(
row.conditionType,
row.currentValue,
row.targetValue,
row.satisfied,
),
progress: row.satisfied === true
? 100
: row.satisfied === false
? (computeConditionProgress(row.conditionType, row.currentValue, row.targetValue) ?? 0)
: computeConditionProgress(row.conditionType, row.currentValue, row.targetValue),
}));
return rows.map(row => {
const matchRate = computeConditionMatchRate(row);
return {
row,
status: getConditionStatus(
row.conditionType,
row.currentValue,
row.targetValue,
row.satisfied,
),
matchRate,
progress: matchRate,
};
});
}
/** 전체 매매조건 일치율 — 백엔드 matchRate 우선 */