
    dim                        U 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mZmZ ddlm	Z	m
Z
mZmZ ddlZ	 ddlmZmZmZmZmZ ej*                  j-                  ej*                  j/                  e      d
      Zej*                  j-                  ed      Zej*                  j-                  ed      Zej*                  j-                  ej*                  j/                  e      d      ZdZdZdZdZ  G d d      Z!da"ee!   e#d<   dTde$de!fdZ% G d d      Z&dTde$de	e'ef   fdZ(e)dk(  r'ddl*Z* e+d        e+d        e+d        e%d	      Z, e+d        ejZ                  e,j]                  d	            Z/ e+d        e,ja                         Z1 e+d!e1d"            e+d#e1d$            e+d%e1d&           e1je                  d'      r0e1d'   Z3 e+d(        e+d)e3d*    d+e3d,    d-        e+d.e3d/            e+d0        e+d1        e+d        e(d	      Z4e4je                  d2      rv e+d3        e5e4d2   dd4 d5      D ]\  \  Z6Z7 e+d6e6 d7e7d8   jq                  d9d:       d;e7d<    d=e7je                  d>d?               e+d@e7dA   dBdCe7dD    dEe7dF   dGdH       ^ e4je                  dI      rA e+dJ       e4dI   dd4 D ].  Z9 e+dKe9d8   jq                  d9d:       dLe9dA   dBdMe9d<    dN       0 e4je                  dO      rA e+dP       e4dO   dd4 D ].  Z: e+dKe:d8   jq                  d9d:       dQe:dF   dGdRe:d<    dN       0  e+dS       yy# e$ r dZdZdZdZd	ZY w xY w)Uu  
Crypto Data Fetcher - Récupère et met en cache les données de 64 cryptos depuis Binance
Ce module permet d'accélérer les requêtes en stockant les données localement.

Fonctionnalités:
- Télécharge les prix, volumes et données OHLCV depuis Binance
- Calcule les indicateurs techniques (RSI, EMA, BB, MACD)
- Stocke les données en cache JSON pour un accès rapide
- Met à jour automatiquement les données selon un intervalle configurable

Auteur: Trading Bot System
Date: Décembre 2025
    N)datetime	timedelta)DictListOptionalAny)MIN_AI_SCORE_FOR_BUYRSI_OVERSOLDRSI_OVERBOUGHTMIN_BUY_SIGNALSBLOCK_BUY_ON_BEARISHF         Tcrypto_cachezcrypto_data.jsonzcache_metadata.jsonwatchlist.jsonzhttps://api.binance.com/api/v3z%https://testnet.binance.vision/api/v3<   c                      e Zd ZdZd$defdZd%dZd%dZdee	   fdZ
defd	Zd
ej                  de	dee   fdZ	 d&d
ej                  de	de	dedee   f
dZd'dee   dedefdZdee   dedefdZd(dee   dededefdZd)dee   dedededef
dZd
ej                  de	dee   fdZd*dedee	ef   fdZdee	ef   fdZde	dee   fdZdee	ef   fd Zefd!eddfd"Zd%d#Z y)+CryptoDataFetcheru6   Gestionnaire de cache pour les données crypto Binanceuse_testnetc                     || _         |rt        nt        | _        i | _        d | _        d| _        d | _        t        j                         | _
        t        j                  t        d       | j                          y )NFT)exist_ok)r   BINANCE_TESTNET_URLBINANCE_API_URLbase_urlcachelast_updateis_updating_update_thread	threadingEvent_stop_eventosmakedirs	CACHE_DIR_load_cache)selfr   s     6/home/ubuntu/crypto_trading_bot/crypto_data_fetcher.py__init__zCryptoDataFetcher.__init__:   sb    &/:+%'
/3 :>$??, 	I- 	    returnNc           	         	 t         j                  j                  t              rgt	        t        dd      5 }t        j                  |      | _        ddd       t        dt        | j                  j                  di              d       t         j                  j                  t              rst	        t        dd      5 }t        j                  |      }t        j                  |j                  dd	            | _        t        d
| j                          ddd       yy# 1 sw Y   xY w# 1 sw Y   yxY w# t        $ r&}t        d|        i | _        d| _        Y d}~yd}~ww xY w)z&Charge le cache depuis le fichier JSONrutf-8encodingNz[CACHE] OK - Cache charge: symbols cryptosr    z[CACHE] Derniere mise a jour: z![CACHE] ERREUR chargement cache: )r#   pathexists
CACHE_FILEopenjsonloadr   printlengetMETADATA_FILEr   fromisoformatr   	Exceptionr'   fmetadataes       r(   r&   zCryptoDataFetcher._load_cacheI   s*   	$ww~~j)*cG< .!%1DJ.3C

