
    iiO                        d Z ddlmZ ddlmZmZ g dZe G d d             Ze G d d             Ze G d	 d
             Z	e G d d             Z
 ed       G d d             Ze G d d             Ze G d d             Ze G d d             Ze G d d             Ze G d d             Ze G d d             Zy)a  
ProjectX Data Models

Author: @TexasCoding
Date: 2025-08-02

Overview:
    Contains all data model classes for the ProjectX API client. Provides
    comprehensive data structures for trading entities, configuration,
    and real-time events. All models use dataclasses for type safety
    and automatic serialization/deserialization.

Key Features:
    - Comprehensive trading entity models (Instrument, Order, Position, Trade)
    - Configuration models with default values
    - Real-time event models for WebSocket data
    - Type-safe dataclass implementations
    - Automatic serialization/deserialization
    - Comprehensive field documentation and examples

Data Models:
    - Trading Entities: Instrument, Order, Position, Trade, Account
    - Configuration: ProjectXConfig with default TopStepX endpoints
    - Responses: OrderPlaceResponse, BracketOrderResponse
    - Events: OrderUpdateEvent, PositionUpdateEvent, MarketDataEvent

Example Usage:
    ```python
    from project_x_py.models import (
        Instrument,
        Order,
        Position,
        Trade,
        Account,
        ProjectXConfig,
        OrderPlaceResponse,
    )

    # Create instrument model
    instrument = Instrument(
        id="CON.F.US.MNQ.U25",
        name="MNQU25",
        description="E-mini NASDAQ-100 Futures September 2025",
        tickSize=0.25,
        tickValue=0.50,
        activeContract=True,
    )

    # Create order model
    order = Order(
        id=12345,
        accountId=1001,
        contractId="CON.F.US.MNQ.U25",
        creationTimestamp="2024-01-01T10:00:00Z",
        updateTimestamp="2024-01-01T10:00:05Z",
        status=OrderStatus.OPEN,
        type=OrderType.LIMIT,
        side=OrderSide.BUY,
        size=5,
        limitPrice=2050.0,
    )

    # Create position model
    position = Position(
        id=67890,
        accountId=1001,
        contractId="CON.F.US.MNQ.U25",
        creationTimestamp="2024-01-01T10:00:00Z",
        type=PositionType.LONG,
        size=5,
        averagePrice=2050.0,
    )

    # Create configuration
    config = ProjectXConfig(
        api_url="https://api.topstepx.com/api",
        user_hub_url="https://rtc.topstepx.com/hubs/user",
        market_hub_url="https://rtc.topstepx.com/hubs/market",
        timezone="America/Chicago",
    )
    ```

Trading Entity Models:
    - Instrument: Tradeable financial instruments with tick information
    - Order: Trading orders with status, type, and execution details
    - Position: Open trading positions with size and average price
    - Trade: Executed trades with P&L and fee information
    - Account: Trading accounts with balance and permissions

Configuration Models:
    - ProjectXConfig: Client configuration with endpoints and settings
    - Default TopStepX endpoints for production use
    - Customizable for different ProjectX deployments
    - Comprehensive validation and error handling

Event Models:
    - OrderUpdateEvent: Real-time order status updates
    - PositionUpdateEvent: Real-time position changes
    - MarketDataEvent: Real-time market data updates

Model Features:
    - Type-safe dataclass implementations
    - Comprehensive field documentation
    - Automatic serialization/deserialization
    - Validation and error handling
    - Default values for optional fields
    - Enum support for status and type fields

See Also:
    - `config`: Configuration management utilities
    - `exceptions`: Error handling for model validation
    - `types`: Type definitions and protocols
    )	dataclass)AnyUnion)AccountBracketOrderResponse
InstrumentMarketDataEventOrderOrderPlaceResponseOrderUpdateEventPositionPositionUpdateEventProjectXConfigTradec                   b    e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   dZedz  ed	<   y)
r   a  
    Represents a tradeable financial instrument/contract.

    Attributes:
        id (str): Unique contract identifier used in API calls
        name (str): Contract name/symbol (e.g., "MNQU25", "ESH25")
        description (str): Human-readable description of the contract
        tickSize (float): Minimum price movement (e.g., 0.1)
        tickValue (float): Dollar value per tick movement
        activeContract (bool): Whether the contract is currently active for trading

    Example:
        >>> print(f"Trading {instrument.name}")
        >>> print(
        ...     f"Tick size: ${instrument.tickSize}, Tick value: ${instrument.tickValue}"
        ... )
    idnamedescriptiontickSize	tickValueactiveContractNsymbolId)	__name__
