DockerSpace / frontend /src /components /MACDChart.tsx
DennisChan0909's picture
feat: market tabs (台股/美股/基金), autocomplete search, favorites filter tabs
b72deed
Raw
History Blame Contribute Delete
2.99 kB
import React from 'react'
import {
ComposedChart,
Bar,
Line,
Cell,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ReferenceLine,
ResponsiveContainer,
} from 'recharts'
import { OHLCVPoint } from '../api/stockApi'
interface Props {
data: OHLCVPoint[]
}
const CustomTooltip = ({ active, payload, label }: any) => {
if (!active || !payload?.length) return null
const d: OHLCVPoint = payload[0]?.payload
return (
<div className="bg-slate-800 border border-slate-600 rounded p-2 text-xs shadow-lg">
<p className="text-slate-300">{label}</p>
{d.macd != null && (
<p>MACD: <span className="text-blue-400">{d.macd.toFixed(3)}</span></p>
)}
{d.macd_signal != null && (
<p>Signal: <span className="text-orange-400">{d.macd_signal.toFixed(3)}</span></p>
)}
{d.macd_hist != null && (
<p>
Hist:{' '}
<span className={d.macd_hist >= 0 ? 'text-green-400' : 'text-red-400'}>
{d.macd_hist.toFixed(3)}
</span>
</p>
)}
</div>
)
}
export const MACDChart: React.FC<Props> = ({ data }) => {
const len = data.length
return (
<ResponsiveContainer width="100%" height={180}>
<ComposedChart data={data} margin={{ top: 4, right: 16, left: 0, bottom: 0 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
<XAxis
dataKey="date"
tick={{ fill: '#94a3b8', fontSize: 10 }}
tickLine={false}
tickFormatter={(val, idx) => {
const step = Math.max(1, Math.floor(len / 10))
return idx % step === 0 ? val : ''
}}
interval={0}
/>
<YAxis
tick={{ fill: '#94a3b8', fontSize: 10 }}
tickLine={false}
tickFormatter={(v) => v.toFixed(1)}
width={40}
/>
<Tooltip content={<CustomTooltip />} />
<Legend
wrapperStyle={{ fontSize: 12 }}
formatter={(value) => <span style={{ color: '#94a3b8' }}>{value}</span>}
/>
<ReferenceLine y={0} stroke="#475569" strokeWidth={1} />
{/* MACD Histogram */}
<Bar dataKey="macd_hist" name="Histogram" isAnimationActive={false} maxBarSize={4}>
{data.map((d, i) => (
<Cell
key={i}
fill={(d.macd_hist ?? 0) >= 0 ? '#22c55e' : '#ef4444'}
fillOpacity={0.7}
/>
))}
</Bar>
{/* MACD Line */}
<Line
dataKey="macd"
stroke="#60a5fa"
strokeWidth={1.5}
dot={false}
name="MACD"
isAnimationActive={false}
connectNulls
/>
{/* Signal Line */}
<Line
dataKey="macd_signal"
stroke="#fb923c"
strokeWidth={1.5}
dot={false}
name="Signal"
isAnimationActive={false}
connectNulls
/>
</ComposedChart>
</ResponsiveContainer>
)
}