전략편집기 기준값 보조지표 설정값 동기화
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/** 보조지표 차트 hline 역할 — DSL에 숫자(K_70) 대신 저장해 DB 설정 변경 시 자동 반영 */
|
||||
export const THRESHOLD_HL_OVER = 'HL_OVER';
|
||||
export const THRESHOLD_HL_MID = 'HL_MID';
|
||||
export const THRESHOLD_HL_UNDER = 'HL_UNDER';
|
||||
|
||||
export type ThresholdHlineRole = typeof THRESHOLD_HL_OVER | typeof THRESHOLD_HL_MID | typeof THRESHOLD_HL_UNDER;
|
||||
|
||||
export function isThresholdSymbol(field?: string): boolean {
|
||||
return field === THRESHOLD_HL_OVER || field === THRESHOLD_HL_MID || field === THRESHOLD_HL_UNDER;
|
||||
}
|
||||
|
||||
export function isThresholdFieldOrSymbol(field?: string): boolean {
|
||||
return !!field && (field.startsWith('K_') || isThresholdSymbol(field));
|
||||
}
|
||||
|
||||
type HlThresh = { over?: number; mid?: number; under?: number };
|
||||
|
||||
export function resolveThresholdFromDef(
|
||||
field: string | undefined,
|
||||
indicatorType: string,
|
||||
hlThresh: Record<string, HlThresh>,
|
||||
): number | null {
|
||||
if (!field) return null;
|
||||
const th = hlThresh[indicatorType] ?? {};
|
||||
if (field === THRESHOLD_HL_OVER) return th.over ?? null;
|
||||
if (field === THRESHOLD_HL_MID) return th.mid ?? null;
|
||||
if (field === THRESHOLD_HL_UNDER) return th.under ?? null;
|
||||
if (field.startsWith('K_')) {
|
||||
const n = parseFloat(field.slice(2));
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 레거시 K_ 값 → hline 역할 심볼 (정확 일치 우선, 없으면 가장 가까운 역할) */
|
||||
export function inferThresholdSymbolFromLegacy(
|
||||
field: string | undefined,
|
||||
indicatorType: string,
|
||||
hlThresh: Record<string, HlThresh>,
|
||||
): string | undefined {
|
||||
if (!field?.startsWith('K_')) return field;
|
||||
const val = parseFloat(field.slice(2));
|
||||
if (!Number.isFinite(val)) return field;
|
||||
const th = hlThresh[indicatorType] ?? {};
|
||||
const eps = 0.0001;
|
||||
if (th.over != null && Math.abs(th.over - val) < eps) return THRESHOLD_HL_OVER;
|
||||
if (th.mid != null && Math.abs(th.mid - val) < eps) return THRESHOLD_HL_MID;
|
||||
if (th.under != null && Math.abs(th.under - val) < eps) return THRESHOLD_HL_UNDER;
|
||||
|
||||
const candidates: { role: ThresholdHlineRole; v: number }[] = [];
|
||||
if (th.over != null) candidates.push({ role: THRESHOLD_HL_OVER, v: th.over });
|
||||
if (th.mid != null) candidates.push({ role: THRESHOLD_HL_MID, v: th.mid });
|
||||
if (th.under != null) candidates.push({ role: THRESHOLD_HL_UNDER, v: th.under });
|
||||
if (candidates.length === 0) return defaultInheritedThresholdField(indicatorType);
|
||||
|
||||
let best = candidates[0];
|
||||
let bestDiff = Math.abs(best.v - val);
|
||||
for (const c of candidates.slice(1)) {
|
||||
const d = Math.abs(c.v - val);
|
||||
if (d < bestDiff) {
|
||||
best = c;
|
||||
bestDiff = d;
|
||||
}
|
||||
}
|
||||
return best.role;
|
||||
}
|
||||
|
||||
/** 상속 모드(thresholdOverride=false) — K_ 스냅샷을 hline 역할 심볼로 정규화 */
|
||||
export function resolveInheritedThresholdField(
|
||||
field: string | undefined,
|
||||
indicatorType: string,
|
||||
hlThresh: Record<string, HlThresh>,
|
||||
): string | undefined {
|
||||
if (!field) return field;
|
||||
if (isThresholdSymbol(field)) return field;
|
||||
if (field.startsWith('K_')) {
|
||||
return inferThresholdSymbolFromLegacy(field, indicatorType, hlThresh)
|
||||
?? defaultInheritedThresholdField(indicatorType);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
/** 상속 모드 기본 rightField — 과열선 역할 */
|
||||
export function defaultInheritedThresholdField(indicatorType: string): string {
|
||||
switch (indicatorType) {
|
||||
case 'DISPARITY':
|
||||
case 'VOLUME_OSC':
|
||||
case 'TRIX':
|
||||
return THRESHOLD_HL_MID;
|
||||
default:
|
||||
return THRESHOLD_HL_OVER;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user