@@ -492,7 +492,7 @@ def execute_buy_order(self, symbol: str, usdc_amount: float) -> Dict:
492492 return {'success' : False , 'error' : str (e )}
493493
494494 def execute_sell_order_with_stop_loss (self , symbol : str , bought_quantity : float , buy_price : float , profit_target : float , buy_transaction_id : int = None ) -> Dict :
495- """Exécute un ordre OCO avec profit + stop-loss + INSERTION EN BASE BULLETPROOF"""
495+ """Exécute un ordre OCO avec profit + stop-loss + INSERTION EN BASE BULLETPROOF + VENTE MARKET D'URGENCE """
496496 try :
497497 # Configuration des ordres
498498 hold = self .advanced_config .get ('hold' , True )
@@ -620,7 +620,7 @@ def execute_sell_order_with_stop_loss(self, symbol: str, bought_quantity: float,
620620 self .logger .debug (f" Step size: { step_size } -> Qty précision: { qty_precision } " )
621621 self .logger .debug (f" Quantité finale: { sell_quantity :.{qty_precision }f} " )
622622
623- self .logger .info (f"🔄 Future transfer : { 'Activé' if hold else 'Désactivé' } " )
623+ self .logger .info (f"🔄 Hold strategy : { 'Activé' if hold else 'Désactivé' } " )
624624 if hold :
625625 self .logger .info (f" 📦 Quantité achetée: { bought_quantity :.8f} " )
626626 self .logger .info (f" 🏪 Quantité à vendre: { sell_quantity :.8f} ({ (sell_quantity / bought_quantity )* 100 :.1f} %)" )
@@ -763,46 +763,152 @@ def execute_sell_order_with_stop_loss(self, symbol: str, bought_quantity: float,
763763
764764 if not use_oco_orders :
765765 # Ordre limite classique (fallback)
766- limit_order = self .binance_client ._make_request_with_retry (
767- self .binance_client .client .order_limit_sell ,
768- symbol = symbol ,
769- quantity = sell_quantity ,
770- price = f"{ target_price :.{price_precision }f} " ,
771- timeInForce = 'GTC'
772- )
773-
774- self .logger .info (f"✅ ORDRE LIMITE PLACÉ { symbol } " )
775- self .logger .info (f" 📈 ID: { limit_order ['orderId' ]} " )
776- self .logger .warning (f"⚠️ Pas de protection stop-loss (ordre limite simple)" )
777-
778- # 🆕 ENREGISTRER EN BASE
779766 try :
780- limit_db_id = self .database .insert_limit_order (
767+ limit_order = self .binance_client ._make_request_with_retry (
768+ self .binance_client .client .order_limit_sell ,
781769 symbol = symbol ,
782- order_id = str (limit_order ['orderId' ]),
783- buy_transaction_id = buy_transaction_id or 0 ,
784- profit_target = profit_target ,
785- target_price = target_price ,
786770 quantity = sell_quantity ,
787- kept_quantity = kept_quantity
771+ price = f"{ target_price :.{price_precision }f} " ,
772+ timeInForce = 'GTC'
788773 )
789774
790- self .logger .info (f"💾 Ordre LIMIT enregistré en base (DB ID: { limit_db_id } )" )
775+ self .logger .info (f"✅ ORDRE LIMITE PLACÉ { symbol } " )
776+ self .logger .info (f" 📈 ID: { limit_order ['orderId' ]} " )
777+ self .logger .warning (f"⚠️ Pas de protection stop-loss (ordre limite simple)" )
778+
779+ # 🆕 ENREGISTRER EN BASE
780+ try :
781+ limit_db_id = self .database .insert_limit_order (
782+ symbol = symbol ,
783+ order_id = str (limit_order ['orderId' ]),
784+ buy_transaction_id = buy_transaction_id or 0 ,
785+ profit_target = profit_target ,
786+ target_price = target_price ,
787+ quantity = sell_quantity ,
788+ kept_quantity = kept_quantity
789+ )
790+
791+ self .logger .info (f"💾 Ordre LIMIT enregistré en base (DB ID: { limit_db_id } )" )
792+
793+ except Exception as db_error :
794+ self .logger .error (f"❌ Erreur insertion LIMIT en base: { db_error } " )
795+ limit_db_id = None
791796
792- except Exception as db_error :
793- self .logger .error (f"❌ Erreur insertion LIMIT en base: { db_error } " )
794- limit_db_id = None
797+ return {
798+ 'success' : True ,
799+ 'order_type' : 'LIMIT' ,
800+ 'order' : limit_order ,
801+ 'target_price' : target_price ,
802+ 'quantity' : sell_quantity ,
803+ 'kept_quantity' : kept_quantity ,
804+ 'limit_db_id' : limit_db_id ,
805+ 'simulation' : False
806+ }
795807
796- return {
797- 'success' : True ,
798- 'order_type' : 'LIMIT' ,
799- 'order' : limit_order ,
800- 'target_price' : target_price ,
801- 'quantity' : sell_quantity ,
802- 'kept_quantity' : kept_quantity ,
803- 'limit_db_id' : limit_db_id ,
804- 'simulation' : False
805- }
808+ except Exception as limit_error :
809+ # 🚨 DERNIER RECOURS : VENTE MARKET IMMÉDIATE
810+ self .logger .error (f"❌ Échec ordre LIMIT { symbol } : { limit_error } " )
811+
812+ # Vérifier si c'est une erreur de limite d'ordres
813+ if "MAX_NUM_ORDERS" in str (limit_error ) or "filter failure" in str (limit_error ).lower ():
814+ self .logger .critical (f"🚨 LIMITE ORDRES ATTEINTE pour { symbol } - VENTE MARKET D'URGENCE!" )
815+
816+ try :
817+ # 🔥 CORRECTION: Vendre TOUTE la quantité achetée
818+ emergency_sell_quantity = bought_quantity # ✅ PAS sell_quantity !
819+
820+ # Respecter les filtres LOT_SIZE pour la vente complète
821+ symbol_info = self .binance_client ._make_request_with_retry (
822+ self .binance_client .client .get_symbol_info ,
823+ symbol = symbol
824+ )
825+
826+ lot_size_filter = next (f for f in symbol_info ['filters' ] if f ['filterType' ] == 'LOT_SIZE' )
827+ step_size = float (lot_size_filter ['stepSize' ])
828+
829+ # Arrondir la quantité totale selon step_size
830+ qty_precision = max (0 , - int (np .log10 (step_size )))
831+ emergency_sell_quantity = round (emergency_sell_quantity / step_size ) * step_size
832+ emergency_sell_quantity = round (emergency_sell_quantity , qty_precision )
833+
834+ self .logger .warning (f"⚡ VENTE MARKET D'URGENCE:" )
835+ self .logger .warning (f" 📦 Quantité achetée: { bought_quantity :.8f} " )
836+ self .logger .warning (f" 🏪 Quantité à vendre: { emergency_sell_quantity :.8f} " )
837+ self .logger .warning (f" ⚠️ Mode: RÉCUPÉRATION COMPLÈTE (pas hold strategy)" )
838+
839+ # VENTE MARKET IMMÉDIATE de TOUT
840+ market_order = self .binance_client ._make_request_with_retry (
841+ self .binance_client .client .order_market_sell ,
842+ symbol = symbol ,
843+ quantity = emergency_sell_quantity
844+ )
845+
846+ # Prix estimé pour les calculs
847+ ticker = self .binance_client ._make_request_with_retry (
848+ self .binance_client .client .get_symbol_ticker ,
849+ symbol = symbol
850+ )
851+ market_price = float (ticker ['price' ])
852+ executed_qty = float (market_order .get ('executedQty' , emergency_sell_quantity ))
853+
854+ self .logger .warning (f"✅ VENTE MARKET RÉALISÉE { symbol } :" )
855+ self .logger .warning (f" 💸 Prix market: { market_price :.6f} USDC" )
856+ self .logger .warning (f" 📊 Quantité vendue: { executed_qty :.8f} " )
857+ self .logger .warning (f" 💰 Valeur récupérée: { market_price * executed_qty :.2f} USDC" )
858+ self .logger .warning (f" 💎 Crypto gardée: 0 (vente complète d'urgence)" )
859+
860+ # Récupérer commissions réelles
861+ try :
862+ commission , commission_asset = self .database .get_order_commissions_from_binance (
863+ self .binance_client , symbol , str (market_order ['orderId' ])
864+ )
865+ except :
866+ commission = market_price * executed_qty * 0.001 # Estimation
867+ commission_asset = 'USDC'
868+
869+ # Enregistrer la transaction de vente market
870+ self .database .insert_transaction (
871+ symbol = symbol ,
872+ order_id = str (market_order ['orderId' ]),
873+ transact_time = str (market_order .get ('transactTime' , int (time .time () * 1000 ))),
874+ order_type = 'MARKET' ,
875+ order_side = 'SELL' ,
876+ price = market_price ,
877+ qty = executed_qty ,
878+ commission = commission ,
879+ commission_asset = commission_asset
880+ )
881+
882+ self .logger .warning (f"📝 Transaction VENTE MARKET COMPLÈTE enregistrée" )
883+
884+ return {
885+ 'success' : True ,
886+ 'order_type' : 'MARKET_EMERGENCY' ,
887+ 'order' : market_order ,
888+ 'target_price' : market_price , # Prix réel obtenu
889+ 'quantity' : executed_qty , # Quantité réellement vendue
890+ 'kept_quantity' : 0.0 , # 🔥 AUCUNE crypto gardée en urgence
891+ 'emergency_sale' : True ,
892+ 'simulation' : False ,
893+ 'warning' : 'Vente market d\' urgence complète - limites ordres atteintes'
894+ }
895+
896+ except Exception as market_error :
897+ self .logger .critical (f"🚨 ÉCHEC VENTE MARKET { symbol } : { market_error } " )
898+ self .logger .critical (f"💀 CRYPTO ACHETÉE MAIS NON VENDUE - INTERVENTION MANUELLE REQUISE!" )
899+ self .logger .critical (f"📦 Quantité non vendue: { bought_quantity :.8f} { symbol .replace ('USDC' , '' )} " )
900+
901+ return {
902+ 'success' : False ,
903+ 'error' : f'Échec complet vente { symbol } : OCO/LIMIT/MARKET tous échoués' ,
904+ 'critical' : True ,
905+ 'manual_intervention_required' : True ,
906+ 'bought_quantity' : bought_quantity ,
907+ 'symbol' : symbol
908+ }
909+ else :
910+ # Autre type d'erreur LIMIT, la relancer
911+ raise limit_error
806912
807913 except Exception as e :
808914 self .logger .error (f"❌ Erreur ordre { symbol } : { e } " )
0 commit comments