
    -hi             
       	   d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Zddl
Z
ddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlZddlZ ed      Zdefd	Z	 dd
lmZmZ dZdZdZ	 ej@                  jC                  dej@                  jE                  ej@                  jG                  ej@                  jI                  e%            d             ddl&m'Z' ddl(m)Z) ddl*Z+dZej@                  jG                  ej@                  jI                  e%            Z-ej@                  jC                  de-       	 ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 dZ7dZ8e1re8ne7Z9e7Z:dZ;dZ<dZ=dZ>dZ?dZ@dZAdZBdZCdZDdZEdZFd ZGd!ZHd"ZId#ZJd$ZKd%ZLd&ZMd'ZNd(ZOd)ZPd*ZQd+ZRd,ZSd'ZTd-ZUd.ZVd/ZWd0ZXd1d2hZYd3d"d"d3d4ZZd5 Z[ e[       Z\e\Z]e\Z^d!Z_d*Z`dZad6Zbd"ZcdZddZed7Zfd8Zgd8Zhd9Zid:Zjd;Zkd<Zld!Zmd=Zndcd>Zoddd?Zpd@ Zqej@                  jE                  e-dA      Zrej@                  jE                  e-dB      Zsej@                  jE                  e-dC      Ztej@                  jE                  e-dD      Zuej@                  jE                  e-dE      Zvej@                  jE                  e-dF      Zwej@                  jE                  e-dG      Zxej@                  jE                  e-dH      ZydIZzd+Z{h dJZ|dK Z} G dL dMej                        Z ej                   dN      Zej                  ej                         de_         ej
                         Zej                   edOdPQ             ej                  e       ej                  j                  ej@                  jE                  e-dR      dST      Zej                   edOdPQ             ej                  e       ej@                  jE                  ej@                  jG                  ej@                  jI                  e%            dU      ZdefdVZdWefdXZ G dY dZ      Z G d[ d\      Z G d] d^      Z G d_ d`      Zda Zedbk(  r e        yy# e$ r dZY w xY w# e$ rZ,Y dZ,[,sdZ,[,ww xY w# e$ r  e5d        ejl                  d       Y <w xY w)eu  
═══════════════════════════════════════════════════════════════════════════════
🕵️ MARKET SPY v3 - Pump Catcher / Scalper ultrarapide
═══════════════════════════════════════════════════════════════════════════════

Stratégie: Détecter les hausses inattendues, significatives et éphémères,
acheter pendant la hausse et revendre dès les premiers signes de baisse.

PRINCIPE:
  - Scan ultra-rapide de TOUTES les paires USDT toutes les 10-12 secondes
  - Comparer le prix actuel vs prix du scan précédent → détecter les surges
  - Confirmer avec mini-analyse klines 1m (5 bougies = 5 minutes)
  - Acheter IMMÉDIATEMENT si surge confirmé
  - Monitoring serré des positions: trailing stop TRÈS serré (0.5%)
  - Revente automatique dès essoufflement (max ~10-15 min de holding)

EXEMPLE (KITE 08/02):
  19:32 → Détection surge +1.5% en 3 min avec volume x5
  19:32 → Achat immédiat @ 0.1395
  19:41 → Prix commence à baisser, trailing stop touché
  19:41 → Vente @ 0.1410 → +1.1% en 9 minutes

USAGE:
  python market_spy.py                 # Mode continu (défaut)
  python market_spy.py --dry-run       # Simulation sans achat
  python market_spy.py --once          # Un seul scan

═══════════════════════════════════════════════════════════════════════════════
    N)datetime	timedeltatimezone)	urlencode)defaultdict)ZoneInfozEurope/Parisreturnc                  4    t        j                  t              S )z,Retourne l'heure actuelle en timezone Paris.)r   nowPARIS_TZ     market_spy.py	now_parisr   5   s    <<!!r   )get_behavior_detectorBehaviorRegimeTFspy_optimizer)SignalClassifier)compute_features_at_timestamp)BINANCE_API_KEYBINANCE_API_SECRETTESTNET_MODEMAX_OPEN_POSITIONSMIN_ORDER_SIZEMAX_ORDER_SIZEu#   ❌ Impossible de charger config.py   zhttps://api.binance.comzhttps://testnet.binance.vision` iP  gMb@?         ?皙?      @         @      @333333?iX           @g      @333333?皙?           $@ih                I@      D@g      ^@g      .NOMUSDC0GUSDC       @)ENJUSDC
GIGGLEUSDCTSTUSDCBROCCOLI714USDCc                     	 t         j                  j                  t        d      } t         j                  j	                  |       rKt        | dd      5 }t        j                  |      }ddd       t        j                  dt                    S 	 t        t              S # 1 sw Y   8xY w# t        $ r Y t        t              S w xY w)z,Charge positionSize depuis bot_settings.jsonzbot_settings.jsonrutf-8encodingNpositionSize)ospathjoin
SCRIPT_DIRexistsopenjsonloadfloatgetr   	Exception)settings_pathfsettingss      r   _load_position_sizerM      s    Z1DE77>>-(mS7; (q99Q<(nnEFF )   ( (    s*   AB, B )&B,  B)%B, ,	CC      ?333333?      ?<   皙?   
   gRQ?c                     | dk\  rd}n"| dk\  rd}n| dk\  rd}n| dk\  rd}n
| d	k\  rd
}nd}|dk\  rt        |dz  d      }n|dk\  rt        |dz  d      }t        |d      S )u   TP de référence — plafond de sécurité max (sortie réelle = trailing stop).
    Stocké dans la position pour lisibilité des logs/dashboard.
    Le trailing stop active bien avant ce seuil dans la majorité des cas.
    r#   g      9@r!         4@r4         .@rN   r,   r          @r$         @?      >@r    r   )minround)surge_strength	vol_ratiobase_tps      r   get_dynamic_tpra      s     	3		3		3		3	CgmT*	c	gmT*!r   c                 v    |dk\  ry|dk\  rt         S |dk\  rt        S |dk\  ry|dk\  ry|dk\  ry|dk\  ry	t        S )
u6  Trailing dynamique v2 — optimisé sur 160 trades réels.
    
    PROBLÈME v1: trailing 0.3% pour PnL < 2% trop serré → coupe les winners
    pendant les micro-dips normaux d'un pump (+19% gains laissés sur 30 trades).
    
    FIX 14/02: Trailing PROGRESSIF entre 0.5% et 2% de gains:
    - PnL ≥ 15% → trailing -5.0% (mouvement explosif type BERA +25%)
    - PnL ≥ 10% → trailing -4.0% (mouvement exceptionnel)
    - PnL ≥ 5%  → trailing -2.5% (gros surge confirmé)
    - PnL ≥ 3%  → trailing -1.8% (surge confirmé, laisser respirer)
    - PnL ≥ 2%  → trailing -1.5% (surge en cours)
    - PnL ≥ 1%  → trailing -0.7% (pump confirmé, micro-dips normaux)
    - PnL 0.5-1% → trailing -0.5% (en montée, pas trop serrer)
    - PnL < 0.5% → trailing -0.3% (juste activé, protéger)
    rW   rY   r,   r!   r4   g?r   rP   ffffff?)TRAILING_STOP_ULTRATRAILING_STOP_LARGETRAILING_STOP_PCT)r^   current_pnls     r   get_dynamic_trailingrh      s]      dd""c""ccccr   c                 &   | j                  dg       }t        |      dk  ryt        |      dz  }t        |d|       |z  }t        ||d       t        |      |z
  z  }t        |dd       }| j                  d|d         }||d	z  kD  xr ||d
z  kD  S )u  Détecte si le prix est en tendance haussière à partir du mini-historique.
    
    Retourne True si le prix fait des higher-lows (tendance soutenue).
    Utilisé pour élargir les trailing et désactiver le MOMENTUM_EXIT.
    
    Logique:
    - Besoin d'au moins 5 points de données (50s de scan)
    - Calcule la moyenne de la 1ère moitié vs la 2ème moitié
    - Si la 2ème moitié est > 1ère moitié ET le prix actuel > prix min récent + 0.3%
      → tendance haussière confirmée
    last_pricesr"   Fr+   Nentry_pricer   gjt?gV-?)rH   lensumr\   )posrj   halfavg_oldavg_new
min_recentrl   s          r   _detect_uptrendrt      s     ''-,K
;!{q D+et$%,G+de$%[)9D)@AG[%&J''-Q8KWu_$IkE6I)IIr   positions.jsonzwatchlist.jsonzespion_trades.jsonzespion_opportunities.jsonzespion_history.jsonzspy_status.jsonzspy_coin_scores.jsonzspy_loss_state.json   >	   DAIUSDCEURUSDCGBPUSDCBUSDUSDCTUSDUSDCUSDPUSDCUSDTUSDCUSTCUSDC	FDUSDUSDCc                     ddddddd} 	 ddl m}  |       }|r|j                         \  }}|| d<   |j                  d	i       }|j                  d
i       }|j                  dd      | d<   |j                  dd      | d<   |j                  dd      | d<   | d   dkD  xr | d   dkD  xr | d   dkD  | d<   | d   dk  xr | d   dk  | d<   | S # t        $ r Y | S w xY w)u  
    Lit le contexte macro (BTC momentum, % alts haussiers) depuis market_regime.
    Retourne un dict utilisé pour adapter les seuils de confirmation et de sortie.

    Clés retournées:
      regime           : BULL_STRONG / BULL_WEAK / NEUTRAL / CORRECTION / BEAR
      btc_mom_3h       : momentum BTC sur 3h (%)
      btc_mom_5h       : momentum BTC sur 5h (%)
      bullish_pct      : % altcoins en tendance haussière (0-100)
      is_recovery_window : BTC 5h > 0.1% ET 3h > -1.0% → rebond en cours
                           → assouplir les seuils pour capturer les premiers movers
      is_freefall      : BTC 3h < -2% ET alts bullish < 30% → chute libre
                           → bloquer les entrées (sauf FLASH fort >= 1.5%)
    NEUTRAL        r0   F)regime
btc_mom_3h
btc_mom_5hbullish_pctis_recovery_windowis_freefallr   )get_market_regime_detectorr   btcaltsmom_3hr   mom_5hr   r   皙?      r[   r   g       r   )market_regimer   detect_regimerH   rI   )ctxr   detectorregime_namemetricsr   r   s          r   get_btc_market_contextr   %  s4     #C<-/#+#9#9#; K'CM++eR(C;;vr*D ## 6C ## 6C!%-!>C L!C' .%,.&- $% L!D( .&-  J  Js   B>C 	CCc                       e Zd ZdZddZy)ParisTimeFormatterz?Formateur qui affiche l'heure de Paris (UTC+1/+2 selon saison).Nc                     t        j                  |j                  t              }|r|j	                  |      S |j	                  d      S )N)tz%H:%M:%S)r   fromtimestampcreatedr   strftime)selfrecorddatefmtcts       r   
formatTimezParisTimeFormatter.formatTime^  s9    ##FNNx@;;w''{{:&&r   N)__name__
__module____qualname____doc__r   r   r   r   r   r   \  s
    I'r   r   
market_spyz%(asctime)s [SPY] %(message)sr   )r   zmarket_spy.logr;   r<   zinvalid_symbols_cache.jsonc                      	 t        t        d      5 } t        t        j                  |             cd d d        S # 1 sw Y   y xY w# t
        $ r t               cY S w xY w)Nr:   )rD   _INVALID_SYMBOLS_CACHE_FILEsetrE   rF   rI   )rK   s    r   _load_invalid_symbols_cacher   ~  sN    -s3 	%qtyy|$	% 	% 	% us*   A :	A AA A AAsymbolsc                     	 t        t        d      5 }t        j                  t	        |       |       d d d        y # 1 sw Y   y xY w# t
        $ r Y y w xY w)Nw)rD   r   rE   dumpsortedrI   )r   rK   s     r   _save_invalid_symbols_cacher     sL    -s3 	*qIIfWoq)	* 	* 	* s+   A  ;A A A A 	AAc                   p    e Zd ZU dZdZdZ e       Zee	d<   d Z
