가상 수정
This commit is contained in:
@@ -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 우선 */
|
||||
|
||||
Reference in New Issue
Block a user