backtest work

This commit is contained in:
Boki 2025-07-03 11:04:33 -04:00
parent 143e2e1678
commit 55b4ca78c9
6 changed files with 427 additions and 129 deletions

View file

@ -12,6 +12,8 @@ interface BacktestResultsProps {
}
export function BacktestResults({ status, results, currentTime }: BacktestResultsProps) {
const [selectedSymbol, setSelectedSymbol] = useState<string>('');
if (status === 'idle') {
return (
<div className="bg-surface-secondary p-8 rounded-lg border border-border h-full flex items-center justify-center">
@ -112,16 +114,55 @@ export function BacktestResults({ status, results, currentTime }: BacktestResult
{/* Performance Chart */}
<div className="bg-surface-secondary p-4 rounded-lg border border-border">
<h3 className="text-base font-medium text-text-primary mb-4">
Portfolio Performance
</h3>
<div className="flex items-center justify-between mb-4">
<h3 className="text-base font-medium text-text-primary">
Portfolio Performance
</h3>
{results.ohlcData && Object.keys(results.ohlcData).length > 1 && (
<select
value={selectedSymbol || Object.keys(results.ohlcData)[0]}
onChange={(e) => setSelectedSymbol(e.target.value)}
className="px-3 py-1 text-sm bg-background border border-border rounded-md text-text-primary focus:outline-none focus:ring-1 focus:ring-primary-500"
>
{Object.keys(results.ohlcData).map(symbol => (
<option key={symbol} value={symbol}>{symbol}</option>
))}
</select>
)}
</div>
{(() => {
const hasOhlcData = results.ohlcData && Object.keys(results.ohlcData).length > 0;
const hasEquityData = results.equity && results.equity.length > 0;
if (hasOhlcData) {
const firstSymbol = Object.keys(results.ohlcData)[0];
const ohlcData = results.ohlcData[firstSymbol];
const activeSymbol = selectedSymbol || Object.keys(results.ohlcData)[0];
const ohlcData = results.ohlcData[activeSymbol];
// Create trade markers for the selected symbol
const tradeMarkers = results.trades
.filter(trade => trade.symbol === activeSymbol)
.map(trade => ({
time: Math.floor(new Date(trade.entryDate).getTime() / 1000),
position: 'belowBar' as const,
color: '#10b981',
shape: 'arrowUp' as const,
text: `Buy ${trade.quantity}@${trade.entryPrice.toFixed(2)}`,
id: `${trade.id}-entry`,
price: trade.entryPrice
}))
.concat(
results.trades
.filter(trade => trade.symbol === activeSymbol && trade.exitDate)
.map(trade => ({
time: Math.floor(new Date(trade.exitDate!).getTime() / 1000),
position: 'aboveBar' as const,
color: '#ef4444',
shape: 'arrowDown' as const,
text: `Sell ${trade.quantity}@${trade.exitPrice.toFixed(2)} (${trade.pnl >= 0 ? '+' : ''}${trade.pnl.toFixed(2)})`,
id: `${trade.id}-exit`,
price: trade.exitPrice
}))
);
return (
<Chart
@ -141,6 +182,7 @@ export function BacktestResults({ status, results, currentTime }: BacktestResult
lineWidth: 3
}
] : []}
tradeMarkers={tradeMarkers}
className="rounded"
/>
);