d Zd ZddZdd	Zdd
Zd ZddZd Zy)SpyApiClientu&   Client API ultraléger pour le scannerr   _invalid_symbolsc                 `   t         | _        t        | _        t	        j
                         | _        | j                  j                  j                  d| j                  i       t        j                  j                  ddd      }| j                  j                  d|       | j                          y )NzX-MBX-APIKEYr+      r   )pool_connectionspool_maxsizemax_retrieszhttps://)r   api_keyr   
api_secretrequestsSessionsessionheadersupdateadaptersHTTPAdaptermount_sync_server_time)r   _adapters     r   __init__zSpyApiClient.__init__  s    &,'')##^T\\$BC$$00QA 1 
 	:x0 r   c                 >   	 | j                   j                  t         dd      }|j                         d   }t	        t        j
                         dz        }||z
  t        _        t        j
                         t        _        y # t        $ r dt        _        Y y w xY w)Nz/api/v3/timer"   )timeout
serverTime  r   )
r   rH   TRADING_APIrE   inttimer   TIME_OFFSET
_last_syncrI   )r   respserver_time
local_times       r   r   zSpyApiClient._sync_server_time  s~    	)<<##{m<$@!#LD))+l3KTYY[4/0J'2Z'?L$&*iikL# 	)'(L$	)s   BB BBc                     t        |      }t        j                  | j                  j	                  d      |j	                  d      t
        j                        j                         }|S )Nr;   )r   hmacnewr   encodehashlibsha256	hexdigest)r   paramsquery_string	signatures       r   _signzSpyApiClient._sign  sU     (HHOO""7+(NN
 )+	 	
 r   Nc                    	 | j                   j                  ||d      }|j                         }t        |t              r|j                  dd      dk  ry |S # t
        $ r"}t        j                  d|        Y d }~y d }~ww xY w)NrT   r   r   coder   zAPI error: )r   rH   rE   
isinstancedictrI   loggererror)r   urlr   r   dataes         r   
public_getzSpyApiClient.public_get  sw    	<<##C#CD99;D$%$((61*=*AK 	LL;qc*+	s   AA A 	B!A>>Bc                    |i }t        j                          t        j                  z
  dkD  r| j                          t	        t        j                          dz        t        j
                  z   |d<   d|d<   | j                  |      |d<   t         | }	 |dk(  r| j                  j                  ||d	      }n| j                  j                  ||d	      }|j                         }t        |t              r|j                  d
      dv r| j                          t	        t        j                          dz        t        j
                  z   |d<   |j                  dd        | j                  |      |d<   |dk(  r| j                  j                  ||d	      }n| j                  j                  ||d	      }|j                         }t        |t              r|j                  d
d      dk  r|j                  d
d      }|j                  dd      }|dk(  r|j                  dd      }	|	rn|	t        j                  vr\t        j                  j!                  |	       t#        t        j                         t$        j'                  d|	 dt(        rdnd d       t$        j+                  dt(        rdnd d| d       y t$        j+                  d| d|        y |S # t,        $ r"}
t$        j+                  d|
        Y d }
~
y d }
~
ww xY w)N,  r   	timestampi'  
recvWindowr   POSTrS   r   r   )iir   msgunknownisymbol u   ⛔ u7    ajouté à la blacklist invalide — paire absente du testnetprodu    (plus jamais tenté)z API error: symbole invalide sur u    — z7 (cette paire n'existe probablement pas sur le testnet)zAPI error [z]: zSigned request error: )r   r   r   r   r   r   r   r   r   postrH   rE   r   r   popr   addr   r   warningr   r   rI   )r   methodendpointr   r   r   r   
error_code	error_msg_bad_symr   s              r   signed_requestzSpyApiClient.signed_request  s   >F99;00036""$!$))+"458P8PP{$|"jj0{hZ(#	||((VR(H||''FB'G99;D$%$((6*:n*L&&(&)$))+*<&=@X@X&X{#

;-&*jj&8{#V#<<,,S,LD<<++C+KDyy{$%$((61*=*A!XXfa0
 HHUI6	&%zz(B7HHL4Q4Q$Q$5599(C3L4Q4QRhZ7n  }Iox  OU  oV  Vk  (l  mLL#CQ]IciCjjopyoz  {r  "s  t  LL;zl#i[!IJK 	LL1!56	s%   H&K <K K 	L#L  Lc                     | j                  dd      }|r/|j                  dg       D ]  }|d   |k(  st        |d         c S  y)NGETz/api/v3/accountbalancesassetfreer   )r   rH   rG   )r   r  accountbs       r   get_balancezSpyApiClient.get_balance  sR    %%e->?[[R0 ,W:& 6++, r   c                 :    |dd|dd}| j                  dd|      S )NBUYMARKET.2f)r   sidetypequoteOrderQtyr   /api/v3/order)r   )r   r   usdt_amountr   s       r   
market_buyzSpyApiClient.market_buy  s1     +C0	
 ""6?FCCr   c           
         dD ]$  }|j                  |      s|dt        |        } n |}	 | j                  |      }|dkD  r&||k  r!t        j	                  d| d| d| d       |}|s	 | j                  |      }|rI|dkD  rDt        dt        t        t        j                  |                         }t        |||z  z
  |      }|dd	| d
}| j                  dd|      S # t
        $ r Y w xY w# t
        $ r Y w xY w)u   Vente market avec quantité exacte.
        🔧 FIX -2010: Binance déduit les frais (0.1%) du token reçu à l'achat,
        donc le solde réel est < executedQty stocké. On vérifie le vrai solde.
        USDCUSDTBUSDBTCETHBNBNr   zmarket_sell: u    solde réel u    < qty stockée u    → ajustement (frais)SELLr
  )r   r  r  quantityr   r  )endswithrm   r  r   debugrI   get_symbol_step_sizemaxr   r]   nplog10r   )	r   r   r  	step_sizequoter  real_balance	precisionr   s	            r   market_sellzSpyApiClient.market_sell  sB    C 	Eu%|U,	
 E	++E2LaL8$;}UG=N^_g^hh  A  B'
  55f=	 QAE"((9*=$> ??@IXI)=>	JH #*	
 ""6?FCC)  		  s#   <C# ,C2 #	C/.C/2	C>=C>c                     | j                  t         dd|i      }|rLd|v rHt        |d         dkD  r7|d   d   }|j                  dg       D ]  }|d   dk(  st	        |d         c S  y	)
u;   Récupère step_size du symbole pour la précision de ventez/api/v3/exchangeInfor   r   r   filters
filterTypeLOT_SIZEstepSizeN)r   r   rm   rH   rG   )r   r   r   sym_inforK   s        r   r  z!SpyApiClient.get_symbol_step_size(  s    +.BChPVEWXI%#d9o*>*BIq)H\\)R0 0\?j0 ://0 r   r   )r  )r   r   r   r   r   r   r   r   r   __annotations__r   r   r   r   r   r  r  r&  r  r   r   r   r   r     sP    0KJ 89c9
!)	,\D'DRr   r   c                   8    e Zd ZdZd Zd Zd	dZd Zd Zd
dZ	y)SurgeDetectoruE  
    Détecte les hausses soudaines en comparant les snapshots de prix.
    
    Principe:
      - Chaque scan stocke le prix de TOUTES les paires
      - On compare scan N vs scan N-1 et N-2
      - Si hausse > seuil en si peu de temps → SURGE détecté
      - Confirmation rapide avec klines 1m (volume + direction)
    c                    t        t              | _        d| _        i | _        d| _        d| _        i | _        t        t              | _	        i | _
        | j                          t        t              | _        i | _        g | _        y )N     r   )r   listprice_historymax_historycooldowncooldown_secondscooldown_winlast_exit_winr   coin_consec_lossescoin_loss_blocked_until_load_loss_state_lt_snapshots_lt_last_ts_lt_trades_hourr   s    r   r   zSurgeDetector.__init__B  sv    (. # #.c"2')$(.!r   c                   8 t        j                          }g }|D ]  }|j                  dd      }	 t        |j                  dd            }t        |j                  dd            }t        |j                  dd            }|dk  rn| j
                  |   }	|	j                  ||f       t        |	      | j                  kD  r,|	| j                   d | j
                  |<   | j
                  |   }	| j                  j                  |d      }
||
z
  t        k\  rj| j                  |   j                  |       t        | j                  |         t        kD  r| j                  |   j                  d       || j                  |<   t        |	      dk  rv|| j                  v rK| j                  j                  |d	      r| j                   n| j"                  }|| j                  |   z
  |k  r|| j$                  j                  |d      k  r|	d
   d   }||z
  |z  dz  }d}t        |	      dk\  r|	d   d   }||z
  |z  dz  }d}t        |	      dk\  r|	d   d   }||z
  |z  dz  }d	}d}d}|t&        k\  rd}d}|}n|t(        k\  r|dk\  rd}d}|}|st        |	      dk\  r||	d   d   z
  |	d   d   z  dz  }d}t        |	      dk\  r||	d   d   z
  |	d   d   z  dz  }d| }| j                  j                  |d      }||z
  t*        k\  }t-        | d      sg | _        | j.                  D cg c]  }||z
  dk  s| c}| _        t        | j.                        t0        k  }|r|r|t2        k\  rd	}d}|t4        k\  rd}|}n|t6        k\  rd}|}|r||k(  rdnd}t9        |dz  d      }d} t;        d      D ]e  }!|dz    |!|z  z   }"|"|z   }#|#dk\  rd}#t=        |"      t        |	      k  s3t=        |#      t        |	      k  sK|	|"   d   }$|	|#   d   }%|%|$kD  sa| dz  } g | dk\  r0d}d }|}|| j                  |<   | j.                  j                  |       |st        |	      d!k\  r||	d"   d   z
  |	d"   d   z  dz  }&d}'t        |	      d#k\  r||	d$   d   z
  |	d$   d   z  dz  }'d%| }(| j                  j                  |(d      })||)z
  t>        k\  }*t-        | d&      sg | _         | j@                  D cg c]  }||z
  dk  s| c}| _         t        | j@                        tB        k  }+|*r|+r |tD        k\  r|tF        k\  rd	},d}-d}.|'tH        k\  rt        |	      d#k\  rd},|'}-d'}.n|&tJ        k\  rd},|&}-d(}.|,rt9        |.dz  d      }d} t;        d      D ]e  }!|.dz    |!|z  z   }"|"|z   }#|#dk\  rd}#t=        |"      t        |	      k  s3t=        |#      t        |	      k  sK|	|"   d   }$|	|#   d   }%|%|$kD  sa| dz  } g | dk\  r0d}d)}|-}|| j                  |(<   | j@                  j                  |       	 |stY        |d      }5|dk(  xr |d*k\  }6|d+vrtZ        n|6rt\        nt^        }7| j                  j                  |d	      rta        |7d,      }7|5|7kD  rBtb        je                  d-| d.|5 d/|7 d0| j                  j                  |d	      rd1nd d2	       |5tf        k  r/|dk(  r|d3k\  s%tb        ji                  d-| d4|5 d5tf         d6       |dk(  r-|d7k  r(|5d8k  r#tb        ji                  d-| d9|d:d;|5d:d<       |5d=kD  r+|d>vr'|d*k  r"tb        ji                  d-| d?|5d:d@| dA       O|j                  ||tY        |d      tY        |d      tY        |d      ||5|tY        |d      |dB
        |S # t        t        f$ r Y w xY wc c}w c c}w )Cuo   
        Met à jour les prix depuis les tickers 24h.
        Retourne la liste des surges détectés.
        r   r   	lastPricer   quoteVolumepriceChangePercentNr+   Fr   d   r&   rk   r-   iTFLASH_SURGErP   BREAKOUT_SURGE   i)   i
_momentum__momentum_trades_hourr/      (   rv   MOMENTUM_SURGEV   i   i}_trend_mom__trend_momentum_trades_hour   U   TREND_MOMENTUM_SURGEr!   )rG  rH  g     A@u
      ⏭️ z : pre-filtre already_pumped_24h(% > %z [re-entry post-gain]u    ) — skip sans appel API klinesr4   z: pre-filtre downtrend_24h(% < u$   %) — micro-rebond dans chute, skiprN         u"   : pre-filtre surge_faible_déclin(.1fz%<1.5%, u0   %/24h) — impulsion bruit en tendance négativerV   )rG  z: pre-filtre pump_excessif_24h(z%>20%) sur u!    — risque achat en fin de cycle)
r   pricechange_1scanchange_2scanchange_5scan
volume_24hprice_change_24h
surge_typer^   r   )5r   rH   rG   
ValueError	TypeErrorr4  appendrm   r5  r>  LONG_TREND_SNAPSHOT_INTERVALr=  LONG_TREND_MAX_SNAPSHOTSr   r6  r9  r8  r7  r;  SURGE_MIN_PRICE_CHANGESURGE_MIN_PRICE_CHANGE_2MOMENTUM_COOLDOWNhasattrrL  MOMENTUM_MAX_PER_HOURMOMENTUM_MIN_CHANGE_1MOMENTUM_MIN_CHANGE_40MOMENTUM_MIN_CHANGE_20r  rangeabsTREND_MOMENTUM_COOLDOWNrT  TREND_MOMENTUM_MAX_PER_HOURTREND_MOMENTUM_MIN_CHANGE_1TREND_MOMENTUM_MIN_CHANGE_5TREND_MOMENTUM_MIN_CHANGE_130TREND_MOMENTUM_MIN_CHANGE_85LONG_TREND_MIN_SNAPSHOTSLONG_TREND_MIN_RISErn   r?  LONG_TREND_MAX_PER_HOURLONG_TREND_COOLDOWNr]   !SURGE_MAX_ALREADY_PUMPED_TRENDING&SURGE_MAX_ALREADY_PUMPED_EXTREME_FLASHSURGE_MAX_ALREADY_PUMPEDr\   r   r  SURGE_MAX_DECLINE_24Hinfo)9r   tickersr   surgestickerr   r]  ra  rb  history_lt_lastcd_time
prev_pricechange_1change_2prev2_pricechange_5prev5_priceis_surgerc  r^   	change_20	change_40_mom_cd_key	_mom_last
_mom_cd_okt_mom_hourly_ok_mom_detected_mom_strength_win_quarter_rising_quarters_q
_idx_start_idx_end_p_start_p_end	change_85
change_130
_tm_cd_key_tm_last	_tm_cd_ok_tm_hourly_ok_tm_detected_tm_strength_tm_win
_lt_oldest_lt_rise_lt_pos_lt_monotone_t
_lt_cd_key	_pump_24h_is_extreme_pre_max_pump_pre	_lt_snapss9                                                           @r   update_priceszSurgeDetector.update_pricesS  sT	   
 iik E	FZZ"-Ffjja89"6::mQ#?@
#(4H!)L#M  z ((0GNNC<( 7|d...-4d6F6F5F5G-H""6*,,V4 ''++FA6HX~!==""6*11%8t))&125MM&&v.2215+.  ( 7|a &/3/A/A/E/Efe/T$++Z^ZoZov..8T1155fa@@
 !QJ+z9S@H H7|q %bk!n"[0K?3F H7|q %bk!n"[0K?3F HJN 11*
!) 55(c/-
!) G 2#gcl1o5aHCO		w<2%"''#,q/"9WS\!_!LPS SI *6(3 MM--k1=	!Io2CC
t%<=13D.9=9S9S-fAWZ]^W^aeWea-f*!$T%?%?!@CX!X.XAV5V$)M$%M $::(,(1"&<<(,(1 %%2i%?rR#&tqy!#4+,("'( 	:B+/!8rH})DJ'1H'<H'1}+-":#g,>3x=TWX_T`C`+2:+>q+A)0):1)=#)H#4$4$9$4	: ,q0'+H)9J-:N9<DMM+6 66==cB G 2#gcl1o5aHCO	
w<3&#(74=+;#;wt}Q?O"OSV!VJ*6(3
==,,Z; 8^0GG	t%BC79D4?C?_?_3r!cfijcjmqcqA3r0 #D$D$D EHc c8?Z3Z_g  lG  `G#(L#$LG!%BBs7|WZGZ'+'1"%"&BB'+'0"$##&w!|Q#7+,("'( 	:B+2Q;"x-)GJ'1H'<H'1}+-":#g,>3x=TWX_T`C`+2:+>q+A)0):1)=#)H#4$4$9$4	: ,q0'+H)?J-9N8;DMM*5 <<CCCH *  ""2A6	#-#>#X>UXCXFPXyFy!BQ`'Mf~  %%))&%8$'t$<M},LL:fX5UV_U``derdsst?C?Q?Q?U?UV\^c?d$;jl#m#C"E F !66
m@[`nru`uKK*VH4OPY{Z^_t^u vE !F G
  =0^c5IiZ^N^KK*VH4VWefiVjjrs|  ~A  sB  Br  !s  t
 %*<L*LQ_beQeKK*VH4ST]^aSbbmnxmy  z[  !\  ]MM"(!&(-h(:(-h(:(-h(:&0,5&0*/*B%(# uE	N A 	* x .gl 4ss*   A^2+_9_/_=_2__Nc                   PQ |i }|j                  t         d|ddd      }|rt        |      dk  rddd	ifS |D cg c]  }t        |d
          c}P|D cg c]  }t        |d          c}Q|D cg c]  }t        |d          }}|D cg c]  }t        |d          }}|D cg c]  }t        |d          }	}|	d   }
t        |	      dkD  rt	        j
                  |	dd       n|
}|dkD  r|
|z  nd}|dkD  rt        |	      dkD  r|	d   |z  nd}t        ||      }g }|D ]   }	 |j                  t        |d                " |r|d   nd}t        |      dkD  r|d   n|}|	d   dkD  r||	d   z  nd}t        |	      dkD  r|	d   dkD  r||	d   z  nd}t        ||      }t        |      dkD  rt        |dd       t        |dd       z  n|xs d}|dkD  r||z  nd}|dk\  }|dk  xr |dkD  }|j                  dd      }|dv }|xr |dk  }t        PQfdt        dd      D              }t        P      d
k\  rPd   Pd   z
  Pd   z  dz  nd}d }dd } |Pd      } t        P      d!k\  r	 |Pd!      n |Pt        P            }!| |!k  }"t        P      d"k\  r |Pdd d      }#|#dkD  r| |#z
  |#z  dz  nd}$nd}$|$d#k  }% |P      }&t        P      d$k\  rPd   Pd   z
  Pd   z  dz  nd}'t        Pfd%t        dt        t        P      d&            D              }(Pd   Qd   kD  })t        Pd   Qd   z
        }*|d   t        Pd   Qd         z
  }+|*dkD  r|+|*dz  kD  nd},t        |      dkD  rt        |dd       n|d   }-Pd   |-z
  |-z  dz  }.|.d'kD  }/t        |      d(k\  rt        |d)d       n t        |      dkD  rt        |dd       n|d   }0t        |      dkD  rt        |dd       n t        |      dkD  rt        |dd       n|d   }1|0|1z
  |1z  dz  }2|2d*k  xr Pd   |1d+z  k  }3i d,t        |d      d-|d.t        |d      d/|)d0|,d1t        |
