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

19 KiB

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

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

VITE_API_URL=http://localhost:8000
VITE_WS_URL=ws://localhost:8000/ws/real-time

TypeScript Types

services/types.ts

Enums

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

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

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

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

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

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

export const settingsApi = {
  get: async (): Promise<AppSettings> => { },

  update: async (settings: Partial<AppSettings>): Promise<{
    message: string;
    updated_fields: string[];
  }> => { },
};

WebSocket Client Interface

services/websocket.ts

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

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

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

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

// 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

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

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

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

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

{
  "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