보조지표 설정 저장 오류
This commit is contained in:
@@ -1589,13 +1589,14 @@ export function useChartWorkspace({
|
|||||||
cfg = { ...fromConfig, id: newIndId(), type: def.type };
|
cfg = { ...fromConfig, id: newIndId(), type: def.type };
|
||||||
} else {
|
} else {
|
||||||
const params = getParams(type, def.defaultParams);
|
const params = getParams(type, def.defaultParams);
|
||||||
const { plots, hlines, cloudColors, bandBackground } = getVisualConfig(type, def.plots, def.hlines);
|
const { plots, hlines, cloudColors, bandBackground, plotVisibility } = getVisualConfig(type, def.plots, def.hlines);
|
||||||
cfg = {
|
cfg = {
|
||||||
id: newIndId(),
|
id: newIndId(),
|
||||||
type: def.type,
|
type: def.type,
|
||||||
params,
|
params,
|
||||||
plots,
|
plots,
|
||||||
hlines,
|
hlines,
|
||||||
|
...(plotVisibility ? { plotVisibility } : {}),
|
||||||
...(cloudColors ? { cloudColors } : {}),
|
...(cloudColors ? { cloudColors } : {}),
|
||||||
...(bandBackground ? { bandBackground } : {}),
|
...(bandBackground ? { bandBackground } : {}),
|
||||||
};
|
};
|
||||||
@@ -1695,6 +1696,7 @@ export function useChartWorkspace({
|
|||||||
updated.hlines,
|
updated.hlines,
|
||||||
updated.cloudColors,
|
updated.cloudColors,
|
||||||
updated.bandBackground,
|
updated.bandBackground,
|
||||||
|
updated.plotVisibility,
|
||||||
);
|
);
|
||||||
|
|
||||||
const applyUpdate = (prev: IndicatorConfig[]): IndicatorConfig[] => {
|
const applyUpdate = (prev: IndicatorConfig[]): IndicatorConfig[] => {
|
||||||
@@ -1785,7 +1787,7 @@ export function useChartWorkspace({
|
|||||||
applyChartIndicators(sortIndicatorsByTypeOrder(chartIndicators));
|
applyChartIndicators(sortIndicatorsByTypeOrder(chartIndicators));
|
||||||
allConfigs.forEach(ind => {
|
allConfigs.forEach(ind => {
|
||||||
saveParams(ind.type, ind.params);
|
saveParams(ind.type, ind.params);
|
||||||
saveVisual(ind.type, ind.plots, ind.hlines, ind.cloudColors, ind.bandBackground);
|
saveVisual(ind.type, ind.plots, ind.hlines, ind.cloudColors, ind.bandBackground, ind.plotVisibility);
|
||||||
});
|
});
|
||||||
setShowBulkIndSettings(false);
|
setShowBulkIndSettings(false);
|
||||||
}, [applyChartIndicators, saveParams, saveVisual]);
|
}, [applyChartIndicators, saveParams, saveVisual]);
|
||||||
|
|||||||
@@ -650,6 +650,7 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
|
|||||||
updated.hlines,
|
updated.hlines,
|
||||||
updated.cloudColors,
|
updated.cloudColors,
|
||||||
updated.bandBackground,
|
updated.bandBackground,
|
||||||
|
updated.plotVisibility,
|
||||||
);
|
);
|
||||||
}, [saveParams, saveVisual]);
|
}, [saveParams, saveVisual]);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import type { EvalIndicatorParams } from '../../utils/strategyEvaluationParams';
|
|||||||
import { DISPLAY_COUNT } from '../../hooks/useUpbitData';
|
import { DISPLAY_COUNT } from '../../hooks/useUpbitData';
|
||||||
import { buildVirtualTradingChartIndicators } from '../../utils/strategyToChartIndicators';
|
import { buildVirtualTradingChartIndicators } from '../../utils/strategyToChartIndicators';
|
||||||
import { buildEvalParamsFromStrategy } from '../../utils/strategyEvaluationParams';
|
import { buildEvalParamsFromStrategy } from '../../utils/strategyEvaluationParams';
|
||||||
|
import { indicatorDefaultsFingerprint } from '../../utils/indicatorDefaultsFingerprint';
|
||||||
import { repairUtf8Mojibake } from '../../utils/textEncoding';
|
import { repairUtf8Mojibake } from '../../utils/textEncoding';
|
||||||
import StrategyEvaluationBarSelector, {
|
import StrategyEvaluationBarSelector, {
|
||||||
resolveBarIndexAtChartClick,
|
resolveBarIndexAtChartClick,
|
||||||
@@ -102,7 +103,7 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
evalLoading = false,
|
evalLoading = false,
|
||||||
onSignalsChange,
|
onSignalsChange,
|
||||||
}) => {
|
}) => {
|
||||||
const { getParams: baseGetParams, getVisualConfig: baseGetVisual } = useIndicatorSettings();
|
const { getParams: baseGetParams, getVisualConfig: baseGetVisual, settingsRevision } = useIndicatorSettings();
|
||||||
const getParams = getParamsOverride ?? baseGetParams;
|
const getParams = getParamsOverride ?? baseGetParams;
|
||||||
const getVisualConfig = getVisualConfigOverride ?? baseGetVisual;
|
const getVisualConfig = getVisualConfigOverride ?? baseGetVisual;
|
||||||
const { defaults: appDefaults } = useAppSettings();
|
const { defaults: appDefaults } = useAppSettings();
|
||||||
@@ -126,7 +127,7 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
const indicators = useMemo(() => {
|
const indicators = useMemo(() => {
|
||||||
if (!strategy) return [] as IndicatorConfig[];
|
if (!strategy) return [] as IndicatorConfig[];
|
||||||
return buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig);
|
return buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig);
|
||||||
}, [strategy, getParams, getVisualConfig]);
|
}, [strategy, getParams, getVisualConfig, settingsRevision]);
|
||||||
|
|
||||||
const auxPaneCount = useMemo(
|
const auxPaneCount = useMemo(
|
||||||
() => countNonOverlayIndicatorPanes(indicators, isOverlayType),
|
() => countNonOverlayIndicatorPanes(indicators, isOverlayType),
|
||||||
@@ -145,6 +146,11 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
[strategy, getParams],
|
[strategy, getParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const indicatorRenderKey = useMemo(
|
||||||
|
() => indicators.map(i => indicatorDefaultsFingerprint(i)).join('|'),
|
||||||
|
[indicators],
|
||||||
|
);
|
||||||
|
|
||||||
const resolveInitialDisplayCount = useCallback(
|
const resolveInitialDisplayCount = useCallback(
|
||||||
(plotWidth: number) => {
|
(plotWidth: number) => {
|
||||||
const approx = Math.floor(plotWidth / 6);
|
const approx = Math.floor(plotWidth / 6);
|
||||||
@@ -473,7 +479,7 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
{!loading && !error && bars.length > 0 && (
|
{!loading && !error && bars.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<TradingChart
|
<TradingChart
|
||||||
key={`${market}-${timeframe}-${strategy?.id ?? 0}-${paramsRevision}-${indicators.map(i => i.id).join(',')}`}
|
key={`${market}-${timeframe}-${strategy?.id ?? 0}-${paramsRevision}-${settingsRevision}-${indicatorRenderKey}`}
|
||||||
bars={bars}
|
bars={bars}
|
||||||
barsMarket={market}
|
barsMarket={market}
|
||||||
market={market}
|
market={market}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ type AllSettings = Record<string, ParamMap>;
|
|||||||
export interface IndicatorVisual {
|
export interface IndicatorVisual {
|
||||||
plots?: PlotDef[];
|
plots?: PlotDef[];
|
||||||
hlines?: HLineDef[];
|
hlines?: HLineDef[];
|
||||||
|
/** 지표선 on/off — plot id → visible */
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
cloudColors?: IchimokuCloudColors;
|
cloudColors?: IchimokuCloudColors;
|
||||||
/** 볼린저밴드 어퍼~로우어 배경 (업비트 백그라운드 그리기) */
|
/** 볼린저밴드 어퍼~로우어 배경 (업비트 백그라운드 그리기) */
|
||||||
bandBackground?: HlinesBackground;
|
bandBackground?: HlinesBackground;
|
||||||
@@ -56,6 +58,7 @@ export interface IndicatorVisual {
|
|||||||
export interface IndicatorVisualConfig {
|
export interface IndicatorVisualConfig {
|
||||||
plots: PlotDef[];
|
plots: PlotDef[];
|
||||||
hlines: HLineDef[];
|
hlines: HLineDef[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
cloudColors?: IchimokuCloudColors;
|
cloudColors?: IchimokuCloudColors;
|
||||||
bandBackground?: HlinesBackground;
|
bandBackground?: HlinesBackground;
|
||||||
}
|
}
|
||||||
@@ -243,6 +246,7 @@ export function useIndicatorSettings(sessionKey = 0, enabled = true) {
|
|||||||
plots: cfg.plots,
|
plots: cfg.plots,
|
||||||
hlines: cfg.hlines,
|
hlines: cfg.hlines,
|
||||||
};
|
};
|
||||||
|
if (cfg.plotVisibility) visual.plotVisibility = cfg.plotVisibility;
|
||||||
if (cfg.cloudColors) visual.cloudColors = cfg.cloudColors;
|
if (cfg.cloudColors) visual.cloudColors = cfg.cloudColors;
|
||||||
if (cfg.type === 'BollingerBands' && cfg.bandBackground) {
|
if (cfg.type === 'BollingerBands' && cfg.bandBackground) {
|
||||||
visual.bandBackground = cfg.bandBackground;
|
visual.bandBackground = cfg.bandBackground;
|
||||||
@@ -321,10 +325,21 @@ export function useIndicatorSettings(sessionKey = 0, enabled = true) {
|
|||||||
? resolveBbBandBackground(saved?.bandBackground)
|
? resolveBbBandBackground(saved?.bandBackground)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const enriched = enrichIndicatorConfig({
|
||||||
|
id: '',
|
||||||
|
type,
|
||||||
|
params: (def?.defaultParams ?? {}) as Record<string, number | string | boolean>,
|
||||||
|
plots,
|
||||||
|
plotVisibility: saved?.plotVisibility,
|
||||||
|
});
|
||||||
|
|
||||||
// 깊은 복사: 여러 슬롯이 같은 참조를 공유하지 않도록
|
// 깊은 복사: 여러 슬롯이 같은 참조를 공유하지 않도록
|
||||||
return {
|
return {
|
||||||
plots: plots.map(p => ({ ...p })),
|
plots: (enriched.plots ?? plots).map(p => ({ ...p })),
|
||||||
hlines: hlines.map(h => ({ ...h })),
|
hlines: hlines.map(h => ({ ...h })),
|
||||||
|
plotVisibility: enriched.plotVisibility
|
||||||
|
? { ...enriched.plotVisibility }
|
||||||
|
: undefined,
|
||||||
cloudColors: cloudColors ? { ...cloudColors } : undefined,
|
cloudColors: cloudColors ? { ...cloudColors } : undefined,
|
||||||
bandBackground: bandBackground ? { ...bandBackground } : undefined,
|
bandBackground: bandBackground ? { ...bandBackground } : undefined,
|
||||||
};
|
};
|
||||||
@@ -343,8 +358,10 @@ export function useIndicatorSettings(sessionKey = 0, enabled = true) {
|
|||||||
hlines?: HLineDef[],
|
hlines?: HLineDef[],
|
||||||
cloudColors?: IchimokuCloudColors,
|
cloudColors?: IchimokuCloudColors,
|
||||||
bandBackground?: HlinesBackground,
|
bandBackground?: HlinesBackground,
|
||||||
|
plotVisibility?: Record<string, boolean>,
|
||||||
) => {
|
) => {
|
||||||
const visual: IndicatorVisual = { plots, hlines };
|
const visual: IndicatorVisual = { plots, hlines };
|
||||||
|
if (plotVisibility != null) visual.plotVisibility = plotVisibility;
|
||||||
if (cloudColors) visual.cloudColors = cloudColors;
|
if (cloudColors) visual.cloudColors = cloudColors;
|
||||||
if (type === 'BollingerBands') {
|
if (type === 'BollingerBands') {
|
||||||
visual.bandBackground = bandBackground ?? resolveBbBandBackground(_visualCache?.[type]?.bandBackground);
|
visual.bandBackground = bandBackground ?? resolveBbBandBackground(_visualCache?.[type]?.bandBackground);
|
||||||
|
|||||||
@@ -391,25 +391,43 @@ export async function saveIndicatorSettings(
|
|||||||
* 앱 시작 시 호출 — 전역 시각 기본값을 DB 에서 가져온다.
|
* 앱 시작 시 호출 — 전역 시각 기본값을 DB 에서 가져온다.
|
||||||
*/
|
*/
|
||||||
export async function loadIndicatorVisualSettings(): Promise<
|
export async function loadIndicatorVisualSettings(): Promise<
|
||||||
Record<string, { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown }>
|
Record<string, {
|
||||||
|
plots?: unknown[];
|
||||||
|
hlines?: unknown[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
|
cloudColors?: unknown;
|
||||||
|
bandBackground?: unknown;
|
||||||
|
}>
|
||||||
> {
|
> {
|
||||||
return (
|
return (
|
||||||
(await request<Record<string, { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown }>>(
|
(await request<Record<string, {
|
||||||
|
plots?: unknown[];
|
||||||
|
hlines?: unknown[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
|
cloudColors?: unknown;
|
||||||
|
bandBackground?: unknown;
|
||||||
|
}>>(
|
||||||
'/indicator-settings/visual'
|
'/indicator-settings/visual'
|
||||||
)) ?? {}
|
)) ?? {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 특정 지표의 시각 설정(색상·선굵기·수평선)을 저장.
|
* 특정 지표의 시각 설정(색상·선굵기·수평선·지표선 on/off)을 저장.
|
||||||
* 사용자가 IndicatorSettingsModal 에서 색상·선굵기를 변경할 때 호출.
|
* 사용자가 IndicatorSettingsModal 에서 색상·선굵기를 변경할 때 호출.
|
||||||
*
|
*
|
||||||
* @param indicatorType 지표 타입 (e.g. "RSI")
|
* @param indicatorType 지표 타입 (e.g. "RSI")
|
||||||
* @param visual { plots: PlotDef[], hlines: HLineDef[] }
|
* @param visual { plots, hlines, plotVisibility, ... }
|
||||||
*/
|
*/
|
||||||
export async function saveIndicatorVisualSettings(
|
export async function saveIndicatorVisualSettings(
|
||||||
indicatorType: string,
|
indicatorType: string,
|
||||||
visual: { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown },
|
visual: {
|
||||||
|
plots?: unknown[];
|
||||||
|
hlines?: unknown[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
|
cloudColors?: unknown;
|
||||||
|
bandBackground?: unknown;
|
||||||
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await request(`/indicator-settings/${encodeURIComponent(indicatorType)}/visual`, {
|
await request(`/indicator-settings/${encodeURIComponent(indicatorType)}/visual`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ function overlayWorkspaceVisualOntoStrategyIndicator(
|
|||||||
hlines: ws.hlines?.length ? ws.hlines : ind.hlines,
|
hlines: ws.hlines?.length ? ws.hlines : ind.hlines,
|
||||||
cloudColors: ws.cloudColors ?? ind.cloudColors,
|
cloudColors: ws.cloudColors ?? ind.cloudColors,
|
||||||
bandBackground: ws.bandBackground ?? ind.bandBackground,
|
bandBackground: ws.bandBackground ?? ind.bandBackground,
|
||||||
|
plotVisibility: ws.plotVisibility ?? ind.plotVisibility,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +154,8 @@ export function mergeGlobalDefaultsOntoChartIndicators(
|
|||||||
hlines: [],
|
hlines: [],
|
||||||
cloudColors: undefined,
|
cloudColors: undefined,
|
||||||
bandBackground: undefined,
|
bandBackground: undefined,
|
||||||
|
/** strat_* — DB visual 기본값(plotVisibility)을 항상 따름 */
|
||||||
|
plotVisibility: undefined,
|
||||||
}
|
}
|
||||||
: ind;
|
: ind;
|
||||||
const cfg = buildMainIndicatorConfig(ind.type, [baseInd], getParams, getVisualConfig);
|
const cfg = buildMainIndicatorConfig(ind.type, [baseInd], getParams, getVisualConfig);
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ type GetVisual = (
|
|||||||
) => {
|
) => {
|
||||||
plots: PlotDef[];
|
plots: PlotDef[];
|
||||||
hlines: HLineDef[];
|
hlines: HLineDef[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
cloudColors?: IchimokuCloudColors;
|
cloudColors?: IchimokuCloudColors;
|
||||||
bandBackground?: import('../types').HlinesBackground;
|
bandBackground?: import('../types').HlinesBackground;
|
||||||
};
|
};
|
||||||
@@ -178,7 +179,7 @@ export function buildChartIndicatorConfig(
|
|||||||
if (!def) return null;
|
if (!def) return null;
|
||||||
|
|
||||||
const params = getParams(type, def.defaultParams as ParamRecord);
|
const params = getParams(type, def.defaultParams as ParamRecord);
|
||||||
const { plots, hlines, cloudColors, bandBackground } = getVisualConfig(
|
const { plots, hlines, cloudColors, bandBackground, plotVisibility } = getVisualConfig(
|
||||||
type,
|
type,
|
||||||
def.plots,
|
def.plots,
|
||||||
def.hlines ?? [],
|
def.hlines ?? [],
|
||||||
@@ -190,6 +191,7 @@ export function buildChartIndicatorConfig(
|
|||||||
params,
|
params,
|
||||||
plots,
|
plots,
|
||||||
hlines,
|
hlines,
|
||||||
|
...(plotVisibility ? { plotVisibility } : {}),
|
||||||
...(cloudColors ? { cloudColors } : {}),
|
...(cloudColors ? { cloudColors } : {}),
|
||||||
...(bandBackground ? { bandBackground } : {}),
|
...(bandBackground ? { bandBackground } : {}),
|
||||||
...extras,
|
...extras,
|
||||||
|
|||||||
@@ -55,7 +55,13 @@ export function initializeIndicatorConfigForEditor(
|
|||||||
type: string,
|
type: string,
|
||||||
defaultPlots: PlotDef[],
|
defaultPlots: PlotDef[],
|
||||||
defaultHlines?: HLineDef[],
|
defaultHlines?: HLineDef[],
|
||||||
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors; bandBackground?: HlinesBackground },
|
) => {
|
||||||
|
plots: PlotDef[];
|
||||||
|
hlines: HLineDef[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
|
cloudColors?: IchimokuCloudColors;
|
||||||
|
bandBackground?: HlinesBackground;
|
||||||
|
},
|
||||||
): IndicatorConfig {
|
): IndicatorConfig {
|
||||||
const def = getIndicatorDef(raw.type);
|
const def = getIndicatorDef(raw.type);
|
||||||
if (!def) return enrichIndicatorConfig(raw);
|
if (!def) return enrichIndicatorConfig(raw);
|
||||||
@@ -79,6 +85,7 @@ export function initializeIndicatorConfigForEditor(
|
|||||||
hlines: raw.hlines?.length ? raw.hlines : visual?.hlines,
|
hlines: raw.hlines?.length ? raw.hlines : visual?.hlines,
|
||||||
cloudColors: raw.cloudColors ?? visual?.cloudColors,
|
cloudColors: raw.cloudColors ?? visual?.cloudColors,
|
||||||
bandBackground: raw.bandBackground ?? visual?.bandBackground,
|
bandBackground: raw.bandBackground ?? visual?.bandBackground,
|
||||||
|
plotVisibility: raw.plotVisibility ?? visual?.plotVisibility,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,11 @@ import {
|
|||||||
getIndicatorDef,
|
getIndicatorDef,
|
||||||
getHLineLabel,
|
getHLineLabel,
|
||||||
mergePlotDefs,
|
mergePlotDefs,
|
||||||
normalizeObvParams,
|
|
||||||
type HLineDef,
|
type HLineDef,
|
||||||
} from './indicatorRegistry';
|
} from './indicatorRegistry';
|
||||||
import { initializeIndicatorConfigForEditor } from './indicatorSettingsEditor';
|
import { initializeIndicatorConfigForEditor } from './indicatorSettingsEditor';
|
||||||
import { mergeGlobalDefaultsOntoChartIndicators } from './indicatorMainConfig';
|
import { mergeGlobalDefaultsOntoChartIndicators } from './indicatorMainConfig';
|
||||||
import { buildMainIndicatorConfig } from './indicatorMainConfig';
|
import { buildChartIndicatorConfig } from './indicatorPaneMerge';
|
||||||
import { normalizeSmaConfig } from './smaConfig';
|
|
||||||
import { normalizeIchimokuConfig } from './ichimokuConfig';
|
|
||||||
import type { EditorConditionState } from './strategyConditionSerde';
|
import type { EditorConditionState } from './strategyConditionSerde';
|
||||||
import { collectUiEvaluationTimeframes } from './strategyTimeframeSync';
|
import { collectUiEvaluationTimeframes } from './strategyTimeframeSync';
|
||||||
|
|
||||||
@@ -66,7 +63,9 @@ type GetVisual = (
|
|||||||
) => {
|
) => {
|
||||||
plots: import('./indicatorRegistry').PlotDef[];
|
plots: import('./indicatorRegistry').PlotDef[];
|
||||||
hlines: HLineDef[];
|
hlines: HLineDef[];
|
||||||
|
plotVisibility?: Record<string, boolean>;
|
||||||
cloudColors?: import('./ichimokuConfig').IchimokuCloudColors;
|
cloudColors?: import('./ichimokuConfig').IchimokuCloudColors;
|
||||||
|
bandBackground?: import('../types').HlinesBackground;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 알림·가상투자 등 전략에서 생성된 차트 지표 id (워크스페이스 ind_* 와 구분) */
|
/** 알림·가상투자 등 전략에서 생성된 차트 지표 id (워크스페이스 ind_* 와 구분) */
|
||||||
@@ -205,46 +204,14 @@ function buildOneIndicator(
|
|||||||
getVisual: GetVisual,
|
getVisual: GetVisual,
|
||||||
stableId?: string,
|
stableId?: string,
|
||||||
): IndicatorConfig | null {
|
): IndicatorConfig | null {
|
||||||
const def = getIndicatorDef(ref.registryType);
|
const id = stableId ?? stableStrategyIndicatorId(ref);
|
||||||
if (!def) return null;
|
let cfg = buildChartIndicatorConfig(
|
||||||
|
ref.registryType,
|
||||||
const params = getParams(ref.registryType, def.defaultParams as ParamRecord);
|
id,
|
||||||
const { plots, hlines, cloudColors } = getVisual(ref.registryType, def.plots, def.hlines ?? []);
|
getParams,
|
||||||
|
getVisual as Parameters<typeof buildChartIndicatorConfig>[3],
|
||||||
let cfg: IndicatorConfig = {
|
);
|
||||||
id: stableId ?? stableStrategyIndicatorId(ref),
|
if (!cfg) return null;
|
||||||
type: def.type,
|
|
||||||
params: { ...params },
|
|
||||||
plots,
|
|
||||||
hlines,
|
|
||||||
...(cloudColors ? { cloudColors } : {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 모든 보조지표의 기간(period)은 반드시 지표 설정(getParams, DB 저장값)을 사용한다.
|
|
||||||
* 전략 DSL 조건의 period/leftPeriod/rightPeriod 로 덮어쓰지 않는다.
|
|
||||||
* 조건의 기간 필드는 부정확(미설정 시 1 등)할 수 있어 SMA(1)=본선 겹침 등
|
|
||||||
* 잘못된 그래프를 만든다. 설정에 저장된 값(예: OBV 신호선 9일)이 유일한 기준.
|
|
||||||
* cfg.params 는 이미 getParams(저장 설정값) 결과이므로 그대로 사용.
|
|
||||||
*/
|
|
||||||
if (ref.registryType === 'SMA') {
|
|
||||||
const mainSma = buildMainIndicatorConfig('SMA', [], getParams, getVisual as Parameters<typeof buildMainIndicatorConfig>[3]);
|
|
||||||
cfg = normalizeSmaConfig({
|
|
||||||
...cfg,
|
|
||||||
params: mainSma?.params ?? cfg.params,
|
|
||||||
plots: mainSma?.plots ?? cfg.plots,
|
|
||||||
plotVisibility: mainSma?.plotVisibility ?? cfg.plotVisibility,
|
|
||||||
});
|
|
||||||
} else if (ref.registryType === 'OBV') {
|
|
||||||
cfg = {
|
|
||||||
...cfg,
|
|
||||||
params: normalizeObvParams({ ...cfg.params }),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ref.registryType === 'IchimokuCloud') {
|
|
||||||
cfg = normalizeIchimokuConfig(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ref.targetValue != null) {
|
if (ref.targetValue != null) {
|
||||||
cfg = { ...cfg, hlines: applyTargetHlines(cfg.hlines ?? [], ref.targetValue) };
|
cfg = { ...cfg, hlines: applyTargetHlines(cfg.hlines ?? [], ref.targetValue) };
|
||||||
|
|||||||
Reference in New Issue
Block a user