d      d2t        |d      d3t        |.d      d4|3d5|&d6|"d7t        |$d      d8|%d9t        |'d      d:|(d;t        |d      d<t        |d      ||d=}4|j                  d>d      }5|j                  d      d?k(  xr |5dk\  }6|j                  d      d@v xr |" }7|j                  d      d?k(  xr |5dAk\  }8|j                  d      dBk(  }9|j                  d      dCk(  }:|j                  dDd      };|j                  dEd      }<|j                  dFd      }=|j                  dGdH      }>d}?|;rdI}?n|<rdJ}?n|=d*k  rdK|=dLdM}?dN}@g }A|j                  dOPd         }B|BdkD  rBPd   z
  |Bz  dz  nd}C|d   dkD  r|d   Pd   z
  |d   z  dz  nd}D|8sb|9s`|:s^|6rdnd'}EC|EkD  r.|j                  d>d      dPk  rd}@Aj                  dQCdLdR       n%DdSkD  r Pd   Bk  rd}@Aj                  dTDdLdU       |8rdV}Fn |6rdW}Fn|9rdW}Fn|:rdX}Fn|7rdW}Fn|;rdY}Fn|<rdP}Fnd}F|Fk  r+|r|FdZz  k\  r|dk\  rnd}@Aj                  d[|dLd\F d]       |8rdn|6s|9rdnd}G||Gk  rd}@Aj                  d^| d_       |,r|8sd}@Aj                  d`       |)s |8s|6r|dkD  s|7s|9sd}@Aj                  da       |8rn|9r>|dbk  rd}@Aj                  dc|ddde       n|"r|&dfkD  rd}@Aj                  dg|&dhdi       n|6r|d*k  rd}@Aj                  dj|dddU       n|;r|dkk  rd}@Aj                  dl|dddU       nj|<r|dk  rcd}@Aj                  dm|dddn       nJ|j                  d      dok(  rdkn|j                  d      dpv rdbndV}H||Hk  rd}@Aj                  dq|dddU       |6s&|7s$|9s"db}I|.|Ik  rd}@Aj                  dr|.dsdtI dU       |7rdundv}J|2|Jk  xr Pd   |1d+z  k  }K|Kr|6sd}@Aj                  dw|2dxdU       |8r|dyk\  r	|rt         }Ln|7rt"        }Lnt$        }L|j                  dzd      LkD  rd}@Aj                  d{|dz    dU       |rFd}@t        |dz        }MAj                  d||M d}|dLd]       t&        j)                  d~|dLd|M d       |6rZ|dk  rU|dk  rPd}@Aj                  d|dLdt        |dz         d       t&        j)                  d|dLdt        |dz         d       |rC@rAd}@t        |dz        }NAj                  d|N d       t&        j)                  d| d|N d       |&dk  r8|"r6|8s4d}@Aj                  d|&dLd       t&        j)                  d|&dLd       nb|"rH|'d*k  rC|(d"k\  r>|6s<|8s:d}@Aj                  d|'dxd|( d       t&        j)                  d|'dxd|( d       n|'dvk  r>|(dk\  r9d}@Aj                  d|'dxd|( d       t&        j)                  d|'dxd|( d       n|%rX|8sV|6r|5dk\  sO|"st&        j)                  d|$dsd       d}@Aj                  d|$dsdU       t&        j)                  d|$dsd       n{|"ry|6rw|5dyk  rr|8sp|j                  dd      }O|OdPk  r;d}@Aj                  d|5dddOddd       t&        j)                  d|5ddd|Oddd       nt&        j)                  d|5dddOddd       @|4d<   A|4d<   |?|4d<   |@|4fS c c}w c c}w c c}w c c}w c c}w # t        t        f$ r |j                  d       Y 
_w xY w)u  
        Confirmation rapide avec klines 1m (dernières bougies).
        Vérifie: volume spike + direction haussière + pas de rejet.

        market_ctx (optionnel): dict retourné par get_btc_market_context().
          - is_recovery_window → seuils assouplis (capturer les premiers movers du rebond)
          - is_freefall        → seuils durcis (pumps instables en chute libre)
        N/api/v3/klines1mr   r   intervallimitr&   Freasoninsufficient_klinesrv   r   r+   rO  r   rE  rT   r   rP   r   g(\?gffffff?rN   rc  r   )TRENDING_SURGEBUILDING_SURGE	SLOW_PUMPrP  LONG_TREND_SURGErW  g?c              3   :   K   | ]  }|   |   kD  sd   ywr   Nr   ).0iclosesopenss     r   	<genexpr>z.SurgeDetector.confirm_surge.<locals>.<genexpr>  s      JVAYq5I!Js   rk   rF  c                     t        |       |k  r	| r| d   S dS d|dz   z  }t        | d |       |z  }| |d  D ]  }||z  |d|z
  z  z   } |S NrO  r   r4   r   rm   rn   valsperiodkr   vs        r   _emaz)SurgeDetector.confirm_surge.<locals>._ema  sr    4y6!#'tBx0S0vz"AD&M"V+A&'] (EAQK'(Hr   c           	         t        |       |dz   k  ryt        dt        |             D cg c]  }t        | |   | |dz
     z
  d       }}t        dt        |             D cg c]  }t        | |dz
     | |   z
  d       }}t        || d        |z  }t        || d        |z  }|dk(  ryt	        ddd||z  z   z  z
  d      S c c}w c c}w )Nr   r0   r   g      Y@rF  )rm   rq  r  rn   r]   )r  r  r  gainslossesavg_gavg_ls          r   _rsiz)SurgeDetector.confirm_surge.<locals>._rsi  s    4y6A:%:?3t9:MNQSa4!9,a0NEN;@CI;NOac$qs)d1g-q1OFOvgh(61Ewx()F2Ezsa%%-&788!<< OOs   C"C
   r   g333333ÿrS   c              3   @   K   | ]  }|   |d z
     k  sd   ywr  r   )r  r  r  s     r   r  z.SurgeDetector.confirm_surge.<locals>.<genexpr>  s)     _vaySYZ[\]Z]S^G^!_s      r%   r"   r   gGz?r_   green_count_3mom_3mcurrent_green	rejectioncurrent_vol_usdtavg_vol_usdtbreakout_marginis_v_bouncersiema_bearishema7_slope_pctema7_decliningmom_15mred_bars_15	buy_ratiobuy_vol_spike)strong_buy_pressuresell_pressurer^   rG  )r  r  r  rW  r!   rP  rW  r   r   r   r   r0   z [REBOND: seuils assouplis]z [FREEFALL: seuils durcis]z [BTC mom3h=r\  %]Tr]  r4   zsurge_retrace(z%_depuis_detection)r)   u   wick_trap(mèche_haute=%)rR   皙?g333333?rO   rc   zvol_low(zx<x)znot_bullish(z	/3 green)rejection_wickcurrent_redr   zmom_weak_momentum(r  z%<0.1%)F   z momentum_exhausted(EMA_bear+RSI=.0fz>70)zmom_negative_flash(皙?zmom_weak_rebond(zmom_insuffisant_freefall(z%<0.5%)r  )r  r  SUSTAINED_SURGEz	mom_weak(zno_breakout(+.2f%<g      r[  zv_bounce(drop=+.1fr'   rb  zalready_pumped_24h(zsell_pressure(buy=z
%<35%,vol=u+      🚫🔴 SELL PRESSURE: Volume élevé (zx) mais u"   % côté vendeurs → distributionzflash_no_buy_pressure(spike=zx,buy=z%<55%)u-      🚫 FLASH sans pression acheteuse: spike=zx, buy_ratio=u%   % → pas de réel intérêt acheteurztrend_weak_buyers(buy=u      🚫 TREND faible: z buy_ratio=u!   % < 55% requis → risque HARD_SL#   zrsi_trap(RSI=z+EMA_bearish)u      🚫🔴 RSI TRAP: RSI=u6   ≤35 + EMA9<EMA21 → dead cat bounce, achat interditzdowntrend_context(15m=z% z/15 red)u&      🚫 DOWNTREND: EMA_bearish mom15m=u   /15 rouges → dead cat bounce   zsevere_downtrend(15m=u      🚫 CHUTE SÉVÈRE: 15m=u   /15 rouges → BLOQUÉu)      ⚠️ EMA7 SLOPE < 0: EMA7 décline (u8   %/3 bougies) malgré EMA7>EMA25 → momentum faiblissantzema7_declining(slope=u      🚫 EMA7 DÉCLINANT: pente=u2   % < -0.15% → tendance s'affaiblit, achat bloquér`  z#flash_ema_bearish(EMA7<EMA25,surge=   %,Δ5=z%<2.0%)u!      🚫 FLASH EMA BEARISH: surge=u   % EMA7<EMA25 Δ5=u   %<2.0% → dead cat probableu       ✅ FLASH EMA BEARISH: surge=u   % EMA7<EMA25 mais Δ5=u+   %≥2.0% → vraie reprise, achat autorisé	confirmedrejection_reasonsmarket_label)   )r   SCAN_APIrm   rG   r   meanr  rf  
IndexErrorrd  rn   rH   rq  r\   rr  r]   r~  r}  r  r   r  )Rr   clientr   
surge_data
market_ctxklinesr  highslowsvolumes_quotecurrent_volavg_volr_   prev_vol_ratiobest_vol_ratiotaker_buy_volscurrent_buy_volprev_buy_volcurrent_buy_ratioprev_buy_ratiobest_buy_ratioavg_buy_volr  r  r  _surge_type_now_is_trend_type_weak_buy_for_trendgreen_countr  r  r  ema9_val	ema21_valema_bearish_now
_ema7_prevr  r  rsi_nowr  r  r  body
upper_wickr  max_recent_highr  is_genuine_breakoutmin_recent_lowmax_older_highrecent_dropr  detailsr^   is_strong_flashis_trendingis_extreme_flashis_momentumis_trend_momentumis_recoveryr   r   r   	mkt_labelr  reasonssurge_detect_priceprice_retrace_pctlast_wick_pct_retrace_limitvol_threshold	min_greenmin_mommin_breakoutdeep_v_bounce_thresholddeep_v_bounce
max_pumpedsell_pct
buy_pct_tr_c5r  r  sR                                                                                   @@r   confirm_surgezSurgeDetector.confirm_surged  sC    J""j'4!<

 Vq8%:;;;'-.!%!+.&,-qt-&,-qt--%+,ad,,.45qt55#B' 25]1Ca1G"''-,-[-4q[K')a	 9@!MHZ]^H^r*W4deY7  	+A+%%eAbEl3	+ 3A>"-c25n2E2I>"- ERRTDUXYDYOmB.??_bDGDVYZDZ_lmo_pst_tLmB.??z} 1>B PSSaObefOfN3B/03~cr7J3KKm|  nD  AD9Dq+5c -4,t3L8L %..r:(  -\  \,F$1F JU2q\JJ DGv;RSCS6":r
*fRj8C?YZ			= O(+Fr(9D$tFCPVK?X	"Y. v;!fSbk1-JKUXY>h3zACG_bN N'%/v, CFf+QSBSF2J*fQi73>YZ_U1c#f+r.B%C__ r
U2Y. 6":b	)*2YVBZr!;;
-1AXJ)5	 .1Z!^#eCRj/r"2J8OKsR-3 .1Y!^T"R[)SVW[S\_`S`T#2Yfjkmfn,/JNU3BZSVW\S]`aSaE#2Jglmogp&7>ISP!D(PVBZ.5:P-P
~q1
[
 eFA&
 ]	

 
 k1 5
 E'1-
 u_a8
 ;
 7
 ?
 eNA6
 n
 uWa(
 ;
" ~q1#
$ U=!4%
& $7*)
4 $(8!<%>>,7=Hb^_bMb nn\2  7B  B  Z  KZ  GZ%>>,7=Hb^_bMb nn\26FF&NN<8<RR !nn%95A!~~mU;!~~lC8
!~~mT: 	5I4I$&z#&6b9I	 (^^GVBZ@ "A%  &*,0BBSH+. 	
 GLBiRSmrVBZ/59<sBY\<M %4SN >1jnnEUWX6Y\_6_!	0A#/FFYZ[$6H)H!	!8s8K2NO MMMMMMMMM) #~9L'LQ^beQe!	.)=RbQR *Ao[\	"INN\+i@A -INN+,  $_#Wbkv!	}-  |!	!3F3<wGH Wr\!	!A'#dST}!	!4VCLCD}!	!1&R@A|!	!:6#,gNO(nn\:kIdWaWeWefrWs  xo  XoPS  uxG!	6#,b9: {; L-!	od-C2l^SUVW
 +6$4#&==e&*~`eOeBeINN^K+=R@A # 5:M?J:J1J>>,a0:=INN0<N1O0PPRST
 I^c12HNN/zNSVCWWYZ[KKEnUXEYYabjak  lN  O  P }s2~7LINN9-9LFSXYghkYkSlRmmstuKKGVYGZZghmn|  ~A  oA  iB  hC  Ch  i  j 9I~34JNN3J<vFGKK00AZLXyz{ b=_5EINN]73-}EFKK4WSMAwxy 4K14D_euINN3GD>K=PXYZKK@bQ\P]]{|} t^r 1INN274.;-xXYKK6wtnB{mSijk $4oR`dgRg"GW[G\ ]J K LINN2>$2GrJKKK9.9N  OA  B  C ^c5IRb..3CSy!	!D^TWDXX^_bcf^ggnop?s?S T##&s)+GI J >~c>R S((+Cy0[] ^  )'.#$"+'!!e /--,5( 
+ +%%c*+s/   mm6mm,m -m%% n	n	c                 H   	 t        j                          t        j                  j                  t              rt        t        dd      5 }t        j                  |      }ddd       j                         D ]i  \  }}|j                  dd      }|j                  dd      }|dkD  r|| j                  |<   t        |t        t        f      sU|kD  s[|| j                  |<   k t        j                  j                  t              rt        t        dd      5 }t        j                  |      }ddd       ddlm}m}	 j                         D ]  \  }}|j                  d      }
|
rt        |
t$              s*	  |j&                  |
      }|j(                  |j+                  |	j,                  	      }|j/                         }|kD  r3t1        | j                  j                  |d      |      | j                  |<    t7        fd
| j                  j                         D              }t8        j;                  d| d       y# 1 sw Y   xY w# 1 sw Y   $xY w# t2        t4        f$ r Y !w xY w# t<        $ r"}t8        j?                  d|        Y d}~yd}~ww xY w)uL   Charge l'état des pertes depuis le fichier JSON (survit aux redémarrages).r:   r;   r<   Nconsec_lossesr   blocked_until)r   r   )tzinfoc              3   4   K   | ]  \  }}|kD  sd   ywr  r   )r  sbur   s      r   r  z1SurgeDetector._load_loss_state.<locals>.<genexpr>1  s     Yuq"PRUXPXYs   u      📂 Loss state chargé: u    coin(s) encore bloqué(s)zLoss state load error: ) r   r?   r@   rC   SPY_LOSS_STATE_FILErD   rE   rF   itemsrH   r:  r   r   rG   r;  SPY_COIN_SCORES_FILEr   r   strfromisoformatrA  replaceutcr   r  rd  re  rn   r   r  rI   r  )r   rK   r   symr  nr@  scoresr   r   bu_isobu_dtbu_tsloadedr   r   s                  @r   r<  zSurgeDetector._load_loss_state  s:   &	8))+Cww~~12-sWE (99Q<D(!% JIC!4A$(HH_a$@M1u78//4!-#u>=SVCV<I44S9J ww~~23.gF *!!YYq\F*7!' IC!XXo6F!FC)@  6 6 6v > <</$)MMM$FE % 1 3;@C $ < < @ @a H%AD88=  Y(D(D(J(J(LYYFKK6vh>XYZC( (* *" '	2   	8LL21#677	8s}   A	I6 I"A,I6 I6 AI6 I1A
I6 <BI >AI6 II6 II6  I3/I6 2I33I6 6	J!?JJ!c                    	 i }t        t        | j                  j                               t        | j                  j                               z         D ]>  }| j                  j                  |d      | j                  j                  |d      d||<   @ t        t        dd      5 }t        j                  ||d       ddd       y# 1 sw Y   yxY w# t        $ r"}t        j                  d	|        Y d}~yd}~ww xY w)
u)   Sauvegarde l'état des pertes sur disque.r   )r?  r@  r   r;   r<   r+   indentNzLoss state save error: )r   r3  r:  keysr;  rH   rD   rE  rE   r   rI   r   r  )r   r   rL  rK   r   s        r   _save_loss_statezSurgeDetector._save_loss_state6  s    
	8D4 7 7 < < >?$tGcGcGhGhGjBkkl %)%<%<%@%@a%H%)%A%A%E%Ec1%MS	
 )3A -Q		$!,- - - 	8LL21#677	8s6   B%C 'C	 C 	CC C 	D C;;D c           
         t        j                          | j                  |<   ||dk  r| j                  |xx   dz  cc<   | j                  |   }|dk\  rd}n
|dk(  rd}nd}t        |xr d	|v       }|duxr |d
k  xr | }|rt	        |d      }d}	n|r|dkD  r|dz  }d|dd}	n|d|ddnd}	t        j                          |z   | j
                  |<   t        j                  d| d| d|dz   d|	        | j                          y|B|dkD  r<d| j                  |<   | j
                  j                  |d       | j                          yyy)u)  Marquer un symbole en cooldown. pnl=None → rejet, pnl<0 → perte, pnl>0 → gain.
        max_pnl: pic de gain durant le trade. Si < 0.25%, considéré comme timing-loss → blocage réduit.
        sell_reason: raison de vente (ex: INSTANT_REVERSAL → blocage minimum 30 min, jamais réduit).Nr   r   r&   i0*  r+   r/   r*   INSTANT_REVERSAL      ?  u!    [INSTANT_REVERSAL → 30min min]z [timing-loss max=r  u   % → ½ durée]z [max=r  r   u      🔒 : u&    perte(s) consécutive(s) → bloqué rQ   z min)
r   r6  r:  boolr  r;  r   r  rW  r   )
r   r   pnlmax_pnlsell_reasonrM  	block_secis_instant_reversalis_timing_losstags
             r   set_cooldownzSurgeDetector.set_cooldownD  s    !%		f?sQw##F+q0+''/AAv!	a 		 #'{'X7I[7X"Y%T1DgnaNaJaN"	40	9IO%N	*74.8HI3:3FwtnB/B3799;3JD((0KK(6("QC/UV_acVcUddhilhmno!!#_q./D##F+((,,VT:!!# ")_r   r   )NNN)
r   r   r   r   r   r  r=  r<  rW  re  r   r   r   r/  r/  7  s*    ""Obf"P(8T8!$r   r/  c                   z    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zdd
ZddZddZd Zd Zd Zed        Zy)SpyPositionManageru   
    Gère les positions spy avec monitoring serré (check à chaque scan ~12s).
    Stratégie: trailing stop très serré + vente rapide dès essoufflement.
    c                 N    || _         i | _        i | _        | j                          y r   )r  	positionsstep_size_cache_load_positions)r   r  s     r   r   zSpyPositionManager.__init__r  s$    !r   c                    	 t         j                  j                  t              r5t	        t        dd      5 }t        j                  |      | _        d d d        | j                          y # 1 sw Y   xY w# t        $ r
 i | _        Y /w xY w)Nr:   r;   r<   )
r?   r@   rC   SPY_TRADES_FILErD   rE   rF   ri  rI   _cleanup_orphaned_spy_positions)r   rK   s     r   rk  z"SpyPositionManager._load_positionsx  sl    	 ww~~o./3A 2Q%)YYq\DN2 	,,.2 2 	 DN	 s(   5A7 A+A7 +A40A7 7B
	B
c                    	 t         j                  j                  t              syt	        t        dd      5 }t        j                  |      }ddd       d}t        j                               D ]Z  }||   }t        |t              s|j                  d      dk(  s.|| j                  vs=||= d}t        j                  d	| d
       \ |r9t	        t        dd      5 }t        j                  ||dt                ddd       yy# 1 sw Y   xY w# 1 sw Y   yxY w# t"        $ r"}t        j%                  d|        Y d}~yd}~ww xY w)uQ   Supprime de positions.json les entrées MARKET_SPY absentes de espion_trades.jsonNr:   r;   r<   Fsource
MARKET_SPYTu      🧹 Positions.json: u    orphelin SPY supprimér   r+   rU  defaultzCleanup orphaned positions: )r?   r@   rC   POSITIONS_FILErD   rE   rF   r3  rV  r   r   rH   ri  r   r  r   rH  rI   r  )r   rK   main_positionschangedr   ro   r   s          r   rn  z2SpyPositionManager._cleanup_orphaned_spy_positions  s1   	=77>>.1ncG< .!%1.G~2245 `$V,c4(SWWX->,-NT^^3*62"&&>vhF]$^_` .#@ HAIIna3GH H . .H H 	=LL7s;<<	=sc   #D" D" D
;D" 
D" D" .4D" "D D" 
DD" DD" D" "	E+EEc                     	 t        t        dd      5 }t        j                  | j                  |dt
               d d d        y # 1 sw Y   y xY w# t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr   r;   r<   r+   rr  zErreur save: )	rD   rm  rE   r   ri  rH  rI   r   r   )r   rK   r   s      r   _save_positionsz"SpyPositionManager._save_positions  si    	.osW= D		$..!AsCD D D 	.LL=,--	.s3   A (AA A
A A 	A<A77A<c                 2   	 i }t         j                  j                  t              r0t	        t        dd      5 }t        j                  |      }ddd       |d   |d   |d   |d   d	|j                  d
      |d   |j                  dd      d|d   ddd||<   t	        t        dd      5 }t        j                  ||dt               ddd       y# 1 sw Y   xY w# 1 sw Y   yxY w# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)z/Enregistre dans positions.json du bot principalr:   r;   r<   Nrl   r  	stop_losstake_profitr	  order_idr   rc  SPY_PUMP_CATCHrq  r   F)rl   r  rz  r{  r  r|  r   patternrp  	max_pricer_  bb_breakout_entryr   r+   rr  zErreur save main: )r?   r@   rC   rt  rD   rE   rF   rH   r   rH  rI   r   r   )r   r   r   ri  rK   r   s         r   _save_to_mainz SpyPositionManager._save_to_main  s   	3Iww~~n-.#@ -A $		!I-  $M2 ,!+.#M2 HHZ0!+.88L2BC&!-0%*!If ncG< ?		)Qq#>? ?!- - ? ? 	3LL-aS122	3sM   7C+ CAC+ ,C
