전략편집기 기준값 보조지표 설정값 동기화
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user