yRT8U4V3WW_`aww~~m,-w? O1#yy|H'/'='=hll=Z\>]'^D$:4;K;K:LMNO O -	. .
O O  	$5aS9:DJ#D	$sN   5D; D#A/D; AD/D; #D,(D; /D84D; 8D; ;	E*E%%E*c           	      j   	 t        t        dd      5 }t        j                  | j                  |dd       ddd       | j
                  r| j
                  j                         ndt        | j                  j                  di             t        d	}t        t        dd      5 }t        j                  ||d
       ddd       t        dt        | j                  j                  di              d       y# 1 sw Y   xY w# 1 sw Y   HxY w# t        $ r}t        d|        Y d}~yd}~ww xY w)z(Sauvegarde le cache dans le fichier JSONwr.   r/      F)indentensure_asciiNr1   )r   symbols_countcache_expiry_minutes)rG   z"[CACHE] SAVED - Cache sauvegarde: r2   z![CACHE] ERREUR sauvegarde cache: )r7   r6   r8   dumpr   r   	isoformatr;   r<   CACHE_EXPIRY_MINUTESr=   r:   r?   r@   s       r(   _save_cachezCryptoDataFetcher._save_cache[   s
   	;j#8 GA		$**aFG @D?O?Ot//99;UY!$TZZ^^Ir%B!C(<H
 mS7; 1q		(Aa01 6s4::>>)UW;X7Y6ZZbcdG G1 1  	;5aS9::	;sF   D $C9A-D %D>:D 9D>D D
D 	D2D--D2c           
      N   t               }	 t        j                  j                  t              rt        t        dd      5 }t        j                  |      }|j                  |j                  dg              |j                  |j                  di       j                                |j                  |j                  di       j                                ddd       t        j                  j                  t              }t        j                  j                  |d	      t        j                  j!                  t        j                  j                  |d
ddd	            g}|D ]k  }	 t        j                  j                  |      rIt        |dd      5 }|j                  t        j                  |      j                                ddd       m t        j                  j!                  t        j                  j                  |d
dd            }	 t        j                  j                  |      rKt        |dd      5 }|j                  t        j                  |      j                  dg              ddd       |D 	cg c]T  }	|	j#                         rB|	j%                         r2t'        |	      dk\  r$|	j)                  d      s|	j)                  d      r|	V }
}	|
j+                          |
rt        dt'        |
       d       |
S g dS # 1 sw Y   6xY w# t        $ r}t        d|        Y d}~Vd}~ww xY w# 1 sw Y   wxY w# t        $ r}t        d| d|        Y d}~d}~ww xY w# 1 sw Y   xY w# t        $ r}t        d|        Y d}~d}~ww xY wc c}	w )uR   Récupère la liste COMPLÈTE des cryptos tradables (bot + spy testnet + spy prod)r-   r.   r/   r1   
auto_addedspy_injectedNz)[CACHE] WARN - Erreur lecture watchlist: zspy_coin_scores.jsonz..crypto_trading_proddataz)[CACHE] WARN - Erreur lecture spy scores : r   z.[CACHE] WARN - Erreur lecture prod watchlist:    USDTUSDCu   [CACHE] Watchlist complète: z cryptos (bot + spy))
BTCUSDTETHUSDTBNBUSDTSOLUSDTXRPUSDTADAUSDTDOGEUSDTAVAXUSDTDOTUSDTLINKUSDT)setr#   r4   r5   WATCHLIST_FILEr7   r8   r9   updater<   keysr?   r:   dirname__file__joinnormpathisasciiisalnumr;   endswithsort)r'   symbols_setrA   rS   rC   base_dirspy_scores_pathsr4   prod_wlsvalids              r(   _get_watchlistz CryptoDataFetcher._get_watchlistm   s   e	Cww~~n-.#@ LA99Q<D&&txx	2'>?&&txxb'A'F'F'HI&&txx'C'H'H'JK	L 77??8,GGLL#9:GGRWW\\(D:OQWYopq
 % 	ODO77>>$'dC': @a#**499Q<+<+<+>?@	O ''""277<<$@UWg#hi	Hww~~g&'39 HQ&&tyy|'7'7	2'FGH ( AqIIKAIIKCFaKjj(AJJv,>  A A 	

1#e*=QRSL
 	
UL L
  	C=aSABB	C@ @ OA$r!MNNOH H 	HB1#FGG	HAs   5L BL
L '-M	3L<M	-M= >5M13M= ?AN"
LL 	L9 L44L9<M	M			M.M))M.1M:6M= =	NNNc                     | j                   r| j                  sy| j                   t        t              z   }t	        j
                         |k  S )u&   Vérifie si le cache est encore valideF)minutes)r   r   r   rM   r   now)r'   expiry_times     r(   is_cache_validz CryptoDataFetcher.is_cache_valid   s;    tzz&&;O)PP||~++r*   sessionsymbolc                   K   	 | j                    d| }|j                  |t        j                  d            4 d{   }|j                  dk(  r)|j                          d{   cddd      d{    S ddd      d{    y7 M7 (7 7 # 1 d{  7  sw Y   yxY w# t        $ r}t        d| d|        Y d}~yd}~ww xY ww)	u+   Récupère les données 24h pour un symbolez/ticker/24hr?symbol=
   totaltimeoutN   z[CACHE] WARN - Erreur ticker rT   r   r<   aiohttpClientTimeoutstatusr8   r?   r:   )r'   rz   r{   urlresponserC   s         r(   _fetch_ticker_24hz#CryptoDataFetcher._fetch_ticker_24h   s     	A]]O#7x@C{{30E0EB0O{P 1 1T\??c)!)01 1 1 1 1
 101 1 1 1 1
   	A1&A3?@@	As   C<B+  BB+ #B'B(B+B+ 7B8B+ <C=B+ B	B+ CB+ BB+ B+ B(BB($B+ 'C(B+ +	C4C
C
CCintervallimitc                   K   	 | j                    d| d| d| }|j                  |t        j                  d            4 d{   }|j                  dk(  r)|j                          d{   cddd      d{    S ddd      d{    y7 M7 (7 7 # 1 d{  7  sw Y   yxY w# t        $ r}t        d	| d
|        Y d}~yd}~ww xY ww)u6   Récupère les données OHLCV (klines) pour un symbolez/klines?symbol=z
&interval=z&limit=r}   r~   r   Nr   z[CACHE] WARN - Erreur klines rT   r   )r'   rz   r{   r   r   r   r   rC   s           r(   _fetch_klineszCryptoDataFetcher._fetch_klines   s     	A]]O?6(*XJgV[U\]C{{30E0EB0O{P 1 1T\??c)!)01 1 1 1 1
 101 1 1 1 1
   	A1&A3?@@	As   CAB1 BB1 
#B-B.B1B1 =B>B1 CB1 BB1 CB1 BB1 B1 B."B%#B.*B1 -C.B1 1	C:CCCCclosesperiodc                    t        |      |dz   k  ryg }g }t        dt        |            D ]c  }||   ||dz
     z
  }|dkD  r#|j                  |       |j                  d       9|j                  d       |j                  t        |             e t        |      |k  ryt	        || d       |z  }t	        || d       |z  }|dk(  ry||z  }	ddd|	z   z  z
  }
t        |
d      S )zCalcule le RSI   g      I@r   Ng      Y@d   rF   )r;   rangeappendabssumround)r'   r   r   gainslossesichangeavg_gainavg_lossrsrsis              r(   _calculate_rsiz CryptoDataFetcher._calculate_rsi   s    v;!#q#f+& 	+AAY!,FzV$a Qc&k*	+ u:ufWX'&0vvgh'(61q= SAF^$S!}r*   valuesc                     t        |      |k  r	|r|d   S dS d|dz   z  }|d   }|dd D ]  }||z
  |z  |z   } t        |d      S )zCalcule l'EMAr   rF   r   N   )r;   r   )r'   r   r   
multiplieremavalues         r(   _calculate_emaz CryptoDataFetcher._calculate_ema   sl    v;!'6":.Q.&1*%
QiABZ 	3E3;*,s2C	3 S!}r*   std_devc                 0  
 t        |      |k  rdddddS || d }t        |      |z  
t        
fd|D              |z  }|dz  }
||z  z   }
||z  z
  }
dkD  r||z
  
z  dz  nd}	t        |d      t        
d      t        |d      t        |	d      dS )	zCalcule les bandes de Bollingerr   )uppermiddlelower	bandwidthNc              3   .   K   | ]  }|z
  d z    yw)rF   N ).0xr   s     r(   	<genexpr>z?CryptoDataFetcher._calculate_bollinger_bands.<locals>.<genexpr>   s     9QF
q(9s         ?r   r   rF   )r;   r   r   )r'   r   r   r   recentvariancestdr   r   r   r   s             @r(   _calculate_bollinger_bandsz,CryptoDataFetcher._calculate_bollinger_bands   s    v;!aaHH!Vv%9&99FB#o#-(#-(8>
eemv-4	 5!_FA&5!_y!,	
 	
r*   fastslowsignalc                     t        |      |k  rddddS | j                  ||      }| j                  ||      }||z
  }|dz  }||z
  }	t        |d      t        |d      t        |	d      dS )zCalcule le MACDr   )macdr   	histogramg?r   )r;   r   r   )
r'   r   r   r   r   ema_fastema_slow	macd_linesignal_liner   s
             r(   _calculate_macdz!CryptoDataFetcher._calculate_macd  s    v;;;&&vt4&&vt4x'	  #o+	 )Q'K+y!,
 	
r*   c                   K   	 | j                  ||      }| j                  ||dd      }t        j                  ||       d{   \  }}|syg }|r|D cg c]  }t	        |d          }}t	        |j                  dd            }	||	t	        |j                  dd            t	        |j                  dd            t	        |j                  d	d            t	        |j                  d
d            t	        |j                  dd            t	        |j                  dd            t	        |j                  dd            t	        |j                  dd            |r| j                  |d      nd|r| j                  |d      nd|r| j                  |d      n|	|r| j                  |d      n|	t        |      dk\  r| j                  |d      n|	|r| j                  |dd      ni |r| j                  |      ni d|r|d   | j                  |d      kD  rdnd| j                  |d      dk  rdn| j                  |d      dkD  rdnd| j                  |      j                  dd      d kD  rd!nd"d#t        j                         j                         d$}
|
S 7 Sc c}w # t        $ r}t        d%| d&|        Y d}~yd}~ww xY ww)'uE   Traite un symbole: récupère les données et calcule les indicateurs1hr   N   	lastPricer   priceChangepriceChangePercentvolumequoteVolume	highPricelowPrice	openPriceweightedAvgPrice   2      	                @)r   rsi_7	ema_shortema_longema_50	bollingerr   r   bullishbearishr   oversoldr   
overboughtneutralr   rU   highnormal)trend
rsi_signal
volatility)r{   pricer   r   r   r   high24hlow24hr   r   
indicatorssignals
updated_atz[CACHE] ERREUR traitement rT   )r   r   asynciogatherfloatr<   r   r   r;   r   r   r   rw   rL   r?   r:   )r'   rz   r{   ticker_taskklines_tasktickerklinesr   kcurrent_pricerS   rC   s               r(   _process_symbolz!CryptoDataFetcher._process_symbol  s    7	00&AK,,WfdCHK#*>>+{#KKNFF F/56!%!+66 "&**[!"<=M !&$VZZq%AB&+FJJ7KQ,O&P

8Q 78$VZZq%AB K!;<

:q 9:"6::k1#=>$)&**5G*K$L ?E4..vr:"?ET00;2CI!4!4VQ!?}CI 3 3FB ?}ADVPRARd11&"=XeU[!@!@S!Qac<BD008 +1VBZ$BUBUV\^`Ba5aYgp040C0CFB0ORT0T*kok~k~  @F  HJ  lK  NP  lP[g  V_,0,K,KF,S,W,WXcef,gjk,k&qy 'lln668=DB K] L 7P  	.vhb<=	s_   K?J J	J KJ J+H*J KJ J 	K'J=8K=KKforcec           	        K   |s'| j                         rt        d       | j                  S | j                  rt        d       | j                  S d| _        t	        j                         }	 | j                         }t        dt        |       d       t        j                         4 d{   }d}i }t        dt        |      |      D ]  }||||z    }|D 	cg c]  }	| j                  ||	       }
}	t        j                  |
  d{   }|D ]  }|s|||d	   <    ||z   t        |      k  sht        j                  d
       d{     ddd      d{    t        |      t        j                         j!                         | j"                  rdndt$        d| _        t        j                         | _        | j)                          t	        j                         |z
  }t        d|ddt        |       d       | j                  d| _        S 7 mc c}	w 7 7 7 # 1 d{  7  sw Y   xY w# t*        $ r+}t        d|        | j                  cY d}~d| _        S d}~ww xY w# d| _        w xY ww)uE   Récupère toutes les données pour tous les symboles de la watchlistz;[CACHE] OK - Cache valide, utilisation des donnees en cachez&[CACHE] WAIT - Mise a jour en cours...Tz [CACHE] UPDATE - Mise a jour de z cryptos depuis Binance...Nr   r   r{   r   binance_testnetbinance)r1   countr   sourcerJ   z%[CACHE] OK - Mise a jour terminee en z.2fzs - r2   Fz[CACHE] ERREUR mise a jour: )ry   r:   r   r   timert   r;   r   ClientSessionr   r   r   r   sleepr   rw   rL   r   rM   r   rN   r?   )r'   r   
