전략편집기 기준값 보조지표 설정값 동기화

This commit is contained in:
Macbook
2026-05-28 09:20:06 +09:00
parent 9137864f48
commit e2816b037f
18 changed files with 710 additions and 153 deletions
+86 -22
View File
@@ -18,6 +18,15 @@ import {
parsePriorExtremePeriod,
syncPriceExtremeSimpleFields,
} from './priceExtremeIndicators';
import {
isThresholdFieldOrSymbol,
isThresholdSymbol,
resolveInheritedThresholdField,
resolveThresholdFromDef,
THRESHOLD_HL_MID,
THRESHOLD_HL_OVER,
THRESHOLD_HL_UNDER,
} from './thresholdSymbols';
import { DEFAULT_START_CANDLE, normalizeStartCandleType } from './strategyStartNodes';
export interface IndicatorPeriodDef {
@@ -164,29 +173,99 @@ export function thresholdField(value: number): string {
}
export function hasEditableThreshold(cond: ConditionDSL): boolean {
return parseThresholdField(cond.rightField) != null
|| parseThresholdField(cond.leftField) != null;
return isThresholdFieldOrSymbol(cond.rightField)
|| isThresholdFieldOrSymbol(cond.leftField)
|| parseThresholdField(cond.rightField) != null;
}
/** 보조지표 차트(DB) hline 기준값 — 전략 오버라이드와 무관하게 항상 DEF에서 조회 */
export function getChartReferenceThreshold(
cond: ConditionDSL,
side: 'left' | 'right',
inheritedField: string | undefined,
def: { hlThresh: Record<string, { over?: number; mid?: number; under?: number }> },
): number | null {
const raw = side === 'left' ? cond.leftField : (inheritedField ?? cond.rightField);
if (!raw) return null;
const field = isThresholdOverridden(cond)
? raw
: resolveInheritedThresholdField(raw, cond.indicatorType, def.hlThresh);
if (!field) return null;
return resolveThresholdFromDef(field, cond.indicatorType, def.hlThresh);
}
/**
* 임계값 표시 — thresholdOverride 가 false 이면 inheritedField(보조지표 설정 DEF) 우선.
* 전략 평가용 임계값 — thresholdOverride=true 이면 targetValue/K_, 아니면 차트 DEF.
*/
export function getConditionThreshold(
cond: ConditionDSL,
side: 'left' | 'right',
inheritedField?: string,
def?: { hlThresh: Record<string, { over?: number; mid?: number; under?: number }> },
): number | null {
if (!isThresholdOverridden(cond) && inheritedField) {
const fromDef = parseThresholdField(inheritedField);
if (fromDef != null) return fromDef;
}
if (isThresholdOverridden(cond) && cond.targetValue != null && Number.isFinite(cond.targetValue)) {
return cond.targetValue;
}
if (!isThresholdOverridden(cond)) {
const rawField = inheritedField ?? (side === 'left' ? cond.leftField : cond.rightField);
const roleField = def
? resolveInheritedThresholdField(rawField, cond.indicatorType, def.hlThresh)
: rawField;
if (def && roleField) {
const fromDef = resolveThresholdFromDef(roleField, cond.indicatorType, def.hlThresh);
if (fromDef != null) return fromDef;
}
if (inheritedField && def) {
const inheritedRole = resolveInheritedThresholdField(
inheritedField,
cond.indicatorType,
def.hlThresh,
);
const fromInherited = resolveThresholdFromDef(
inheritedRole,
cond.indicatorType,
def.hlThresh,
);
if (fromInherited != null) return fromInherited;
}
}
const field = side === 'left' ? cond.leftField : cond.rightField;
return parseThresholdField(field);
}
export function setConditionThreshold(
cond: ConditionDSL,
side: 'left' | 'right',
value: number,
def?: { hlThresh: Record<string, { over?: number; mid?: number; under?: number }> },
): ConditionDSL {
const fieldKey = side === 'left' ? 'leftField' : 'rightField';
const current = cond[fieldKey];
if (!isThresholdFieldOrSymbol(current)) return cond;
const inheritedField = side === 'right'
? (current?.startsWith('K_') || isThresholdSymbol(current) ? current : THRESHOLD_HL_OVER)
: current;
const chartRef = def
? getChartReferenceThreshold(cond, side, inheritedField, def)
: null;
if (chartRef != null && Math.abs(chartRef - value) < 0.0001) {
const role = isThresholdSymbol(inheritedField)
? inheritedField
: (side === 'right' ? THRESHOLD_HL_OVER : inheritedField);
const { targetValue: _t, ...rest } = cond;
return { ...rest, [fieldKey]: role, thresholdOverride: false };
}
return {
...cond,
[fieldKey]: thresholdField(value),
targetValue: value,
thresholdOverride: true,
};
}
export function setConditionValuePeriod(
cond: ConditionDSL,
period: number,
@@ -213,21 +292,6 @@ export function setConditionRightPeriod(cond: ConditionDSL, period: number): Con
return syncCompositeFields({ ...cond, composite: true, rightPeriod: p, rightPeriodOverride: true });
}
export function setConditionThreshold(
cond: ConditionDSL,
side: 'left' | 'right',
value: number,
): ConditionDSL {
const fieldKey = side === 'left' ? 'leftField' : 'rightField';
const current = cond[fieldKey];
if (!current?.startsWith('K_')) return cond;
return {
...cond,
[fieldKey]: thresholdField(value),
targetValue: value,
thresholdOverride: true,
};
}
/** 신규 조건 노드 — 보조지표 설정 기본값 상속(오버라이드 없음) */
export function initConditionPeriodsInherit(