가상투자 종목카드박스 레이아웃 수정
This commit is contained in:
@@ -4,11 +4,20 @@ import {
|
||||
compositeFieldLabel,
|
||||
compositeValueField,
|
||||
getCompositeDefaultPeriods,
|
||||
getDonchianFieldOpts,
|
||||
isDonchianComposite,
|
||||
isThresholdField,
|
||||
parseDonchianPeriod,
|
||||
parsePeriodFromCompositeField,
|
||||
syncCompositeFields,
|
||||
type CompositePeriodDef,
|
||||
} from './compositeIndicators';
|
||||
import {
|
||||
isPriceExtremeIndicator,
|
||||
migratePriceExtremeCondition,
|
||||
parsePriorExtremePeriod,
|
||||
syncPriceExtremeSimpleFields,
|
||||
} from './priceExtremeIndicators';
|
||||
import { DEFAULT_START_CANDLE, normalizeStartCandleType } from './strategyStartNodes';
|
||||
|
||||
export interface IndicatorPeriodDef {
|
||||
@@ -36,6 +45,9 @@ const VALUE_FIELD_PREFIX: Record<string, string> = {
|
||||
|
||||
export function getDefaultIndicatorPeriod(indicatorType: string, def: IndicatorPeriodDef): number {
|
||||
switch (indicatorType) {
|
||||
case 'NEW_HIGH':
|
||||
case 'NEW_LOW':
|
||||
return 9;
|
||||
case 'RSI': return def.rsiPeriod;
|
||||
case 'CCI': return def.cciPeriod;
|
||||
case 'ADX': return def.adxPeriod;
|
||||
@@ -59,6 +71,12 @@ function parseFieldPeriod(field?: string): number | null {
|
||||
|
||||
/** 조건 노드의 RSI 등 값(좌측) 기간 */
|
||||
export function getConditionValuePeriod(cond: ConditionDSL, def: IndicatorPeriodDef): number {
|
||||
if (isPriceExtremeIndicator(cond.indicatorType)) {
|
||||
if (cond.period && cond.period > 0) return cond.period;
|
||||
const fromRight = parsePriorExtremePeriod(cond.rightField);
|
||||
if (fromRight) return fromRight;
|
||||
return getDefaultIndicatorPeriod(cond.indicatorType, def);
|
||||
}
|
||||
if (cond.composite) {
|
||||
if (cond.leftPeriod && cond.leftPeriod > 0) return cond.leftPeriod;
|
||||
const fromField = parsePeriodFromCompositeField(cond.indicatorType, cond.leftField);
|
||||
@@ -100,6 +118,7 @@ export function isValuePeriodFieldStored(indicatorType: string, field?: string):
|
||||
}
|
||||
|
||||
export function usesValuePeriodField(cond: ConditionDSL): boolean {
|
||||
if (isPriceExtremeIndicator(cond.indicatorType)) return true;
|
||||
if (cond.composite) return true;
|
||||
const prefix = VALUE_FIELD_PREFIX[cond.indicatorType];
|
||||
if (!prefix) return false;
|
||||
@@ -133,6 +152,9 @@ export function setConditionValuePeriod(
|
||||
_def: IndicatorPeriodDef,
|
||||
): ConditionDSL {
|
||||
const p = Math.max(1, Math.min(500, Math.round(period)));
|
||||
if (isPriceExtremeIndicator(cond.indicatorType)) {
|
||||
return syncPriceExtremeSimpleFields({ ...cond, period: p });
|
||||
}
|
||||
if (cond.composite) {
|
||||
return syncCompositeFields({ ...cond, composite: true, leftPeriod: p });
|
||||
}
|
||||
@@ -170,6 +192,10 @@ export function initConditionPeriods(
|
||||
condition: ConditionDSL,
|
||||
def: IndicatorPeriodDef,
|
||||
): ConditionDSL {
|
||||
if (isPriceExtremeIndicator(indicatorType)) {
|
||||
const period = condition.period ?? getDefaultIndicatorPeriod(indicatorType, def);
|
||||
return syncPriceExtremeSimpleFields({ ...condition, period });
|
||||
}
|
||||
if (condition.composite) return condition;
|
||||
const prefix = VALUE_FIELD_PREFIX[indicatorType];
|
||||
if (!prefix) return condition;
|
||||
@@ -191,9 +217,19 @@ const COMMON_PERIODS = [5, 7, 9, 10, 12, 13, 14, 20, 21, 26, 28, 50, 60, 120];
|
||||
|
||||
export function getPeriodPresetOptions(indicatorType: string, def: IndicatorPeriodDef): number[] {
|
||||
const base = getDefaultIndicatorPeriod(indicatorType, def);
|
||||
if (isPriceExtremeIndicator(indicatorType)) {
|
||||
return [...new Set([base, 5, 9, 10, 20, 55, ...COMMON_PERIODS])].sort((a, b) => a - b);
|
||||
}
|
||||
return [...new Set([base, ...COMMON_PERIODS])].sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
export function getPeriodSettingsLabel(cond: ConditionDSL): string | null {
|
||||
if (isPriceExtremeIndicator(cond.indicatorType)) {
|
||||
return cond.indicatorType === 'NEW_LOW' ? '신저가 기간 (봉)' : '신고가 기간 (봉)';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 복합지표 요소1(단기)·요소2(장기) 기간 프리셋 */
|
||||
export function getCompositePeriodPresetOptions(
|
||||
indicatorType: string,
|
||||
@@ -242,6 +278,18 @@ export function getCompositeFieldOpts(
|
||||
: getConditionRightPeriod(cond, def);
|
||||
const presets = getCompositePeriodPresetOptions(indicatorType, def, side);
|
||||
const periods = [...new Set([...presets, current])].sort((a, b) => a - b);
|
||||
|
||||
if (isDonchianComposite(indicatorType)) {
|
||||
const opts = getDonchianFieldOpts(periods);
|
||||
const cur = slot === 1 ? cond.leftField : cond.rightField;
|
||||
if (cur && !opts.some(o => o.value === cur)) {
|
||||
const p = parseDonchianPeriod(cur);
|
||||
const label = p != null ? compositeFieldLabel(indicatorType, slot, p) : cur;
|
||||
return [{ value: cur, label }, ...opts];
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
return periods.map(p => ({
|
||||
value: compositeValueField(indicatorType, p),
|
||||
label: compositeFieldLabel(indicatorType, slot, p),
|
||||
|
||||
Reference in New Issue
Block a user