|
@@ -285,11 +285,8 @@ class ExternalEventMonitor:
|
|
|
📊 Position remains open. Use /positions to view details
|
|
|
"""
|
|
|
else:
|
|
|
- # Fallback to generic notification
|
|
|
- await self.notification_manager.send_external_trade_notification(
|
|
|
- full_symbol, side_from_fill, amount_from_fill, price_from_fill,
|
|
|
- action_type, timestamp_dt.isoformat()
|
|
|
- )
|
|
|
+ # No fallback notification sent - only position-based notifications per user preference
|
|
|
+ logger.debug(f"No notification sent for action_type: {action_type}")
|
|
|
return
|
|
|
|
|
|
await self.notification_manager.send_generic_notification(message.strip())
|
|
@@ -338,6 +335,11 @@ class ExternalEventMonitor:
|
|
|
if self.last_processed_trade_time and timestamp_dt <= self.last_processed_trade_time:
|
|
|
continue
|
|
|
|
|
|
+ # Check if this fill has already been processed to prevent duplicates
|
|
|
+ if trade_id and stats.has_exchange_fill_been_processed(str(trade_id)):
|
|
|
+ logger.debug(f"Skipping already processed fill: {trade_id}")
|
|
|
+ continue
|
|
|
+
|
|
|
fill_processed_this_iteration = False
|
|
|
|
|
|
if not (symbol_from_fill and side_from_fill and amount_from_fill > 0 and price_from_fill > 0):
|
|
@@ -438,7 +440,7 @@ class ExternalEventMonitor:
|
|
|
'position_closed', timestamp_dt, active_lc, realized_pnl
|
|
|
)
|
|
|
|
|
|
- stats._migrate_trade_to_aggregated_stats(lc_id)
|
|
|
+ stats.migrate_trade_to_aggregated_stats(lc_id)
|
|
|
if bot_order_db_id_to_update:
|
|
|
stats.update_order_status(order_db_id=bot_order_db_id_to_update, new_status='filled', amount_filled_increment=amount_from_fill)
|
|
|
fill_processed_this_iteration = True
|
|
@@ -468,7 +470,7 @@ class ExternalEventMonitor:
|
|
|
stop_loss_info, full_symbol, side_from_fill, amount_from_fill, price_from_fill,
|
|
|
f'{lc_pos_side}_closed_external_sl', timestamp_dt.isoformat(), realized_pnl
|
|
|
)
|
|
|
- stats._migrate_trade_to_aggregated_stats(lc_id)
|
|
|
+ stats.migrate_trade_to_aggregated_stats(lc_id)
|
|
|
# Modify shared state carefully
|
|
|
if exchange_order_id_from_fill in self.shared_state['external_stop_losses']:
|
|
|
del self.shared_state['external_stop_losses'][exchange_order_id_from_fill]
|
|
@@ -543,7 +545,7 @@ class ExternalEventMonitor:
|
|
|
action_type, timestamp_dt, existing_lc, realized_pnl
|
|
|
)
|
|
|
|
|
|
- stats._migrate_trade_to_aggregated_stats(lc_id)
|
|
|
+ stats.migrate_trade_to_aggregated_stats(lc_id)
|
|
|
fill_processed_this_iteration = True
|
|
|
|
|
|
elif action_type in ['position_increased', 'position_decreased'] and existing_lc:
|
|
@@ -591,12 +593,7 @@ class ExternalEventMonitor:
|
|
|
)
|
|
|
logger.info(f"📋 Recorded trade via FALLBACK: {trade_id} (Unmatched External Fill)")
|
|
|
|
|
|
- # Send generic notification for unmatched trade
|
|
|
- if self.notification_manager:
|
|
|
- await self.notification_manager.send_external_trade_notification(
|
|
|
- full_symbol, side_from_fill, amount_from_fill, price_from_fill,
|
|
|
- "external_unmatched", timestamp_dt.isoformat()
|
|
|
- )
|
|
|
+ # No notification sent for unmatched external trades per user preference
|
|
|
fill_processed_this_iteration = True
|
|
|
|
|
|
if fill_processed_this_iteration:
|