Skip to content

Commit 2a8705e

Browse files
TexasCodingclaude
andcommitted
feat: enhance factory functions with auto-initialization (v2.0.8)
- Add auto_connect and auto_subscribe options to create_trading_suite - Add create_initialized_trading_suite for one-line setup - Reduce boilerplate code by ~95% for trading strategies - Add examples demonstrating simplified setup approach - Update documentation and changelog for v2.0.8 BREAKING CHANGE: None - all changes are backward compatible 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 5cc8e92 commit 2a8705e

File tree

9 files changed

+581
-23
lines changed

9 files changed

+581
-23
lines changed

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Old implementations are removed when improved
1414
- Clean, modern code architecture is prioritized
1515

16+
## [2.0.8] - 2025-08-03
17+
18+
### Added
19+
- **🚀 Enhanced Factory Functions**: Dramatically simplified trading suite setup
20+
- `create_initialized_trading_suite()`: One-line setup with everything connected and ready
21+
- Enhanced `create_trading_suite()` with auto-initialization options:
22+
- `auto_connect`: Automatically connect realtime client and subscribe to user updates
23+
- `auto_subscribe`: Automatically subscribe to market data and start feeds
24+
- `initial_days`: Configurable historical data loading (default: 5)
25+
- Reduces boilerplate code by ~95% for most use cases
26+
- Still allows full manual control when needed
27+
28+
### Examples
29+
- **12_simplified_strategy.py**: Demonstrates the new simplified setup approach
30+
- **13_factory_comparison.py**: Shows the difference between old manual setup and new auto-initialization
31+
32+
### Improved
33+
- **📖 Documentation**: Updated README with comprehensive factory function documentation
34+
- **🎯 Developer Experience**: Trading strategies can now focus on logic instead of setup boilerplate
35+
- **🔄 Flexibility**: Three levels of initialization control:
36+
1. `create_initialized_trading_suite()` - Everything automatic
37+
2. `create_trading_suite(..., auto_connect=True, auto_subscribe=True)` - Configurable automation
38+
3. `create_trading_suite(..., auto_connect=False, auto_subscribe=False)` - Full manual control
39+
40+
### Technical Details
41+
- Factory functions now handle all initialization steps:
42+
- WebSocket connection and user update subscription
43+
- Historical data loading
44+
- Instrument search and contract resolution
45+
- Market data subscription
46+
- Real-time feed initialization
47+
- OrderBook initialization (if enabled)
48+
- All initialization is properly sequenced to avoid race conditions
49+
- Error handling ensures clear feedback if initialization fails
50+
1651
## [2.0.7] - 2025-08-03
1752

1853
### Added

README.md

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,37 +128,117 @@ if __name__ == "__main__":
128128
asyncio.run(main())
129129
```
130130

131-
### Real-time Trading Suite
131+
### Trading Suite (NEW in v2.0.8)
132+
133+
The easiest way to get started with a complete trading setup:
132134

133135
```python
134136
import asyncio
135-
from project_x_py import ProjectX, create_trading_suite
136-
137-
async def on_tick(tick_data):
138-
print(f"Price: ${tick_data['price']}")
137+
from project_x_py import ProjectX, create_initialized_trading_suite
139138

140139
async def main():
141140
async with ProjectX.from_env() as client:
142141
await client.authenticate()
143142