__module____qualname____doc__str__annotations__floatboolr        L/home/work/apex_v16/venv/lib/python3.12/site-packages/project_x_py/models.pyr   r      s8    $ 	G
IOHcDjr"   r   c                   N    e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   y)	r   ac  
    Represents a trading account with balance and permissions.

    Attributes:
        id (int): Unique account identifier
        name (str): Account name/label
        balance (float): Current account balance in dollars
        canTrade (bool): Whether trading is enabled for this account
        isVisible (bool): Whether the account is visible in the interface
        simulated (bool): Whether this is a simulated/demo account

    Example:
        >>> print(f"Account: {account.name}")
        >>> print(f"Balance: ${account.balance:,.2f}")
        >>> print(f"Trading enabled: {account.canTrade}")
    r   r   balancecanTrade	isVisible	simulatedN)	r   r   r   r   intr   r   r   r    r!   r"   r#   r   r      s'    " 	G
INNOOr"   r   c                      e Zd ZU dZeed<   eed<   eed<   eed<   edz  ed<   eed<   eed	<   eed
<   eed<   dZedz  ed<   dZedz  ed<   dZ	e
dz  ed<   dZe
dz  ed<   dZe
dz  ed<   dZedz  ed<   edefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zede
fd       Zedefd       Zedefd        Zy)!r
   a\  
    Represents a trading order with all its details.

    Attributes:
        id (int): Unique order identifier
        accountId (int): Account that placed the order
        contractId (str): Contract being traded
        symbolId (Optional[str]): Symbol ID corresponding to the contract
        creationTimestamp (str): When the order was created (ISO format)
        updateTimestamp (Optional[str]): When the order was last updated
        status (int): Order status code (OrderStatus enum):
            0=None, 1=Open, 2=Filled, 3=Cancelled, 4=Expired, 5=Rejected, 6=Pending
        type (int): Order type (OrderType enum):
            0=Unknown, 1=Limit, 2=Market, 3=StopLimit, 4=Stop, 5=TrailingStop, 6=JoinBid, 7=JoinAsk
        side (int): Order side (OrderSide enum): 0=Bid, 1=Ask
        size (int): Number of contracts
        fillVolume (Optional[int]): Number of contracts filled (partial fills)
        limitPrice (Optional[float]): Limit price (for limit orders)
        stopPrice (Optional[float]): Stop price (for stop orders)
        filledPrice (Optional[float]): The price at which the order was filled, if any
        customTag (Optional[str]): Custom tag associated with the order, if any

    Example:
        >>> side_str = "Bid" if order.side == 0 else "Ask"
        >>> print(f"Order {order.id}: {side_str} {order.size} {order.contractId}")
    r   	accountId
contractIdcreationTimestampNupdateTimestampstatustypesidesizer   
fillVolume
limitPrice	stopPricefilledPrice	customTagreturnc                      | j                   dk(  S )zCheck if order is still open.   r/   selfs    r#   is_openzOrder.is_open        {{ar"   c                      | j                   dk(  S )z$Check if order is completely filled.   r;   r<   s    r#   	is_filledzOrder.is_filled   r?   r"   c                      | j                   dk(  S )zCheck if order was cancelled.   r;   r<   s    r#   is_cancelledzOrder.is_cancelled   r?   r"   c                      | j                   dk(  S )zCheck if order was rejected.   r;   r<   s    r#   is_rejectedzOrder.is_rejected   r?   r"   c                     | j                   dv S )z,Check if order is working (open or pending).)r:      r;   r<   s    r#   
is_workingzOrder.is_working   s     {{f$$r"   c                     | j                   dv S )z&Check if order is in a terminal state.)rA   rD      rG   r;   r<   s    r#   is_terminalzOrder.is_terminal  s     {{l**r"   c                      | j                   dk(  S )zCheck if this is a buy order.r   r1   r<   s    r#   is_buyzOrder.is_buy       yyA~r"   c                      | j                   dk(  S )zCheck if this is a sell order.r:   rP   r<   s    r#   is_sellzOrder.is_sell  rR   r"   c                 "    | j                   rdS dS )zGet order side as string.BUYSELL)rQ   r<   s    r#   side_strzOrder.side_str  s     u//r"   c                 N    dddddddd}|j                  | j                  d	      S )
zGet order type as string.LIMITMARKET
STOP_LIMITSTOPTRAILING_STOPJOIN_BIDJOIN_ASK)r:   rA   rD   rM   rG   rJ      UNKNOWN)getr0   )r=   type_maps     r#   type_strzOrder.type_str  s7     
 ||DIIy11r"   c                 N    dddddddd}|j                  | j                  d	      S )