C+ CC+ C($C+ (C+ +	D4DDc                 |   	 t         j                  j                  t              rqt	        t        dd      5 }t        j                  |      }d d d        |v r<||= t	        t        dd      5 }t        j                  ||dt               d d d        y y y # 1 sw Y   KxY w# 1 sw Y   y xY w# t        $ r Y y w xY w)Nr:   r;   r<   r   r+   rr  )
r?   r@   rC   rt  rD   rE   rF   r   rH  rI   )r   r   rK   ri  s       r   _remove_from_mainz$SpyPositionManager._remove_from_main  s    		ww~~n-.#@ -A $		!I-Y&!&)ncGD G		)Qq#FG G ' .- -G G 		sF   5B/ B!B/ .B#B/ B B/ #B,(B/ ,B/ /	B;:B;c                    	 t         j                  j                  t              rt	        t        dd      5 }t        j                  |      }ddd       t               }d}j                         D ]  \  }}|j                  d      }|r)	 ddl
m}  |t        |            }	||	k\  rd|d<   d|d	<   d
}|j                  d      }
|
sV|j                  d	d      dkD  sl|j                  d      r~	 ddl
m}  |t        |
            }||z
  j                         dkD  rd|d	<   d
} |r| j                  |       |S 	 i S # 1 sw Y   xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y i S w xY w)uq   Charge spy_coin_scores.json (crée si absent). Auto-nettoie les blocked_until expirés et l'historique obsolète.r:   r;   r<   NFr@  r   parser?  T
last_tradeiQ )r?   r@   rC   rG  rD   rE   rF   r   rF  rH   dateutil.parserr  rH  rI   total_seconds_save_coin_scores)r   rK   r   r   rv  rL  entryrD  _dtparsebtr  lts               r   _load_coin_scoresz$SpyPositionManager._load_coin_scores  s   #	ww~~23.gF (!99Q<D(k"&**, !JC?3B!I!)#b'!2B"by9=o 69:o 6*.
 "'<!8J!eii&Ca&GPUPYPYZiPj!I!)#j/!:B #b779EA9:o 6*.-!2 **40A 4F 	E( (  ) ! !  ) ! !
  			s|   6E) D?=E) (E4E) E) E) 14E%E) ?EE) 	EE) EE) 	E&#E) %E&&E) )	E65E6c                 (   	 t         dz   }t        |dd      5 }t        j                  ||dt               ddd       t        j                  |t                y# 1 sw Y   $xY w# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)	z,Sauvegarde atomique de spy_coin_scores.json..tmpr   r;   r<   r+   rr  NzErreur save coin_scores: )
rG  rD   rE   r   rH  r?   rJ  rI   r   r  )r   rN  tmprK   r   s        r   r  z$SpyPositionManager._save_coin_scores  s}    	:&/Cc31 <Q		&!As;<JJs01< <  	:LL4QC899	:s-   A& A"A& A#A& &	B/BBc                 j   | j                         }|j                  |dddddddd      }|dxx   dz  cc<   t               j                         |d<   t	        |j                  dd      |z   d	      |d<   |dkD  r|d
xx   dz  cc<   d|d<   d|d<   n|dxx   dz  cc<   |dxx   dz  cc<   |d   t
        k\  rft               t        t              z   }|j                         |d<   t        j                  d| d|d    d|j                  d       dt         d	       |||<   | j                  |       y)uP   Met à jour le score du coin après chaque trade et applique le circuit breaker.r   Nr   )tradeswinsr  r?  r@  r  total_pnl_usdtr  r   r  r  rv   r  r?  r@  r  )hoursu      🔴 CIRCUIT BREAKER r\  u%    pertes consec. → bloqué jusqu'au z%d/%m %H:%M (zh))r  rH   r   	isoformatr]   SPY_CB_MAX_CONSEC_LOSSESr   SPY_CB_BLOCK_HOURSr   r   r   r  )r   r   pnl_pctpnl_usdtrN  r  block_untils          r   _update_coin_scorez%SpyPositionManager._update_coin_score  sZ   '')

6a#$
 
 	h1'k335l"'		2BC(H8(SUV"WQ;&MQM%&E/"%)E/"(Oq O/"a'"_%)AA'kI<N,OO)4)>)>)@o&.vhb9O8P Q,,7,@,@,O+PPRSeRffhj vv&r   c           
      8   | j                         }|j                  |      }|sy|j                  dd      }|j                  dd      }|j                  dd      }|j                  d      }|rY|dk  rT	 ddlm}	  |	|      }
t	               |
k  r8|dk\  rn2|
t	               z
  j
                  }d	d
|j                  dd       d| dfS |dk\  ry|dk\  r$|dk  r||z  }|dk  rd	d|dz  dd| d| d|dfS |dk\  r|dk  rd	d|dd| dfS y# t        $ r Y Qw xY w)u  Vérifie si le coin est bloqué par le circuit breaker.
        
        Critères stricts pour ne bloquer que les vrais perdants chroniques,
        pas les bons coins avec une série perdante temporaire.
        
        surge_strength: si >= 2.5%, les blocages stats (winrate/PnL) sont bypassés.
        Si >= 3.0% (flash extrême), même le blocage temporel est court-circuité —
        un breakout violent peut marquer un vrai retournement même sur un perdant.
        )Fr   r  r   r  r  r@  r  r!   TzCB: r?  u+    pertes consec. + PnL négatif → bloqué jr'   r   r[  r(   zCB: winrate rF  r  z% (/z), PnL r  iu   CB: PnL cumulé z USDT (z trades))r  rH   r  r  r   daysrI   )r   r   r^   rN  r  totalr  	total_pnlr@  dtparser  	remainingwrs                r   _is_coin_blockedz#SpyPositionManager._is_coin_blocked  s    '')

6"		(A&yy#II.2	 		/2Y!^<]+;#%,%')+%5$;$;	#tEIIoa,H+IItu~t  @A  &B   B  B S 
 A:)d*BDy|BsF3<s4&%PYZ^O_``` A:)c/+Id+;75'RRR-  s   4AD 	DDNc                 |   t        | j                        t        k\  rt        j	                  dt         d       y|| j                  v ryt        |t              r"|j                  d|j                  dd            nd}| j                  ||      \  }}|rt        j                  d| d	| d
       y|j                  dd      }t               }	d}
d}	 | j                  j                  d      }||
z  }t        |	t        ||	dz              }||	dz  kD  r"t        j                  d|dd|dd|	dd       d}t!        | d      rs| j"                  rg| j"                  j$                  rQ| j"                  j$                  }|j'                         }|dk  r&t        j                  d|j(                   d|d       ||z  }|dk  rt        j                  d|dd       yd}d}|xs d}|dk(  r|j                  d d!      }|d"v }|xr |j                  d#d      d$k\  }|d%k(  xr |d&k\  }|r|st        j                  d'| d(       y|d%k(  r<|s:|r|j                  d)d      nd}|d*k  rCt        j                  d+|d,d-|d.d/       y|s"|s |d0k  rt        j                  d1|d,d2       yd3}d4}n|d5k(  rd6}d7}n|dk(  rd8}d9}n| d:}||z  }t        |d      }t        j                  d;| d<|dd=       |dkD  r|n| j                  j                  d      }||d>z   k  rt        j	                  d?|d,d@       y	 | j                  j+                  t,         dAdB|i      }|r]t/        |j                  dC|dC               }|dC   |z
  |dC   z  dDz  }|dEkD  r)t        j                  dF| dG|d.dH|dIdJ|dC   dIdK	       yt0        s	 | j                  j+                  t,         dLdB|i      }|rjt/        |j                  dMd            }|dkD  rJ||dC   z
  |dC   z  dDz  }|t2        kD  r0t        j                  dF| dN|d,dOt2         dP|dIdQ|dC   dId       y|t4        j6                  v r%t        j	                  dR| dSt0        rdTndU dV       yt        j                  dW| dX| dY|d.dZ       	 | j                  j9                  ||      }|s$t        j;                  d[| d\t0        rdTndU        yt/        |j                  d]i g      d   j                  dC|dC               } t=        d^ |j                  d]g       D              }!|!dk(  rt/        |j                  d_d            }!| dk(  r%t/        |j                  d`d            }"|!dkD  r|"|!z  } | j                  j?                  |      }#|#r|#| j@                  |<   |r|j                  dad      nd}$tC        |d   |$      }%i db| dc|!dd| detD        dDz  z
  z  df| de|%dDz  z   z  dg|%dhdidj| dkddldmdn|j                  do      dptG        jH                  tJ        jL                        jO                         dqtQ        jP                         d |d    d|d   drdsdt|du| gd|r|j                  dvdw      ndw|r|j                  dxd      nd|j                  dyd      dz}&|&| j                  |<   | jS                          | jU                  ||&       t        j                  d{|! d|| d}|         t        j                  d~tD         d|% dtV         dtX         dtZ         d       y# t        $ r |	}Y w xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r9}'t        j;                  d| d	|'        t]        j^                          Y di}'~'ydi}'~'ww xY w)u/   Ouvre une position spy (achat market immédiat)u      ⚠️ Max z positions spyFstrengthr^   r   r^   u      🚫 r\  u	    → SKIPr   g̬?r  r&   g)\(?u!      💹 Réinvestissement: solde=r  u    USDC → position=z USDC (base=)r   _parent_spyu      🧠 Comportement u   : position ×.0%rT   u      🧠 Position trop petite (u    USDT) → SKIPBULLr   BEARrc  r   )r  r  r  r  ACCELERATING_SURGEr  r  g333333?rG  r!   u      🚫 BEAR régime: u'    bloqué (besoin BuyVol ≥85% en BEAR)r  r4   u      🚫 BEAR régime: FLASH r  u   % bloqué (buy_spike r\  zx < 2.0x requis)rN   u      🚫 BEAR régime: surge u   % < 1.5% requis → BLOQUÉrP   u#   BEAR (50% — flash fort autorisé)
CORRECTIONg?zCORRECTION (65%)r  zNEUTRAL (80%)z (100%)u      📊 Régime: u    → Position: z USDTr"   u      ⚠️ Solde insuffisant (z USDC)/api/v3/ticker/pricer   r]  rF  rZ  
      ⚠️ u   : Prix retombé u   % depuis détection (.6fz < u   ) → SKIP (mèche évitée)z/api/v3/ticker/bookTickeraskPriceu   : slippage ask trop élevé (rX  u   %) → SKIP (ask=u    vs détection=u      ⛔ z: symbole invalide sur r   exchangeu    — SKIP (blacklist auto)u      💰 ACHAT z	 USDT de z (surge z%)...u      ❌ Ordre échoué u#    — paire probablement absente du fillsc              3   R   K   | ]  }t        |j                  d d             ! yw)qtyr   N)rG   rH   )r  rK   s     r   r  z3SpyPositionManager.open_position.<locals>.<genexpr>  s     TU155?3Ts   %'executedQtycummulativeQuoteQtyr_   rl   r  rz  r   r{  dynamic_tp_pcttrailing_stopNr  r_  r  r	  r|  orderIdr   
entry_timerp  rq  
indicatorsrj   r  2   r  r`  )consecutive_dropsrsi_at_entryema7_slope_at_entrydelta_5mu      ✅ ACHAT OK:   @ z      SL: -z	% | TP: +z% (dyn) | Trailing: -%/u
   % après +rY  Tu      ❌ Erreur achat )0rm   ri  SPY_MAX_POSITIONSr   r   r   r   rH   r  r  rM   r  r  r  r\   rI   rl  r  behaviorget_position_multipliercurrent_regimer   r  rG   r   MAX_BUY_SLIPPAGE_PCTr   r   r  r   rn   r  rj  ra   HARD_STOP_LOSS_PCTr   r   r   rK  r  r   rx  r  rf   TRAILING_STOP_WIDETRAILING_ACTIVATION	traceback	print_exc)(r   r   r  confirm_detailscached_regimesurge_strength_valblocked	cb_reasonr^   
_base_size_capital_ratio_current_balance_proportional_sizeposition_sizebehavior_multbhregime_multiplierregime_labelr   surge_type_nowis_trending_typeis_extreme_buyis_extreme_flash_open	buy_spikebalancelive_ticker
live_price_retrace_livebook	ask_priceslippage_pctorderfilled_price
filled_qtycummstepr_   
dynamic_tppositionr   s(                                           r   open_positionz SpyPositionManager.open_positionR  s	   t~~"33NN^,=+>nMNT^^# cmmwy}b~Z^^J
GWY\8]^  EH!226J\2]KK(6("YKyAB $(8!<(*
 		'#{{66v>!1N!B  
C0BJQRN,STMzD00?@PQT?UUhivwzh{  |H  IS  TW  HX  XY  Z  [
 4'D,<,<AQAQAZAZ!!**B668Ms"3B4E4E3FmTabeSfgh%52KK8s8K?[\  #0y& '^^L"=N-  2`   `,\1D1D[RS1TX\1\N$2m$C$]Z]H]!4^4DDklm=09NIXO//E^a	s?KK">~c>RRghqrugv  wG  !H  I %.CY\H\:>#:NNijk $@LL( $-LI% $*L)]'2L%(99M2.'~_]SVDWW\]^ '7&:"@W@WX^@_]Q&&NN:73-vNO
	++00*01Hf3EK ";??7Jw<O#PQ
",W"5
"BjQXFY!Y]` ` 4'KK$VH,<]3<O P&s+3z'/B3.GGce ! {{--j 9:Xv<N  %dhhz1&= >I 1}(1Jw4G(G:V]K^'^ad'd'*>>"KK",VH4QR^_bQccgh|g} ~11:3zZaObcfNggh!j $)
 \222NNWVH,CQ]IcmCn  oI  J  Kn]O9VHH^\_L``efgD	KK**6=AE5fX=`nzaj  AK  aL  M  N !7RD!9!!<!@!@*U\J]!^_LTUYYwPR=STTJQ"599]A#>?
q UYY'<a@A>#'*#4L ;;33F;D/3$$V, BQ++K=VYI'
3C(DiPJ|J \Q1Cc1I-IJ |q:3C/CD	
 !*   \ 3  EIIi0 X\\(,,7AAC diik j6 !*-="> ,  o!" ~#$ &'BQ 3 3E2 >WY Tc':':;KQ'Ohi 'NN>1=7H< &.DNN6"  "vx0KK+J<qL>RSKK+&8%9:, O%%6$7r:L9MZXkWllmo p Y  	'&M	'X  		.  V  	LL/xr!=>!	sY   A#] <B] B]) 0A]9 2I]9 ]]	]&%]&)	]65]69	^;/^66^;c                    | j                   syg }t        j                         }t        | j                   j                               D 	]b  \  }}|j	                  |      }|6	 | j
                  j                  t         dd|i      }|rt        |d         }|S|j	                  d      }||dk  rl||z
  |z  dz  }	||j	                  d|      z
  d	z  }
|j	                  d
      }|||d
