Skip to content

Commit 6408130

Browse files
TexasCodingclaude
andcommitted
fix: Correct orderbook scalping example to use actual OrderBook API
- Use get_market_imbalance() instead of non-existent get_imbalance() - Access TypedDict fields with bracket notation where needed - Fix iceberg detection parameters - Correct volume profile method parameters - Remove references to non-existent enable_analytics() - Use get_orderbook_snapshot() as fallback for imbalance calculation - Fix all f-string formatting issues The example now properly uses the OrderBook class methods that actually exist in the SDK. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 46b1080 commit 6408130

File tree

1 file changed

+92
-86
lines changed

1 file changed

+92
-86
lines changed

examples/advanced_trading/04_orderbook_analysis_and_scalping_strategy.py

Lines changed: 92 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ async def initialize_orderbook(self) -> bool:
4141
if hasattr(mnq_context, "orderbook") and mnq_context.orderbook:
4242
self.orderbook = mnq_context.orderbook
4343
print("✅ Order book initialized successfully")
44-
45-
# Enable analytics if available
46-
if hasattr(self.orderbook, "enable_analytics"):
47-
await self.orderbook.enable_analytics()
48-
print("✅ Order book analytics enabled")
49-
5044
return True
5145
else:
5246
print(
@@ -63,64 +57,57 @@ async def analyze_order_book_imbalance(self) -> Optional[dict]:
6357
return None
6458

6559
try:
66-
# Get order book imbalance using analytics
67-
if hasattr(self.orderbook, "get_imbalance"):
68-
imbalance = await self.orderbook.get_imbalance(levels=5)
60+
# Get market imbalance using the correct method
61+
imbalance_data = await self.orderbook.get_market_imbalance(levels=5)
6962

70-
if imbalance and abs(imbalance.ratio) >= self.imbalance_threshold:
63+
if imbalance_data and hasattr(imbalance_data, "imbalance_ratio"):
64+
ratio = float(imbalance_data.imbalance_ratio)
65+
66+
if abs(ratio) >= self.imbalance_threshold:
7167
return {
72-
"direction": "bullish" if imbalance.ratio > 0 else "bearish",
73-
"strength": abs(imbalance.ratio),
74-
"bid_size": imbalance.bid_size,
75-
"ask_size": imbalance.ask_size,
76-
"spread": imbalance.spread,
77-
"levels": imbalance.levels,
68+
"direction": "bullish" if ratio > 0 else "bearish",
69+
"strength": abs(ratio),
70+
"bid_liquidity": imbalance_data.bid_liquidity,
71+
"ask_liquidity": imbalance_data.ask_liquidity,
72+
"spread": imbalance_data.spread
73+
if hasattr(imbalance_data, "spread")
74+
else 0,
75+
"levels": 5,
7876
}
79-
else:
80-
# Fallback to manual calculation
81-
book_state = await self.orderbook.get_state()
82-
83-
if not book_state or not book_state.bids or not book_state.asks:
84-
return None
85-
86-
# Take top 5 levels
87-
top_bids = list(book_state.bids.values())[:5]
88-
top_asks = list(book_state.asks.values())[:5]
89-
90-
# Calculate size at each level
91-
total_bid_size = sum(order.size for order in top_bids)
92-
total_ask_size = sum(order.size for order in top_asks)
9377

94-
if total_bid_size + total_ask_size == 0:
95-
return None
78+
# Fallback to orderbook snapshot
79+
snapshot = await self.orderbook.get_orderbook_snapshot(levels=5)
9680

97-
# Calculate imbalance ratio
98-
bid_ratio = total_bid_size / (total_bid_size + total_ask_size)
81+
if snapshot:
82+
# Calculate imbalance from snapshot
83+
bid_sizes = (
84+
sum(level.size for level in snapshot.bids) if snapshot.bids else 0
85+
)
86+
ask_sizes = (
87+
sum(level.size for level in snapshot.asks) if snapshot.asks else 0
88+
)
9989

100-
# Get best bid/ask for spread
101-
best_bid = max(book_state.bids.keys()) if book_state.bids else 0
102-
best_ask = min(book_state.asks.keys()) if book_state.asks else 0
103-
spread = float(best_ask - best_bid) if best_bid and best_ask else 0
104-
105-
# Determine imbalance direction
106-
if bid_ratio >= self.imbalance_threshold:
107-
return {
108-
"direction": "bullish",
109-
"strength": bid_ratio,
110-
"bid_size": total_bid_size,
111-
"ask_size": total_ask_size,
112-
"spread": spread,
113-
"levels": 5,
114-
}
115-
elif bid_ratio <= (1 - self.imbalance_threshold):
116-
return {
117-
"direction": "bearish",
118-
"strength": 1 - bid_ratio,
119-
"bid_size": total_bid_size,
120-
"ask_size": total_ask_size,
121-
"spread": spread,
122-
"levels": 5,
123-
}
90+
if bid_sizes + ask_sizes > 0:
91+
bid_ratio = bid_sizes / (bid_sizes + ask_sizes)
92+
93+
if bid_ratio >= self.imbalance_threshold:
94+
return {
95+
"direction": "bullish",
96+
"strength": bid_ratio,
97+
"bid_size": bid_sizes,
98+
"ask_size": ask_sizes,
99+
"spread": float(snapshot.spread) if snapshot.spread else 0,
100+
"levels": 5,
101+
}
102+
elif bid_ratio <= (1 - self.imbalance_threshold):
103+
return {
104+
"direction": "bearish",
105+
"strength": 1 - bid_ratio,
106+
"bid_size": bid_sizes,
107+
"ask_size": ask_sizes,
108+
"spread": float(snapshot.spread) if snapshot.spread else 0,
109+
"levels": 5,
110+
}
124111

125112
return None
126113

@@ -130,21 +117,29 @@ async def analyze_order_book_imbalance(self) -> Optional[dict]:
130117

131118
async def check_for_iceberg_orders(self) -> Optional[dict]:
132119
"""Detect potential iceberg orders in the book."""
133-
if not self.orderbook or not hasattr(self.orderbook, "detect_iceberg"):
120+
if not self.orderbook:
134121
return None
135122

136123
try:
137124
# Use orderbook's iceberg detection
138-
iceberg_info = await self.orderbook.detect_iceberg()
125+
iceberg_info = await self.orderbook.detect_iceberg_orders(
126+
threshold=0.7, lookback_seconds=60
127+
)
139128

140-
if iceberg_info and iceberg_info.detected:
141-
return {
142-
"detected": True,
143-
"side": "bid" if iceberg_info.side == 0 else "ask",
144-
"price_level": iceberg_info.price_level,
145-
"confidence": iceberg_info.confidence,
146-
"refill_count": iceberg_info.refill_count,
147-
}
129+
if iceberg_info and iceberg_info.get("detected"):
130+
detections = iceberg_info.get("detections", [])
131+
if detections:
132+
# Get the most confident detection
133+
best_detection = max(
134+
detections, key=lambda x: x.get("confidence", 0)
135+
)
136+
return {
137+
"detected": True,
138+
"side": best_detection.get("side", "unknown"),
139+
"price_level": best_detection.get("price", 0),
140+
"confidence": best_detection.get("confidence", 0),
141+
"refill_count": best_detection.get("refill_count", 0),
142+
}
148143

149144
return None
150145

@@ -154,25 +149,31 @@ async def check_for_iceberg_orders(self) -> Optional[dict]:
154149

155150
async def analyze_volume_profile(self) -> Optional[dict]:
156151
"""Analyze volume profile for key levels."""
157-
if not self.orderbook or not hasattr(self.orderbook, "get_volume_profile"):
152+
if not self.orderbook:
158153
return None
159154

160155
try:
161-
profile = await self.orderbook.get_volume_profile(bins=10)
162-
163-
if profile:
164-
# Find Point of Control (highest volume level)
165-
poc = profile.poc
166-
value_area = profile.value_area
156+
# Get volume profile with correct parameters
157+
profile = await self.orderbook.get_volume_profile(
158+
lookback_periods=100, price_bins=10
159+
)
167160

161+
if profile and hasattr(profile, "poc"):
168162
return {
169-
"poc": float(poc.price),
170-
"poc_volume": poc.volume,
171-
"value_area_high": float(value_area.high),
172-
"value_area_low": float(value_area.low),
173-
"total_volume": profile.total_volume,
163+
"poc": float(profile.poc.price) if profile.poc else 0,
164+
"poc_volume": profile.poc.volume if profile.poc else 0,
165+
"value_area_high": float(profile.value_area.high)
166+
if profile.value_area
167+
else 0,
168+
"value_area_low": float(profile.value_area.low)
169+
if profile.value_area
170+
else 0,
171+
"total_volume": profile.total_volume
172+
if hasattr(profile, "total_volume")
173+
else 0,
174174
}
175175

176+
# If no profile data, return None
176177
return None
177178

178179
except Exception as e:
@@ -261,14 +262,19 @@ async def place_scalp_order(
261262
# Display analysis details
262263
if "orderbook" in analysis_data:
263264
ob = analysis_data["orderbook"]
264-
print(f"\nOrder Book Analysis:")
265+
print("\nOrder Book Analysis:")
265266
print(f" Imbalance: {ob['strength']:.2%} {ob['direction']}")
266-
print(f" Bid Size: {ob['bid_size']}, Ask Size: {ob['ask_size']}")
267+
if "bid_size" in ob:
268+
print(f" Bid Size: {ob['bid_size']}, Ask Size: {ob['ask_size']}")
269+
elif "bid_liquidity" in ob:
270+
print(
271+
f" Bid Liquidity: {ob['bid_liquidity']}, Ask Liquidity: {ob['ask_liquidity']}"
272+
)
267273
print(f" Spread: ${ob['spread']:.2f}")
268274

269275
if "tape" in analysis_data:
270276
tape = analysis_data["tape"]
271-
print(f"\nTape Reading:")
277+
print("\nTape Reading:")
272278
print(f" Momentum: {tape['strength']:.2%} {tape['direction']}")
273279
print(f" Volume: Buy={tape['buy_volume']}, Sell={tape['sell_volume']}")
274280

@@ -344,7 +350,7 @@ async def monitor_scalps(self):
344350

345351
# Time-based cancellation (scalps should be quick)
346352
if elapsed_time > 300: # 5 minutes
347-
print(f"\nCancelling stale scalp order (>5 min old)")
353+
print("\nCancelling stale scalp order (>5 min old)")
348354

349355
# Cancel stop and target orders
350356
bracket = scalp["bracket"]
@@ -468,7 +474,7 @@ async def on_orderbook_update(_event: Event):
468474
print("Strategy Settings:")
469475
print(f" Imbalance Threshold: {strategy.imbalance_threshold:.0%}")
470476
print(f" Profit Target: {strategy.scalp_profit_ticks} ticks")
471-
print(f" Stop Loss: 3 ticks")
477+
print(" Stop Loss: 3 ticks")
472478
print(f" Max Positions: {strategy.max_positions}")
473479
print("\nAnalyzing market microstructure for scalping opportunities...")
474480
print("Press Ctrl+C to exit")
@@ -490,7 +496,7 @@ async def on_orderbook_update(_event: Event):
490496
# Get volume profile if available
491497
volume_profile = await strategy.analyze_volume_profile()
492498

493-
print(f"\nStatus Update:")
499+
print("\nStatus Update:")
494500
print(f" Price: ${current_price:.2f}")
495501
print(f" Active Scalps: {active_scalps}/{strategy.max_positions}")
496502
print(f" Tick Buffer: {recent_ticks}/100")

0 commit comments

Comments
 (0)