start_timer1   rz   
batch_sizeresultsr   batchr{   tasksbatch_resultsresultelapsedrC   s                  r(   fetch_all_dataz CryptoDataFetcher.fetch_all_dataR  sP     ,,.OP:::;::YY[
-	%))+G4S\NB\]^,,. 1 1'
q#g,
; 1A#Aa
l3EQVWvT11'6BWEW*1..%*@$@M"/ ?!8>GF8$45?
 :~G4%mmC00011 1( #W&lln668/3/?/?+Y(<DJ  (||~D iikJ.G9'#d3w<.X`ab::  %DS1 X$@ 1!1 1 1 1J  	045::$D		  %Ds   A(I?+A H< +H,H< /*H'H2H'	H 
H'H'2H'
H#H'H< H%B3H< I?H< H'#H'%H< 'H9-H0.H95H< <	I0I+I0I3 #I?+I00I3 3	I<<I?c                     | j                   S )u2   Retourne les données en cache (sans mise à jour))r   r'   s    r(   get_cached_dataz!CryptoDataFetcher.get_cached_data  s    zzr*   c                 \    | j                   j                  di       }|j                  |      S )u.   Retourne les données d'un symbole spécifiquer1   )r   r<   )r'   r{   r1   s      r(   get_symbol_dataz!CryptoDataFetcher.get_symbol_data  s%    **..B/{{6""r*   c                    | j                   j                  di       }|sddddS t        d |j                         D              }t	        |      |z
  }|j                         D cg c],  }|j                  di       j                  d      d	k(  s(|d
   . }}|j                         D cg c],  }|j                  di       j                  d      dk(  s(|d
   . }}t        |j                         d d      }|dd D cg c]  }|d
   |j                  dd      d }}|dd D cg c]  }|d
   |j                  dd      d }	}t	        |      | j                         | j                   j                  d      t        |||rt        |t	        |      z  dz  d      ndd|dd |dd d||	dS c c}w c c}w c c}w c c}w )u   Retourne un résumé du cacher1   r   FN)r   rs   r   c              3   j   K   | ]+  }|j                  d i       j                  d      dk(  s(d - yw)r   r   r   r   Nr<   )r   rr   s     r(   r   z0CryptoDataFetcher.get_summary.<locals>.<genexpr>  s/     j!155B;O;S;ST[;\`i;iAjs   )33r   r   r   r{   r   c                 &    | j                  dd      S )Nr   r   r  r   s    r(   <lambda>z/CryptoDataFetcher.get_summary.<locals>.<lambda>  s    !%%H\^_B` r*   TkeyreverserU   r   )r{   r   r   r   r   )r   r   ratior}   )r   r   )r   rs   r   expiry_minutesmarket_sentimentr   top_gainers
