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
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
"filename": "CHANGELOG.md",
"hashed_secret": "89a6cfe2a229151e8055abee107d45ed087bbb4f",
"is_verified": false,
"line_number": 2183
"line_number": 2198
}
],
"README.md": [
Expand Down Expand Up @@ -325,5 +325,5 @@
}
]
},
"generated_at": "2025-09-02T01:57:55Z"
"generated_at": "2025-09-02T03:30:00Z"
}
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Migration guides will be provided for all breaking changes
- Semantic versioning (MAJOR.MINOR.PATCH) is strictly followed

## [3.5.7] - 2025-02-02

### 🐛 Fixed

**Order Placement**:
- **Decimal Serialization**: Fixed JSON serialization error when placing orders with Decimal prices
- **API Compatibility**: Ensured all price values are properly converted to float for API requests
- **Price Precision**: Maintained internal Decimal precision while ensuring JSON compatibility

### 📚 Documentation

**Examples**:
- **Quick Start Example**: Fixed and verified the quick_start.py example in Documentation_Examples
- **Order Placement**: Ensured all documentation examples work with the fixed serialization

## [3.5.6] - 2025-02-02

### 🐛 Fixed
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ A **high-performance async Python SDK** for the [ProjectX Trading Platform](http

This Python SDK acts as a bridge between your trading strategies and the ProjectX platform, handling all the complex API interactions, data processing, and real-time connectivity.

## 🚀 v3.5.6 - Event System & Bracket Order Enhancements
## 🚀 v3.5.7 - Order Placement Serialization Fix

**Latest Version**: v3.5.6 - Critical fixes for multi-instrument event handling and automatic price alignment for bracket orders, ensuring robust real-time trading operations.
**Latest Version**: v3.5.7 - Fixed JSON serialization error when placing orders with Decimal prices, ensuring all price values are properly converted for API requests while maintaining internal precision.

**Key Improvements**:
- 🔄 **Event Forwarding**: Fixed multi-instrument event propagation with proper bus forwarding
Expand All @@ -39,7 +39,7 @@ This Python SDK acts as a bridge between your trading strategies and the Project
- 🛡️ **Improved Reliability**: 30+ test fixes ensuring production stability
- ⚡ **Real-time Fixes**: Corrected bar data access in streaming examples

See [CHANGELOG.md](CHANGELOG.md) for complete v3.5.6 fixes and previous version features.
See [CHANGELOG.md](CHANGELOG.md) for complete v3.5.7 fixes and previous version features.

### 📦 Production Stability Guarantee

Expand Down
30 changes: 30 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@ All notable changes to the ProjectX Python SDK will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.5.7] - 2025-02-02

### 🐛 Fixed

**Order Placement**:
- **Decimal Serialization**: Fixed JSON serialization error when placing orders with Decimal prices
- **API Compatibility**: Ensured all price values are properly converted to float for API requests
- **Price Precision**: Maintained internal Decimal precision while ensuring JSON compatibility

### 📚 Documentation

**Examples**:
- **Quick Start Example**: Fixed and verified the quick_start.py example in Documentation_Examples
- **Order Placement**: Ensured all documentation examples work with the fixed serialization

## [3.5.6] - 2025-02-02

### 🐛 Fixed

**Multi-Instrument Event System**:
- **Event Forwarding**: Implemented event forwarding from instrument-specific EventBuses to suite-level EventBus
- **InstrumentContext Methods**: Added `on()`, `once()`, `off()`, and `wait_for()` methods that delegate to event_bus
- **Event Propagation**: Fixed broken event system that prevented `mnq_context.wait_for(EventType.NEW_BAR)` from working
- **Multi-Instrument Support**: Events now properly flow from individual instruments to the suite level

**Bracket Order Improvements**:
- **Automatic Price Alignment**: Changed validation from failing to auto-aligning prices to tick size
- **Smart Adjustment**: Orders with misaligned prices are now automatically corrected instead of rejected
- **Better UX**: Improved user experience by handling price alignment transparently

## [3.4.0] - 2025-08-28

### 🚀 New Feature: ETH vs RTH Trading Sessions (Experimental)
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/advanced.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Advanced Trading Examples

