Files
energy-trade/FRONTEND_IMPLEMENTATION.md
kbt-devops a22a13f6f4 Add initial implementation strategy documentation
Add comprehensive documentation for energy trading system:
- Backend: FastAPI architecture, API routes, services, WebSocket
- Frontend: React structure, components, state management
- ML: Feature engineering, XGBoost price prediction, RL battery optimization
2026-02-11 02:16:25 +07:00

781 lines
19 KiB
Markdown

# Frontend Implementation Strategy
## Overview
This document outlines the React frontend for the energy trading system UI. The frontend provides real-time monitoring, backtesting tools, ML model insights, and trading controls.
**Backend API**: `http://localhost:8000`
---
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ React Application │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Pages Layer │ │
│ │ Dashboard │ Backtest │ Models │ Trading │ Settings │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Components Layer │ │
│ │ Charts │ Forms │ Alerts │ Tables │ Controls │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Services Layer │ │
│ │ API Client │ WebSocket │ State Management │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ FastAPI Backend │
│ REST API + WebSocket │
└──────────────────────────────────────────────────────────────┘
```
---
## Project Structure
```
frontend/
├── public/
│ ├── favicon.ico
│ └── index.html
├── src/
│ ├── App.tsx # Main app component
│ ├── main.tsx # Entry point
│ ├── index.css # Global styles
│ │
│ ├── components/
│ │ ├── common/
│ │ │ ├── Header.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ ├── Loading.tsx
│ │ │ └── Error.tsx
│ │ │
│ │ ├── charts/
│ │ │ ├── PriceChart.tsx
│ │ │ ├── BatteryChart.tsx
│ │ │ ├── PnLChart.tsx
│ │ │ ├── GenerationChart.tsx
│ │ │ └── ModelMetricsChart.tsx
│ │ │
│ │ ├── alerts/
│ │ │ ├── AlertPanel.tsx
│ │ │ └── AlertItem.tsx
│ │ │
│ │ ├── tables/
│ │ │ ├── ArbitrageTable.tsx
│ │ │ ├── TradeLogTable.tsx
│ │ │ └── ModelListTable.tsx
│ │ │
│ │ └── forms/
│ │ ├── BacktestForm.tsx
│ │ ├── TrainingForm.tsx
│ │ └── SettingsForm.tsx
│ │
│ ├── pages/
│ │ ├── Dashboard.tsx
│ │ ├── Backtest.tsx
│ │ ├── Models.tsx
│ │ ├── Trading.tsx
│ │ └── Settings.tsx
│ │
│ ├── hooks/
│ │ ├── useWebSocket.ts
│ │ ├── useApi.ts
│ │ ├── useBacktest.ts
│ │ ├── useModels.ts
│ │ └── useTrading.ts
│ │
│ ├── services/
│ │ ├── api.ts # REST API client
│ │ ├── websocket.ts # WebSocket client
│ │ └── types.ts # TypeScript types
│ │
│ ├── store/
│ │ ├── index.ts # Zustand store setup
│ │ ├── dashboardSlice.ts
│ │ ├── backtestSlice.ts
│ │ ├── modelsSlice.ts
│ │ └── tradingSlice.ts
│ │
│ └── lib/
│ ├── utils.ts
│ ├── constants.ts
│ └── formatters.ts
├── tests/
├── .env.example
├── .env.local
├── package.json
├── tsconfig.json
├── vite.config.ts
└── tailwind.config.js
```
---
## Configuration
### vite.config.ts
```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
},
'/ws': {
target: 'ws://localhost:8000',
ws: true,
},
},
},
});
```
### .env.example
```bash
VITE_API_URL=http://localhost:8000
VITE_WS_URL=ws://localhost:8000/ws/real-time
```
---
## TypeScript Types
### services/types.ts
#### Enums
```typescript
export enum Region {
FR = "FR",
BE = "BE",
DE = "DE",
NL = "NL",
UK = "UK",
}
export enum Strategy {
FUNDAMENTAL = "fundamental",
TECHNICAL = "technical",
ML = "ml",
MINING = "mining",
}
export enum TradeType {
BUY = "buy",
SELL = "sell",
CHARGE = "charge",
DISCHARGE = "discharge",
}
export enum BacktestStatus {
PENDING = "pending",
RUNNING = "running",
COMPLETED = "completed",
FAILED = "failed",
CANCELLED = "cancelled",
}
export enum ModelType {
PRICE_PREDICTION = "price_prediction",
RL_BATTERY = "rl_battery",
}
```
#### Key Interfaces
```typescript
export interface PriceData {
timestamp: string;
region: Region;
day_ahead_price: number;
real_time_price: number;
volume_mw: number;
}
export interface BatteryState {
battery_id: string;
timestamp: string;
capacity_mwh: number;
charge_level_mwh: number;
charge_level_pct: number;
charge_rate_mw: number;
discharge_rate_mw: number;
efficiency: number;
}
export interface BacktestConfig {
start_date: string;
end_date: string;
strategies: Strategy[];
use_ml: boolean;
battery_min_reserve?: number;
battery_max_charge?: number;
arbitrage_min_spread?: number;
}
export interface BacktestMetrics {
total_revenue: number;
arbitrage_profit: number;
battery_revenue: number;
mining_profit: number;
battery_utilization: number;
price_capture_rate: number;
win_rate: number;
sharpe_ratio: number;
max_drawdown: number;
total_trades: number;
}
export interface BacktestStatus {
id: string;
status: BacktestStatus;
progress: number;
current_step: string;
started_at?: string;
completed_at?: string;
error?: string;
}
export interface ModelInfo {
id: string;
type: ModelType;
name: string;
horizon?: number;
created_at: string;
metrics: Record<string, number>;
status: string;
}
export interface TrainingRequest {
model_type: ModelType;
horizon?: number;
start_date: string;
end_date: string;
hyperparameters: Record<string, unknown>;
}
export interface TrainingStatus {
id: string;
status: BacktestStatus;
progress: number;
current_epoch?: number;
total_epochs?: number;
metrics: Record<string, number>;
started_at?: string;
completed_at?: string;
error?: string;
}
export interface PredictionRequest {
model_id: string;
timestamp: string;
features?: Record<string, unknown>;
}
export interface PredictionResponse {
model_id: string;
timestamp: string;
prediction: number;
confidence?: number;
features_used: string[];
}
export interface StrategyStatus {
strategy: Strategy;
running: boolean;
last_updated?: string;
}
export interface TradingPosition {
region: Region;
position_mw: number;
battery_charge_pct: number;
pnl: number;
}
export interface Alert {
id: string;
timestamp: string;
type: AlertType;
severity: "info" | "warning" | "error";
message: string;
data: Record<string, unknown>;
acknowledged: boolean;
}
```
---
## API Client Interface
### services/api.ts
#### Dashboard API
```typescript
export const dashboardApi = {
getSummary: async (): Promise<DashboardSummary> => { },
getPrices: async (): Promise<Record<string, PriceData>> => { },
getPriceHistory: async (
region: string,
start?: string,
end?: string,
limit?: number
): Promise<{ region: string; data: PriceData[] }> => { },
getBatteryStates: async (): Promise<BatteryState[]> => { },
getArbitrage: async (minSpread?: number): Promise<{
opportunities: ArbitrageOpportunity[];
count: number;
}> => { },
};
```
#### Backtest API
```typescript
export const backtestApi = {
start: async (request: BacktestRequest): Promise<{
backtest_id: string;
status: BacktestStatus;
}> => { },
get: async (backtestId: string): Promise<{
status: BacktestStatus;
results?: BacktestResult;
}> => { },
getResults: async (backtestId: string): Promise<BacktestResult> => { },
getTrades: async (backtestId: string, limit?: number): Promise<{
backtest_id: string;
trades: Trade[];
total: number;
}> => { },
list: async (): Promise<{
backtests: BacktestStatus[];
total: number;
}> => { },
delete: async (backtestId: string): Promise<{ message: string }> => { },
};
```
#### Models API
```typescript
export const modelsApi = {
list: async (): Promise<{ models: ModelInfo[]; total: number }> => { },
train: async (request: TrainingRequest): Promise<{
training_id: string;
status: TrainingStatus;
}> => { },
getStatus: async (modelId: string): Promise<TrainingStatus> => { },
getMetrics: async (modelId: string): Promise<{
model_id: string;
metrics: Record<string, number>;
}> => { },
predict: async (request: PredictionRequest): Promise<PredictionResponse> => { },
};
```
#### Trading API
```typescript
export const tradingApi = {
getStrategies: async (): Promise<{ strategies: StrategyStatus[] }> => { },
toggleStrategy: async (control: {
strategy: Strategy;
action: "start" | "stop";
}): Promise<{ status: StrategyStatus }> => { },
getPositions: async (): Promise<{ positions: TradingPosition[] }> => { },
};
```
#### Settings API
```typescript
export const settingsApi = {
get: async (): Promise<AppSettings> => { },
update: async (settings: Partial<AppSettings>): Promise<{
message: string;
updated_fields: string[];
}> => { },
};
```
---
## WebSocket Client Interface
### services/websocket.ts
```typescript
class WebSocketService {
private ws: WebSocket | null = null;
private url: string;
private eventHandlers: Map<WebSocketEventType, Set<EventHandler>> = new Map();
private isConnected = false;
constructor(url: string = import.meta.env.VITE_WS_URL);
connect(): void;
disconnect(): void;
subscribe<T = unknown>(
eventType: WebSocketEventType,
handler: (data: T) => void
): () => void; // Returns unsubscribe function
getConnectionStatus(): boolean;
private handleMessage(message: WebSocketMessage): void;
private attemptReconnect(): void;
}
export const webSocketService = new WebSocketService();
```
### WebSocket Event Types
```typescript
export type WebSocketEventType =
| "price_update"
| "battery_update"
| "arbitrage_opportunity"
| "trade_executed"
| "alert_triggered"
| "backtest_progress"
| "model_training_progress";
export interface WebSocketMessage<T = unknown> {
type: WebSocketEventType;
timestamp: string;
data: T;
}
```
---
## State Management (Zustand)
### store/index.ts
```typescript
interface DashboardState {
summary: DashboardSummary | null;
prices: Record<string, PriceData>;
batteryStates: BatteryState[];
arbitrageOpportunities: ArbitrageOpportunity[];
alerts: Alert[];
updateSummary: (summary: DashboardSummary) => void;
updatePrices: (prices: Record<string, PriceData>) => void;
addAlert: (alert: Alert) => void;
// ...
}
interface BacktestState {
backtests: Record<string, BacktestStatus>;
currentBacktest: string | null;
isRunning: boolean;
updateBacktest: (status: BacktestStatus) => void;
setCurrentBacktest: (backtestId: string | null) => void;
// ...
}
interface ModelsState {
models: ModelInfo[];
trainingJobs: Record<string, TrainingStatus>;
selectedModel: string | null;
setModels: (models: ModelInfo[]) => void;
updateTrainingJob: (job: TrainingStatus) => void;
// ...
}
interface TradingState {
strategies: Record<string, StrategyStatus>;
positions: TradingPosition[];
pnl: number;
updateStrategy: (strategy: StrategyStatus) => void;
updatePositions: (positions: TradingPosition[]) => void;
// ...
}
export const useStore = create<AppStore>((set) => ({
// ... state and actions
}));
```
---
## Custom Hooks
### hooks/useWebSocket.ts
```typescript
export function useWebSocket() {
const subscribe = <T = unknown>(
eventType: WebSocketEventType,
handler: (data: T) => void
): (() => void) => {
return webSocketService.subscribe<T>(eventType, handler);
};
const isConnected = webSocketService.getConnectionStatus();
return { subscribe, isConnected };
}
```
### hooks/useApi.ts
```typescript
// Dashboard hooks
export function useDashboardSummary();
export function usePrices();
export function useBatteryStates();
export function useArbitrageOpportunities(minSpread?: number);
// Backtest hooks
export function useStartBacktest();
export function useBacktest(backtestId: string);
export function useBacktestList();
// Models hooks
export function useModels();
export function useTrainModel();
// Trading hooks
export function useStrategies();
export function useToggleStrategy();
export function usePositions();
// Settings hooks
export function useSettings();
export function useUpdateSettings();
```
---
## Pages Interface
### Dashboard.tsx
```typescript
export default function Dashboard() {
const { subscribe } = useWebSocket();
const { prices, batteryStates, arbitrageOpportunities, alerts } = useStore();
const { data: pricesData } = usePrices();
// Subscribe to real-time updates
useEffect(() => {
const unsubscribePrice = subscribe('price_update', (data) => { });
const unsubscribeBattery = subscribe('battery_update', (data) => { });
const unsubscribeAlert = subscribe('alert_triggered', (data) => { });
return () => {
unsubscribePrice();
unsubscribeBattery();
unsubscribeAlert();
};
}, [subscribe]);
// Render stats cards, charts, tables
}
```
### Backtest.tsx
```typescript
export default function Backtest() {
const [selectedBacktestId, setSelectedBacktestId] = useState<string | null>(null);
const { mutate: startBacktest, isPending } = useStartBacktest();
const { data: backtest } = useBacktest(selectedBacktestId || '');
const { data: backtestList } = useBacktestList();
const handleStartBacktest = (config: any) => {
startBacktest({ config, name: config.name }, {
onSuccess: (data) => {
setSelectedBacktestId(data.backtest_id);
},
});
};
// Render form, results, progress
}
```
### Models.tsx
```typescript
export default function Models() {
const [selectedModel, setSelectedModel] = useState<string | null>(null);
const [showTrainingForm, setShowTrainingForm] = useState(false);
const { data: modelsData } = useModels();
const { mutate: trainModel, isPending } = useTrainModel();
const handleTrainModel = (config: any) => {
trainModel(config, {
onSuccess: () => {
setShowTrainingForm(false);
},
});
};
// Render model list, training form, model details
}
```
### Trading.tsx
```typescript
export default function Trading() {
const { data: strategiesData } = useStrategies();
const { data: positionsData } = usePositions();
const { mutate: toggleStrategy } = useToggleStrategy();
const handleToggleStrategy = (strategyName: string, running: boolean) => {
toggleStrategy({
strategy: strategyName as any,
action: running ? 'stop' : 'start',
});
};
// Render strategy status, positions, controls
}
```
---
## Dependencies
### package.json
```json
{
"name": "energy-trading-ui",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "vitest",
"type-check": "tsc --noEmit"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"recharts": "^2.10.0",
"zustand": "^4.4.0",
"@tanstack/react-query": "^5.0.0",
"axios": "^1.6.0",
"date-fns": "^2.30.0",
"lucide-react": "^0.292.0"
},
"devDependencies": {
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@vitejs/plugin-react": "^4.2.0",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vitest": "^1.0.0",
"tailwindcss": "^3.3.5"
}
}
```
---
## Data Flow
### API Calls
```
Component → useApi Hook → API Client → Axios → Backend
React Query Cache
Automatic Refetch
```
### WebSocket Updates
```
WebSocket Event → WebSocketService → Event Handler → Store Update → Component Re-render
```
### State Synchronization
```
API Response → React Query Cache → Component Props → Zustand Store (optional)
WebSocket Event → Zustand Store → Component Re-render
```
---
## Key Integration Points
### Backend API Integration
- REST API endpoints are fully typed in `services/types.ts`
- API client methods in `services/api.ts` match backend routes
- WebSocket events match backend event types
### Error Handling
- API errors handled by React Query error states
- WebSocket reconnection automatic with exponential backoff
- Component-level error boundaries for unhandled errors
### Performance
- React Query caching with automatic refetch intervals
- WebSocket connection pooling
- Component memoization where appropriate
- Virtual scrolling for large data tables