top_losers)	r   r<   r   r   r;   sortedry   rM   r   )
r'   r1   bullish_countbearish_countrr   r   r   sorted_by_changer  r  s
             r(   get_summaryzCryptoDataFetcher.get_summary  s   **..B/#  jw~~'7jjG}4)0)9rAQUU9b=Q=U=UVb=cgq=qAhKrr+2>>+;vaquuYPR?S?W?WXd?eiu?uakv
v "'.."28`jnobrsutubvw]^!H+?SUV9WXwwaqrtruavw\]8>RTU8VWw
w \((*::>>,72((IP}s7|;cA1EVW! %SbM("o '$
 	
 sv xws$   %)F3F3*)F8F8F=)Ginterval_secondsc                 6     j                   r& j                   j                         rt        d       y j                  j	                           fd}t        j                  |d       _          j                   j                          t        d d       y)u5   Démarre la mise à jour automatique en arrière-planz2[CACHE] WARN - Mise a jour automatique deja activeNc                  r   j                   j                         sxj                   j                         j                   j                         ry 	 t        j                  j                  d             j                   j                         swy y # t        $ r} t        d|         Y d } ~ 9d } ~ ww xY w)NTr   z[CACHE] ERREUR auto-update: )r"   is_setwaitr   runr  r?   r:   )rC   r!  r'   s    r(   update_loopz8CryptoDataFetcher.start_auto_update.<locals>.update_loop  s    &&--/  %%&67##**,>KK 3 3$ 3 ?@ &&--/ ! >8<==>s   %B 	B6B11B6T)targetdaemonz([CACHE] AUTO-UPDATE active (intervalle: zs))r   is_aliver:   r"   clearr    Threadstart)r'   r!  r(  s   `` r(   start_auto_updatez#CryptoDataFetcher.start_auto_update  s}    4#6#6#?#?#AFG 
	> (..k$O!!#89I8J"MNr*   c                     | j                   j                          | j                  r| j                  j                  d       t	        d       y)u#   Arrête la mise à jour automatiquerU   r   z[CACHE] AUTO-UPDATE arreteeN)r"   rb   r   rh   r:   r	  s    r(   stop_auto_updatez"CryptoDataFetcher.stop_auto_update  s=    $$Q$/+,r*   T)r+   N)r   r   )r   )r   r   )      r   )F)!__name__
__module____qualname____doc__boolr)   r&   rN   r   strrt   ry   r   r   r   r   r   intr   r   r   r   r   r   r   r   r  r
  r  r   UPDATE_INTERVAL_SECONDSr/  r1  r   r*   r(   r   r   7   s   @D $$;$4
S	 4
l, ,	w/D/D 	c 	V^_cVd 	 ?B
7+@+@ 
# 
%(
8;
FNtn
T%[ # u <T%[ # % 
e 
c 
Y^ 
im 
,
d5k 
 
 
[^ 
gk 
(9W-B-B 9C 9T\]aTb 9v<%$ <%4S> <%|c3h #c #htn #
'
T#s(^ '
R 9P O# OTX O0-r*   r   _fetcherr   r+   c                 2    t         t        |       a t         S )z&Retourne l'instance globale du fetcherr   )r=  r   r?  s    r(   get_fetcherr@    s     $=Or*   c                       e Zd ZdZdddddddZededeeef   fd	       Z	eddede
de
dee   fd       Zeddedede
dee   fd       Zeddedededee   fd       Zy
)TradingOpportunityScoreru  
    Système de scoring pour identifier les meilleures opportunités de trading.
    Utilise les paramètres de config.py pour être cohérent avec le bot.
    
    Critères de scoring (sur 100 points):
    - RSI Signal (25 pts): Survente = achat, Surachat = vente
    - Tendance EMA (20 pts): Prix au-dessus/dessous des EMA
    - Momentum (20 pts): Force du mouvement récent
    - Volatilité (15 pts): Bandes de Bollinger favorables
    - Volume (10 pts): Volume supérieur à la moyenne
    - Stabilité (10 pts): Pas de mouvements extrêmes
    
    Seuils utilisés depuis config.py:
    - MIN_AI_SCORE_FOR_BUY: {min_score} (score minimum pour achat)
    - RSI_OVERSOLD: {rsi_oversold} (seuil survente)
    - RSI_OVERBOUGHT: {rsi_overbought} (seuil surachat)
       r      r}   )r   r   momentumr   r   	stabilitycrypto_datar+   c                 	   | sddi dS | j                  di       }| j                  di       }i }d}|j                  dd      }t        }t        }||dz
  k  rd	}n>||k  rd
}n6||dz   k  rd}n+||dz   k  rd}n ||dz   kD  rd}n||kD  rd}n||dz
  kD  rd}nd}||d	d|d<   ||z  }| j                  dd      }	|j                  d|	      }
|j                  d|	      }|j                  dd      }|j                  dd      }|j                  dd      }|dkD  r/|dkD  r*|dkD  r%||cxkD  r|kD  rn nd}n*||cxkD  r|kD  rn nd}nd}n|
dkD  r|dkD  r
|
|kD  rdnd}nd}|	dkD  r7|
dkD  r2|dkD  r-|
|kD  r|	|
kD  rd}n"|
|kD  rd}n|	|kD  rd}n|
|k  r|	|
k  rd}nd}nd}|
|kD  rdnd}||d|d|d<   ||z  }| j                  dd      }d |cxk  rdk  rn nd}nNd|cxk  rd k  rn nd!}n=d|cxk  rd!k  rn nd}n,d"|cxk  rdk  rn nd}nd#|cxk  rd"k  rn nd}n
|d#k  rd}nd}||dd$|d%<   ||z  }|j                  d&i       }|j                  d'd      }|j                  d(d      }|j                  d)d      }|j                  d*d      }|j                  d+d      }|dkD  r#|dkD  r||z
  |z  d,z  }|d-kD  rd.}n|d/k  rd0}nd1}n|d2kD  rd.}n
|d3k  rd0}nd1}d |cxk  rdk  rn nd!}n,d2|cxk  rd k  rn nd}nd|cxk  rdk  rn nd}n
|dkD  rd}nd}d4}|	dkD  rE|dkD  r@|dkD  r;||kD  r|	|z
  ||z
  z  nd4}|d5k  rt        d!|dz         }n|d6kD  rt	        d|d7z
        }||d!||d8|d9<   ||z  }| j                  d:d      }|d;kD  rd}n|d<kD  rd}n|d=kD  rd>}n
|d?kD  rd@}nd }||ddA|dB<   ||z  }| j                  dCd      } | j                  dDd      }!| dkD  r3|!dkD  r.| |!z
  |!z  d,z  }"|"d7k  rd}#n|"dk  rd}#n|"dk  rd>}#n|"d!k  rd@}#nd }#nd}#dEt               v r"nd|#ddF|dG<   ||#z  }dH}$|dkD  r|n|
}%|dkD  r|n|}&|%dkD  r|&dkD  r|%|&z
  |&z  d,z  }'|'dk\  rdI}$|dk(  xs |dk(  xs |d0k(  xs |t        kD  xs |d3k  }(|$xs |(})|dk  }*t        }+|$rdJ},dK}-n/||+dz   k\  rdL},dM}-n"||+k\  rdN},dO}-n|dPk\  rdQ},dR}-n|dSk\  rdT},dU}-ndV},dW}-||,|-||||||)|dX
S )Yu   
        Calcule le score d'opportunité pour une crypto.
        Retourne un dict avec le score total et les détails.
        Utilise les seuils de config.py.
        r   none)scorer   detailsr   r   r   r   rU   rC        r}   r   r   r3  )r   rJ  maxr   r   r   ema_9ema_21r   r   r   mixedunknownr      )	directionrJ  rN  ema_alignmentr   r   rF   rD  i)
change_24hrJ  rN  rE  r   r   r   r   r   prev_middler   g?upgdownflatr   r   r   g?g?r   )r   rJ  rN  bb_directionbb_positionr   r   i ii    i@B r   )quote_volumerJ  rN  r   r   r   daily_range)r`  rJ  rN  rF  FTblockedu   🚫 NO BUY (EMA9 >= EMA21)
strong_buyu   🚀 Achat Fortbuyu	   ✅ Achat-   r   u   ⏸️ HOLDr   sellu
   📉 Ventestrong_sellu   🔻 Vente Forte)