<   |	|d<   n||kD  r
||d
<   |	|d<   |j	                  dg       }|j                  |       t        |      dkD  r|dd }||d<   d}||j	                  d|      z
  }t        | di       }|j	                  dd      }|j	                  d      rdn"|dv rdn|j	                  d      s|dv rdnt        }d| }|j	                  |d      }|dk\  r||z
  dk\  r	 | j
                  j                  t         d|ddd      }|rt        |      dk\  rd }|D cg c]  }t        |d           }} ||d!      }t        |      d"k\  r	 ||d"      n ||t        |            }t        |      dk\  r ||dd# d!      n|}|dkD  r||z
  |z  dz  nd$}|||<   t        |d      |d%<   t        |d      |d&<   t        |d'      |d(<   |d)kD  |d*<   ||k  |d+<   ||k  xr |d,k  |d-<   |j	                  d*d      }|j	                  d-d.      }|j	                  d+d      }|xs	 |duxr | }|j	                  d/d      } | d0k\  r|d1k  rd2nd3}!|d4k  r!|d   d)k  r|	|!k  rd5|	d6d7|d8d9|d   d6d:}n8|t        k\  r|d   t         k  r|j	                  d;d<      }"t#        t$        |"d=z        }#t'        |#t(        d>z        }#|j	                  dg       }$t        |$      d'k\  xr |$d?   |$d@   cxkD  xr |$d#   kD  nc }%|j	                  dAd      }&|xs |du xr |&d)kD  }'|	|# k  r|%s|'sdB|d   d6dC|	d6dD|
d8dE|#dFd:	}njd|cxk  rdGk  rn n|d   d)k  rdH|d8d9|d   d6dI|	d6d:}n@|dk\  ru|rs|j	                  d%d      }|j	                  d&d      }|j	                  d(d      }(dJ|dKdL|dKdM|(dNdO|	d6d:	}t*        j-                  dP| dQ|(dNdR|	d6dS|d   d6d:	       n|j	                  dT      ||dT   k  r	dU|	d6d:}n|j	                  dV      r$||dV   k  r|	dkD  rdW|d   d6dI|	d6dX|dV   dKdY}no|	t.        k\  r
|j	                  d;d1      })t1        |)|	      }*|j	                  dZd[      }+|+d\k\  rd]|	cxk  rd^k  rn nt'        |*d<      }*t3        |      },|xr	 |	t.        k\  }-|-r9|j	                  d(d      }.|.d_k\  rd`nda}/|*|/z  }*|d
   db|*dz  z
  z  }0|0|dV<   dc|dd<   nA|,r|	d<k\  r
|*dez  }*dc|df<   |d
   db|*dz  z
  z  }0|j	                  dV      xs d}1|0|1kD  r|0|dV<   n|1}0||0k  r||-rdgn|,rdhndi}2dj|d   d6dI|	d6dk|*dFdl|2 dY	}n[|
t4        k\  r9|r	t4        dmz  nt4        }3|rd^ndn}4|
|3k\  r5|	|4k  r/|rdondi}5dp|3d8dq|5 dr|	d6d:}n|
|k\  r|	dsk  r|	t$         kD  rv|st|}6t3        |      r|	dkD  rt7        |d]z        }6|d   d]k\  r|	dkD  rt7        |d0z        }6|
|6k  rd}n|	dkD  r|d   dsk\  rt7        |dez        }6|
|6k\  r|dt|	d6dD|
d8du|6 dv}nt        |      d'k\  r||	d^k  rw|sut3        |      }7|d?   |d@   cxk  r|d#   k  rPn nM|j	                  dwd      dbz   |dw<   |7rdxnt8        }8|dw   |8k\  r.|	dkD  s|d   dyk\  r!|7r|	dskD  rndz|dw    d{|	d6d:}nd|dw<   nd|dw<   |j	                  dZd[      d\k\  rd0ndn}9|j	                  dZd[      d\k\  rdsnd<}:|%|s#|d   |9k\  r|d   d|k  r|	|:k  rd}|d   d6dI|	d6d:}||d~k\  r|	t.        k  r|s	 | j
                  j                  t         d|dd d      };|;rt        |;      d'k\  r|	dkD  rd'ndm}<d}=|;|< d D ]L  }t        |d!         }>t        |      dkD  rt        |d         n|>dsz  }?|>dkD  r|?|>z  nds}@|@t:        k  sH|=dbz  }=N |=|<k\  r:t        db@z
  dz        }Ad|A d|< d|	d6d:}t*        j-                  d| d|< d       |r(|j                  ||||	|j	                  dd$      f       |j	                  dV      r	d|dV   dKndi}B|j	                  d(      }(|rd|(d6dln|(|(dk  rd|(d6dlndi}C|	dkD  rdnd}D| j                   s	t        | j                         d'k  s	4t*        j-                  dD d| d|	d6d|d   d6d|
dFdqC B        	e |D ]q  \  }}E}}F}G| j=                  ||E||F       t?        | d      s*| j@                  s7FdkD  | j@                  jB                  |<   | j@                  jE                  ||FGE       s | jG                          y# t        $ r Y 	w xY wc c}w # t        $ r Y ~w xY w# t        $ r Y w xY w)u   
        Check TOUTES les positions à chaque scan (~12s).
        Utilise les prix des tickers (gratuit, pas d'API call).
        Nr  r   r]  rl   r   rF  r  rQ   r  r_  rj   rT   _market_ctxr   r   r   r-   r  r  r   r   )BULL_STRONG	BULL_WEAK   _ema_check_Z   r  r     r  c                     t        |       |k  r	| r| d   S dS d|dz   z  }t        | d |       |z  }| |d  D ]  }||z  |d|z
  z  z   } |S r  r  r  s        r   	_ema_calcz5SpyPositionManager.check_positions.<locals>._ema_calcr  sr    "4y6137tBx @S @ #vz 2A #D&M 2V ;A%)&'] 8$%EAQK$78#$Hr   rv   r   r  rk   r   
_ema7_last_ema25_lastr&   _ema7_sloper  _ema7_rising_live_ema_bearish_liveg_ema7_bd_liveFr  r4   rM  r   g333333-   zINSTANT_REVERSAL (r  z% en r  zs, max=r  r^   r   r  g?rO  rE  r  zEARLY_SL (max=z%, z% after z	min, SL=-r\  r2  u"   EARLY_FLAT (aucun momentum après z%, now=zEMA7_DOWNTREND (EMA7=r  z<EMA25=z, slope=z+.3fz%, pnl=u      📉 EMA7 DOWNTREND u'   : baisse confirmée (EMA7<EMA25, slope=u   %) → vente primaire (pnl=z%, max=rz  z	HARD_SL (r  zTRAILING (activated, max=z%, TS=r  r  r  rV  rN   rY   r%   g?gffffff?r   T_ema7_trail_widerZ   _uptrend_detectedu
    [ema7↑]z
 [uptrend]r   zTRAILING (max=z	%, trail=rY  r+   r!   u	   ×EMA7↑	MAX_HOLD_r\   r  rP   zSTAGNATION (zmin, seuil=zmin)r  r"   r   zMOMENTUM_EXIT (z drops, rX   zREVERSAL (peak=x   zVOLUME_ROUGE (u   % vendeurs × z klines, pnl=u      🔴📉 u   : VOLUME ROUGE × u#    → sortie (épuisement acheteurs)z TS=u    EMA7↑u    EMA7↓   🟢   🔴   r  r\  z	% | Max: 
% | Hold: _parent_detector)r^  r_  r`  )$ri  r   r3  rF  rH   r  r   r  rG   rI   rf  rm   getattrSTAGNATION_EXIT_MINUTESr]   EARLY_SL_DELAYEARLY_SL_MIN_PNLr  EARLY_SL_PCTr\   r  r   r  r  rh   rt   MAX_HOLD_MINUTESr   MOMENTUM_EXIT_CANDLESVOLUME_EXIT_SELL_RATIO_sellrl  r  r9  re  rx  )Hr   tickers_dictto_sellr   r   ro   r]  r   r  r  hold_minutesr  rj   r`  hold_seconds_mctx_regime_stagnation_minutes_ema_cache_key_ema_last_ts_klines_emar  r  _cls_ema_e7_e25_e7_prev_slope_ema7_rising_ema7_bd_ema7_bearish_ema7_bullish_delta5_pos_ir_threshold
_surge_str_effective_early_sl_last_p_recovering_ema7_entry_slope_ema7_protect_slp	surge_str	trail_pct	rsi_entry
is_uptrend_ema7_trail_active	_ema7_slp
_ema7_multtrailing_slold_ts	trend_tag_max_hold_eff_pnl_thr_tag_effective_stagis_uptrend_mom
_min_drops_rev_peak_min_rev_exit_pnlklines_vol_exit_check_count_sell_dominated_total_buy_r	_sell_pctts_info_ema_tagemojir  r^  r_  sH                                                                           r   check_positionsz"SpyPositionManager.check_positions&  s   
 ~~iik 4 4 67 U	QKFC $$V,E};;11#*$89Hf;MD  %d7m 4 }GGM*E}
.#5G#'',"<<BL ,I #(K !(I"#(K !(I ''-4Ku%;"$)#$/!,CKs!;;L D-4Eii)4Gii.!77ii 45D`9`'	    +6(3N77>15Lr!cL&8B&>"&++"8"8#*N3#)tbI#K #s;'72'=% :E#EAE!A$K#E#E(15:=h-2:My26S\]egjksgtSuBEh-SUBU9Xcr]A#>[^FNQRl#.H!<s!BX[36N+38a=L)38q>M*383CM*39D=/036:/047$J3TVe^O, 77#6=L77?E:H
  GG$7>M(]]$-F-\}K\M ''*a0K%0C%7L2<MDTXMb S^d%:w?V 274.lSVEWW^_bcl_mnr^ssuv /C	NEU4U WW%5s;
&),
S8H&I#&)*=?QTW?W&X#''-4!'la/[GBK'"+4[PWXZP[4[ %(GG,A1$E! , c1E1bJ[^bJb111+m$23y>$2Gs7SW.X`amnq`rr{  }P  QT  |U  UW  #XK |*s*s9~/D B<PSBTT[\_`i\jko[ppwx  AE  xF  FH  I #ww|Q/ww}a0ww}a0+C9GD: F!$KwwtnB@  5fX >226t =$$+D>Y8MRQ R
 %1es;?O6O )'$r: )es?7K.KPWZ[P[ 9#i.9NgV]^bUccijmn}j~  @C  jD  DE  F
 //GG$4b9	0GD	GGNB7	?sg';'; #Is 3I
 -S1

 &2%TgAT6T"% #q 9I(1S(8cJ )J 6I"%k"2a)c/6I"JK+6C(.2C*+ "gn$-O	37/0"%k"2a)c/6I"JK
 !WW_5:F"V+/:O,&,K'0BYcikI$23y>$2GwwW[n\efopsettuv  vA  AB  #CK
 !118D 01 4JZ".3C=0Wx5G*6;BD$-mC-@D6GTX>Y["\K !4437VbUbKbkx #6"3'GaK&)*=*C&DO y>S(Wq[&)*=*C&DO#o5&*q[S^s%:&)*=*C&DO?2{7J$0h|TWFXXcdscttx"yK [!Q&7S=!0!5r?[_F{2F/2ww7JA/NQR/RC+,&4:OJ./:=7Q;RUV_R`dhRh)gm ,;C@S<T;UU]^efj]kkm*nK/0C+,+,'( %(GGNB$?2$ES3M$'GGNB$?2$ES3M"<C	Nm<[`cdm`nqt`t  zA  DQ  zQ /It/DGGTX>Y[\ "|s':wI\?\eq&*kk&<&<#*N3#)taH'O '3+?1+D,3aKqQ*+!0,!@ 5A%*1Q4[F58Vb[U1R5\fslD281*#B!$:: /1 45 +l:(-q2vn(=I,:9+^T`Saanovw{n||~*K"KK,vh>PQ]P^  _B  )C  D UGSWWYX[E\]^?Bww?WD_!5c :;]_ww}-/;htDk+595E$QR(HT$Kq1XZ  #*A+6>>c$..&9Q&>KK#eWAfXR~ F&&))nT%: ;''3C&8H:gY!P Qg
U	Qn
 4; 	i/FFE3JJvvuc2
 t/0T5J5J?BQw%%33F;%%226sGag2h	i 	q
 ! @ $F ! ` ! sQ   "5h4>i	i$B3i	BiAi4	i ii			ii	i&%i&c                    | j                   j                  |      }|sy|d   }|}dD ]$  }|j                  |      s|dt        |        } n d}	d}
	 | j                  j                  |      }	d}
t        j                         |j                  d	t        j                               z
  }| j                  j                  |      }|
r|	d
k(  rt        j                  d| d       	 | j                  j                  |||      }|rt        |j                  di g      d
   j                  d|            }||d   z
  |d   z  dz  }|d
kD  rdnd}t        j                  d| d| d| d|dd	       | j                  ||||||       | j                   |= | j!                          | j#                  |       y	 ||d   z
  |d   z  dz  }|d
kD  rdnd}t        j                  d| d|        t        j                  d| d| d| d|dd|dz  d d!       | j                  |||||d"z   |       | j                   |= | j!                          | j#                  |       y|
r+|	d
kD  r&|	|k  r!t        j                  d#| d$|	 d%| d&       |	}d'}|
r|	d
kD  r|	|z  |k  r||d   z
  |d   z  dz  }|d
kD  rdnd}t        j                  d(| d)|	 d*| d+|	|z  d,d-| d.       t        j                  d| d/| d| d|dd|dz  d d!       | j                  |||||d0z   |       | j                   |= | j!                          | j#                  |       yt        j                  d1| d$|        	 | j                  j                  |||      }|rt        |j                  di g      d
   j                  d|            }||d   z
  |d   z  dz  }|d
kD  rdnd}t        j                  d| d2| d| d|dd|dz  d d!       | j                  ||||||       | j                   |= | j!                          | j#                  |       yt        j%                  d3|        y# t        $ r&}t        j                  d| d|        Y d}~d}~ww xY w# t        $ r$}t        j                  d| d       Y d}~ d}~ww xY w# t        $ r}d4t'        |      v sd5t'        |      j)                         v r||d   z
  |d   z  dz  }|d
kD  rdnd}t        j                  d6| d7       t        j                  d| d/| d| d|dd	       | j                  |||||d8z   |       | j                   |= | j!                          | j#                  |       n4t        j%                  d9| d$|        t+        j,                          Y d}~yY d}~yd}~ww xY w):u   Exécute la venteNr  r  r   FTu      ℹ️ get_balance z indisponible: r  r   r  u;   : balance=0 — tentative ordre réel avant vente virtueller  r]  rl   rF  u   ✅u   ❌r  z VENDU (balance-0-fix) r  z | PnL: r  rY  u       ℹ️ Ordre réel échoué (z), fallback vente virtuelleu      ⚠️ VENTE VIRTUELLE u    (balance=0 confirmé): u    CLÔTURE VIRTUELLE r  rQ   r\  r\   z
 [VIRTUAL]u      ℹ️ Balance réelle r\  u    (stocké: u   ) → ajustement fraisrY   u      ⚠️ CLÔTURE DUST u   : balance réelle r  z = .3fz USDT < z USDT (min notional)u    CLÔTURE DUST z [DUST]u      🔔 VENTE z VENDU u      ❌ Vente échouée z-1013NOTIONALu      ⚠️ NOTIONAL trop faible u    — clôture dust forcéez [DUST-NOTIONAL]u      ❌ Erreur vente )ri  rH   r  rm   r  r  rI   r   r  r   rj  r   r&  rG   r  _archiverx  r  r   rH  upperr  r  )r   r   r  current_pricer  ro   r  r  r#  r$  
balance_okr   	hold_timer  _order_test
sell_price
actual_pnlrS  _eMIN_NOTIONAL_USDTr  s                        r   r  zSpyPositionManager._sell  s   nn  (z? B 	Eu%|U,	
 
	M;;2259LJ IIK#'',		"DD	
 ##''/ ,!+NNZx/jkla"kk55fhM!&{w'Ea'H'L'LWVc'd!eJ#-M0B#Bc-FX"X\_!_J%/!^EEKK#eW,CF83zlZbcmnrbsst uvMM&#z:vyYv.((***62  )3}+==]ASSWZZJ'!^EENN7x?WX^W_`aKK#eW$8M? S)$/z)B,s9K3P QMM&#}j&<BWYbcv&  """6*,*|h/FKK4UG2l^;W_V``vwx#H  ,*}0LPa/a(3}+==]ASSWZZJ'!^EENN5fX=OP\~]^_d^e f+M9#>hGXFYYmo pKK#eWOF83}o N)$/z)B,s9K3P QMM&#}j&9BTV_`v&  """6*nVHBvh78	&KK++FHdCE"599Wrd#;A#>#B#B7M#Z[
)C,>>#mBTTX[[
!+aUc%xs:, G"",T!2*Yr\#<NcS T fc:z69UNN6*$$&&&v.6vh?@a  	MLL1%sKLL	M:  a?tC^_``ah  	&#a& J#a&,,.$@,s=/AASEWW[^^
!+aU!@Hbcdc%xs=/QYZdeiYjjklmfc=*fOaFaclmNN6*$$&&&v.3F82aSAB##%% /	&sQ   Q (CR /CS S 	R(R		R	R>R99R>
WC5W

Wc                 	   	 g }t         j                  j                  t              r0t	        t        dd      5 }t        j                  |      }ddd       |j                  ||d   ||d   t        |d      t        |d   ||d   z
  z  d      t        |j                  d	d
      d      t        |d
      t        |dz  d      |j                  dd      |j                  dd
      ||j                  dd      t        j                  t        j                        j                         d       t        |d   ||d   z
  z  d      }	| j                  |||	       t!        | d      ro| j"                  rc| j"                  xj$                  |	z  c_        |	d
