Skip to content

Commit 8027c60

Browse files
committed
feat: Update examples to use modern API
Refactored all applicable examples to use the latest dictionary-style component access for `TradingSuite` (e.g., `suite["MNQ"].data` instead of `suite.data`). This change brings the examples in line with the current multi-instrument API, ensuring they serve as accurate and up-to-date guides for users. Key changes include: - Replaced deprecated direct property access for `data`, `orders`, `positions`, `risk_manager`, and `orderbook` with the recommended instrument-based context access. - Updated method calls to reflect the latest asynchronous and dictionary-based API, such as for statistics and real-time data handling. - Corrected the use of instrument properties like `instrument_info` and `symbol`. - Removed redundant `suite.connect()` calls, as `TradingSuite.create()` now handles connections automatically. - Modernized the code by using enhanced model properties like `.direction` and `.side_str` for cleaner logic.
1 parent 97300ac commit 8027c60

28 files changed

+510
-324
lines changed

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@
203203
"filename": "examples/17_join_orders.py",
204204
"hashed_secret": "11fa7c37d697f30e6aee828b4426a10f83ab2380",
205205
"is_verified": false,
206-
"line_number": 245
206+
"line_number": 247
207207
}
208208
],
209209
"examples/README.md": [
@@ -325,5 +325,5 @@
325325
}
326326
]
327327
},
328-
"generated_at": "2025-08-31T01:30:08Z"
328+
"generated_at": "2025-08-31T14:45:33Z"
329329
}

examples/00_trading_suite_demo.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ async def main():
3232

3333
# Everything is connected and ready!
3434
print(f"Connected: {suite.is_connected}")
35-
print(f"Instrument: {suite.symbol}") # Use symbol property instead of instrument
35+
if suite.instrument is None:
36+
raise Exception("Instrument is None")
37+
print(f"Instrument: {suite.instrument.symbolId}") # Access instrument info
3638

3739
# Access components - new multi-instrument way (recommended)
3840
print("\n=== Component Access (Recommended) ===")
@@ -64,7 +66,7 @@ async def main():
6466
)
6567

6668
print(f"Connected: {suite2.is_connected}")
67-
print(f"Has orderbook: {suite2.orderbook is not None}")
69+
print(f"Has orderbook: {suite2['MGC'].orderbook is not None}")
6870

6971
# Use as context manager for automatic cleanup
7072
print("\n\n=== Using as context manager ===")

examples/02_order_management.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ async def main() -> bool:
186186

187187
# TradingSuite v3 includes order manager with real-time tracking
188188
print("\n🏗️ Using TradingSuite order manager...")
189-
order_manager = suite.orders
189+
order_manager = suite["MNQ"].orders
190190
print("✅ Order manager ready with real-time tracking")
191191

192192
# Track orders placed in this demo for cleanup
@@ -437,7 +437,7 @@ async def main() -> bool:
437437
print("📋 No orders filled yet")
438438

439439
# Check current positions (to detect fills that weren't caught)
440-
current_positions = await suite.client.search_open_positions()
440+
current_positions = await suite["MNQ"].positions.get_all_positions()
441441
if current_positions:
442442
print(f"📊 Open positions: {len(current_positions)}")
443443
for pos in current_positions:
@@ -477,7 +477,7 @@ async def main() -> bool:
477477
print("📊 ORDER STATISTICS")
478478
print("=" * 50)
479479

480-
stats = order_manager.get_order_statistics()
480+
stats = await order_manager.get_order_statistics_async()
481481
print("Order Manager Statistics:")
482482
print(f" Orders Placed: {stats.get('orders_placed', 0)}")
483483
print(f" Orders Cancelled: {stats.get('orders_cancelled', 0)}")
@@ -517,7 +517,7 @@ async def main() -> bool:
517517
print(f"⚠️ Error cancelling order #{order.id}: {e}")
518518

519519
# Check for positions and close them
520-
positions = await suite.client.search_open_positions()
520+
positions = await suite["MNQ"].positions.get_all_positions()
521521
print(f"Found {len(positions)} open positions")
522522

523523
closed_count = 0

