|
@@ -421,59 +421,130 @@ class InfoCommands:
|
|
|
|
|
|
# Group orders by symbol
|
|
|
orders_by_symbol = {}
|
|
|
- for order in orders:
|
|
|
- symbol = order.get('symbol', '').replace('/USDC:USDC', '')
|
|
|
- if symbol not in orders_by_symbol:
|
|
|
- orders_by_symbol[symbol] = []
|
|
|
- orders_by_symbol[symbol].append(order)
|
|
|
+ # Keep track of parent_bot_order_ref_ids for pending SLs already displayed with an open parent order
|
|
|
+ displayed_sl_parent_refs = set()
|
|
|
|
|
|
- for symbol, symbol_orders in orders_by_symbol.items():
|
|
|
+ for order in orders: # Iterate through orders from self.trading_engine.get_orders()
|
|
|
+ symbol_display_key = order.get('symbol', '').replace('/USDC:USDC', '')
|
|
|
+ if symbol_display_key not in orders_by_symbol:
|
|
|
+ orders_by_symbol[symbol_display_key] = []
|
|
|
+ orders_by_symbol[symbol_display_key].append(order) # Group by display key
|
|
|
+
|
|
|
+ formatter = get_formatter() # Get formatter once
|
|
|
+
|
|
|
+ for symbol, symbol_orders_list in orders_by_symbol.items():
|
|
|
orders_text += f"📊 <b>{symbol}</b>\n"
|
|
|
|
|
|
- formatter = get_formatter()
|
|
|
- for order in symbol_orders:
|
|
|
- side = order.get('side', '').upper()
|
|
|
- amount = float(order.get('amount', 0))
|
|
|
- price = float(order.get('price', 0))
|
|
|
- order_type = order.get('type', 'unknown').title()
|
|
|
- order_id = order.get('id', 'N/A')
|
|
|
+ for order_data in symbol_orders_list: # This is an individual exchange order
|
|
|
+ side = order_data.get('side', '').upper()
|
|
|
+ amount = float(order_data.get('amount', 0))
|
|
|
+ price = float(order_data.get('price', 0))
|
|
|
+ order_type = order_data.get('type', 'unknown').title()
|
|
|
+ exchange_order_id = order_data.get('id', 'N/A') # Renamed for clarity
|
|
|
|
|
|
- # Order emoji
|
|
|
side_emoji = "🟢" if side == "BUY" else "🔴"
|
|
|
|
|
|
- orders_text += f" {side_emoji} {side} {amount:.6f} @ {formatter.format_price_with_symbol(price, symbol)}\n"
|
|
|
- orders_text += f" 📋 Type: {order_type} | ID: {order_id}\n"
|
|
|
+ orders_text += f" {side_emoji} {side} {formatter.format_amount(amount, symbol)} @ {formatter.format_price_with_symbol(price, symbol)}\n"
|
|
|
+ orders_text += f" 📋 Type: {order_type} | ID: {exchange_order_id}\n"
|
|
|
|
|
|
- # Check for pending stop losses linked to this order
|
|
|
stats = self.trading_engine.get_stats()
|
|
|
if stats:
|
|
|
- # Try to find this order in our database to get its bot_order_ref_id
|
|
|
- order_in_db = stats.get_order_by_exchange_id(order_id)
|
|
|
+ order_in_db = stats.get_order_by_exchange_id(exchange_order_id)
|
|
|
if order_in_db:
|
|
|
bot_ref_id = order_in_db.get('bot_order_ref_id')
|
|
|
if bot_ref_id:
|
|
|
- # Look for pending stop losses with this order as parent
|
|
|
pending_sls = stats.get_orders_by_status(
|
|
|
- status='pending_trigger',
|
|
|
- order_type_filter='stop_limit_trigger',
|
|
|
+ status='pending_activation',
|
|
|
+ order_type_filter='pending_sl_activation',
|
|
|
parent_bot_order_ref_id=bot_ref_id
|
|
|
)
|
|
|
|
|
|
if pending_sls:
|
|
|
- sl_order = pending_sls[0] # Should only be one
|
|
|
+ sl_order = pending_sls[0]
|
|
|
sl_price = sl_order.get('price', 0)
|
|
|
- sl_side = sl_order.get('side', '').upper()
|
|
|
- orders_text += f" 🛑 Pending SL: {sl_side} @ {formatter.format_price_with_symbol(sl_price, symbol)} (activates when filled)\n"
|
|
|
+ sl_conceptual_side = sl_order.get('side', '').upper()
|
|
|
+
|
|
|
+ orders_text += f" ⏳ Pending SL Activation: {sl_conceptual_side} at {formatter.format_price_with_symbol(sl_price, symbol)}\n"
|
|
|
+ orders_text += f" (Activates after main order fills)\n"
|
|
|
+ displayed_sl_parent_refs.add(bot_ref_id)
|
|
|
|
|
|
orders_text += "\n"
|
|
|
|
|
|
- orders_text += f"💼 <b>Total Orders:</b> {len(orders)}\n"
|
|
|
+ orders_text += f"💼 <b>Total Open Exchange Orders:</b> {len(orders)}\n"
|
|
|
+
|
|
|
+ # Now, check for any other pending_sl_activation orders whose parents are not in the open list
|
|
|
+ stats_for_orphan_check = self.trading_engine.get_stats() # Get stats again if not already available
|
|
|
+ if stats_for_orphan_check:
|
|
|
+ all_pending_sl_activations = stats_for_orphan_check.get_orders_by_status(
|
|
|
+ status='pending_activation',
|
|
|
+ order_type_filter='pending_sl_activation'
|
|
|
+ )
|
|
|
+
|
|
|
+ orphaned_pending_sls_to_display = []
|
|
|
+ for sl_order_data in all_pending_sl_activations:
|
|
|
+ parent_ref = sl_order_data.get('parent_bot_order_ref_id')
|
|
|
+ if parent_ref not in displayed_sl_parent_refs:
|
|
|
+ orphaned_pending_sls_to_display.append(sl_order_data)
|
|
|
+
|
|
|
+ if orphaned_pending_sls_to_display:
|
|
|
+ orders_text += "\n"
|
|
|
+ orders_text += "⏳ <b>Pending SL Activations (Entry Order Assumed Filled/Closed)</b>\n\n"
|
|
|
+
|
|
|
+ orphaned_sls_by_symbol_group = {}
|
|
|
+ for sl_data in orphaned_pending_sls_to_display:
|
|
|
+ sl_symbol_raw = sl_data.get('symbol', '')
|
|
|
+ sl_symbol_display_key = sl_symbol_raw.replace('/USDC:USDC', '')
|
|
|
+ if sl_symbol_display_key not in orphaned_sls_by_symbol_group:
|
|
|
+ orphaned_sls_by_symbol_group[sl_symbol_display_key] = []
|
|
|
+ orphaned_sls_by_symbol_group[sl_symbol_display_key].append(sl_data)
|
|
|
+
|
|
|
+ for sl_sym_key, sl_list_items in orphaned_sls_by_symbol_group.items():
|
|
|
+ orders_text += f"📊 <b>{sl_sym_key}</b>\n"
|
|
|
+ for sl_item in sl_list_items:
|
|
|
+ sl_price_val = sl_item.get('price', 0)
|
|
|
+ sl_side_val = sl_item.get('side', '').upper()
|
|
|
+ orders_text += f" ⏳ Pending SL: {sl_side_val} at {formatter.format_price_with_symbol(sl_price_val, sl_sym_key)}\n"
|
|
|
+ orders_text += f" (Awaiting activation by bot)\n\n"
|
|
|
+
|
|
|
+ orders_text += f"📦 <b>Total Pending Activations (Entry Filled):</b> {len(orphaned_pending_sls_to_display)}\n"
|
|
|
+
|
|
|
orders_text += f"💡 Use /coo [token] to cancel orders"
|
|
|
|
|
|
else:
|
|
|
orders_text = "📋 <b>Open Orders</b>\n\n"
|
|
|
orders_text += "📭 No open orders\n\n"
|
|
|
- orders_text += "💡 Use /long, /short, /sl, or /tp to create orders"
|
|
|
+ # Check for purely conceptual pending SLs even if no exchange orders are open
|
|
|
+ stats_for_empty_check = self.trading_engine.get_stats()
|
|
|
+ if stats_for_empty_check:
|
|
|
+ all_pending_sl_activations_empty = stats_for_empty_check.get_orders_by_status(
|
|
|
+ status='pending_activation',
|
|
|
+ order_type_filter='pending_sl_activation'
|
|
|
+ )
|
|
|
+ if all_pending_sl_activations_empty:
|
|
|
+ orders_text += "\n"
|
|
|
+ orders_text += "⏳ <b>Pending SL Activations (Entry Order Assumed Filled/Closed)</b>\n\n"
|
|
|
+ formatter_for_empty = get_formatter() # Ensure formatter is available
|
|
|
+
|
|
|
+ orphaned_sls_by_symbol_group_empty = {}
|
|
|
+ for sl_data_empty in all_pending_sl_activations_empty:
|
|
|
+ sl_symbol_raw_empty = sl_data_empty.get('symbol', '')
|
|
|
+ sl_symbol_display_key_empty = sl_symbol_raw_empty.replace('/USDC:USDC', '')
|
|
|
+ if sl_symbol_display_key_empty not in orphaned_sls_by_symbol_group_empty:
|
|
|
+ orphaned_sls_by_symbol_group_empty[sl_symbol_display_key_empty] = []
|
|
|
+ orphaned_sls_by_symbol_group_empty[sl_symbol_display_key_empty].append(sl_data_empty)
|
|
|
+
|
|
|
+ for sl_sym_key_empty, sl_list_items_empty in orphaned_sls_by_symbol_group_empty.items():
|
|
|
+ orders_text += f"📊 <b>{sl_sym_key_empty}</b>\n"
|
|
|
+ for sl_item_empty in sl_list_items_empty:
|
|
|
+ sl_price_val_empty = sl_item_empty.get('price', 0)
|
|
|
+ sl_side_val_empty = sl_item_empty.get('side', '').upper()
|
|
|
+ orders_text += f" ⏳ Pending SL: {sl_side_val_empty} at {formatter_for_empty.format_price_with_symbol(sl_price_val_empty, sl_sym_key_empty)}\n"
|
|
|
+ orders_text += f" (Awaiting activation by bot)\n\n"
|
|
|
+ orders_text += f"📦 <b>Total Pending Activations (Entry Filled):</b> {len(all_pending_sl_activations_empty)}\n"
|
|
|
+ else:
|
|
|
+ orders_text += "💡 Use /long, /short, /sl, or /tp to create orders" # Original message if no pending SLs either
|
|
|
+ else:
|
|
|
+ orders_text += "💡 Use /long, /short, /sl, or /tp to create orders"
|
|
|
|
|
|
await reply_method(text=orders_text, parse_mode='HTML')
|
|
|
else:
|