OBV 신호선 점선 처리로 본선과 시각 구분 보장

- 진단 로그로 두 시리즈가 정상 생성됨을 확인 (series:2, visible:true, color:#2196F3)
- 미니차트는 800봉 누적 OBV 계산 → 마지막 200봉 구간에서 OBV와 SMA(9)가 수렴,
  주황 신호선이 파란 본선을 덮어 1개 선처럼 보이는 것이 원인
- registry plot1에 lineStyle:'dashed' 추가
- normalizeSignalLineIndicatorPlots OBV 분기에서 plot0=solid, plot1=dashed 강제

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-06-09 09:00:00 +09:00
parent 96f4ad8f7d
commit 91d52e9e26
2 changed files with 9 additions and 23 deletions
-22
View File
@@ -928,23 +928,6 @@ export class ChartManager {
); );
} }
// ── OBV 진단 로그 (개발용) ────────────────────────────────────────────
if (config.type === 'OBV') {
const plotKeys = Object.keys(result.plots);
const seriesIds = seriesMeta.map(m => m.plotId);
const volSum = this.rawBars.reduce((s, b) => s + (Number(b.volume) || 0), 0);
// eslint-disable-next-line no-console
console.error(
'[OBV Debug] series:', seriesList.length,
'| plotIds:', seriesIds,
'| resultKeys:', plotKeys,
'| plotVisibility:', JSON.stringify(config.plotVisibility),
'| plot0Color:', config.plots?.find(p => p.id === 'plot0')?.color,
'| bars:', this.rawBars.length,
'| volSum>0:', volSum > 0,
'| pane:', pane,
);
}
// hlines(과열선/중앙선/침체선)는 첫 번째 시리즈에만 한 번 생성 (중복 방지) // hlines(과열선/중앙선/침체선)는 첫 번째 시리즈에만 한 번 생성 (중복 방지)
const hlineRefs: IPriceLine[] = []; const hlineRefs: IPriceLine[] = [];
@@ -2921,11 +2904,6 @@ export class ChartManager {
} else { } else {
opts['color'] = plot.color ?? '#aaa'; opts['color'] = plot.color ?? '#aaa';
} }
// ── OBV plot0 스타일 진단 로그 ──────────────────────────────────────────
if (entry.type === 'OBV' && pid === 'plot0') {
// eslint-disable-next-line no-console
console.error('[OBV Style] plot0 opts:', JSON.stringify({ visible: opts['visible'], color: opts['color'], lineWidth: opts['lineWidth'] }));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
series.applyOptions(opts as any); series.applyOptions(opts as any);
}); });
+9 -1
View File
@@ -349,7 +349,7 @@ export const INDICATOR_REGISTRY: IndicatorDef[] = [
{ type:'HistoricalVolatility',name:'Historical Volatility', koreanName:'역사적변동성', shortName:'HV', category:'Volatility', overlay:false, defaultParams:{length:20, annualBars:252}, plots:[{id:'plot0',title:'HV', color:'#E91E63',type:'line',lineWidth:2}], description:'역사적 변동성 (연화)' }, { type:'HistoricalVolatility',name:'Historical Volatility', koreanName:'역사적변동성', shortName:'HV', category:'Volatility', overlay:false, defaultParams:{length:20, annualBars:252}, plots:[{id:'plot0',title:'HV', color:'#E91E63',type:'line',lineWidth:2}], description:'역사적 변동성 (연화)' },
// ── Volume ──────────────────────────────────────────────────────────────── // ── Volume ────────────────────────────────────────────────────────────────
{ type:'OBV', name:'On Balance Volume', koreanName:'잔량균형지수', shortName:'OBV', category:'Volume', overlay:false, defaultParams:{maType:'SMA', maLength:9}, plots:[{id:'plot0',title:'OBV', color:'#2196F3',type:'line',lineWidth:2},{id:'plot1',title:'Signal',color:'#FF9800',type:'line',lineWidth:1}], hlines:[], description:'잔량 균형 지수 (OBV + 이동평균 신호선)' }, { type:'OBV', name:'On Balance Volume', koreanName:'잔량균형지수', shortName:'OBV', category:'Volume', overlay:false, defaultParams:{maType:'SMA', maLength:9}, plots:[{id:'plot0',title:'OBV', color:'#2196F3',type:'line',lineWidth:2},{id:'plot1',title:'Signal',color:'#FF9800',type:'line',lineWidth:1,lineStyle:'dashed'}], hlines:[], description:'잔량 균형 지수 (OBV + 이동평균 신호선)' },
{ type:'VR', name:'Volume Ratio', koreanName:'거래량비율', shortName:'VR', category:'Volume', overlay:false, defaultParams:{length:10}, plots:[{id:'plot0',title:'VR', color:'#AB47BC',type:'line',lineWidth:2}], hlines:[{price:200,color:'#EF5350'},{price:100,color:'#607D8B'},{price:50,color:'#4CAF50'}], description:'거래량 비율 (VR)' }, { type:'VR', name:'Volume Ratio', koreanName:'거래량비율', shortName:'VR', category:'Volume', overlay:false, defaultParams:{length:10}, plots:[{id:'plot0',title:'VR', color:'#AB47BC',type:'line',lineWidth:2}], hlines:[{price:200,color:'#EF5350'},{price:100,color:'#607D8B'},{price:50,color:'#4CAF50'}], description:'거래량 비율 (VR)' },
{ type:'Disparity', name:'Disparity Index', koreanName:'이격도', shortName:'Disp', category:'Oscillators', overlay:false, defaultParams:{ultraLength:5, shortLength:10, midLength:20, longLength:60, src:'close'}, plots:[{id:'plot0',title:'초단기',color:'#E91E63',type:'line',lineWidth:1},{id:'plot1',title:'단기',color:'#FF9800',type:'line',lineWidth:1},{id:'plot2',title:'중기',color:'#4CAF50',type:'line',lineWidth:1},{id:'plot3',title:'장기',color:'#2196F3',type:'line',lineWidth:1}], hlines:[{price:100,color:'#607D8B'}], description:'이격도 (종가÷이평×100)' }, { type:'Disparity', name:'Disparity Index', koreanName:'이격도', shortName:'Disp', category:'Oscillators', overlay:false, defaultParams:{ultraLength:5, shortLength:10, midLength:20, longLength:60, src:'close'}, plots:[{id:'plot0',title:'초단기',color:'#E91E63',type:'line',lineWidth:1},{id:'plot1',title:'단기',color:'#FF9800',type:'line',lineWidth:1},{id:'plot2',title:'중기',color:'#4CAF50',type:'line',lineWidth:1},{id:'plot3',title:'장기',color:'#2196F3',type:'line',lineWidth:1}], hlines:[{price:100,color:'#607D8B'}], description:'이격도 (종가÷이평×100)' },
{ type:'Psychological', name:'Psychological Line', koreanName:'심리도', shortName:'Psy', category:'Oscillators', overlay:false, defaultParams:{length:12}, plots:[{id:'plot0',title:'심리도',color:'#00BCD4',type:'line',lineWidth:2}], hlines:[{price:75,color:'#EF5350',label:'과열선'},{price:50,color:'#607D8B',label:'중앙선'},{price:25,color:'#4CAF50',label:'침체선'}], description:'심리도 (상승일 비율)' }, { type:'Psychological', name:'Psychological Line', koreanName:'심리도', shortName:'Psy', category:'Oscillators', overlay:false, defaultParams:{length:12}, plots:[{id:'plot0',title:'심리도',color:'#00BCD4',type:'line',lineWidth:2}], hlines:[{price:75,color:'#EF5350',label:'과열선'},{price:50,color:'#607D8B',label:'중앙선'},{price:25,color:'#4CAF50',label:'침체선'}], description:'심리도 (상승일 비율)' },
@@ -481,6 +481,14 @@ function normalizeSignalLineIndicatorPlots(
type: 'line' as const, type: 'line' as const,
color: reg.color, color: reg.color,
lineWidth: Math.max(2, normalized.lineWidth ?? reg.lineWidth ?? 2), lineWidth: Math.max(2, normalized.lineWidth ?? reg.lineWidth ?? 2),
lineStyle: 'solid' as const,
};
}
// OBV 신호선 — 값이 본선과 거의 같더라도 점선으로 시각적 구분 보장
if (p.id === 'plot1') {
return {
...normalized,
lineStyle: 'dashed' as const,
}; };
} }
return normalized; return normalized;