feat: autonomous trading engine — full implementation
- Database migration 018 with 13 tables for trading engine state - Trading engine service (services/trading/) with 12 pure computation modules: position sizer, stop-loss manager, reserve pool, circuit breaker, risk tier controller, correlation matrix, tax lots, trading window, gradual entry, notifications, micro-trading, backtester - Core TradingEngine with pre-trade evaluation pipeline and integration wiring - FastAPI HTTP service with 14 endpoints (health, config, decisions, metrics, backtest) - Performance tracker with Sharpe ratio, drawdown, profit factor computation - 194 Python tests (165 property-based + 29 integration) - Frontend: 13 TanStack Query hooks, 7 dashboard panels, tabbed Trading Engine page - Helm chart entry, network policy, nginx proxy, ingress for trading-engine - Shared infrastructure: enums, Redis keys, TradingConfig in AppConfig
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useTradingMetricsHistory } from '../../api/tradingHooks';
|
||||
import { Card, LoadingSpinner } from '../../components/ui';
|
||||
import {
|
||||
LineChart, Line, BarChart, Bar, AreaChart, Area,
|
||||
XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, Cell,
|
||||
} from 'recharts';
|
||||
|
||||
const tooltipStyle = {
|
||||
backgroundColor: '#1e293b',
|
||||
border: '1px solid #334155',
|
||||
borderRadius: 8,
|
||||
};
|
||||
|
||||
export function PerformanceCharts() {
|
||||
const { data: snapshots, isLoading } = useTradingMetricsHistory();
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (!snapshots) return [];
|
||||
return snapshots.map((s) => ({
|
||||
date: new Date(s.snapshot_date).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),
|
||||
portfolioValue: s.portfolio_value,
|
||||
cumulativeReturn: (s.cumulative_return ?? 0) * 100,
|
||||
dailyReturn: (s.daily_return ?? 0) * 100,
|
||||
drawdown: (s.current_drawdown_pct ?? 0) * 100,
|
||||
maxDrawdown: (s.max_drawdown ?? 0) * 100,
|
||||
}));
|
||||
}, [snapshots]);
|
||||
|
||||
if (isLoading) return <LoadingSpinner />;
|
||||
|
||||
if (chartData.length === 0) {
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-sm text-gray-500">No performance history available yet</p>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Cumulative P&L */}
|
||||
<Card>
|
||||
<h2 className="mb-3 text-sm font-medium text-gray-400">Cumulative P&L</h2>
|
||||
<ResponsiveContainer width="100%" height={280}>
|
||||
<LineChart data={chartData}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
|
||||
<XAxis dataKey="date" tick={{ fill: '#6b7280', fontSize: 11 }} />
|
||||
<YAxis tick={{ fill: '#6b7280', fontSize: 11 }} tickFormatter={(v) => `${v.toFixed(1)}%`} />
|
||||
<Tooltip
|
||||
contentStyle={tooltipStyle}
|
||||
labelStyle={{ color: '#9ca3af' }}
|
||||
formatter={(value: number) => [`${value.toFixed(2)}%`, 'Cumulative Return']}
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="cumulativeReturn"
|
||||
stroke="#6366f1"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
name="Cumulative Return"
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</Card>
|
||||
|
||||
{/* Daily Returns */}
|
||||
<Card>
|
||||
<h2 className="mb-3 text-sm font-medium text-gray-400">Daily Returns</h2>
|
||||
<ResponsiveContainer width="100%" height={220}>
|
||||
<BarChart data={chartData}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
|
||||
<XAxis dataKey="date" tick={{ fill: '#6b7280', fontSize: 11 }} />
|
||||
<YAxis tick={{ fill: '#6b7280', fontSize: 11 }} tickFormatter={(v) => `${v.toFixed(1)}%`} />
|
||||
<Tooltip
|
||||
contentStyle={tooltipStyle}
|
||||
labelStyle={{ color: '#9ca3af' }}
|
||||
formatter={(value: number) => [`${value.toFixed(2)}%`, 'Daily Return']}
|
||||
/>
|
||||
<Bar dataKey="dailyReturn" name="Daily Return">
|
||||
{chartData.map((entry, i) => (
|
||||
<Cell key={i} fill={entry.dailyReturn >= 0 ? '#22c55e' : '#ef4444'} />
|
||||
))}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</Card>
|
||||
|
||||
{/* Drawdown */}
|
||||
<Card>
|
||||
<h2 className="mb-3 text-sm font-medium text-gray-400">Drawdown</h2>
|
||||
<ResponsiveContainer width="100%" height={220}>
|
||||
<AreaChart data={chartData}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
|
||||
<XAxis dataKey="date" tick={{ fill: '#6b7280', fontSize: 11 }} />
|
||||
<YAxis tick={{ fill: '#6b7280', fontSize: 11 }} tickFormatter={(v) => `${v.toFixed(1)}%`} />
|
||||
<Tooltip
|
||||
contentStyle={tooltipStyle}
|
||||
labelStyle={{ color: '#9ca3af' }}
|
||||
formatter={(value: number) => [`${value.toFixed(2)}%`, 'Drawdown']}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="drawdown"
|
||||
stroke="#ef4444"
|
||||
fill="#ef444433"
|
||||
name="Current Drawdown"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user