rJ  r   recommendationrK  r   r   rU  r\  
is_bearishrW  )r<   r
   r   minrN  dirr	   ).rG  r   r   rK  total_scorer   rsi_oversoldrsi_overbought	rsi_scorer   r   r   rO  rP  r   rU  trend_scoretrend_directionrW  momentum_scorebbr   bb_lowerbb_upper	bb_middlebb_prev_middlebb_sloper\  	vol_scorer]  r   volume_scorer   lowr`  stability_scoreema_blocks_buy	ema_9_val
ema_21_valema_diff_pctis_bearish_secondaryrh  
is_fallingmin_score_buyr   rg  s.                                                 r(   calculate_scorez(TradingOpportunityScorer.calculate_score  s    &R@@ __\26
//)R0 nnUB'#'!!I<I<!##I<"$$I>A%%I>!I>A%%II#&2Fy  +NN;6	>>*e4w*!,!, 19!
v&& )&(5( ) ']x!|)2X)=I9M%M19Q8a<8#	(9 X% ! X%%)*; K'08';))8;WYlyz{" !__%91=
 
aN* q N!r!N:!!N:""N"_NN-7.Y[\
~% ^^K,FF;*	66'1%66'1%FF8Q'	 q1q=^a/"^3~ELH#~#D%%!^L"_!L!L 	QI)aIaI]II 19A(Q,HPS[H[58+80CDadKS IM2	s"9q=1	.7)TVht  FQ  !Ry  2KLj Lj LiLL-3lSUV|# y!,ooh*!8a 3J#-4KQ"$q"#r!"#r!"#"#O>Ksu>T{Z[fu  A   B& "QYEI	%zVx
q=Z!^&3zASHLq !% Y& y(F" .  O 	 $;';
  !^
 - F:NMA--!F.NM)F(NBF*NBF)N"F/N !,$*($$
 	
r*   N
cache_datar   	min_scorec           	         |t        dt        dz
        }| j                  di       }g }|j                         D ]o  \  }}t        j                  |      }|j                  d      dk(  r0|d   |k\  s9|j                  ||j                  dd	      |j                  d
d	      d|       q |j                  d d       |d| S )u   
        Retourne les meilleures opportunités de trading triées par score.
        EXCLUT les cryptos où EMA9 >= EMA21 (signal='blocked').
        Utilise MIN_AI_SCORE_FOR_BUY - 20 comme seuil par défaut (50 si MIN=70).
        Nr   r   r1   r   ra  rJ  r   r   r   r{   r   rW  c                     | d   S NrJ  r   r  s    r(   r  z@TradingOpportunityScorer.get_top_opportunities.<locals>.<lambda>4  s
    7 r*   Tr  rN  r	   r<   itemsrB  r  r   rm   )r  r   r  r1   opportunitiesr{   rS   scorings           r(   get_top_opportunitiesz.TradingOpportunityScorer.get_top_opportunities  s     B 4r 9:I..B/#MMO 	LFD.>>tDG {{8$	1w9,$$$!XXgq1"&((+?"C& 	& 	  	3TBVe$$r*   rsi_thresholdc           
         |d}|t        dt        dz
        }| j                  di       }g }|j                         D ]  \  }}|j                  di       }|j                  dd      }||k  s0t        j                  |      }	|	j                  d      dk(  rZ|	d	   |k\  sc|j                  ||j                  d
d      ||j                  dd      d|	        |j                  d        |S )u   
        Retourne les cryptos avec signal d'achat (RSI bas + bon score).
        EXCLUT les cryptos où EMA9 >= EMA21 (signal='blocked').
        Accepte les creux BB avec un score minimum réduit.
        rd  rC  r1   r   r   r   r   ra  rJ  r   r   r   )r{   r   r   rW  c                     | d   S )Nr   r   r  s    r(   r  z:TradingOpportunityScorer.get_buy_signals.<locals>.<lambda>]  s
    qx r*   )r  r  )
r  r  r  r1   buy_signalsr{   rS   r   r   r  s
             r(   get_buy_signalsz(TradingOpportunityScorer.get_buy_signals8  s
     MB 4r 9:I..B/#MMO 	LFD,3J..+C]"2BB4H ;;x(I57#y0&&"(!%'1!5"&*hh/CQ&G	(
 "( 	* 	/0r*   
min_change
max_changec                 F   | j                  di       }g }|j                         D ]b  \  }}|j                  dd      }||cxk  r|k  s$n 't        j                  |      }|j	                  ||j                  dd      |d|       d |j                  d d       |d	d
 S )uZ   
        Retourne les cryptos avec bon momentum (hausse modérée, pas extrême).
        r1   r   r   r   r  c                     | d   S r  r   r  s    r(   r  z=TradingOpportunityScorer.get_momentum_plays.<locals>.<lambda>w  s
    !G* r*   Tr  Nr}   )r<   r  rB  r  r   rm   )	r  r  r  r1   momentum_playsr{   rS   r   r  s	            r(   get_momentum_playsz+TradingOpportunityScorer.get_momentum_playsa  s    
 ..B/#MMO 	LFDXX2A6FV1z12BB4H%%$!XXgq1"(' 	' 	 	 4dCcr""r*   )r}   N)NN)r   r3  )r5  r6  r7  r8  WEIGHTSstaticmethodr   r:  r   r  r;  r   r  r   r  r  r   r*   r(   rB  rB    s    ( G E
T E
d38n E
 E
N %$ %s %C %[_`d[e % %B &D & &RU &aefjak & &P #t # #PU #_cdh_i # #r*   rB  c           
      L   t        |       }|j                         }|r|j                  d      sdg dS t        j	                  |dd      t        j                  |dd      t        j                  |d	d
      |j                  d      t        |j                  di             dS )u5   Retourne les opportunités de trading depuis le cacher1   z