examples/03_position_management.py

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async def get_current_market_price(
4040
"""Get current market price with async fallback for closed markets."""
4141
# Try to get real-time price first if available
4242
try:
43-
current_price = await suite.data.get_current_price()
43+
current_price = await suite[symbol].data.get_current_price()
4444
if current_price:
4545
return float(current_price)
4646
except Exception as e:
@@ -103,10 +103,10 @@ async def display_positions(
103103
if suite:
104104
try:
105105
# Get current market price
106-
current_price = await suite.data.get_current_price()
107-
if current_price and suite.instrument:
106+
current_price = await suite[position.symbol].data.get_current_price()
107+
if current_price and suite[position.symbol].instrument_info:
108108
# Use the instrument already loaded in suite
109-
instrument_info = suite.instrument
109+
instrument_info = suite[position.symbol].instrument_info
110110
point_value = instrument_info.tickValue / instrument_info.tickSize
111111

112112
# Calculate P&L using position manager's method
@@ -138,20 +138,32 @@ async def display_risk_metrics(position_manager: "PositionManager") -> None:
138138
if hasattr(position_manager, "get_risk_metrics"):
139139
risk_check = await position_manager.get_risk_metrics()
140140
# Check if we're within daily loss limits and position limits
141-
within_daily_loss = risk_check["daily_loss"] <= risk_check["daily_loss_limit"]
142-
within_position_limit = risk_check["position_count"] <= risk_check["position_limit"]
143-
within_risk_limits = risk_check["current_risk"] <= risk_check["max_risk"]
141+
within_daily_loss = (
142+
risk_check["daily_loss"] <= risk_check["daily_loss_limit"]
143+
)
144+
within_position_limit = (
145+
risk_check["position_count"] <= risk_check["position_limit"]
146+
)
147+
within_risk_limits = (
148+
risk_check["current_risk"] <= risk_check["max_risk"]
149+
)
144150

145151
if within_daily_loss and within_position_limit and within_risk_limits:
146152
print("✅ All positions within risk limits")
147153
else:
148154
violations = []
149155
if not within_daily_loss:
150-
violations.append(f"Daily loss: ${risk_check['daily_loss']:.2f} / ${risk_check['daily_loss_limit']:.2f}")
156+
violations.append(
157+
f"Daily loss: ${risk_check['daily_loss']:.2f} / ${risk_check['daily_loss_limit']:.2f}"
158+
)
151159
if not within_position_limit:
152-
violations.append(f"Position count: {risk_check['position_count']} / {risk_check['position_limit']}")
160+
violations.append(
161+
f"Position count: {risk_check['position_count']} / {risk_check['position_limit']}"
162+
)
153163
if not within_risk_limits:
154-
violations.append(f"Current risk: ${risk_check['current_risk']:.2f} / ${risk_check['max_risk']:.2f}")
164+
violations.append(
165+
f"Current risk: ${risk_check['current_risk']:.2f} / ${risk_check['max_risk']:.2f}"
166+
)
155167
if violations:
156168
print(f"⚠️ Risk limit violations: {', '.join(violations)}")
157169
else:
@@ -162,14 +174,12 @@ async def display_risk_metrics(position_manager: "PositionManager") -> None:
162174
if hasattr(position_manager, "get_risk_metrics"):
163175
risk_summary = await position_manager.get_risk_metrics()
164176
print("\nRisk Summary:")
177+
print(f" Current Risk: ${risk_summary.get('current_risk', 0):,.2f}")
178+
print(f" Max Risk Allowed: ${risk_summary.get('max_risk', 0):,.2f}")
165179
print(
166-
f" Current Risk: ${risk_summary.get('current_risk', 0):,.2f}"
167-
)
168-
print(
169-
f" Max Risk Allowed: ${risk_summary.get('max_risk', 0):,.2f}"
180+
f" Max Drawdown: {risk_summary.get('max_drawdown', 0) * 100:.1f}%"
170181
)
171-
print(f" Max Drawdown: {risk_summary.get('max_drawdown', 0)*100:.1f}%")
172-
print(f" Win Rate: {risk_summary.get('win_rate', 0)*100:.1f}%")
182+
print(f" Win Rate: {risk_summary.get('win_rate', 0) * 100:.1f}%")
173183
print(f" Profit Factor: {risk_summary.get('profit_factor', 0):.2f}")
174184
else:
175185
print("Risk summary not available")
@@ -210,10 +220,10 @@ async def monitor_positions(
210220
try:
211221
# Try to calculate real P&L with current prices
212222
if suite and positions:
213-
current_price = await suite.data.get_current_price()
214-
if current_price and suite.instrument:
223+
current_price = await suite["MNQ"].data.get_current_price()
224+
if current_price and suite["MNQ"].instrument_info:
215225
# Use the instrument already loaded in suite
216-
instrument_info = suite.instrument
226+
instrument_info = suite["MNQ"].instrument_info
217227
point_value = (
218228
instrument_info.tickValue / instrument_info.tickSize
219229
)
@@ -282,11 +292,11 @@ async def main() -> bool:
282292

283293
# Check for existing positions
284294
print("\n📊 Checking existing positions...")
285-
existing_positions = await suite.positions.get_all_positions()
295+
existing_positions = await suite["MNQ"].positions.get_all_positions()
286296

287297
if existing_positions:
288298
print(f"Found {len(existing_positions)} existing positions")
289-
await display_positions(suite.positions, suite)
299+
await display_positions(suite["MNQ"].positions, suite)
290300
else:
291301
print("No existing positions found")
292302

@@ -312,15 +322,17 @@ async def main() -> bool:
312322
try:
313323
response = await loop.run_in_executor(
314324
None,
315-
lambda: input("\n Place test order? (y/N): ").strip().lower(),
325+
lambda: input("\n Place test order? (y/N): ")
326+
.strip()
327+
.lower(),
316328
)
317329
except (KeyboardInterrupt, asyncio.CancelledError):
318330
print("\n\n⚠️ Script interrupted by user")
319331
return False
320332

321333
if response == "y":
322334
print("\n Placing market order...")
323-
order_response = await suite.orders.place_market_order(
335+
order_response = await suite["MNQ"].orders.place_market_order(
324336
contract_id=contract_id,
325337
side=0,
326338
size=1, # Buy
@@ -334,9 +346,9 @@ async def main() -> bool:
334346
await asyncio.sleep(3)
335347

336348
# Refresh positions
337-
existing_positions = (
338-
await suite.positions.get_all_positions()
339-
)
349+
existing_positions = await suite[
350+
"MNQ"
351+
].positions.get_all_positions()
340352
if existing_positions:
341353
print(" ✅ Position created!")
342354
else:
@@ -345,23 +357,23 @@ async def main() -> bool:
345357
print("\n ⚠️ Skipping test order")
346358

347359
# Display comprehensive position information
348-
if await suite.positions.get_all_positions():
360+
if await suite["MNQ"].positions.get_all_positions():
349361
print("\n" + "=" * 80)
350362
print("📈 POSITION MANAGEMENT DEMONSTRATION")
351363
print("=" * 80)
352364

353365
# 1. Display current positions
354-
await display_positions(suite.positions, suite)
366+
await display_positions(suite["MNQ"].positions, suite)
355367

356368
# 2. Show risk metrics
357-
await display_risk_metrics(suite.positions)
369+
await display_risk_metrics(suite["MNQ"].positions)
358370

359371
# 3. Portfolio statistics
360372
print("\n📊 Portfolio Statistics:")
361373
print("-" * 80)
362374
try:
363-
if hasattr(suite.positions, "get_portfolio_pnl"):
364-
stats = await suite.positions.get_portfolio_pnl()
375+
if hasattr(suite["MNQ"].positions, "get_portfolio_pnl"):
376+
stats = await suite["MNQ"].positions.get_portfolio_pnl()
365377
print(f" Total Trades: {stats.get('total_trades', 0)}")
366378
print(f" Winning Trades: {stats.get('winning_trades', 0)}")
367379
print(f" Average Win: ${stats.get('average_win', 0):,.2f}")
@@ -377,8 +389,8 @@ async def main() -> bool:
377389
print("\n📈 Performance Analytics:")
378390
print("-" * 80)
379391
try:
380-
if hasattr(suite.positions, "get_portfolio_pnl"):
381-
analytics = await suite.positions.get_portfolio_pnl()
392+
if hasattr(suite["MNQ"].positions, "get_portfolio_pnl"):
393+
analytics = await suite["MNQ"].positions.get_portfolio_pnl()
382394
print(f" Total P&L: ${analytics.get('total_pnl', 0):,.2f}")
383395
print(f" Max Drawdown: ${analytics.get('max_drawdown', 0):,.2f}")
384396
print(
@@ -398,10 +410,10 @@ async def main() -> bool:
398410
print("=" * 80)
399411

400412
# Monitor for 30 seconds
401-
await monitor_positions(suite.positions, suite, duration=30)
413+
await monitor_positions(suite["MNQ"].positions, suite, duration=30)
402414

403415
# 6. Offer to close positions
404-
if await suite.positions.get_all_positions():
416+
if await suite["MNQ"].positions.get_all_positions():
405417
print("\n" + "=" * 80)
406418
print("🔧 POSITION MANAGEMENT")
407419
print("=" * 80)
@@ -413,19 +425,21 @@ async def main() -> bool:
413425
try:
414426
response = await loop.run_in_executor(
415427
None,
416-
lambda: input("\nClose all positions? (y/N): ").strip().lower(),
428+
lambda: input("\nClose all positions? (y/N): ")
429+
.strip()
430+
.lower(),
417431
)
418432
except (KeyboardInterrupt, asyncio.CancelledError):
419433
print("\n\n⚠️ Script interrupted by user")
420434
return False
421435

422436
if response == "y":
423437
print("\n🔄 Closing all positions...")
424-
positions = await suite.positions.get_all_positions()
438+
positions = await suite["MNQ"].positions.get_all_positions()
425439

426440
for position in positions:
427441
try:
428-
result = await suite.orders.close_position(
442+
result = await suite["MNQ"].orders.close_position(
429443
position.contractId, method="market"
430444
)
431445
if result and result.success:
@@ -439,7 +453,9 @@ async def main() -> bool:
439453

440454
# Final position check
441455
await asyncio.sleep(3)
442-
final_positions = await suite.positions.get_all_positions()
456+
final_positions = await suite[
457+
"MNQ"
458+
].positions.get_all_positions()
443459
if not final_positions:
444460
print("\n✅ All positions closed successfully!")
445461
else:
@@ -453,8 +469,8 @@ async def main() -> bool:
453469
print("=" * 80)
454470

455471
try:
456-
if hasattr(suite.positions, "get_portfolio_pnl"):
457-
session_summary = await suite.positions.get_portfolio_pnl()
472+
if hasattr(suite["MNQ"].positions, "get_portfolio_pnl"):
473+
session_summary = await suite["MNQ"].positions.get_portfolio_pnl()
458474
print(f" Session Duration: {session_summary.get('duration', 'N/A')}")
459475
print(
460476
f" Positions Opened: {session_summary.get('positions_opened', 0)}"
@@ -485,7 +501,7 @@ async def main() -> bool:
485501
# Ask user if they want to close positions
486502
if suite:
487503
try:
488-
positions = await suite.positions.get_all_positions()
504+
positions = await suite["MNQ"].positions.get_all_positions()
489505
if positions:
490506
print(f"\n⚠️ You have {len(positions)} open position(s).")
491507
print("Would you like to close them before exiting?")
@@ -511,12 +527,12 @@ async def main() -> bool:
511527
# Check if we need to close positions
512528
if cleanup_positions:
513529
print("\n🧹 Performing cleanup...")
514-
positions = await suite.positions.get_all_positions()
530+
positions = await suite["MNQ"].positions.get_all_positions()
515531
if positions:
516532
print(f" Closing {len(positions)} open position(s)...")
517533
for position in positions:
518534
try:
519-
result = await suite.orders.close_position(
535+
result = await suite["MNQ"].orders.close_position(
520536
position.contractId, method="market"
521537
)
522538
if result and result.success:
@@ -530,7 +546,9 @@ async def main() -> bool:
530546
await asyncio.sleep(2)
531547

532548
# Final check
533-
final_positions = await suite.positions.get_all_positions()
549+
final_positions = await suite[
550+
"MNQ"
551+
].positions.get_all_positions()
534552
if final_positions:
535553
print(f" ⚠️ {len(final_positions)} position(s) still open")
536554
else:

examples/04_realtime_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ async def main() -> bool:
242242
print(f" Timeframes: {', '.join(timeframes)}")
243243

244244
# Components are now accessed as attributes
245-
data_manager = suite.data
245+
data_manager = suite["MNQ"].data
246246

247247
print("\n✅ All components connected and subscribed:")
248248
print(" - Real-time client connected")

examples/05_orderbook_analysis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ async def main() -> bool:
451451
print(f" Simulated: {account.simulated}", flush=True)
452452

453453
# Get orderbook from suite
454-
orderbook = suite.orderbook
454+
orderbook = suite["MNQ"].orderbook
455455
if not orderbook:
456456
print("❌ Orderbook not available in suite", flush=True)
457457
await suite.disconnect()

examples/06_advanced_orderbook.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,14 +446,14 @@ async def main():
446446
print("✅ Suite initialized successfully!")
447447
if suite.client.account_info:
448448
print(f" Account: {suite.client.account_info.name}")
449-
if suite.orderbook:
450-
print(f" Tracking: {suite.orderbook.instrument}")
449+
if suite["MNQ"].orderbook:
450+
print(f" Tracking: {suite["MNQ"].orderbook.instrument}")
451451

452452
# Wait for initial data
453453
print("\n⏳ Collecting market data for 10 seconds...")
454454
await asyncio.sleep(10)
455455

456-
orderbook: OrderBook | None = suite.orderbook
456+
orderbook: OrderBook | None = suite["MNQ"].orderbook
457457
if not orderbook:
458458
raise ValueError("Orderbook not found")
459459

examples/07_technical_indicators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,8 @@ async def main() -> int | None:
528528
print("\n📊 Monitoring indicators in real-time...")
529529

530530
# Check if we have data_manager
531-
if hasattr(suite, "data") and suite.data:
532-
await real_time_indicator_updates(suite.data, duration_seconds=30)
531+
if "MNQ" in suite and suite["MNQ"].data:
532+
await real_time_indicator_updates(suite["MNQ"].data, duration_seconds=30)
533533
else:
534534
print(" Real-time monitoring not available in this configuration")
535535

0 commit comments

Comments
 (0)