Source code for project_x_py.utils.trading_calculations

"""
Trading-related calculations for position sizing, risk management, and price calculations.

Author: @TexasCoding
Date: 2025-08-02

Overview:
    Provides trading-related calculations for position sizing, risk management,
    and price calculations. Includes tick value calculations, position sizing
    based on risk management, price rounding to tick sizes, and risk/reward
    ratio calculations for trading strategy development.

Key Features:
    - Tick value calculations for different instruments
    - Position sizing based on risk management principles
    - Price rounding to valid tick sizes
    - Risk/reward ratio calculations
    - Position value calculations
    - Comprehensive risk management tools

Trading Calculations:
    - Tick value and price movement calculations
    - Position sizing with risk management
    - Price alignment to tick size requirements
    - Risk/reward ratio analysis
    - Position value and exposure calculations
    - Risk management and sizing optimization

Example Usage:
    ```python
    from project_x_py.utils import (
        calculate_tick_value,
        calculate_position_sizing,
        round_to_tick_size,
        calculate_risk_reward_ratio,
        calculate_position_value,
    )

    # Calculate tick value for price movement
    tick_value = calculate_tick_value(0.5, 0.1, 1.0)  # 5 ticks
    print(f"Tick value: ${tick_value}")

    # Calculate position sizing based on risk
    sizing = calculate_position_sizing(50000, 0.02, 2050, 2040, 1.0)
    print(f"Position size: {sizing['position_size']} contracts")
    print(f"Risk per trade: {sizing['actual_risk_percent']:.2%}")

    # Round price to valid tick size
    price = round_to_tick_size(2050.37, 0.1)
    print(f"Rounded price: {price}")

    # Calculate risk/reward ratio
    ratio = calculate_risk_reward_ratio(2050, 2045, 2065)
    print(f"Risk/Reward ratio: {ratio:.2f}")

    # Calculate position value
    value = calculate_position_value(5, 2050.0, 1.0, 0.1)
    print(f"Position value: ${value:,.2f}")
    ```

Risk Management Features:
    - Position sizing based on account balance and risk tolerance
    - Risk per trade calculation and validation
    - Price risk and dollar risk calculations
    - Actual vs. target risk percentage tracking
    - Risk management optimization and validation
    - Comprehensive risk analysis and reporting

Tick Value Calculations:
    - Dollar value of price movements
    - Tick size validation and error handling
    - Multi-instrument tick value support
    - Precision calculations for accurate pricing
    - Error handling for invalid inputs

Position Sizing:
    - Risk-based position sizing algorithms
    - Account balance and risk tolerance integration
    - Stop loss and entry price calculations
    - Position size optimization and validation
    - Risk percentage tracking and reporting
    - Comprehensive sizing analysis

Performance Characteristics:
    - Fast calculation algorithms for real-time trading
    - Memory-efficient calculations
    - Type-safe operations with proper validation
    - Optimized for high-frequency trading scenarios
    - Comprehensive error handling and validation

See Also:
    - `utils.portfolio_analytics`: Portfolio analysis and metrics
    - `utils.pattern_detection`: Pattern detection for trading signals
    - `utils.data_utils`: Data processing and analysis
"""

from typing import Any