kD  r | j"                  xj&                  dz  c_        n| j"                  xj(                  dz  c_        t!        | d      r| j"                  r| j"                  j*                  rl| j"                  j*                  j-                  t        |j                  d	d
      d      t        |d      t        |d
      ||t/        j.                         d       t        dz   }
t	        |
dd      5 }t        j0                  ||dt2               ddd       t        j4                  |
t               	 t         j                  j7                  t         j                  j9                  t              xs dd      }i }t         j                  j                  |      r*t	        |d      5 }t        j                  |      }ddd       t        |d   ||d   z
  z  d      }|j                  dd
      dz   |d<   |d
kD  r|j                  dd
      dz   |d<   n|j                  dd
      dz   |d<   t        |j                  dd
      |z   d      |d<   t        j                  t        j                        j                         |d<   |dz   }t	        |d      5 }t        j0                  ||d       ddd       t        j4                  ||       y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   )xY w# 1 sw Y   GxY w# t:        $ r Y yw xY w# t:        $ rK 	 t        dz   }
t         j                  j                  |
      rt        j<                  |
       Y yY y#  Y Y yxY ww xY w) z"Archive le trade dans l'historiquer:   r;   r<   Nrl   r  r&   rv   r_  r   rQ   r   rc  r   r^   r   )r   rl   r^  r  r  r  r_  r  r  rc  r^   exit_reasonr  	exit_timer  )r_  r  r  rc  r   r   r  r   r+   rr  .zspy_cumulative_stats.jsontotal_trades
total_winstotal_lossesr  last_updatedrT  )r?   r@   rC   SPY_HISTORY_FILErD   rE   rF   rf  r]   rH   r   r   r   rK  r  r  rl  r  session_pnlsession_winssession_lossesr  feed_trade_resultr   r   rH  rJ  rA   dirnamerI   remove)r   r   ro   r^  r  r  r\  r  rK   pnl_usdt_valtmp_file
cumul_filecumulcfr  	tmp_cumuls                   r   rX  zSpyPositionManager._archive	  sC   T	Gww~~./*C'B +a"iilG+ NN "=1(
O !,!#j/Z#mBT5T"UWXY A!6: %i 3 %i"na 8!gglB7"%''*:A">%!ggk26%\\(,,7AAC * !ZJ]AS4S!TVWXL##FG\B t]+0@0@  ,,<,!#$$11Q61$$33q83 t]+0@0@TEUEUE^E^  ));;$SWWY%:A>$Wa0$))Q$7#)$!%=  (&0Hhg6 =!		'1Q<=JJx!12WW\\"''//:J*K*RsTop
77>>*-j#. ." $		". ZJ]AS4S!TVWX(-		.!(Dq(Hn%a<*/))L!*Dq*HE,',1IIna,H1,LE.)*/		:JA0NQY0Y[\*]&'(0X\\(B(L(L(Nn%&/	)S) 3RIIeR23

9j1M+ +`= =. .3 3    	+f477>>(+IIh' ,	s   7R QH5R Q'""R A2R 7Q4CR "R;R Q$R 'Q1,R 4Q>9R R
R 	RR RR 	S0&=S''S,)S0,S0c                 ,    t        | j                        S r   )rm   ri  r@  s    r   countzSpyPositionManager.countd	  s    4>>""r   )r   r   )r   r   r   r   r   rk  rn  rx  r  r  r  r  r  r  r  rT  r  rX  propertyrx  r   r   r   rg  rg  l  sk    
/=*.34
&P:'87vRhl\v&pVp # #r   rg  c                   Z    e Zd ZdZddZd Zd Zd Zd Zd Z	d Z
d	 ZddZefdZd Zy
)	MarketSpyu}   
    Scanner ultrarapide: scan toutes les 12s, détecte les surges,
    achète immédiatement, vend dès essoufflement.
    c                    || _         t               | _        t               | _        t        | j                        | _        | j                  | j                  _        d | j                  _        | j                         | _
        ddddddd| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        t)        j(                         | _        t)        j(                         | _        d | _        d| _        d| _        g | _        d| _        d| _        g | _        d| _        t>        r
tA               nd | _!        i | _"        d | _#        tH        rwtJ        rq	 tM        jN                         | _#        tP        jS                  d| jF                  jT                  d	d
| jF                  jV                  jY                  dd      dd       n7tH        r1tJ        s+tP        j]                  ddt_               v rt`        nd d       tP        jS                  d       tP        jS                  d       tP        jS                  d       tP        jS                  d|rdnd        tP        jS                  dtb         d       tP        jS                  dtd         dtb         dtf         d       tP        jS                  dti               ddd d!d"tj                tP        jS                  d#tl         dtn         dtp         d$tr         d%tt         d&       | jB                  r0tP        jS                  d'| jB                  jw                                 | jF                  r-tP        jS                  d(| jF                  jT                  d	       tP        jS                  d       | | j                  _        y # tZ        $ r#}tP        j]                  d|        Y d }~d }~ww xY w))Nr   Fr   r0   )r   r   r   r   r   r   r   INITIALIZINGu%      🤖 ML Classifier chargé (seuil=r  z, AUC=test_aucz.4fr  u&      ⚠️ ML Classifier indisponible: u,      ⚠️ ML Classifier: imports manquants (_ml_errr   u   ════════════════════════════════════════════════════════════u$   🕵️ MARKET SPY v3 - Pump Catcherz	   Mode: DRY-RUNLIVEz   Scan: every rC  z   Surge: +r  z	s | Vol: xz   Position: r  u    USDC base (scaling auto ×g     @r\  z% du solde) | Max: z   Exit: Trailing -z% (dyn) | SL -z$% | NO TP CAP (trailing only) | Max r\   u      🧠 u-      🤖 ML Filter: ACTIF (TESTNET) — seuil )<dry_runr   r  r/  r   rg  ri  r  r  _load_watchlist	watchlistr  
scan_countsurges_detectedsurges_confirmedtrades_executedrk  rl  rm  trades_this_hourr   
hour_start
start_timelast_scan_timelast_scan_durationlast_eligible_countlast_surgescurrent_phaseerrors_count
scan_timeslast_watchlist_auto_update_BEHAVIOR_AVAILABLEr   r  _pending_ft_checksml_classifierr   _ML_CLASSIFIER_AVAILABLEr   rF   r   r  optimal_thresholdtraining_statsrH   rI   r   dirr  SCAN_INTERVALri  SURGE_MIN_VOLUME_RATIOrM   r  rf   r  rd   r  r  get_status_line)r   r  r   s      r   r   zMarketSpy.__init__s	  sq   "n%+DKK8*.--'%)"--/&/27s*-dD   !  !))+))+""##$ +*+' 4G-/D"$ "4M%5%:%:%<"CDDVDVDhDhilCm n""&"4"4"C"C"G"G
TU"VWZ![[\^ _ ":NNIU^bebgUg'mvIwwxyzJ:;JiW	&ABCom_A67k"8!9M? K12!5 	6m$7$9##>>YZefiYjj}  P  ~Q  R  	S)*;)<B?Q>RRTUhTiiw  yK  xL L66F5GsL 	M==KK(4==#@#@#B"CDEKKGHZHZHlHlmpGqrsJ%)"+  M!GsKLLMs   #A/N. .	O7OOc                    	 t         j                  j                  t              rt	        t        dd      5 }t        j                  |      }ddd       t        j                  dg             }t        |j                  di       j                               }t        |j                  di       j                               }||z  |z  S 	 t               S # 1 sw Y   xY w# t        $ r Y t               S w xY w)u  Charge la watchlist complète pour le spy: manuels + auto-ajoutés + spy_injected.
        
        🔧 FIX 29/03: Le spy scanne symbols (dashboard/bot) + auto_added (spy only).
        Les auto_added ne sont PAS dans symbols[] pour ne pas polluer le dashboard.
        🔧 FIX 10/04: Inclure spy_injected — survit aux redémarrages (était perdu en mémoire seulement).
        r:   r;   r<   Nr   
auto_addedspy_injected)r?   r@   rC   WATCHLIST_FILErD   rE   rF   r   rH   rV  rI   )r   rK   r   manualautoinjecteds         r   r  zMarketSpy._load_watchlist	  s    		ww~~n-.#@ (A99Q<D(TXXi45488L"5::<=txx;@@BC}x// . u( (  	u	s)   5C! CA<C! CC! !	C65C6c                    	 |t         j                  v ry| j                  j                  |      \  }}|ryg i d}t        j
                  j                  t              r0t        t        dd      5 }t        j                  |      }ddd       t        |j                  dg             }|j                  di       }	||v r||	v rt               j                         |	|   d<   |	|   j                  d	d
      dz   |	|   d	<   |	|d<   t        t        dd      5 }t        j                  ||d       ddd       t         j#                  d| d|	|   d	    d       yt               j                         t               j                         |j                  dd      t%        |j                  dd
      d      t%        |j                  dd
      d      ddd|	|<   |	|d<   t               j                         |d<   t        t        dd      5 }t        j                  ||d       ddd       | j&                  j)                  |       t         j#                  d| d|j                  d       d|j                  dd
      dd|j                  dd
      dd	       t         j#                  d       y# 1 sw Y   *xY w# 1 sw Y   xY w# 1 sw Y   xY w# t*        $ r"}
t         j-                  d|
        Y d}
~
yd}
~
ww xY w) u*  🆕 FIX 27/02: Injecte un symbole confirmé dans la watchlist du bot.
        
        🔧 FIX 29/03: Injection via spy_injected{} seulement (pas dans symbols[]).
        Le bot recharge la watchlist toutes les ~30s et lit spy_injected.
        Le symbole est marqué avec un TTL de 24h.
        N)r   r  r:   r;   r<   r   r  
last_surgesurge_countr   r   r   r+   rT  u         📡 u   : TTL spy renouvelé (surge #r  rc  r   r^   r_      )added_atr  rc  r^   r_   r  	ttl_hours
updated_atu!    INJECTÉ (spy_injected)! (surge=z, strength=r\  z%, vol=r  u8         → Le bot IA l'analysera au prochain cycle (~30s)u)         ⚠️ Erreur injection watchlist: )r   r   ri  r  r?   r@   rC   r  rD   rE   rF   r   rH   r   r  r   r   r  r]   r  r   rI   r   )r   r   surger&  _cb_blocked
_cb_reasonwatchlist_datarK   r   r  r   s              r   _inject_to_watchlistzMarketSpy._inject_to_watchlist	  s   4	J666&*nn&E&Ef&M#K)+R@Nww~~n-.#@ 2A%)YYq\N2 .,,Y;<G)--nbAL  \)9B9N9N9PL(6:Fv:N:R:RS`bc:dgh:hL(75AN>2ncGD ?		.!A>?KK+fX5RS_`fSghuSvRwwx yz &K113'k335#iib9"'		2BA(F"J"7;;{A#>B $L  .:N>*+4;+@+@+BN<(ncG< 7		.!A67 NNv&KK+fX .!!&<!8 9UYYO_abEcdgDh i%kk+q9#>bB C KKRTO2 2? ?&7 7  	JLLDQCHII	Jsr   K  K :K 0J.BK J;/*K B/K 	K"BK .J83K ;K K KK 	K?K::K?c                    	 t         j                  j                  t              syt	        t        dd      5 }t        j                  |      }ddd       j                  di       }|syt               }g }|j                         D ]  \  }}|j                  dd      }|j                  d      xs |j                  d	d
      }		 t        j                  |	      }
||
z
  j                         dz  }||k\  so|j                  |        |syt!               }	 ddlm}  |t              j&                  dz  }|j                         r\t	        |      5 }t        j                  |      }ddd       t)        t*              rt!        |j-                               n	t!               }g }|D ]O  }||v rt0        j3                  d| d       !||= | j4                  j7                  |       |j                  |       Q |r||d<   |j9                         |d<   t	        t        dd      5 }t        j:                  ||d       ddd       t0        j3                  dt=        |       ddj?                  |              yy# 1 sw Y   .xY w# t        t        f$ r |}
Y w xY w# 1 sw Y   :xY w# t.        $ r Y w xY w# 1 sw Y   xY w# t.        $ r"}t0        jA                  d|        Y d}~yd}~ww xY w)u   Retire de la watchlist les symboles injectés par le spy dont le TTL est expiré.
        
        Un symbole expiré = aucun nouveau surge depuis 'ttl_hours' heures.
        Appelé toutes les ~50 scans (~25min) pour garder la watchlist propre.
        Nr:   r;   r<   r  r  r  r  r  r   r/   r   )Pathru   u      ⏳ SPY TTL: u'    expiré mais EN POSITION — conservér  r   r+   rT  u      🧹 SPY TTL: u3    symbole(s) expiré(s) retiré(s) de la watchlist: , u$      ⚠️ Erreur nettoyage TTL spy: )!r?   r@   rC   r  rD   rE   rF   rH   r   rF  r   rI  rd  re  r  rf  r   pathlibr  parentr   r   rV  rI   r   r  r  discardr  r   rm   rA   r   )r   rK   r  r  r   expiredr   r  ttl_hlast_surge_strlast_surge_dthours_elapsedactive_positionsr  pos_filepfpos_dataremovedr   s                      r   _cleanup_expired_spy_symbolsz&MarketSpy._cleanup_expired_spy_symbols
  s   8	E77>>.1ncG< .!%1. *--nbAL+CG , 2 2 4 	+b1!%,!7!S488JPR;S($,$:$:>$JM "%}!4 C C E L E)NN6*	+   #u(/669II??$h 12#'99R=1?I(TX?Ys8==?';_b_d$ G! '--KK"26(:a bc (&&v.v&' 1=~./2}}|,.#@ ;AIIna:;/G~=pquqzqz  |C  rD  qE  F  G [. . #I. ($'M(1 1   ; ;  	ELL?sCDD	Es   #K K I:K +AK JK 6K 
K :J, J';J, "BK $J<=;K :J?K JK JK J)$J, ,	J95K 8J99K <KK 	K3K..K3c                   , d}d}||z   }d}d}h d}g d}h d}	 t         j                  d       | j                  j                  t         d	      }	|	rt        |	t              st         j                  d
       yg }
|	D ]  }|j                  dd      }|j                  d      s'||v s||v r0|dd ,,j                         r,j                         sVt        ,fd|D              rk	 t        |j                  dd            }t        |j                  dd            }||k\  s|dk\  s|
j!                  ||f        |
j#                  d        |
d| D cg c]  \  }}|	 }}}g }|	D ]  }|j                  dd      }|j                  d      s'||v s||v r0|dd ,,j                         r,j                         sVt        ,fd|D              rk	 t        |j                  dd            }t        |j                  dd            }t        |j                  dd            }||k\  s|dk\  s|dkD  s|j!                  |||f        |j#                  d        |D ci c]	  \  }}}|| }}}}|D cg c]  \  }}}d|cxk  r|k  rn n|||f }}}}|d| D cg c]  \  }}}|
 }}}t        t$        j'                  ||z               d| }t)        d |
D              }t*        j,                  j/                  t0              syt3        t0        dd      5 }t5        j6                  |      }ddd       t)        j                  dg             }|j                  d i       }t9               }g }g } | j;                         }!t        |j=                               D ]  }||v r|j?                         ||   d!<   ||   j                  d!||   j                  d"d            }"	 tA        jB                  |"      }#||#z
  jE                         d#z  }$|$d$k\  sx||!vs}||= | jF                  jI                  |       | j!                  |        |
