import React, { useState, useEffect, useCallback } from 'react'; import { Box, TextField, Grid, Typography, Button, Alert, Divider, Accordion, AccordionSummary, AccordionDetails, Dialog, DialogTitle, DialogContent, DialogActions, Chip, IconButton, Tooltip, CircularProgress, Switch, FormControlLabel, FormControl, Select, MenuItem, InputLabel, } from '@mui/material'; import { RestartAlt, ExpandMore, CheckCircle, Error, Palette, Add, Delete, Star, StarBorder, HelpOutline, Close } from '@mui/icons-material'; import { useChartColors, ChartColorSettings } from '../../contexts/ChartColorContext'; import { useIndicatorSettings, IndicatorSettings, DEFAULT_INDICATOR_SETTINGS, } from '../../contexts/IndicatorSettingsContext'; import { getIndicatorPeriods, addPeriod, updatePeriod, deletePeriod, invalidatePeriodsCache, IndicatorPeriodsResponse, PeriodInfo, } from '../../services/indicatorPeriodApi'; // 타입과 기본값을 Context에서 재내보내기 (하위 호환성 유지) export type { IndicatorSettings } from '../../contexts/IndicatorSettingsContext'; export { DEFAULT_INDICATOR_SETTINGS, loadIndicatorSettingsFromStorage as loadIndicatorSettings, saveIndicatorSettingsToStorage as saveIndicatorSettings, } from '../../contexts/IndicatorSettingsContext'; // 기간 관리 컴포넌트 interface PeriodManagerProps { indicatorType: string; label: string; } const PeriodManager: React.FC = ({ indicatorType, label }) => { const [periods, setPeriods] = useState(null); const [loading, setLoading] = useState(true); const [newPeriod, setNewPeriod] = useState(''); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const loadPeriods = useCallback(async () => { try { setLoading(true); setError(null); const data = await getIndicatorPeriods(indicatorType); setPeriods(data); } catch (err: any) { console.error('기간 로드 실패:', err); // API 오류 시 빈 응답으로 처리 (데이터 추가 가능하도록) setPeriods({ indicatorType, indicatorDisplayName: label, periods: [], defaultPeriod: null, }); setError(`${label} 기간 데이터를 불러올 수 없습니다. 새 기간을 추가해주세요.`); } finally { setLoading(false); } }, [indicatorType, label]); useEffect(() => { loadPeriods(); }, [loadPeriods]); const handleAddPeriod = async () => { const periodNum = parseInt(newPeriod); if (!periodNum || periodNum < 1) return; try { setError(null); await addPeriod({ indicatorType, period: periodNum, isDefault: (periods?.periods.length || 0) === 0, // 첫 번째면 기본값 enabled: true, }); invalidatePeriodsCache(); setNewPeriod(''); setSuccess(`${periodNum}일 기간이 추가되었습니다.`); setTimeout(() => setSuccess(null), 2000); loadPeriods(); } catch (err: any) { const message = err.response?.data?.message || err.response?.data || '추가 실패'; setError(typeof message === 'string' ? message : JSON.stringify(message)); } }; const handleDeletePeriod = async (id: number, period: number) => { if (!window.confirm(`${period}일 기간을 삭제하시겠습니까?`)) return; try { setError(null); await deletePeriod(id); invalidatePeriodsCache(); setSuccess('삭제되었습니다.'); setTimeout(() => setSuccess(null), 2000); loadPeriods(); } catch (err: any) { setError('삭제 실패: ' + (err.response?.data?.message || err.message)); } }; const handleSetDefault = async (id: number, period: number) => { try { setError(null); await updatePeriod(id, { isDefault: true }); invalidatePeriodsCache(); setSuccess(`${period}일이 기본값으로 설정되었습니다.`); setTimeout(() => setSuccess(null), 2000); loadPeriods(); } catch (err: any) { setError('기본값 설정 실패: ' + (err.response?.data?.message || err.message)); } }; if (loading) { return ( 기간 로드 중... ); } const hasPeriods = periods && periods.periods && periods.periods.length > 0; return ( 📊 전략 규칙용 기간 관리 ({label}) {error && ( setError(null)}> {error} )} {success && ( setSuccess(null)}> {success} )} {hasPeriods ? ( periods.periods.map((p: PeriodInfo) => ( : undefined} onDelete={() => handleDeletePeriod(p.id, p.period)} onClick={() => !p.isDefault && handleSetDefault(p.id, p.period)} sx={{ cursor: p.isDefault ? 'default' : 'pointer', '&:hover': { opacity: p.isDefault ? 1 : 0.8 } }} /> )) ) : ( 등록된 기간이 없습니다. 아래에서 기간을 추가해주세요. )} setNewPeriod(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleAddPeriod()} sx={{ width: 100 }} inputProps={{ min: 1, max: 500 }} /> 💡 칩 클릭: 기본값 설정 | ⭐ 기본값 | ✕ 삭제 {!hasPeriods && ( 전략 규칙 생성 시 선택할 수 있는 기간을 추가해주세요. )} ); }; // 색상 선택 컴포넌트 const ColorPicker: React.FC<{ label: string; value: string; onChange: (color: string) => void; }> = ({ label, value, onChange }) => ( onChange(e.target.value)} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', opacity: 0, cursor: 'pointer', }} /> {label} onChange(e.target.value)} sx={{ width: 100 }} inputProps={{ style: { fontSize: 12 } }} /> ); interface IndicatorSettingsTabProps { onSave?: (settings: IndicatorSettings) => void; } const IndicatorSettingsTab: React.FC = ({ onSave }) => { const { indicatorSettings, saveIndicatorSettings, resetIndicatorSettings } = useIndicatorSettings(); const [settings, setSettings] = useState(indicatorSettings); const { colors, updateColors } = useChartColors(); const [localColors, setLocalColors] = useState>({ macdLine: colors.macdLine, signalLine: colors.signalLine, histogramPositive: colors.histogramPositive, histogramNegative: colors.histogramNegative, stochasticK: colors.stochasticK, stochasticD: colors.stochasticD, }); const [resultDialogOpen, setResultDialogOpen] = useState(false); const [saveResult, setSaveResult] = useState<{ success: boolean; message: string }>({ success: false, message: '' }); const [macdHelpOpen, setMacdHelpOpen] = useState(false); // Context의 설정값이 변경되면 로컬 상태도 동기화 useEffect(() => { setSettings(indicatorSettings); }, [indicatorSettings]); // 설정 변경 시 즉시 Context에 반영 (실시간 차트 업데이트) const handleSettingChange = (newSettings: Partial) => { const updated = { ...settings, ...newSettings }; setSettings(updated); // 즉시 Context에 반영하여 차트에 실시간 적용 saveIndicatorSettings(updated); }; const handleSave = () => { try { saveIndicatorSettings(settings); if (onSave) { onSave(settings); } updateColors(localColors); setSaveResult({ success: true, message: `보조지표 설정이 저장되었습니다.\n\n` + `신심리도: (${settings.newPsychologicalPeriod})\n` + `투자심리도: (${settings.investPsychologicalPeriod})\n` + `MACD: (${settings.macdFastPeriod}, ${settings.macdSlowPeriod}, ${settings.macdSignalPeriod})\n` + `CCI: (${settings.cciPeriod}, ${settings.cciSignalPeriod})\n` + `ADX: (${settings.adxPeriod})\n` + `BWI: (${settings.bwiPeriod})\n` + `DMI: (${settings.dmiPeriod})\n` + `OBV: (${settings.obvPeriod})\n` + `RSI: (${settings.rsiPeriod})\n` + `Stochastic Slow: (${settings.stochasticKPeriod}, ${settings.stochasticDPeriod}, ${settings.stochasticSlowing})\n` + `Williams %R: (${settings.williamsRPeriod})\n` + `TRIX: (${settings.trixPeriod}, ${settings.trixSignalPeriod})\n` + `VolumeOSC: (${settings.volumeOscShortPeriod}, ${settings.volumeOscLongPeriod})\n` + `VR: (${settings.vrPeriod})\n` + `이격도: (초단기:${settings.disparityUltraShortPeriod}, 단기:${settings.disparityShortPeriod}, 중기:${settings.disparityMidPeriod}, 장기:${settings.disparityLongPeriod})` }); setResultDialogOpen(true); } catch (error) { setSaveResult({ success: false, message: `저장 중 오류가 발생했습니다: ${error}` }); setResultDialogOpen(true); } }; const handleResetAll = () => { if (window.confirm('모든 보조지표 설정을 기본값으로 초기화하시겠습니까?')) { resetIndicatorSettings(); setSettings(DEFAULT_INDICATOR_SETTINGS); if (onSave) onSave(DEFAULT_INDICATOR_SETTINGS); setSaveResult({ success: true, message: `모든 보조지표 설정이 기본값으로 초기화되었습니다.` }); setResultDialogOpen(true); } }; return ( 보조지표 파라미터 설정 (15가지) 차트에서 사용되는 15가지 보조지표의 파라미터를 설정합니다. 변경된 설정은 즉시 차트에 반영됩니다. {/* 1. 신심리도 설정 */} }> 1️⃣ 신심리도 (New Psychological Line) handleSettingChange({ newPsychologicalPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 5" /> handleSettingChange({ newPsychologicalOversold: Number(e.target.value) })} inputProps={{ min: -100, max: 100 }} helperText="기본값: -50" /> handleSettingChange({ newPsychologicalMiddle: Number(e.target.value) })} inputProps={{ min: -100, max: 100 }} helperText="기본값: 0" /> handleSettingChange({ newPsychologicalOverbought: Number(e.target.value) })} inputProps={{ min: -100, max: 100 }} helperText="기본값: 50" /> 신심리도는 시장 참여자들의 심리 상태를 측정하는 지표입니다. 상승일수 비율로 과매수/과매도를 판단합니다. {/* 2. 투자심리도 설정 */} }> 2️⃣ 투자심리도 (Investor Psychological Line) handleSettingChange({ investPsychologicalPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 10" /> 투자심리도는 일정 기간 동안의 상승일 비율을 백분율로 표시합니다. 75% 이상은 과매수, 25% 이하는 과매도로 판단합니다. {/* 3. MACD 설정 */} }> 3️⃣ MACD (Moving Average Convergence Divergence) { e.stopPropagation(); setMacdHelpOpen(true); }} sx={{ color: 'info.main', '&:hover': { bgcolor: 'info.light', color: 'info.dark' } }} > handleSettingChange({ macdFastPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 12" /> handleSettingChange({ macdSlowPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 100 }} helperText="기본값: 26" /> handleSettingChange({ macdSignalPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 9" /> 라인 색상 설정 setLocalColors({ ...localColors, macdLine: color })} /> setLocalColors({ ...localColors, signalLine: color })} /> setLocalColors({ ...localColors, histogramPositive: color })} /> setLocalColors({ ...localColors, histogramNegative: color })} /> {/* 4. CCI 설정 */} }> 4️⃣ CCI (Commodity Channel Index) handleSettingChange({ cciPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 13" /> handleSettingChange({ cciSignalPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 10" /> handleSettingChange({ cciOversold: Number(e.target.value) })} inputProps={{ min: -300, max: -50 }} helperText="기본값: -100" /> handleSettingChange({ cciMiddle: Number(e.target.value) })} inputProps={{ min: -50, max: 50 }} helperText="기본값: 0" /> handleSettingChange({ cciOverbought: Number(e.target.value) })} inputProps={{ min: 50, max: 300 }} helperText="기본값: 100" /> {/* 5. ADX 설정 */} }> 5️⃣ ADX (Average Directional Index) handleSettingChange({ adxPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 11" /> handleSettingChange({ adxStrongThreshold: Number(e.target.value) })} inputProps={{ min: 15, max: 50 }} helperText="기본값: 25" /> ADX가 강한 추세 기준값 이상일 때 추세가 강하다고 판단합니다. {/* 6. BWI 설정 */} }> 6️⃣ BWI (Bollinger Band Width Index) handleSettingChange({ bwiPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 20" /> BWI는 볼린저 밴드의 폭을 측정하여 변동성을 나타내는 지표입니다. 값이 클수록 변동성이 높고, 값이 작을수록 변동성이 낮습니다. {/* 7. DMI 설정 */} }> 7️⃣ DMI (Directional Movement Index) handleSettingChange({ dmiPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 14" /> DMI는 +DI와 -DI로 구성되며 추세의 방향을 나타냅니다. +DI {'>'} -DI 이면 상승 추세, -DI {'>'} +DI 이면 하락 추세입니다. {/* 8. OBV 설정 */} }> 8️⃣ OBV (On Balance Volume) handleSettingChange({ obvPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 9" /> OBV는 거래량의 누적치로 가격 움직임의 선행 지표입니다. 가격이 상승하면 거래량을 더하고, 하락하면 거래량을 뺍니다. {/* 9. RSI 설정 */} }> 9️⃣ RSI (Relative Strength Index) handleSettingChange({ rsiPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 9" /> handleSettingChange({ rsiOversold: Number(e.target.value) })} inputProps={{ min: 0, max: 100 }} helperText="기본값: 30 (매수 신호)" /> handleSettingChange({ rsiMiddle: Number(e.target.value) })} inputProps={{ min: 0, max: 100 }} helperText="기본값: 50" /> handleSettingChange({ rsiOverbought: Number(e.target.value) })} inputProps={{ min: 0, max: 100 }} helperText="기본값: 70 (매도 신호)" /> {/* 10. Stochastic Slow 설정 */} }> 🔟 Stochastic Slow 기간 설정 handleSettingChange({ stochasticKPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 12" /> handleSettingChange({ stochasticSlowing: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 5" /> handleSettingChange({ stochasticDPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 5" /> 매매 기준값 설정 handleSettingChange({ stochasticOversold: Number(e.target.value) })} inputProps={{ min: 5, max: 40 }} helperText="기본값: 20 (매수 신호)" /> handleSettingChange({ stochasticNeutral: Number(e.target.value) })} inputProps={{ min: 40, max: 60 }} helperText="기본값: 50 (중립 구간)" /> handleSettingChange({ stochasticOverbought: Number(e.target.value) })} inputProps={{ min: 60, max: 95 }} helperText="기본값: 80 (매도 신호)" /> 라인 색상 설정 setLocalColors({ ...localColors, stochasticK: color })} /> setLocalColors({ ...localColors, stochasticD: color })} /> 기준선 색상 설정 setLocalColors({ ...localColors, stochasticOversoldColor: color })} /> setLocalColors({ ...localColors, stochasticNeutralColor: color })} /> setLocalColors({ ...localColors, stochasticOverboughtColor: color })} /> {/* 11. Williams %R 설정 */} }> 1️⃣1️⃣ Williams %R handleSettingChange({ williamsRPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 11" /> handleSettingChange({ williamsROversold: Number(e.target.value) })} inputProps={{ min: -100, max: 0 }} helperText="기본값: -80" /> handleSettingChange({ williamsRMiddle: Number(e.target.value) })} inputProps={{ min: -100, max: 0 }} helperText="기본값: -50" /> handleSettingChange({ williamsROverbought: Number(e.target.value) })} inputProps={{ min: -100, max: 0 }} helperText="기본값: -20" /> {/* 기준선 색상 설정 */} 기준선 스타일 설정 {/* 침체선 */} 침체선 (-80) updateColors({ williamsROversoldColor: e.target.value })} size="small" /> updateColors({ williamsROversoldWidth: Number(e.target.value) })} inputProps={{ min: 0.5, max: 5, step: 0.5 }} size="small" /> {/* 중간선 */} 중간선 (-50) updateColors({ williamsRMiddleColor: e.target.value })} size="small" /> updateColors({ williamsRMiddleWidth: Number(e.target.value) })} inputProps={{ min: 0.5, max: 5, step: 0.5 }} size="small" /> {/* 과열선 */} 과열선 (-20) updateColors({ williamsROverboughtColor: e.target.value })} size="small" /> updateColors({ williamsROverboughtWidth: Number(e.target.value) })} inputProps={{ min: 0.5, max: 5, step: 0.5 }} size="small" /> Williams %R은 0에서 -100 사이의 값을 가집니다. -80 이하는 침체, -20 이상은 과열로 판단합니다. {/* 12. TRIX 설정 */} }> 1️⃣2️⃣ TRIX (Triple Exponential Moving Average) handleSettingChange({ trixPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 12" /> handleSettingChange({ trixSignalPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 20 }} helperText="기본값: 9" /> handleSettingChange({ trixOversold: Number(e.target.value) })} inputProps={{ min: -2, max: -0.1, step: 0.1 }} helperText="기본값: -0.5" /> handleSettingChange({ trixMiddle: Number(e.target.value) })} inputProps={{ min: -0.5, max: 0.5, step: 0.1 }} helperText="기본값: 0" /> handleSettingChange({ trixOverbought: Number(e.target.value) })} inputProps={{ min: 0.1, max: 2, step: 0.1 }} helperText="기본값: 0.5" /> TRIX는 EMA의 EMA의 EMA를 사용하여 노이즈를 필터링한 모멘텀 지표입니다. 0선 상향 돌파 시 매수, 하향 돌파 시 매도 신호로 해석합니다. {/* 13. VolumeOSC 설정 */} }> 1️⃣3️⃣ VolumeOSC (Volume Oscillator) handleSettingChange({ volumeOscShortPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 50 }} helperText="기본값: 10" /> handleSettingChange({ volumeOscLongPeriod: Number(e.target.value) })} inputProps={{ min: 10, max: 100 }} helperText="기본값: 20" /> VolumeOSC는 단기 거래량 이동평균과 장기 거래량 이동평균의 차이를 백분율로 나타냅니다. 양수면 거래량 증가 추세, 음수면 거래량 감소 추세입니다. {/* 14. VR 설정 */} }> 1️⃣4️⃣ VR (Volume Ratio) handleSettingChange({ vrPeriod: Number(e.target.value) })} inputProps={{ min: 5, max: 50 }} helperText="기본값: 10" /> VR은 상승일 거래량과 하락일 거래량의 비율입니다. 일반적으로 70% 이하는 과매도, 250% 이상은 과매수로 판단합니다. {/* 15. 이격도 설정 */} }> 1️⃣5️⃣ 이격도 (Disparity Index) {/* 각 선 활성화 스위치 */} 선 표시 설정 handleSettingChange({ disparityUltraShortEnabled: e.target.checked })} /> } label="초단기 (5일)" /> handleSettingChange({ disparityShortEnabled: e.target.checked })} /> } label="단기 (20일)" /> handleSettingChange({ disparityMidEnabled: e.target.checked })} /> } label="중기 (60일)" /> handleSettingChange({ disparityLongEnabled: e.target.checked })} /> } label="장기 (120일)" /> {/* 기간 설정 */} 기간 설정 {/* 초단기 (5일) */} handleSettingChange({ disparityUltraShortPeriod: Number(e.target.value) })} inputProps={{ min: 1, max: 20 }} helperText="기본값: 5일" disabled={!settings.disparityUltraShortEnabled} /> {/* 단기 (20일) */} handleSettingChange({ disparityShortPeriod: Number(e.target.value) })} inputProps={{ min: 10, max: 50 }} helperText="기본값: 20일" disabled={!settings.disparityShortEnabled} /> {/* 중기 (60일) */} handleSettingChange({ disparityMidPeriod: Number(e.target.value) })} inputProps={{ min: 30, max: 100 }} helperText="기본값: 60일" disabled={!settings.disparityMidEnabled} /> {/* 장기 (120일) */} handleSettingChange({ disparityLongPeriod: Number(e.target.value) })} inputProps={{ min: 60, max: 200 }} helperText="기본값: 120일" disabled={!settings.disparityLongEnabled} /> 이격도는 현재 주가와 이동평균선 사이의 괴리율을 나타내는 지표입니다. 100을 기준으로 100 이상이면 주가가 이동평균선보다 위에, 100 이하면 아래에 있습니다. 초단기(5일), 단기(20일), 중기(60일), 장기(120일) 4개의 이격도를 동시에 표시합니다. {/* 기준선 설정 */} 기준선 스타일 설정 handleSettingChange({ disparityBaseLineEnabled: e.target.checked })} /> } label="기준선 표시 (100)" sx={{ mb: 2 }} /> updateColors({ disparityBaseLineColor: e.target.value })} size="small" disabled={!settings.disparityBaseLineEnabled} /> updateColors({ disparityBaseLineWidth: Number(e.target.value) })} inputProps={{ min: 0.5, max: 5, step: 0.5 }} size="small" disabled={!settings.disparityBaseLineEnabled} /> 선 스타일 {/* 이동평균 기간 관리 섹션 */} }> 📊 이동평균 기간 관리 (전략 규칙용) 전략 규칙 생성 시 선택 가능한 이동평균 기간을 관리합니다. {/* 저장 결과 팝업 */} setResultDialogOpen(false)} maxWidth="sm" fullWidth> {saveResult.success ? : } {saveResult.success ? '저장 완료' : '저장 실패'} setResultDialogOpen(false)} size="small" sx={{ color: '#fff' }}> {saveResult.message} {/* MACD 상세 설명 다이얼로그 */} setMacdHelpOpen(false)} maxWidth="md" fullWidth PaperProps={{ sx: { bgcolor: 'background.paper', backgroundImage: 'none', }, }} > MACD 상세 설명 setMacdHelpOpen(false)} size="small" sx={{ color: 'white' }}> 1️⃣ MACD란? MACD는 두 개의 이동평균선의 차이를 이용해 ✔ 추세 방향 ✔ 매수·매도 시점 ✔ 힘의 강도(모멘텀) 를 판단하는 지표입니다. "주가의 흐름이 강해지고 있는지, 약해지고 있는지"를 보여줍니다. 2️⃣ MACD의 구성 요소 (3가지) ① MACD 선 • 12일 지수이동평균(EMA) – 26일 EMA
• 단기 추세와 중기 추세의 차이
② 시그널 선 • MACD 선의 9일 EMA
• 매매 신호를 보조하는 기준선
③ 히스토그램 • MACD 선 – 시그널 선
• 두 선의 간격을 막대그래프로 표시
• 힘이 커지는지 / 약해지는지 시각적으로 보여줌
3️⃣ MACD 해석 방법 (핵심) 🔹 1. 골든크로스 / 데드크로스 가장 많이 쓰이는 신호입니다. ✔ 매수 신호 • MACD 선이 시그널 선을 아래에서 위로 돌파
• 상승 모멘텀 시작 가능성
✔ 매도 신호 • MACD 선이 시그널 선을 위에서 아래로 이탈
• 하락 모멘텀 시작 가능성
🔹 2. 0선 기준 해석 MACD가 0선 위/아래에 있는지도 중요합니다. • 0선 위 → 상승 추세 우위 • 0선 아래 → 하락 추세 우위 📌 0선 위에서 골든크로스 = 신뢰도 ↑
📌 0선 아래 데드크로스 = 하락 지속 가능성 ↑
🔹 3. 히스토그램 변화 히스토그램은 추세의 힘을 보여줍니다. • 막대가 점점 커짐 → 추세 강화 • 막대가 줄어듦 → 추세 약화 • 방향 전환 → 추세 전환 가능성 🔹 4. 다이버전스 (중요) 주가와 MACD의 방향이 다를 때 나타납니다. ✔ 강세 다이버전스 • 주가는 하락하는데 MACD는 저점 상승
• → 반등 가능성
✔ 약세 다이버전스 • 주가는 상승하는데 MACD는 고점 하락
• → 조정 가능성
4️⃣ 실전 활용 팁 ✅ MACD는 추세장에서 강력 횡보장에서는 잦은 헛신호 발생 ✅ 다른 지표와 함께 사용 RSI, 이동평균선, 거래량과 병행 추천 ✅ 시간봉에 따라 성격이 다름 • 일봉 → 중기 추세
• 분봉 → 단기 매매 (노이즈 많음)
5️⃣ MACD의 한계 (중요) ❌ 후행성 지표 이동평균 기반 → 신호가 늦을 수 있음 ❌ 단독 사용은 위험 반드시 차트 패턴·지지저항·거래량과 함께 확인
); }; export default IndicatorSettingsTab;