obv 신호선
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { getIndicatorDef, mergePlotDefs, normalizeHLines, PlotDef, HLineDef } from '../utils/indicatorRegistry';
|
||||
import { getIndicatorDef, mergePlotDefs, normalizeHLines, normalizeObvParams, PlotDef, HLineDef } from '../utils/indicatorRegistry';
|
||||
import { createDefaultSmaParams, createDefaultSmaPlots, normalizeSmaConfig } from '../utils/smaConfig';
|
||||
import { normalizeIchimokuConfig, mergeIchimokuPlots } from '../utils/ichimokuConfig';
|
||||
import {
|
||||
@@ -177,6 +177,9 @@ export function useIndicatorSettings(sessionKey = 0) {
|
||||
if (type === 'IchimokuCloud') {
|
||||
return normalizeIchimokuConfig({ id: '', type: 'IchimokuCloud', params: merged }).params;
|
||||
}
|
||||
if (type === 'OBV') {
|
||||
return normalizeObvParams(merged);
|
||||
}
|
||||
return merged;
|
||||
},
|
||||
[settingsRevision],
|
||||
|
||||
@@ -791,7 +791,7 @@ export class ChartManager {
|
||||
const showSeriesTitle = pane < 2 && showPriceLabel;
|
||||
series = this.chart.addSeries(LineSeries, {
|
||||
color: plotDef.color,
|
||||
lineWidth: (plotDef.lineWidth ?? 1) as 1 | 2 | 3 | 4,
|
||||
lineWidth: Math.max(1, plotDef.lineWidth ?? 1) as 1 | 2 | 3 | 4,
|
||||
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
||||
priceLineVisible: false,
|
||||
lastValueVisible: showPriceLabel,
|
||||
|
||||
@@ -441,6 +441,45 @@ export function mergePlotDefs(saved: PlotDef[] | undefined, defaults: PlotDef[])
|
||||
});
|
||||
}
|
||||
|
||||
/** OBV·CCI·RSI·TRIX — registry 신호선(plot1) 병합·표시 보장 (DB에 plot0만 저장된 경우 대비) */
|
||||
const SIGNAL_LINE_INDICATOR_TYPES = new Set(['OBV', 'CCI', 'RSI', 'TRIX']);
|
||||
|
||||
function normalizeSignalLineIndicatorPlots(
|
||||
type: string,
|
||||
plots: PlotDef[],
|
||||
registryPlots: PlotDef[],
|
||||
plotVisibility: Record<string, boolean>,
|
||||
params: Record<string, number | string | boolean>,
|
||||
): { plots: PlotDef[]; plotVisibility: Record<string, boolean> } {
|
||||
if (!SIGNAL_LINE_INDICATOR_TYPES.has(type)) {
|
||||
return { plots, plotVisibility };
|
||||
}
|
||||
const merged = mergePlotDefs(plots, registryPlots);
|
||||
const regSignal = registryPlots.find(p => p.id === 'plot1');
|
||||
const nextPlots = regSignal
|
||||
? merged.map(p => {
|
||||
if (p.id !== 'plot1') return p;
|
||||
return {
|
||||
...regSignal,
|
||||
...p,
|
||||
id: 'plot1',
|
||||
title: regSignal.title,
|
||||
type: 'line' as const,
|
||||
lineWidth: Math.max(1, p.lineWidth ?? regSignal.lineWidth ?? 1),
|
||||
};
|
||||
})
|
||||
: merged;
|
||||
const nextVis = { ...plotVisibility };
|
||||
if (type === 'OBV') {
|
||||
nextVis.plot1 = true;
|
||||
} else if ((type === 'CCI' || type === 'RSI') && params.maType === 'None') {
|
||||
nextVis.plot1 = false;
|
||||
} else if (nextVis.plot1 !== false) {
|
||||
nextVis.plot1 = true;
|
||||
}
|
||||
return { plots: nextPlots, plotVisibility: nextVis };
|
||||
}
|
||||
|
||||
/** 업비트 OBV 신호선 MA 종류 (단순·지수·가중만) */
|
||||
export const OBV_MA_TYPE_OPTIONS = ['SMA', 'EMA', 'WMA'] as const;
|
||||
export type ObvMaType = (typeof OBV_MA_TYPE_OPTIONS)[number];
|
||||
@@ -520,18 +559,20 @@ export function enrichIndicatorConfig(
|
||||
if (cfgNorm.type === 'DMI') {
|
||||
params = normalizeDmiParams(params);
|
||||
}
|
||||
const plots = cfgNorm.type === 'BollingerBands'
|
||||
let plots = cfgNorm.type === 'BollingerBands'
|
||||
? mergeBbPlots(cfgNorm.plots, def.plots)
|
||||
: mergePlotDefs(cfgNorm.plots, def.plots);
|
||||
const plotVisibility: Record<string, boolean> = { ...cfgNorm.plotVisibility };
|
||||
let plotVisibility: Record<string, boolean> = { ...cfgNorm.plotVisibility };
|
||||
for (const p of plots) {
|
||||
if (plotVisibility[p.id] === undefined) plotVisibility[p.id] = true;
|
||||
}
|
||||
if (cfgNorm.type === 'OBV') {
|
||||
plotVisibility.plot1 = plotVisibility.plot1 !== false;
|
||||
} else if ((cfgNorm.type === 'CCI' || cfgNorm.type === 'RSI') && params.maType === 'None') {
|
||||
plotVisibility.plot1 = false;
|
||||
}
|
||||
({ plots, plotVisibility } = normalizeSignalLineIndicatorPlots(
|
||||
cfgNorm.type,
|
||||
plots,
|
||||
def.plots,
|
||||
plotVisibility,
|
||||
params,
|
||||
));
|
||||
|
||||
const out: import('../types').IndicatorConfig = {
|
||||
...cfgNorm,
|
||||
@@ -636,6 +677,9 @@ export async function calculateIndicator(
|
||||
if (type === 'CCI') {
|
||||
calcParams = normalizeCciParams(params);
|
||||
}
|
||||
if (type === 'OBV') {
|
||||
calcParams = normalizeObvParams(params);
|
||||
}
|
||||
if (type === 'IchimokuCloud') {
|
||||
const { senkou } = resolveIchimokuDisplacements(params);
|
||||
calcParams = { ...params, displacement: senkou };
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
enrichIndicatorConfig,
|
||||
getIndicatorDef,
|
||||
getHLineLabel,
|
||||
mergePlotDefs,
|
||||
normalizeObvParams,
|
||||
type HLineDef,
|
||||
} from './indicatorRegistry';
|
||||
import { buildMainIndicatorConfig } from './indicatorMainConfig';
|
||||
@@ -199,6 +201,17 @@ function buildOneIndicator(
|
||||
plots: mainSma?.plots ?? cfg.plots,
|
||||
plotVisibility: mainSma?.plotVisibility ?? cfg.plotVisibility,
|
||||
});
|
||||
} else if (ref.registryType === 'OBV') {
|
||||
const p = normalizeObvParams({ ...cfg.params });
|
||||
const signalLen = ref.rightPeriod ?? ref.period;
|
||||
if (signalLen != null && signalLen > 0) {
|
||||
p.maLength = signalLen;
|
||||
}
|
||||
cfg = {
|
||||
...cfg,
|
||||
params: p,
|
||||
plots: mergePlotDefs(cfg.plots, def.plots),
|
||||
};
|
||||
} else if (ref.period != null && ref.period > 0) {
|
||||
cfg = {
|
||||
...cfg,
|
||||
|
||||
Reference in New Issue
Block a user