모의투자, 백테스팅 레이아웃 수정

This commit is contained in:
Macbook
2026-05-24 20:13:21 +09:00
parent 958b813f3b
commit af230a4233
23 changed files with 2394 additions and 782 deletions
@@ -40,9 +40,11 @@ function sparkPath(values: number[], w: number, h: number, min?: number, max?: n
interface Props {
market: string;
timeframe?: Timeframe;
/** 실시간 차트처럼 세로 스택 pane */
stacked?: boolean;
}
const PaperIndicatorPanel: React.FC<Props> = ({ market, timeframe = '1h' }) => {
const PaperIndicatorPanel: React.FC<Props> = ({ market, timeframe = '1h', stacked = false }) => {
const [rsi, setRsi] = React.useState<number[]>([]);
const [macd, setMacd] = React.useState<number[]>([]);
const [cci, setCci] = React.useState<number[]>([]);
@@ -54,7 +56,7 @@ const PaperIndicatorPanel: React.FC<Props> = ({ market, timeframe = '1h' }) => {
const bars = await fetchUpbitCandles(market, timeframe, 120);
if (cancelled) return;
const closes = bars.map(b => b.close);
setRsi(computeRsi(closes).slice(-40));
setRsi(computeRsi(closes).slice(-60));
const ema = (arr: number[], p: number) => {
const k = 2 / (p + 1);
let v = arr[0];
@@ -62,7 +64,7 @@ const PaperIndicatorPanel: React.FC<Props> = ({ market, timeframe = '1h' }) => {
};
const e12 = ema(closes, 12);
const e26 = ema(closes, 26);
setMacd(e12.slice(-40).map((v, i) => v - e26[closes.length - 40 + i]));
setMacd(e12.slice(-60).map((v, i) => v - e26[closes.length - 60 + i]));
const tp = bars.map(b => (b.high + b.low + b.close) / 3);
const cciVals: number[] = [];
for (let i = 20; i < tp.length; i++) {
@@ -71,22 +73,25 @@ const PaperIndicatorPanel: React.FC<Props> = ({ market, timeframe = '1h' }) => {
const md = slice.reduce((a, v) => a + Math.abs(v - sma), 0) / slice.length;
cciVals.push(md === 0 ? 0 : (tp[i] - sma) / (0.015 * md));
}
setCci(cciVals.slice(-40));
setCci(cciVals.slice(-60));
} catch { /* ignore */ }
})();
return () => { cancelled = true; };
}, [market, timeframe]);
const panels = useMemo(() => [
{ label: 'RSI', values: rsi, color: '#a78bfa', ref: [30, 70] },
{ label: 'RSI (14)', values: rsi, color: '#a78bfa', ref: [30, 70] as number[] },
{ label: 'MACD', values: macd, color: '#38bdf8' },
{ label: 'CCI', values: cci, color: '#fbbf24', ref: [-100, 100] },
{ label: 'CCI (20)', values: cci, color: '#fbbf24', ref: [-100, 100] as number[] },
], [rsi, macd, cci]);
const rootClass = stacked ? 'ptd-ind-stack' : 'ptd-indicators';
const itemClass = stacked ? 'ptd-ind-row' : 'ptd-ind-panel';
return (
<div className="ptd-indicators">
<div className={rootClass}>
{panels.map(p => (
<div key={p.label} className="ptd-ind-panel">
<div key={p.label} className={itemClass}>
<div className="ptd-ind-label">{p.label}</div>
<svg viewBox="0 0 120 48" className="ptd-ind-svg" preserveAspectRatio="none">
{p.ref?.map((r, i) => {