Models & Exceptions
Data models and exception classes used throughout the project-x-py package.
Core Models
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.MGC.M25”, name=”MGCH25”, description=”Mini Gold Futures March 2025”, tickSize=0.1, tickValue=1.0, activeContract=True,
)
# Create order model order = Order(
id=12345, accountId=1001, contractId=”CON.F.US.MGC.M25”, 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.MGC.M25”, 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
- class Account(id, name, balance, canTrade, isVisible, simulated)[source]
Bases:
object
Represents a trading account with balance and permissions.
- id
Unique account identifier
- Type:
- name
Account name/label
- Type:
- balance
Current account balance in dollars
- Type:
- canTrade
Whether trading is enabled for this account
- Type:
- isVisible
Whether the account is visible in the interface
- Type:
- simulated
Whether this is a simulated/demo account
- Type:
Example
>>> print(f"Account: {account.name}") >>> print(f"Balance: ${account.balance:,.2f}") >>> print(f"Trading enabled: {account.canTrade}")
-
id:
int
-
name:
str
-
balance:
float
-
canTrade:
bool
-
isVisible:
bool
-
simulated:
bool
- __init__(id, name, balance, canTrade, isVisible, simulated)
- class BracketOrderResponse(success, entry_order_id, stop_order_id, target_order_id, entry_price, stop_loss_price, take_profit_price, entry_response, stop_response, target_response, error_message)[source]
Bases:
object
Response from placing a bracket order with entry, stop loss, and take profit.
- success
Whether the bracket order was successfully placed
- Type:
- entry_order_id
ID of the entry order
- Type:
Optional[int]
- stop_order_id
ID of the stop loss order
- Type:
Optional[int]
- target_order_id
ID of the take profit order
- Type:
Optional[int]
- entry_price
Entry price used
- Type:
- stop_loss_price
Stop loss price used
- Type:
- take_profit_price
Take profit price used
- Type:
- entry_response
Response from entry order
- Type:
- stop_response
Response from stop loss order
- Type:
Optional[OrderPlaceResponse]
- target_response
Response from take profit order
- Type:
Optional[OrderPlaceResponse]
- error_message
Error message if bracket order failed
- Type:
Optional[str]
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}")
-
success:
bool
-
entry_price:
float
-
stop_loss_price:
float
-
take_profit_price:
float
-
entry_response:
OrderPlaceResponse
|None
-
stop_response:
OrderPlaceResponse
|None
-
target_response:
OrderPlaceResponse
|None
- __init__(success, entry_order_id, stop_order_id, target_order_id, entry_price, stop_loss_price, take_profit_price, entry_response, stop_response, target_response, error_message)
- class Instrument(id, name, description, tickSize, tickValue, activeContract, symbolId=None)[source]
Bases:
object
Represents a tradeable financial instrument/contract.
- id
Unique contract identifier used in API calls
- Type:
- name
Contract name/symbol (e.g., “MGCH25”)
- Type:
- description
Human-readable description of the contract
- Type:
- tickSize
Minimum price movement (e.g., 0.1)
- Type:
- tickValue
Dollar value per tick movement
- Type:
- activeContract
Whether the contract is currently active for trading
- Type:
Example
>>> print(f"Trading {instrument.name}") >>> print( ... f"Tick size: ${instrument.tickSize}, Tick value: ${instrument.tickValue}" ... )
-
id:
str
-
name:
str
-
description:
str
-
tickSize:
float
-
tickValue:
float
-
activeContract:
bool
- __init__(id, name, description, tickSize, tickValue, activeContract, symbolId=None)
- class MarketDataEvent(contractId, lastPrice, bid, ask, volume, timestamp)[source]
Bases:
object
-
contractId:
str
-
lastPrice:
float
-
timestamp:
str
- __init__(contractId, lastPrice, bid, ask, volume, timestamp)
-
contractId:
- class Order(id, accountId, contractId, creationTimestamp, updateTimestamp, status, type, side, size, symbolId=None, fillVolume=None, limitPrice=None, stopPrice=None, filledPrice=None, customTag=None)[source]
Bases:
object
Represents a trading order with all its details.
- id
Unique order identifier
- Type:
- accountId
Account that placed the order
- Type:
- contractId
Contract being traded
- Type:
- symbolId
Symbol ID corresponding to the contract
- Type:
Optional[str]
- creationTimestamp
When the order was created (ISO format)
- Type:
- updateTimestamp
When the order was last updated
- Type:
Optional[str]
- status
Order status code (OrderStatus enum): 0=None, 1=Open, 2=Filled, 3=Cancelled, 4=Expired, 5=Rejected, 6=Pending
- Type:
- type
Order type (OrderType enum): 0=Unknown, 1=Limit, 2=Market, 3=StopLimit, 4=Stop, 5=TrailingStop, 6=JoinBid, 7=JoinAsk
- Type:
- side
Order side (OrderSide enum): 0=Bid, 1=Ask
- Type:
- size
Number of contracts
- Type:
- fillVolume
Number of contracts filled (partial fills)
- Type:
Optional[int]
- limitPrice
Limit price (for limit orders)
- Type:
Optional[float]
- stopPrice
Stop price (for stop orders)
- Type:
Optional[float]
- filledPrice
The price at which the order was filled, if any
- Type:
Optional[float]
- customTag
Custom tag associated with the order, if any
- Type:
Optional[str]
Example
>>> side_str = "Bid" if order.side == 0 else "Ask" >>> print(f"Order {order.id}: {side_str} {order.size} {order.contractId}")
-
id:
int
-
accountId:
int
-
contractId:
str
-
creationTimestamp:
str
-
status:
int
-
type:
int
-
side:
int
-
size:
int
- property is_open: bool
Check if order is still open.
- property is_filled: bool
Check if order is completely filled.
- property is_cancelled: bool
Check if order was cancelled.
- property is_rejected: bool
Check if order was rejected.
- property is_working: bool
Check if order is working (open or pending).
- property is_terminal: bool
Check if order is in a terminal state.
- property is_buy: bool
Check if this is a buy order.
- property is_sell: bool
Check if this is a sell order.
- property side_str: str
Get order side as string.
- property type_str: str
Get order type as string.
- property status_str: str
Get order status as string.
- property filled_percent: float
Get percentage of order that has been filled.
- property remaining_size: int
Get remaining unfilled size.
- property symbol: str
Extract symbol from contract ID.
- __init__(id, accountId, contractId, creationTimestamp, updateTimestamp, status, type, side, size, symbolId=None, fillVolume=None, limitPrice=None, stopPrice=None, filledPrice=None, customTag=None)
- class OrderPlaceResponse(orderId, success, errorCode, errorMessage)[source]
Bases:
object
Response from placing an order.
- orderId
ID of the newly created order
- Type:
- success
Whether the order placement was successful
- Type:
- errorCode
Error code (0 = success)
- Type:
- errorMessage
Error message if placement failed
- Type:
Optional[str]
Example
>>> if response.success: ... print(f"Order placed successfully with ID: {response.orderId}") ... else: ... print(f"Order failed: {response.errorMessage}")
-
orderId:
int
-
success:
bool
-
errorCode:
int
- __init__(orderId, success, errorCode, errorMessage)
- class OrderUpdateEvent(orderId, status, fillVolume, updateTimestamp)[source]
Bases:
object
-
orderId:
int
-
status:
int
-
updateTimestamp:
str
- __init__(orderId, status, fillVolume, updateTimestamp)
-
orderId:
- class Position(id, accountId, contractId, creationTimestamp, type, size, averagePrice)[source]
Bases:
object
Represents an open trading position.
- id
Unique position identifier
- Type:
- accountId
Account holding the position
- Type:
- contractId
Contract of the position
- Type:
- creationTimestamp
When the position was opened (ISO format)
- Type:
- type
Position type code (PositionType enum): 0=UNDEFINED, 1=LONG, 2=SHORT
- Type:
- size
Position size (number of contracts, always positive)
- Type:
- averagePrice
Average entry price of the position
- Type:
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}" ... )
-
id:
int
-
accountId:
int
-
contractId:
str
-
creationTimestamp:
str
-
type:
int
-
size:
int
-
averagePrice:
float
- property is_long: bool
Check if this is a long position.
- property is_short: bool
Check if this is a short position.
- property direction: str
Get position direction as string.
- property symbol: str
Extract symbol from contract ID (e.g., ‘MNQ’ from ‘CON.F.US.MNQ.H25’).
- property signed_size: int
Get size with sign (negative for short positions).
- property total_cost: float
Calculate total position cost.
- unrealized_pnl(current_price, tick_value=1.0)[source]
Calculate unrealized P&L given current price.
- __init__(id, accountId, contractId, creationTimestamp, type, size, averagePrice)
- class PositionUpdateEvent(positionId, contractId, size, averagePrice, updateTimestamp)[source]
Bases:
object
-
positionId:
int
-
contractId:
str
-
size:
int
-
averagePrice:
float
-
updateTimestamp:
str
- __init__(positionId, contractId, size, averagePrice, updateTimestamp)
-
positionId:
- class ProjectXConfig(api_url='https://api.topstepx.com/api', realtime_url='wss://realtime.topstepx.com/api', user_hub_url='https://rtc.topstepx.com/hubs/user', market_hub_url='https://rtc.topstepx.com/hubs/market', timezone='America/Chicago', timeout_seconds=30, retry_attempts=3, retry_delay_seconds=2.0, requests_per_minute=60, burst_limit=10)[source]
Bases:
object
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”
- api_url
Base URL for the API endpoints
- Type:
- realtime_url
URL for real-time WebSocket connections
- Type:
- user_hub_url
URL for user hub WebSocket (accounts, positions, orders)
- Type:
- market_hub_url
URL for market hub WebSocket (quotes, trades, depth)
- Type:
- timezone
Timezone for timestamp handling
- Type:
- timeout_seconds
Request timeout in seconds
- Type:
- retry_attempts
Number of retry attempts for failed requests
- Type:
- retry_delay_seconds
Delay between retry attempts
- Type:
- requests_per_minute
Rate limiting - requests per minute
- Type:
- burst_limit
Rate limiting - burst limit
- Type:
-
api_url:
str
= 'https://api.topstepx.com/api'
-
realtime_url:
str
= 'wss://realtime.topstepx.com/api'
-
user_hub_url:
str
= 'https://rtc.topstepx.com/hubs/user'
-
market_hub_url:
str
= 'https://rtc.topstepx.com/hubs/market'
-
timezone:
str
= 'America/Chicago'
-
timeout_seconds:
int
= 30
-
retry_attempts:
int
= 3
-
retry_delay_seconds:
float
= 2.0
-
requests_per_minute:
int
= 60
-
burst_limit:
int
= 10
- __init__(api_url='https://api.topstepx.com/api', realtime_url='wss://realtime.topstepx.com/api', user_hub_url='https://rtc.topstepx.com/hubs/user', market_hub_url='https://rtc.topstepx.com/hubs/market', timezone='America/Chicago', timeout_seconds=30, retry_attempts=3, retry_delay_seconds=2.0, requests_per_minute=60, burst_limit=10)
- class Trade(id, accountId, contractId, creationTimestamp, price, profitAndLoss, fees, side, size, voided, orderId)[source]
Bases:
object
Represents an executed trade with P&L information.
- id
Unique trade identifier
- Type:
- accountId
Account that executed the trade
- Type:
- contractId
Contract that was traded
- Type:
- creationTimestamp
When the trade was executed (ISO format)
- Type:
- price
Execution price
- Type:
- profitAndLoss
Realized P&L (None for half-turn trades)
- Type:
Optional[float]
- fees
Trading fees/commissions
- Type:
- side
Trade side: 0=Buy, 1=Sell
- Type:
- size
Number of contracts traded
- Type:
- voided
Whether the trade was voided/cancelled
- Type:
- orderId
ID of the order that generated this trade
- Type:
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}")
-
id:
int
-
accountId:
int
-
contractId:
str
-
creationTimestamp:
str
-
price:
float
-
fees:
float
-
side:
int
-
size:
int
-
voided:
bool
-
orderId:
int
- __init__(id, accountId, contractId, creationTimestamp, price, profitAndLoss, fees, side, size, voided, orderId)
Configuration
- class ProjectXConfig(api_url='https://api.topstepx.com/api', realtime_url='wss://realtime.topstepx.com/api', user_hub_url='https://rtc.topstepx.com/hubs/user', market_hub_url='https://rtc.topstepx.com/hubs/market', timezone='America/Chicago', timeout_seconds=30, retry_attempts=3, retry_delay_seconds=2.0, requests_per_minute=60, burst_limit=10)[source]
Bases:
object
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”
- __init__(api_url='https://api.topstepx.com/api', realtime_url='wss://realtime.topstepx.com/api', user_hub_url='https://rtc.topstepx.com/hubs/user', market_hub_url='https://rtc.topstepx.com/hubs/market', timezone='America/Chicago', timeout_seconds=30, retry_attempts=3, retry_delay_seconds=2.0, requests_per_minute=60, burst_limit=10)
Client Models
- class Account(id, name, balance, canTrade, isVisible, simulated)[source]
Bases:
object
Represents a trading account with balance and permissions.
Example
>>> print(f"Account: {account.name}") >>> print(f"Balance: ${account.balance:,.2f}") >>> print(f"Trading enabled: {account.canTrade}")
- __init__(id, name, balance, canTrade, isVisible, simulated)
- class Instrument(id, name, description, tickSize, tickValue, activeContract, symbolId=None)[source]
Bases:
object
Represents a tradeable financial instrument/contract.
Example
>>> print(f"Trading {instrument.name}") >>> print( ... f"Tick size: ${instrument.tickSize}, Tick value: ${instrument.tickValue}" ... )
- __init__(id, name, description, tickSize, tickValue, activeContract, symbolId=None)
Trading Models
- class Order(id, accountId, contractId, creationTimestamp, updateTimestamp, status, type, side, size, symbolId=None, fillVolume=None, limitPrice=None, stopPrice=None, filledPrice=None, customTag=None)[source]
Bases:
object
Represents a trading order with all its details.
- status
Order status code (OrderStatus enum): 0=None, 1=Open, 2=Filled, 3=Cancelled, 4=Expired, 5=Rejected, 6=Pending
- Type:
- type
Order type (OrderType enum): 0=Unknown, 1=Limit, 2=Market, 3=StopLimit, 4=Stop, 5=TrailingStop, 6=JoinBid, 7=JoinAsk
- Type:
Example
>>> side_str = "Bid" if order.side == 0 else "Ask" >>> print(f"Order {order.id}: {side_str} {order.size} {order.contractId}")
- __init__(id, accountId, contractId, creationTimestamp, updateTimestamp, status, type, side, size, symbolId=None, fillVolume=None, limitPrice=None, stopPrice=None, filledPrice=None, customTag=None)
- class OrderPlaceResponse(orderId, success, errorCode, errorMessage)[source]
Bases:
object
Response from placing an order.
Example
>>> if response.success: ... print(f"Order placed successfully with ID: {response.orderId}") ... else: ... print(f"Order failed: {response.errorMessage}")
- __init__(orderId, success, errorCode, errorMessage)
- class BracketOrderResponse(success, entry_order_id, stop_order_id, target_order_id, entry_price, stop_loss_price, take_profit_price, entry_response, stop_response, target_response, error_message)[source]
Bases:
object
Response from placing a bracket order with entry, stop loss, and take profit.
- entry_response
Response from entry order
- Type:
- stop_response
Response from stop loss order
- Type:
Optional[OrderPlaceResponse]
- target_response
Response from take profit order
- Type:
Optional[OrderPlaceResponse]
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}")
-
entry_response:
OrderPlaceResponse
|None
-
stop_response:
OrderPlaceResponse
|None
-
target_response:
OrderPlaceResponse
|None
- __init__(success, entry_order_id, stop_order_id, target_order_id, entry_price, stop_loss_price, take_profit_price, entry_response, stop_response, target_response, error_message)
- class Position(id, accountId, contractId, creationTimestamp, type, size, averagePrice)[source]
Bases:
object
Represents an open trading 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}" ... )
- unrealized_pnl(current_price, tick_value=1.0)[source]
Calculate unrealized P&L given current price.
- __init__(id, accountId, contractId, creationTimestamp, type, size, averagePrice)
- class Trade(id, accountId, contractId, creationTimestamp, price, profitAndLoss, fees, side, size, voided, orderId)[source]
Bases:
object
Represents an executed trade with P&L information.
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}")
- __init__(id, accountId, contractId, creationTimestamp, price, profitAndLoss, fees, side, size, voided, orderId)
Exception Classes
Base Exception
API Exceptions
- class ProjectXConnectionError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Connection and network errors.
- class ProjectXAuthenticationError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Authentication-related errors.
- class ProjectXServerError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Server-side errors (5xx).
- class ProjectXRateLimitError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Rate limiting errors.
Data Exceptions
- class ProjectXDataError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Data validation and processing errors.
- class ProjectXInstrumentError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Instrument-related errors.
Trading Exceptions
- class ProjectXOrderError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Order placement and management errors.
- class ProjectXPositionError(message, error_code=None, response_data=None)[source]
Bases:
ProjectXError
Position management errors.