144-
# Create complete trading suite
145-
suite = await create_trading_suite(
143+
# One line creates and initializes everything!
144+
suite = await create_initialized_trading_suite(
146145
instrument="MNQ",
147146
project_x=client,
148-
timeframes=["1min", "5min", "15min"]
147+
timeframes=["5min", "15min", "1hr"],
148+
initial_days=5
149149
)
150150

151-
# Connect real-time services
152-
await suite["realtime_client"].connect()
153-
await suite["data_manager"].initialize(initial_days=5)
151+
# Everything is ready to use:
152+
# ✅ Realtime client connected
153+
# ✅ Historical data loaded
154+
# ✅ Market data streaming
155+
# ✅ All components initialized
156+
157+
# Access components
158+
data = await suite["data_manager"].get_data("5min")
159+
orderbook = suite["orderbook"]
160+
order_manager = suite["order_manager"]
161+
position_manager = suite["position_manager"]
162+
163+
# Your trading logic here...
164+
165+
if __name__ == "__main__":
166+
asyncio.run(main())
167+
```
168+
169+
### Factory Functions (v2.0.8+)
170+
171+
The SDK provides powerful factory functions to simplify setup:
172+
173+
#### create_initialized_trading_suite
174+
The simplest way to get a fully initialized trading environment:
175+
176+
```python
177+
suite = await create_initialized_trading_suite(
178+
instrument="MNQ",
179+
project_x=client,
180+
timeframes=["5min", "15min", "1hr"], # Optional, defaults to ["5min"]
181+
enable_orderbook=True, # Optional, defaults to True
182+
initial_days=5 # Optional, defaults to 5
183+
)
184+
# Everything is connected and ready!
185+
```
186+
187+
#### create_trading_suite
188+
For more control over initialization:
189+
190+
```python
191+
suite = await create_trading_suite(
192+
instrument="MNQ",
193+
project_x=client,
194+
timeframes=["5min", "15min"],
195+
auto_connect=True, # Auto-connect realtime client (default: True)
196+
auto_subscribe=True, # Auto-subscribe to market data (default: True)
197+
initial_days=5 # Historical data to load
198+
)
199+
```
200+
201+
#### Manual Setup (Full Control)
202+
If you need complete control:
203+
204+
```python
205+
suite = await create_trading_suite(
206+
instrument="MNQ",
207+
project_x=client,
208+
auto_connect=False,
209+
auto_subscribe=False
210+
)
211+
# Now manually connect and subscribe as needed
212+
await suite["realtime_client"].connect()
213+
await suite["data_manager"].initialize()
214+
# ... etc
215+
```
216+
217+
### Real-time Trading Example
218+
219+
```python
220+
import asyncio
221+
from project_x_py import ProjectX, create_initialized_trading_suite
222+
223+
async def on_tick(tick_data):
224+
print(f"Price: ${tick_data['price']}")
225+
226+
async def main():
227+
async with ProjectX.from_env() as client:
228+
await client.authenticate()
229+
230+
# Create fully initialized trading suite
231+
suite = await create_initialized_trading_suite("MNQ", client)
154232

155-
# Subscribe to real-time data
233+
# Add callbacks
156234
suite["data_manager"].add_tick_callback(on_tick)
157-
await suite["data_manager"].start_realtime_feed()
235+
236+
# Get current price
237+
current_price = await suite["data_manager"].get_current_price()
158238

159239
# Place a bracket order
160240
response = await suite["order_manager"].place_bracket_order(
161-
contract_id=instrument.id,
241+
contract_id=suite["instrument_info"].id,
162242
side=0, # Buy
163243
size=1,
164244
entry_price=current_price,
@@ -284,6 +364,8 @@ The `examples/` directory contains comprehensive async examples:
284364
7. **07_technical_indicators.py** - Using indicators with async data
285365
8. **08_order_and_position_tracking.py** - Integrated async monitoring
286366
9. **09_get_check_available_instruments.py** - Interactive async instrument search
367+
10. **12_simplified_strategy.py** - NEW: Simplified strategy using auto-initialization
368+
11. **13_factory_comparison.py** - NEW: Comparison of factory function approaches
287369

288370
## 🔧 Configuration
289371

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
project = "project-x-py"
2424
copyright = "2025, Jeff West"
2525
author = "Jeff West"
26-
release = "2.0.7"
27-
version = "2.0.7"
26+
release = "2.0.8"
27+
version = "2.0.8"
2828

2929
# -- General configuration ---------------------------------------------------
3030

examples/12_simplified_strategy.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simplified trading strategy example using the enhanced factory functions.
4+
5+
This example demonstrates how the new auto-initialization features in
6+
create_trading_suite dramatically reduce boilerplate code.
7+
"""
8+
9+
import asyncio
10+
import logging
11+
import signal
12+
from datetime import datetime
13+
from typing import TYPE_CHECKING
14+
15+
from project_x_py import ProjectX, create_initialized_trading_suite
16+
from project_x_py.indicators import RSI, SMA
17+
from project_x_py.models import Instrument, Position
18+
19+
if TYPE_CHECKING:
20+
from project_x_py.types.protocols import (
21+
OrderManagerProtocol,
22+
PositionManagerProtocol,
23+
RealtimeDataManagerProtocol,
24+
)
25+
26+
27+
class SimplifiedStrategy:
28+
"""A simple momentum strategy using the enhanced factory functions."""
29+
30+
def __init__(self, trading_suite: dict, symbol: str):
31+
self.suite = trading_suite
32+
self.symbol = symbol
33+
self.instrument: Instrument = trading_suite["instrument_info"]
34+
self.data_manager: RealtimeDataManagerProtocol = trading_suite["data_manager"]
35+
self.order_manager: OrderManagerProtocol = trading_suite["order_manager"]
36+
self.position_manager: PositionManagerProtocol = trading_suite[
37+
"position_manager"
38+
]
39+
self.is_running = False
40+
self.logger = logging.getLogger(__name__)
41+
42+
async def check_signal(self):
43+
"""Check for trading signals."""
44+
# Get 5-minute data
45+
if not self.data_manager:
46+
raise ValueError("Data manager not initialized")
47+
data = await self.data_manager.get_data(timeframe="5min", bars=50)
48+
if data is None or len(data) < 50:
49+
return None
50+
51+
# Calculate indicators
52+
data = data.pipe(SMA, period=20).pipe(RSI, period=14)
53+
54+
last_close = data["close"].tail(1).item()
55+
last_sma = data["sma_20"].tail(1).item()
56+
last_rsi = data["rsi_14"].tail(1).item()
57+
58+
# Simple momentum signal
59+
if last_close > last_sma and last_rsi < 70:
60+
return {"signal": "BUY", "confidence": min(80, last_rsi)}
61+
elif last_close < last_sma and last_rsi > 30:
62+
return {"signal": "SELL", "confidence": min(80, 100 - last_rsi)}
63+
64+
return None
65+
66+
async def run_loop(self, check_interval: int = 30):
67+
"""Run the strategy loop."""
68+
self.is_running = True
69+
self.logger.info(f"🚀 Strategy started for {self.symbol}")
70+
71+
while self.is_running:
72+
try:
73+
signal = await self.check_signal()
74+
if signal:
75+
self.logger.info(
76+
f"📊 Signal: {signal['signal']} "
77+
f"(Confidence: {signal['confidence']:.1f}%)"
78+
)
79+
80+
# Display status
81+
positions: list[
82+
Position
83+
] = await self.position_manager.get_all_positions()
84+
print(f"\n{datetime.now().strftime('%H:%M:%S')}")
85+
print(f" Positions: {len(positions)}")
86+
87+
await asyncio.sleep(check_interval)
88+
89+
except Exception as e:
90+
self.logger.error(f"Strategy error: {e}")
91+
await asyncio.sleep(check_interval)
92+
93+
def stop(self):
94+
"""Stop the strategy."""
95+
self.is_running = False
96+
self.logger.info("🛑 Strategy stopped")
97+
98+
99+
async def main():
100+
"""Main function demonstrating simplified setup."""
101+
logging.basicConfig(level=logging.INFO)
102+
logger = logging.getLogger(__name__)
103+
104+
# Signal handler for graceful shutdown
105+
stop_event = asyncio.Event()
106+
107+
def signal_handler(_signum, _frame):
108+
print("\n⚠️ Shutdown signal received...")
109+
stop_event.set()
110+
111+
signal.signal(signal.SIGINT, signal_handler)
112+
113+
try:
114+
# LOOK HOW SIMPLE THIS IS NOW! 🎉
115+
async with ProjectX.from_env() as client:
116+
await client.authenticate()
117+
if not client.account_info:
118+
raise ValueError("No account info found")
119+
print(f"✅ Connected as: {client.account_info.name}")
120+
121+
# One line to create a fully initialized trading suite!
122+
suite = await create_initialized_trading_suite(
123+
instrument="MNQ",
124+
project_x=client,
125+
timeframes=["5min", "15min", "1hr"],
126+
initial_days=3,
127+
)
128+
129+
# That's it! Everything is connected and ready to use:
130+
# ✅ Realtime client connected
131+
# ✅ User updates subscribed
132+
# ✅ Historical data loaded
133+
# ✅ Market data subscribed
134+
# ✅ Realtime feeds started
135+
# ✅ Orderbook subscribed (if enabled)
136+
137+
# Get the instrument info
138+
instrument: Instrument = suite["instrument_info"]
139+
140+
print("\n🎯 Trading suite fully initialized!")
141+
print(f" Instrument: {instrument.symbolId}")
142+
print(f" Contract: {instrument.activeContract}")
143+
print(" Components: All connected and subscribed")
144+
145+
# Create and run strategy
146+
strategy = SimplifiedStrategy(suite, "MNQ")
147+
148+
# Run until stopped
149+
strategy_task = asyncio.create_task(strategy.run_loop())
150+
await stop_event.wait()
151+
152+
# Cleanup (also simplified - just stop the strategy)
153+
strategy.stop()
154+
strategy_task.cancel()
155+
156+
# The context manager handles all cleanup automatically!
157+
print("\n✅ Clean shutdown completed")
158+
159+
except Exception as e:
160+
logger.error(f"❌ Error: {e}", exc_info=True)
161+
162+
163+
if __name__ == "__main__":
164+
print("\n" + "=" * 60)
165+
print("SIMPLIFIED TRADING STRATEGY EXAMPLE")
166+
print("=" * 60)
167+
print("\nThis example shows the new auto-initialization features:")
168+
print("- Single function call to create trading suite")
169+
print("- Automatic connection and subscription handling")
170+
print("- No boilerplate setup code needed!")
171+
print("\nPress Ctrl+C to stop\n")
172+
173+
asyncio.run(main())

0 commit comments

Comments
 (0)