D ci c]  \  }}||
 }%}}tK        |      |k  r#t         j                  d%tK        |       d&       nt)        |j=                               }&|&t)        |      z
  |!z
  }'|'D ]  }|%j                  |d      }(|j                  |d      })|(|k\  r%d|)cxk  rd'k  rn n|j?                         ||   d!<   Q||= | jF                  jI                  |       | j!                  |        |D ]|  }||v s||v rtK        |      |k\  r nc|j?                         |j?                         |%j                  |d      d(||<   | jF                  jM                  |       |j!                  |       ~ ||d <   |j?                         |d)<   t3        t0        d*d      5 }t5        jN                  ||d+,       ddd       tK        |      tK        |      z   }*t         j                  d-|* d.tK        |       d/tK        |       d0tK        |D cg c]	  }||v s| c}       d1tK        |D cg c]  }||v s||vs| c}       d2tK        |       d3tK        |        d4       |rVt         j                  d5d6jQ                  tS        |      dd7        tK        |      d7kD  rd8tK        |      d7z
   d9ndz          | r1t         j                  d:d6jQ                  tS        |                     yy# t        t        f$ r Y w xY wc c}}w # t        t        f$ r Y 	w xY wc c}}}w c c}}}w c c}}w # 1 sw Y   QxY w# t        t        f$ r |}#Y w xY wc c}}w # 1 sw Y   xY wc c}w c c}w # tT        $ r"}+t         jW                  d;|+        Y d}+~+yd}+~+ww xY w)<u  🆕 Met à jour les symboles auto-découverts par le spy (toutes les heures).

        🔧 FIX 29/03: SÉPARATION STRICTE dashboard/spy:
        - auto_added{} = symboles spy-only (vol >= 2M$), stockés UNIQUEMENT dans auto_added
        - symbols[] = liste manuelle du dashboard/bot, JAMAIS modifiée par cette fonction
        - Le spy scanne symbols + auto_added en runtime (via _load_watchlist)
        - Le dashboard/bot ne voit que symbols[] → pas d'inflation

        🚀 OPT 07/04: Reclassement dynamique des slots + track momentum breakout
        - 10 slots "volume"    : top volume 24h (liquidité)
        - 5  slots "momentum"  : top gainers 24h >= 2M$ vol (pompes émergentes)
        - Rebalance complet chaque heure, sauf positions actives protégées
        r.   r"   r   r[   >   CUSDCrw   rx   ry   rz   PAXGUSDCr{   USD1USDCUSDEUSDCr|   r}   WBTCUSDCWLFIUSDCXUSDUSDC	BFUSDUSDCr   	RLUSDUSDC)r  TUSDr  FDUSDPAXGXAUT>
   ADAUSDCBNBUSDCBTCUSDCDOTUSDCETHUSDCLTCUSDCSOLUSDCTRXUSDCXRPUSDCDOGEUSDCu0   🔄 Mise à jour symboles spy depuis Binance.../api/v3/ticker/24hru5      ⚠️ Réponse Binance vide — skip mise à jourNr   r   r  r  c              3   &   K   | ]  }|v  
 y wr   r   r  kwbases     r   r  z3MarketSpy._auto_update_watchlist.<locals>.<genexpr>}
       =brTz=   rC  r   rB  gư>c                     | d    S Nr   r   r  s    r   <lambda>z2MarketSpy._auto_update_watchlist.<locals>.<lambda>
      !A$ r   )keyc              3   &   K   | ]  }|v  
 y wr   r   r  s     r   r  z3MarketSpy._auto_update_watchlist.<locals>.<genexpr>
  r  r  rD  c                     | d    S r  r   r  s    r   r  z2MarketSpy._auto_update_watchlist.<locals>.<lambda>
  r  r   r4   c              3   &   K   | ]	  \  }}|  y wr   r   )r  rC  _s      r   r  z3MarketSpy._auto_update_watchlist.<locals>.<genexpr>
  s     ;A1;s   r:   r;   r<   r   r  	last_seenr  r/   r  u!      ⚠️ new_target trop court (u#   ) — rebalance annulé cette heurer1   )r  r  ra  r  r   r+   rT  u      ✅ Spy scan: z symboles (z dashboard + z spy-auto: zvol + zmomentum) (+u    ajoutés, -u
    retirés)u      ➕ Spy auto: r  rM  z +z autresu      ➖ Spy retiré: u)      ⚠️ Erreur _auto_update_watchlist: ),r   r  r  r   PRODUCTION_APIr   r3  r   rH   r  isasciiisalnumanyrG   rd  re  rf  sortr   fromkeysr   r?   r@   rC   r  rD   rE   rF   r   _load_bot_positionsrV  r  r   rI  r  r  r  rm   r   r   rA   r   rI   r   )-r   SLOTS_VOLUMESLOTS_MOMENTUMMAX_AUTO_ADDEDMIN_AUTO_VOLUMEMOMENTUM_MAX_GAIN_24HEXCLUDE_EXACTEXCLUDE_KEYWORDSEXCLUDE_MAJORSresponseeligible_with_volr  rL  volr]  rC  r  
top_volumeeligible_momentumchangecr  eligible_change_maptop_momentum
new_targeteligiblerK   r  manual_symbolsr  r   addedr  r  last_seen_strlast_seen_dthours_invisiblevol_mapcurrent_auto	to_removesym_volsym_gain
total_scanr   r  s-                                               @r   _auto_update_watchlistz MarketSpy._auto_update_watchlistE
  s    %6# $
 M
b	JKKJK{{--!""56H :h#=VW !#" 9jj2.||F+-'3.+@3Bx<<>$,,.=,<==

=! <=C!&**[!"<=E /)ex.?%,,c3Z8%9* """7(9-<(HI1!IJI !#" Ajj2.||F+-'3.+@3Bx<<>$,,.=,<=="6::mQ#?@C"6::k1#=>E"6::.BA#FGF /)ex.?FQJ%,,c63-?@'A( """77H"I"IGAq!1a4"I"I ;L !G !Gwq!Q$'1$E0E$E #$Q !G !G->-OP'!QAPLP dmmJ,EFGXJ;):;;H 77>>.1ncG< .!%1. !!3!3Ir!BCN'++L"=J+CEG  $779JOO-. ,(?36==?JsOK0$.sO$7$7ZPS_EXEXYcegEh$iM+'/'='=m'L (+\'9&H&H&JT&QO&",<L1L&sO..s3s+,  )::1q!t:G:
 :-!B3z?BSSvwx":??#45(3z?:=MM	 % 	(C&{{32G266sA>H/1a(6Jd6J7:}}
34 "3NN**3/NN3'	( " ".(C:,=z?n4"%--/"%--/")++c1"5#
3
 ""3'S!" ,6N<(+.==?N<(ncG< 7		.!A67 ^,s:>JKK#J< 0'(c*o5Fk:AajABC DZ]13DR\I\!]^_ `%j\c'l^:	G /		&-:L0M/NO<?JOr#e*R-8QSU V2499VG_3M2NOP I #I.  J( #I.  #J!GP. .& '	2 +'*+ ;T7 7 B]  	JLLDQCHII	JsX  A_ ;A/_ +6]!_ '_ -0_ ]!)A2_ A]'-_ 3_ 9_ ?/_ .]=<
_ ^$_ 0^=A_ _ ,^B2_ 5^
_ &_ +6_ !^6.F_ ;^<A_ '	_	1_	5_ 	___B0_ ]_ ]	_ ']:6_ 9]::_ ^_ ^3/_ 2^33	_ <__ 	_>_99_>c           	         	 t         j                  j                  t              rjt	        t        dd      5 }t        j                  |      }|j                         D ch c]  \  }}t        |t              sd|v s| c}}cd d d        S 	 t               S c c}}w # 1 sw Y   t               S xY w# t        $ r Y t               S w xY w)Nr:   r;   r<   rl   )r?   r@   rC   rt  rD   rE   rF   rF  r   r   rI   r   )r   rK   r   r  r  s        r   r  zMarketSpy._load_bot_positions  s    	ww~~n-.#@ fA99Q<D*.**,e$!Q*Q:MR_cdRdAef f . u ff
 u  	u	sL   5B5 )B  B9B>BB 	B5 B  B2%B5 2B5 5	C
	C
c                 8#   | xj                   dz  c_         t        j                         }d| _        t        j                         | j                  z
  dk\  r d| _        t        j                         | _        d| _        | j
                  j                  t         d      }|sd| _        | j                          yg }i }|D ]  }|j                  d	d
      }	 t        |d         ||<   |j                  d      s9t        r	|t        v rH	 t        |j                  dd            }t        |j                  dd            }|| j"                  v }	|	rdnt$        }
|	rdnt&        }|	rt        d      nt(        }||
k  s
||kD  s||k  r|| j*                  j*                  v r|j-                  |        d| _        | j.                  j1                  |      }t3        |      | _        d| _        | j*                  j7                  |       t        j                         |z
  | _        t        j                         | _        | j<                  j-                  | j8                         t3        | j<                        dkD  r| j<                  dd | _        | j>                  r| j@                  rt        j                         }g }| j@                  jC                         D ]X  \  }}||d   z
  }|dk\  s|j                  |      }|r!| j>                  jE                  ||d   ||       |j-                  |       Z |D ]  }| j@                  |=  |s| jF                  D cg c]/  }t        j                         |j                  dd      z
  dk  s.|1 c}| _#        d| _        | j                          | j                   dz  dk(  rf	 tI               | _%        | jJ                  | j*                  _%        | jJ                  }|j                  d      dv rtL        jO                  d|d    d       | j                   dz  dk(  r| j>                  rd | j>                  jU                          nd
}| jV                  dk\  rd!nd"}| jX                  | jZ                  z   dkD  r.d | d#| jV                  d$d%| jX                   d&| jZ                   d'	nd
}tL        jO                  d(| j                    d t3        |       d)| j*                  j\                   d*| j^                   | | 
       yd+| _        | xj^                  t3        |      z  c_/        |ja                  d, d-.       t        j                         }|D ]+  }| jF                  j-                  |d	   |d/   |d0   |d1       - | jF                  D cg c]  }||j                  dd      z
  dk  s| c}| _#        | jF                  d2d | _#        | j                   dz  dk(  r	 tI               | _%        | jJ                  | j*                  _%        | jJ                  }|d3   r%tL        jO                  d4|d5   d6d7|d8   d9d:       n)|d;   r$tL        jO                  d<|d=   d>d?|d5   d>d@       | jJ                  }| jc                         }d}| j>                  r| j>                  je                         }|d   }|D 	]  }|d	   } |d0   }!|d/   }"| j>                  r'|d   t        j                         dA| j@                  | <   tL        jO                  dB|  d |! dC|"dDdE|dF   d>dG|dH   d>dI|dJ   d>dK       | |v r1tL        jO                  dL       | j.                  jg                  |        | j                  th        k\  rtL        jO                  dM       tj        r|tl        jn                  k(  rnn|!dOk(  r|"dPk\  stL        jO                  dQ| j>                  jU                          dR       | jq                  |i dNdS| j>                  jr                  dT   dUdRV       | j.                  jg                  |        ~tj        r|tl        jt                  k(  rznnx| j>                  jw                         }#|"|#k  rYtL        jO                  dW|"dDdX|#d6dY       | jq                  |i dNdZ|"dDd[|#d6d\V       | j.                  jg                  |        |j                  d3      r7|!dOk(  r|"d]k\  s-tL        jO                  d^|d5   d6d_|d8   d9d`|! d#|"dDda	       Y|!dbk(  r|"dck  r|j                  dJd      }$|j                  dHd      }%|"ddk  s
|$dek  s|%dfk  rYtL        jO                  dg|"dDdh|$dDdG|%dDdi       | j.                  jg                  |        | jq                  |i dNdj|"dDdkV       |!dlk(  rV|"dek  rQtL        jO                  dm|"dDdn       | j.                  jg                  |        | jq                  |i dNdo|"dDdpV       J|j                  dJ|"      }&|!dOk(  rf|"dqk  ra|&|"drz  k\  rYtL        jO                  ds|"dDdt|&dDdu       | j.                  jg                  |        | jq                  |i dNdv|"dDdw|&dDd\V       |!dOk(  r>| tx        v r6tL        jO                  dx|  dy       | j.                  jg                  |        
|!dOk(  ro| tz        v rgtz        |    }'|j                  dJd      }(|"|'k  rG|(dzk  rBtL        jO                  d{|  d||"dDdX|'d6d}|(dDd~	       | j.                  jg                  |        ~| j*                  j}                  | |"      \  })}*|)rB| j.                  jg                  |        |"dk\  r tL        jO                  d|  d||"dDd|* dR       |!dOk(  xr |"dk\  }+d
},|j                  d;      rd},n|j                  d3      rd},tL        jO                  d|, d|+rdnd
        | j.                  j                  | j
                  | ||      \  }-}.|-r| xj                  dz  c_@        t        |.j                  dd      dz        }/|.j                  d      rdn|/dk\  rdnd}0tL        jO                  d|.d   d6d|0 |/ d|.j                  dd      d6d|.d    d|.d   d>dK       dN}1d}2| j                  r	 t        j                         }3| j
                  j                  t         d| ddd      }4|4rt3        |4      dk\  rg }5|4D ]  }6|5j-                  t        |6d         t        |6d         t        |6d         t        |6d         t        |6d         t        |6d         t        |6d         t        |6d         t        |6d         d	        t        j                  |5      }7t        |4d   d         }8t        |7|8d      }9|9r|"|9d/<   |!|9d0<   | j                  j                  |9|7|8      }2|2d   }:|2d   };|2d   }<|2d   }=t        j                         |3z
  dz  }>|;dk(  r/d-}1tL        jO                  d|:dd|2d   dDd|<d9d|= d |>d9d       nitL        jO                  d|:dd|2d   dDd|<d9d|= d |>d9d       n<tL        jS                  d       n&tL        jS                  d|4rt3        |4      nd d       |1rC| j.                  jg                  |        d|2d   dd|2d   dDdR}?| jq                  ||.dN|?V       R| j                  | ||.       | j                  rJtL        jO                  d|         | j.                  jg                  |        | jq                  ||.dNdV       | j*                  j                  | ||.|j                  dd            }@|@r[| xj                  dz  c_L        | xj                  dz  c_        | j.                  jg                  |        | jq                  ||.d-       	G| j.                  jg                  |        | jq                  ||.dNdV       	ytL        jO                  ddj                  |.j                  dg                     | j.                  jg                  |        | jq                  ||.dNdj                  |.j                  dg             V       
 d| _        | j                          y# t        t        f$ r Y ,w xY w# t        t         f$ r Y Bw xY wc c}w # tP        $ r#}tL        jS                  d|        Y d}~d}~ww xY wc c}w # tP        $ r#}tL        jS                  d|        Y d}~
d}~ww xY w# tP        $ r$}tL        j                  d| d       Y d}~d}~ww xY w)u   
        Un cycle de scan ultra-rapide:
        1. Fetch tous les tickers (1 appel API)
        2. Détecter les surges
        3. Confirmer avec klines 1m
        4. Acheter si confirmé
        5. Vérifier/vendre les positions existantes
        r   SCANNINGr/   r   FETCHING_TICKERSr  WAITINGNr   r   rB  r  rC  g-C6
