#!/usr/bin/env python3 """ ui_models.py - Pydantic Models and Data Structures Defines all API request/response models and data validation schemas """ from datetime import datetime from decimal import Decimal from typing import Dict, List, Optional, Any, Union from pydantic import BaseModel, Field, validator # Pydantic models for API requests/responses class TradingPairConfig(BaseModel): """Configuration for a trading pair""" symbol: str enabled: bool priority: int = 1 record_from_date: Optional[str] = None class TradingPairAdd(BaseModel): """Request to add a new trading pair""" symbol: str priority: int = 1 record_from_date: Optional[str] = None class BulkDownloadRequest(BaseModel): """Request for bulk historical data download""" symbols: List[str] # Changed from 'symbol' to 'symbols' to support multiple start_date: str end_date: Optional[str] = None intervals: Optional[List[str]] = None class GapFillRequest(BaseModel): """Request to fill data gaps""" symbol: str interval: str gap_start: str gap_end: str class AutoGapFillRequest(BaseModel): """Request to automatically fill gaps for a symbol""" symbol: str intervals: Optional[List[str]] = None fill_genuine_gaps: bool = True class GapDetectionRequest(BaseModel): """Request to detect gaps""" symbol: Optional[str] = None interval: Optional[str] = None class TechnicalIndicatorsConfig(BaseModel): """Complete technical indicators configuration (matching config.conf structure)""" enabled: Optional[List[str]] = None periods: Optional[Dict[str, Any]] = None calculation_intervals: Optional[List[str]] = None class Config: extra = "allow" # Allow additional fields class ConfigUpdate(BaseModel): """Update application configuration - accepts partial updates""" trading_pairs: Optional[List[TradingPairConfig]] = None technical_indicators: Optional[Dict[str, Any]] = None collection: Optional[Dict[str, Any]] = None gap_filling: Optional[Dict[str, Any]] = None database: Optional[Dict[str, Any]] = None ui: Optional[Dict[str, Any]] = None monitoring: Optional[Dict[str, Any]] = None alerts: Optional[Dict[str, Any]] = None data_quality: Optional[Dict[str, Any]] = None features: Optional[Dict[str, Any]] = None system: Optional[Dict[str, Any]] = None class Config: extra = "allow" # Allow additional config sections class EnvVarUpdate(BaseModel): """Update environment variable""" key: str value: str class ChartDataRequest(BaseModel): """Request chart data for visualization""" symbol: str interval: str = "1h" limit: int = 500 # Utility functions for JSON serialization def serialize_for_json(obj: Any) -> Any: """Recursively serialize datetime and Decimal objects in nested structures""" if isinstance(obj, datetime): return obj.isoformat() elif isinstance(obj, Decimal): return float(obj) elif isinstance(obj, dict): return {k: serialize_for_json(v) for k, v in obj.items()} elif isinstance(obj, list): return [serialize_for_json(item) for item in obj] return obj