Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/01_basic_client_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
This is the foundation for all other async examples.

Usage:
Run with: uv run examples/async_01_basic_client_connection.py
Run with: uv run examples/01_basic_client_connection.py
Or use test.sh which sets environment variables: ./test.sh

Author: TexasCoding
Expand Down
9 changes: 7 additions & 2 deletions examples/02_order_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_02_order_management.py
Or: uv run examples/02_order_management.py

Author: TexasCoding
Date: July 2025
Expand All @@ -32,6 +32,7 @@
create_realtime_client,
setup_logging,
)
from project_x_py.models import Order


async def wait_for_user_confirmation(message: str) -> bool:
Expand Down Expand Up @@ -80,7 +81,11 @@ async def show_order_status(order_manager, order_id: int, description: str):
else:
# Fall back to API check for status
print(f" Order {order_id} not in real-time cache, checking API...")
api_order = await order_manager.get_order_by_id(order_id)
api_order: Order | None = await order_manager.get_order_by_id(order_id)
if not isinstance(api_order, Order):
print(f" Order {order_id} not found in API either")
return

if api_order:
status_map = {1: "Open", 2: "Filled", 3: "Cancelled", 4: "Partially Filled"}
status = status_map.get(api_order.status, f"Unknown ({api_order.status})")
Expand Down
34 changes: 15 additions & 19 deletions examples/03_position_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_03_position_management.py
Or: uv run examples/03_position_management.py

Author: TexasCoding
Date: July 2025
Expand All @@ -30,13 +30,14 @@
create_realtime_client,
setup_logging,
)
from project_x_py.async_realtime_data_manager import AsyncRealtimeDataManager
from project_x_py.position_manager import PositionManager
from project_x_py.realtime_data_manager import RealtimeDataManager


async def get_current_market_price(
client: ProjectX,
symbol="MNQ",
realtime_data_manager: AsyncRealtimeDataManager | None = None,
realtime_data_manager: RealtimeDataManager | None = None,
):
"""Get current market price with async fallback for closed markets."""
# Try to get real-time price first if available
Expand Down Expand Up @@ -74,7 +75,7 @@ async def try_get_data(days, interval):
return None


async def display_positions(position_manager):
async def display_positions(position_manager: PositionManager):
"""Display current positions with detailed information."""
print("\n📊 Current Positions:")
print("-" * 80)
Expand All @@ -88,29 +89,24 @@ async def display_positions(position_manager):
# Get portfolio P&L concurrently with position display
pnl_task = asyncio.create_task(position_manager.get_portfolio_pnl())

portfolio_pnl = await pnl_task
# Display each position
for symbol, position in positions.items():
print(f"\n{symbol}:")
print(f" Quantity: {position.quantity}")
for position in positions:
print(f"\n{position.contractId}:")
print(f" Quantity: {position.size}")
print(f" Average Price: ${position.averagePrice:.2f}")
print(f" Position Value: ${position.positionValue:.2f}")
print(f" Unrealized P&L: ${position.unrealizedPnl:.2f}")

# Show percentage change
if position.averagePrice > 0:
pnl_pct = (
position.unrealizedPnl / (position.quantity * position.averagePrice)
) * 100
print(f" P&L %: {pnl_pct:+.2f}%")
print(f" Position Value: ${position.averagePrice:.2f}")
print(f" Unrealized P&L: ${portfolio_pnl.get('unrealized_pnl', 0):.2f}")

# Show portfolio totals
portfolio_pnl = await pnl_task
print("\n" + "=" * 40)
print(f"Portfolio Total P&L: ${portfolio_pnl:.2f}")
print(f"Portfolio Total P&L: ${portfolio_pnl.get('net_pnl', 0):.2f}")
print("=" * 40)


async def monitor_positions_realtime(position_manager, duration_seconds=30):
async def monitor_positions_realtime(
position_manager: PositionManager, duration_seconds: int = 30
):
"""Monitor positions with real-time updates."""
print(f"\n🔄 Monitoring positions for {duration_seconds} seconds...")

Expand Down
6 changes: 3 additions & 3 deletions examples/04_realtime_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_04_realtime_data.py
Or: uv run examples/04_realtime_data.py

Author: TexasCoding
Date: July 2025
Expand All @@ -35,10 +35,10 @@
)

if TYPE_CHECKING:
from project_x_py.async_realtime_data_manager import AsyncRealtimeDataManager
from project_x_py.realtime_data_manager import RealtimeDataManager


async def display_current_prices(data_manager: AsyncRealtimeDataManager):
async def display_current_prices(data_manager: RealtimeDataManager):
"""Display current prices across all timeframes asynchronously."""
print("\n📊 Current Prices:")

Expand Down
11 changes: 6 additions & 5 deletions examples/05_orderbook_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
- Market imbalance monitoring
- Best bid/ask tracking

Uses MNQ for Level 2 orderbook data with AsyncOrderBook.
Uses MNQ for Level 2 orderbook data with OrderBook.

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_05_orderbook_analysis.py
Or: uv run examples/05_orderbook_analysis.py