Cache vide)errorr  r}   r   )r   r  #   )r  r  rF   )r  r  r   )top_opportunitiesr  r  r   total_cryptos)r@  r
  r<   rB  r  r  r  r;   )r   fetcherr   s      r(   get_opportunitiesr  }  s    +&G##%E		),%;; 6KKEY[giKj/??UWce?f2EEeXYfhEiii-UYYy"56 r*   __main__z<============================================================zCrypto Data Fetcher - Testr?  z+
Recuperation des donnees depuis Binance...r$  z
Resume du cache:z  - Cryptos en cache: r   z  - Cache valide: rs   z  - Derniere MAJ: r   r  z
Sentiment du marche:z  - Bullish: r   z (r  z%)z  - Bearish: r   z=
============================================================z4OPPORTUNITES DE TRADING (Nouveau Systeme de Scoring)r  z!
Top 5 Opportunites (Score > 50):rU   r   z  z. r{   rV   r3   z: Score rJ  z/100 | r   zN/Az
     RSI: r   z.1fz
 | Trend: r   z | 24h: rW  z+.2f%r  z
Signaux d'Achat (RSI < 35):z  - z: RSI=z	 | Score=z/100r  z
Momentum Plays (+2% a +10%):rT   z
% | Score=z
Test termine!r2  );r8  r#   r8   r   r   r   r   r   typingr   r   r   r   r    configr	   r
   r   r   r   ImportErrorr4   rh   rf   rg   r%   r6   r=   rc   r   r   rM   r<  r   r=  __annotations__r9  r@  rB  r:  r  r5  sysr:   r  r'  r  rS   r   summaryr<   	sentimentopps	enumerater   oppreplacesigmpr   r*   r(   <module>r     s,   
     ( , ,     GGLL2NC	WW\\)%78
Y(=>bggooh79IJ 3=    h- h-X )-($
% ,T -> H# H#X4 4S> $ z	(O	
&'	(Od+G 

897;;w--D-9:D	 !!#G	"77#3"4
56	ww/0
12	w}56
78{{%&./	&(i	232i6H5ILMi	2345 
/	
@A	(O.Dxx#$24%8 9"1 =qA 	jFAsBqcCM11&"=>hs7|nT[\_\c\cdlns\t[uvwJs5z#.jWhsS_O`aeNffghi	j xx-/&r* 	oCDX..vr:;6#e*SAQQZ[^_f[gZhhlmn	o xx !.0'(!, 	qBDH--fb9:"R=Md<SS]^`ah^i]jjnop	q 

a ]   LNO s   M MM