This page demonstrates sophisticated trading strategies and advanced features of the ProjectX Python SDK v3.5.6. These examples include order placement with automatic price alignment, risk management, and complex event-driven trading systems with proper multi-instrument event forwarding.
This page demonstrates sophisticated trading strategies and advanced features of the ProjectX Python SDK v3.5.7. These examples include order placement with automatic price alignment, risk management, and complex event-driven trading systems with proper multi-instrument event forwarding.

!!! warning "Live Trading Alert"
**These examples place REAL ORDERS on the market!**
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/realtime.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Real-time Data Processing Examples

This page demonstrates how to work with real-time market data streams using the ProjectX Python SDK v3.5.6. Learn to handle WebSocket data, process multiple timeframes, and build real-time trading systems with the enhanced event system.
This page demonstrates how to work with real-time market data streams using the ProjectX Python SDK v3.5.7. Learn to handle WebSocket data, process multiple timeframes, and build real-time trading systems with the enhanced event system.

## Prerequisites

Expand Down
107 changes: 80 additions & 27 deletions docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
# Quick Start

This guide will help you get started with the ProjectX Python SDK.
This guide will help you get started with the ProjectX Python SDK. Some examples will place live trades and orders. Please use with caution!!

## Basic Setup

### Single Instrument (Traditional)

```python
import asyncio

from project_x_py import TradingSuite


async def main():
# Create a trading suite for single instrument
suite = await TradingSuite.create(
instruments=["MNQ"], # List notation (recommended)
timeframes=["1min", "5min"],
features=["orderbook"], # Optional features
initial_days=5 # Historical data to load
initial_days=5, # Historical data to load
)

# Access the instrument context
mnq = suite["MNQ"]

if suite.client.account_info is None:
raise Exception("Account info is None")

# Everything is now connected and ready
print(f"Connected to: {suite.client.account_info.name}")

Expand All @@ -32,19 +37,25 @@ async def main():
# Clean shutdown
await suite.disconnect()


# Run the async function
asyncio.run(main())
```

### Multi-Instrument Setup (v3.5.0)

```python
import asyncio

from project_x_py import TradingSuite


async def multi_instrument_setup():
# Create suite for multiple instruments
suite = await TradingSuite.create(
instruments=["MNQ", "ES", "MGC"], # Multiple futures
timeframes=["1min", "5min"],
features=["orderbook", "risk_manager"]
features=["orderbook", "risk_manager"],
)

print(f"Managing {len(suite)} instruments: {list(suite.keys())}")
Expand All @@ -56,6 +67,7 @@ async def multi_instrument_setup():

await suite.disconnect()


asyncio.run(multi_instrument_setup())
```

Expand All @@ -64,6 +76,11 @@ asyncio.run(multi_instrument_setup())
### Single Instrument Trading

```python
import asyncio

from project_x_py import TradingSuite


async def trading_example():
suite = await TradingSuite.create(["MNQ"]) # List notation
mnq = suite["MNQ"] # Get instrument context
Expand All @@ -72,31 +89,38 @@ async def trading_example():
order = await mnq.orders.place_market_order(
contract_id=mnq.instrument_info.id,
side=0, # 0=Buy, 1=Sell
size=1
size=1,
)
print(f"Order placed: {order.order_id}")
print(f"Order placed: {order.orderId}")

# Check position
position = await mnq.positions.get_position("MNQ")
if position:
print(f"Position: {position.net_position} @ ${position.average_price:,.2f}")
print(f"Position: {position.size} @ ${position.averagePrice:,.2f}")

# Place a stop loss
if position and position.net_position > 0:
if position and position.size > 0:
stop_order = await mnq.orders.place_stop_order(
contract_id=mnq.instrument_info.id,
side=1, # Sell
size=position.net_position,
stop_price=position.average_price - 20 # 20 points below entry
size=position.size,
stop_price=position.averagePrice - 20, # 20 points below entry
)
print(f"Stop loss placed: {stop_order.order_id}")
print(f"Stop loss placed: {stop_order.orderId}")

await suite.disconnect()

asyncio.run(trading_example())
```

### Multi-Instrument Pairs Trading