Note: This example includes several wait periods:
- 5 seconds for initial data population
Expand All @@ -38,6 +38,7 @@
create_realtime_client,
setup_logging,
)
from project_x_py.orderbook import OrderBook


async def display_best_prices(orderbook):
Expand Down Expand Up @@ -259,9 +260,9 @@ async def monitor_orderbook_feed(orderbook, duration_seconds=60):
print(f" Update Cycles: {update_count}", flush=True)


async def demonstrate_all_orderbook_methods(orderbook):
"""Comprehensive demonstration of all AsyncOrderBook methods."""
print("\n🔍 Testing all available AsyncOrderBook methods...", flush=True)
async def demonstrate_all_orderbook_methods(orderbook: OrderBook):
"""Comprehensive demonstration of all OrderBook methods."""
print("\n🔍 Testing all available OrderBook methods...", flush=True)
print(
"📝 Note: Some methods may show zero values without live market data connection"
)
Expand Down
37 changes: 24 additions & 13 deletions examples/06_multi_timeframe_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_06_multi_timeframe_strategy.py
Or: uv run examples/06_multi_timeframe_strategy.py

Author: TexasCoding
Date: July 2025
Expand All @@ -31,9 +31,10 @@
create_trading_suite,
)
from project_x_py.indicators import RSI, SMA
from project_x_py.models import BracketOrderResponse, Position


class AsyncMultiTimeframeStrategy:
class MultiTimeframeStrategy:
"""
Async multi-timeframe trend following strategy.

Expand All @@ -47,11 +48,13 @@ class AsyncMultiTimeframeStrategy:

def __init__(
self,
client: ProjectX,
trading_suite: dict,
symbol: str = "MNQ",
max_position_size: int = 2,
risk_percentage: float = 0.02,
):
self.client = client
self.suite = trading_suite
self.symbol = symbol
self.max_position_size = max_position_size
Expand Down Expand Up @@ -245,19 +248,20 @@ async def generate_trading_signal(self):
async def execute_signal(self, signal_data: dict):
"""Execute trading signal with proper risk management."""
# Check current position
positions = await self.position_manager.get_all_positions()
current_position = positions.get(self.symbol)
positions: list[Position] = await self.position_manager.get_all_positions()
current_position = next(
(pos for pos in positions if pos.contractId == self.symbol), None
)

# Position size limits
if (
current_position
and abs(current_position.quantity) >= self.max_position_size
):
if current_position and abs(current_position.size) >= self.max_position_size:
self.logger.info("Max position size reached, skipping signal")
return

# Get account info for position sizing
account_balance = float(self.order_manager.project_x.account_info.balance)
account_balance = (
float(self.client.account_info.balance) if self.client.account_info else 0
)

# Calculate position size based on risk
entry_price = signal_data["price"]
Expand Down Expand Up @@ -285,11 +289,11 @@ async def execute_signal(self, signal_data: dict):
return

# Get active contract
instruments = await self.order_manager.project_x.search_instruments(self.symbol)
instruments = await self.client.search_instruments(self.symbol)
if not instruments:
return

contract_id = instruments[0].activeContract
contract_id = instruments[0].id

# Place bracket order
self.logger.info(
Expand All @@ -313,8 +317,14 @@ async def execute_signal(self, signal_data: dict):
take_profit_price=take_profit,
)

if not isinstance(response, BracketOrderResponse):
self.logger.error(f"❌ Unexpected order type: {type(response)}")
return

if response and response.success:
self.logger.info(f"✅ Order placed successfully: {response.orderId}")
self.logger.info(
f"✅ Order placed successfully: {response.entry_order_id}"
)
else:
self.logger.error("❌ Order placement failed")

Expand Down Expand Up @@ -433,7 +443,8 @@ def signal_handler(signum, frame):
await suite["data_manager"].start_realtime_feed()

# Create and configure strategy
strategy = AsyncMultiTimeframeStrategy(
strategy = MultiTimeframeStrategy(
client=client,
trading_suite=suite,
symbol="MNQ",
max_position_size=2,
Expand Down
9 changes: 4 additions & 5 deletions examples/07_technical_indicators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
Async Technical Indicators Analysis Example
Technical Indicators Analysis Example

Demonstrates concurrent technical analysis using async patterns:
- Concurrent calculation of multiple indicators
Expand All @@ -12,7 +12,7 @@

Usage:
Run with: ./test.sh (sets environment variables)
Or: uv run examples/async_07_technical_indicators.py
Or: uv run examples/07_technical_indicators.py

Author: TexasCoding
Date: July 2025
Expand Down Expand Up @@ -179,7 +179,7 @@ async def on_data_update(timeframe):
update_count += 1

# Get latest data
data = await data_manager.get_data(timeframe)
data: pl.DataFrame | None = await data_manager.get_data(timeframe)
if data is None:
return

Expand All @@ -189,8 +189,7 @@ async def on_data_update(timeframe):
return

# Calculate key indicators
data = data.pipe(RSI, period=14)
data = data.pipe(SMA, period=20)
data = data.pipe(RSI, period=14).pipe(SMA, period=20)

last_row = data.tail(1)
timestamp = datetime.now().strftime("%H:%M:%S")
Expand Down
Loading
Loading