zGet order status as string.NONEOPENFILLED	CANCELLEDEXPIREDREJECTEDPENDING)r   r:   rA   rD   rM   rG   rJ   rb   )rc   r/   )r=   
status_maps     r#   
status_strzOrder.status_str%  s7     

 ~~dkk955r"   c                 r    | j                   | j                  dk(  ry| j                   | j                  z  dz  S )z-Get percentage of order that has been filled.r           d   r3   r2   r<   s    r#   filled_percentzOrder.filled_percent3  s3     ??"dii1n$))+s22r"   c                 d    | j                   | j                  S | j                  | j                   z
  S )zGet remaining unfilled size.rs   r<   s    r#   remaining_sizezOrder.remaining_size:  s+     ??"99yy4??**r"   c                     d| j                   v r.| j                   j                  d      }t        |      dk\  r|d   S | j                   S )z Extract symbol from contract ID..rM   rD   r,   splitlenr=   partss     r#   symbolzOrder.symbolA  sB     $//!OO))#.E5zQQxr"   )r   r   r   r   r)   r   r   r   r3   r4   r   r5   r6   r7   propertyr    r>   rB   rE   rH   rK   rN   rQ   rT   rX   re   ro   rt   rv   r~   r!   r"   r#   r
   r
      s   6 	GNO4ZK
I
I
IHcDj!Jd
!#J#"Iut|" $K$ IsTz        4      d      T     %D % % +T + +       0# 0 0 2# 2 2 6C 6 6 3 3 3 + + +   r"   r
   c                   @    e Zd ZU dZeed<   eed<   eed<   edz  ed<   y)r   a  
    Response from placing an order.

    Attributes:
        orderId (int): ID of the newly created order
        success (bool): Whether the order placement was successful
        errorCode (int): Error code (0 = success)
        errorMessage (Optional[str]): Error message if placement failed

    Example:
        >>> if response.success:
        ...     print(f"Order placed successfully with ID: {response.orderId}")
        ... else:
        ...     print(f"Order failed: {response.errorMessage}")
    orderIdsuccess	errorCodeNerrorMessage)r   r   r   r   r)   r   r    r   r!   r"   r#   r   r   K  s"      LMN*r"   r   F)initc                   :   e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   eed<   dededededededed	ed
dfdZ	ded
e
eeef   fdZed
efd       Zed
efd       Zed
efd       Zed
efd       Zed
efd       Zed
efd       Zddeded
efdZy)r   a  
    Represents an open trading position.

    Attributes:
        id (int): Unique position identifier
        accountId (int): Account holding the position
        contractId (str): Contract of the position
        creationTimestamp (str): When the position was opened (ISO format)
        type (int): Position type code (PositionType enum):
            0=UNDEFINED, 1=LONG, 2=SHORT
        size (int): Position size (number of contracts, always positive)
        averagePrice (float): Average entry price of the position

    Note:
        This model contains only the fields returned by ProjectX API.
        For P&L calculations, use PositionManager.calculate_position_pnl() method.

    Example:
        >>> direction = "LONG" if position.type == PositionType.LONG else "SHORT"
        >>> print(
        ...     f"{direction} {position.size} {position.contractId} @ ${position.averagePrice}"
        ... )
    r   r+   r,   r-   r0   r2   averagePrice_extrar8   Nc                f    || _         || _        || _        || _        || _        || _        || _        y )N)r   r+   r,   r-   r0   r2   r   )	r=   r   r+   r,   r-   r0   r2   r   r   s	            r#   __init__zPosition.__init__  s7     "$!2		(r"   keyc                     t        | |      }t        |t        t        z  t        z        r|S t        d| dt        |       d      )Nz