?i@B infDETECTING_SURGESCHECKING_POSITIONSrF  ir   rQ   r]  r[  r"   r   r  u      🌡️ Régime: z (hors surge)u   Contexte marché indisponible: rT   z | u   📈u   📉r  r  z$ (zW/zL)u	      💓 #z paires | Pos spy: z | Surges total: PROCESSING_SURGESc                     | d   S )Nr^   r   r  s    r   r  z$MarketSpy.run_scan.<locals>.<lambda>  s    !$4"5 r   T)r  reverser^   rc  )r   r  r  r   r  r   u*      🔴 MARCHÉ EN CHUTE LIBRE: BTC mom3h=r   r\  z% | Alts haussiers=r   r  u   % → seuils durcisr   u&      🟢 FENÊTRE DE REBOND: BTC mom5h=r   r  z% mom3h=u   % → seuils assouplis)r]  r   u   
   ⚡ SURGE: z | +r  u   % | Δ1=r^  u   % Δ2=r_  u   % Δ5=r`  rY  u$         → Skip (bot position active)u         → Skip (max trades/h)FrG  r!   u+         → 🧠 PANIQUE: observation seule (r  zbehavior_panique(FTR=ftrr  )executedr  u"         → 🧠 SPECULATION: surge rZ  z% requiszbehavior_speculation(r  r  rN   u#         → Skip FREEFALL: BTC mom3h=z% alts=u   % — z%% insuffisant (requis: FLASH >= 1.5%)r  rZ   r    r  r%   u%         → Skip TRENDING trop faible: u   % < 1.3% (Δ5=u5   % — exception: Δ5≥0.8 ET Δ2≥0.3 nécessaires)ztrending_weak(z%<1.3%)r  u)         → Skip ACCELERATING trop faible: z% < 0.8% requiszaccelerating_weak(z%<0.8%)rc   r'   u#         → Skip surge épuisé: Δ1=u   % mais Δ5=u   % → mouvement finiu   surge_exhausted(Δ1=r  u         → ⛔ u7   : blacklisté FLASH_SURGE (pump <10s, attend WebSocket)r4   u         → ⏭️ z: surge u   % requis (fast spiker, Δ5=z	% < 2.0%)r  r   u         🔒 u   % ignoré — CB actif (rO   z	 [REBOND]z [FREEFALL]u!         🔍 Confirmation klines 1mz...z (mode FLASH adaptatif)r  rP   r  r  r  u   🟡r  u         ✅ CONFIRMÉ! Vol=r_   zx | BuyVol=z	% (spike r  zx) | Green=r  z	/3 | Mom=r  r  r  r  r  r   r+   r&   rv   r   r   )		open_timerD   highlowclosevolumequote_volume
num_tradestaker_buy_quote_volrO  )lookback_minutesprobabilitysignal
confidence
model_typer   SKIPu         🤖 ML SKIP: prob=rV  z	 < seuil 	thresholdz | conf=z% | msu         🤖 ML BUY: prob=u    ≥ seuil uD         🤖 ML: features insuffisantes (klines<30min) → passthroughu%         🤖 ML: klines insuffisantes (u   ) → passthroughu         🤖 ML erreur: u"    → passthrough (trade autorisé)zml_skip(prob=<u%         🏜️ DRY-RUN: Achat simulé zdry-runr   )r  )r  order_failedu         ❌ Rejeté: r  r  )Nr  r   r  r  r  r  r   r  _write_statusrH   rG   rd  KeyErrorr  EXCLUDE_STABLECOINSSTABLECOINSre  r  	MIN_PRICEMIN_VOLUME_USDT	MAX_PRICEri  rf  r   r  rm   r  rT  r  r  r  r  r  rF  feed_surge_observationr  r   r  r   r  rI   r  r  rk  rl  rm  rx  r  r  r  
get_regimere  SPY_MAX_TRADES_PER_HOURr  r   PANIQUE_log_opportunityr   SPECULATIONget_min_surge_strengthFLASH_SURGE_BLACKLISTFLASH_SURGE_STRICTr  r=  r  r]   r  r   pd	DataFramer   predictr   r  r  r  r  rA   )Ar   
scan_startr  r  r  r  rL  r]  r  in_watchlisteffective_min_priceeffective_min_voleffective_max_pricer  now_ftr  ft_symft_dataelapsedcheck_pricerC  r   r   bh_line	pnl_emojipnl_strr   r  bot_positionsbehavior_regimer  r  r   rc  r^   min_strengthr<  _c2_delta5_strict_min_delta5_strictr  r  	is_strongmkt_hintr  r&  buy_pctbuy_icon
ml_blocked	ml_resultml_start
raw_klineskl_datar  	klines_dftimestamp_msfeaturesml_prob	ml_signalml_confml_model
ml_elapsed
_ml_reasonsuccesssA                                                                    r   run_scanzMarketSpy.run_scan  s    	1YY[
' 99;(D0$%D!"iikDO 0++((H:5H)IJ!*D   	A%%"%C$)!K.$9S! <<'"sk'9aeeK34AEE-34
 $..0L-9'y/;) 3?%,I**e6I.ISSdMddnn...OOA;	@ 0,,X6#&x=  2&&|4 #'))+
":"iikt667t#%"oode4DO ==T44YY[FI#'#:#:#@#@#B - 7;#77b="."2"26":K"<<"GG$4k7 $$V,- ! 1++C01 +/+;+;la		aeeT_abNc@cgk?klD!*D  "a'H'='?D$151A1ADNN.**Cwwx(,BB&:3x=/$WX #q(EI]]C = = ?@AXZ&*&6&6!&;F	w{  xI  xI  LP  L_  L_  x_  cd  wdC	{!D,<,<T+B#dFWFWEXXZ[_[n[nZooqr  jli'8CM? K&&*nn&:&:%; <++/+?+?*@	'T U  1F+5tDiik 	A##H+./, 	% 	 (,'7'7`!C!%%UVBW<W[_;_A`++CD1 ??Q!#D#9#; -1-=-=*&&}%KK"LSQ]M^_bLc d114]1CC0HH[!] ^-.KK"H\IZ[_H` a((+L(9$'??U!W X
 %%
002 ==))+B lO b	\E8_F|,J"#34N }}"7^!%3''/
 KK*6(#j\ B)#. /#N3D9 :#N3D9 :#N3D9	< = &BD**62$$(??;= =P."8"88UZ #m3#8MKK ###'==#@#@#B"C1!F G))%e1Ft}}G\G\]bGcdgFhhi/j * lMM..v6BUN$>$>>[`#}}CCE!L0KK"D^TWDXX\]ijm\nnv wx))%e1F~VYFZZ\]ijm\nnp/q * sMM..v6
 ~~m,"m3#8MKK"EjQ]F^_bEc d''1-'@&EV",Q~c.BBg!i j  --.32Fii2ii2!C'39c	KK"GWZG[ \''*3ivc#Y>s!u vMM..v6))%en]klo\ppwLx)y 11ns6JGWZG[[jkl**62%%eR%J\]klo\ppwHx%y ii?Gm+0D>C#77A.QTAUU`ahil`m  nB  C  D**62%%eR%J^_mnq^rrx  zA  BE  yF  FH  II%  J ]*v9N/NnVH4klm**62 ]*v9K/K08!&>1!=!K/NS4HKK"3F88NSVCWW[\ghk[l  mH  IW  X[  H\  \e  !f  gMM..v6
 '+nn&E&Ef]k&E&l#K**62!S(KK+fXXnS=QQijtiuuv wx #m3M#8MIH~~23&.(KK;H:S7@3bIK L!%!<!<T[[&RWYc!dIw%%*%K = CD%,[[1F%G6X_ceXefkq78LS7Q R$$,:gYiO]`@abe?f g##*?#;"< =!!(!24 8; < #
 	%%3g#'99;%)[[%;%;'j7'-4#N&
 &#j/R*?&(G%/ # '14QqT,1!A$K,1!A$K+01;-21Q4[.3AaDk49!A$K25ad);@2<
0" 
!## )+W(=I+.z"~a/@+AL (EYP\or'sH'=K)9 :9C 6 -1,>,>,F,FxQZ\h,i	*3M*B,5h,?	*3L*A+4\+B.2iikH.D-L
#,#615J$*KK2KGTW=Xabklwbxy|a} ~88?}D
RUV`adUeeg1i %j %+KK2J7SV-Wbclmxcyz}b~ 88?}D
RUV`adUeeg1i %j !'/s u"LL+PdnQTU_Q`tuPv  wH  *I  J MM..v6#0=1I#0NaPYZePfgjOkkl!mJ))%5Q[)\ ))&%A<<KK"Gx PQMM..v6))%5QZ)["nn::65'JT..YaclJm ; oG,,1,--2-226:--eWt-L 226:--eWuUc-d1$))GKKH[]_<`2a1bcd**62%%eWu+/99W[[ATVX5Y+Z & \Cb	\H 'G )  	* f  m ! HLL#B1#!FGGH2 a  D>qcBCCD\ % g)?sBd'effgs   AC6AC./AD AD6A%AD	 AD87AD8*B	AD= HAE,CAC+C*AC+C.ADD ADD		AD5DAD0D0AD5D=	AE)EAE$E$AE)E,	AFE5AFFAFc                    	 t        j                          | j                  z
  }| j                  r+t        | j                        t	        | j                        z  nd}|dkD  r| j
                  |z  dz  nd}g }| j                  j                  j                         D ]  \  }}t        j                          |j                  dt        j                                z
  dz  }|j                  |t        |j                  dd      d      t        |d      |j                  dd      |j                  d	      d
ud        i ddd| j                  d| j                  rdnddt        |d      d| j
                  dt        d| j                  dt        | j                  d      dt        |d      dt        |d      d| j                   dt	        | j"                        d| j$                  d| j&                  d| j(                  d| j*                  d | j                  j,                  || j.                  | j0                  t2        t4        t6        t8        t:         d!t<         t>        d"t@        d#tC               jE                         tG        jH                         d$}| jJ                  rL| jJ                  jM                         }	|	d%   |	d&   |	d'   d(   |	d'   d)   |	d'   d*   |	d'   d+   |	d,   |	d-   d.|d/<   tO        tP        d0d12      5 }
tS        jT                  ||
dtV        3       d
d
d
       y
# 1 sw Y   y
xY w# tX        $ r Y y
w xY w)4u9   Écrit le fichier de statut temps réel pour le dashboardr   rQ   r  r_  r+   r   rc  r   r  N)r   r  r  rc  trailing_activerunningTphasemoder  r  uptime_secondsr  scan_intervalr  r  r&   avg_scan_durationscans_per_minutepairs_monitoredwatchlist_countr  r  r  r  r  r  zunlimited (trailing only))surge_min_changevolume_ratio_minr  max_positionsr  hard_slr{  max_hold_min)positions_detailr  r  configr   pidr   regime_duration_minr   r  irrsurge_ft_ratesample_sizeshould_tradeposition_multiplier)r   r  r  r  r  r  r  r  r  r   r;   r<   rr  )-r   r  r  rn   rm   r  ri  rF  rH   rf  r]   r  r  r  r  r  r  r  r  r  r  r  rx  r  r  ri  r  SPY_POSITION_SIZEr  rf   r  r  r  r   r  r?   getpidr  r:  rD   SPY_STATUS_FILErE   r   rH  rI   )r   uptimeavg_scan_timescans_per_minpositions_inforL  ro   hold_minstatusr  rK   s              r   r2  zMarketSpy._write_status  s`   E	YY[4??2FKO??C03t3GG`aM?EzT__v5:qM  N NN44::< S IIK#'',		*LLPRR%%!$SWWY%:A>$)(A$6"%'',";'*ww'?t'K' !4!++! T\\	v! !%"2	!
 doo!  ! !$"5"5! %eD,C,CQ&G! $U=!%<! #E-$;! "4#;#;! "3t~~#6! "4#7#7! #D$9$9! "4#7#7!  #D$9$9!!" #DNN$8$8#!$ %3#// $ 1 1(>(>%6%6(9':!<N;O%P1#>$4	 '[224yy{A!FH }}]]--/ l+-.C+Di=/i=/%'	]?%C#%i=#?$&~$6+-.C+D	&z" osW= <		&!As;< < < 		s0   LL; L/&L; /L84L; 8L; ;	MMNc                    	 g }t         j                  j                  t              r0t	        t        dd      5 }t        j                  |      }d d d        |j                  t               j                         |d   |d   t        |d   dz  d      |d	   |j                  d
d      |d   dd|j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      |d   |d   |d   d|d   d|j                  dd      dddt        |j                  dd      dz         dg||d       t        |      d kD  r|d!d  }t	        t        d"d      5 }t        j                  ||d#t        $       d d d        y # 1 sw Y   exY w# 1 sw Y   y xY w# t        $ r Y y w xY w)%Nr:   r;   r<   r   rc  r^   rM  r   r]  rb  r   ra  r  r_   r  r  r   r  Fr  r^  r_  )r  bb_position
momentum_3volume_spiker  r  r  r  r^   r^  r_  VOL_r\  r  BUY_rP   rF  rY  )r   r   r~  scorer]  rb  volume_usdtr  signalsr  r  r1  ir   r+   rr  )r?   r@   rC   SPY_LOG_FILErD   rE   rF   rf  r   r  r]   rH   rm   r   rH  rI   )r   r  r&  r  r  r  rK   s          r   r=  zMarketSpy._log_opportunity  s   &	Gww~~l+,g> +!"iilG+ NN&[224/ .u%56;Q?w$)II.@!$D$\2#$")++h":$+KKQ$?!([!!<%,[[#%F+2;;7Le+T%,[[%%H&+,<&=$).$9$).$9 ",/4KQR8STW7XXY1Z^bchipitit  vA  CF  jG  HK  jK  dL  cM  MN  ]O  P$ / 4 7|c!!$%.lC': =a		'1Q<= =A+ +@= = 		sG   7G F2D<G F?)G 2F<7G ?GG G 	GGc                    t         j                  d| d       	 	 	 t        j                         }| j                          | j                  dk(  s$t        j                         | j
                  z
  dk\  r)| j                          t        j                         | _        | j                  dz  dk(  r | j                          | j                          t        d|t        j                         |z
  z
        }|dkD  rt        j                  |       # t        $ r  t        $ r}| xj                  dz  c_        d| _        t         j                  d|        t         j                  t!        j"                                | j%                          t        j                  d	       Y d }~d }~ww xY w# t        $ r? t         j                  d
       d| _        | j%                          | j                          Y y w xY w)Nu%   
🔄 Mode continu - Scan toutes les u   s (Ctrl+C pour arrêter)r   i  r  r   ERRORu   ❌ Erreur: r"   u   

🛑 Arrêt du Spy...STOPPED)r   r  r   rl  r  r  r  _print_summaryr  r  sleepKeyboardInterruptrI   r  r  r   r  
format_excr2  )r   r  t0waitr   s        r   run_continuouszMarketSpy.run_continuous  s   <XJF^_`"	""BMMO !+		d>]>]0]bf/f335:>))+7+q0++-99;q(diikB.>"?@Dax

4(# & )   "%%*%)0D&LL<s!34LL!5!5!78&&(JJqMM" ! 	"KK34!*D !		"s=   F- C0D F- F* B F% F- %F**F- -AG54G5c                    t         j                  dd        t         j                  d       t         j                  d        t         j                  d| j                   d| j                   d| j                   d       t         j                  d| j
                   d	| j                  j                          | j                  j                  j                         D ]k  \  }}t        j                         |j                  d
t        j                               z
  dz  }t         j                  d| d|d    d|d   dd|dd	       m 	 t        j                  j                  t              rt        t        dd      5 }t!        j"                  |      }d d d        rt%        d |D              }t%        d |D              }t'        j(                  |D cg c]  }|d   	 c}      }	t'        j(                  |D cg c]  }|j                  dd       c}      }
t         j                  d| dt+        |       d|t+        |      z  d z  d!d"|d#d$|	dd%|
dd       | j.                  r0t         j                  d&| j.                  j1                                 t         j                  d        y # 1 sw Y    xY wc c}w c c}w # t,        $ r Y uw xY w)'N
u   ═══════════════════════════════════════════════════════u#   📊 RÉSUMÉ SPY v3 - Pump Catcherz
   Scans: z | Surges: r  u    confirmés)z   Trades: z | Positions: r  rQ   u      📌 z: Entry=rl   z
 | MaxPnL=r_  r  z	% | Hold=r\  r\   r:   r;   r<   c              3   2   K   | ]  }|d    dkD  sd  yw)r  r   r   Nr   r  r  s     r   r  z+MarketSpy._print_summary.<locals>.<genexpr>L  s     CQ!I,2BqCs   c              3   @   K   | ]  }|j                  d d        yw)r  r   N)rH   r  s     r   r  z+MarketSpy._print_summary.<locals>.<genexpr>M  s     #GQAEE*a$8#Gs   r  r  r   u      📈 r  z wins (rF  r  z
%) | PnL: z+.4fz USDT | Avg: r  r  )r   r  r  r  r  r  ri  rx  rF  r   rH   r?   r@   rC   rj  rD   rE   rF   rn   r   r  rm   rI   r  r  )r   rL  ro   holdrK   histr  r  r  avg_pnlavg_holds              r   r  zMarketSpy._print_summary:  s   b%&9;zl$j 1T=Q=Q<R S--.l< 	=k$"6"6!7~dnnFZFZE[\]00668 	NHCIIK#'',		"DDJDKK(3%xM0B/C D!!$Y 5YtCjM N	N
	ww~~./*C'B (a99Q<D(C$CCD ##G$#G GI ggT&Bq|&BCG!ww$'OQna(@'OPHKK(4&#d)GDTNSVDVWZC[ \&&/%5 6&&-d^:hs^3!P Q
 ==KK#dmm;;=>?@zl$( (
 'C'O  		sD   5K J6AK K%K ?KAK 6K ;K 	KK)Fr   )r   r   r   r   r   r  r  r  r  r  rl  r2  r=  r  r  r  r   r   r   r{  r{  m	  sR    
@*D&;Jz>E@EJNENGR'V '4 %"N%r   r{  c                     t        j                  d      } | j                  ddd       | j                  ddd       | j                  d	t        t        d
t         d       | j                         }t        |j                        }|j                  rt        j                  d       |j                          t        j                  d|j                   d       t        j                  |j                         t        j                  d       |j                          |j                          y |j!                  |j                         y )Nu$   🕵️ Market Spy v3 - Pump Catcher)descriptionz--once
store_truezUn seul cycle (2 scans))actionhelpz	--dry-runzMode simulationz
--intervalu!   Intervalle entre scans (défaut: zs))r  rs  r  )r  u'   📸 Scan 1: snapshot de référence...u   ⏳ Attente zs...u%   📸 Scan 2: détection des surges...)r  )argparseArgumentParseradd_argumentr   r  
parse_argsr{  r  oncer   r  rl  r  r   r  r  r  )parserargsspys      r   mainr  ^  s   $$1WXF
<UV
L?PQ
3?bQ  S D
DLL
)Cyy=>l4==/67

4==!;<.r   __main__)r   )r   )r   r?   sysrE   r   r   r   r  logginglogging.handlersr  r   r   r   urllib.parser   collectionsr   zoneinfor   r   numpyr   r   r   market_behaviorr   r   r  ImportErrorr  _ml_classifierr@   insertrA   ro  abspath__file__signal_classifierr   feature_engineeringr   pandasrB  r  rB   r~  r   r   r   r   r   r   printexitr  TESTNET_APIr   r  r7  r8  r6  r4  r  ri  rj  r  SURGE_CONFIRM_KLINESrp  ro  rn  rk  rm  rx  rw  ru  rv  rs  rt  rz  rg  ry  rh  r|  r{  r  r}  r~  r  r@  rA  rM   _BASE_POSITION_SIZEr  SPY_POSITION_SIZE_STRONGr  r;  rf   r  re   rd   r  r  r  r  r  r  r  r  r  r  ra   rh   rt   rt  r  rm  r  rj  r  rG  rE  r  r  r5  r   	Formatterr   	getLoggerr   setLevelINFO	propagateStreamHandler_console_handlersetFormatter
addHandlerhandlersWatchedFileHandlerfile_handlerr   r   r   r   r   r/  rg  r{  r  r   r   r   r   <module>r     s  < 
 
         2 2 " #    N#"8 "
 E
 ! 	HHOOArww||BGGOOBGGOOH4M$NP_`a2A# WW__RWW__X67
 :   +.)k~ 		              #  # " !    "      $( !). &    	 
! *+ ' .                2BJ0 j*:;j*:;'',,z+?@ww||J(CD77<<
,AB '',,z+<=ww||J0FG ww||J0EF    =1n'** ' 
		<	(    )7((*    01PZde f   " # 22GGLL-. 3    ,-LV`a b   ,  !ggll277??277??8;T+UWst S  c cTn$ n$jz# z#B j% j%b/0 zF si      		  	
/0CHHQKs7   
Q -A:Q 8Q" QQQQ"RR