```python
import asyncio

from project_x_py import TradingSuite


async def pairs_trading_example():
suite = await TradingSuite.create(["ES", "MNQ"]) # S&P 500 vs NASDAQ

Expand All @@ -107,6 +131,9 @@ async def pairs_trading_example():
es_price = await es_context.data.get_current_price()
mnq_price = await mnq_context.data.get_current_price()

if es_price is None or mnq_price is None:
raise Exception("No price data available")

# Calculate spread (normalize by contract values)
spread = (es_price * 50) - (mnq_price * 20)
print(f"ES/MNQ Spread: ${spread:.2f}")
Expand All @@ -115,42 +142,54 @@ async def pairs_trading_example():
if spread > 500: # ES expensive relative to MNQ
await es_context.orders.place_market_order(
contract_id=es_context.instrument_info.id,
side=1, size=1 # Sell ES
side=1,
size=1, # Sell ES
)
await mnq_context.orders.place_market_order(
contract_id=mnq_context.instrument_info.id,
side=0, size=1 # Buy MNQ
side=0,
size=1, # Buy MNQ
)
print("Executed pairs trade: Short ES, Long MNQ")

await suite.disconnect()


asyncio.run(pairs_trading_example())
```

## Real-time Data Streaming

### Single Instrument Streaming

```python
from project_x_py import EventType
import asyncio

from project_x_py import EventType, TradingSuite
from project_x_py.event_bus import Event


async def stream_data():
suite = await TradingSuite.create(
["MNQ"],
timeframes=["1min", "5min"]
)
suite = await TradingSuite.create(["MNQ"], timeframes=["15sec", "1min"])

mnq = suite["MNQ"]

# Register event handlers
async def on_new_bar(event):
async def on_new_bar(event: Event):
data = event.data
timeframe = data.get('timeframe')
bar = data.get('data')
timeframe = data.get("timeframe")
bar = data.get("data")
if bar:
print(f"MNQ New {timeframe} bar: ${bar['close']:,.2f} Vol: {bar['volume']:,}")
print(
f"MNQ New {timeframe} bar: ${bar['close']:,.2f} Vol: {bar['volume']:,}"
)

async def on_quote(event):
async def on_quote(event: Event):
quote = event.data

if quote["bid"] is None or quote["ask"] is None:
return

print(f"MNQ Quote: Bid ${quote['bid']:,.2f} Ask ${quote['ask']:,.2f}")

# Subscribe to events for MNQ
Expand All @@ -161,25 +200,36 @@ async def stream_data():
await asyncio.sleep(30)

await suite.disconnect()


asyncio.run(stream_data())
```

### Multi-Instrument Streaming

```python
import asyncio

from project_x_py import EventType, TradingSuite
from project_x_py.event_bus import Event


async def multi_stream_data():
suite = await TradingSuite.create(
["MNQ", "ES", "MGC"],
timeframes=["1min", "5min"]
timeframes=["15sec", "1min"],
)

# Register handlers for each instrument
for symbol, context in suite.items():

async def make_handler(sym):
async def on_new_bar(event):
async def on_new_bar(event: Event):
data = event.data
if data.get('timeframe') == '5min':
bar = data.get('data')
print(f"{sym} 5min: ${bar['close']:,.2f}")
if data.get("timeframe") == "1min":
bar = data.get("data")
print(f"{sym} 1min: ${bar['close']:,.2f}")

return on_new_bar

handler = await make_handler(symbol)
Expand All @@ -188,6 +238,9 @@ async def multi_stream_data():
# Stream all instruments simultaneously
await asyncio.sleep(30)
await suite.disconnect()


asyncio.run(multi_stream_data())
```

## Next Steps
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/realtime.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Real-time Data Guide

This guide covers comprehensive real-time data streaming using ProjectX Python SDK v3.5.6+. All real-time operations are fully asynchronous and provide high-performance WebSocket connectivity with automatic reconnection, memory management, and enhanced event forwarding for multi-instrument support.
This guide covers comprehensive real-time data streaming using ProjectX Python SDK v3.5.7+. All real-time operations are fully asynchronous and provide high-performance WebSocket connectivity with automatic reconnection, memory management, and enhanced event forwarding for multi-instrument support.

## Overview

Expand Down
Loading
Loading