전략편집기 지표요소값 오류 수정
This commit is contained in:
@@ -28,6 +28,11 @@ import {
|
|||||||
THRESHOLD_HL_UNDER,
|
THRESHOLD_HL_UNDER,
|
||||||
} from './thresholdSymbols';
|
} from './thresholdSymbols';
|
||||||
import { DEFAULT_START_CANDLE, normalizeStartCandleType } from './strategyStartNodes';
|
import { DEFAULT_START_CANDLE, normalizeStartCandleType } from './strategyStartNodes';
|
||||||
|
import {
|
||||||
|
getIndicatorPrimaryPeriod,
|
||||||
|
formatIndicatorPeriodLabel,
|
||||||
|
} from './strategyIndicatorPeriods';
|
||||||
|
import type { DefType } from './strategyEditorShared';
|
||||||
|
|
||||||
export interface IndicatorPeriodDef {
|
export interface IndicatorPeriodDef {
|
||||||
rsiPeriod: number;
|
rsiPeriod: number;
|
||||||
@@ -52,22 +57,19 @@ export const VALUE_FIELD_PREFIX: Record<string, string> = {
|
|||||||
INVEST_PSYCHOLOGICAL: 'INVEST_PSY_VALUE',
|
INVEST_PSYCHOLOGICAL: 'INVEST_PSY_VALUE',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getDefaultIndicatorPeriod(indicatorType: string, def: IndicatorPeriodDef): number {
|
export function getDefaultIndicatorPeriod(
|
||||||
switch (indicatorType) {
|
indicatorType: string,
|
||||||
case 'NEW_HIGH':
|
def: IndicatorPeriodDef | DefType,
|
||||||
case 'NEW_LOW':
|
): number {
|
||||||
return 9;
|
return getIndicatorPrimaryPeriod(indicatorType, def as DefType);
|
||||||
case 'RSI': return def.rsiPeriod;
|
}
|
||||||
case 'CCI': return def.cciPeriod;
|
|
||||||
case 'ADX': return def.adxPeriod;
|
/** @internal DefType 전체 필드 — 팔레트 라벨 등 */
|
||||||
case 'WILLIAMS_R': return def.williamsR;
|
export function getDefaultIndicatorPeriodLabel(
|
||||||
case 'TRIX': return def.trixPeriod;
|
indicatorType: string,
|
||||||
case 'VR': return def.vrPeriod;
|
def: IndicatorPeriodDef | DefType,
|
||||||
case 'PSYCHOLOGICAL':
|
): string {
|
||||||
case 'NEW_PSYCHOLOGICAL': return def.newPsy;
|
return formatIndicatorPeriodLabel(indicatorType, def as DefType);
|
||||||
case 'INVEST_PSYCHOLOGICAL': return def.investPsy;
|
|
||||||
default: return 14;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFieldPeriod(field?: string): number | null {
|
function parseFieldPeriod(field?: string): number | null {
|
||||||
|
|||||||
@@ -393,8 +393,9 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'ADX': {
|
case 'ADX': {
|
||||||
const { over, mid, under } = th({ over: 40, mid: 25, under: 20 });
|
const { over, mid, under } = th({ over: 40, mid: 25, under: 20 });
|
||||||
|
const adxP = cond ? getConditionValuePeriod({ ...cond, indicatorType: 'ADX' }, DEF) : DEF.adxPeriod;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'ADX_VALUE', label:`ADX 라인(${DEF.adxPeriod}일)` },
|
{ value:'ADX_VALUE', label:`ADX 라인(${adxP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -402,8 +403,9 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'TRIX': {
|
case 'TRIX': {
|
||||||
const { mid } = th({ mid:0 });
|
const { mid } = th({ mid:0 });
|
||||||
|
const trixP = cond ? getConditionValuePeriod({ ...cond, indicatorType: 'TRIX' }, DEF) : DEF.trixPeriod;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'TRIX_VALUE', label:`TRIX 라인(${DEF.trixPeriod}일)` },
|
{ value:'TRIX_VALUE', label:`TRIX 라인(${trixP}일)` },
|
||||||
{ value:'TRIX_SIGNAL', label:`TRIX 시그널(${DEF.trixSignal}일)` },
|
{ value:'TRIX_SIGNAL', label:`TRIX 시그널(${DEF.trixSignal}일)` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
]);
|
]);
|
||||||
@@ -449,8 +451,11 @@ export const getFieldOpts = (
|
|||||||
case 'PSYCHOLOGICAL':
|
case 'PSYCHOLOGICAL':
|
||||||
case 'NEW_PSYCHOLOGICAL': {
|
case 'NEW_PSYCHOLOGICAL': {
|
||||||
const { over, mid, under } = th({ over:75, mid:50, under:25 });
|
const { over, mid, under } = th({ over:75, mid:50, under:25 });
|
||||||
|
const psyP = cond
|
||||||
|
? getConditionValuePeriod({ ...cond, indicatorType: ind }, DEF)
|
||||||
|
: DEF.newPsy;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'PSY_VALUE', label:`심리도 라인(${DEF.newPsy}일)` },
|
{ value:'PSY_VALUE', label:`심리도 라인(${psyP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -458,8 +463,11 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'INVEST_PSYCHOLOGICAL': {
|
case 'INVEST_PSYCHOLOGICAL': {
|
||||||
const { over, mid, under } = th({ over:75, mid:50, under:25 });
|
const { over, mid, under } = th({ over:75, mid:50, under:25 });
|
||||||
|
const ipsyP = cond
|
||||||
|
? getConditionValuePeriod({ ...cond, indicatorType: 'INVEST_PSYCHOLOGICAL' }, DEF)
|
||||||
|
: DEF.investPsy;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'INVEST_PSY_VALUE', label:`투자심리도 라인(${DEF.investPsy}일)` },
|
{ value:'INVEST_PSY_VALUE', label:`투자심리도 라인(${ipsyP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -467,8 +475,9 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'WILLIAMS_R': {
|
case 'WILLIAMS_R': {
|
||||||
const { over, mid, under } = th({ over:-20, mid:-50, under:-80 });
|
const { over, mid, under } = th({ over:-20, mid:-50, under:-80 });
|
||||||
|
const wrP = cond ? getConditionValuePeriod({ ...cond, indicatorType: 'WILLIAMS_R' }, DEF) : DEF.williamsR;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'WILLIAMS_R_VALUE', label:`Williams %R 라인(${DEF.williamsR}일)` },
|
{ value:'WILLIAMS_R_VALUE', label:`Williams %R 라인(${wrP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -476,8 +485,9 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'BWI': {
|
case 'BWI': {
|
||||||
const { over, mid, under } = th({ over:80, mid:50, under:20 });
|
const { over, mid, under } = th({ over:80, mid:50, under:20 });
|
||||||
|
const bwiP = DEF.bwiPeriod;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'BWI_VALUE', label:`BWI 라인(${DEF.bwiPeriod}일)` },
|
{ value:'BWI_VALUE', label:`BWI 라인(${bwiP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -485,8 +495,9 @@ export const getFieldOpts = (
|
|||||||
}
|
}
|
||||||
case 'VR': {
|
case 'VR': {
|
||||||
const { over, mid, under } = th({ over:200, mid:100, under:50 });
|
const { over, mid, under } = th({ over:200, mid:100, under:50 });
|
||||||
|
const vrP = cond ? getConditionValuePeriod({ ...cond, indicatorType: 'VR' }, DEF) : DEF.vrPeriod;
|
||||||
return condOpts([
|
return condOpts([
|
||||||
{ value:'VR_VALUE', label:`VR 라인(${DEF.vrPeriod}일)` },
|
{ value:'VR_VALUE', label:`VR 라인(${vrP}일)` },
|
||||||
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
{ value:THRESHOLD_HL_OVER, label:`${overTerm}(${over})` },
|
||||||
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
{ value:THRESHOLD_HL_MID, label:`중앙선(${mid})` },
|
||||||
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
{ value:THRESHOLD_HL_UNDER, label:`${underTerm}(${under})` },
|
||||||
@@ -1002,9 +1013,14 @@ export const CondEditor: React.FC<CondEditorProps> = ({ cond, signalType, onChan
|
|||||||
disabled={isHoldType}
|
disabled={isHoldType}
|
||||||
onFieldChange={v => {
|
onFieldChange={v => {
|
||||||
const bases: Record<string, string> = {
|
const bases: Record<string, string> = {
|
||||||
RSI: 'RSI_VALUE', CCI: 'CCI_VALUE', ADX: 'ADX_VALUE',
|
RSI: 'RSI_VALUE',
|
||||||
WILLIAMS_R: 'WILLIAMS_R_VALUE', TRIX: 'TRIX_VALUE', VR: 'VR_VALUE',
|
CCI: 'CCI_VALUE',
|
||||||
PSYCHOLOGICAL: 'PSY_VALUE', NEW_PSYCHOLOGICAL: 'PSY_VALUE',
|
ADX: 'ADX_VALUE',
|
||||||
|
WILLIAMS_R: 'WILLIAMS_R_VALUE',
|
||||||
|
TRIX: 'TRIX_VALUE',
|
||||||
|
VR: 'VR_VALUE',
|
||||||
|
PSYCHOLOGICAL: 'PSY_VALUE',
|
||||||
|
NEW_PSYCHOLOGICAL: 'PSY_VALUE',
|
||||||
INVEST_PSYCHOLOGICAL: 'INVEST_PSY_VALUE',
|
INVEST_PSYCHOLOGICAL: 'INVEST_PSY_VALUE',
|
||||||
};
|
};
|
||||||
const base = bases[normalized.indicatorType];
|
const base = bases[normalized.indicatorType];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Connection, Edge, Node } from '@xyflow/react';
|
import type { Connection, Edge, Node } from '@xyflow/react';
|
||||||
import type { LogicNode, ConditionDSL } from './strategyTypes';
|
import type { LogicNode, ConditionDSL } from './strategyTypes';
|
||||||
import { nodeToText, type DefType } from './strategyEditorShared';
|
import { nodeToText, type DefType } from './strategyEditorShared';
|
||||||
|
import { formatIndicatorPeriodLabel } from './strategyIndicatorPeriods';
|
||||||
import {
|
import {
|
||||||
START_NODE_ID,
|
START_NODE_ID,
|
||||||
defaultStartMeta,
|
defaultStartMeta,
|
||||||
@@ -735,17 +736,7 @@ export function logicNodeToFlow(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getIndicatorPeriodLabel(indicator: string, def: DefType): string {
|
export function getIndicatorPeriodLabel(indicator: string, def: DefType): string {
|
||||||
switch (indicator) {
|
return formatIndicatorPeriodLabel(indicator, def);
|
||||||
case 'RSI': return String(def.rsiPeriod);
|
|
||||||
case 'MACD': return `${def.macdFast}/${def.macdSlow}`;
|
|
||||||
case 'CCI': return String(def.cciPeriod);
|
|
||||||
case 'STOCHASTIC': return `${def.stochK}/${def.stochD}`;
|
|
||||||
case 'ADX': return String(def.adxPeriod);
|
|
||||||
case 'MA': return String(def.maLines[0] ?? 5);
|
|
||||||
case 'EMA': return String(def.maLines[0] ?? 5);
|
|
||||||
case 'BOLLINGER': return String(def.bbPeriod);
|
|
||||||
default: return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 트리에서 노드 추출 (부모에서 제거 후 반환) */
|
/** 트리에서 노드 추출 (부모에서 제거 후 반환) */
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* 전략편집기 — 보조지표 설정(DEF)에서 기간 표시·기본값 조회.
|
||||||
|
* 팔레트 칩, PaletteItemModal, getDefaultIndicatorPeriod, getFieldOpts 라벨에 공통 사용.
|
||||||
|
*/
|
||||||
|
import type { DefType } from './strategyEditorShared';
|
||||||
|
|
||||||
|
/** 팔레트·요약용 기간 문자열 (복수 파라미터는 슬래시 구분) */
|
||||||
|
export function formatIndicatorPeriodLabel(indicator: string, def: DefType): string {
|
||||||
|
switch (indicator) {
|
||||||
|
case 'RSI':
|
||||||
|
return String(def.rsiPeriod);
|
||||||
|
case 'CCI':
|
||||||
|
return String(def.cciPeriod);
|
||||||
|
case 'ADX':
|
||||||
|
return String(def.adxPeriod);
|
||||||
|
case 'WILLIAMS_R':
|
||||||
|
return String(def.williamsR);
|
||||||
|
case 'TRIX':
|
||||||
|
return `${def.trixPeriod}/${def.trixSignal}`;
|
||||||
|
case 'VR':
|
||||||
|
return String(def.vrPeriod);
|
||||||
|
case 'BWI':
|
||||||
|
return String(def.bwiPeriod);
|
||||||
|
case 'OBV':
|
||||||
|
return def.obvPeriod === def.obvSignal
|
||||||
|
? String(def.obvPeriod)
|
||||||
|
: `${def.obvPeriod}/${def.obvSignal}`;
|
||||||
|
case 'MACD':
|
||||||
|
return `${def.macdFast}/${def.macdSlow}/${def.macdSignal}`;
|
||||||
|
case 'STOCHASTIC':
|
||||||
|
return `${def.stochK}/${def.stochD}`;
|
||||||
|
case 'DMI':
|
||||||
|
return String(def.dmiPeriod);
|
||||||
|
case 'VOLUME_OSC':
|
||||||
|
return `${def.volOscShort}/${def.volOscLong}`;
|
||||||
|
case 'DISPARITY':
|
||||||
|
return `${def.dispUltra}/${def.dispShort}/${def.dispMid}/${def.dispLong}`;
|
||||||
|
case 'PSYCHOLOGICAL':
|
||||||
|
case 'NEW_PSYCHOLOGICAL':
|
||||||
|
return String(def.newPsy);
|
||||||
|
case 'INVEST_PSYCHOLOGICAL':
|
||||||
|
return String(def.investPsy);
|
||||||
|
case 'MA':
|
||||||
|
return def.maLines.length ? def.maLines.join('/') : '5';
|
||||||
|
case 'EMA':
|
||||||
|
return def.maLines.length ? def.maLines.slice(0, 4).join('/') : '5';
|
||||||
|
case 'BOLLINGER':
|
||||||
|
return `${def.bbPeriod}(σ${def.bbStdDev})`;
|
||||||
|
case 'ICHIMOKU':
|
||||||
|
return `${def.ichTenkan}/${def.ichKijun}/${def.ichSenkouB}`;
|
||||||
|
case 'NEW_HIGH':
|
||||||
|
case 'NEW_LOW':
|
||||||
|
return '9';
|
||||||
|
case 'VOLUME':
|
||||||
|
return '';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 팔레트·프리셋용 대표 기간(일) — 단일 숫자 입력 지표 */
|
||||||
|
export function getIndicatorPrimaryPeriod(indicator: string, def: DefType): number {
|
||||||
|
switch (indicator) {
|
||||||
|
case 'RSI':
|
||||||
|
return def.rsiPeriod;
|
||||||
|
case 'CCI':
|
||||||
|
return def.cciPeriod;
|
||||||
|
case 'ADX':
|
||||||
|
return def.adxPeriod;
|
||||||
|
case 'WILLIAMS_R':
|
||||||
|
return def.williamsR;
|
||||||
|
case 'TRIX':
|
||||||
|
return def.trixPeriod;
|
||||||
|
case 'VR':
|
||||||
|
return def.vrPeriod;
|
||||||
|
case 'BWI':
|
||||||
|
return def.bwiPeriod;
|
||||||
|
case 'OBV':
|
||||||
|
return def.obvPeriod;
|
||||||
|
case 'MACD':
|
||||||
|
return def.macdFast;
|
||||||
|
case 'STOCHASTIC':
|
||||||
|
return def.stochK;
|
||||||
|
case 'DMI':
|
||||||
|
return def.dmiPeriod;
|
||||||
|
case 'VOLUME_OSC':
|
||||||
|
return def.volOscShort;
|
||||||
|
case 'DISPARITY':
|
||||||
|
return def.dispShort;
|
||||||
|
case 'PSYCHOLOGICAL':
|
||||||
|
case 'NEW_PSYCHOLOGICAL':
|
||||||
|
return def.newPsy;
|
||||||
|
case 'INVEST_PSYCHOLOGICAL':
|
||||||
|
return def.investPsy;
|
||||||
|
case 'MA':
|
||||||
|
case 'EMA':
|
||||||
|
return def.maLines[0] ?? 5;
|
||||||
|
case 'BOLLINGER':
|
||||||
|
return def.bbPeriod;
|
||||||
|
case 'ICHIMOKU':
|
||||||
|
return def.ichTenkan;
|
||||||
|
case 'NEW_HIGH':
|
||||||
|
case 'NEW_LOW':
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
return 14;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user