Trading Suite Guide¶
The TradingSuite is the recommended entry point for building trading applications with the ProjectX SDK. In v3.5.0, it has been revolutionized with multi-instrument support, enabling simultaneous management of multiple futures contracts while maintaining full backward compatibility. It provides a unified interface that combines all components (client, order management, position tracking, real-time data, and optional features) into a single, easy-to-use container.
Why Use TradingSuite?¶
The TradingSuite simplifies SDK usage by:
- One-line initialization - No complex setup or dependency management
- Multi-instrument support (v3.5.0) - Manage multiple contracts simultaneously
- Automatic component wiring - All components work together seamlessly
- Built-in configuration - Sensible defaults with easy customization
- Feature flags - Enable only what you need
- Unified event system - Single place to handle all trading events
- Dictionary-like access - Intuitive
suite["SYMBOL"]
syntax - Event isolation - Proper separation between instruments
- Parallel processing - Efficient concurrent operations
Quick Start¶
Single Instrument Setup (Backward Compatible)¶
import asyncio
from project_x_py import TradingSuite
async def main():
# Traditional single instrument (still supported)
suite = await TradingSuite.create(["MNQ"]) # List notation recommended
mnq = suite["MNQ"] # Access instrument context
# Everything is ready:
# - Client authenticated
# - Real-time data connected
# - Order and position managers initialized
# Get current price
price = await mnq.data.get_current_price()
print(f"MNQ Current Price: ${price:.2f}")
# Clean shutdown
await suite.disconnect()
asyncio.run(main())
Multi-Instrument Setup (v3.5.0 New)¶
import asyncio
from project_x_py import TradingSuite
async def multi_instrument_main():
# Revolutionary multi-instrument support
suite = await TradingSuite.create(
instruments=["MNQ", "ES", "MGC"], # Multiple futures
timeframes=["1min", "5min"],
features=["orderbook", "risk_manager"],
)
print(f"Managing {len(suite)} instruments: {list(suite.keys())}")
# Dictionary-like access to each instrument
mnq_context = suite["MNQ"]
es_context = suite["ES"]
mgc_context = suite["MGC"]
# Get prices for all instruments
for symbol, context in suite.items():
price = await context.data.get_current_price()
print(f"{symbol}: ${price:.2f}")
await suite.disconnect()
asyncio.run(multi_instrument_main())
Multi-Timeframe Setup¶
import asyncio
from project_x_py import TradingSuite
async def main():
await multi_timeframe_setup()
await multi_instrument_timeframes()
async def multi_timeframe_setup():
# Setup with multiple timeframes for analysis
suite = await TradingSuite.create(
["MNQ"], # Single instrument with multiple timeframes
timeframes=["1min", "5min", "15min"],
initial_days=10, # Load 10 days of historical data
)
mnq = suite["MNQ"]
# Access different timeframe data
bars_1min = await mnq.data.get_data("1min")
bars_5min = await mnq.data.get_data("5min")
bars_15min = await mnq.data.get_data("15min")
if bars_1min is None or bars_5min is None or bars_15min is None:
raise Exception("No data available")
print(f"MNQ 1min bars: {len(bars_1min)}")
print(f"MNQ 5min bars: {len(bars_5min)}")
print(f"MNQ 15min bars: {len(bars_15min)}")
await suite.disconnect()
# Multi-instrument with multiple timeframes
async def multi_instrument_timeframes():
suite = await TradingSuite.create(
["MNQ", "ES"], # List of instruments
timeframes=["1min", "5min", "15min"],
)
# Each instrument has all timeframes available
for symbol, context in suite.items():
bars_1min = await context.data.get_data("1min")
bars_5min = await context.data.get_data("5min")
bars_15min = await context.data.get_data("15min")
if bars_1min is None or bars_5min is None or bars_15min is None:
raise Exception("No data available")
print(f"{symbol} 1min bars: {len(bars_1min)}")
print(f"{symbol} 5min bars: {len(bars_5min)}")
print(f"{symbol} 15min bars: {len(bars_15min)}")
await suite.disconnect()
asyncio.run(main())
Multi-Instrument with Optional Features¶
import asyncio
from project_x_py import TradingSuite
from project_x_py.trading_suite import Features
async def feature_setup():
# Enable optional features for multiple instruments
suite = await TradingSuite.create(
["MNQ", "MES"], # List of instruments
timeframes=["1min", "5min"],
features=[Features.ORDERBOOK, Features.RISK_MANAGER],
)
# Wait for 120 seconds to ensure features are initialized
await asyncio.sleep(20)
# Each instrument has its own feature instances
total_exposure = 0.0
for symbol, context in suite.items():
print(f"\n{symbol} Features:")
# Level 2 order book data (per instrument)
if context.orderbook:
snapshot = await context.orderbook.get_orderbook_snapshot()
print(snapshot)
print(
f" Order book depth: {len(snapshot['bids'])} bids, {len(snapshot['asks'])} asks"
)
# Risk management tools (per instrument)
if context.risk_manager:
# Access risk configuration
config = context.risk_manager.config
print(f" Max position size: {config.max_position_size}")
# Get current risk metrics
metrics = await context.risk_manager.get_risk_metrics()
print(f" Current risk: ${metrics['current_risk']:,.2f}")
print(f" Margin used: ${metrics['margin_used']:,.2f}")
total_exposure += metrics["margin_used"]
# Portfolio-level risk summary
print(f"\nTotal Portfolio Exposure: ${total_exposure:,.2f}")
await suite.disconnect()
asyncio.run(feature_setup())
Configuration Options¶
Basic Configuration¶
from project_x_py import TradingSuite
async def basic_config():
suite = await TradingSuite.create(
"ES", # E-mini S&P 500 (positional argument)
timeframes=["5min"], # Single timeframe
initial_days=5, # 5 days of history
timezone="America/New_York", # Eastern timezone
auto_connect=True # Auto-connect (default)
)
await suite.disconnect()
Advanced Configuration¶
from project_x_py.types import (
OrderManagerConfig,
PositionManagerConfig,
DataManagerConfig
)
async def advanced_config():
# Custom component configurations
order_config = OrderManagerConfig(
max_concurrent_orders=5,
default_timeout=60.0,
retry_attempts=3
)
position_config = PositionManagerConfig(
track_unrealized=True,
calculate_metrics=True,
update_frequency=2.0 # Update every 2 seconds
)
data_config = DataManagerConfig(
max_bars_per_timeframe=2000,
enable_tick_data=True,
data_validation=True
)
suite = await TradingSuite.create(
"MNQ", # Positional argument
timeframes=["1min", "5min"],
features=["orderbook"],
order_manager_config=order_config,
position_manager_config=position_config,
data_manager_config=data_config
)
await suite.disconnect()
Configuration from File¶
Create a configuration file:
# config/trading.yaml
instrument: "MNQ"
timeframes:
- "1min"
- "5min"
- "15min"
features:
- "orderbook"
- "risk_manager"
initial_days: 7
timezone: "America/Chicago"
order_manager:
max_concurrent_orders: 10
default_timeout: 30.0
position_manager:
track_unrealized: true
calculate_metrics: true
data_manager:
max_bars_per_timeframe: 1500
enable_tick_data: true
Load from configuration:
async def config_from_file():
# Load configuration from YAML file
suite = await TradingSuite.from_config("config/trading.yaml")
# Or from dictionary
config_dict = {
"instrument": "MNQ",
"timeframes": ["1min", "5min"],
"features": ["orderbook"]
}
suite = await TradingSuite.from_dict(config_dict)
await suite.disconnect()
Core Components¶
Client Access¶
async def client_access():
suite = await TradingSuite.create("MNQ")
# Access the underlying ProjectX client
client = suite.client
# Get account information
account = await client.get_account_info()
print(f"Account Balance: ${account.balance:,.2f}")
# Get historical data via client
historical_bars = await client.get_bars("MNQ", days=30, interval=300)
print(f"Historical bars: {len(historical_bars)}")
await suite.disconnect()
Order Management¶
Single Instrument Order Management¶
async def order_management():
suite = await TradingSuite.create(["MNQ"])
mnq = suite["MNQ"]
# Access the integrated order manager for MNQ
orders = mnq.orders
# Place different order types
market_order = await orders.place_market_order(
contract_id=mnq.instrument_id,
side=0, # Buy
size=1
)
limit_order = await orders.place_limit_order(
contract_id=mnq.instrument_id,
side=0, # Buy
size=1,
limit_price=21000.0
)
# Advanced bracket order
bracket_order = await orders.place_bracket_order(
contract_id=mnq.instrument_id,
side=0, # Buy
size=1,
entry_price=21050.0,
stop_offset=25.0, # $25 stop loss
target_offset=50.0 # $50 profit target
)
print(f"MNQ Bracket order placed: {bracket_order.main_order_id}")
await suite.disconnect()
Multi-Instrument Order Management¶
async def multi_instrument_orders():
suite = await TradingSuite.create(["MNQ", "ES", "MGC"])
# Place orders across multiple instruments
tasks = []
# ES long position
es_task = suite["ES"].orders.place_limit_order(
contract_id=suite["ES"].instrument_id,
side=0, size=1, limit_price=5100.0
)
tasks.append(es_task)
# MNQ short position
mnq_task = suite["MNQ"].orders.place_limit_order(
contract_id=suite["MNQ"].instrument_id,
side=1, size=1, limit_price=21100.0
)
tasks.append(mnq_task)
# Execute all orders concurrently
results = await asyncio.gather(*tasks, return_exceptions=True)
for i, result in enumerate(results):
symbol = ["ES", "MNQ"][i]
if isinstance(result, Exception):
print(f"{symbol} order failed: {result}")
else:
print(f"{symbol} order placed: {result.order_id}")
await suite.disconnect()
Position Tracking¶
Single Instrument Position Tracking¶
async def position_tracking():
suite = await TradingSuite.create(["MNQ"])
mnq = suite["MNQ"]
# Access the integrated position manager for MNQ
positions = mnq.positions
# Get current position
position = await positions.get_position("MNQ")
if position:
print(f"MNQ Position:")
print(f" Size: {position.size}")
print(f" Avg Price: ${position.avg_price:.2f}")
print(f" Unrealized P&L: ${position.unrealized_pnl:.2f}")
await suite.disconnect()
Multi-Instrument Portfolio Tracking¶
async def portfolio_tracking():
suite = await TradingSuite.create(["MNQ", "ES", "MGC"])
# Track positions across all instruments
portfolio_value = 0
total_pnl = 0
print("Portfolio Positions:")
for symbol, context in suite.items():
position = await context.positions.get_position(symbol)
if position:
print(f" {symbol}: {position.size} @ ${position.avg_price:.2f} (P&L: ${position.unrealized_pnl:.2f})")
portfolio_value += abs(position.size * position.avg_price)
total_pnl += position.unrealized_pnl
else:
print(f" {symbol}: No position")
print(f"\nPortfolio Summary:")
print(f" Total Value: ${portfolio_value:,.2f}")
print(f" Total P&L: ${total_pnl:.2f}")
# Portfolio-level metrics
portfolio_metrics = await suite.get_portfolio_metrics()
print(f" Diversification Score: {portfolio_metrics.get('diversification_score', 0):.2f}")
print(f" Risk Score: {portfolio_metrics.get('risk_score', 0):.2f}")
await suite.disconnect()
Real-time Data¶
Single Instrument Real-time Data¶
async def realtime_data():
suite = await TradingSuite.create(["MNQ"], timeframes=["1min", "5min"])
mnq = suite["MNQ"]
# Access the real-time data manager for MNQ
data = mnq.data
# Get current price
current_price = await data.get_current_price()
print(f"MNQ Current Price: ${current_price:.2f}")
# Get latest bars
latest_1min = await data.get_data("1min", count=10) # Last 10 1-min bars
latest_5min = await data.get_data("5min", count=5) # Last 5 5-min bars
print(f"MNQ Latest 1min bars: {len(latest_1min)}")
print(f"MNQ Latest 5min bars: {len(latest_5min)}")
await suite.disconnect()
Multi-Instrument Real-time Data¶
async def multi_realtime_data():
suite = await TradingSuite.create(
instruments=["MNQ", "ES", "MGC"],
timeframes=["1min", "5min"]
)
# Get current prices for all instruments
print("Current Prices:")
for symbol, context in suite.items():
current_price = await context.data.get_current_price()
print(f" {symbol}: ${current_price:.2f}")
# Get latest 5min bars for all instruments
print("\nLatest 5min Data:")
for symbol, context in suite.items():
latest_5min = await context.data.get_data("5min", count=1)
if len(latest_5min) > 0:
latest_bar = latest_5min.tail(1)
close_price = latest_bar["close"].item()
volume = latest_bar["volume"].item()
print(f" {symbol}: Close ${close_price:.2f}, Volume {volume:,}")
await suite.disconnect()
Optional Features¶
OrderBook (Level 2 Data)¶
from project_x_py import Features
async def orderbook_feature():
suite = await TradingSuite.create(
"MNQ",
features=[Features.ORDERBOOK]
)
# Access Level 2 order book
if suite.orderbook:
depth = await suite.orderbook.get_depth()
trades = await suite.orderbook.get_recent_trades()
print(f"Order Book:")
print(f" Best Bid: ${depth.best_bid:.2f}")
print(f" Best Ask: ${depth.best_ask:.2f}")
print(f" Spread: ${depth.spread:.2f}")
print(f" Recent Trades: {len(trades)}")
# Get market microstructure data
microstructure = await suite.orderbook.get_microstructure_analysis()
print(f" Order Flow Imbalance: {microstructure.order_flow_imbalance:.2f}")
await suite.disconnect()
Risk Manager¶
async def risk_manager_feature():
suite = await TradingSuite.create(
"MNQ",
features=[Features.RISK_MANAGER]
)
# Access risk management tools
if suite.risk_manager:
# Get risk limits
limits = await suite.risk_manager.get_limits()
print(f"Risk Limits:")
print(f" Max Position Size: {limits.max_position_size}")
print(f" Max Daily Loss: ${limits.max_daily_loss:.2f}")
# Check if trade is allowed
trade_allowed = await suite.risk_manager.check_trade_allowed(
instrument="MNQ",
side=0, # Buy
size=2
)
print(f"Trade allowed: {trade_allowed}")
# Get current risk metrics
risk_metrics = await suite.risk_manager.get_risk_metrics()
print(f"Current Risk: ${risk_metrics.current_risk:.2f}")
await suite.disconnect()
Event Handling¶
Event System Architecture (v3.5.6+)¶
The event system in v3.5.6+ features automatic event forwarding from instrument-specific EventBuses to the suite-level EventBus, enabling flexible event handling patterns:
- Instrument-level events: Each instrument has its own EventBus for isolated event handling
- Suite-level events: All instrument events are forwarded to the suite EventBus for unified handling
- Event methods on InstrumentContext: Direct access to
on()
,once()
,off()
, andwait_for()
methods
Setting Up Event Handlers¶
Single Instrument Event Handling¶
from project_x_py import EventType
async def event_handling():
suite = await TradingSuite.create(["MNQ"], timeframes=["1min"])
mnq = suite["MNQ"]
# Define event handlers for MNQ
async def on_new_bar(event):
print(f"MNQ New {event.timeframe} bar:")
print(f" Close: ${event.data.close:.2f}")
print(f" Volume: {event.data.volume:,}")
async def on_order_filled(event):
print(f"MNQ Order filled: {event.order_id}")
print(f" Price: ${event.fill_price:.2f}")
print(f" Quantity: {event.fill_quantity}")
async def on_position_changed(event):
position = event.data
print(f"MNQ Position changed:")
print(f" New size: {position.size}")
print(f" Unrealized P&L: ${position.unrealized_pnl:.2f}")
# Register event handlers directly on instrument context (v3.5.6+)
await mnq.on(EventType.NEW_BAR, on_new_bar)
await mnq.on(EventType.ORDER_FILLED, on_order_filled)
await mnq.on(EventType.POSITION_CHANGED, on_position_changed)
# Or use wait_for for specific events (v3.5.6+)
new_bar_event = await mnq.wait_for(EventType.NEW_BAR)
# Keep the application running to receive events
await asyncio.sleep(300) # Run for 5 minutes
await suite.disconnect()
Multi-Instrument Event Handling¶
async def multi_instrument_events():
suite = await TradingSuite.create(
instruments=["MNQ", "ES", "MGC"],
timeframes=["1min", "5min"]
)
# Option 1: Register handlers on individual instruments
for symbol, context in suite.items():
# Create symbol-specific handlers using closures
def make_handlers(sym):
async def on_new_bar(event):
if event.timeframe == "5min": # Only 5min bars
print(f"{sym} 5min bar: ${event.data.close:.2f}")
async def on_order_filled(event):
print(f"{sym} Order filled: {event.order_id} @ ${event.fill_price:.2f}")
async def on_position_changed(event):
position = event.data
print(f"{sym} Position: {position.size} (P&L: ${position.unrealized_pnl:.2f})")
return on_new_bar, on_order_filled, on_position_changed
# Register handlers for this instrument (v3.5.6+ direct methods)
bar_handler, order_handler, position_handler = make_handlers(symbol)
await context.on(EventType.NEW_BAR, bar_handler)
await context.on(EventType.ORDER_FILLED, order_handler)
await context.on(EventType.POSITION_CHANGED, position_handler)
# Option 2: Register a single handler at suite level for all instruments (v3.5.6+)
async def unified_bar_handler(event):
# Events from all instruments are forwarded to suite EventBus
instrument = event.data.get("instrument", "Unknown")
print(f"{instrument} new bar: ${event.data.close:.2f}")
await suite.on(EventType.NEW_BAR, unified_bar_handler)
print("Monitoring events for all instruments...")
await asyncio.sleep(300) # Run for 5 minutes
await suite.disconnect()
Multiple Event Handlers¶
async def multiple_event_handlers():
suite = await TradingSuite.create("MNQ", timeframes=["1min", "5min"])
# Strategy event handler
async def strategy_handler(event):
if event.timeframe == "5min":
# Implement 5-minute strategy logic
pass
# Risk management event handler
async def risk_handler(event):
# Check risk on every position change
if hasattr(event, 'data') and hasattr(event.data, 'unrealized_pnl'):
if event.data.unrealized_pnl < -500: # $500 loss limit
print("Risk limit exceeded!")
# Logging event handler
async def log_handler(event):
print(f"Event: {event.event_type} at {event.timestamp}")
# Register multiple handlers for the same event
await suite.on(EventType.NEW_BAR, strategy_handler)
await suite.on(EventType.NEW_BAR, log_handler)
await suite.on(EventType.POSITION_CHANGED, risk_handler)
await asyncio.sleep(300)
await suite.disconnect()
Connection Management¶
Context Manager (Recommended)¶
async def context_manager_usage():
# Recommended: Use context manager for automatic cleanup
async with TradingSuite.create("MNQ") as suite:
# Suite is automatically connected on entry
current_price = await suite.data.get_current_price()
print(f"Current Price: ${current_price:.2f}")
# Place a trade
order = await suite.orders.place_market_order(
contract_id=suite.instrument_id,
side=0, # Buy
size=1
)
# Suite automatically disconnects on exit
Manual Connection Management¶
async def manual_connection_management():
suite = None
try:
# Create and connect manually
suite = await TradingSuite.create("MNQ")
# Check connection status
client_connected = await suite.client.is_connected()
realtime_connected = await suite.realtime.is_connected()
print(f"Client connected: {client_connected}")
print(f"Real-time connected: {realtime_connected}")
# Your trading logic here
finally:
if suite:
await suite.disconnect()
Reconnection Handling¶
async def reconnection_handling():
suite = await TradingSuite.create("MNQ", features=["auto_reconnect"])
# Monitor connection status
async def on_connection_status(event):
if event.status == "disconnected":
print("Connection lost - attempting reconnection...")
elif event.status == "reconnected":
print("Connection restored")
await suite.on(EventType.CONNECTION_STATUS_CHANGED, on_connection_status)
# Manual reconnection if needed
if not await suite.client.is_connected():
await suite.client.reconnect()
if not await suite.realtime.is_connected():
await suite.realtime.reconnect()
await suite.disconnect()
Statistics and Monitoring¶
Health Monitoring¶
async def health_monitoring():
suite = await TradingSuite.create("MNQ", features=["orderbook"])
# Get overall health score using HealthMonitor
from project_x_py.statistics.health import HealthMonitor
stats = await suite.get_stats()
monitor = HealthMonitor()
health_score = await monitor.calculate_health(stats)
print(f"System Health: {health_score:.1f}/100")
if health_score < 70:
# Get detailed health breakdown
breakdown = await monitor.get_health_breakdown(stats)
for category, score in breakdown.items():
if category not in ['overall_score', 'weighted_total'] and score < 70:
print(f" {category}: {score:.1f}/100")
await suite.disconnect()
Performance Statistics¶
async def performance_statistics():
suite = await TradingSuite.create("MNQ")
# Get comprehensive statistics
stats = await suite.get_stats()
print(f"TradingSuite Statistics:")
print(f" Total Operations: {stats.get('total_operations', 0):,}")
print(f" Total Errors: {stats.get('total_errors', 0)}")
print(f" Memory Usage: {stats.get('memory_usage_mb', 0):.1f} MB")
print(f" Component Count: {stats.get('components', 0)}")
# Component-specific statistics from MNQ context
mnq = suite["MNQ"]
order_stats = await mnq.orders.get_stats()
print(f"\nOrder Manager:")
print(f" Orders Placed: {order_stats.get('orders_placed', 0)}")
print(f" Orders Filled: {order_stats.get('orders_filled', 0)}")
print(f" Error Count: {order_stats.get('error_count', 0)}")
position_stats = await mnq.positions.get_stats()
print(f"\nPosition Manager:")
print(f" Positions Opened: {position_stats.get('positions_opened', 0)}")
print(f" Positions Closed: {position_stats.get('positions_closed', 0)}")
await suite.disconnect()
Statistics Export¶
async def statistics_export():
from project_x_py.statistics.export import StatsExporter
import json
suite = await TradingSuite.create("MNQ", features=["orderbook"])
# Get statistics and export in different formats
stats = await suite.get_stats()
exporter = StatsExporter()
# Prometheus format (for monitoring systems)
prometheus_metrics = await exporter.to_prometheus(stats)
with open("metrics.prom", "w") as f:
f.write(prometheus_metrics)
# CSV format (for analysis)
csv_data = await exporter.to_csv(stats, include_timestamp=True)
with open("trading_stats.csv", "w") as f:
f.write(csv_data)
# JSON format (for applications)
json_data = json.dumps(stats, indent=2)
with open("trading_stats.json", "w") as f:
f.write(json_data)
await suite.disconnect()
Complete Trading Example¶
Here's a complete example that demonstrates most TradingSuite features:
import asyncio
from project_x_py import TradingSuite, EventType
from project_x_py.indicators import RSI, SMA
from datetime import datetime
async def complete_trading_example():
"""Complete trading application using TradingSuite."""
# Setup with multiple features
suite = await TradingSuite.create(
"MNQ", # Positional argument
timeframes=["1min", "5min"],
features=["orderbook", "risk_manager"],
initial_days=5
)
print(f"Connected to {suite.instrument_info.description}")
print(f"Instrument ID: {suite.instrument_id}")
# Event handlers
async def on_new_bar(event):
"""Handle new bar data for strategy logic."""
if event.timeframe == "5min":
# Get recent data
bars = await suite.data.get_data("5min", count=50)
# Apply technical indicators
data_with_indicators = bars.pipe(RSI, period=14).pipe(SMA, period=20)
if len(data_with_indicators) > 20:
latest = data_with_indicators.tail(1)
rsi_value = latest["rsi_14"].item()
sma_value = latest["sma_20"].item()
close_price = latest["close"].item()
print(f"5min Bar - Close: ${close_price:.2f}, RSI: {rsi_value:.1f}, SMA: ${sma_value:.2f}")
# Simple RSI strategy
current_position = await suite.positions.get_position("MNQ")
current_size = current_position.size if current_position else 0
# Entry signals
if rsi_value < 30 and close_price < sma_value and current_size == 0:
print("= RSI Oversold + Below SMA - Going Long")
await suite.orders.place_bracket_order(
contract_id=suite.instrument_id,
side=0, # Buy
size=1,
entry_price=None, # Market order
stop_offset=25.0,
target_offset=50.0
)
elif rsi_value > 70 and close_price > sma_value and current_size == 0:
print("=4 RSI Overbought + Above SMA - Going Short")
await suite.orders.place_bracket_order(
contract_id=suite.instrument_id,
side=1, # Sell
size=1,
entry_price=None, # Market order
stop_offset=25.0,
target_offset=50.0
)
async def on_order_filled(event):
"""Handle order fills."""
print(f"Order {event.order_id} filled at ${event.fill_price:.2f}")
async def on_position_changed(event):
"""Handle position changes."""
position = event.data
print(f"= Position Update: {position.size} @ ${position.avg_price:.2f}, P&L: ${position.unrealized_pnl:.2f}")
# Register event handlers
await suite.on(EventType.NEW_BAR, on_new_bar)
await suite.on(EventType.ORDER_FILLED, on_order_filled)
await suite.on(EventType.POSITION_CHANGED, on_position_changed)
# Monitor for 10 minutes
print("= Starting trading strategy...")
start_time = datetime.now()
try:
while True:
await asyncio.sleep(30) # Check every 30 seconds
# Print status update
from project_x_py.statistics.health import HealthMonitor
current_price = await suite.data.get_current_price()
stats = await suite.get_stats()
monitor = HealthMonitor()
health_score = await monitor.calculate_health(stats)
print(f"= MNQ: ${current_price:.2f} | Health: {health_score:.0f}/100")
# Run for 10 minutes
if (datetime.now() - start_time).total_seconds() > 600:
break
except KeyboardInterrupt:
print("= Trading interrupted by user")
finally:
# Final status report
print("\n= Final Report:")
# Get final statistics
stats = await suite.get_stats()
print(f" Total Operations: {stats.get('total_operations', 0):,}")
print(f" Total Errors: {stats.get('total_errors', 0)}")
# Get final position
position = await suite.positions.get_position("MNQ")
if position:
print(f" Final Position: {position.size} contracts")
print(f" Unrealized P&L: ${position.unrealized_pnl:.2f}")
else:
print(" No open position")
# Cleanup
await suite.disconnect()
print("= Disconnected successfully")
# Run the example
if __name__ == "__main__":
asyncio.run(complete_trading_example())
Best Practices¶
Initialization¶
# Recommended: Use TradingSuite.create()
suite = await TradingSuite.create("MNQ", features=["orderbook"])
# Good: Use context manager for automatic cleanup
async with TradingSuite.create("MNQ") as suite:
# Trading operations
# L Not recommended: Manual component initialization
# client = ProjectX.from_env()
# orders = OrderManager(client) # Too complex, error-prone
Resource Management¶
# Good: Monitor resource usage
stats = await suite.get_stats()
if stats.get('memory_usage_mb', 0) > 100: # 100MB threshold
print("High memory usage - consider cleanup")
# Good: Use appropriate features
features = ["orderbook"] # Only what you need
suite = await TradingSuite.create("MNQ", features=features)
Error Handling¶
# Good: Handle connection errors
try:
suite = await TradingSuite.create("MNQ")
except ProjectXConnectionError:
print("Failed to connect - check network and credentials")
except Exception as e:
print(f"Unexpected error: {e}")
# Good: Check component availability
if suite.orderbook:
depth = await suite.orderbook.get_depth()
else:
print("OrderBook not enabled")
Performance¶
# Good: Use appropriate timeframes
await TradingSuite.create("MNQ", timeframes=["5min", "15min"]) # What you need
# L Wasteful: Too many timeframes
# await TradingSuite.create("MNQ", timeframes=["15sec", "30sec", "1min", "2min", "5min"])
# Good: Batch operations when possible
positions = await suite.positions.get_all_positions() # Single call
# vs multiple individual calls
Next Steps¶
- Learn about Order Management for detailed order handling
- Explore Position Tracking for portfolio management
- Set up Real-time Data for market data streaming
- Use Technical Indicators for market analysis
- Implement Risk Management for capital protection
The TradingSuite provides a solid foundation for building sophisticated trading applications. Start with the basic setup and gradually add features as your needs grow.