Attribute z
 has type z, expected int, str, or float)getattr
isinstancer)   r   r   	TypeErrorr0   )r=   r   values      r#   __getitem__zPosition.__getitem__  sJ    c"eS3Y./LSEDK=8UV r"   c                      | j                   dk(  S )z!Check if this is a long position.r:   r0   r<   s    r#   is_longzPosition.is_long  rR   r"   c                      | j                   dk(  S )z"Check if this is a short position.rA   r   r<   s    r#   is_shortzPosition.is_short  rR   r"   c                 8    | j                   ry| j                  ryy)z!Get position direction as string.LONGSHORT	UNDEFINED)r   r   r<   s    r#   	directionzPosition.direction  s     <<]]r"   c                     d| j                   v r.| j                   j                  d      }t        |      dk\  r|d   S | j                   S )zFExtract symbol from contract ID (e.g., 'MNQ' from 'CON.F.US.MNQ.H25').rx   rM   rD   ry   r|   s     r#   r~   zPosition.symbol  sB     $//!OO))#.E5zQQxr"   c                 L    | j                   r| j                   S | j                  S )z2Get size with sign (negative for short positions).)r   r2   r<   s    r#   signed_sizezPosition.signed_size  s     "]]		z9		9r"   c                 4    | j                   | j                  z  S )zCalculate total position cost.)r2   r   r<   s    r#   
total_costzPosition.total_cost  s     yy4,,,,r"   current_price
tick_valuec                     | j                   r|| j                  z
  | j                  z  |z  S | j                  r| j                  |z
  | j                  z  |z  S y)z
        Calculate unrealized P&L given current price.

        Args:
            current_price: Current market price
            tick_value: Value per point move (default: 1.0)

        Returns:
            Unrealized P&L in dollars
        rq   )r   r   r2   r   )r=   r   r   s      r#   unrealized_pnlzPosition.unrealized_pnl  sS     <<!D$5$55BZOO]]%%5BZOOr"   )g      ?)r   r   r   r   r)   r   r   r   r   r   r   r   r   r    r   r   r   r~   r   r   r   r!   r"   r#   r   r   c  sg   0 	GNO
I
I) ) 	)
 ) ) ) ) ) ) 
)*s uS#u_'=     $   3      :S : : -E - -E u u r"   r   c                       e Zd ZU dZdZeed<   eed<   eed<   eed<   eed<   edz  ed	<   eed
<   eed<   eed<   e	ed<   eed<   y)r   aD  
    Represents an executed trade with P&L information.

    Attributes:
        id (int): Unique trade identifier
        accountId (int): Account that executed the trade
        contractId (str): Contract that was traded
        creationTimestamp (str): When the trade was executed (ISO format)
        price (float): Execution price
        profitAndLoss (Optional[float]): Realized P&L (None for half-turn trades)
        fees (float): Trading fees/commissions
        side (int): Trade side: 0=Buy, 1=Sell
        size (int): Number of contracts traded
        voided (bool): Whether the trade was voided/cancelled
        orderId (int): ID of the order that generated this trade

    Note:
        A profitAndLoss value of None indicates a "half-turn" trade, meaning
        this trade opened or added to a position rather than closing it.

    Example:
        >>> side_str = "Buy" if trade.side == 0 else "Sell"
        >>> pnl_str = f"${trade.profitAndLoss}" if trade.profitAndLoss else "Half-turn"
        >>> print(f"{side_str} {trade.size} @ ${trade.price} - P&L: {pnl_str}")
    )r+   r,   r-   feesr   r   priceprofitAndLossr1   r2   voidedr   r+   r,   r-   r   Nr   r   r1   r2   r   r   )
