129 lines
3.5 KiB
Python
129 lines
3.5 KiB
Python
|
|
"""
|
||
|
|
Data normalization utilities.
|
||
|
|
|
||
|
|
This module provides functions for normalizing various data formats
|
||
|
|
to consistent standards across the application.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from typing import Optional
|
||
|
|
from logging import Logger
|
||
|
|
|
||
|
|
|
||
|
|
def normalize_trade_side(
|
||
|
|
side: str,
|
||
|
|
logger: Optional[Logger] = None,
|
||
|
|
component_name: str = "normalization"
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Normalize trade side to standard format.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
side: Raw trade side string
|
||
|
|
logger: Optional logger for error messages
|
||
|
|
component_name: Name for logging
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Normalized side ('buy' or 'sell')
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
ValueError: If side is invalid, empty, or unknown
|
||
|
|
"""
|
||
|
|
if not side or not isinstance(side, str):
|
||
|
|
error_msg = f"Invalid trade side: {side}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
normalized = side.lower().strip()
|
||
|
|
|
||
|
|
# Handle common variations
|
||
|
|
if normalized in ['buy', 'bid', 'b', '1']:
|
||
|
|
return 'buy'
|
||
|
|
elif normalized in ['sell', 'ask', 's', '0', '2']:
|
||
|
|
return 'sell'
|
||
|
|
else:
|
||
|
|
error_msg = f"Invalid trade side: {side}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
|
||
|
|
def validate_symbol_format(
|
||
|
|
symbol: str,
|
||
|
|
logger: Optional[Logger] = None,
|
||
|
|
component_name: str = "normalization"
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Validate and normalize symbol format.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
symbol: Trading symbol
|
||
|
|
logger: Optional logger for error messages
|
||
|
|
component_name: Name for logging
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Normalized symbol
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
ValueError: If symbol is invalid
|
||
|
|
"""
|
||
|
|
if not symbol or not isinstance(symbol, str):
|
||
|
|
error_msg = f"Invalid symbol: {symbol}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
# Remove whitespace and convert to uppercase
|
||
|
|
normalized = symbol.strip().upper()
|
||
|
|
|
||
|
|
# Basic validation
|
||
|
|
if not normalized or len(normalized) < 3:
|
||
|
|
error_msg = f"Symbol too short: {symbol}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
# Check for common delimiters
|
||
|
|
if '-' not in normalized and '/' not in normalized:
|
||
|
|
error_msg = f"Invalid symbol format (missing delimiter): {symbol}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
return normalized
|
||
|
|
|
||
|
|
|
||
|
|
def normalize_exchange_name(
|
||
|
|
exchange: str,
|
||
|
|
logger: Optional[Logger] = None,
|
||
|
|
component_name: str = "normalization"
|
||
|
|
) -> str:
|
||
|
|
"""
|
||
|
|
Normalize exchange name.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
exchange: Exchange name
|
||
|
|
logger: Optional logger for error messages
|
||
|
|
component_name: Name for logging
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Normalized exchange name
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
ValueError: If exchange name is invalid
|
||
|
|
"""
|
||
|
|
if not exchange or not isinstance(exchange, str):
|
||
|
|
error_msg = f"Invalid exchange name: {exchange}"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
normalized = exchange.lower().strip()
|
||
|
|
|
||
|
|
if not normalized:
|
||
|
|
error_msg = "Exchange name cannot be empty"
|
||
|
|
if logger:
|
||
|
|
logger.error(f"{component_name}: {error_msg}")
|
||
|
|
raise ValueError(error_msg)
|
||
|
|
|
||
|
|
return normalized
|