[docs] def calculate_tick_value( price_change: float, tick_size: float, tick_value: float ) -> float: """ Calculate dollar value of a price change. Args: price_change: Price difference tick_size: Minimum price movement tick_value: Dollar value per tick Returns: float: Dollar value of the price change Example: >>> # MGC moves 5 ticks >>> calculate_tick_value(0.5, 0.1, 1.0) 5.0 """ # Validate inputs if tick_size <= 0: raise ValueError(f"tick_size must be positive, got {tick_size}") if tick_value < 0: raise ValueError(f"tick_value cannot be negative, got {tick_value}") if not isinstance(price_change, int | float): raise TypeError(f"price_change must be numeric, got {type(price_change)}") num_ticks = abs(price_change) / tick_size return num_ticks * tick_value
[docs] def calculate_position_value( size: int, price: float, tick_value: float, tick_size: float ) -> float: """ Calculate total dollar value of a position. Args: size: Number of contracts price: Current price tick_value: Dollar value per tick tick_size: Minimum price movement Returns: float: Total position value in dollars Example: >>> # 5 MGC contracts at $2050 >>> calculate_position_value(5, 2050.0, 1.0, 0.1) 102500.0 """ # Validate inputs if tick_size <= 0: raise ValueError(f"tick_size must be positive, got {tick_size}") if tick_value < 0: raise ValueError(f"tick_value cannot be negative, got {tick_value}") if price < 0: raise ValueError(f"price cannot be negative, got {price}") if not isinstance(size, int): raise TypeError(f"size must be an integer, got {type(size)}") ticks_per_point = 1.0 / tick_size value_per_point = ticks_per_point * tick_value return abs(size) * price * value_per_point
[docs] def round_to_tick_size(price: float, tick_size: float) -> float: """ Round price to nearest valid tick. Args: price: Price to round tick_size: Minimum price movement Returns: float: Price rounded to nearest tick Raises: ValueError: If tick_size is not positive or price is negative Example: >>> round_to_tick_size(2050.37, 0.1) 2050.4 """ # Validate inputs if tick_size <= 0: raise ValueError(f"tick_size must be positive, got {tick_size}") if price < 0: raise ValueError(f"price cannot be negative, got {price}") return round(price / tick_size) * tick_size
[docs] def calculate_risk_reward_ratio( entry_price: float, stop_price: float, target_price: float ) -> float: """ Calculate risk/reward ratio for a trade setup. Args: entry_price: Entry price stop_price: Stop loss price target_price: Profit target price Returns: float: Risk/reward ratio (reward / risk) Raises: ValueError: If prices are invalid (e.g., stop/target inversion) Example: >>> # Long trade: entry=2050, stop=2045, target=2065 >>> calculate_risk_reward_ratio(2050, 2045, 2065) 3.0 """ if entry_price == stop_price: raise ValueError("Entry price and stop price cannot be equal") risk = abs(entry_price - stop_price) reward = abs(target_price - entry_price) is_long = stop_price < entry_price if is_long and target_price <= entry_price: raise ValueError("For long positions, target must be above entry") elif not is_long and target_price >= entry_price: raise ValueError("For short positions, target must be below entry") if risk <= 0: return 0.0 return reward / risk
[docs] def calculate_position_sizing( account_balance: float, risk_per_trade: float, entry_price: float, stop_loss_price: float, tick_value: float = 1.0, ) -> dict[str, Any]: """ Calculate optimal position size based on risk management. Args: account_balance: Current account balance risk_per_trade: Risk per trade as decimal (e.g., 0.02 for 2%) entry_price: Entry price for the trade stop_loss_price: Stop loss price tick_value: Dollar value per tick Returns: Dict with position sizing information Example: >>> sizing = calculate_position_sizing(50000, 0.02, 2050, 2040, 1.0) >>> print(f"Position size: {sizing['position_size']} contracts") """ # Validate inputs if account_balance <= 0: raise ValueError(f"account_balance must be positive, got {account_balance}") if not 0 < risk_per_trade <= 1: raise ValueError( f"risk_per_trade must be between 0 and 1, got {risk_per_trade}" ) if entry_price <= 0: raise ValueError(f"entry_price must be positive, got {entry_price}") if stop_loss_price <= 0: raise ValueError(f"stop_loss_price must be positive, got {stop_loss_price}") if tick_value <= 0: raise ValueError(f"tick_value must be positive, got {tick_value}") try: # Calculate risk per share/contract price_risk = abs(entry_price - stop_loss_price) if price_risk == 0: return {"error": "No price risk (entry equals stop loss)"} # Calculate dollar risk dollar_risk_per_contract = price_risk * tick_value # Calculate maximum dollar risk for this trade max_dollar_risk = account_balance * risk_per_trade # Calculate position size position_size = max_dollar_risk / dollar_risk_per_contract # Round down to whole contracts position_size = int(position_size) # Calculate actual risk actual_dollar_risk = position_size * dollar_risk_per_contract actual_risk_percent = actual_dollar_risk / account_balance return { "position_size": position_size, "price_risk": price_risk, "dollar_risk_per_contract": dollar_risk_per_contract, "max_dollar_risk": max_dollar_risk, "actual_dollar_risk": actual_dollar_risk, "actual_risk_percent": actual_risk_percent, "risk_reward_ratio": None, # Can be calculated if target provided } except Exception as e: return {"error": str(e)}