r   r   r   r   	__slots__r)   r   r   r   r    r!   r"   r#   r   r     sM    4I 	GNOL4<
K
I
ILLr"   r   c                       e Zd ZU dZeed<   edz  ed<   edz  ed<   edz  ed<   eed<   eed<   eed	<   d
ed<   d
ed<   d
ed<   edz  ed<   y)r   aP  
    Response from placing a bracket order with entry, stop loss, and take profit.

    Attributes:
        success (bool): Whether the bracket order was successfully placed
        entry_order_id (Optional[int]): ID of the entry order
        stop_order_id (Optional[int]): ID of the stop loss order
        target_order_id (Optional[int]): ID of the take profit order
        entry_price (float): Entry price used
        stop_loss_price (float): Stop loss price used
        take_profit_price (float): Take profit price used
        entry_response (OrderPlaceResponse): Response from entry order
        stop_response (Optional[OrderPlaceResponse]): Response from stop loss order
        target_response (Optional[OrderPlaceResponse]): Response from take profit order
        error_message (Optional[str]): Error message if bracket order failed

    Example:
        >>> if response.success:
        ...     print(f"Bracket order placed successfully:")
        ...     print(f"  Entry: {response.entry_order_id} @ ${response.entry_price}")
        ...     print(f"  Stop: {response.stop_order_id} @ ${response.stop_loss_price}")
        ...     print(
        ...         f"  Target: {response.target_order_id} @ ${response.take_profit_price}"
        ...     )
        ... else:
        ...     print(f"Bracket order failed: {response.error_message}")
    r   Nentry_order_idstop_order_idtarget_order_identry_pricestop_loss_pricetake_profit_pricezOrderPlaceResponse | Noneentry_responsestop_responsetarget_responseerror_message)	r   r   r   r   r    r   r)   r   r   r!   r"   r#   r   r     sZ    8 M$J:4Z//..00:r"   r   c                       e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	eed	<   d
Z
eed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   y)r   a  
    Configuration settings for the ProjectX client.

    Default URLs are set for TopStepX endpoints. For custom ProjectX endpoints,
    update the URLs accordingly using create_custom_config() or direct assignment.

    TopStepX (Default):
    - user_hub_url: "https://rtc.topstepx.com/hubs/user"
    - market_hub_url: "https://rtc.topstepx.com/hubs/market"

    Attributes:
        api_url (str): Base URL for the API endpoints
        realtime_url (str): URL for real-time WebSocket connections
        user_hub_url (str): URL for user hub WebSocket (accounts, positions, orders)
        market_hub_url (str): URL for market hub WebSocket (quotes, trades, depth)
        timezone (str): Timezone for timestamp handling
        timeout_seconds (int): Request timeout in seconds
        retry_attempts (int): Number of retry attempts for failed requests
        retry_delay_seconds (float): Delay between retry attempts
        requests_per_minute (int): Rate limiting - requests per minute
        burst_limit (int): Rate limiting - burst limit
    zhttps://api.topstepx.com/apiapi_urlzwss://realtime.topstepx.com/apirealtime_urlz"https://rtc.topstepx.com/hubs/useruser_hub_urlz$https://rtc.topstepx.com/hubs/marketmarket_hub_urlzAmerica/Chicagotimezone   timeout_secondsrD   retry_attemptsg       @retry_delay_seconds<   requests_per_minute
   burst_limitN)r   r   r   r   r   r   r   r   r   r   r   r   r)   r   r   r   r   r   r!   r"   r#   r   r   G  so    . 2GS19L#9<L#<@NC@%Hc%OSNC!$$!!Kr"   r   c                   <    e Zd ZU eed<   eed<   edz  ed<   eed<   y)r   r   r/   Nr3   r.   )r   r   r   r)   r   r   r!   r"   r#   r   r   l  s    LKd
r"   r   c                   @    e Zd ZU eed<   eed<   eed<   eed<   eed<   y)r   
positionIdr,   r2   r   r.   N)r   r   r   r)   r   r   r   r!   r"   r#   r   r   t  s    OO
Ir"   r   c                   \    e Zd ZU eed<   eed<   edz  ed<   edz  ed<   edz  ed<   eed<   y)r	   r,   	lastPriceNbidaskvolume	timestamp)r   r   r   r   r   r   r)   r!   r"   r#   r	   r	   }  s0    O		$JNr"   r	   N)r   dataclassesr   typingr   r   __all__r   r   r
   r   r   r   r   r   r   r   r	   r!   r"   r#   <module>r      s>  pd "       8   4 J J JZ   . } } }@ 3 3 3l ' ' 'V ! ! !H         r"   