- Introduced a new transformation module that includes safety limits for trade operations, enhancing data integrity and preventing errors. - Refactored existing transformation logic into dedicated classes and functions, improving modularity and maintainability. - Added detailed validation for trade sizes, prices, and symbol formats, ensuring compliance with trading rules. - Implemented logging for significant operations and validation checks, aiding in monitoring and debugging. - Created a changelog to document the new features and changes, providing clarity for future development. - Developed extensive unit tests to cover the new functionality, ensuring reliability and preventing regressions. These changes significantly enhance the architecture of the transformation module, making it more robust and easier to manage.
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 |