/**
* 설정 화면 — 백테스팅 설정 패널 (2열 카드 레이아웃)
*/
import React, { useState, useEffect, useCallback } from 'react';
import {
type BacktestSettingsDto,
DEFAULT_BACKTEST_SETTINGS,
loadBacktestSettings,
saveBacktestSettings,
} from '../utils/backendApi';
// ── 백테스팅 전용 UI 컴포넌트 ───────────────────────────────────────────────
const BtSection: React.FC<{ title: string; children: React.ReactNode }> = ({ title, children }) => (
);
const BtGrid: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
);
const BtField: React.FC<{
label: string;
desc?: string;
full?: boolean;
children: React.ReactNode;
}> = ({ label, desc, full, children }) => (
{label}
{desc && {desc}}
{children}
);
export interface BacktestSettingsPanelProps {
btAutoPopup?: boolean;
onBtAutoPopup?: (v: boolean) => void;
btShowPrice?: boolean;
onBtShowPrice?: (v: boolean) => void;
}
export const BacktestSettingsPanel: React.FC = ({
btAutoPopup = true,
onBtAutoPopup,
btShowPrice = true,
onBtShowPrice,
}) => {
const [cfg, setCfg] = useState(DEFAULT_BACKTEST_SETTINGS);
const [saving, setSaving] = useState(false);
const [saved, setSaved] = useState(false);
useEffect(() => {
loadBacktestSettings().then(s => { if (s) setCfg(s); });
}, []);
const update = useCallback(async (patch: Partial) => {
const next = { ...cfg, ...patch };
setCfg(next);
setSaving(true);
setSaved(false);
try {
await saveBacktestSettings(next);
setSaved(true);
setTimeout(() => setSaved(false), 1500);
} finally {
setSaving(false);
}
}, [cfg]);
const field = (key: K, value: BacktestSettingsDto[K]) =>
update({ [key]: value } as Partial);
return (
{(saving || saved) && (
{saving ? '저장 중…' : '✓ 저장됨'}
)}
field('initialCapital', Number(e.target.value))}
/>
field('tradeSizeValue', Number(e.target.value))}
/>
{cfg.commissionType === 'LINEAR' ? (
field('commissionRate', Number(e.target.value) / 100)}
/>
) : (
)}
field('slippageRate', Number(e.target.value) / 100)}
/>
{cfg.stopLossEnabled ? (
field('stopLossPct', Number(e.target.value))} />
) : }
{cfg.takeProfitEnabled ? (
field('takeProfitPct', Number(e.target.value))} />
) : }
{cfg.trailingStopEnabled ? (
field('trailingStopPct', Number(e.target.value))} />
) : }
field('reentryWaitBars', Number(e.target.value))} />
field('maxOpenTrades', Number(e.target.value))} />
{cfg.partialExitEnabled ? (
field('partialExitPct', Number(e.target.value))} />
) : }
{cfg.positionMode === 'SIGNAL_ONLY' && (
Signal-Only 모드: 매도 시그널이 이전 매수 없이도 발생합니다
)}
);
};
export default BacktestSettingsPanel;