
    [ j                    p"   S SK r S SKrS SKrS SKJrJrJrJr  S SKJ	r	  S SK
Jr  S SKrS SKrS SKrS SKJrJrJr  S SKrS SKrS SKrS SKr S SKJr  S SKrS SKrS SKJr  S SKrS SKr S SK!r"S SK#r$S S	KJ%r%  S S
K&J'r'  S SK(J)r)J*r*  S SK+J,r,  S SK-r-S SK.r.S SK(r(S SK/r/S SK0r0S SK1r1S SK2J3r3  S SK4J5r5  S SK6J7r7  S SKJ8r8  S SK9J:s  J;r<  S SK=r=S SK>r>S SK?r?S SK@r@S SKArAS SKBrCS SKDrDS SKEJFrG  S SKHrH\>R                  " \?R                  " 5       S9rK S SKLrL S SKMJMrM   S SKNrNSrO S SKPrPSrQ S SKRrRSrS S SKTJUrV  SrW S SKXJYrY  SrZ S SK[J\r\  S S K]J^r_  Sr`\.R                  " S"5        \%" 5       rb0 qcSqdS# reS$ rf0 qg\%" 5       rhGSS% jriS& rjGSS' jrk\k" 5       rl\lR                  R                  S(S)S*S+S,S-.5        S. roS/rpS0rqS1rrS2 rsS3 rtS4S5S6.S4S7S6.S4S8S6.S4S9S6.S4S:S6.S4S;S6.S4S<S6.S4S=S6.S>.SS?.quS@ rv\" \w5      rx SA\xR                  SB'   S\xR                  SC'   SDSESFSGSH.\xR                  SI'   \" \x5      rz\" SJ5        \	" \xSNSOSP00SSQ9  \xR                  SR 5       r " SS ST\zGR                   5      r " SU SV\zGR                   5      r " SW SX\zGR                   5      r " SY SZ\zGR                   5      r " S[ S\\zGR                   5      r " S] S^\zGR                   5      r " S_ S`\zGR                   5      r " Sa Sb\zGR                   5      r " Sc Sd\zGR                   5      r " Se Sf\zGR                   5      r " Sg Sh\zGR                   5      r " Si Sj\zGR                   5      r " Sk Sl\zGR                   5      r\xGR                  5          \zGR                  5         SSS5        GSSm jrSn rGSSo jrSp rSq rSr rSs rSt rGSSu jr\GR2                  GR5                  SvSw5      rSxrSyrSzS{S|S}S~SSSSSSSSS.r " S S5      rS r " S S5      rS\4S jrS rS r " S S5      r\" 5       rSSS.qS r\GRT                  " \SS9r\GRY                  5          " S S5      r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r " S S5      r " S S5      r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r " S S5      r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       rS r\xGR]                  SS/S9S 5       rS rS r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       rS rS rS rGSS jrGSS jr\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       r\xGR]                  SS/S9S 5       rS SKrS SKr S SKr S SKrS rSqS rS rS rSqS r " S S5      rS rGSS jr " S S5      r " S S5      rSqSqS rGSS jrS rGSS jrS r " S S5      rS rS rS rS rS rS SKrGSS jrS rGSS jr " S S5      r\" SSES9rGSS jr " S S5      rSqSqS rGSS jrS r\xGR]                  SS/S9GS  5       r\xGR]                  GSS/S9GS 5       r\xGR]                  GSS/S9GS 5       r\xGR]                  GSS/S9GS 5       r\xGR]                  GSS/S9GS 5       rGS	 rGS
 rGS r\xGR]                  GSS/S9GS 5       r\xGR]                  GSS/S9GS 5       r\xGR]                  GSS/S9GS 5       Gr \xGR]                  GSS/S9GS 5       GrGS Gr\xGR]                  GSS/S9GS 5       GrGSGqGS GrGS GrGS Gr\RJ                  " 5       GrGSGS jGr	\xGR]                  GSS/S9GS 5       Gr
\xGR]                  GSS/S9GS 5       Gr0 GS GS _GS!GS _GS"GS"_GS#GS"_GS$GS$_GS%GS$_GS&GS&_GS'GS&_GS(GS(_GS)GS(_GS*GS*_GS+GS*_GS,GS-_GS-GS-_GS.GS-_GS/GS/_GS0GS/_0 GS1GS1_GS2GS2_GS3GS2_GS4GS5_GS6GS5_GS7GS5_GS8GS9_GS:GS9_GS;GS9_GS<GS<_GS=GS<_GS>GS?_GS@GS@_GSAGSA_GSBGSA_GSCGSC_GSDGSC_EGSEGSEGSFGSGGSH.EGr " GSI GSJ5      Gr\xGR]                  GSKS/S9GSL 5       Gr\xGR]                  GSMS/S9GSN 5       Gr\xGR]                  GSOS/S9GSP 5       Gr\xGR]                  GSQS/S9GSR 5       Gr\xGR]                  GSSS/S9GST 5       GrGSU Gr\xGR]                  GSVS/S9GSW 5       Gr\xGR]                  GSXS/S9GSY 5       Gr\xGR]                  GSZS/S9GS[ 5       Gr\xGR]                  GS\S/S9GS] 5       Gr\xGR]                  GS^S/S9GS_ 5       Gr\xGR]                  GS`S/S9GSa 5       Gr\xGR]                  GSbS/S9GSc 5       Gr\xGR]                  GSdS/S9GSe 5       GrSGq\xGR]                  GSfS/S9GSg 5       Gr\xGR]                  GShS/S9GSi 5       Gr\xGR]                  GSjS/S9GSk 5       Gr\xGR]                  GSlS/S9GSm 5       Gr \xGR]                  GSnS/S9GSo 5       Gr!\xGR]                  GSpS/S9GSq 5       Gr"GSrGr#\" GSsGSt9Gr$SDGr%GSuGSvGSwGSxGSy.Gr&GSz Gr'GS{ Gr(GS| Gr)GS} Gr*GS~ Gr+GS Gr,GS Gr-GS Gr.GS Gr/GS Gr0GS Gr1\xGR]                  GSS/S9GS 5       Gr2\xGR]                  GSS/S9GS 5       Gr3\xGR]                  GSS/S9GS 5       Gr4\xGR]                  GSGS/S9GS 5       Gr5\xGR]                  GSS/S9GS 5       Gr6\xGR]                  GSS/S9GS 5       Gr7\xGR]                  GSS/S9GS 5       Gr8\xGR]                  GSS/S9GS 5       Gr9GS Gr:\xGR]                  GSS/S9GS 5       Gr;\xGR]                  GSS/S9GS 5       Gr<\xGR]                  GSS/S9GS 5       Gr=GS Gr>\xGR]                  GSS/S9GS 5       Gr?\xGR]                  GSS/S9GS 5       Gr@GS GrAGS GrBGS GrC " GS GS\CGR                  GR                  5      GrFGS GrG\wGS:X  Ga  \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" GS5        \" 5         \" 5         \GRT                  " G\GSS9GrHG\HGRY                  5         \AGR                  " GS5      GR                  \AGR                  5        Sq\GRT                  " G\:SS9GrLG\LGRY                  5         \GRT                  " G\>SS9GrMG\MGRY                  5         \" GS5        \GRT                  " G\CSS9GrNG\NGRY                  5          " GS GS\5      GrO\xGR]                  GSS/S9GS 5       GrPGS GrQGS GrRS SKrGS GrSGS GrTGS GrU\wGS:X  a9  \GRT                  " G\USS9GRY                  5         \xGR                  GSGSSSGS9  gg! \ a    Sr\" S5         GNf = f! \ a    SrL\" S5         GNf = f! \ a    S rM GN(f = f! \ a    SrNSrO\" S5         GN:f = f! \ a    SrPSrQ\" S5         GNLf = f! \ a    SrRSrS\" S5         GN^f = f! \ a    SrVSrW\" S5         GNnf = f! \ a    SrYSrZ\" S5         GN~f = f! \ a    Sr\Sr_Sr`\" S!5         GNf = f! \{ a'  r|\" SK\| 35         " SL SM5      r}\}" 5       rz Sr|C|GNSr|C|ff = f! , (       d  f       GN= f! \ a    Sr G
NEf = f! \ a    Sr G
NOf = f(      N)Flaskjsonifyrequest	send_file)CORS)
SQLAlchemy)datetime	timedeltatimezone)FPDFz0[WARN] fpdf2 not installed - PDF export disabledBeautifulSoup)Lock)ThreadPoolExecutor)defaultdictdeque)SequenceMatcher)urljoin)Retry)HTTPAdapter)StringIO)parsedate_to_datetime)cafilez[WARN] pdfplumber not installed)tqdmc                     U $ N )xkwargss     6/root/GenerationalWealth/GenerationalWealth/backend.pyr   r   K   s    !8    TFz<[WARN] opencv-python not installed - video features disabledz4[WARN] easyocr not installed - OCR features disabledz5[WARN] yt-dlp not installed - video download disabled)pipelinez>[WARN] transformers not installed - FinBERT sentiment disabledsync_playwrightz;[WARN] playwright not installed - browser scraping disabled)	webdriver)Optionsz>[WARN] selenium not installed - WAF token via browser disabledignorec                     [         (       d{  [           [         (       d`   S[        5       ;   aQ  [        (       aF  [        R	                  5          [        S5      n U (       a  [        R                  U 5        Sq S S S 5        S S S 5        g g ! , (       d  f       N= f! [         a  n[        SU 35         S nAN8S nAff = f! , (       d  f       g = f)Napp
isin_cacheTzISIN Cache load error: )
_isin_cache_loaded_isin_cache_lockglobalsr)   app_contextdb_load_generic_isin_cacheupdate	Exceptionprintdataes     r    ensure_isin_cacher7      s    %%9	)cc __.#2<#@D#[%7%7%=15. /	  
 /. ! 93A37889 sR   B>-B*B6B
B	BB>B
B;#B61B>6B;;B>>
Cc                     [             [        R                  5          [        S[        5        S S S 5        S S S 5        g ! , (       d  f       N= f! [
         a  n [        SU  35         S n A N7S n A ff = f! , (       d  f       g = f)Nr*   zError saving ISIN cache: )r,   r)   r.   db_save_genericr0   r2   r3   r6   s    r    
save_cacher;      s]    		3"k: # 
	"" 	3-aS122	3	 
	sN   A5A?A
A		AA5A
A2A-(A5-A22A55
Bc                 N   [        U S5      (       a  U R                  5       n OSn SSS.SSS.SS	S.S
SS.SSS.SSS.SSS.SSS.SSS.SSS.SSS.S.nUR                  5        H  u  p4X0;   d  M  Us  $    US:X  a  SSS.$ US;   a  SS S.$ US!:X  a  S"S#S.$ US$:X  a  S%S&S.$ SSS.$ )'z=Returns a reference index ticker based on sector and country.lowerunknown^IXICz
NASDAQ 100)symbolnameXLVzHealth Care SelectXLFzFinancial SelectXLYzCons. DiscretionaryXLPzCons. StaplesXLEzEnergy SelectXLUzUtilities SelectXLIzIndustrial SelectXLBzMaterials SelectXLREzReal Estate SelectXLCzCommunication Svc)
technology
healthcarezfinancial serviceszconsumer cyclicalzconsumer defensiveenergy	utilitiesindustrialszbasic materialszreal estatezcommunication servicesUnited States^GSPCS&P 500)FranceGermanyNetherlandsSpainItaly	^STOXX50EzEuro Stoxx 50China	000001.SSzShanghai CompJapan^N225z
Nikkei 225)hasattrr=   items)sectorcountrymappingkvs        r    get_sector_reference_indexre      s   vw&,,.& "),?!&0DE).8JK(-7LM).H"O< %/AB"'1DE&+5GH"(2FG-2<O"PG ;q   /!Wi*P#PHH\g  rA  RB  KB'[/"RR'Wl"KKy11r!   c           	      `   U (       d  g[            U [        ;   a  [        U    sSSS5        $  SSS5         [        R                  " U 5      nUR                  nU(       a  [        U5      S:  a    UR                  nU(       a   [        S5      eUR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      S	.n[        US   US   5      nUS
   US'   US   US'   [            U[        U '   SSS5        [        SU  SUS    SUS    35        U$ ! , (       d  f       GN= f!    N= f! , (       d  f       NC= f! [         aN  n[        SU  SU 35        SSSSS.n[            U[        U '   SSS5        O! , (       d  f       O= fUs SnA$ SnAff = f)z3Fetches sector, country, and currency for a ticker.N   z&Empty info returned from Yahoo Financer`   Unknownindustryra   region)r`   ri   ra   rj   r@   reference_index_tickerrA   reference_index_namez[METADATA] Success for : z / z[METADATA] Error for rR   rS   )r`   ra   rk   rl   )_metadata_lock_metadata_cacheyfTickerinfolen	fast_info
ValueErrorgetre   r3   r2   )tickertrr   fir5   refr6   failure_datas           r    fetch_metadata_for_tickerr|      s    $ 
_$"6* 
$ 
*IIfvv s4y1}kk FGG hhx3Y7xx	95hhx3	
 )hiI),X%&'*6{#$&*OF#  	'xr$x.1AT)_DUVWK 
" T  ^
  %fXRs34 #,	]d  H  I&2OF# ^^sq   D+8E /D= A:E =
E#E +
D:=E?E 
EE 
F-F(=
F	F(
F	F("F-(F-c                     [         R                  " 5       n[        U U U UUS9n[        US9nUR	                  SU5        UR	                  SU5        U$ )N)totalreadconnectbackoff_factorstatus_forcelist)max_retrieszhttp://zhttps://)requestsSessionr   r   mount)retriesr   r   sessionretryadapters         r    create_retry_sessionr     sV     G%)E e,GMM)W%MM*g&Nr!   zoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36*/*z#fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7zhttps://finance.yahoo.comzhttps://finance.yahoo.com/)
User-AgentAcceptAccept-LanguageOriginRefererc                    U (       d  g  [         R                  S   nSnU(       a   [        R                  R	                  U 5      nO<[         R                  5          [        R                  R	                  U 5      nSSS5        W(       a  UR                  (       a  UR                  $ SU  3nSS0n [        R	                  XVSS	9nUR                  5       nS
U;   a  [        US
   5      S:  a  US
   S   n	U	R	                  S5      n
U
(       a   W(       aH  [        X
S9n[        R                  R                  U5        [        R                  R                  5         U
$ [         R                  5          [        X
S9n[        R                  R                  U5        [        R                  R                  5         SSS5        U
$ U
$ g!   Sn GN= f! , (       d  f       GN[= f! [         a  n SnAGNJSnAff = f! , (       d  f       U
$ = f! [         a5  n[        R                  R                  5          SnAU
$ !     SnAU
$ = fSnAff = f! [         a  n[!        SU  SU 35         SnAgSnAff = f)u6   Résout un ISIN en symbole Yahoo Finance avec cache DBNSQLALCHEMY_DATABASE_URITFz5https://query2.finance.yahoo.com/v1/finance/search?q=r   oMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
   headerstimeoutquotesr   r@   )isinrw   zError resolving rm   )r)   config
IsinTickerqueryrv   r.   rw   r2   _http_sessionjsonrs   dbr   mergecommitrollbackr3   )r   _has_contextcachedr6   urlr   respr5   quoter@   	new_cachesave_errs                r    get_symbol_from_isinr   !  s   	!56Q[
  &&**40V//##))--d3 $ fmm==  B$
HC  HG.  r Byy{tDN 3a 7N1%EYYx(F""%/T%I)))4**, M "oo/(2(LIJJ,,Y7JJ--/ 0 M6M g	! [ $#
  4 0/ M ! "**--// M "TM"  . b,--.s   G ;G!  G;+G! 1AI AH I H 1AG98H  I I G	G! 
GG! !
G61G69
HH I H 
I
H93I 9I;I<I II

I 
I2I--I2zNhttps://assets.traderepublic.com/assets/files/DE/Instrument_Universe_DE_en.pdfzInstrument_Universe_DE_en.pdfzall_stocks_from_pdf.jsonc                  R   [         R                  R                  [        5      (       a  [	        S[         S35        g [	        S[
         S35         [        R                  " [
        SS9n U R                  S:X  aL  [        [        S5       nU R                  S	S
9 H  nUR                  U5        M     S S S 5        [	        S5        g [	        SU R                   35        [        SU R                   35      e! , (       d  f       NJ= f! [         a  n[	        SU 35        UeS nAff = f)Nz[OK] Le fichier z existe deja.z[DOWN]? Telechargement de ...T)stream   wbi    )
chunk_sizez[OK] Telechargement termine.z![ERROR] Echec du telechargement: zDownload failed: zError downloading PDF: )ospathexistsPDF_FILENAMEr3   PDF_URLr   rv   status_codeopeniter_contentwriter2   )responsefchunkr6   s       r    download_pdfr   g  s    	ww~~l## m<=	&wis
34<<53&lD)Q%22d2CEGGEN D * 015h6J6J5KLM/0D0D/EFGG *)  's+,s6   9D 
(C62D 0D 6
D D 
D&D!!D&c                  8   [        S5        / n  [        R                  " 5       n[        R                  " U5        [        R
                  (       dU  [        R                  R                  [        R                  5        [        R                  R                  SSSS9[        l        UR                  [        R                  5       5      n UR                  5         [        S[!        U 5       S35         ["        R%                  5          [&        R(                  R                  S	5      nU(       d*  ['        S	U S
9n[*        R,                  R/                  U5        O Xl        [2        R4                  " 5       Ul        [*        R,                  R9                  5         [        S5        SSS5        U $ ! [         a/  n[        SU 35        [        R                  " 5         / s SnA$ SnAff = f! , (       d  f       U $ = f! [         a  n[        SU 35         SnAU $ SnAff = f)zq
Revised to fetch stocks from Trade Republic API instead of PDF.
Keeps function name for backward compatibility.
z;[START] Fetching Stocks Universe via API (replacing PDF)...secret
tr_sessionNfallbackz([ERROR] Error fetching stocks from API: z"[OK] Extraction terminee via API. z instruments trouves.
pdf_stockskeyr5   z&[SAVE] Sauvegarde dans DB (pdf_stocks)zDB Error save pdf stocks: )r3   asyncionew_event_loopset_event_looptr_apisession_tokenr   r   config_pathrv   run_until_completefetch_all_stocks_recursivecloser2   	traceback	print_excrs   r)   r.   
CachedDatar   r   r   addr5   r	   utcnow
updated_atr   )stocksloopr6   caches       r    extract_stocks_from_pdfr   {  s   
 

GHF%%'t$ ##MMv112#)==#4#4X|VZ#4#[F (()J)J)LM

 
.s6{m;P
QR0__$$((6E"|&A

u%#
#+??#4 JJ:<  M-  8<=	  M  0*1#.//M0sU   CF( 0G6 BG$G6 (
G!2$GG!G!$
G3.G6 3G6 6
H HHpendingu   Connexion Base de Données)statuslabelzChargement du PortefeuillezFlux News (RSS)zTransactions Insidersu   Calendrier ÉconomiquezTendances Sectoriellesu    Prévisions & Analyses Bancairesu   Données Macro-économiques)databasewalletrssinsidersforexsector_trends	forecastsmacro)stepscompletec                     U [         S   ;   a  U[         S   U    S'   [        S [         S   R                  5        5       5      nU[         S'   g )Nr   r   c              3   6   #    U  H  u  pUS    S;   v   M     g7f)r   successerrorNr   ).0rc   ss      r    	<genexpr>&update_loading_step.<locals>.<genexpr>  s     bCa411X;"66Cas   r   )LOADING_STATEallr_   )stepr   all_dones      r    update_loading_stepr     sN    }W%%17gt$X. b=QXCYC_C_CabbH (M*r!   z)sqlite:///financial_terminal_multiuser.dbr   SQLALCHEMY_TRACK_MODIFICATIONS   2   <   i  )	pool_sizemax_overflowpool_timeoutpool_recycleSQLALCHEMY_ENGINE_OPTIONSz&[OK] Database initialized successfullyz[ERROR] Database init failed: c                   N    \ rS rSr\rS rS=r=r=r	=r
=r=r=rrS rSrS rSrg)MockDBi  c                      g r   r   )arc   s     r    <lambda>MockDB.<lambda>      r!   Nc                      g r   r   )r  s    r    r  r    r  r!   c                     g r   r   selfs    r    
create_allMockDB.create_all  s    dr!   r   )__name__
__module____qualname____firstlineno__objectModelColumnIntegerStringFloatTextDateTimeDateBooleanJSON
ForeignKeyr   r
  __static_attributes__r   r!   r    r   r     sA    $MQQQ&Q5Q4Q(QTQGd$
"r!   r   z/*origins*)	resourcessupports_credentialsc                 `    SU R                   S'   SU R                   S'   SU R                   S'   U $ )Nr  zAccess-Control-Allow-Originz)Content-Type, Authorization, X-User-PhonezAccess-Control-Allow-HeaderszGET, POST, PUT, DELETE, OPTIONSzAccess-Control-Allow-Methods)r   )r   s    r    add_cors_headersr"    s:    69H237bH347XH34Or!   c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      SSS9r	\R                  \R                  S5      SS9r
\R                  \R                  S	5      5      r\R                  \R                  S	5      5      r\R                  \R                  \R                  S
9rSrg)Useri  Tprimary_keyr   F)uniquenullabler   r(  d   defaultr   N)r  r  r  r  r   r  r  idr  phonepin
first_name	last_namer  r	   r   
created_atr  r   r!   r    r$  r$    s    	2::4	0BIIbiimD5IAE
))BIIbME)
2C299S>*J		"))C.)I2;;@Jr!   r$  c                       \ rS rSr\R                  \R                  S5      SS9r\R                  \R                  S5      5      r\R                  \R                  \
R                  S9rSrg)r   i     Tr%  r+  r   N)r  r  r  r  r   r  r  r   rw   r  r	   r   r   r  r   r!   r    r   r     sL    99RYYr]95DYYryy}%F2;;@Jr!   r   c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  \R                  S5      5      r	\R                  \R                  \R                  S9r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R$                  5      rSrg)PortfolioSnapshot  Tr%  user.idr+  r   N)r  r  r  r  r   r  r  r-  r  user_idr  r	   r   	timestampr  cashtotal_valuepositions_countr  raw_datar  r   r!   r    r6  r6    s    	2::4	0Bii

BMM)$<=G		"++x	?I99RXXD))BHH%Kii

+Oyy!Hr!   r6  c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      5      r	\R                  \R                  S5      5      r
\R                  \R                  S5      SS9r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  S5      5      r\R                  \R"                  5      r\R                  \R&                  5      rSrg	)
NewsItemi  Tr%  r   r7  r'  r4  r   N)r  r  r  r  r   r  r  r-  r  sourcetitler   r  summaryr  published_at	sentimentr  sentiment_scorer  related_tickersr  r   r!   r    r@  r@    s    	2::4	0BYYryy}%FIIbiin%E
))BIIcN4)
0Cii G99R[[)L		"))B-(Iii)Oii(Or!   r@  c                   (   \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      5      r	\R                  \R                  S5      5      r
\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  S5      5      r\R                  \R*                  \R.                  S9rS	rg
)InsiderTransactioni	  Tr%  r4  r   r*  r7  r+  r   N)r  r  r  r  r   r  r  r-  r  rw   companyinsider_namerelationdatetransactionr  costsharesvalueshares_totalsec_formr  r	   r   last_updatedr  r   r!   r    rJ  rJ  	  s   	2::4	0BYYryy}%Fii		#'G99RYYs^,Lyy3(H99RYYr]#D))BIIcN+K99RXXDYYrxx FIIbhhE99RXX&Lyy3(H99R[[(//9BLr!   rJ  c                   r   \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      5      r	\R                  \R                  S5      5      r
\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  5      r\R                  \R                  S5      5      r\R                  \R                  S5      SS	9r\R                  \R"                  5      r\R                  \R                  S5      5      rS
rg)BankForecasti  Tr%  r*  r4  r   r   r7  rA  r   N)r  r  r  r  r   r  r  r-  r  bankrw   rK  recommendationr  target_pricedate_published
source_urlr  rD  market_sentimentr  r   r!   r    rW  rW    s    	2::4	0B99RYYs^$DYYryy}%Fii		#'GYYryy~.N99RXX&LYYryy}-N299S>$7Jii Gyy2/r!   rW  c                   p   \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      SS9r	\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  \R                  S9r\R                  \R"                  5      rSrg)	SectorTrendi$  Tr%  r*  rA  r+  r   N)r  r  r  r  r   r  r  r-  r  sector_namer  monthly_trendstocks_countr  r	   r   rU  r  detailsr  r   r!   r    r_  r_  $  s    	2::4	0B))BIIcN4)8KIIbhh'M99RZZ(L99R[[(//9BLii Gr!   r_  c                       \ rS rSr\R                  \R                  S5      SS9r\R                  \R                  5      r	\R                  \R                  \R                  S9rSrg)r   i,  r*  Tr%  r+  r   N)r  r  r  r  r   r  r  r   r  r5   r  r	   r   r   r  r   r!   r    r   r   ,  sH    
))BIIcN)
5C99RWWD2;;@Jr!   r   c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      SS9r	\R                  \R                  5      r\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  S5      5      r\R                  \R                  \R"                  S9rS	rg
)TechnicalWarningi1  Tr%  r4  rA  r   r   r+  r   N)r  r  r  r  r   r  r  r-  r  rw   r  rsisignal_typelevelmessager  r	   r   r   r  r   r!   r    rf  rf  1  s    	2::4	0BYYryy}TY2F
))BHH
C))BIIbM*KIIbiim$Eii		#'G2;;@Jr!   rf  c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      5      r	\R                  \R                  S5      5      r
\R                  \R                  S5      5      r\R                  \R                  5      r\R                  \R                  \R                   S9rSrg)	BankAnalysisi:  Tr%  r   r7  r+  r   N)r  r  r  r  r   r  r  r-  r  rX  rC  r   r  analysisr  r	   r   r:  r  r   r!   r    rl  rl  :  s    	2::4	0B99RYYr]#DIIbiin%E
))BIIcN
#Cyy!H		"++x	?Ir!   rl  c                   h   \ rS rSr\R                  \R                  SS9r\R                  \R                  \R                  S5      5      r	\R                  \R                  S5      SS9r\R                  \R                  S5      5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  5      r\R                  \R                  S5      5      r\R                  \R                  S	5      5      r\R                  \R                  S5      5      r\R                  \R.                  \R2                  S
9rSrg)WalletInvestmentiB  Tr%  r8  r4  Fr)  r   r   r+  r   N)r  r  r  r  r   r  r  r-  r  r9  r  r   rA   r  quantity	buy_pricecurrent_pricer<  pnlpnl_percentexchangeinstrument_typelogor  r	   r   r   r  r   r!   r    ro  ro  B  s-   	2::4	0Bii

BMM)$<=G99RYYr]U93D99RYYs^$Dyy"H		"((#IIIbhh'M))BHH%K
))BHH
C))BHH%Kyy2'Hii		".O99RYYs^$D2;;@Jr!   ro  c                   X   \ rS rSr\R                  \R                  SS9r\R                  \R                  \R                  S5      5      r	\R                  \R                  SS9r\R                  \R                  S5      SS9r\R                  \R                  \R                   S9rS	rg
)
WalletCashiS  Tr%  r8          r+  r   EURr   N)r  r  r  r  r   r  r  r-  r  r9  r  amountr  currencyr  r	   r   r   r  r   r!   r    ry  ry  S  s    	2::4	0Bii

BMM)$<=GYYrxxY-Fyy2y6H2;;@Jr!   ry  c                      \ rS rSr\R                  \R                  SS9r\R                  \R                  S5      SS9r	\R                  \R                  5      r\R                  \R                  \R                  S9rSrg)		MacroDataiZ  Tr%  r*  rA  r+  r   N)r  r  r  r  r   r  r  r-  r  categoryr  r5   r  r	   r   r   r  r   r!   r    r  r  Z  s^    	2::4	0Byy3y5H99RWWD2;;@Jr!   r  c                     [         R                  5          S n U(       a>  [        R                  R	                  US9R                  5       nU(       a  UR                  nU(       d  S[        5       ;   a  [        R                  R                  [        R                  5        [        R                  R                  SSS S9nU(       a>  [        R                  R	                  US9R                  5       nU(       a  UR                  nU R                  SU R                  S0 5      5      nS	n[        U[         5      (       a  [#        UR                  S
S5      5      nO&[        U[$        ["        45      (       a  [#        U5      n[&        R                  R	                  US9R                  5       nU(       d'  [(        R*                  R-                  ['        XrS95        O Xxl        [0        R2                  " 5       Ul        U R                  SU R                  SU R                  S/ 5      5      5      n	U	 GHk  n
U
R                  S5      (       d  M  [6        R                  R	                  U
S   US9R                  5       nU(       Gdo  [7        U
S   UU
R                  SS5      [#        U
R                  SU
R                  SS5      5      5      [#        U
R                  SU
R                  SS5      5      5      [#        U
R                  SU
R                  SS5      5      5      [#        U
R                  SU
R                  SS5      5      5      [#        U
R                  SS5      5      [#        U
R                  SU
R                  SS5      5      5      U
R                  S S!5      U
R                  S"U
R                  S#S$5      5      U
R                  S%S!5      S&9n[(        R*                  R-                  U5        GM  [#        U
R                  SU
R                  SUR8                  5      5      5      n[#        U
R                  SU
R                  SS5      5      =(       d    S5      n[#        U
R                  SU
R                  SS5      5      =(       d    S5      nXl        US:  a  Xl        US:  a  Xl        UR<                  =(       d    SnUR:                  =(       d    SnUU-  Ul        UU-  nUR>                  U-
  Ul         US:  a  UR@                  U-  S'-  OS	Ul!        U
R                  SURD                  5      =(       d    URD                  Ul"        U
R                  S%URF                  5      =(       d    URF                  Ul#        [0        R2                  " 5       Ul        GMn     [I        UU[K        S( U	 5       5      U-   [M        U	5      U S)9n[(        R*                  R-                  U5        [(        R*                  RO                  5         S S S 5        g ! [         a  n[        SU 35         S nAGN%S nAff = f! , (       d  f       g = f! [         a  n[        S*U 35         S nAg S nAff = f)+Nr.  r   r   phone_numberr   z!Error identifying user for save: availableCashavailable_cashrz  r|  r   r9  )r|  r9  my_investments	positionspositions_detailedr   )r   r9  rA   rh   rp  qtyrq  avgPricerr  currentPricer<  
totalValuers  rt  
pnlPercentru   instrumentTyperv  stockrw  )r   r9  rA   rp  rq  rr  r<  rs  rt  ru  rv  rw  r*  c           
   3   x   #    U  H0  n[        UR                  S UR                  SS5      5      5      v   M2     g7f)r<  r  r   N)floatrv   r   is     r    r   $db_save_portfolio.<locals>.<genexpr>  s1     i]hXYaeeM155q;Q&R S S]hs   8:)r9  r;  r<  r=  r>  zDB Error save portfolio: )(r)   r.   r$  r   	filter_byfirstr-  r-   r   r   r   r   rv   r2   r3   
isinstancedictr  intry  r   r   r   r|  r	   r   r   ro  rp  rq  rr  r<  rs  rt  rA   rw  r6  sumrs   r   )r5   
user_phoner9  ur.  r6   cash_objcash_valcash_dbinvestmentsitemexistinginvnew_qtynew_bpxnew_cpxcpx_effbpx_eff
cost_basissnaps                       r    db_save_portfolior  e  s   ]/__G?--J-?EEGQQTT7 8wy#8MM&&v'9'9:"MM--hQU-VE JJ00u0=CCEg xx:JB1OPHH(D))eHLLST<U6V8HsEl33hX &&000AGGIG

zKL!)%-__%6" ((#3TXXk488ThjlKm5noK#xx''+11;;fW^;_eeg*!&\ '!XXfi8!&txx
DHHUA<N'O!P"'dhhzST>U(V"W&+DHH_dhh~_`Fa,b&c$)$((=$((<YZB[*\$]!$((5!"45$)$((=$((<YZB[*\$]!%*b!9(,1A488L]_fCg(h!XXfb1C JJNN3'
 !&dhhzYaYjYj@k&l mG %dhh{YZ@[&\&a`a bG %dhhYZ@[&\&a`a bG(/%{-4*{18. '449G&009G+2W+<H(+2W+<J+3+?+?*+LHLPZ]^P^HLL:,E,KdgH(+/88FHMM+J+[hmmHM+/88FHMM+J+[hmmHM+3??+<H'Y $^ %i]hiiltt #K 0D JJNN4 JJu    ?9!=>>?! v  /)!-../s_   Y X2C+XS>X2Y 
X/X*$X2*X//X22
Y <Y  Y 
Y%Y  Y%c                     [         R                  5          [        R                  R	                  U 5      nU(       d)  [        XS9n[
        R                  R                  U5        O Xl        [        R                  " 5       Ul        [
        R                  R                  5         S S S 5        g ! , (       d  f       g = f! [         a  n[        SU  SU 35         S nAg S nAff = f)Nr   zDB Error save generic rm   )r)   r.   r   r   rv   r   r   r   r5   r	   r   r   r   r2   r3   )r   r5   r   r6   s       r    r9   r9     s    3__$$((-E"s6

u%!
#+??#4 JJ   3&se2aS1223s5   B> BB-$B> -
B;7B> ;B> >
C#CC#c                 J    [         R                  5          [        R                  R	                  U 5      nU(       a"  UR
                  b  UR
                  sS S S 5        $ UsS S S 5        $ ! , (       d  f       g = f! [         a  n[        SU  SU 35        Us S nA$ S nAff = f)NzError loading generic key rm   )r)   r.   r   r   rv   r5   r2   r3   )r   r,  r   r6   s       r    r/   r/     s    
__$$((-E/ zz     *3%r!56sF   A; ?A*	A; A* 	A; *
A84A; 8A; ;
B"BB"B"c                  *    [         R                  5          [        S5      (       d2  [        S5        [        R
                  " [        SS9R                  5         [        S5      (       d/  [        S5        [        R
                  " S SS9R                  5         [        5       (       d_  [        S:X  d
  [        S	:X  aK  [        R                  5       (       d2  [        S
5        [        R
                  " [        SS9R                  5         [        5       (       d1  [        S5        S n [        R
                  " U SS9R                  5         S n[        (       ae   [        R                  R!                  S5      nU(       a>  ["        R$                  R'                  US9R)                  5       nU(       a  UR*                  nUc   [,        R.                  R1                  [,        R2                  5        [,        R.                  R!                  SSS S9nU(       a>  ["        R$                  R'                  US9R)                  5       nU(       a  UR*                  n[4        R$                  R'                  US9R7                  [4        R*                  R9                  5       5      R)                  5       nU(       a  UR:                  (       a   [=        US9sS S S 5        $ !    GN= f!    N= f! , (       d  f       g = f! [>         a  n[        SU 35        0 s S nA$ S nAff = f)Nseasonalityz3Missing seasonality: triggering background fetch...Ttargetdaemonoptions_GOOGz.Missing options data: triggering GOOG fetch...c                      [        S5      $ )NGOOG)fetch_options_chain_apir   r!   r    r  *db_load_latest_portfolio.<locals>.<lambda>  s
    0G0Or!   idler   z;Missing sector trends: triggering background calculation...z7Missing bank forecasts: triggering background scrape...c                       SSK Jn   U " 5       nUR                  5         g ! [         a  n[	        SU 35         S nAg S nAff = f)Nr   )BankForecastScraperzBackground bank scrape error: )backendr  
scrape_allr2   r3   )r  scraperr6   s      r    background_bank_scrape8db_load_latest_portfolio.<locals>.background_bank_scrape  sD    C>!4!6w))+# C=aSABBCs     
A=AX-User-Phoner  r   r  r   r  !Error loading portfolio from DB: ) r)   r.   r/   r3   	threadingThreadfetch_seasonality_apistartdb_load_sector_trendssector_update_status_sector_update_locklockedupdate_sector_monthly_trendsdb_load_bank_forecastsr   r   rv   r$  r   r  r  r-  r   r   r   r   r6  order_bydescr>  load_portfolio_datar2   )r  r9  r.  r  r  r6   s         r    db_load_latest_portfolior    sR   <__"=11KL  (=dKQQS">22FG  (OX\]cce )**'615IW5T/6688[\!((0LUYZ``b)++OPC   (>tLRRT Gw#OO//?E JJ00u0=CCEg ]]''(:(:;#]]..xRV.WU!ZZ111>DDFw %**44W4ENNO`OcOcOhOhOjkqqsD &w7q N  a r  1!56	sn   K. D=KA$K8K<BKA7K	K. KKKK
K+'K. +K. .
L8LLLc                    U (       a  [        U 5      S:X  a  [        S5        g [        R                  5          [        R
                  R                  [        5      R                  5         U R                  5        GH  u  p[        U[        5      (       a  UR                  S/ 5      OUnU GHb  n[        UUR                  SUR                  SS5      5      UR                  SUR                  S	S5      5      UR                  S
UR                  SS5      5      UR                  SUR                  SS5      5      UR                  SUR                  SS5      5      [        [        UR                  SUR                  SS5      5      5      R                  SS5      R                  SS5      R                  SS5      =(       d    S5      [        [        UR                  SUR                  SS5      5      5      R                  SS5      =(       d    S5      [        [        UR                  SUR                  SUR                  SS5      5      5      5      R                  SS5      R                  SS5      =(       d    S5      [        [        UR                  SUR                  SS5      5      5      R                  SS5      =(       d    S5      UR                  SUR                  SS5      5      S9n[        R
                  R!                  U5        GMe     GM     [        R
                  R#                  5         SSS5        g! , (       d  f       g= f! [$         a  n[        S U 35         SnAgSnAff = f)!z<Save dictionary of insiders {ticker: { 'all': [...] }} to DBr   zO[WARN] db_save_insiders: No data provided, skipping update to avoid clearing DBNr   rK  Companyr  insiderInsiderrelationshipRelationshiprN  r  rO  TransactionrP  Cost0,>$rQ  SharesrR  Valuez	Value ($)rS  zShares TotalrT  z
SEC Form 4)rw   rK  rL  rM  rN  rO  rP  rQ  rR  rS  rT  zDB Error save insiders: )rs   r3   r)   r.   r   r   r   rJ  deleter_   r  r  rv   r  strreplacer   r   r2   )	data_dictrw   groupstradesrx   txnr6   s          r    db_save_insidersr  !  s   I!+_`.__JJ/0779"+//"3 4>fd3K3K&**UB/QW Q,% !iy"1E F%&UU9aeeIr6J%K!"~quu^R7P!QUU6155+<=$%EE-}b9Q$R"3quuVQUU635G'H#I#Q#QRUVX#Y#a#abefh#i#q#qruvx#y#~}~$Sxx9M)N%O%W%WX[\^%_%dcde#CgquuWaeeKY\F]7^(_$`$h$hilmo$p$x$xy|}  %A  %F  EF  G%*3quu^QUU>[^E_/`+a+i+ijmnp+q+vuv%w!"z155r3J!KC JJNN3' ! #4( JJ/ 0  .(,--.s5   M K=L>5M >
MM M 
M1M,,M1c                  L    S n [         R                  5          [        R                  R	                  5       n0 n[
        R                  " 5       [        SS9-
  nU GH  nUR                  U;  a  / / S.X$R                  '   UR                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  UR                   UR"                  UR$                  S.nX$R                     S   R'                  U5        U " UR                  5      nU(       d  M  Xc:  d  M  X$R                     S   R'                  U5        GM     UsS S S 5        $ ! , (       d  f       g = f! [(         a  n[+        SU 35        0 s S nA$ S nAff = f)	Nc                      U R                  5       R                  SS5      n[        R                  " US5      $ !    g = f)N'20z%b %d %Y)stripr  r	   strptime)date_strds     r    
parse_date$db_load_insiders.<locals>.parse_dateE  s=    NN$,,S$7((J77s   69 =   daysr   recent_7days)rw   rK  r  r  rN  rO  rP  rQ  rR  rS  rT  r   r  z Error loading insiders from DB: )r)   r.   rJ  r   r   r	   nowr
   rw   rK  rL  rM  rN  rO  rP  rQ  rR  rS  rT  appendr2   r3   )r  txnsresultcutoffrx   tradedtr6   s           r    db_load_insidersr  C  sG   (	 __%++//1DF\\^iQ&77F886)/12'FF88$  hh yy ~~$%JJFF#$==FFhhWW$%NN !

 xx '..u5'2",88$^4;;EB+ . 9 :  045	sG   E? DE.7E.>&E.$	E? .
E<8E? <E? ?
F#	FF#F#c                     [         R                  5          U  GH  nUR                  S5      nU(       d  M  [        R                  R                  US9R                  5       nU(       a  UR                  SUR                  5      Ul        UR                  SUR                  5      Ul        UR                  SUR                  5      Ul	        UR                  SUR                  5      Ul
        UR                  SUR                  5      Ul        UR                  SUR                  5      Ul        UR                  S	UR                  5      Ul        GM:  [        UR                  S5      UR                  S5      UR                  S5      UR                  S5      UR                  S5      UUR                  SS
5      UR                  S	S
5      S9n[        R                  R!                  U5        GM     [        R                  R#                  5         S S S 5        g ! , (       d  f       g = f! [$         a  n['        SU 35         S nAg S nAff = f)Nr   r\  rX  rw   rY  rZ  rN  rD  rF  r  )rX  rw   rY  rZ  r[  r\  rD  r]  zDB Error save forecasts: )r)   r.   rv   rW  r   r  r  rX  rw   rY  rZ  r[  rD  r]  r   r   r   r   r2   r3   )r   r   r   r  db_itemr6   s         r    db_save_bank_forecastsr  n  s    /__eeElH'--7737GMMO$%EE&(--$@HM&'eeHhoo&FHO./ee4DhF]F].^H+,-EE.(BWBW,XH)./eeFH<S<S.TH+'(uuY8H8H'IH$01k8C\C\0]H- +UU6] uuX'(uu-='>%&UU>%:'(uuV}#& !i 4)*{B)?	G JJNN7+5 6 JJ; <  /)!-../s5   H* G:HH* 
H'#H* 'H* *
I4IIc                  X    S n [         R                  5          [        R                  R	                  [        R
                  R                  5       5      R                  5       nU Vs/ s Hu  nUR                  UR                  UR                  UR                  U " UR                  5      U " UR                  5      UR                  UR                  UR                  S.	PMw     snsS S S 5        $ s  snf ! , (       d  f       g = f! [          a  n[#        SU 35        / s S nA$ S nAff = f)Nc                 r    U (       d  g[        U [        5      (       a  U R                  5       $ [        U 5      $ )Nr  )r  r	   	isoformatr  )r  s    r    format_date+db_load_bank_forecasts.<locals>.format_date  s(    R!X&&q{{}(<q6Mr!   )	rX  rw   rY  rZ  rN  r:  r   rD  rF  zError loading forecasts: )r)   r.   rW  r   r  r-  r  r   rX  rw   rY  rZ  r[  r\  rD  r]  r2   r3   )r  r_   r  r6   s       r    r  r    s    	
 __ &&//0D0D0FGKKME 
 ! (("#"2"2 !#A$4$45()9)9:||99//
 
 
   )!-.	sN   D AC4'A<C/#C4%	D /C44
D>D D 
D)D$D)$D)c                 
    [         R                  5          [        R                  R	                  U S9R                  5       n[        R                  R	                  U S9R                  5       nU(       a  UR                  OSnU(       Ga  / n0 nU H  n[        UR                  5      nXuUR                  '   U(       d  M/  [           [        R                  U0 5      nU[        ;  d  UR                  S5      S:X  a  Xt;  a  UR                  U5        SSS5        M     U(       aR  [        S[!        U5       S35        U H4  n	 [!        U5      S:  a  ["        R$                  " S	5        ['        U	5        M6     / nU GH:  nUR                  UR                  5      n0 nU(       a%  [           [        R                  U0 5      nSSS5        UR                  0 SUR                  _SUR*                  _SUR,                  _SUR.                  _SUR0                  _SUR2                  _SUR4                  _SUR6                  _SUR8                  _SUR:                  _SUR<                  _SU_SUR                  SS5      _SUR                  SS5      _SUR                  S5      _SUR                  S5      _5        GM=     U Vs/ s H  oS   S:w  d  M  US   PM     nn[!        U5      S:X  aR  [!        U5      S:  aC  [        S[!        U5       SUS   R                  S5       SUS   R                  S5       S35        O[!        U5      S:  a   US S!.UUUS"U0S#./S$.sSSS5        $  SSS5        SS S!./ / / S"S0S#./S$.$ ! , (       d  f       GM  = f! [(         a  n
[        S
U	 SU
 35         Sn
A
GMr  Sn
A
ff = f! , (       d  f       GN = fs  snf ! , (       d  f       Nr= f! [(         a  n
[        S%U
 35         Sn
A
NSn
A
ff = f)&z3Charge le portfolio depuis la DB avec fallback JSONr  rz  r`   rh   NzFetching metadata for z tickers (Sync)...rg         ?z[METADATA] Failed to fetch rm   r   rA   r  r  r  r  rs  r  ru  r  rw  rw   ra   rk   rl   r   z[PORTFOLIO DEBUG] [WARN] 0/z, positions have sector data. Sample Ticker: z (ISIN: )r{  )r|  r}  r|  )r  r  )r  r  r  walletsr  )r)   r.   ro  r   r  r   ry  r  r|  r   r   rn   ro   rv   r  r3   rs   timesleepr|   r2   rA   rp  rq  rr  r<  rs  rt  ru  rv  rw  )r9  r  r  cash_amounttickers_to_fetchtemp_isin_ticker_mapr  rx   currrw   r6   r  metapknown_sectorss                  r    r  r    sd   O7__*00::7:KOOQK &&000AGGIG,3'..K#% ')$ 'C-chh7Q67#((3,$3$7$72$>T ! 8DHHX<NR[<[$%$=%5%<%<Q%? -n	 ' $237G3H2II[\]"2O"#34q8$**S/5f=	 #3 	&C,00:A D+#2#6#6q"#=D , $$ &&& s||& #CMM	&
 '(9(9& %coo& sww& %coo& #CLL& )#*=*=& & !!& !$((8Y"?& "488Iy#A&  1$((;S2T!&" /9O0P#&  '< 7@ \iX;R[C[8i \}%*s9~/A8Y8HHtu~  @A  vB  vF  vF  GO  vP  uQ  QY  Zc  de  Zf  Zj  Zj  kq  Zr  Ys  st  u  v'!+ 2=%&P&/!*.7HVaKb cd	O 
  d &)e<"$3HI	 E -n  ) O!$?xr!"MNNO ,^0 !]A Z  71!5667s   O  B%O?OAM;0O0N26O(N8?C>O=O
	O
BO	O  #O  ;
N	O
N5N0)O0N55O8
OO
OO  O   
P*O==PGROQ_API_KEYr  z/https://api.groq.com/openai/v1/chat/completionszllama-3.3-70b-versatilez#trade_republic_wallet_complete.jsonzforex_cache.jsonzinsider_transactions.jsonzbloomberg_markets_news.jsonbloomberg_news.jsonzGOOG_options_analysis.jsonzsector_trends_monthly.jsonsector_trends.jsonzseasonality_analysis.jsonzbank_forecasts.jsonzbank_analyses.jsonzearnings_cache.jsonzcot_data_cache.json)	portfolior   r   newsbloomberg_liveoptionsr   sectors_performancer  bank_forecastsbank_analysesearningscot_datac                   :    \ rS rSrSrS rS
S\S\4S jjrS r	Sr
g	)TruthSocialScraperi$  uO   
Scraper pour récupérer les posts de Truth Social avec gestion de Cloudflare
c                      [         R                  " SSSS.S9U l        SSS	S
SSSSSSSS.U l        SU l        g !   [        S5        [        R
                  " 5       U l         ND= f)NchromewindowsF)browserplatformmobile)r&  zACloudscraper not available, falling back to requests (might fail)r   Jtext/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8zen-US,en;q=0.9,fr;q=0.8gzip, deflate, br1
keep-alivedocumentnavigatenone	max-age=0)r   r   r   Accept-EncodingDNT
ConnectionUpgrade-Insecure-RequestsSec-Fetch-DestSec-Fetch-ModeSec-Fetch-SiteCache-Controlzhttps://truthsocial.com)cloudscrapercreate_scraperr  r3   r   r   r   base_urlr  s    r    __init__TruthSocialScraper.__init__)  s}    
	/'66' )#DL Lb82&),(($(
 2'	/VW$,,.T\s	   : 'A#username	max_postsc                 b   UR                  SS5      n[        SU S35         U R                   SU 3nU R                  R	                  U0 U R
                  ESS0ESS	9nUR                  S
:X  a  UR                  5       nUR	                  S5      nU(       aq  U R                   SU S3nU R                  R	                  U0 U R
                  ESS0ESU0SS9nUR                  S
:X  a!  UR                  5       n	U R                  U	5      $ / $ ! [         a  n
[        SU
 35        / s Sn
A
$ Sn
A
ff = f)u'   
Récupère les posts d'un utilisateur
@r  z)TRUTH SOCIAL: Recuperation des posts de @r   z/api/v1/accounts/lookup?acct=r   application/jsonr   r   r   r-  z/api/v1/accounts/z	/statuseslimitr   paramsr   zTRUTH SOCIAL Error: N)
r  r3   r;  r  rv   r   r   r   _parse_postsr2   )r	  r>  r?  api_urlapi_response	user_datar9  	posts_urlposts_responsepostsr6   s              r    get_user_posts!TruthSocialScraper.get_user_postsH  sZ    ##C,9(3GH 	'DXJOG<<++G >,,>,>  , L
 ''3.(--/	#---#'==/1B7)9 UI%)\\%5%5! N4<< N;M N '3 "	 &6 &N &11S8 . 3 3 5#0077 I 	(,-I	s$   C$D
 D
 

D.D)#D.)D.c                 J   / nU GH  nUR                  SS5      n [        US5      nUR                  5       R                  5       nUR                  S5      UR                  S5      UUR                  S5      UR                  SS5      UR                  S	S5      UR                  S
S5      UR                  S/ 5       Vs/ s H  owR                  S5      PM     snSSUR                  S0 5      R                  S5      S.nUR	                  U5        GM     U$ !   Un N= fs  snf )u!   Parse les données JSON des postscontentr  html.parserr-  r2  r   reblogs_countr   favourites_countreplies_countmedia_attachmentstruth_socialDonald J. Trumpaccountavatar)r-  r2  rP  r   rR  rS  rT  mediarB  authorrY  )rv   r   get_textr  r  )	r	  
posts_dataparsed_postspostcontent_htmlsouptext_contentmparsed_posts	            r    rF  TruthSocialScraper._parse_postsq  s   D88Ir2L,$\=A#}}446
 hhtn"hh|4'xx!%/1!=$(HH-?$C!%/1!=049Lb0QR0Q1%%,0QR(+((9b155h?K ,- 0 %,+ Ss   *D>D D)r;  r   r  N)r4  )r  r  r  r  __doc__r<  r  r  rM  rF  r  r   r!   r    r"  r"  $  s%    2>'s 's 'Rr!   r"  c                  Z   [        5       n U R                  SSS9nU(       GaO  [        S[        U5       S35        [	        S5      =(       d    / nU Vs0 s H,  o3R                  S5      (       d  M  UR                  S5      U_M.     nn/ nU H  n UR                  SS	5      n[        U5      nU(       a   UR                  S
S5      R                  5       OSn	U(       a  SU;   a  US   n
OSn
SUS'   SUS'   XS'   SU	 SU
S S3US'   SUS'   XvS'   SS/US'   UR                  S5      nU(       a
  X;   a  XL   n UR                  U5        M     [        SU5        [        S[        U5       S!35        g [        S"5        g s  snf ! [         a  n[        SU 35        SUS'    S nANS nAff = f)#u9   Tâche de fond pour mettre à jour les posts Truth SocialrealDonaldTrumpr4  )r?  [OK] z1 Truths recuperes. Starting Immediate Analysis...rV  r   rP  r  r   neutralscorerz  Tai_analysis_v2	   criticality_scoresentiment_label#Direct Truth Social Feed. FinBERT:  (.2fr
  ai_reasoningzTruth Social Updatetitle_fr
summary_frTRUMPTruth Socialsearch_keywordsz*[WARN] Error in immediate Truth analysis: FNz& Truths analyzed & saved (Fast-Track).z[WARN] Aucun Truth recupere.)r"  rM  r3   rs   r/   rv   analyze_sentiment_finbertr=   r2   r  r9   )r  	new_postsexisting_postsr  existing_mapmerged_postsr_  rP  bert_results_label	score_valr6   r   r  s                 r    update_truth_social_postsr    s    "G&&'8B&GIc)n%%VWX )8>B1?PA55<eaPD/((9b17@IT+//'9=CCEZc7k#9 +G 4I #I *.%&,-()*1&')LWIUWXabeWffg'h^$#8Z %,\"+2N*C&' ((5/Cs*', %K N 	5c,'((NOP,-[ Q4  /B1#FG).%&/s%   E>0E>BF
F*F%%F*c                       \ rS rSrSrS rSS\S\S\R                  4S jjr
S rS	 rS
 rS rS\S\4S jrS\4S jrSS\S\S\R                  4S jjrS\S\4S jrSrg)RealInstitutionalDataScraperi  u.   Scraper de données institutionnelles réellesc                     SU l         SU l        SSSSS.U l        [        R                  " 5       U l        U R
                  R                  R                  U R                  5        g )Nz)https://publicreporting.cftc.gov/resourcezhttps://www.sec.govz7GenerationalWealth/1.0 (generationalwealth@example.com)zgzip, deflatezwww.sec.govr,  )r   r1  Hostr3  )cftc_base_urlsec_base_urlr   r   r   r   r1   r  s    r    r<  %RealInstitutionalDataScraper.__init__  sU    H1S.!&	
  '')##DLL1r!   	commodityrC  returnc           
      D   SSSSSSSSS	.nUR                  5       U;  a#  [        S
U 35        [        R                  " 5       $ X1R                  5          nU R                   S3nUSU S3SS.n [        SU S35        U R
                  R                  XVSS9nUR                  5         UR                  5       nU(       d  [        R                  " 5       $ [        R                  " U5      n	SSSSSSSSSS.	n
U
R                  5        Vs/ s H  oU	R                  ;   d  M  UPM     nnX   R                  5       nU Vs/ s H  oU   PM	     snUl
        UR                  SS  H  n[        R                  " X   S S!9X'   M     SUR                  ;   a  US   US   -
  US"'   SUR                  ;   a  US   US   -
  US#'   SUR                  ;   a  US   US   -
  US$'   U$ s  snf s  snf ! [         a-  n[        S%U 35        [        R                  " 5       s SnA$ SnAff = f)&u4   
Récupère les VRAIES données COT depuis la CFTC.
084691088691067651023651085692001612002602005602)silvergold	crude_oilnatural_gascopperwheatcornsoybeansz [ERROR] Commodite non reconnue: z/jun7-fc8e.jsonzcftc_contract_market_code='r  zreport_date_as_yyyy_mm_dd DESC)z$limitz$wherez$orderz[NET] Connexion a la CFTC pour r   r   rE  r   r  u   Marchéu   Intérêt_OuvertDealer_LongDealer_ShortAsset_Mgr_LongAsset_Mgr_ShortLev_Money_LongLev_Money_Short)	report_date_as_yyyy_mm_ddmarket_and_exchange_namesopen_interest_alldealer_positions_long_alldealer_positions_short_allasset_mgr_positions_long_allasset_mgr_positions_short_alllev_money_positions_long_alllev_money_positions_short_all   Ncoerceerrors
Dealer_NetAsset_Mgr_NetLev_Money_Netz[ERROR] Erreur COT: )r=   r3   pd	DataFramer  r   rv   raise_for_statusr   keyscolumnscopy
to_numericr2   )r	  r  rC  commodity_codes	cftc_coder   rE  r   r5   dfcolsc	availabledf_cleancolr6   s                   r    get_cot_data_real.RealInstitutionalDataScraper.get_cot_data_real  sD   
 !# 	
 ??O34YK@A<<>!#OO$56	##$O43I;a@6
,	"3I;cBC||''B'GH%%'==?D||~%d#B .4-6%7-:.<0@1B0@1B
D %)IIKCKq

?KIC}))+H1:;AQ;H  ''+ "hmH M ,  0 00)1-)@8NC[)[&8#3#33,45E,FRcId,d)8#3#33,45E,FRcId,d)O! D;   	"(,-<<>!	"sJ   /A$G( 4G( GG%G( =G#BG( 
G( (
H2"HHHc                      [         R                  " U5      nUR                  nUb  UR                  (       d  U$ g! [         a
  n SnAgSnAff = f)u9   
Récupère les détenteurs institutionnels d'une action
N)rp   rq   institutional_holdersemptyr2   )r	  rw   r  institutionalr6   s        r    get_institutional_holders6RealInstitutionalDataScraper.get_institutional_holders'  sL    	IIf%E "77M(1D1D$$ 		   7; 
A
Ac                      [         R                  " U5      nUR                  nUb  UR                  (       d  U$ g! [         a
  n SnAgSnAff = f)u>   
Récupère les fonds communs de placement détenant l'action
N)rp   rq   mutualfund_holdersr  r2   )r	  rw   r  
mutualfundr6   s        r    get_mutual_fund_holders4RealInstitutionalDataScraper.get_mutual_fund_holders9  sL    	IIf%E 11J%j.>.>!! 		r  c                 |    [         R                  " U5      nU R                  U5      nU R                  U5      nUUS.$ )u6   
Analyse complète de la propriété institutionnelle
)r  mutual_funds)rp   rq   r  r  )r	  rw   r  inst_holdersfund_holderss        r    analyze_institutional_ownership<RealInstitutionalDataScraper.analyze_institutional_ownershipK  sF     		&! 55f=33F; *(
 	
r!   c                 B    0 nU H  nU R                  U5      X#'   M     U$ )uB   
Compare les détentions institutionnelles pour plusieurs tickers
)r  )r	  tickersresultsrw   s       r    compare_institutional_holdings;RealInstitutionalDataScraper.compare_institutional_holdingsZ  s,     F"BB6JGO  r!   rw   c                 \    SU 3nSSSSSSS.n[         R                  " S	5        [        R                  " X#S
S9nUR	                  5         [        UR                  S5      nUR                  SSS9nU(       d  0 $ 0 nU Hw  nUR                  S5      n	U	 H]  n
U
R                  S5      n[        S[        U5      S	-
  S5       H,  nX   R                  SS9nXS	-      R                  SS9nXU'   M.     M_     My     UUR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      UR                  SS5      S.	nU$ ! [         a  n[        S U 35        0 s S nA$ S nAff = f)!Nz https://finviz.com/quote.ashx?t=zsMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36r)  zen-US,en;q=0.5r,  r+  r0  )r   r   r   r3  r4  r8        r   rQ  tablezsnapshot-table2class_trtdr   r  Tr  zInst OwnN/AzInsider Ownz
Inst TranszInsider TranszShort Float
Market CapP/EzTarget Price)	rq   Institutional_OwnInsider_Own
Inst_TransInsider_TransShort_Float
Market_Capr  Target_Pricez[ERROR] Erreur Finviz: )r  r  r   rv   r  r   rP  find_allrangers   r\  r2   r3   )r	  rw   r   r   r   ra  tablesr5   r  rowsrowr  r  r   rR  institutional_datar6   s                    r    get_finviz_data,RealInstitutionalDataScraper.get_finviz_datag  s   /	4VH=C Tf#3*-0!,G JJqM||C"EH%%' !1!1=AD]]73D]EF	D~~d+C<<-D"1c$ik15"g..T.: $qS	 2 2 2 >$)S	 6     !%)XXj%%@#xxu="hh|U;!%/5!A#xxu="hh|U;xxu- $ ?
" &% 	+A3/0I	s%   A7F :DF 
F+F& F+&F+company_namec                 R    SnUSSS.nU R                   R                  X#SS9nUR                  5         [        R                  " UR
                  5      nUR                  S5      nUb  UR                  R                  S5      $ g ! [         a  n[        S	U 35         S nAg S nAff = f)
N(https://www.sec.gov/cgi-bin/browse-edgar
getcompanyxml)rK  actionoutputr  r  z.//CIKr   z[ERROR] Erreur recherche CIK: )r   rv   r  ET
fromstringrP  findtextzfillr2   r3   )r	  r  r   rE  r   rootcik_elemr6   s           r    search_cik_real,RealInstitutionalDataScraper.search_cik_real  s    	<C'&F
 ||''B'GH%%'==!1!12Dyy*H#}}**2.. 	21#67	s   B B 
B&B!!B&cikc                 d    UR                  S5      nSnSUSSSUSS.nU R                  R                  XES	S
9nUR                  5         [        R
                  " UR                  5      nUR                  S5      nU(       d  [        R                  " 5       $ US   n	U	R                  S5      n
U	R                  S5      nU
b  U
R                  OS/Ub  UR                  OS/S.n[        R                  " U5      $ ! [         a-  n[        SU 35        [        R                  " 5       s S nA$ S nAff = f)Nr   r  r  z13F-HRr  excluder  )r  CIKtypedatebownercountr  r  r  z	.//filingr   
filingDate
filingHREFr  )Filing_DateDocument_URLz[ERROR] Erreur 13F: )r  r   rv   r  r  r  rP  findallr  r  r  r   r2   r3   )r	  r  rC  
cik_paddedr   rE  r   r  filingsfilingfiling_datefiling_hrefr5   r6   s                 r    get_latest_13f_holdings4RealInstitutionalDataScraper.get_latest_13f_holdings  s!   	"2J<C&! "F ||''B'GH%%'==!1!12Dll;/G||~%QZF ++l3K ++l3K 5@4K 0 0QVW5@5L!1!1RW XD <<%% 	"(,-<<>!	"s%   BC8 A!C8 8
D/"D*$D/*D/c                 T   SUR                  5       0nU R                  U5      nX2S'   / nUb  Un[        US5      (       a  UR                  SS9nU Hv  n UR	                  SS5      n [        U5      nUR                  UR	                  S	S
5      US-  S [        UR	                  SS5      5      UR	                  SS5      S.5        Mx     XBS'   U R                  U5      n	XS'   U R                  U5      n
XS'   U$ !   Sn N= f! [         a  n[        SU 35         SnAM  SnAff = f)uE   
Analyse COMPLÈTE d'une action avec données RÉELLES multi-sources
rw   yahoo_holdersNto_dictrecordsorient	pctChanger   Holderrh   r*  rr  zDate Reportedr  r  )Owner
Change_Pctr  Shares_HeldzError parsing holder for F13: f13r  finviz)upperr  r^   r  rv   r  r  r  r2   r3   r  r  )r	  rw   r  r  f13_datar  h
pct_changer6   r  finviz_datas              r    analyze_stock_complete3RealInstitutionalDataScraper.analyze_stock_complete  sR    V\\^, 66v>#0  $#G}i00'//y/A@!"{A!6J'%*:%6
 OO!"x!;)3c)9#(> #AEE/5$A B'(uuXq'9	%  $ " 33F;". **62'-'%&
 ! @:1#>??@s1   D(C;3AD;D?D
D'D""D')r  r   r  r   N)r  r   )r  )r  r  r  r  rf  r<  r  r  r  r  r  r  r  r  r  r  r  r  r  r,  r  r   r!   r    r  r    s    8
2G"3 G"# G"r|| G"V$$
	0c 0d 0hC &"3 "s "2<< "B/S /T /r!   r  r  c                     U c  g[        U S5      (       a*   SSKJn  U R                  UR                  R
                  :g  $ [        U S5      (       a  U R                  $ g! [         a     N*f = f)u   Check whether a websockets connection is closed.

Compatible with both:
  - websockets < 11  : WebSocketClientProtocol  → has `.closed` bool property
  - websockets >= 11 : ClientConnection          → has `.state` enum attribute
NTstater   closedF)r^   websockets.connection
connectionr/  StateOPENr2   r0  )ws_wscs     r    _ws_is_closedr7    sh     
zr7	088tzz.. r8yy  		s   (A 
A+*A+c                  0   [         R                  " [        R                  " 5       R                  5      R                  5       n U SSSSSSS/ SQS	S
S.n[        R                  " [        R                  " U5      R                  5       5      R                  5       $ )uP   Génère dynamiquement un device-info cohérent au format Base64 attendu par TR.Edgez	146.0.0.0Windows10zEurope/Paris1920x1080x32)frfr-FRenzen-GBzen-US      )stableDeviceIdr&  browserVersionr   	osVersionr   timezoneOffsetscreenpreferredLanguagesnumberOfCoresdeviceMemory)hashlibsha512uuiduuid4bytes	hexdigestbase64	b64encoder   dumpsencodedecode)	device_iddevice_infos     r    generate_device_inforX    s{    tzz|112<<>I#%" EK DJJ{3::<=DDFFr!   c                     [         (       d  [        S5        g[        S5        [        5       n U R                  S5        U R                  S5        U R                  S5        U R                  S5         [        R
                  " U S9nUR                  S	S
S05        UR                  S5        [        R                  " S5        UR                  5       n[        S[        U5       SU Vs/ s H  o3R                  S5      PM     sn 35        SnU H8  nSUR                  SS5      ;   d  M  US   n[        S[        U5       S35          O   U(       d:   UR                  S5      nU(       a!  [        S[        [        U5      5       S35        UR                  5         U(       a  [        S5        U$ [        S5        gs  snf ! [         a     NAf = f! [         a  n[        SU 35         SnAgSnAff = f)zRUtilise Selenium en mode Headless pour obtenir le token AWS WAF de Trade Republic.u3   [WARN] Selenium not available — WAF token skippedr  z>[BOT] Recuperation du token WAF via Selenium (arriere-plan)...z--headless=new--no-sandbox--disable-dev-shm-usagez--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0)r  z%Page.addScriptToEvaluateOnNewDocumentrB  zEObject.defineProperty(navigator, 'webdriver', {get: () => undefined})https://app.traderepublic.com/rB  z   -> z cookies trouves : rA   Nzaws-waf-tokenrR  z)   -> Cookie 'aws-waf-token' trouve (len=r
  zGreturn window.AWSWafIntegration && window.AWSWafIntegration.getToken();z   -> Token WAF via JS (len=z%[OK] Token WAF recupere avec succes !z^[WARN]  Token WAF introuvable - le WAF Challenge n'a peut-etre pas eu le temps de se resoudre.z[ERROR] Erreur Selenium WAF : )SELENIUM_AVAILABLEr3   ChromeOptionsadd_argumentr%   Chromeexecute_cdp_cmdrv   r  r  get_cookiesrs   execute_scriptr  r2   quit)r  driverall_cookiesr  	waf_tokencookier6   s          r    get_waf_token_with_seleniumri  .  s   CD	
JKoG)*(23	^%!!'2F]I
 	 	

34

1((*s;'((;T_<`T_qUU6]T_<`;abc	!F&**VR"88"7O	A#i.AQQRST	 " "11]	 8S^9L8MQOP 	9:no1 =a"    .qc23s[   2A5G 'F;$G )(G 9G  #G /G ;G  
G
G GG 
G2G--G2c                       \ rS rSrSS jrS rSS jrSS jrS rS r	S	 r
S
 rSS jrS rS rS rS rS S jrS rS rS!S jrS rS"S jrS rS#S jrS rS rS"S jrSrg)$TradeRepublicAPIid  c                    [         R                  " 5       U l        U R                  R                  U5        Xl        U R                  R                  SSSS9U l        U R                  R                  SSSS9U l        U R                  R                  SSSS9U l	        U R                  R                  S	S
S S9U l
        U R                  R                  S	SS S9U l        U R                  R                  S	SSS9U l        U R                  R                  S	SSS9U l        U R                  R                  S	SS S9U l        U R                  R                  S	SS S9U l        U R                  R                  S	SSS9U l        U R                  R                  S	SSS9U l        U R"                  (       d  [%        5       U l        S U l        SU l        S U l        0 U l        g )Ngeneraloutput_formatr   r   output_folderz./outextract_detailsFr   r  r/  r0  r  r1  r   
tr_refreshrg  rW  r   )configparserConfigParserr   r   r   rv   rn  ro  
getbooleanrp  r  r/  r0  r1  r   refresh_tokenrg  rW  rX  	websocket
message_idcached_sec_acccached_exchanges)r	  r   s     r    r<  TradeRepublicAPI.__init__e  s   "//1%& "[[__YRX_Y![[__YRY_Z#{{55iAR]b5c !KKOOHntOT;;??8UT?B++//(L2/N;L![[__X|d_S![[__X|d_S ;L;;??8]R?P35D # "r!   c                    U R                   (       d  gU R                  (       a  U R                  $  U R                   R                  S5      n[        U5      S:w  a  gUS   n[        U5      S-  nU(       a  USSU-
  -  -  n[        R
                  " U5      R                  S5      n[        R                  " U5      nUR                  S0 5      nUR                  S	0 5      nUR                  S
0 5      nUR                  S0 5      n	U	R                  S/ 5      n
U
(       a%  [        U
5      S:  a  U
S   U l        U R                  $  [        SU R                   35        U R                  $ ! [         a  n[        SU 35         SnAgSnAff = f)z;Extract Securities Account Number from Session Token (JWT).N.   r     =utf-8actaccr  r,  secr   zSecAccNo from JWT: z Error parsing JWT for secAccNo: )r   rx  splitrs   rQ  urlsafe_b64decoderU  r   loadsrv   r3   r2   )r	  partspayload_b64paddingpayload_strpayloadr  r  r  r,  sec_listr6   s               r    get_sec_acc_noTradeRepublicAPI.get_sec_acc_no  sg   !!$t':': :#	:&&,,S1E5zQt  (K+&*Gsa'k':: 22;?FFwOKjj-G
 ++eR(C''%$CGGGR(Eii	2.G{{5"-HCMA-&.qk#*** '(;(;'<=>&&& 	:4QC899	:s$   *E' C%E' $E' '
F	1FF	c                    U R                  5       nU(       d  [        S5        gUR                  5       nSU SU S3nSn U R                  R	                  SSSS9nU(       a  UnOVS	U R                   3n U R                  R	                  SS
SS9nU(       a  USU 3-  n[        U SS5      nU(       a  USU 3-  nSUSSSSSSSSSSSSS.n	 [        SU SU(       a  SOS S35        [        R                  " XIS S!9n
U
R                  S":X  a  [        S#5        U
R                  5       $ U
R                  S$:X  aA  [        S%5        U R                  5       (       a  U R                  U5      $ [        S&5        S'S(S).$ [        S*U
R                   S+U
R                  SS"  35        S,U
R                  S-.$ ! [
         a     GNbf = f! [
         a     GN/f = f! [
         a  n[        S.U 35         SnAgSnAff = f)/zRFetch portfolio chart data from TR API V2. Uses full browser cookies if available.z4[ERROR] Cannot fetch chart: No Account Number found.NzLhttps://api.traderepublic.com/api-gateway/portfolio-chart/v2/chart?secAccNo=z&range=z&currency=EURr   tr_browser_cookiesr   tr_session=	tr_claimsz; tr_claims=rg  z; aws-waf-token=z}Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36 Edg/147.0.0.0https://app.traderepublic.comr\  r   r>  rB  z15.6.4webr  cors	same-siteno-cache)r   Cookier   r   r   r   Content-Typex-tr-app-versionx-tr-platformr5  r6  r7  Pragmar8  zFetching TR Chart: z
 (cookies=r&  zsession-onlyr
  r  r   r   z([OK] Portfolio Chart fetched via TR API.  zW[WARN] Portfolio Chart 401: session expired - attempting auto-refresh via tr_refresh...zM[ERROR] Auto-refresh failed. Paste fresh browser cookies via /api/tr-cookies.authu5   Session expirée. Collez les cookies depuis DevTools.r   rj  z[ERROR] Portfolio Chart HTTP rm   http)r   r   z#[ERROR] Portfolio Chart Exception: )r  r3   r=   r   rv   r2   r   getattrr   r   r   refresh_session_tokenfetch_portfolio_chartr   )r	  
range_codesec_acc	api_ranger   browser_cookiescookie_headerclaimswafr   r   r6   s               r    r  &TradeRepublicAPI.fetch_portfolio_chart  sH   %%'HI$$&	\]d\eelmvlw  xE  F 	"kkooh8LW[o\O +M *$*<*<)=>M;N!|F8%<<M $T2C#3C5!99 Z#57#. ("%$) '
"	'uJOyYg6hhijk<<bAD3&@Ayy{"!!S(op--//55jAAef!'4kll5d6F6F5Gr$))TXUX/IZ[\!'43C3CDDg  		  P  	7s;<	sP    F0 5*G AG (A G )G 96G 0
F>=F>
GG
G4G//G4Nc                    U R                   R                  S5      (       d  U R                   R                  S5        U R                   R                  SSU5        U(       a#  U R                   R                  SSU5        X l        [        U R                  S5       nU R                   R                  U5        SSS5        Xl        [        S5        g! , (       d  f       N = f)z5Save the session token to config.ini for persistence.r   r   rq  wNz'[OK] Session token saved to config.ini.)
r   has_sectionadd_sectionsetru  r   r   r   r   r3   )r	  tokenru  
configfiles       r    save_session_token#TradeRepublicAPI.save_session_token  s    {{&&x00KK##H-,6KKOOHlMB!.$""C(JKKj) )"78 )(s   C
Cc                 D   U R                   R                  U R                  5        U R                  =(       d    U R                   R	                  SSSS9nU(       d  [        S5        gSnU R                  5       nSU 3US	'   U R                  (       a  US	==   S
U R                   3-  ss'    [        S5        [        R                  " X#SSS9n[        SUR                   35        SnSnS nUR                  S;   Ga  U" US5      nU" US5      nU(       d   UR                  5       nUR	                  S5      =(       d)    UR	                  S5      =(       d    UR	                  S5      nUR	                  S5      =(       d    UR	                  S5      =(       d    UnU(       dz  UR                  R	                  SS5      n	[        R                  " SU	5      n
U
(       a  U
R!                  S5      n[        R                  " SU	5      nU(       a  UR!                  S5      nU(       a-  U R#                  XV=(       d    U5        SU l        [        S5        g[        SUR&                  SS  S 35        g! [         a     Nf = f! [         a  n[        S!U 35         SnAgSnAff = f)"zxExchange the tr_refresh token for a fresh tr_session without user interaction.
Returns True on success, False otherwise.r   rq  Nr   z0[TR Refresh] [ERROR] No refresh token available.Fz5https://api.traderepublic.com/api/v1/auth/web/refreshztr_refresh=r  z; tr_session=z?[TR Refresh] Attempting session token refresh via tr_refresh...r  r   r   allow_redirectsz[TR Refresh] -> HTTP c                      U R                   R                  U5      $ ! [         a6    U R                    H#  nUR                  U:X  d  M  UR                  s  s $     g f = fr   )cookiesrv   r2   rA   rR  )r   rA   r  s      r    _get_cookie;TradeRepublicAPI.refresh_session_token.<locals>._get_cookie  sV     #++//55   %--66T>#$77N .  	 s    'AAAA)r         r   sessionTokenr  access_tokenrefreshTokenru  
Set-Cookier  ztr_session=([^;,\s]+)r  ztr_refresh=([^;,\s]+)z1[TR Refresh] [OK] Session refreshed successfully.TzD[TR Refresh] [WARN] No new session token in refresh response (body: r   r
  z [TR Refresh] [ERROR] Exception: )r   r   r   ru  rv   r3   _build_login_headersr   r   r_  r   r   r2   r   researchgroupr  rx  r   )r	  refresh_tokr   r   r   new_sessionnew_refreshr  body
set_cookierc  m2r6   s                r    r  &TradeRepublicAPI.refresh_session_token  sT    	))*((bDKKOOHl]aO,bDEE++-)+7H=1C1C0D!EE4	ST==rSXYD)$*:*:);<=KK  ?2)$=)$= ##yy{&*hh~&>&o$((7BS&oW[W_W_`nWo&*hh~&>&j$((?B[&j_j
 #!%!1!1,!CJ		":JGA&'ggaj#;ZHB&(hhqk''5OKP&*#IK\]a]f]fgkhk]l\mmnop) % ,  	4QC89	sE   -A*I= BI- B4I= I= -
I:7I= 9I::I= =
JJJc                 B   0 nUR                   R                  5        H~  u  p40 nUR                  S5      nU HS  nUR                  S5      S   nSU;   d  M  UR                  SS5      u  pU
R                  5       XYR                  5       '   MU     U(       a  UOUX#'   M     U$ )N, ;r   r  r  )r   r_   r  r  )r	  r   extracted_headersheaderheader_valueparsed_dictentriesentry	key_valuer   rR  s              r    headers_to_dict TradeRepublicAPI.headers_to_dictJ  s    $,$4$4$:$:$< FK"((.G !KK,Q/	)#!*a!8JC/4{{}K		,	 !
 8C% %= ! r!   c                 J    SSSSSSU R                   SU R                  SS	S
SS.$ )zQConstruit les headers complets requis par l'API Trade Republic (anti-WAF inclus).r   r>  rB  r  r\  z}Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0z14.23.3r  r  r  r  )r   r   r  r   r   r   zx-aws-waf-tokenr  zx-tr-device-infor  r5  r6  r7  )rg  rW  r  s    r    r  %TradeRepublicAPI._build_login_headersW  sC     #.57?  $~~ ) $ 0 0"%$)#
 	
r!   c                    [        5       U l        U R                  (       a  U R                  R                  S5      (       d  U R                  R	                  S5        U R                  R                  SSU R                  5        [        U R                  S5       nU R                  R                  U5        SSS5        U R                  $ U R                  $ ! , (       d  f       U R                  $ = f)zPLance Selenium pour obtenir un nouveau token WAF et le persiste dans config.ini.r   rg  r  N)	ri  rg  r   r  r  r  r   r   r   )r	  r  s     r    _refresh_waf_token#TradeRepublicAPI._refresh_waf_tokenm  s    46>>;;**844''1KKOOHk4>>Bd&&,
!!*- -~~t~~ -,~~s   C
C.c                   ^ ^^ TT l         TT l        U(       a  UT l        U(       a  UT l        T R                  R                  S5      (       d  T R                  R                  S5        T R                  R                  SST5        T R                  R                  SST5        U(       a  T R                  R                  SSU5        U(       a  T R                  R                  SSU5        [        T R                  S5       nT R                  R                  U5        SSS5        UUU 4S jn [        S	T S
35        T R                  (       d,  T R                  5         T R                  (       d  [        S5        U" 5       n[        SUR                   SUR                  R!                  SS5       35        UR                  S;   aH  [        SUR                   S35        T R                  5         U" 5       n[        SUR                   35        UR                  S;   ag  UR                  R!                  S5      nU(       aE  [        SUR                   SU S35        ["        R$                  " UTTS.T R'                  5       SSS9nUR)                  5         UR+                  5       n	U	R!                  S5      n
U	R!                  S5      nU
(       a  SXS.$ SS S!.$ ! , (       d  f       GN= f! ["        R,                  R.                   Ga6  nUR0                  b  UR0                  R                  OS"nS#n UR0                  R2                  nO!    O= fS$U 3n UR0                  R+                  5       n[5        U[6        5      (       az  UR!                  S%5      nU(       a+  [5        U[8        5      (       a  US&   R!                  S'U5      nOQUR!                  S'5      (       a  US'   nO5UR!                  S(5      (       a  US(   nO!   U(       a  S$U S)USS*  3n O= f[        S+U S,U S-USS.  S/35        SUS!.s SnA$ SnAf[:         a&  n[        S+U 35        S[=        U5      S!.s SnA$ SnAff = f)0z8Initiate login process: Send credentials, get processId.r   r  r/  r0  r1  r  Nc                  V   > [         R                  " ST TS.TR                  5       SSS9$ )Nz3https://api.traderepublic.com/api/v1/auth/web/loginphoneNumberr/  r  Fr   r   r   r  )r   r_  r  )r.  r/  r	  s   r    _do_request4TradeRepublicAPI.initiate_login.<locals>._do_request  s3     ==E%*37113 % r!   z[KEY] Initiating login for r   zH[WARN]  Selenium n'a pas pu obtenir le token WAF - tentative sans token.z   -> Status TR: z  | Redirect: Locationr/  )i  i  z[WARN]  zK WAF detecte - actualisation du token via Selenium et nouvelle tentative...z   -> Retry status TR: )i-  i.  i3  i4  z   -> Redirection z vers z - suivi POST expliciter  r  Fr  	processIdcountdownInSecondsT)r   r  	countdownzNo processId receivedr   ?r  zHTTP r  r   rj  r   rm   r   z[ERROR] Login init error: z	 (status=z, body=,  r
  )r  r/  r0  r1  r   r  r  r  r   r   r   r3   rg  r  r   r   rv   r   r_  r  r  r   
exceptions	HTTPErrorr   r   r  r  listr2   r  )r	  r.  r/  r0  r1  r  r  r   location	resp_json
process_idr  r6   r   raw_bodymsgerr_jsonr  s   ```               r    initiate_loginTradeRepublicAPI.initiate_loginx  s   !tydn {{&&x00KK##H-.%8%-t{{xzJdkkoohYG$""C(JKKj) )		C	7/wc:; >>'')~~de=D%d&6&6%7~dllFVFVWaciFjEklm :-!1!1 22}~'')"}/0@0@/ABC #77<<++J7.t/?/?.@xjPghi#== -23? $ 9 9 ; "(-D !!#		I"{3J!&:;I#'jYY$/FGGk )(n "",, 	445JJ4J!**00PSKH::??+'CB::??,h--%\\(3F*VT":":$QimmIs;!i00&y1!g..&w/B!+b$30@AC.se9[MQYZ^[^Q_P``abc$s33 	7.qc23$s1v66	7s   K.F$K* K* 
K'*Q-	'P:1MP:M

P:A1O?P:O?"P:#O?>P:?P!P:4Q-:Q-Q("Q-(Q-c                      [         R                  " SU S3U R                  5       SSS9  SS0$ ! [         a  nS[	        U5      S.s S nA$ S nAff = f)	N4https://api.traderepublic.com/api/v1/auth/web/login/z/resendr   Fr  r   Tr   )r   r_  r  r2   r  )r	  r  r6   s      r    
resend_smsTradeRepublicAPI.resend_sms  s^    		7MMFzlRYZ113 %	 t$$ 	7$s1v66	7s   ,/ 
AAAAc                 l    [         R                  " SU SU 3U R                  5       SSS9nUR                  S:w  a  [	        S5        SSS	.$ [	        S
5        S nU" UR
                  S5      nU" UR
                  S5      nU(       dZ  U R                  U5      nUR                  S0 5      n[        U[        5      (       a"  UR                  S5      nUR                  S5      nU(       a  U R                  XV5        SS0$ SSS	.$ ! [         a&  n	[	        SU	 35        S[        U	5      S	.s Sn	A	$ Sn	A	ff = f)zComplete login with SMS code.r  /r   Fr  r   z#[ERROR] Device verification failed.zVerification failedr   z[OK] Device verified!c                      U R                  U5      $ ! [         a,    U  H#  nUR                  U:X  d  M  UR                  s  s $     g f = fr   )rv   r2   rA   rR  )r  rA   rh  s      r    get_cookie_safe8TradeRepublicAPI.complete_login.<locals>.get_cookie_safe  sJ     ";;t,,   ")!;;$.#)<</ #*   s    A	A	A	A	r   rq  r  r   TzNo session token in responsez[ERROR] Login complete error: N)r   r_  r  r   r3   r  r  rv   r  r  r  r2   r  )
r	  r  coderesp2r  r  refreshresponse_headersr  r6   s
             r    complete_loginTradeRepublicAPI.complete_login  s9   +	7MMFzlRSTXSYZ113 %	E   C';<#(3HII)*  $EMM<@E%emm\BG #'#7#7#> *..|R@gt,,#KK5E%kk,7G ''7!4((#(3QRR 	721#67$s1v66	7s+   A
D B0D >D 
D3D.(D3.D3c           
        #    U R                   (       d  [        S5        gSSU R                    3SS.n [        R                  " SUSS	S	S
[        S9I S
h  vN U l        U R
                  R                  S5      I S
h  vN   [        R                  " U R
                  R                  5       SS9I S
h  vN nSU;   a  [        S5        S
S
S.q
g[        SU 35        g N Na N.! [         au  n[        SU 35        S[        U5      ;   d-  S[        U5      ;   d  S[        U5      ;   d  S[        U5      ;   a!  [        S5        U R                  S5        SSS.q
 S
nAgS
nAff = f7f)zEstablish WebSocket connection.z7[ERROR] No session token available. Please login first.Fr   r  r  )r   r  r   zwss://api.traderepublic.comr4  r   N)additional_headersping_intervalping_timeoutclose_timeoutmax_sizesslzconnect 34 {"locale":"fr","platformId":"webtrading","platformVersion":"edge-chromium - 143.0.0","clientId":"app.traderepublic.com","clientVersion":"12.12.0"}      @r   	connectedz[OK] WebSocket connected.r  rj  Tz'[WARN] Unexpected connection response: z%[ERROR] WebSocket connection failed: 401100010063003z_[WARN] Session expired or invalid (code 3003). Clearing token - please log in again via the UI.r  i  z%Session expired. Please log in again.)r   r3   
websocketsr   _SSL_CTXrv  sendr   wait_forrecvTR_WS_ERRORr2   r  r  )r	  r   r   r6   s       r    r   TradeRepublicAPI.connect  sk     !!KL L#D$6$6#785
	#-#5#5-#*  $ DN ..%%  'F  G  G  G$--dnn.A.A.CSQQHh&12'+=?zJK) GQ  	9!=>A&CF"2fA6F&TWXYTZJZwx''+'+8_`	sq   1E%!C# C'C# =C>4C# 2C!3C# E%C# E%C# C# !C# #
E"-A+EE%E""E%c                 x   #    U R                   (       a#  U R                   R                  5       I S h  vN   g g  N7fr   )rv  r   r  s    r    r   TradeRepublicAPI.closeC  s*     >>..&&((( (s   /:8:c                 *  #    U R                   (       d!  U R                  5       I S h  vN nU(       d  / $ U =R                  S-  sl        U R                  nSUUS.n U R                   R                  SU S[        R
                  " U5       35      I S h  vN     [        R                  " U R                   R                  5       SS9I S h  vN nUR                  U S	35      (       au  UR                  SS
5      n[        U5      S
:  aS  [        R                  " US
   5      nUR                  S/ 5      n	U R                   R                  SU 35      I S h  vN   U	$ OSUR                  U S35      (       a:  [        SU SU 35        U R                   R                  SU 35      I S h  vN    / $ GM   GN GN# N! [        R                   a    [        SU 35         / $ f = f N N=! [          a  n
[        SU SU
 35         S n
A
/ $ S n
A
ff = f7f)Nr  aggregateHistoryLight)r
  r  r-  sub  g      $@r  ztimeout fetching z Ar  
aggregatesunsub z EzError fetching rm   zException fetching )rv  r   rw  r  r   rS  r   r  r  TimeoutErrorr3   
startswithr  rs   r  rv   r2   )r	  instrument_id	range_valr  msg_idr  r   r  r5   r!  r6   s              r    fetch_aggregate_history_light.TradeRepublicAPI.fetch_aggregate_history_lightG  s    ~~"lln,I	1 ,
	>..%%VHAdjj6I5J&KLLL !(!1!1$..2E2E2GQU!VVD
 ??fXR=11 JJsA.E5zA~#zz%(3%)XXlB%?
 #nn11F6(2CDDD)) & __xr]33OM?"TFCD..--vh.?@@@
 	3 # - M
 W++ -m_=>( 	- E A  	>'b<==		>s   %HF54H8G* F8G* 0F= F;F= BG* G&G* HAG* *G(+G* /H2G* 5H8G* ;F= ="G#G*  H"G##G* (G* *
H4HHHHc           
        #    U R                   (       d,  U R                  5       I Sh  vN nU(       d  [        S5        / $ 0 n[        S/5      n[	        [
        R                  5      [        S5       Vs/ s H  n[        U5      PM     sn-   / SQ-   n[        S5        SnU(       GaE  UR                  5       nUS-  n[        U5      S	::  d	  US
-  S:X  a'  [        SU S[        U5       S[        U5       S35        U =R                  S-  sl        U R                  nSUSSSSS./S.S.n	Sn
 U R                   R                  SU S[        R                  " U	5       35      I Sh  vN    SnU(       Gd(   [         R"                  " U R                   R%                  5       SS9I Sh  vN nUR'                  S5      (       a  MV  UR)                  SS	5      n[        U5      S	:  a  US   [        U5      :X  a  US   S;   ac  [        U5      S	:  aS  [        R*                  " US	   5      nUR-                  SS5      n
U R                   R                  SU 35      I Sh  vN   SnO1US   S:X  a(  U R                   R                  SU 35      I Sh  vN   SnU(       d  GM(  S nU
U:  a  U H  nUR/                  UU-   5        M     OU
S:  a  U R1                  Xr5      I Sh  vN   U(       a  GME  [        S![        U5       S"35        [	        UR3                  5       5      $  GNs  snf  GN! [         an    U R                  5       I Sh  vN  (       aK  U R                   R                  SU S[        R                  " U	5       35      I Sh  vN     GN'!     GM  = f GM   f = f GN! [         a  n SnAGM  SnAff = f GNe GN6! [         a     GN5f = f N7f)#zz
Retrieves ALL stocks (~11k+) using a recursive prefix scan to bypass the 10k limit.
Returns a list of raw stock objects.
Nz&[ERROR] Not connected to TR WebSocket.r  r   )r|  -&r  z/[NET] Demarrage du scan RECURSIF des actions...r   r  r  r4  z   --> Scan: 'z
' (Queue: z, Trouves: r
  
neonSearchr
  r  r   rR  qpagepageSizefilterr
  r5   r  r   Fr  r  echoACresultCountr"  TE  z[OK] Scan complet termine. z actions recuperees.)rv  r   r3   r   r  stringascii_lowercaser  r  popleftrs   rw  r  r   rS  r2   r   r  r  r$  r  r  rv   r  _fetch_all_pagesvalues)r	  r  all_unique_resultssearch_queuer  extended_charsprocessed_countr   r'  r  total_count
probe_doner   r6   r  r5   	thresholdr  s                     r    r   +TradeRepublicAPI.fetch_all_stocks_recursiveu  s    
 ~~"lln,I>?	bT{ f445*/)4)Q#a&)45-. 	?A  ((*Eq O 5zQ/B"6!";ugZL8I7J+VYZlVmUnnopq OOq O__F % !'-@A	G Knn))D$**W:M9N*OPPP"
$%,%5%5dnn6I6I6KUX%YY
 v.. JJsA.E5zQ58s6{+B 8z1"5zA~'+zz%(';.2hh}a.H&*nn&9&9F6(:K&L L L-1
"1X_"&.."5"5vh6G"HHH)-J) %*4 IY&'A ''	2 ( ?//JJJM lP 	+C0B,C+DDXYZ&--/00y - 5D Q ,,.((!%!4!4tF81TZZPWEXDY5Z![[[&h  Z$  !M I  Ks!  %OLAO3L B$O-8L( %L%&L( +
O 60N& &N#'N& +B/O N?1O OO A OOO,2O O%L( (N M
N 8NN	NONN ON ON  O#N& &
N<0O 4O7N<<O O 
OOOOc           	      "  #    U R                   (       d   U R                  5       I S h  vN nU(       d  g SnSn U =R                  S-  sl        U R                  nSUUUSSS./S.S	.n U R                   R                  S
U S[        R
                  " U5       35      I S h  vN   Sn Sn	U	(       Gdi   [        R                  " U R                   R                  5       SS9I S h  vN n
U
R                  S5      (       a  MV  U
R                  SS5      n[        U5      S:  a  US   [        U5      :X  a  US   S;   a  [        U5      S:  a  [        R                  " US   5      nUR                  S/ 5      nU H(  nUR                  S5      nU(       d  M  X;  d  M$  XU'   M*     [        U5      U:  a  SnU R                   R                  SU 35      I S h  vN   Sn	O3US   S:X  a*  U R                   R                  SU 35      I S h  vN   Sn	SnU	(       d  GMi  U(       a  g US-  n[        R"                  " S5      I S h  vN   GM   GN# GN! [         ad    U R                  5       I S h  vN     U R                   R                  S
U S[        R
                  " U5       35      I S h  vN     GN!     g = ff = f GN! [         a    U R                  5       I S h  vN     M  f = f GN N! [        R                    a     g f = f N7f)Nr  r   Tr-  r
  r  r.  r/  r4  r  r   F       @r  r5  r  r   r6  r  r   r"  r:  g{Gz?)rv  r   rw  r  r   rS  r2   r   r  r  r$  r  rs   r  r  rv   r#  r  )r	  r   storage_dictr  r1  	page_sizer'  r  page_finishedresponse_receivedr   r  r5   r  rr   s                   r    r?  !TradeRepublicAPI._fetch_all_pages  s    ~~#||~-Y	OOq O__F %  )'-@A	Gnn))D$**W:M9N*OPPP "M%$)!+%,%5%5dnn6I6I6KUX%YY v.. JJsA.E5zQ58s6{+B 8z1"5zA~'+zz%(';*.((9b*A *1A+,55=D'+t0H=>T(: *1 $'w<)#;48M&*nn&9&9F6(:K&L L L48 1"1X_"&.."5"5vh6G"HHH04-,0MC ,+J AID--%%%E  .* Q lln$$..--VHAdjj>Q=R.STTT  Z$ #||~--0 !M I ''  &s  %LI
A L)8I !I"I &L)
K3 40K $K%K )B)K3 K3 :K3 K.1K3 	K1
K3 &LLLI J>-I0.J>48J5,J/-J52L5J:7J>8L:J>>LK K+!K$"K+'K3 (L*K++K3 1K3 3L
L	L

Lc                 R  #    U R                   (       d  [        S5      eU =R                  S-  sl        U R                  nU R                   R                  SU S[        R
                  " U5       35      I Sh  vN   Sn  [        R                  " U R                   R                  5       SS9I Sh  vN nUR                  S5      (       a  MN  UR                  SS	5      n[        U5      S	:  a  Mq  US
   nUS   n	U[        U5      :X  a@  U	S:X  a:  [        SU SU 35          U R                   R                  SU 35      I Sh  vN   gU[        U5      :X  a,  [        U5      S	:  a  [        R                  " US	   5      nO0 nOGM   U R                   R                  SU 35      I Sh  vN   U$  GN9 GN Nr!    g= f! [        R                   a@    [        SU 35          U R                   R                  SU 35      I Sh  vN    g!    g= f[         aJ  n
[        SU SU
 35         Sn
A
 U R                   R                  SU 35      I Sh  vN    g!    g= fSn
A
ff = f N!    U$ = f!  U R                   R                  SU 35      I Sh  vN    f !    f = f= f7f)z,Subscribe, get one message, and unsubscribe.zWebSocket not connectedr  r  r   NrJ  r  r5  r  r   r:  z[ERROR] API Error on rm   r"  z[WARN] Timeout waiting for z[ERROR] Error reading )rv  r2   rw  r  r   rS  r   r  r  r$  r  rs   r  r3   r  r#  )r	  r  rA   log_structurer'  r5   r   r  frame_id
frame_typer6   s              r    
_sub_unsubTradeRepublicAPI._sub_unsub'	  s    ~~5661nn!!D$**W2E1F"GHHH*	!(!1!1$..2E2E2GQT!UU &&v.. sA.u:>"1X"1X
 s6{*zS/@1$r(DE&nn))F6(*;<<<% s6{*5zA~#zz%(3!5 Jnn))F6(*;<<< _ 	I VJ = ## 	/v67nn))F6(*;<<<  	*4&1#67nn))F6(*;<<<	 =nn))F6(*;<<<s3  A6J'8F19J' 1G  1F42A/G  #!F9 F7F9 	J'
:G  I3 G  	!I+ *I)+I+ /J'4G  7F9 9F=;J' "I&"I3 $!H HH J'HJ'	I&I!-I3 2!I II J'IJ'!I&&I3 )I+ +I0-J'3J$5!JJJJ$J!J$$J'c                   #    U R                   (       a  U R                   $ [        S5        U R                  SS0S5      I Sh  vN nU(       a  SU;   a  US   n[        U[        5      (       a:  U H3  nUR                  S5      nU(       d  M  [        SU 35        X@l         Us  $    OC[        U[        5      (       a.  UR                  S5      nU(       a  [        SU 35        X@l         U$ [        S	5        g N7f)
z0Dynamically fetch the securities account number.zB[SEARCH] Searching for securitiesAccountNumber via accountPairs...r
  accountPairsAccountPairsNaccountssecuritiesAccountNumberz[OK] Securities Account Found: z:[ERROR] securitiesAccountNumber not found in accountPairs.)rx  r3   rU  r  r  rv   r  )r	  resaccounts_listr  r  s        r    get_securities_account'TradeRepublicAPI.get_securities_account`	  s     &&&RSOOV^$<nMM:$
OM-..(C!gg&?@Gw!@	JK/6, ' ) M400(,,-FG<WIFG+2(#^JK% Ns   A C9C7AC9A+C9c                   #    U(       d  [        S5        U R                  5       I S h  vN nU(       d  U(       d  [        S5        0 $ U(       d  [        SU S35        U R                  SUS.S5      I S h  vN nU(       d  [        S5        U R                  S	S
0S5      I S h  vN n0 n[        U[        5      (       aJ  [        U5      S:  a;  US   nU(       d/  [        SUR                  S5       SUR                  S5       35        / nU(       a  SU;   a  US   nOSU;   a  U(       d  [        S[        US   5       S35        US    Hv  nUR                  S5      =(       dJ    UR                  S5      =(       d2    UR                  S5      =(       d    UR                  S5      =(       d    / nUR                  U5        Mx     U(       Ga  U(       d  [        S[        U5       S35        / n	U GH  n
U
R                  S5      nU(       d  M  [        U
R                  SS5      5      nSnSnU
R                  S5      n[        U[        5      (       a  [        UR                  SS5      5      nOUb  [        U5      n U R                  U5      I S h  vN nU(       d  U(       d  [        SU S 35        S!nU R                  UU5      I S h  vN nU(       d  U(       d  [        S"U S#U 35        U R                  U5      nUS:X  a  U(       a  U(       d   X-  nUX-  -
  nX-  S:  a
  UX-  -  S&-  OSnUU
R                  S'5      UUUUUUS([        5       ;   a  WOS!U
R                  S)S*5      U
R                  S+5      S,.nU	R                  U5        GM     UU	U	[!        ["        R$                  " 5       5      S-.n ['        UU R(                  S.9  U(       d  [        S/5        U	$ U(       d  [        S15        0 $  GN GN GNY!    GN= f GNu GN?! [         a#  nU(       d  [        S$U S%U 35         S nAGN S nAff = f! [         a  n[        S0U 35         S nAU	$ S nAff = f7f)2Nz/
? Fetching Portfolio (Optimized for Stocks)...z1[WARN] Cannot fetch portfolio without Account ID.z&[SEARCH] Fetching portfolio items for r   compactPortfolioByTypeV2)r
  secAccNoPortfolioV2z[SEARCH] Fetching cash info...r
  r;  Cashr   z[MONEY] Cash found: r|  r   
currencyIdr  
categoriesz? Found z categories.r  r_   productsri  z/ positions found. Enriching with market data...r   netSizerz  averageBuyInrR  z[WARN] No exchange found for z, defaulting to LSXLSXz[ERROR] No ticker data for r|  z[WARN] Error enriching rm   r*  rA   exchange_idr  r  imageIdr   rA   rp  rq  rr  r<  rs  rt  ru  r  rw  )r  r  r  rU  )r  z[SAVE] Saved to Database.zError saving portfolio data: z-[ERROR] No positions found or empty response.)r3   r^  rU  r  r  rs   rv   extendr  r  get_home_exchange
get_ticker_extract_pricer2   localsr  r  r	   r  r  r  )r	  silent
sec_acc_nor5   cash_rawr  r  catr_   enriched_positionsposr   r  rq  
curr_price
avg_buy_inrk  rw   r6   r<  rs  rt  pos_datawallet_datas                           r    fetch_portfolio TradeRepublicAPI.fetch_portfolioz	  s&    DE  6688
 E"UVY uEj\QTUV__/ZH
 
 u=?&&)96BBh%%#h-!*;&qk^E$89K9KH9U8VVWXfXjXjkwXxWy"z{ 	D  O	%T,5G1H0I&V W .S !WW[1xSWWW5ExQZI[x_b_f_fgq_rxvxU%%e,	 / 55Y(88g!hi!# wwv CGGIq12	 
 !WW^4
j$// %jnnWa&@ AI+&+J&7)P(,(>(>t(D"DK&%u/LTFRe-f'g&+
 $(??4#EEF!&!<TF!K=QR!%!4!4V!<J!S(VF ".!S_5BE/UVAVsco6#=\] !GGFO #!*%/#.#./</He&)gg.>&HGGI. #))(3y !D "0"4&8 #HLLN 3	K;!+$:K:KLu%@A &%5!PQIs 9
 CP "T
 #E F ! P!5+B4&1#)N#OPH  ;5aS9::%%;s   &Q$O7AQ$6O:7-Q$$O=%GQ$3P ?PP8PPA	PB$Q$;&P> !Q$:Q$=Q$ PQ$PP
P;P60Q$6P;;Q$>
Q!QQ$Q!!Q$c                    #    XR                   ;   a  U R                   U   $ SXR                  S.nU R                  USU 3S9I S h  vN nU(       a  UR                  S5      OS nU(       a  X@R                   U'   U$  N57f)NhomeInstrumentExchanger
  r-  r  z	Exchange rA   
exchangeId)ry  r   rU  rv   )r	  r   r  r5   r\  s        r    ro  "TradeRepublicAPI.get_home_exchange	  s|     (((((..34J\J\]__WYtf3E_FF(,dhh|$$*-!!$'
 Gs   AA>A<6A>c                 p   #    U SU 3nSX0R                   S.nU R                  USU 3S9I S h  vN $  N7f)Nr|  rw   r  zTicker r  )r   rU  )r	  r   rk  	ticker_idr  s        r    rp  TradeRepublicAPI.get_ticker

  sE     fAk]+	#9?Q?QR__WWTF3C_DDDDs   -646c                 F   U(       a  [        U[        5      (       d  gS n SU;   a*  [        US   [        5      (       a  SUS   ;   a	  US   S   nO_SU;   a*  [        US   [        5      (       a  SUS   ;   a	  US   S   nO/SU;   a)  [        US   [        5      (       a  SUS   ;   a  US   S   nU(       d:  SU;   a4  [        US   [        5      (       a  US   nSU;   a  US   nOSU;   a  US   nU(       d  g[        U[        5      (       d  [	        U5      $  [	        UR                  SS	5      5      nUR                  S
S5      nUSU-  -  $ ! [         a  n[        SU 35         S nAgS nAff = f!    g= f! [         a  n[        SU SU 35         S nAgS nAff = f)Nrz  lastpricebidaskaggregatedInfoz'[WARN] Error parsing ticker structure: rR  r   fractionDigitsr  r   z+[WARN] Error calculating price from object rm   )r  r  r2   r3   r  rv   )r	  ticker_data	price_objaggr6   valdigitss          r    rq  TradeRepublicAPI._extract_price
  s   *[$"?"?		$K4G)N)NSZ^ijp^qSq'/8	+%*[5G*N*NSZ^ijo^pSp'.w7	+%*[5G*N*NSZ^ijo^pSp(/8 !1[!@ZP[\lPmosEtEt"#34sNGImVY
 )T**y))		gq12C]]#3Q7F",''  	;A3?@	  C  	?	{"QCPQ	sB   CE &E 
E4 4E; 
E1E,,E14E8;
F FF c                   #    SXR                   S.nU R                  USU 3S9I Sh  vN n0 nU(       d  U$ UR                  S/ 5      nU(       d  U$ US   nUR                  S0 5      nUR                  S	5      S
:X  a  UR                  S5      (       a  US   US'   UR                  S/ 5      nU(       a  US   n	U	R                  S5      n
U
(       a  XS'   U	R                  SS5      US'   SU;  aD  U	R                  SS5      n[        R                  " SU5      nU(       a  UR                  S5      US'   UR                  SS5      nXS'   [        R                  " SUR                  SS5      5      nU(       a   [        UR                  S5      5      US'   S nUSS  H3  nUR                  S	5      S:X  d  M  U" U5      nUR                  U5        M5     U$  GN!    NH= f7f)uw  Fetch details for a specific transaction.

API response structure:
  sections[0]: header section  {"title": "You invested €726.48",
                                "action": {"payload": "<ISIN>", "type": "instrumentDetail"},
                                "data": [{"timestamp": "2026-02-10T13:06:39.808407Z",
                                          "status": "executed", "icon": "logos/<ISIN>/v2"}]}
  sections[1]: {"title": "Overview", "type": "table",
                "data": [{"title": "Shares", "detail": {"text": "5"}}, ...]}
  sections[2]: {"title": "Documents", ...}
  sections[3]: {"title": "", "type": "table", ...}
timelineDetailV2r  zTx r  Nsectionsr   r  r
  instrumentDetailr  r   r5   r:  r   r  iconlogos/([A-Z0-9]{12})r  rC  header_titlez[\d]+[.,][\d]+r  r|  
amount_eurc                 l   0 nU R                  S/ 5       H  n[        U[        5      (       d  M  UR                  SS5      R                  5       nUR                  S0 5      n[        U[        5      (       a  UR                  SS5      nO[        U[        5      (       a  UnOSnU(       d  M  XQU'   M     U$ )Nr5   rC  r  detailr   )rv   r  r  r  r  )sectionoutr  r   r  r  s         r    _get_table_textCTradeRepublicAPI.fetch_transaction_details.<locals>._get_table_texto
  s    CFB/!$--hhw+113(B/fd++ **VR0C,, CC3"H 0 Jr!   r  )	r   rU  rv   r  r  r  r  r  r1   )r	  transaction_idr  r5   r  r  
header_secr  header_datar  tsr  rc  rC  amount_matchr  r  
table_datas                     r    fetch_transaction_details*TradeRepublicAPI.fetch_transaction_details8
  s     .^N`N`a__WS8H3I_JJM88J+M a[
"-::f!33

98M8M#I.F6N nnVR0NE;'B&({#$yy26F8V#yy,II5t<%&WWQZF6N w+!&~yy!2EMM#s4KL',\-?-?-B'C|$
	" AB<Cwwv'),S1
j)  
  KJs.   &G#GEG#;G G#: G#G G#c                   #    [        S5        / nS n SU R                  S.nU(       a  X4S'   U R                  USS9I S h  vN nU(       d  OUR                  S/ 5      nU(       d  OU(       a  [        S[	        U5       S	35        U He  nUR                  S
5      nU(       d  M  [
        R                  " S5      I S h  vN   U R                  U5      I S h  vN n	UR                  U	5        Mg     UR                  U5        UR                  S0 5      R                  S5      nU(       d  OGM  [        U S5      (       d5  [        R                  " 5       U l        U R                  R                  S5        U R                  R                  SSS S9n
U
(       a  SU
 3OSn[        X5        [        S[	        U5       S35        U$  GN GN N7f)Nz&
[DOC] Fetching Transaction History...timelineTransactions)r
  r  afterzTransactions Pager  r_   z   extracting details for z	 items...r-  皙?cursorsr   
config.inir   r  r   tr_transactions_tr_transactionsri  z transactions saved to DB.)r3   r   rU  rv   rs   r   r  r  r1   rn  r^   rr  rs  r   r   r9   )r	  rp  all_transactionsafter_cursorr  r5   r_   rO  t_idrc  r.  r   s               r    fetch_historyTradeRepublicAPI.fetch_history
  s    785@R@RSG#/ 7JKKDHHWb)E23u:,iHI#(K&??40Dt%mmD111(,(F(Ft(L"L#**73 $) ##E*88Ir266w?L7 < tX&&'446T[[[l+.4H,1 (7H.c*+,,FGHE L 2"Ls=   >G
 GA G
%G
>G?G
GC+G
G
G
)ry  rx  r   r   rW  rp  r0  r1  rw  ro  rn  r  r/  ru  r   rg  rv  )r  )1dr   )NN)1y)rh   FF)rj  )r  r  r  r  r<  r  r  r  r  r  r  r  r  r  r  r   r   r(  r   r?  rU  r^  r}  ro  rp  rq  r  r  r  r   r!   r    rk  rk  d  s    #@)VDL9DL!
,	_7B
7-7d*X),\b1HL&\7r4~H
E
'RM^, r!   rk  r  c                  >  ^ [        5       m[        R                  " 5       n [        R                  " U 5        U4S jn U R	                  U" 5       5        U R                  5         g ! [
         a  n[        SU 35         S nAN.S nAff = f! U R                  5         f = f)Nc                    >#    [        S5         TR                  (       d  TR                  R                  TR                  5        TR                  R                  SSS S9n TR                  R                  SSS S9nU (       a  U Tl        UTl        O+[        S5        [        R                  " S5      I S h  vN   M  TR                  5       I S h  vN nU(       dg  TR                  (       d*  [        S	5        [        R                  " S
5      I S h  vN   O)[        S5        [        R                  " S5      I S h  vN   GM4  U(       a?   TR                  SS9I S h  vN   [        R                  " S5      I S h  vN   U(       a  M?  TR                  5       I S h  vN   [        R                  " S5      I S h  vN   GM   GN N N N Nm NQ! [         a  n[        SU 35         S nAMd  S nAff = f NX N<7f)Nz/[INFO] Starting Live Updates Loop (every 5s)...Tr   r   r   r  z&[WAIT] Live Loop: Waiting for login...r   z`[WAIT] Live Loop: Session cleared (3003 / expired). Please log in via the UI. Retrying in 15s...r  z7[WARN] Live Loop: Connection failed, retrying in 10s...rs  rg   z[ERROR] Live Loop Error: )r3   r   r   r   r   rv   r  r   r  r   r}  r2   r   )r  r.  r  r6   live_apis       r    
loop_logic$run_live_updates.<locals>.loop_logic
  s    ?@**%%h&:&:;!,,X|d,S!,,X~PT,U.3X+-2X*CD"==,,,  (//11Y ..}~"==,,,TU"==,,, #3343@@@ #==+++ 9 >>###==###S  - 2 - - A ,! 6qc:;
 $#s   B3G96G7G9GA G9G)G9;G	<G9G GG ;G<G  G9	G9G5G9:G7;G9G9G9	G9G G 
G2G-'G9-G22G97G9z[ERROR] Live Thread Died: )rk  r   r   r   r   r2   r3   r   )r   r  r6   r  s      @r    run_live_updatesr  
  s~    !H!!#D4 +$Z
- 	

  0*1#.//0 	

s)   A% %
B/B=B
 BB
 
Br  c                   ,    \ rS rSrS rS rS rS rSrg)CashAnalyzeri  c                 H   Xl         U(       a  [        R                  " U5      O[        R                  " 5       U l        SSSS.SSSS.SSSS.SSSS.SSSS.S	SSS./S
SSS.SSSS.SSSS.SSSS.SSSS.SSSS.SSSS./SSSS.SSSS.SSSS.SSSS./SSSS.SSSS.SSSS./S.U l        / U l        U R                  R                  5        H:  u  p#U H/  nU R
                  R                  US   R                  5       5        M1     M<     0 SS_S S!_S"S#_S$S%_S&S'_S(S)_S*S+_S,S-_S.S/_S0S1_S2S3_S4S5_S6S7_S8S9_S:S;_S<S=_S>S?_0 S@S?_SASB_SCSD_SESD_SFSG_SHSI_SJSK_SLS'_SMSN_SOSP_SQSR_SSST_SUSV_SWSX_SYSZ_S[S\_S]S^_E0 S_S`_SaSb_ScSd_SeSf_SgSh_SiSj_SkSl_SmSn_SoSp_SqSr_SsSt_SuSv_SwSx_SySx_SzS{_S|S}_S~S_E0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_E0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_E0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_E0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SGS _GSGS_GSGS_GSGS_EGSGSGS	GS
S3GS.EU l	        / GSQU l        g (  NSpotifyMusiqueGlobal)nom	categoriepayszApple MusicDeezerzYouTube MusiczAmazon MusicTidalNetflixu   VidéozDisney+zAmazon Prime Videoz	Apple TV+zHBO Maxz
Paramount+HuluUSAz
Google OneStockageDropboxzMicrosoft OneDriveiCloudzMicrosoft 365u   ProductivitézAdobe Creative Cloudz	Canva Pro)streaming_musiquestreaming_videocloud_stockageproductiviter  uberzuber.comnetflixznetflix.comspotifyzspotify.comapplez	apple.comamazonz
amazon.comgooglez
google.com	starbuckszstarbucks.com	mcdonaldszmcdonalds.comburger kingzburgerking.fr	deliveroozdeliveroo.co.ukubereatszubereats.comyoutubezyoutube.comdisneyzdisneyplus.comadobez	adobe.com	microsoftzmicrosoft.comgithubz
github.comchatgptz
openai.comopenaisteamzsteampowered.complaystationzplaystation.compsnxboxzxbox.comnintendoznintendo.comvintedz
vinted.comprimelinkedinzlinkedin.comslackz	slack.comzoomzzoom.usdropboxzdropbox.comcanvaz	canva.comfigmaz	figma.comnotionz	notion.sodeezerz
deezer.comdaznzdazn.comcanalzcanalplus.com	beinsportzbeinsports.comleclercze-leclerc.comintermarchezintermarche.com	carrefourzcarrefour.comauchanz	auchan.frlidlzlidl.fraldizaldi.frfranprixzfranprix.frmonoprixzmonoprix.frpicardz	picard.frbiocoopz
biocoop.frzsuper uzmagasins-u.comz	systeme ucasinozgroupe-casino.frnettoznetto.frzgrand fraiszgranfrais.comr~   ztotalenergies.frtotalenergiesshellz	shell.combpzbp.comessozesso.frengiez	engie.comedfzedf.frorangez	orange.frsfrzsfr.frbouygueszbouygues-telecom.frfreezfree.friliadziliad.frsncfzsncf.comratpzratp.fr	blablacarzblablacar.frairbnbz
airbnb.combookingzbooking.comexpediazexpedia.com	trainlinezthetrainline.comouigoz	ouigo.comthalysz
thalys.comeurostarzeurostar.comeasyjetzeasyjet.comryanairzryanair.com
air francezairfrance.fr	transaviaztransavia.comvoloteazvolotea.com	boulangerzboulanger.comfnaczfnac.comdartyz	darty.com	decathlonzdecathlon.frzarazzara.comh&mzhm.comuniqloz
uniqlo.comnikeznike.comadidasz
adidas.comzfoot lockerzfootlocker.frcourirz
courir.comkiabiz	kiabi.comz
la redoutezlaredoute.fr	cdiscountzcdiscount.comveepeez	veepee.frikeazikea.comleroyzleroymerlin.fr	castoramazcastorama.frbricomarchezbricomarche.com	bricoramazbricorama.frzbrico depotzbricodepot.frzmaisons du mondezmaisonsdumonde.combutzbut.frdoctolibzdoctolib.fralanzalan.comqontoz	qonto.comshinezshine.frrevolutzrevolut.comn26zn26.compaypalz
paypal.comlydiazlydia-app.comsumeriazsumeria.moneyfortuneozfortuneo.fr
boursoramazboursorama.comzcredit agricolezcredit-agricole.frsocietegeneralezsocietegenerale.frbnpzbnpparibas.frlclzlcl.frdominosz
dominos.frz	pizza hutzpizzahut.frsubwayz
subway.comzquick.frzkfc.frzfiveguys.frzjust-eat.fr)quickkfcz	five guyszjust eat	uber eats)7r  r  r  r  zprime videozprime memberr  icloudz
google onezgoogle storager  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  zfree mobilezfree telecomr5  r4  fitbitstravazwiftgymfitnesszle monde	mediapartnytwsjftz	les echoszcanal+r  z	rmc sportr  r  tidalaudibleovhawsherokudigitaloceanhetzner)
transactionsr  r  r  services_statiquessubscription_keywordsr_   r  r=   logo_map)r	  rX  rv  r_   r  s        r    r<  CashAnalyzer.__init__  s   (0<",,|,",,. "	8L%IxP y(K'iR&YQiJ" "(K!(K,8XV#(HM!(K$8XNXuE  %:xP!
HM,:xX z8L	 (oxX._V^_#/8T1#
@ &("11779JC**11$u+2C2C2EF  :
6
J6
 )=6
:C]6
 [6
 #+L6
 ;CL6
 	6
 +6	6
 IVWf	6

 *6

 -76

 IRS`6
 &6
 )06
 ?J?6
 l6
 %.|6
 >F|6
 '6
 *78I6
 LQRc6
 J6
 !+N6
 =El6
 \6
 $.~6
 @G6
 I6
  )-6
 :A+6
 [6
 #+K6
 :B<6
 J6
 !(6
 ;FGW6
 6
 )67H6
  !6
  +3K!6
" I#6
"  &y#6
" 3=m#6
$ %6
$ (0%6
$ ?H%6
& ''6
& *56F'6
( ()6
( +2:)6
* ?+6
. '/6
. *9:L/6
0 [16
0 #'16
0 39)16
2 [36
2 #(36
4 k56
4 $)(56
6 -76
6 06y76
6 CJ:76
: J;6
: !'	;6
: 4?;6
< l=6
< %.}=6
< ?H=6
> +?6
> .5k?6
> DL\?6
@ A6
@ )2=A6
@ CL]A6
B .C6
B +6C6
B IRS`C6
F G6
F +1*G6
F ?F{G6
H I6
H *0I6
H >CHI6
J lK6
J %+JK6
J 9A,K6
L ?M6
L -5lM6
L EL[M6
N .O6
N +6O6
N IQR]O6
R JS6
R !()9S6
R <GS6
T ,U6
T /:>U6
T LYZiU6
V  4W6
V 7<XW6
Z [6
Z (.z[6
Z <CK[6
\ Z]6
\ "+M]6
\ <A)]6
^ l_6
^ %,__6
^ ?H_6
` a6
` (45Ea6
` HYZna6
b 3c6
b 6;Oc6
b NST\c6
f |g6
f &1-g6
f BJ<g6
h  }%Nk6
r	&
"r!   c                     UR                  5       n[        U R                  [        SS9 H  nX2;   d  M
  U R                  U   s  $    g)z]Match merchant name against logo_map using raw title too (handles E.LECLERC, LIDL 0123, etc.)Tr   reverseN)r=   sortedr[  rs   )r	  merchant_namemerchant_lowerr   s       r    _get_domainCashAnalyzer._get_domainq  sB    &,,.$--S$?C$}}S)) @ r!   c                     U(       d  g[        U5      R                  5       n[        U R                  [        SS9 H  nX2;   d  M
  U R                  U   s  $    g)zAMatch against raw transaction title directly for better coverage.NTr^  )r  r=   r`  r[  rs   )r	  	raw_title	raw_lowerr   s       r    _get_domain_from_raw!CashAnalyzer._get_domain_from_rawz  sL    	N((*	$--S$?C}}S)) @ r!   c                   ^ ^4^5^6^7^8 T R                   R                  (       a  / / / 0 S.$ T R                   R                  5       nSUR                  ;   a   [        R
                  " US   5      US'   O1SUR                  ;   a  [        R
                  " US   5      US'   OSS0$ UR                  S5      nS nUR                  US	S
9US'   SUR                  ;   a  SOSUR                  ;   a  SOSm7SUR                  ;   a  SOSUR                  ;   a  SOS m8U7U 4S jnUR                  US	S
9US'   / SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ SQS.m4T R                  R                  5        HC  u  pEU H8  nUS   nUT4;  a  / T4U'   T4U   R                  US    R                  5       5        M:     ME     U4U7U84S! jm5UR                  U54S" jS	S
9US#S$/'   / nXS#   S%:H     R                  5       n	U	R                  S5       H  u  pU
R                  5       m6[        U64S& jT R                   5       5      (       d  M;  UR                  S5      R                  S'   nT R!                  U
5      nU(       a  S(U S)3OS*nUR                  U
[#        [%        US   5      5      S+US   R'                  S,5      US   [)        S-S.9-   R'                  S,5      S/UUS0.5        M     U	S   R*                  R-                  5       U	S1'   U	S   R/                  S25      U	S3'   U	R                  SS3/5       GH  u  u  pn[1        U5      S4:  a  M  UR                  S5      nUS   R2                  n/ n[5        S	[1        U5      5       H:  nUU   UUS	-
     -
  [6        R8                  " S	S55      -  nUR                  U5        M<     U(       d  M  [6        R:                  " U5      n[6        R<                  " U5      nS nS6Us=::  a  S7::  a  O  O	US8:  a  S9nOS:Us=::  a  S;::  a  O  OUS<:  a  S=nU(       d  GM  [        R
                  " US'   5      n[?        S2[A        S>[C        S>US8-  -
  5      5      5      n[D        RF                  " 5       U-
  RH                  nUS9:H  =(       a    US?:  =(       d    US=:H  =(       a    US;:  nU(       d  GM  T R!                  U
5      nU(       a  S(U S)3OS*nUR                  U
[#        [%        US   R;                  5       5      5      UUR'                  S,5      U[)        US.9-   R'                  S,5      UUUS0.5        GM     0 nU H$  nUS   nUU;  d  US@   UU   S@   :  d  M  UUU'   M&     [K        [M        UR3                  5       5      SA SB9nUS   R*                  R'                  SC5      USD'   / nUR                  SD5       H  u  nnXS#   SE:H     S   RO                  5       n XS#   S%:H     S   RO                  5       n!XS#   SF:H  US#   SG:H  -     S   RO                  5       n"U U!-   [%        U"5      -   n#UR                  U[/        U S45      [/        [%        U!5      S45      [/        [%        U"5      S45      [/        U U!-   U"-   S45      [/        U#S45      SH.5        M     / n$XS#   S%:H     RQ                  S>5      n%U%R                  (       d  U%R                  S$5      S   RO                  5       R%                  5       R                  SISJ9n&U&RO                  5       n'U&R                  5        H=  u  n(n)U$R                  U([/        U)S45      U'S2:  a  [/        U)U'-  S>-  S	5      OS2SK.5        M?     / n*UR                  SSISJ9RS                  5        GH  u  n+n,S*n-[U        U,RW                  SLS*5      5      n.[X        RZ                  " SMU.5      n/U/(       a  U/R]                  S	5      n0SNU0 SO3n-OT[U        U,RW                  T7S*5      5      n1T R_                  U15      =(       d    T R!                  U,S   5      nU(       a  S(U S)3n-U*R                  U,S   R'                  S,5      U,S   [/        U,S   S45      U,S$   U-U/(       a  U/R]                  S	5      OS*SP.5        GM     [O        U V2s/ s H  n2U2SQ   S9:X  d  M  [%        U2SR   5      PM     sn25      [O        U V2s/ s H  n2U2SQ   S=:X  d  M  [%        U2SR   5      PM     sn25      SS-  -   U(       a  US'   S%   OS2U(       a  US'   SG   SS-  OS2ST.n3UUU$U*U3SU.$ !   [        R
                  " US   SS9US'    GN= fs  sn2f s  sn2f )VN)subscriptions	cash_flowrX  statsr:  rN  ms)unitr   z"Date field missing in transactionsc                     SU ;   ab  [        U S   [        [        45      (       a  [        U S   5      $ [        U S   [        5      (       a  [        U S   R	                  SS5      5      $ g)Nr|  rR  r   rz  )r  r  r  r  rv   )r  s    r    
get_amount(CashAnalyzer.analyze.<locals>.get_amount  s]    3c(mc5\::5XCW<Wc(mT225XARARSZ\]A^;_4_r!   r  axisr  rC  rA   descriptionsubTitlesubtitlec                   > [        U R                  TS5      5      R                  5       n[        R                  " SSU5      n[        R                  " SSU5      nUR                  5       n/ SQnU Vs/ s H  oDU;  d  M
  [        U5      S:  d  M  UPM     nnU(       d  gSR                  U5      nTR                   H  nXe;   d  M
  UR                  5       s  $    SR                  S US S	  5       5      $ s  snf )
Nr  z[\d\-.,]r   z\s[a-z]{2,3}$)paymentcartecbvirprlvpaiementfacbillsepadebitrN  rR  arlr  Inconnuc              3   @   #    U  H  oR                  5       v   M     g 7fr   )
capitalize)r   r  s     r    r   DCashAnalyzer.analyze.<locals>.clean_merchant_name.<locals>.<genexpr>  s     >IqLLNNIs   r  )
r  rv   r=   r  subr  rs   joinr[  r  )	r  r   wordsjunkr  name_strr   raw_colr	  s	          r    clean_merchant_name1CashAnalyzer.analyze.<locals>.clean_merchant_name  s    CGGGR()//1A{C+A'Q/AGGIE AD %F1$Q3q6A:QEFxxH}}?3>>+;$; % 88>E"1I>>> Gs   3	C7 C7C7merchant)r  r"  r#  r!  r%  r&  r'  r(  r)  r  r:  zapple store)r  r  r  r  r  r   r  r  r  marketzsuper U)r  r  r  r  r~   r  r	  r
  r  scooterlimebirdbolt)r  r  r  r  rF  
restaurantbistrocafebarsushipizza)cinemaugcgaumontr  r  r  r  )r  r  r  hotelsr  r  r  r  )
r  r  r  r  r  r  internetr(  waterelectric)r  r  r  r  r  rS  rT  r  )	pharmacier4  r5  mutuelledoctordentist)r.  zleroy merlinr0  habitatmaison)rX  frais
cotisationr6  r7  r8  r9  r;  )Shopping	Groceries	TransportzFood & DrinkEntertainmentTravel	UtilitiesTechHealthHomeFinancer  r  c                 ~  >^^^ [        U R                  SS5      5      R                  5       nUS;   a  g[        U R                  T
S5      5      R                  5       mT(       a)  [        U R                  TS5      5      R                  5       OSm/ SQn/ SQn[        U4S jU 5       5      (       d4  [        U4S jU 5       5      (       d  [        U4S	 jU 5       5      (       a  gU S
   S:  a  gU S   R                  5       mT	R	                  5        H&  u  pE[        UU4S jU 5       5      (       d  M"  SU4s  $    g)N	eventTyper  )r  savings_plan)savingsu   Épargne)z(adr)z inc.z corp.z ag z se z plc nvgmbhisharesvanguard	xtrackersamundispdrlyxoretf
wisdomtree)	sparplansavings planorderkaufbuyinvestachattitresouscriptionc              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   )r   r   nms     r    r   =CashAnalyzer.analyze.<locals>.classify_row.<locals>.<genexpr>  s     /Jq7J   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r   r   r  s     r    r   r    s     6TACxr  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r  s     r    r   r    s     [ynxijad\dnxr  r  r   )incomeRevenusr  c              3   D   >#    U  H  oT;   =(       d    UT;   v   M     g 7fr   r   )r   rc   m_lowerr  s     r    r   r    s     A1G|.qBw.s    expense)r  Autre)r  rv   r=   anyr_   )r  evt
invest_ind
invest_actrv  keywordsr  r  r  category_rulesr  sub_cols         @@@r    classify_row*CashAnalyzer.analyze.<locals>.classify_row  s   cggk2./557C//8MSWWWb)*002B7>#cgggr*+113BC qJyJ/J///36T6T3T3TX[[ynx[yXyXy,5zQ':*o++-G!/!5!5!7AAAA$c>) "8 &r!   c                 <   > [         R                  " T" U 5      5      $ r   )r  Series)r   r  s    r    r  &CashAnalyzer.analyze.<locals>.<lambda>  s    RYY|A5Or!   rv  r  r  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   )r   rc   r  s     r    r   'CashAnalyzer.analyze.<locals>.<genexpr>  s     D)CA<)Cr  z*https://www.google.com/s2/favicons?domain=z&sz=128r  zMensuel (Est.)%Y-%m-%dr   r  Z   )rA   r|  	frequencylast_paymentnext_payment
confidencerw  domain	date_normr   amount_approxr  D   #   rg   Monthlyi^  i|  r   Annuelr*  -   r  c                     U S   $ )Nr|  r   r   s    r    r  r  2  s    8r!   r   z%Y-%m	month_strr  
investmentr  )monthr  r  r  netr  F	ascending)r  r|  
percentager  r  z+https://assets.traderepublic.com/img/logos/z/v2.png)rN  r  r|  r  rw  r   r  r|  rA  )total_subscriptions_monthlymonthly_burn_rateprojected_annual_savings)recurring_subscriptionsrl  spending_breakdownrX  rD  )0r  r  r  r  r  to_datetimesort_valuesapplyrY  r_   r  r=   groupbyr  rZ  ilocrc  r  absstrftimer
   r  	normalizeroundrs   r@  r  nptimedelta64meanstdmaxminr  r	   r  r  r`  r  r  tailiterrowsr  rv   r  r  r  rh  )9r	  r  rq  r  svc_typer_   r  cat_namerk  expensesr  r  last_rowr  logo_urlr|  dates	intervalsr  diffavg_intervalstd_devfreqlast_tx_dater  days_since_last	is_activeunique_subsr  r   rl  rA   incexpr  savings_val	breakdownrecent_expensesby_catr~   rv  r  recent_txnsr   r  rw  
icon_field
isin_matchr   rf  r   rm  r  r  r  r  r  s9   `                                                   @@@@@r    analyzeCashAnalyzer.analyze  s	   77==%'b"WYZZWW\\^ "**$H^^B{O<6
 rzz!..F4RZBCC^^F#	
 HHZaH05	 %

2'&BJJBV\i *bjj 8*JZ\ZdZdLdjjn	?  "5A>: O S O Yeqy_XNc
  $66<<>OH,>1/1N8,x(//U0A0A0CD	   ?	&, #%((+OVW("XE: i9,-224  (//
;OHnn&GD)C)CDDD ,,V499"=))(3[aGxwWgi$$$#C$89!1$,V$4$=$=j$I%-f%5	r8J%J$T$TU_$`"$$$	& 	  <( !) 0 3 3 = = ?$,UO$9$9!$<!)1)9)9::W)X%X5zA~x%%f-E&M((EI1c%j)a51:-31GG  & * h779-LffY'G D\'R'GaK	++"Xdt!~~eBi8 CS!1D-E$FG
#+<<>L#@"F"F!Y.G?R3GxTU]M]Mwbqtwbw	9!--h7F_e!KF8SZ[kmH!(( ("'E%L,=,=,?(@"A%)(4(=(=j(I)5	|8T)T(^(^_i(j&0 ("(	* 	A *YX  Cf+C+%\):[=Ml=[)[#&C  ! tK$6$6$89?TU V*--009;	::k2KD%u13E:>>@Cu24U;??ACu5%,):STUV[\``bC 9C0KQ- S1-#CHa0S3Y_a0 a0  3& 	i946;;C@$$$,,Z8?CCEIIKWWbgWhFJJLE"LLNS   ##Cm?Dqy%UC";a"  + nnVun=FFHFAsDSWWVR01J#:JGJ!''*DTF'R   45	229=bAQAQRUV`RaAbGxwWDF,,Z8
OE
A.
O/9
((+r   I2 ,/-/w-Q[\]h[imv[v0@AhK0@-/w+x|  \i  AH  \i  WX  mn  oz  m{  G  mG  BR  BE  FG  HP  FQ  BR  \i  AH  }I  JL  }L  ,M=F2y!9AKT2y)AB)FZ[
 (5""+'
 	
QH^^B{O$G6
D 0x  AHs$   d$ e'ee
e
$e)r  r[  rY  rZ  rX  N)	r  r  r  r  r<  rc  rh  r/  r  r   r!   r    r  r    s    l
\y
r!   r  z/api/cash/analysisGET)methodsc                     [         R                  R                  S5      n U (       d8   [        R                  " 5       nUR                  S5        UR                  SSS S9n U (       a  SU  3OSn[        U5      nU(       d  U (       a  [        S5      nU(       d  / n[        U5      nUR                  5       n[        SUS	.5      $ !    Nh= f)
Nr  r  r   r  r   r  r  r   r   r5   )
r   r   rv   rr  rs  r   r/   r  r/  r   )r.  r   r   rX  analyzerr  s         r    get_cash_analysisr6    s     OO/E 
"//1V[[&ZZ.4ZHU ).UG
$3DC #3'L E'(9:L)HFi899! 
s   7C Cz"/api/institutional/cot/<commodity>c                 "    [        [        R                  R                  SS5      5      n[	        5       nUR                  X5      n[        SUR                  SS9S.5      $ ! [         a#  n[        S[        U5      S.5      S	4s S nA$ S nAff = f)
NrC  r   r   r  r  r4  r   r   rj  r7  )
r  r   argsrv   r  r  r   r  r2   r  )r  rC  r  r  r6   s        r    get_cot_apir:    s    DGLL$$Wb12.0&&y8)RZZyZ5QRSS D'c!f=>CCDs   AA! !
B+B	B	Bz!/api/institutional/stock/<ticker>c                     [        5       nUR                  U 5      nSU;   a7  [        US   [        R                  5      (       a  US   R                  SS9US'   SU;   a7  [        US   [        R                  5      (       a  US   R                  SS9US'   [        SUS.5      $ ! [         a#  n[        S[        U5      S.5      S	4s S nA$ S nAff = f)
Nr  r  r  r  r   r4  r   r8  r7  )	r  r,  r  r  r  r  r   r2   r  )rw   r  r  r6   s       r    get_inst_stock_apir<    s    	D.0008g%*W_5Mr||*\*\'.'?'G'Gy'G'YGO$W$GN4KR\\)Z)Z&-n&=&E&EY&E&WGN#)W=>> D'c!f=>CCDs   B"B% %
C/CCCz$/api/institutional/13f/<institution>c                      [        5       nUR                  U 5      nU(       d  [        SSS.5      S4$ UR                  U5      n[        SUR	                  SS9S.5      $ ! [
         a#  n[        S[        U5      S.5      S	4s S nA$ S nAff = f)
Nr   zInstitution not foundr8    r   r  r  r4  r7  )r  r  r   r  r  r2   r  )institutionr  r  r  r6   s        r    get_13f_apir@    s    D.0%%k2w;RSTVYYY,,S1)RZZyZ5QRSS D'c!f=>CCDs"   1A  +A   
B*BBBz/api/assets/enriched/<ticker>c                 ,2  ^^ U R                  5       R                  5       n U 0 / 0 0 0 / 0 0 0 S.
n [        S5      =(       d    0 nUR                  S/ 5      UR                  S/ 5      -   n/ nU R                  5       nU H  nUR                  SS5       UR                  SS5       UR                  SS5       UR                  S	S5       3R                  5       nXW;   d  Mb  UR                  S
S5      =(       d    SnUR                  SS5      =(       d    Sn	UR	                  XR                  5       UR                  S5      =(       d    UR                  SS5      UR                  SS5      S.5        M     U V
s/ s H  oS   S:  d  M  U
PM     nn
U V
s/ s H  oS   S:  d  M  U
S   PM     nn
[        S U 5       5      n[        S U 5       5      nU(       a!  [        [        U5      [        U5      -  S5      OSn[        U5      [        U5      UUUUSS X:  a  SOX:  a  SOSS.US'    [        R                  " U 5      nSn[        R                  " 5       R                  n[        R                   " U U S3U S3S S!S"9n[#        UR$                  [&        R(                  5      (       a	  US#   U    nO(S#UR$                  ;   a  US#   OUR*                  SS2S4   nUR-                  5       n/ n[/        UUS-   5       H  nUUR0                  R                  U:H     n[        U5      S$:  a  M0  [3        UR*                  S   5      n[3        UR*                  S%   5      n[        UU-
  U-  S&-  S$5      nUR	                  UU[        US$5      [        US$5      S'.5        M     UUS('    [        R                   " U S*S+S!S,9n[#        UR$                  [&        R(                  5      (       a	  US#   U    mO(S#UR$                  ;   a  US#   OUR*                  SS2S4   mTR-                  5       mU4S- jnU" S.5      nU" S/5      nU" S05      n[        T5      S1:  a  U" S15      Og[        T5      S:  aW  [        [3        TR*                  S%   5      [3        TR*                  S   5      -
  [3        TR*                  S   5      -  S&-  S$5      OSn [        R                  " U 5      R4                  n!U!R                  S25      =(       d    S3R                  5       n"Sn#Sn$ [6        R8                  R;                  5       n%U% HX  mTR<                  (       d  M  [?        U4S4 jU"RA                  5        5       5      (       d  M@  TRB                  n#TR<                  n$  O    UUUU U"RE                  5       U#U$Ub  [        UU#=(       d    S-
  S$5      OSS6.US7'    [        R                  " U 5      n'Sn( U'RF                  n(U(b  U(RH                  (       a   U'RJ                  n(U(Gb6  U(RH                  (       Gd$  0 n)S9S:S;S<S=S>S?.n*U*RM                  5        H  u  n+n,U(R0                   H  n-U+R                  5       [O        U-5      R                  5       ;   d  M0  0 U)U,'   U(R$                   Hv  n.U(RP                  U-U.4   n/[&        RR                  " U/5      (       d  M1  [U        U.S@5      (       a  [O        U.R                  5      O[O        U.5      SSA n0[W        U/5      U)U,   U0'   Mx       M     M     [Y        [[        SB U)R]                  5        5       5      SCSD9SS n1U)U1SE.USF'    [        R                  " U 5      n2Sn3 U2R^                  n3U3b"  [U        U3SH5      (       a  U3RH                  (       a   U2R`                  n3/ n4U3Gb  U3RH                  (       Gd  SIu  n5n6n7U3R0                   HB  n8[O        U85      R                  5       n9SJU9;   a  U8n5SKU9;   a  U8n6SLU9;   d  SMU9;   d  SNU9;   d  M@  U8n7MD     Sn:U3R0                   H$  n8SO[O        U85      R                  5       ;   d  M"  U8n:M&     [c        U3R$                  5      SSP n;Sn<[e        U;5       GH  n.[U        U.SQ5      (       a  U.Rg                  SR5      O[O        U.5      SS n= U.Rh                  S-
  SS-  S-   n>STU> SUU.R                   3n=U5bD  [&        RR                  " U3RP                  U5U.4   5      (       a  [3        U3RP                  U5U.4   5      OSn?U6bD  [&        RR                  " U3RP                  U6U.4   5      (       a  [3        U3RP                  U6U.4   5      OSn@U7bD  [&        RR                  " U3RP                  U7U.4   5      (       a  [3        U3RP                  U7U.4   5      OSnAU:bD  [&        RR                  " U3RP                  U:U.4   5      (       a  [3        U3RP                  U:U.4   5      OSnBU?b+  U<(       a$  U<S:w  a  [        U?U<-
  [k        U<5      -  S&-  S5      OSnCWBb  U?(       a  [        WBU?-  S&-  S5      OWAb  U?(       a  [        WAU?-  S&-  S5      OSnDU4R	                  U=U?b  [W        U?5      OSW@b  [W        W@5      OSWDWCSV.5        U?n<GM"     SnE U2Rl                  nFUFGba  [#        WF[n        5      (       a  WFR                  SW5      =(       d    WFR                  SX5      nGUG(       a0  SY[#        WG[b        5      (       a  [O        WGS   5      O
[O        WG5      0nEWFR                  SZ5      =(       d    WFR                  S[5      nHWFR                  S\5      =(       d    WFR                  S]5      nIWH(       a-  0 WE=(       d    0 E[W        WH5      WI(       a  [W        WI5      OSS^.EnEOe[U        WFS_5      (       aT  WFRq                  5       nJ[c        UJRM                  5       5      SS`  VKVLs0 s H  u  nKnL[O        UK5      [O        UL5      _M     nEnKnL[c        [e        U45      5      WESb.USc'    [        R                  " U 5      nN/ nO UNRr                  nPUPGbG  WPRH                  (       Gd5  WPRu                  5        GH   u  nQnRURR                  Se5      nSURR                  Sf5      nTURR                  Sg5      =(       d    WRR                  Sh5      nU[U        WRSi5      (       a(  [O        WRR                  SjURRv                  5      5      SSk OSnVWSc  M  WUb0  [k        [3        WU5      5      Sk:  a  [        [3        WU5      S&-  S5      OWUb  [        [3        WU5      S5      OSnWWOR	                  WV[        [3        WS5      S$5      WTb  [        [3        WT5      S$5      OSWWSl.5        GM#     WO(       d   WNRx                  nXUXbv  WXRH                  (       de  WXRu                  5        HQ  u  nnRWOR	                  [O        U5      [        [3        URR                  SmS5      =(       d    S5      S$5      SSSl.5        MS     WOSSP USn'    SpSqSrSsStSuSv.nY0 nZUYRM                  5        GH5  u  n+n[ [        R                   " U[S S+S!S,9n\[#        U\R$                  [&        R(                  5      (       a	  W\S#   W[   n\O(S#W\R$                  ;   a  W\S#   OW\R*                  SS2S4   n\W\R-                  5       n\[        U\5      S:  a  M  [        [3        W\R*                  S%   5      [3        U\R*                  S   5      -
  [3        U\R*                  S   5      -  S&-  S$5      n][        R                   " U S S+S!S,9n^[#        U^R$                  [&        R(                  5      (       a	  W^S#   U    n_O(S#W^R$                  ;   a  W^S#   OW^R*                  SS2S4   n_W_R-                  5       n_Sn`[        U_5      S:  a  [        W\5      S:  az  [&        Rz                  " W_W\/SSw9R-                  5       na[        Ua5      SA:  aF  [        [3        WaR*                  SS2S4   R}                  UaR*                  SS2S4   5      5      S$5      n`W][        [3        W\R*                  S%   5      S$5      W`Sx.WZU+'   GM8     WZUSy'    [        R                  " U 5      nbUbR4                  ncUcR                  S{5      ndUcR                  S|5      =(       d    WcR                  S}5      neWcR                  S~5      nfUcR                  S5      ngUcR                  S5      nhWd(       a  [W        Wd5      OSWf(       a  [        [3        Wf5      S$5      OSWg(       a'  [3        Wg5      S::  a  [        [3        Wg5      S&-  S$5      OWg(       a  [        [3        Wg5      S$5      OSWh(       a  [W        Wh5      OSWe(       a  [W        We5      OSWd(       a"  Wh(       a  WhS:w  a  [        WdWh-
  Uh-  S&-  S5      OSS.US'    [        R                  " U 5      niUiR~                  njUj(       GaY  WjS   nkWiR                  Uk5      nlUlR                  nmUlR                  nnSUmR$                  ;   a  [W        WmS   R                  5       5      OSnoSWnR$                  ;   a  [W        WnS   R                  5       5      OSnpSWmR$                  ;   a  [W        WmS   R                  5       5      OSnqSWnR$                  ;   a  [W        WnS   R                  5       5      OSnrWo(       a  [        WpWo-  S$5      OSnsWq(       a  [        WrWq-  S$5      OSntSS jnuWkWoWpWqWrWsUtUu" Wm5      Uu" Wn5      Ut=(       d    SS:  a  SOWt=(       d    SS:  a  SOSS.
US'    [        R                   " U SS!S9nv[#        UvR$                  [&        R(                  5      (       a
   WvS#   U    nwO(S#WvR$                  ;   a  WvS#   OWvR*                  SS2S4   nwWwR                  S5      R                  5       R-                  5       nwUwR                  5       R-                  5       S&-  nx/ SQny/ nz[/        SS5       H  n{WxUxR0                  Rh                  U{:H     n|U|R\                   VLs/ s H+  nL[&        R                  " UL5      (       a  M   [3        WL5      PM-     n}nLU}(       a!  [        [        W}5      [        U}5      -  S$5      OSn~[        S W} 5       5      nWzR	                  WyW{S-
     U{U~U[        U}5      S.5        M     [        R                  " 5       R                  n/ n[/        US-
  US-   5       H  nWxUxR0                  R                  U:H     nURH                  (       a  M2  0 nURM                  5        HN  u  nn[&        R                  " U5      (       a  M#  [        [3        W5      S5      W[O        WRh                  5      '   MP     W(       d  M  WR	                  UWS.5        M     WR                  5         WzUS.US'   [        [        U5      5      $ s  sn
f s  sn
f ! [         a  n[        SU  SU 35         SnAGNSnAff = f!   UR*                  SS2S4   n GN= f! [         a  n[        S)U  SU 35         SnAGNSnAff = f!   UR*                  SS2S4   m GN= f! [         a  n&[        S5U& 35         Sn&A&GN2Sn&A&ff = f! [         a  n[        S8U  SU 35         SnAGN$SnAff = f!    GN= f!   Sn( GN= f! [         a  n[        SGU  SU 35         SnAGNSnAff = f! [         a     GNf = f! [         a    Sn3 GNf = f! [         a     GNf = fs  snLnKf ! [         a  nM[        SaUM 35         SnMAMGNSnMAMff = f! [         a  n[        SdU  SU 35         SnAGNSnAff = f! [         a     G
N7f = f! [         a     G	Nf = f! [         a  n[        SoU  SU 35         SnAG	NSnAff = f!   W\R*                  SS2S4   n\ G	Nc= f!   W^R*                  SS2S4   n_ GN= f! [         a     G
M  f = f! [         a  n[        SzU  SU 35         SnAGNSnAff = f! [         a  n[        SU  SU 35         SnAGNSnAff = f! [         a  n[        SU  SU 35         SnAGN[SnAff = f! [         a    WvR*                  SS2S4   nw GNf = fs  snLf ! [         a  n[        SU  SU 35         SnAGNSnAff = f)uf  
Endpoint unique qui renvoie pour un ticker :
  - news_sentiment  : score agrégé + points de vigilance depuis bloomberg_rss
  - annual_returns  : performance annuelle (calendrier) depuis 2019
  - momentum        : perf 1M/3M/6M/1Y + comparaison sectorielle (SectorTrend)
  - financials      : Revenus, Coût des ventes, Résultat Net (annuel via yfinance)
)
rw   news_sentimentannual_returnsmomentum
financialsquarterly_resultseps_surprisemacro_correlationshort_interestoptions_flowbloomberg_rssr_   news_segmentsrC  r  rt  rD  ru  rn  r   ro  rj  rs  )criticalityrF  rC  	reasoningrM  r  c              3   :   #    U  H  oS    S;   d  M  Sv   M     g7frF  )positivebullishr  Nr   r  s     r    r   &get_assets_enriched.<locals>.<genexpr>       W7an@V.V7   	c              3   :   #    U  H  oS    S;   d  M  Sv   M     g7f)rF  )negativebearishr  Nr   r  s     r    r   rS    rT  rU  r  Nrg   rR  rX  )total_mentionsvigilance_countavg_criticalitypositive_countnegative_countvigilance_itemssentiment_biasrB  z[ENRICHED] Sentiment error for rm   i  z-01-01z-12-311moF)r  endintervalprogressCloser  r  r*  )yearperfr   r   rC  z$[ENRICHED] Annual returns error for r  r  )periodrb  rc  c                    > [        T5      U S-   :  a  g [        TR                  U S-   *    5      n[        TR                  S   5      nU(       a  [        X!-
  U-  S-  S5      $ S $ )Nr  r  r*  r  )rs   r  r
  r  )n_daysoldr  closess      r    get_perf%get_assets_enriched.<locals>.get_perf"  s`    6{VaZ'fqjM23CB(C8;5#)s*S0!4EEr!      ?   ~      r`   rh   c              3   \   >#    U  H!  oTR                   R                  5       ;   v   M#     g 7fr   )r`  r=   )r   wordsts     r    r   rS  7  s#     )jUiT"..2F2F2H*HUis   ),z[ENRICHED] Sector DB error: )1m3m6mr  r`   sector_monthlyr`  vs_sector_1mrD  z[ENRICHED] Momentum error for revenuecogsgross_profitopex
net_incomeebitda)zTotal RevenuezCost Of RevenuezGross ProfitzOperating Expensez
Net IncomeEBITDAre  r~  c              3   R   #    U  H  oR                  5         H  o"v   M     M     g 7fr   )r  )r   r  yrs      r    r   rS  p  s     L=a668Rr8r=s   %'T)r_  )r  yearsrE  z [ENRICHED] Financials error for r  )NNNtotal revenue
net incomezoperating incomezoperating expenseebitzgross profitrB  r  z%YQr}  Qr   )quarterrz  r~  	op_margin
rev_growthEarnings DateearningsDateearnings_datezRevenue LowrevenueEstimateLowzRevenue HighrevenueEstimateHigh)rev_est_lowrev_est_highr     z[ENRICHED] Calendar error: )quartersguidancerF  z'[ENRICHED] Quarterly results error for 	epsActualepsEstimateepsSurprisesurprisePercentrA   r  r   )r  actualestimatesurprise_pctEarningsrG  z"[ENRICHED] EPS surprise error for ^VIX^TNXzDX-Y.NYBrR   GC=FCL=F)VIXUS10YDXYSP500Oru   Pétrolers  )perf_1mcurrentcorrelationrH  z'[ENRICHED] Macro correlation error for sharesShortfloatSharessharesFloat
shortRatioshortPercentOfFloatsharesShortPriorMonth)shares_shortshort_ratioshort_pct_floatshares_short_prevfloat_shares
change_pctrI  z$[ENRICHED] Short interest error for openInterestvolumec                    U R                   (       d  SU R                  ;  a  / $ U R                  US5      nUR                  5        VVs/ s H  u  p4[	        [        US   5      S5      [        US   5      [        UR                  SS5      =(       d    S5      [	        [        UR                  SS5      =(       d    S5      S-  S5      S	.PM     snn$ s  snnf )
Nr  striker  r  r   impliedVolatilityr*  r  )r  oivoliv)r  r  nlargestr  r  r  r  rv   )r  ntopr   rO  s        r    top_strikes(get_assets_enriched.<locals>.top_strikes5  s    88~RZZ?kk!^4 gjfrfrftv gu^b^_ $)q{);Q#?"1^#45 #AEE(A$6$;! <$U1551Da+H+MA%NQT%TVWXZ guv v vs   	BC皙?333333?neutre)
expirycall_oiput_oicall_volput_volpc_ratio_oipc_ratio_vol	top_callstop_putsbiasrJ  z"[ENRICHED] Options flow error for z
2015-01-01)r  rc  ME)Janu   FévMarAvrMaiJunJulu   AoûSepOctNovu   Déc   rz  c              3   4   #    U  H  oS :  d  M
  Sv   M     g7f)r   r  Nr   )r   rd   s     r    r   rS  a  s     5A1uaas   		)r  	month_numavg_pctpositive_yearstotal_yearsrm  )re  months)monthly_avgsyearly_gridr  z![ENRICHED] Seasonality error for )r}  )Jr'  r  r/   rv   r  r=   r  r  rs   r2   r3   rp   rq   r	   r  re  downloadr  r  r  
MultiIndexr
  dropnar  indexr  rr   r_  r   r   r`  r  r  ra  rC  income_stmtr  rE  r_   r  locnotnar^   r  r`  r  r@  quarterly_income_stmtquarterly_financialsr  reversedr  r  r  calendarr  r  earnings_historyr  rA   r  concatcorrr  option_chaincallsputsresampler  r*  isnar_  r   clean_for_json)rw   r  bloomberg_data	all_itemsrelatedticker_upperr  r   csslr  r^  scores	positives	negatives	avg_scorer6   rx   
start_yearcurrent_yearhistannualr  yr_dataopen_pclose_prf  	perf_histrl  r  perf_3mperf_6mperf_1yt_infostock_sectorrx  sector_name_matchedtrendsdb_et_finfinr  wantedr   r   row_namer  r  yr_strr  t_qqfinr  rev_rowni_rowoi_rowrnrnsgp_rowr  prev_revq_labelq_numrO  nir  gpr  r  r  caledrev_lowrev_highr  rc   rd   gc_et_epseps_listehr   r  r  r  surpriser  surp_pctearnmacro_symbols
macro_datasymr)  pct_1mstock_hstock_sr  alignedt_sirr   r  shares_floatr  r  
prev_shortt_opt	exp_datesnearestchainr  r  total_call_oitotal_put_oitotal_call_voltotal_put_volr  r  r  hist_sea	close_seamonthly_rets	MONTHS_FRr  rc  vals_s
vals_cleanavgrx  
current_yrr  
months_pctidx_valpct_valrk  rt  s                                                                                                                                        @@r    get_assets_enrichedrJ    s    \\^!!#FF?(9?R"&&w3n6H6HZ\6]]	||~Dhhwr*+DHHZ,C+DTXXiXZE[D\]a]e]efrsu]v\wx~~  AD#XX115:XX/;Hyr
*.((:*>*W$((7TVBW.2hh~r.J L M  '.Gg=1AQ1F1gG,3LGq7G!7K"!M"GLW7WW	W7WW	;AE#f+F3Q7q	!'l"?3(''.r2+4+@iT]Tiyox$
 DIIf
||~**{{6J<v)>|nTZD[$)E;dllBMM22Wf- %,t||$;4=1a4D{{}
L1$45B4::??b01G7|a7<<?+FGLL,-G'F*f4s:A>DMM2tU61=MX]^eghXijk 6 $* 
0>KKtdUS	i''77#G,V4 ,3i6G6G+GYw'Y^^\]_`\`MaF	F 2,2,3-#&v;#4(3-  X[  \b  Xc  fg  Xg5%TVBX[`agalalmnao[pBpty  {A  {F  {F  GH  {I  uJ  BJ  MP  BP  RS  <T  mq 6"''

8,9	@@B "	9 &&**,F>>>c)jUaUgUgUi)j&j&j%'%5%5N*,..'	  "((*,.IPI\E'^-@q"A1Ebf	
z'@		&!	##C ;#))&& ?3999D!*#) .%+*"F %lln
s #		H{{}H(;(;(==$&S	#&;;C"%''(C-"8C!xx}}:A#v:N:NSXXTWX[T\]_^_T`47HS	& 1	 $/
  !* - 3L4;;=LLVZ[\^]^_E,05#AF< 
JGii	,,D <GD'22tzz// DJJJ&6#GVVjj"gmmo"c)"3&"%,0Cs0JfX[mF ! Fjj!SW]]_4rf ! %bq)DH~18j1I1I#,,u-sSVxXZYZ| YY]q014E !%#((4G 7>6IbhhW[W_W_`gil`lWmNnNnU488GSL12tx6<6IbhhW[W_W_`fil`lWmNnNnU488FSL12tx6<6IbhhW[W_W_`fil`lWmNnNnU488FSL12tx6<6IbhhW[W_W_`fil`lWmNnNnU488FSL12txOP}ainvz{n{UALCM#AC#GK  BF
79~!U26C<3lnlz  @ARWXZ]^X^adXdfgRh  GK	&)*s1vD-/^#b'!*",!  ) &. 	8,,Cc4((1LSWW^5LB$3:bRVCWCWSAZ]`ac]d#e!ggm4U@T8UG!ggn5WAV9WH  ,Rx~2  ,RsSZ|  Gmpqymz  MQ  ,RS),,A;?	?2A;NO;N41aAA;NHO
 Xh/0 '
"#B		&!	''B~bhhh kkmFAs"ww{3F"ww}5H"ww}5SAR9SHIPQTV\I]I]s3779chh#?@"EceG)FNFZ_bchiqcr_svx_x5x3)>#B  ]e  ]q  @E  FK  LT  FU  WX  @Y  w{ GuUSY]\]G^RZRfU5?A5Nlp9A)C D , ~~#DJJ#'==?C CGuUSVSZSZ[eghSiSnmnMoqrGs  BF  X\  )]  ^ $3 "*"1~
)G#  
 
'--/JE3KKED5Qaii77wZ_ '.&:'
q!tAHHJq6A:x affRj 1E!&&)4D DaffUViHXX[^^`ab++fUTTYZgoor}}==#*7#3F#; 3:W__2Lgg.RYR^R^_`bc_cRdG!..*w<!#A
 ii!1=DDFG7|a'$U7<<1+=+B+B7<<PQSTPTCU+V%WYZ[065qvvVXzIZ\]C^os$t
5!5 0: '1"#
Dyy yy((=1((=1LTXXm5L((<0((#89((#:;
:F#l"3tBM%k(:A">SWL[`efu`vz{`{%o(>(Da"H  gv  CH  IN  O^  I_  ab  Cc  |@:D#j/t:F#l"3t^joy  I  MN  N%
)Bj(PSV(VXY"Z  TX$
 &B		&!MM	lG&&w/EKKEJJD@NRWR_R_@_Cn 5 9 9 ;<efM@NRVR^R^@^C^ 4 8 8 :;deL@HRWR_R_@_Ch 3 3 56efN@HRVR^R^@^CX 2 2 45deMHUE,-"?!D\`KHVE-."@!D\`Lv "(&*(* ,(/'-&2&7a3%>	S_SdcdhkRkYqy&F>" 1A;;v\EJh&&660$W-f5	 .58H8H-H)hmm\]_`\`NaI&&t,113::<	 ++-446<k	 q"A!,"4"4":":a"?@F,2MMLMq(%(MJLAK%J#j/91=QTC555C"1q5)"%":!   \\^((

Q
Q7B"<#5#5#:#:b#@AG}}J$+MMO www''5:5>15MJs7==12 %4 z""B*#EF 8 	 )&!
} >&)**i HL  ?/xr!=>>? +499QT?D  D4VHBqcBCCD 2Y^^AqD1F<  	90788	9  >.vhb<==>	4  @01#>??@  		
  0 ! >  P 	8/v677	8  G7xr!EFFG*  		    B26("QC@AAB& -q!tA 9gll1a4&8G    G7xr!EFFG(  D4VHBqcBCCDR  B26("QC@AAB  0$MM!Q$/	0 M<  A1&A3?@@As  B+AX BAX 7AXAXAX AX#	AX,B AX -A>AY +AY 3C2AY &A A[ &AZ .D"A[ 2AZ" &AZ" 1AZ" 
A[ AZ" 8A[ A\ A[1 +A\  A[9 A/A\ ?>A\ BA\ A^  A\, ,%A^ A\= A&A^ 2A^ >AA^ 'A]G
A^ DA]' A^ A A]' "A]!>A]' A^ A_ 5C A^6 9BA^6 A_ BA_ A_ ""Aa	 A A`7A`AA`7Aa	 BA`7.A`6C<A`7A2
Aa	 A=E Aa2 GFAb M"?Ac- N"Ac N*B6Ac- Q Ac(RAc(RC>Ac- V4Ac- W0Ac- X
AX X
AY X$AX;X;AY YAYYAY Y
AZY(AY?Y?AZZAZZA[ Z"
A[Z,A[ Z:A[ [ A[[A[ [
A[.[A[)[)A[.[1A[6[3A\ [9A\ [=A\ \
A\)\A\$\$A\)\,
A\:\6A^ \9A\:\:A^ \=A]]	A^ ]A]]A^ ]
A]]A^ ]A]]A^ ]!A]' ]'
A^
]1A^]?A^ ^A^
^
A^ ^
A^3^A^.^.A^3^6
A__ A_ _A__A_ _
A__A_ _A__A_ _
A_>_"A_9_9A_>`A``A`7`A`4`1A`7`7
AaaAa	 aAaaAa	 a	
Aa/aAa*a*Aa/a2
Aba<AbbAbb
Acb%Ab<b<AccAc%c!Ac- c$Ac%c%Ac- c-
Adc7AddAdc                   B    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
rg)GlobalMarketDatai  u   
Récupère les données des marchés mondiaux :
- Matières premières (Or, Pétrole, etc.)
- Devises (Forex)
- Obligations (Treasury Yields)
- Indices mondiaux (CAC 40, DAX, etc.)
c                     SSS.U l         [        R                  " 5       U l        U R                  R                   R	                  U R                   5        g )N<Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8r   r   )r   r   r   r   r1   r  s    r    r<  GlobalMarketData.__init__  s?    XW
  '')##DLL1r!   c                    [         R                  " U5      n UR                  nUR                  nUR                  nUbo  Ubl  [        U5      S:  a]  [        U5      [        U5      -
  n[        U[        U5      -  S-  S5      n[        [        U5      S5      [        [        U5      S5      U4$ UR                  SSS9nUR                  (       a  [        SU 35      e[        US	   R                  S
   5      nUR                  S
   R                  5       n	XR                  R                  S 5      U	:     n
U
R                  (       d  [        U
S	   R                  S
   5      O[        US	   R                  S   5      nXE-
  n[        U(       a  Xe-  S-  OSS5      n[        US5      [        US5      U4$ ! [         a     GNf = f)z^Real-time price via fast_info (works outside US market hours). Falls back to intraday history.r   r*  r  r~  2d5m)rg  rb  zNo data for rd  r  c                 "    U R                  5       $ r   )rN  r  s    r    r  2GlobalMarketData._fetch_realtime.<locals>.<lambda>  s
    !&&(r!   )rp   rq   rt   
last_priceprevious_closer  r  r2   historyr  ru   r
  r  rN  map)r	  r@   rx   ry   r  prevchangepctr  today	prev_barss              r    _fetch_realtime GlobalMarketData._fetch_realtime  s   IIf		BmmG$$D"t'7E$K!Ow%+5FU4[036:U7^Q/uV}a1H#MM yyty4::|F8455W**2./

2##%(:;eCD	9BuYw',,R01eTXY`TaTfTfghTiNjTV]S(q!<Wa %"2C77  		s   BF4 4
GGc                 $   0 n0 SS_SS_SS_SS_S	S
_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS _S!S"_n[        S#5        UR                  5        HZ  u  p4 U R                  U5      u  pVnU[        US$5      [        US$5      US%[        R
                  " 5       R                  5       S&.X'   M\     [        R
                  " 5       R                  5       US*'   U$ ! [         a,  n[        S'U S(U 35        [        U5      US).X'    S nAM  S nAff = f)+NGoldr  SilverSI=FPlatinumzPL=F	PalladiumzPA=FCopperzHG=FCrude_Oil_WTIr  Crude_Oil_BrentzBZ=FNatural_GasNG=FHeating_OilzHO=FGasolinezRB=FWheatzZW=FCornzZC=FSoybeanszZS=FCoffeezKC=FSugarzSB=FCottonzCT=FCocoazCC=Fz8[PKG] Recuperation des matieres premieres (real-time)...r  USD)r@   r  r\  r  r}  last_update  [ERROR] Erreur rm   r   r@   r:  	r3   r_   r`  r  r	   r  r  r2   r  )	r	  commoditiessymbolsrA   r@   r  r\  r  r6   s	            r    get_commodities GlobalMarketData.get_commodities  s   
F
$f
.8&
BMv
W_ag
V
%6
@Mv
Wdfl
nx  {A
 V
 $V
 .8
 BJ6
 T[\b
 emnt
 w~  @F

 	HI#MMOLDH,0,@,@,H)z$"5!_#FA.", %#+<<>#;#;#=%! , $,<<>#;#;#=K 	  H)$r!56.1!f$G!Hs   AC
D#!D

Dc                    0 nSSSSSSSSS	S
SSSS.n[        S5        UR                  5        HY  u  p4 U R                  U5      u  pVnU[        US5      [        US5      U[        R
                  " 5       R                  5       S.X'   M[     [        R
                  " 5       R                  5       US'   U$ ! [         a,  n[        SU SU 35        [        U5      US.X'    S nAM  S nAff = f)NEURUSD=XzGBPUSD=XzUSDJPY=XzUSDCHF=XzAUDUSD=XzNZDUSD=XzUSDCAD=XzEURGBP=XzEURJPY=XzGBPJPY=XUSDCNY=XzUSDHKD=XzUSDSGD=X)EUR/USDzGBP/USDzUSD/JPYzUSD/CHFzAUD/USDzNZD/USDzUSD/CADzEUR/GBPzEUR/JPYzGBP/JPYUSD/CNYzUSD/HKDzUSD/SGDz6
[FOREX] Recuperation des devises Forex (real-time)...r~  )r@   rater\  r  rw  rx  rm   ry  r:  rz  )	r	  r   pairs	pair_namer@   r  r\  r  r6   s	            r    	get_forexGlobalMarketData.get_forex  s    !jZ\f!jZ\f!jZ\fs}

 	GH!&IG+/+?+?+G(j$!$N#FA.",#+<<>#;#;#=$  "/ &\\^557k	  G))Bqc:;-0Vv#F Gs   AB33
C)=!C$$C)c                 >   0 nSSSSSSS.n[        S5        UR                  5        H  u  p4 [        R                  " U5      nUR	                  SS9nUR
                  (       d  US	   R                  S
   n[        U5      S:  a  US	   R                  S   OUnXx-
  n	U[        [        U5      S5      [        [        U	5      S5      [        R                  " 5       R                  5       SS.X'   M  M     SU;   aD  SU;   a>  SUS   ;   a5  SUS   ;   a,  US   S   US   S   -
  n[        US5      US:  a  SOSSS.US'   [        R                  " 5       R                  5       US'   U$ ! [         a-  n
[        SU SU
 35        [        U
5      US.X'    S n
A
GMp  S n
A
ff = f)Nz^IRX^FVXr  z^TYX)1_Month3_Month2_Year5_Year10_Year30_Yearz0
[DATA] Recuperation des taux obligataires US...5drg  rd  r  r  r   r}  %)r@   yieldr\  rw  ro  rx  rm   ry  r  r  r  NormalzInverted (Recession Signal)bps)rR  interpretationro  10Y_2Y_Spreadr:  )r3   r_   rp   rq   rY  r  r
  rs   r  r  r	   r  r  r2   r  )r	  yieldsr|  rA   r@   rw   r  current_yield
prev_yieldr\  r6   spreads               r    get_treasury_yields$GlobalMarketData.get_treasury_yields  s   &Ffagtz
 	AB#MMOLDC6*~~T~2zz$(M$6$6r$:M:=d)a-g!3!3A!6]J*7F"(!&u]';Q!?"'fq"9'/||~'?'?'A #$FL	 "	 ,( 8v#5'VIEV:V[bflmufv[vI&w/&2B72KKFvq).4qj(>['F?#
 'lln668{  C)$r!56),Q6BCs   C E%%
F/!FFc                 *   0 nSSSSSSSSS	S
SSSS.n[        S5        UR                  5        H  u  p4 U R                  U5      u  pVnU[        US5      [        US5      U[        R
                  " 5       R                  5       S.X'   US:X  a#  US:  a  SOUS:  a  SO	US:  a  SOSnXU   S'   M  M     [        R
                  " 5       R                  5       US'   U$ ! [         a,  n	[        SU SU	 35        [        U	5      US.X'    S n	A	M  S n	A	ff = f)NrR   ^DJIr?   z^RUT^FCHIz^GDAXIz^FTSErY   r]   z^HSIr[   r  z^BVSP)zS&P_500	Dow_JonesNASDAQRussell_2000CAC_40DAXFTSE_100EURO_STOXX_50
Nikkei_225	Hang_SengShanghai_Compositer  Brazil_Bovespaz9
[WORLD] Recuperation des indices mondiaux (real-time)...r  )r@   r  r\  r  rw  r  r  zLow Fear (Complacent)r4  r  r   zElevated FearzHigh Fear (Panic)r  rx  rm   ry  r:  rz  )
r	  indicesr|  rA   r@   r  r\  r  rF  r6   s
             r    get_global_indices#GlobalMarketData.get_global_indices	  sA   VwX^hGVa!kW	
 	JK#MMOLDD,0,@,@,H)z$"5!_#FA.",#+<<>#;#;#=! 5=;@2: 7W\_aWa8z  CE  {Egv  K^I6?DM"23 ! ,   (||~779	  D)$r!56*-a&F CDs   A:C
D&!DDc                     U R                  5       U R                  5       U R                  5       U R                  5       [        R
                  " 5       R                  5       S.$ )N)r{  r   treasury_yieldsr  r:  )r}  r  r  r  r	   r  r  r  s    r    get_all_market_data$GlobalMarketData.get_all_market_data%  sL    //1^^%#779..0!113
 	
r!   r   r   N)r  r  r  r  rf  r<  r`  r}  r  r  r  r  r  r   r!   r    rL  rL    s+    28442"J8
r!   rL  c                   *    \ rS rSrSrS rS rS rSrg)MarketCorrelatori0  u   
Analyse le portefeuille et identifie les corrélations de marché pertinentes.
Crée des 'Surveillances' basées sur la composition du portefeuille.
c                    S/ SQSSSSS.SS	S
SS./S.S/ SQSSSSS.SSSSS./S.S/ SQSSSSS.SSSSS./S.S/ SQSSS S!S.S"S#S S$S./S.S%/ S&QSS	S
S'S.S(S)S*S+S./S.S,/ S-QS.S/SS0S.S1S2S3S4S./S.S5/ S6QS7S8S3S9S./S./U l         g ):NzTechnology & Growth)
TechnologySoftwareSemiconductorNVIDIAApple	MicrosoftGoogleMetaAmazonTeslaASMLAMDIntelr  AICyberr?   r  r  u   Corrélation Secteur Techr@   rA   r
  reasonr  zTaux US 10 Ansr  u   Sensibilité aux Taux (Growth))r  r  
indicatorsEnergy)r  OilGas	PetroleumShellTotalExxonChevronBPEniEquinorr  u   Pétrole WTIr  u   Prix de l'Énergierl  zGaz NaturelzPrecious Metals)	rc  rd  MiningPreciousAgnicoBarrickNewmontzFranco-NevadaWheatonr  z	Or (Gold)zActif Sous-jacentre  zArgent (Silver)zCrypto & Blockchain)	BitcoinCryptoCoinbaseMicroStrategy
BlockchainEthereumMinerRiotMarathonzBTC-USDr  cryptou   Leader du Marché CryptozETH-USDr  zAlternative Crypto Majeure
Financials)Bank	Financial	InsuranceJPMChaseGoldmanSachsBNPAxaAllianz	Santanderu   Marge d'Intérêtr  zYield Curver  u   Indicateur de Récession/MargezChina Exposure)AlibabaTencentzJD.comNioBaidurZ   Emergingr[   zShanghai Compositeu   Exposition Marché Chinoisr  r  r   zRisque de Change (Yuan)zEuropean Stocks)LVMHzL'OrealAirbusSiemensSAPInditexEuror  r  zImpact Taux de Change Exportrulesr  s    r    r<  MarketCorrelator.__init__5  sT    2 |&'Upq%/?\|} %%~{^st%}k]rs . A%{K[no%/@+atu 2 F()XYst(*hZvw ) I%/?\pq.x  dD  E -a*4HRY  fB  C)9gYrs ._  *9gYwx	c9

r!   c                 H   0 nU Vs0 s H  o3S   U_M
     nn[        UR                  5       5      nU Vs/ s H  nSU;  d  M  UPM     nnU(       a   [        R                  " SR	                  U5      5      nU H  n	 UR
                  U	   n
U
R                  SS9nUR                  (       d  US   R                  S   n[        U5      S:  a  US   R                  S	   OUS
   R                  S   nX-
  nUS:w  a  X-  S-  OSnXI   nU	US   UUUUS   UR                  SS5      S.X)'   M  M     SU;   a   [        R                  " S5      R                  SS9S   R                  S   n[        R                  " S5      R                  SS9S   R                  S   nUU-
  nSSUSSUS   S   SUS:  a  SOSS.US'   U$ U$ s  snf s  snf ! [         a  n[        SU	 SU 35         SnAGMu  SnAff = f! [         a  n[        SU 35         SnANSnAff = f!    U$ = f)uD   Récupère les données live pour une liste de symboles spécifiquesr@   Spreadr   r  r  rd  r  r  Openr   r*  rA   r  r
  generic)r@   rA   r  r\  r  r  r
  z$Error fetching correlation data for rm   NzBulk fetch error: r  r  r  r  zYield Curve (10Y-2Y)r  r  zInverted (Warning))r@   rA   r  r\  r  r  r
  r  )r  r  rp   Tickersr  r  rY  r  r
  rs   rv   r2   r3   rq   )r	  symbols_neededr5   r  
symbol_mapunique_symbolsr   fetch_symbolsr  r@   rw   r  r  r[  r\  r]  rr   r6   t10t2r  s                        r    get_market_data_subset'MarketCorrelator.get_market_data_subsetr  s_   7EF~t8nd*~
F joo/0$2HNqha6GNH0**SXXm%<=+FT!(!8%~~T~:#zz&*7m&8&8&<G=@Y]4=#5#5b#9PTU[P\PaPabdPeD%,^F;?196=C"7!C#-#5D*0(,V)0*0.1*.x.(,(C,DL  * ,8 n,ii'//t/<WEJJ2NYYv&..d.;GDII"MBh-2 "#(9(C$25'h?S	)_% tu G I8 % T DVHBqcRSST 0*1#.//0( Ds`   G
GG*G7 >B-G+G7 8BH 
G4G/(G7 /G44G7 7
HHHH!c                    0 nU GHO  nUR                  SS5      R                  5       nUR                  S5      (       a   UR                  SS5      R                  5       OSnU R                   H  nSnUS    H!  nUR                  5       n	X;   d  X;   d  M  Sn  O   U(       d  M8  US    H  n
U
S   nX;  a$  UU
S   U
S	   S
UR                  SS5       3S.X+'   M1  SX+   S   ;   d  M>  X+   S   R                  S5      n[	        U5      S:  a#  X+   S==   SUR                  S5       3-  ss'   M  SX+   S   ;  d  M  X+   S==   S-  ss'   M     M     GMR     [        UR                  5       5      nU R                  U5      n/ nUR                  5        H8  u  nnX;   a  UR                  X   5        M   UR                  0 UESSS.E5        M:     U$ )u   
Analyse les positions et retourne une liste d'indicateurs à surveiller.
portfolio_positions: Liste de dicts {'name': '...', 'ticker': '...', 'isin': '...'}
rA   r  rw   Fr  Tr  r@   r
  u   Impacté par Positionr  u   Impacté parr  r  r}  r   z, ...r  r   )r  r  )
rv   r=   r  r  rs   r  r@  r  r_   r  )r	  portfolio_positionsactive_indicatorsrx  rA   rw   rulematchkwkw_lowerindr/  current_reasonssymbols_list	live_datar  r  s                    r    r/  MarketCorrelator.analyze  s   
 &C7762&,,.D69ggh6G6GSWWXr*002RF 

z*B!xxzH'8+=!%	 + 5#L1!(m7*-(+F(+F,9#''&*:U9V*W	6-2  .1B1G1QQ2C2H2R2X2XY]2^#&#7!#;%6%;H%E2cggV\oM^I_%_%E%*2C2H2R%R%6%;H%E%P%E#  2 # 'F -4467//=	 *002ICy~.    ""#   3 r!   r  N)	r  r  r  r  rf  r<  r  r/  r  r   r!   r    r  r  0  s    ;
z>@:r!   r  z/api/market/correlationsc                  h    [        5       n U (       d  [        SS/ S.5      $ U R                  S/ 5      nU(       d  U R                  S/ 5      n[        5       nUR	                  U5      n[        SUS.5      $ ! [
         a1  n[        SU 35        [        S	[        U5      S
.5      S4s SnA$ SnAff = f)uG   Endpoint pour récupérer les indicateurs clés basés sur le portfoliowarningPortfolio emptyr   rj  r5   r  r  r   r4  zCorrelation Error: r   r8  r7  N)r  r   rv   r  r/  r2   r3   r  )r  r  
correlatorrm  r6   s        r    get_portfolio_correlationsr    s    D,.	y=NXZ[\\MM+r2	!&6;I%'
%%i0)X>?? D#A3'('c!f=>CCDs#   A6 AA6 6
B1 &B,&B1,B1z/api/ai/news-recommendationsc                      [        S5      n SnU (       a  SU ;  a  SnOTU R                  S5      nU(       a<   [        R                  " U5      n[        R                  " 5       U-
  [        SS9:  a  SnU(       a  [        S5        [        5       n U R                  S/ 5      nU(       d  [        S	S
/ S.5      $ SR                  USS  Vs/ s H  nSUS    SUS   SS  3PM     sn5      nSnSU S3nSUS.SUS./n	[        S5        [        U	SS9n
 U
R                  SS5      R                  SS5      R                  5       n[        R                  " U5      nU H  nM     [        S US!.5      $ !   Sn GN= fs  snf ! [        R                   a+  n[        S"U S#U
 35        [        S$S%S&.5      S'4s SnA$ SnAff = f! [          a1  n[        S(U 35        [        S$[#        U5      S&.5      S'4s SnA$ SnAff = f))z0Analyses news (RSS) via Groq to recommend stocksrK  Fr_   T
fetched_atr~  hoursz+Refreshing Bloomberg RSS for AI analysis...r  zNo news data availabler  
Nr4  z- rC  rm   rD  r   z{You are an expert financial analyst. Your goal is to identify investment opportunities based strictly on the provided news.z<Analyze the following market news headlines and summaries:

a  

Identify the top 3-6 stock tickers that are most 'prized' or have the highest upside potential based on these specific news events. Focus on companies with positive momentum, breakouts, or strong fundamental catalysts mentioned.
Return a strictly valid JSON array of objects. No markdown, no intro text.
Format: [{'ticker': 'AAPL', 'name': 'Apple Inc', 'reason': 'Detailed explanation citing the specific news...', 'score': 8.5, 'sentiment': 'Bullish'}]
Score is between 0-10. Sentiment is 'Bullish' or 'Neutral'.systemrolerP  userz!Calling Groq for News Analysis...i  )
max_tokens```jsonr  ```r   r4  zAI JSON Error: z. Response: r   zFailed to parse AI responser8  r7  zAI News Error: )r/   rv   r	   fromisoformatr  r
   r3   fetch_bloomberg_rss_apir   r  call_groq_apir  r  r   r  JSONDecodeErrorr2   r  )rss_datashould_refreshr!  
last_fetchr_   r  news_contextsystem_promptuser_promptmessagesai_response
clean_jsonrecommendationsrecjer6   s                   r    get_ai_news_recommendationsr<    s:   GD"?3 7(2!N!l3J*!)!7!7
!CJ||~
2YQ5GG)- ?@.0HWb)i<T^`abb yy\abece\f!g\fTXBtG}oRY8M7N"O\f!gh J 	
 M\N [J J 	 -84
 	12#H>	_$,,Y;CCE2NTTVJ"jj4O ' ' iIJJa*%)N "hJ ## 	_OB4|K=ABg:WXY[^^^	_  Ds#$'c!f=>CCDsr   5G ;E0 3AG 7G 	E:$.G AE? 0E74G ?F> F93F>4G 9F>>G 
G<&G71G<7G<c                   .    \ rS rSrSrS rSS jrS rSrg)	TechnicalAnalyzeriQ  u   
Scanne le portefeuille pour détecter des signaux techniques:
- RSI > 70 (Surachat) ou < 30 (Survente)
- Croisement SMA (Golden Cross / Death Cross)
- Tendance long terme (Prix > SMA 200)
c                 .    SU l         SU l        SU l        g )N   r   r   )
period_rsiperiod_sma_shortperiod_sma_longr  s    r    r<  TechnicalAnalyzer.__init__X  s     ""r!   c                    UR                  5       nUR                  US:  S5      R                  US9R                  5       nUR                  US:  S5      * R                  US9R                  5       nXE-  nSSSU-   -  -
  $ )Nr   windowr*  r  )r  whererollingr  )r	  seriesrg  deltagainlossrss          r    calculate_rsiTechnicalAnalyzer.calculate_rsi]  s    EAIq)22&2AFFHUQY**3363BGGI[cQVn%%r!   c                 
    [         R                  " U5      nUR                  SS9n[        U5      S:  a  g US   nUR                  S   nU R                  X@R                  5      R                  S   nUR                  SS9R                  5       R                  S   nUR                  SS9R                  5       R                  S   n UR                  n	U	R                  S5      n
U	R                  S	5      nU	R                  S
5      nU	R                  S5      nU	R                  SS5      R                  SS5      nU[        [        U5      S5      [        [        U5      S5      [        [        U5      S5      [        [        U5      S5      U
(       a  [        U
S5      OSU(       a  [        US5      OSU(       a  [        US5      OSUUR                  5       S./ S.nUS:  a(  US   R                  SSSS[!        U5       S3SS.5        O-US:  a'  US   R                  SSS S![!        U5       S"3S#S.5        XX:  a  S$US%'   OS&US%'   Xx:  az  S'US('   UR                  SS9R                  5       R                  S)   nUR                  SS9R                  5       R                  S)   nUU::  a  US   R                  SS*S S+S#S.5        OS,US('   U(       a*  US:  a$  US-:  a  US   R                  S.S/S S0U S13S#S.5        US2;   a>  U(       a7  XS3-  :  a/  US   R                  S.S4S5S6[!        X-  S-
  S7-  5       S83S9S.5         UR                  S:S  nUS;   R#                  5       nUS<   R%                  5       n[        [        U5      S5      [        [        U5      S5      [        UU-
  UU-
  -  S7-  S5      S=.US>'   S US?'   U$ !   Su  ppn GN= f!   S US>'    N= f! [&         a  n[)        S@U SAU 35         S nAg S nAff = f)BNr  r  r   rd  r  r   rF  	forwardPEpegRatiobetatargetMeanPricerecommendationKeyr/  r   r   )NNNNr/  r  r  r  )pepegrT  rZ  	consensus)rw   r  rg  sma_50sma_200fundamentalalertsF   r]  	TechniqueRSIWarningzSurachat (RSI z). Risque court terme.red)r
  subtyperi  rj  colorr   OpportunityzSurvente (RSI u   ). Point d'entrée potentiel.greenBullishtrendBearishGoldencross_statusr  Crossu5   GOLDEN CROSS Confirmé ! (50 croise 200 à la hausse)Deathr   Fondamentaler  u   Sous-évaluée (PEG u   ). Croissance peu chère.)z
Strong BuyBuygffffff?	ConsensusGoodzAnalystes Bullish (Cible +r*  %)bluer<  LowHigh)support
resistance	range_poslevelsr3  z	TA Error rm   )rp   rq   rY  rs   r
  rO  rA  rI  r  rr   rv   r  r  r  rC  r  r  r  r  r2   r3   )r	  ticker_symbolrw   r  r   rr  rg  rZ  r[  rr   rW  rX  rT  r  rY  signalprev_sma_50prev_sma_200recent_histrv  rw  r6   s                         r    analyze_ticker TechnicalAnalyzer.analyze_tickerd  sS   A	YY}-F>>>.D4y3ME!JJrNM $$UOO<AA"EC ]]"]-22499"=Fmm3m/446;;B?GW{{XXk*hhz*xx'"34!%*=v!F!N!NsTW!X
 (u]3Q7U3Z+fq1 w3*,%A,%,/5a=U.2E$N$*!/!5!5!7  F" Rxx '''$&!/Cz9OP")  rx '''$*!/Cz9VW$)  &"+w"+w )1~&#mm2m6;;=BB2F$}}C}8==?DDRH,.H%,, +#*!.#Z!(.  *1~& sQw37!((* '*!5cU:ST$*  !666f_cOcFc!((**#!;C&BVXYAY[^@^<_;``bc#* ("iio%e,002(0446
  %U7^Q7"'j(91"=!&)@ZRYEY(Z^a'acd!e$x  &*F>"MGW8V5~t(#'x   	Im_Bqc23	sP   4O BO A2O :HO A:O <O OO OO 
P'O==P)rA  rC  rB  Nr@  )	r  r  r  r  rf  r<  rO  r  r  r   r!   r    r>  r>  Q  s    #
&Br!   r>  z/api/analysis/technicalsc            
          [        5       n U (       d  [        SS/ S.5      $ U R                  S/ 5      n[        [	        U Vs/ s H+  o"R                  S5      (       d  M  UR                  S5      PM-     sn5      5      nUSS n[        5       n/ n[        SS	9 nU Vs0 s H  ovR                  UR                  U5      U_M!     nnU H-  n	U	R                  5       n
U
(       d  M  UR                  U
5        M/     SSS5        [        S
US.5      $ s  snf s  snf ! , (       d  f       N&= f! [         a1  n[        SU 35        [        S[        U5      S.5      S4s SnA$ SnAff = f)z>Scanne le portefeuille utilisateur pour les signaux techniquesr  r  r  r  rw   Nr4  rg   max_workersr   r4  zScan Error: r   r8  r7  )r  r   rv   r  r  r>  r   submitr  r  r  r2   r3   r  )r  r  r  unique_tickersr5  r  executorrx   futuresfuturer\  r6   s               r    get_technical_signalsr    sC   D,.	y=NXZ[\\MM+r2	cI"YIqx?155?I"YZ[ (,$&  A.(O]^~!x'>'>BAE~G^!mmo3NN3'	 " / )W=>># #Z _ /.  DQC !'c!f=>CCDsj   D*  D* DD4%D* D&DD$D9D* D* D
D'#D* *
E%4&E E% E%z/api/analysis/360POSTc                  `    [        5       n U (       d  [        SS0 S.5      $ U R                  S/ 5      n[        [	        U Vs/ s H+  o"R                  S5      (       d  M  UR                  S5      PM-     sn5      5      SS nS n[        5       n0 n0 n[        S	S
9 nU V	s0 s H!  oR                  UR                  U	5      SU	4_M#     n
n	U V	s0 s H  oR                  XI5      SU	4_M     nn	0 U
EUEnU HD  nX   u  p UR                  5       nU(       a#  US:X  a  UUUR                  SU5      '   M>  UX'   MD  MF     SSS5        U V	s0 s H  o/ _M     nn	 [        R                  5          U H  n[        R                  R!                  US9R#                  [        R$                  R'                  5       5      R)                  S5      R+                  5       nU HM  nUU   R-                  UR.                  =(       d    SUR0                  UR2                  UR4                  S.5        MO     M     SSS5        [7        S5      =(       d    0 n[7        S5      =(       d    0 nSnSnSnSnUR9                  5        GHP  u  nn[;        U[<        5      (       d  M  [?        UR                  SS5      5      RA                  5       nSU;   d  SURA                  5       ;   a$  [C        UR                  SS5      =(       d    S5      nSU;   d(  SURA                  5       ;   d  SURA                  5       ;   aH  [C        UR                  SS5      =(       d    S5      n[C        UR                  SS5      =(       d    S5      nS U;   d+  S!URA                  5       ;   d  S"URA                  5       ;   d  GM,  [C        UR                  SS5      =(       d    S5      nGMS     SnSn UR9                  5        H  u  nn[;        U[<        5      (       d  M  S#[?        U5      ;   a&  [C        UR                  S$S5      =(       d    S5      nMR  S%[?        U5      ;   d  Mc  S&[?        U5      ;  d  Mt  [C        UR                  S$S5      =(       d    S5      n M     U(       a  U (       a  [E        UU -
  S'5      OSn!US(:  a  S)u  n"n#O)US:  a  S*u  n"n#OUS+:  a  S,u  n"n#OUS-:  a  S.u  n"n#OS/u  n"n#US:  a  S0OUS+:  a  S1O	US-:  a  S2OSn$U!b  U!S:  a  [G        SU$S-
  5      n$[7        S35      =(       d    0 n%U%R                  S4/ 5      n&U V	s0 s H  o/ _M     n'n	/ n(U&SS5  H  n)[C        U)R                  S6S5      =(       d    S5      n*U)R                  S7S85      =(       d    S8n+U)R                  S9S5      =(       d    Sn,U)R                  S:5      =(       d    U,n-U)R                  S;S5      =(       d    Sn.U*S<:  a'  U(R-                  U-U+U*U.U)R                  S=S5      S>.5        U,RA                  5       n/U H#  nUU/;   d  M  U'U   R-                  U-U+U*S?.5        M%     M     U(RI                  S@ SASB9  U(SSC n(/ n0Sn1/ n2U GH  n3U3R                  S5      =(       d    SRK                  5       nU(       d  M5  UR                  U0 5      n4UR                  U0 5      n5U'R                  U/ 5      n6UR                  U/ 5      n7U6(       ax  [M        SD U6 5       5      [O        U65      -  n8[M        SE U6 5       5      n9U2R-                  U85        U9[O        U65      S'-  :  a  SFOU9[O        U65      S'-  :  a  SGOS8n:[E        U8SH5      n;OS8n:Sn;U4R                  SISJ5      n<U<SK:X  a  U1SH-  n1Sn= U4R                  SL5      (       a3  U4R                  SM5      (       a  [C        U4SL   5      [C        U4SM   5      :  n=Sn>U7(       a>  [M        SN U7 5       5      n?[M        SO U7 5       5      n@U?U@SP-  :  a  SQn>OW@U?SP-  :  a  SRn>OS8n>U0R-                  0 SU_SU3R                  SU5      _SSU3R                  SSS5      _ST[C        U3R                  STS5      =(       d    S5      _SU[C        U3R                  SVS5      =(       d    S5      _SW[C        U3R                  SXS5      =(       d    S5      _SY[C        U3R                  SZS5      =(       d    S5      _S[[C        U3R                  S\S5      =(       d    S5      _SIU<_S]U4R                  S]5      _S^U=_S_U4R                  S_/ 5      _S`U4R                  S`0 5      _SU4R                  S5      _SaU;_SbU:_Sc[O        U65      _0 SdU6SS' _SeU7SSf _SgU>_ShU5R                  Sh0 5      _SiU5R                  Si5      _SjU5R                  Sj5      _SkU5R                  Sk5      _SlU5R                  Sl5      _SmU5R                  Sm/ 5      _SnU5R                  Sn5      _SoU5R                  So5      _SpU5R                  Sp5      _SqU5R                  Sq5      _SrU5R                  Sr5      _SsU5R                  Ss5      _StU5R                  St5      _SuU5R                  SuS5      _E5        GM     [O        U05      nAUA(       a  [E        U1WA-  Sv-  5      OSwnBU2(       a&  [E        [M        U25      [O        U25      -  S-  Sv-  5      OSwnC[M        Sx U0 5       5      nD[E        UD[G        WASH5      -  Sv-  5      nEU0 Vs/ s H2  o"Sh   R                  Sy5      (       d  M  USh   R                  SyS5      PM4     nFnUF(       a  [M        WF5      [O        UF5      -  OSfnG[G        S[Q        Sv[E        SvUGS'-  -
  5      5      5      nH[E        WBSz-  WCS{-  -   U$S|-  -   WES}-  -   UHS~-  -   5      nIUIS:  a  Su  nJnKOWIS1:  a  Su  nJnKOWIS:  a  Su  nJnKOSu  nJnK0 nL [        R                  5          [R        R                  R+                  5       nMUM H<  nNUNRT                  (       d  M  WNRV                  UNRX                  S.WLUNRT                  '   M>     SSS5        / nP [[        5       nQ[	        U5      nRUQ VSs/ s H3  nSUSR                  S5      =(       d    SRA                  5       WR;   d  M1  WSPM5     nTnSUT(       a  WTOWQSS nP[        SWIWJWKWBWCU$WEWHS.[E        USH5      U"U#S.[E        US'5      [E        US5      S.S[E        US'5      0[E        US'5      [E        U S'5      U!U!(       a  U!S:  a  SO
U!(       a  SOSS.U(U0WLWP[\        R^                  " 5       Ra                  5       S.
S.5      $ s  snf s  sn	f s  sn	f ! [         a   n[        SU SU SU 35         SnAGM  SnAff = f! , (       d  f       GNY= fs  sn	f ! , (       d  f       GN= f! [         a  n[        SU 35         SnAGNSnAff = fs  sn	f ! [         a     GN-f = fs  snf ! , (       d  f       GN= f! [         a  nO[        SUO 35         SnOAOGNSnOAOff = fs  snSf ! [         a  nU[        SUU 35         SnUAUGNSnUAUff = f! [         aF  nV[        SUV 35        [b        Rd                  " 5         [        S[?        UV5      S.5      S4s SnVAV$ SnVAVff = f)u]   Analyse complète du portefeuille — Technique + Insiders + Macro + News + Events + Enrichedr  zPortfolio vider  r  rw   Nr4  c                 ,   U 0 SS/ SSSSSSSSS.n [         R                  " U 5      n0 n UR                  =(       d    0 n UR	                  S5      =(       d    SR                  5       US'    UR	                  S5      nUR	                  S5      nUR	                  S5      nUR	                  S5      nUb  [        U5      S	::  a  [        [        U5      S
-  S5      O[        [        U5      S5      nU(       aF  U(       a?  [        U5      S:  a0  [        [        U5      [        U5      -
  [        U5      -  S
-  S	5      OSn	UU(       a  [        [        U5      S	5      OSU	S.US'    UR                  n
U
(       Ga~  UR                  U
S   5      nSUR                  R                  ;   a&  [        UR                  S   R                  5       5      OSnSUR                  R                  ;   a&  [        UR                  S   R                  5       5      OSnSUR                  R                  ;   a&  [        UR                  S   R                  5       5      OSnSUR                  R                  ;   a&  [        UR                  S   R                  5       5      OSnU(       a  [        X-  S5      OSnU(       a  [        X-  S5      OSnU=(       d    S	S:  a  SOU=(       d    S	S:  a  SOSUS'   UUS'   XS'   XS'    SnUR                  nUb"  [!        US5      (       a  UR"                  (       a  UR$                  nUGb  UR"                  (       Gd  ['        S UR(                   5       S5      n['        S UR(                   5       S5      n[+        UR                  5      SS nSn[-        U5       GHD  n [!        US5      (       a%  SUR.                  S	-
  S -  S	-    S!UR0                   3O[3        U5      SS" nUbD  [4        R6                  " UR8                  UU4   5      (       a  [        UR8                  UU4   5      OSnUbD  [4        R6                  " UR8                  UU4   5      (       a  [        UR8                  UU4   5      OSnUb%  U(       a  [        UU-
  [;        U5      -  S
-  S	5      OSnUS#   R=                  UU(       a  [        U5      OSU(       a  [        U5      OSUS$.5        UnGMG     [+        [-        US#   5      5      US#'    UR>                  nUGb  UR"                  (       Gd  SnSnSnURA                  5        H  u  n n!U!R	                  S%5      n"U!R	                  S&5      n#U!R	                  S'5      =(       d    U!R	                  S(5      n$U"b%  U#b"  US	-  n[        U"5      [        U#5      :  a  US	-  nU$c  M~  Ub  M  [;        [        U$5      5      S):  a  [        [        U$5      S
-  S	5      O[        [        U$5      S	5      nM     U(       a  [        UU-  S
-  5      OSUS*'   UUS+'    URB                  n%U%b  [E        U%[F        5      (       a  U%O"[!        U%S,5      (       a  U%RI                  5       O0 n&U&R	                  S-5      =(       d)    U&R	                  S.5      =(       d    U&R	                  S/5      n'U'(       a-  [E        U'[*        5      (       a  U'S   OU'n([3        U(5      SS) US0'   U&R	                  S15      =(       d    U&R	                  S&5      n)U)b  [        [        U)5      S5      US2'    UR	                  S35      =(       d    UR	                  S45      n*U*(       aW  [E        U*[        [        45      (       a+  [J        RL                  " U*5      n+U+RO                  S55      US6'   O[3        U*5      SS) US6'   UR	                  S75      =(       d    UR	                  S85      n,U,(       a  [        [        U,5      S 5      US9'    URQ                  S:S;9n-U-R"                  (       dr  [S        U-5      S<:  ac  [        [        U-S=   RT                  S>   5      [        U-S=   RT                  S   5      -
  [        U-S=   RT                  S   5      -  S
-  S	5      US?'   U$ ! [         a     GNkf = f! [         a     GNPf = f! [         a     GNif = f! [         a     GNf = f! [         a     GNf = f! [         a    Sn GNf = f! [         a     GMh  f = f! [         a     GNf = f! [         a     GN f = f! [         a     GNf = f! [         a     GNOf = f! [         a     U$ f = f! [         a  n.[W        S@U  SAU. 35         Sn.A.U$ Sn.A.ff = f)BzSFetch short interest, options bias, quarterly trend, EPS beat rate, upcoming eventsNr  )rw   rI  options_bias
options_pcquarterly_trendeps_beat_rateeps_lastupcoming_earningseps_estimateupcoming_dividenddividend_amountannual_perf_1yr`   r`   r  r  r  r  r  r*  r  r   )	pct_floatratior  rI  r  r  r  rR  r  rX  r  r  r  options_call_oioptions_put_oir  c              3   d   #    U  H&  nS [        U5      R                  5       ;   d  M"  Uv   M(     g7f)r  Nr  r=   r   rO  s     r    r   Bget_analysis_360.<locals>.fetch_ticker_enriched.<locals>.<genexpr>^  s)     'c:aTWXYTZT`T`TbAb:   !0	0c              3   d   #    U  H&  nS [        U5      R                  5       ;   d  M"  Uv   M(     g7f)r  Nr  r  s     r    r   r  _  s)     '`:aQTUVQWQ]Q]Q_A_:r  r~  r  r  r}  r   r  r  )r0  revr   growthr  r  r  r  r   r  r  r  r  r  Earnings_Dater  EPS Estimater  dividendDateexDividendDater  r  dividendRatelastDividendValuer  r  r  r4  rd  r  r  z[360] Enriched error for rm   ),rp   rq   rr   r2   rv   r  r  r  r  r  r  r  r  r  r  r  r^   r  r  nextr  r  r  r  re  r  r  r  r  r  r  r  r  r  r  r  r  r	   fromtimestampr  rY  rs   r
  r3   )/rw   r  rx   rr   spsrsp_prevssr]  chgexpsr:  r  r  call_vput_vpcpc_vr  r  r  r  prev_rr  qlrO  r   grwr)  beats	total_eps	last_surpr   r  r  r  r*  r"  cal_dr#  ed_valeps_estdiv_datediv_dtdiv_amtr  outer_es/                                                  r    fetch_ticker_enriched/get_analysis_360.<locals>.fetch_ticker_enriched  sP	    !"$ $"#%!% %) $%)#'"&FGGIIf%66<RD
(,(:(@b'G'G'IF8$
"78B,/B"hh'>?G-0B~;@9>eE"IOQ7uUZ[]U^`aOb_afmrwx  sA  DE  sEeU2Yw%?5>$QTW$WYZ[  KO),<>U59a%8D*-4/099D !tAw 7LZ^c^i^i^q^qLq#ekk.&A&E&E&G"HwxLZ^c^h^h^p^pLp#ejj&@&D&D&F"GvwLTX]XcXcXkXkLk#ekk(&;&?&?&A"BqrLTX]XbXbXjXjLj#ejj&:&>&>&@"Apq;BU6#3Q7;AuU^Q7t?CyqC>OdhdmlmqtctV_  {C~./1|,4;0139/0
D ! 7 7|g(>(>4::$%$:$:T'


"&'c4::'cei"j"&'`4::'`bf"g#DLL1"15!%#+D>C%LSTWY`LaLaq#))A+)9!);(<AchhZ%HgjkngoprqrgsFMFY^`^f^fgkgogopwy|p|g}^~^~U488GSL+A%B  EIFLFY^`^f^fgkgogopvx{p{g|^}^}U488FCK+@%A  EITUTafleQZ3v;,F,La&Prv &'8 9 @ @r\]RUVWRXcgz|orsuov  CG  SV  BW  !X)* $2 59&IZB[9\4]01
++B~bhhh !q9d)&(kkmFAs%(WW[%9F'*ww}'=H'*ww}'='[IZA[H%1h6J )Q	#(=E(O#C$)QJE'3	8IORSXYaSbOcfhOhE%/C2G,Knsty  {C  uD  FG  oH	 '4 U^%	8IC8O2Pcg/-6z*
**C'1#t'<'<T[\_ajTkTk3;;=qs"YY7r599^;TrX]XaXabqXr.8T.B.BRUF:=f+cr:JF#67"'))N";"Wuyy?W".5:5>15MF>2
#xx7U488DT;UH%he==%-%;%;H%EF:@//*:UF#67:=h-:LF#67"hh~6W$((CV:WG49%.!4L01
99D91D::#d)b.38%W@R@RSU@V:WZ_`del`m`r`rst`uZv:vz  AE  FM  AN  AS  AS  TU  AV  {W  :W  Z]  :]  _`  4a/0 MG !  ! " ! $ !  %*d*  )5$5 $- % $% ! ( !  !  !  !  M  G1&G9EFFMGs  e- b +b/ -C7c  %Fc 8d :c" %d +c3 7A9d 1D?d0d B2d) d) A+d) 7Dd: :Ce 
Be 
b,(e- +b,,e- /
b=9e- <b==e-  
c
e- ce- 
ce- ce- "
c0,d /c00d 3d?d dd 
dd dd 
d&"e- %d&&e- )
d73e- 6d77e- :
ee- ee- 
ee- ee- 
e*&e- )e**e- -
f7ffr  r  techenrz[360] Future error (r  ): rw   r   r  )rA   rO  rR  rN  z[360] Insiders DB error: market_indicesmarket_treasuryrz  rA   r  r  r   zS&PSPXGSPCr  r  NDXIXICr;  r  2r  r  r  )u   Très Calmeemerald)u   Faible Volatilitér  r  )u   Modéréamberr   )u   Élevér  )Paniquerb  P   r   (   rK  r_   x   rn  ro  rj  rC  rt  linkr~  	published)rC  rF  rM  r  r  )rC  rF  rM  c                     U S   $ )NrM  r   r  s    r    r  "get_analysis_360.<locals>.<lambda>  s	    Am$4r!   Tr^  rB  c              3   *   #    U  H	  oS    v   M     g7f)rM  Nr   r   r  s     r    r   #get_analysis_360.<locals>.<genexpr>   s     ?A/   c              3   :   #    U  H  oS    S;   d  M  Sv   M     g7frP  r   r  s     r    r   r  !  s     Zu!+BY0YAAurU  rQ  rW  r  rh  Neutralrg  rZ  r[  c              3      #    U  H6  nS [        UR                  SS5      5      R                  5       ;   d  M2  Sv   M8     g7f)r  rO  r  r  Nr  rv   r=   r  s     r    r   r  4  s3     ^s!eAEE-QS<T8U8[8[8].]AAss
   1A 	A c              3      #    U  Hc  nS [        UR                  SS5      5      R                  5       ;   d/  S[        UR                  SS5      5      R                  5       ;   d  M_  Sv   Me     g7f)salerO  r  sellr  Nr  r  s     r    r   r  5  s}       Rs!fAEE-QS<T8U8[8[8].]agknopotot  vC  EG  pH  lI  lO  lO  lQ  bQAAss   AA-$	A-      ?rR  rX  r   r  	avg_pricer  rr  r  rt  r  market_valuemarketValuerg  	sma_crossr]  r\  
news_scorerB  
news_counttop_newsr   rg   insider_signalrI  r  r  r  r  r  r  r  r  r  r  r  r  r`   r*  r   c              3   R   #    U  H  oR                  S 5      S:X  d  M  Sv   M     g7f)r  rR  r  Nrv   )r   r  s     r    r   r  i  s$     `%755AQ;RV_;_!!%7s   '	'r  333333?皙?      ?333333?皙?K   )	Excellentr  )Soliders  r  )Prudentr  )u   Risquérb  )ra  rb  z[360] Sector data error: rA  z[360] Bank Forecast Error: r   )
technicalsr  r   r   short)rR  regimerd  )r  r  u	   InverséeNormaler  )vixsp500nasdaq	yield_10yyield_2yyield_spreadyield_curve)
health_scorehealth_labelhealth_colorhealth_breakdownmacro_snapshotr  positions_analysissector_datar  
scanned_atr4  zAnalyse 360 Error: r   r8  r7  )3r  r   rv   r  r  r>  r   r  r  r  r2   r3   r)   r.   rJ  r   r  r  rU  r  rC  r   r  rL  rO  rR  rN  r/   r_   r  r  r  r'  r  r  r  sortr  r  rs   r  r_  r`  ra  rb  r  r	   r  r  r   r   )Wr  r  r  r  r  r5  tech_by_tickerenriched_by_tickerr  rx   tech_futuresenr_futuresall_futuresr  kindrw   r\  feinsiders_by_tickerr  txins_er  treasuryvix_valsp500_changenasdaq_changesp500_pricer   r  rA   y10_valy2_valr  
vix_regime	vix_colormacro_regime_scorer0  
news_itemsticker_newsr  r  critrF  rC  rt  r  title_upperr		  
bull_countnews_scores_collectedrx  sigr  tnewsinsavg_critpos_cdom_sentnews_score_valrh  r  r  buyssellsr~   
tech_scorenews_score_overallbullish_insinsider_score
short_pcts	avg_shortshort_scorer	  r	  r	  r
	  
all_trendsrt  sec_e	bank_datar   portfolio_tickers_setr   ticker_matchedber6   sW                                                                                          r    get_analysis_360r=	    s   kD,.	i<LVXYZZMM+r2	cI"YIqx?155?I"YZ[\_]_`Y	x %&A.(`no`n[\__X-D-DaH6ST+U`nLo`no`n[\__-BFPQ
R`nKo;|;{;K%*2J --/C6>HKN3778V+DE9<.6	 	 &	 /" .<<^e^<	7",F-33==V=LUU*77<<>eBi  #*6299$&OO$9r+->>%'XX$&GG	;  #	 - #  ##34;"#45;c|3[HCc4(((swwvr*+113D} 4 3 8q9} 4#))+8M$SWW\1%=%BC$SWWWa%8%=A>45CIIK#76SYY[;P %cgglA&>&C! D ( v (HCc4(((s3x5!1D1I+JCTS%9E#''RY[\J]JbabDc6 )
 076w'+tR<4L1J	r\4S1J	r\4G1J	r\4G1J	4D1J	#*R<R7R<RSZ]_S_Reg&1*!$Q(:R(?!@ %_5;\\'2.
&45n"un5t$Ddhh':A>C!DD!2I>K)I"-3E,5H,2Dqy(04d.2hh{B.G!I J  ++-K([('..PYjn/op ) % 	4dCBQ<  
-Cggh'-2446F8"&&vr2C&**626COOFB/E&**626C ???#e*LZuZZ%,,X6).Ua)?:SX[^_d[ehi[iSiZox!&x!3$tn GGGY/E	!:?:I#778$$);); %c(m 4uS^7L LI "N^s^^  Rs  R  R%#+%)TCZ'):C%% ('F('CGGFF$;(' CGGFB$7(' E#''%*;*@q$A	('
 E#''*a*@*EA$F('  E#''.!*D*I$J(' E#'',*B*Ga$H(' E#''-*C*Hq$I(' E(' CGGEN(' I(' CGGHb$9(' CGGM2$>(' CGGG$4('" N#('$ !H%('& CJ'('( E"1I)(', CG-('. !N/('2 !CGG,<b$A3('4 CGGN$;5('6 CGGL$97('8 "CGG,=$>9(': !CGG,<$=;('< "CGG,=r$B=('>  CGGO$<?('@ CGGJ$7A('D $sww/B'CE('F sww~'>G('H $sww/B'CI('J "sww/@'AK('L !sww/?'@M('N swwx'<O(' (K ` &':?uZ%/#56R
jU3'<#=DY@Z#Z]_#_be#ef  FH`%7``kCqM9C?@GY  CGY!_o]p]t]t  vA  ^B=a()--k1=GY
  C9CC
Oc*o5	!SeC)a-,?&@AB%%&%& %& %	&
 2>T!;|R>Q!;|R>R!;|>Q!;| 
	7"(..224
$B~~~-/-=-=,.OO7BNN3 % # 		6.0I$'$7!)2oAquuX7L"6S6S6UYn6naNo*8inI !-!-!-","4"4"/"-% /4GQ.?:`i$j38q3ITYZeghTi$j%153J$K$)'1$5$)&!$4$*39fqjK[aigl# '/&8&1&/&.lln&>&>&@1
  	K #ZH po ! J0bB4HIIJ /." =""  	7-eW566	7T 6f "d"z C( #"  	7-eW566	7 p 	6/t455	6@  D#A3'('c!f=>CCDs  y  y uu4(y v!(u	vu,v 2u#2v4u#8v>y 
v"y v9 -Cv'/v9 7E'y #By y Cy ,w8C!y Ey ;A	w$L6y :w5w53By x  3w:*w:x 	y x7 %0x2x2x7 /B$y y 
v#
v-vvvv
vy '
v61v9 4y 6v9 9
wwy wy $
w2.y 1w22y :
x	x y 	x 
x/x*$y *x//y 2x7 7
yyy yy 
z-';z("z-(z-z/api/market/allc                      / SQn 0 nU  H5  n[        U5      nU(       d  M  UR                  SS5      nUS:X  a  SnX1U'   M7     [        U5      $ )zReturns cached market data)market_commoditiesmarket_forexr  r  market_r  r	  r  )r/   r  r   )r  r   r   r5   	short_keys        r    get_market_datarC	    sZ     WDHs#4Ir2IJ&4E	"&Y  8r!   z/api/market/updatec                      [        5       n U R                  5       nSU;   a  [        SUS   5        SU;   a  [        SUS   5        SU;   a  [        SUS   5        SU;   a  [        SUS   5        [        S	S
US   S.5      $ ! [         aF  n[        SU 35        [        R                  " 5         [        S[        U5      S.5      S4s SnA$ SnAff = f)zForces update of market datar{  r?	  r   r@	  r  r  r  r  r   zMarket data updatedr:  )r   rj  r:  zValidation Error: r   r8  r7  N)	rL  r  r9   r   r2   r3   r   r   r  )r  r5   r6   s      r    update_market_datarE	    s    D!#))+D /2F]H["\d?ONDMJ$o6GN_I`&ao.>YP)8M\`al\mnoo D"1#&''c!f=>CCDs   A?B 
C;CCCz/api/auth/loginc                  (   [         R                  n U R                  S5      nU R                  S5      nU R                  S5      nU R                  S5      nU(       a  U(       d  [        SSS.5      S4$  [        R                  5          [        R                  R                  US	9R                  5       nU(       d>  [        UUU=(       d    S
U=(       d    S
S9n[        R                  R                  U5        O X%l        U(       a  X5l        U(       a  XEl        [        R                  R!                  5         S S S 5        [&        R)                  XX4S9n[        U5      $ ! , (       d  f       N-= f! ["         a  n[%        SU 35         S nANMS nAff = f)Nr.  r/  	firstNamelastNameFzPhone and PIN requiredr     r  r  )r.  r/  r0  r1  zDB Error User Save: )r0  r1  )r   r   rv   r   r)   r.   r$  r   r  r  r   r   r   r/  r0  r1  r   r2   r3   r   r  )r5   r.  r/  r0  r1  r(  r6   r  s           r    
auth_loginrJ	    s6   <<DHHWE
((5/C+&J$I53KLMsRR*__::''e'4::<D)/R'o2	 

t$ynJJ $ ""5*"ZF6?'   *$QC())*s7   4E/ B/E7E/ 
E,(E/ ,E/ /
F9FFz/api/auth/profilec                     [         R                  R                  S5      n U (       dJ  [        R                  R                  [        R                  R                  5       5      R                  5       nO+[        R                  R                  U S9R                  5       nU(       a-  [        UR                  UR                  UR                  S.5      $ [        0 5      $ )Nr  r  )rG	  rH	  r.  )r   r   rv   r$  r   r  r-  r  r  r  r   r0  r1  r.  )r.  r(  s     r    get_user_profilerL	    s     OO/Ezz""477<<>288:zz##%#0668ZZ
  	
 2;r!   z/api/auth/rememberedc                  d   [         R                  R                  [         R                  5        [	        [         R                  R                  SSSS9[         R                  R                  SSSS9[         R                  R                  SSSS9[         R                  R                  SSSS9S.5      $ )	uK   Récupère les informations d'identification sauvegardées dans config.ini.r   r0  r  r   r1  r  r/  )rG	  rH	  r.  r/  )r   r   r   r   r   rv   r   r!   r    get_remembered_userrN	    s     MMv))*]]&&x&KMM%%hb%I""8^b"I}}  52 >	  r!   c                  "    [         R                  " 5       n [         R                  " U 5        S nU R                  U" 5       5        U R	                  5         g! [
         a-  n[        SU 35        [        R                  " 5          SnAgSnAff = f)z
Called as a background thread after a successful login.
1. Connects via WebSocket and fetches the live portfolio.
2. Removes from DB any WalletInvestment rows that are no longer held.
3. Recalculates PnL / total_value for every remaining position.
c            	        #    [        5       n U R                  5       I S h  vN nU(       d  [        S5        g [        S5        U R                  SS9I S h  vN nU R	                  5       I S h  vN   U(       a  [        U[        5      (       d  [        S5        g U Vs1 s H  o3R                  S5      (       d  M  US   iM!     nn[        S[        U5       S[        U5       35        [        R                  5          S n [        R                  R                  [        R                  5        [        R                  R                  S	S
S S9nU(       a>  [         R"                  R%                  US9R'                  5       nU(       a  UR(                  n[,        R"                  R%                  US9R/                  5       n	Sn
U	 H_  nUR0                  U;  d  M  [        SUR0                   SUR2                   S35        [4        R6                  R9                  U5        U
S-  n
Ma     U
(       a.  [4        R6                  R;                  5         [        SU
 S35        O[        S5        Sn[,        R"                  R%                  US9R/                  5        H  nUR<                  =(       d    SnUR>                  =(       d    SnUR@                  =(       d    SnUS:  d  MJ  US:  d  MR  X-  Ul!        URB                  X-  -
  Ul"        US:  a  URD                  X-  -  S-  OSUl#        [H        RJ                  " 5       Ul&        US-  nM     [4        R6                  R;                  5         [        SU S35        S S S 5        g  GN\ GN* GNs  snf ! [*         a  n[        SU 35         S nAGNS nAff = f! , (       d  f       g = f7f)NzD[SYNC] [ERROR] WebSocket connection failed - portfolio sync skipped.z1[SYNC] [REFRESH] Syncing portfolio after login...Tr  z@[SYNC] [WARN]  No positions returned from TR - skipping cleanup.r   z[SYNC] [OK] z ISINs currently held: r   r  r   r  z'[SYNC] [WARN]  Could not resolve user: r  r   z'[SYNC] [DEL]  Removing stale position: rq  r
  r  z[SYNC] [OK] Removed z stale position(s).z)[SYNC] [OK] No stale positions to remove.rz  r*  z![SYNC] [OK] Recalculated PnL for z position(s).)'rk  r   r3   r}  r   r  r  rv   rs   r`  r)   r.   r   r   r   r   r$  r   r  r  r-  r2   ro  r   r   rA   r   r   r  r   rp  rr  rq  r<  rs  rt  r	   r   r   )apir  fresh_positionsr  
live_isinsr9  r.  r  r6   
all_db_posremovedrx  recalculatedr  cpxbpxs                   r    _run(sync_portfolio_after_login.<locals>._run!  s    "$C!kkm+I\]EF$'$7$7t$7$DDO))+"*_d*K*KXY-<N_f)!F)_JNLZ 11HPZI[H\]^"IMM&&v'9'9:"MM--hQU-VE JJ00u0=CCE&'ddG
 .33==g=NRRT
%Cxxz1 GzQSTWT\T\S]]^_`

))#.1	 & JJ%%'0	9LMNEF  !+11;;G;LPPRCLL1cC--4CMM1cCQw37*-)*-//SY*GKNQR7377ci+@3+FX[*2//*;$!+ S 

!!#9,}UVU #"! , E O ! ICA3GHHI #"s   OM<4OM?O-N.0ON;	N9O=N0BN
A N0DN0N0#BN03
O?OOO

N-N("N0(N--N00
N>:Oz%[SYNC] [ERROR] Portfolio sync error: N)	r   r   r   r   r   r2   r3   r   r   )r   rY	  r6   s      r    sync_portfolio_after_loginr[	    su    F%%'t$<	W| 	'

 5aS9:s   AA 
B!#B		Bz/api/auth/verifyc                  \   [         R                  n U R                  S5      nU R                  S5      nU(       a  U(       d  [        SSS.5      S4$ [        R                  X5      nUR                  S5      (       a  [        S5        [        R                  " [        S	S
9R                  5         [        R                  " [        S	S
9R                  5         [        R                  " [        S	S
9R                  5         [        R                  " [        S	S
9R                  5         [        U5      $ )Nr  r  FzProcess ID and Code requiredr   rI	  r   z:[OK] Login successful. Triggering background sync tasks...Tr  )r   r   rv   r   r   r  r3   r  r  r  r  r[	  refresh_bank_forecasts_on_logincheck_macro_freshness_on_login)r5   r  r  r  s       r    auth_verifyr_	  f  s    <<D+&J88FDT53QRSUXXX"":4Fzz)JK <TJPPR :4HNNP ?MSSU >tLRRT6?r!   c                  h    [         R                  5          [        S5        [        S [        R
                  R                  [        R                  5      R                  5        5       5      n [        5       nUR                  5       nU=(       d    /  Vs/ s H(  nUR                  S5      (       d  M  US   U ;  d  M&  UPM*     nnU(       a  [        S[        U5       S35        O[        S5        SSS5        gs  snf ! , (       d  f       g= f! [         a  n[        SU 35         SnAgSnAff = f)	u   
Appelé à chaque connexion. Re-crawle toutes les sources bancaires
et compare les URLs aux entrées existantes pour détecter de nouvelles publications.
Sauvegarde uniquement les nouveaux articles trouvés.
zC[LOGIN] [BANK] Verification des nouvelles Perspectives Bancaires...c              3   `   #    U  H$  nUR                   (       d  M  UR                   v   M&     g 7fr   r   r   r  s     r    r   2refresh_bank_forecasts_on_login.<locals>.<genexpr>  s$       *i3>> *i   ..r   z[LOGIN] [NEW] z; nouvelles perspectives bancaires detectees - sauvegarde...z=[LOGIN] [OK] Perspectives bancaires a jour, aucune nouveaute.Nz7[LOGIN] [ERROR] Erreur refresh perspectives bancaires: )r)   r.   r3   r  rW  r   with_entitiesr\  r   r  r  rv   rs   r2   )existing_urlsr  fresh_resultsrO  	new_itemsr6   s         r    r]	  r]	  }  s   M__WX  *6*<*<*J*J<KbKb*c*g*g*i  M *+G#..0M)/R//a55< $%eHM$A /   s9~&66qrs UV!  "  MGsKLLMsS   D A>C>C92C9=C9-C>0D 9C>>
DD D 
D1D,,D1c                  8    [         R                  5          [        R                  " 5       [	        SS9-
  n [
        R                  R                  [
        R                  S:H  [
        R                  U :  -  5      R                  5       nU(       d"  [
        R                  R                  5       S:X  a!  [        S5        [        5         [        S5        O[        S5        SSS5        g! , (       d  f       g= f! [         a  n[        SU 35         SnAgSnAff = f)	uy   
Appelé à chaque connexion. Vérifie si les MacroData sont plus vieilles
que 24h. Si oui, relance update_macro_data().
   r"  Nr   zL[LOGIN] [DATA] Indicateurs Macro obsoletes (> 24h) - mise a jour en cours...z*[LOGIN] [OK] Indicateurs Macro mis a jour.z&[LOGIN] [OK] Indicateurs Macro a jour.z+[LOGIN] [ERROR] Erreur verification macro: )r)   r.   r	   r   r
   r  r   r3  r   r  r  r3   update_macro_datar2   )rG  staler6   s      r    r^	  r^	    s    
A__ )IB,??IOO**%%-)2F2F2RSeg  	--/14de!#BC>?   A;A3?@@As5   C7 CC&C7 &
C40C7 4C7 7
DDDz/api/auth/resendc                      [         R                  n U R                  S5      nU(       d  [        SSS.5      S4$ [        R                  U5      n[        U5      $ )Nr  FzProcess ID requiredr   rI	  )r   r   rv   r   r   r  )r5   r  r  s      r    auth_resendrn	    sL    <<D+&J53HIJCOOz*F6?r!   z/api/auth/statusc                      [         R                  R                  [         R                  5        [         R                  R	                  SSS S9[         l        [        [         R
                  5      n [        SU 05      $ )Nr   r   r   loggedIn)r   r   r   r   rv   r   boolr   )is_logged_ins    r    auth_statusrs	    sZ     MMv))*!==,,X|d,SF,,-LJ-..r!   c                    U c  g[        U [        5      (       a&  [        R                  " U S-  5      R	                  SS9$  [        U 5      R                  5       n[        R                  " SSU5      nUR	                  SS5      n[        R                  " SS	U5      n[        R                  " U5      R	                  SS9$ ! [         a     gf = f)
u  
Parse a TR timestamp string to a naive datetime.
Handles nanosecond precision (9 digits after '.') that Python's
fromisoformat rejects — truncates to at most 6 fractional digits (microseconds).
Also normalises +0000 → +00:00 and Z → +00:00.
Returns None on failure.
N     @@tzinfoz([+-])(\d{2})(\d{2})$z\1\2:\3Zz+00:00z(\.\d{6})\d+z\1)r  r  r	   r  r  r  r  r  r  r,  r2   )r  r   s     r    	_parse_tsry	    s     
z"c%%b6k2::$:GG
GMMOFF+Z;IIc8$FF?E1-%%a(000== s   A=B? ?
CCc                 
  ^ SSSSSSSSSSS.
nS nU R                  S5      nU(       Ga  U GHD  nUR                  S5      =(       d    SR                  5       nUR                  S5      =(       d    SnUS	:X  Ga  XaS'   UR                  S
5      =(       d    0 nUR                  S5      S:X  a  UR                  S5      (       a  US   US'   UR                  S5      =(       d    0 n[        U[        5      (       a  U(       a  US   O0 n[        U[        5      (       ag  US   =(       d    UR                  S5      US'   US   =(       d    UR                  S5      =(       d    SUS'   UR                  S5      (       a  US   US'   UR                  5       m[
        R                  " SU5      n	U	(       a  U" U	R                  S5      5      n
[        U4S jS 5       5      (       a  SUS'   [        U
5      US'   GM  [        U4S jS 5       5      (       a  SUS'   [        U
5      * US'   GM  XS'   GM  GM  US;   d  GM  UR                  S5      =(       d    /  GH  n[        U[        5      (       d  M  UR                  S5      =(       d    SR                  5       R                  5       nUR                  S5      =(       d    0 n[        U[        5      (       a(  UR                  S5      =(       d    SR                  5       O[        U5      R                  5       nUS ;   a  SUS'   M  US!;   a  SUS'   M  US";   a  U" U5      nUS:  a  XS#'   M  M  US$;   d  GM   U" U5      nUS:  d  GM  XS%'   GM     GMG     US   (       d?  US   (       a5  [
        R                  " S&US   5      nU(       a  UR                  S5      US'   US   S:X  a.  US#   S:  a%  US%   S:  a  US#   US%   -  nUS   S:X  a  UOU* US'   U$ U R                  S5      =(       d    SUS'   U R                  S5      US'   U R                  S5      =(       d    SUS'   U R                  S5      =(       d    SUS'   U R                  S'5      =(       d    U R                  S(5      =(       d    SUS('   U R                  S5      =(       d    0 n[        U[        5      (       a$  UR                  S)5      nUb  [        U5      US'   O*O)[        U[        [        45      (       a  [        U5      US'   [
        R                  " S&US   5      nU(       a  UR                  S5      US'   U$ !    N;= f)*u  
Normalize a TR timeline item regardless of whether it is:
  • a flat dict  (classic timelineTransactions response)
  • a sections-based dict  (timelineDetailV2 / newer timeline format)

Returns a canonical dict:
    isin      – ISIN string or ''
    icon      – icon URL string
    timestamp – ISO string or int or None
    status    – status string
    title     – header title ('You received €175.33', etc.)
    subtitle  – subtitle / subtitleText
    amount    – float  (positive = received/SELL, negative = paid/BUY, 0 = unknown)
    tx_type   – 'SELL'|'BUY'|None  (None means caller must decide)
    shares    – float (0 if unavailable)
    price     – float (0 if unavailable)
r  Nrz  )
r   r  r:  r   rC  rw  r|  tx_typerQ  r  c                     [         R                  " SS[        U 5      5      R                  SS5      n[         R                  " SU5      nU(       a  [        US   5      $ S$ !    g= f)Nz[^\d.,]r  r  r|  z[\d.]+r   rz  )r  r  r  r  r  r  )r   cleannumss      r    
_parse_num-_normalize_tr_transaction.<locals>._parse_num  sQ    z2s4y199#sCzz)U+&*E$q'N33ss   	A  A   A$r  r
  rC  r  r  r  r  r   r5   r   r:  r   r  u   [€$£]?\s*([\d]+[.,][\d]+)r  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r   r   t_lowers     r    r   ,_normalize_tr_transaction.<locals>.<genexpr>  s     ]1\A<1\r  )receivederhaltensoldverkaufSELLr{	  r|  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r	  s     r    r   r	    s     o3na'\3nr  )investedr  boughtr  r  r  BUY)r  horizontaltabler  r   )r  r	  r	  )r  r  r  r  r  )rQ  u   stückanteileanzahlrp  zshares purchasedzshares soldznumber of sharesrQ  )zprice per sharer  kursu   ausführungskurszshare pricezexecution pricezprix unitairer  zlogos/([A-Z0-9]{12})(?:/|$)subtitleTextrw  rR  )rv   r=   r  r  r  r  r  r  r  r  r  r  r  r  )r	  r  r	  r  r  sec_type	sec_titler  r5   amt_mraw_amtr  	row_key_lr  det_textrd   rc  rawamtr  r	  s                       @r    _normalize_tr_transactionr	    s   & BTRs3C vvj!HC.B557H(.BI8#(G*0b::f%);;

9@U@U"("3CKwwv,"dD))&*47DdD))'*;'7'P488K;PC$'*8}'UDHHX<N<TRTCMxx''&*6lF#//+		"A9M(Q8G]1\]]])/I),WHo3nooo).I*-g,H(/H  99GGFO1r1C%c400 !$!1!7R > > @ F F HI # 1 7RFFPQWY]F^F^F!3!9r @ @ BdghndodududwH !$??)/I"&ZZ).I" '^ ^&x0q5!h-5" 'Z Z&x0q5g,+ 2E t 6{s6{		8#f+FA
#f+ x=CCMA$5#g,:Jh-#g,.C#&y>V#;C#CM( J! 66&>/RF66+.KFF8,2HFF7O1rGFF>2NbffZ6HNBJffX$"c4  '''"C%*3ZS]  c5\**!#JCMII4c&kBAGGAJc&kJ s   U Uc                   ^+^,#    [        S5        [        S5        [        S5        [        S5        U R                  SS9I Sh  vN n[        S[        U5       S35        [        R                  " S	5      n/ S
Qn/ SQn/ nS=n=pxU GHu  n	Sn
U	R                  SS5      n[        R                  " SU5      nU(       a6  UR                  UR                  S5      5      (       a  UR                  S5      n
U
(       dP  S HJ  nU	R                  US5      nU(       d  M  UR                  [        U5      5      (       d  M?  [        U5      n
  O   U
(       d  US-  nM  U	R                  S5      =(       d    U	R                  S5      =(       d    Sn[        U5      nU(       d  US-  nGM  U	R                  S5      =(       d    0 n [        U[        5      (       a  [        UR                  SS5      5      O
[        U5      nUS:X  a  US-  nGM  U	R                  S5      =(       d    U	R                  S5      =(       d    SR                  5       nU	R                  S5      =(       d    U	R                  S5      =(       d    SR                  5       nU SU 3m+[!        U+4S jU 5       5      n[!        U+4S jU 5       5      nU(       a
  U(       d  SnOU(       a
  U(       d  SnOUS:  a  SnOSnUR#                  U
UUUS .5        GMx     [        S![        U5       S"U S#U S$U S%3	5        U(       d  [        S&5        / $ [%        U Vs1 s H  nUS'   iM
     sn5      n[        S([        U5       S)35        0 nU H+  n
['        U
5      nU(       a  UUU
'   M  [        S*U
 S+35        M-     [        S,[        U5       S-[        U5       S.35        0 m,[%        [)        UR+                  5       5      5      nU(       Ga  [-        S/ U 5       5      nU[/        S0S19-
  R1                  S25      n[2        R4                  " 5       [/        SS19-   R1                  S25      n[        S3U S4U S5[        U5       S635         [6        R8                  " [        U5      S:  a  UOUS   UUS7SS7S89n S9U R:                  ;   a  U S9   n![=        U!S:5      (       a~  U Hw  n"U"U!R:                  ;   d  M  U!U"   R?                  5        V#V$s0 s H>  u  n#n$[@        RB                  " U$5      (       a  M#  U#R1                  S25      [        U$5      _M@     sn$n#T,U"'   My     ObU!R?                  5        V#V$s0 s H>  u  n#n$[@        RB                  " U$5      (       a  M#  U#R1                  S25      [        U$5      _M@     sn$n#T,US   '   [        S;[        T,5       S<35        S>[        4U,4S? jjn&/ n'U H  nUS'   n
UR                  U
5      nU(       a  U&" UUS   5      OSn(U(S:  a  [E        US   5      U(-  OSn)US   US@   U
U=(       d    SU)U(US   SA.n*U'R#                  U*5        [        SBU*S@    SU
 SCU=(       d    SD SEUS   R1                  S25       SFU)SG SHU(SG SIUS   SJ 35        M     [        S5        [        SK[        U'5       SL35        [        S5        U'$  GNp! [         a
    US-  n GMB  f = fs  snf s  sn$n#f s  sn$n#f ! [         a  n%[        S=U% 35         Sn%A%GNGSn%A%ff = f7f)MuN  
Fetches transaction history using ONLY timelineTransactions (same WebSocket as cash-flow).
NO timelineDetailV2 calls – price/shares are resolved via yfinance outside of TR.

Steps:
  1. Get raw items from timelineTransactions  (WebSocket – already reliable)
  2. Extract ISIN from icon field, date from timestamp, amount from amount.value
  3. Determine BUY/SELL from title keywords or amount sign
  4. Batch-download price history via yfinance for each unique ISIN → ticker
  5. Derive shares = |amount| / price_on_date

Returns: [{date, type, isin, ticker, shares, price, amount}]
z5[TX_HISTORY] ========================================z[[TX_HISTORY] [START] Fetching transactions (timelineTransactions only - no detail WS calls)zH[TX_HISTORY]    Shares/prices resolved via yfinance outside TR WebSocketFrp  Nz[TX_HISTORY] [PKG] Retrieved z raw timeline items.^[A-Z]{2}[A-Z0-9]{10}$)r	  r	  r	  r	  r  )r	  r  r  r  r  r  r   r  r  zlogos/([A-Z0-9]{10,12})(?:/|$)r  )instrumentIdr   r-  r:  rN  r|  rR  rz  rC  	titleTextrw  r	  r   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r   rc   	full_texts     r    r   4fetch_full_transaction_history_v2.<locals>.<genexpr>  s     6g9ngr  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r	  s     r    r   r	    s     5f9nfr  r	  r	  )r   rN  r|  r
  z[TX_HISTORY] [SEARCH] z' BUY/SELL candidates (skipped: no_isin=z
, no_date=z, no_amount=r
  z/[TX_HISTORY] [WARN]  No valid candidates found.r   z[TX_HISTORY] ? Resolving z! unique ISINs -> Yahoo tickers...z[TX_HISTORY]   [WARN]  z+ -> no Yahoo ticker found (will skip price)z[TX_HISTORY]    r  z ISINs resolved.c              3   *   #    U  H	  oS    v   M     g7f)rN  Nr   r   r  s     r    r   r	    s     5*Qy*r  r  r  r  z.[TX_HISTORY] [DATA] Downloading price history z->z for z tickers via yfinance...T)r  ra  auto_adjustrc  threadsrd  r_   z+[TX_HISTORY] [OK] Price history loaded for z	 tickers.z.[TX_HISTORY] [WARN]  yfinance download error: r  c                    > TR                  U 0 5      n[        SS5       H)  nU[        US9-
  R                  S5      nXB;   d  M%  X$   s  $    g)z;Return closing price on or up to 7 days before target_date.r   rB  r  r  rz  )rv   r  r
   r  )rw   target_daterY  rK  r  ticker_price_historys        r    	_price_on4fetch_full_transaction_history_v2.<locals>._price_on  sQ    &**6261a[Eye44>>zJA|z! ! r!   r
  rN  r
  r   rw   rQ  r  r|  z[TX_HISTORY]   [OK] rq  r  z) date= shares=.4fz price=z amt=rr  z[TX_HISTORY] [OK] z$ total BUY/SELL transactions parsed.)#r3   r  rs   r  compilerv   r  r  r  r  ry	  r  r  r  r2   r=   r  r  r  r   r  r@  r  r
   r  r	   r  rp   r  r  r^   r_   r  r  r  )-rQ	  all_txsISIN_RESELL_KWBUY_KW
candidatescnt_no_isincnt_no_datecnt_no_amountr	  r   r  rc  fldrd   ts_rawrN  amt_objr|  rC  rw  is_sellis_buyr{	  r  unique_isinsisin_to_tickerrw   all_tickersmin_date	start_strend_strr	  close_dftkridxr  r6   r	  parsed_transactionsr  rQ  recordr	  r	  s-                                              @@r    !fetch_full_transaction_history_v2r	  X  s     

AB	
gh	
TU	
AB %%e%<<G	)#g,7K
LMjj23GAGOF J011K1+ vvfb!II7>qwwqz**771:D 5FF3O1s1v..q6D	 6 1K $<v<" 1K &&"(b	7A'47P7PU7;;w23V[\cVdF S=QM FF7O@rvvk':@bGGIFF:&F"&&*@FBMMOgQxj)	6g665f556GGGaZGG4QXYZs v 
"3z?"3 4*m:k],}o]^` a ?@	 J7Jq6J78L	%c,&7%88Y
Z[N%d+#)N4 +D61\]^  
S013|3D2EEU
VW 9;s>00234K5*55	q 11;;JG	\\^iQ&77AA*M>ykG9 U%&&>@ 	A	H++";/!3Q C #++%w<8W--*("2"22 190C0C0E90EHC')wws| !EZ 8%* D0E905  + )1(8<(8HC!wws| =Z0%*<(8<(Q8
 ?DX@Y?ZZcde%  6##D)1761V9-S-2QYQx[!E)C iilk
 	""6*$VF^$4AdV2fm_ Mi((45 6s|75+U1X;s:KM 	N! ( 
AC	s#6788\
]^	ACM =X  	QM	D 8N9<  	HB1#FGG	Hs   ?\Z3C\\;B\?;Z6:E\?[D\*A&[ [ *"[[/[ "[4["[ 5C?\6[
\	[

\[ 
\([<6\<\\c                     U (       d  / $ U R                  S S9  U(       a=  [        S[        U5       S35        U  Vs/ s H  o"S   U;   d  M  UPM     n nU (       d  / $ [        S U  5       5      nU(       d  / $ U S   S   n[        R
                  " 5       n[        S	[        U5       S
UR                  5        S35        0 n/ nU H,  n[        U5      n	U	(       d  M  XU'   UR                  U	5        M.     U(       d  / $  [        R                  " XtUSSS9S   n
U
R                  SS9R                  SS9n
[        [        5      n/ n[        R                   " XESS9n[        ["        5      nU  H+  nUS   R%                  S5      nUU   R                  U5        M-     U GH7  nUR%                  S5      nUU;   aC  UU    H:  nUS   S:X  a  US   OUS   * nXS   ==   U-  ss'   XS      S:  d  M3  SXS   '   M<     SnUR'                  5        H  u  nnUS:  d  M  UR)                  U5      nU(       d  M(   [+        U
[        R,                  5      (       a"  UU
R.                  ;   a  U
R0                  U   OSnO3UU
R.                  ;   a!  UU
R2                  ;   a  U
R0                  UU4   OSnUUU-  -  nM     UR                  U[5        US5      S.5        GM:     U$ s  snf ! [         a  n[        SU 35        / s SnA$ SnAff = f!    GM   = f)z
Reconstructs daily portfolio value from transaction history.
If filter_isins is provided, only considers transactions for these ISINs.
c                     U S   $ NrN  r   r  s    r    r  1calculate_reconstructed_history.<locals>.<lambda>  s    AfIr!   r  z? Filtering history for z current ISINs...r   c              3   *   #    U  H	  oS    v   M     g7fr   Nr   r   rx   s     r    r   2calculate_reconstructed_history.<locals>.<genexpr>%  s     4|!fI|r  r   rN  z[DATA] Fetching history for  ISINs from r   Fr  ra  rc  r	  rd  z[ERROR] YF Download error: Nffill)methodbfillr  r  ra  r!  r  r
  r	  rQ  rz  r  )r  rR  )r	  r3   rs   r  r	   r  rN  r   r  rp   r  r2   fillnar   r  r  
date_ranger  r  r_   rv   r  r  r  r  r  r  )rX  filter_isinsrx   	all_isinsr	  max_date
ticker_mapr  r   r/  r  r6   portfolio_holdingsdaily_valuesr	  
tx_by_dater  d_strrK  	total_valrQ  rw   r  s                          r    calculate_reconstructed_historyr	    s   
  -. (\):(;;LMN#/M<aV93L<MBY 4|44IRiAv&H||~H 
(Y(8X]]_DUUX
YZJG"4(3"tNN3	  2I[[h\abcjk
 
'	"	)	)	)	9B %U+L X#FJ T"JfIz*1Q  

:& J&'(yE'9((|"V9-6-%i014VW6H66S ' 	.446LD&z#-6!%b"))4423rxx-RVVAYQU:;rxx-FVXV`V`L`RVVAvI%6fgU!Ve^3	 7 	UU9a5HIJ5 8 Q N2  +A3/0	V !Ds6   KK?K  6A<L 
L*K?9L?LLc                   ^^,^- U (       d  / / 4$ U(       a  U  Vs/ s H  o"S   U;   d  M  UPM     n nU (       d  / / 4$ [        U S S9n [        S U  5       5      nU S   S   R                  SSSSSS9n[        R                  " 5       R                  SSSSS	9n0 nS
 n[        SS9 nUR                  Xs5       H!  u  mn	U	(       a  XT'   M  [        ST 35        M#     SSS5        U(       d  [        S5        / / 4$ [        [        UR                  5       5      5      n
[        S[        U5       S[        U5       SU
 35         [        R                  " [        U
5      S:  a  U
OU
S   U[        SS9-
  U[        SS9-   SSS9n[        UR                  [         R"                  5      (       a  US   m-O,SUR                  ;   a  US/   R%                  SU
S   0S9m-OUm- T-R)                  5       R+                  5       m-[         R,                  " T-R.                  5      R1                  S5      T-l        [        U-4S jT-R                   5       5      nU
 V	s/ s H  oU;  d  M
  U	PM     nn	U(       a  [        SU 35        UR3                  5        VV	s0 s H  u  pX;   d  M  X_M     nnn	U(       d  [        S5        / / 4$ U-4S jm,U,4S jn/ n/ nS nSn/ n[5        [        5      nU  HD  nUR7                  US   5      (       d  M  UUS   R9                  S!5         R;                  U5        MF     [         R<                  " XES"S#9 GH  nUR9                  S!5      nUR?                  5       nUU;   Ga^  UU    GHT  nUS   mUR7                  TS$5      nU(       d  M$  [A        [C        UR7                  S%S&5      5      5      nT," UUS   5      nUS&:X  a  [        S'US(    S)T S*35        Mq  US&:X  aN  [E        SS+5       H!  nT," UUS   [        US9-   5      nUS:  d  M!    O   US&:X  a  [        S'US(    S)T S,35        M  UU-  n[C        UR7                  S-5      =(       d    S5      nUS::  a  UnUS(   S.:X  ah  U(       a,  U(       a%  US:  a  U" UU5      n U U-
  U-  n!US U!-   -  nU U-   nOUnUR;                  TUUUUS/.5        UR;                  US.TUUUUS0.5        GMf  US(   S1:X  d  GMr  U(       a&  U(       a  US:  a  U" UU5      n U U-
  U-  n!US U!-   -  n[G        U4S2 jU 5       5      n"U"S:  a  [I        UU"-  S 5      n#OS n#/ n$U HP  n%U%S   T:X  a3  S U#-
  n&U&S3:  a&  U$R;                  0 U%EU%S-   U&-  U%S4   U&-  S5.E5        M=  M?  U$R;                  U%5        MR     U$nUR;                  US1TUUUUS0.5        U(       a  U" UU5      nGMR  SnGMW     U(       d  GM  U(       d  GM  US:  d  GM  U" UU5      n'U'U-
  U-  n(US U(-   -  S -
  S6-  n)UR;                  U[K        U)S75      S8.5        GM     [        S9[        U5       S:U(       a  US;   S<   OS= S>35        [        S?[        U5       35        U HV  n%T," U%S@   U5      n*U%SA   S:  a  U*U%SA   -  OSn+[        SBU%S    SCU%S@    SDU%SA   SE SFU*SE SGU+SE SHU%S4   SI SJU%S-   SK 35        MX     [        SLUSK 35        U(       a"  [        SMUS    35        [        SNUS;    35        UU4$ s  snf ! , (       d  f       GN4= f! [&         a  n[        SU 35        / / 4s SnA$ SnAff = fs  sn	f s  sn	nf )Ou  
Portfolio performance using Time-Weighted Return (TWR).

TWR is completely immune to cash-injection distortion.

Each lot stores:
    eur_invested  – the actual EUR paid at Trade Republic (|amount|)
    buy_yf_price  – the yfinance close price on the buy day (from THIS download)

Current value of a lot:
    lot_value(d) = eur_invested × (price(ticker, d) / buy_yf_price)

This keeps the calculation fully self-consistent within a single yfinance
download and avoids any eur/usd mix or cross-download price discrepancy.

Sub-period anchoring (key fix vs previous version):
    subperiod_start_mv = v_before_existing + abs(eur_new_cash)
Instead of recomputing from lots with potentially stale buy prices.

Returns: (daily_series, events)
    daily_series : [{'date': str, 'value': float}, ...]   TWR % from first purchase
    events       : [{'date', 'type', 'isin', 'ticker', 'shares', 'price', 'amount'}, ...]
r   c                     U S   $ r	  r   r  s    r    r  Ccalculate_portfolio_performance_from_transactions.<locals>.<lambda>  s    !F)r!   r  c              3   *   #    U  H	  oS    v   M     g7fr	  r   r	  s     r    r   Dcalculate_portfolio_performance_from_transactions.<locals>.<genexpr>  s     3
1vY
r  r   rN  N)rw	  hourminutesecondmicrosecond)r	  r	  r	  r	  c                     U [        U 5      4$ r   )r   )r   s    r    _resolveCcalculate_portfolio_performance_from_transactions.<locals>._resolve  s    )$///r!   rB  r  z"[PERF] [WARN]  No ticker for ISIN z*[PERF] [ERROR] No ticker symbols resolved.z[PERF] [OK] r  z ISINs resolved: r  r   r  FTr	  rd  )r  z([PERF] [ERROR] yfinance download error: c              3   x   >#    U  H/  nTU   R                  5       R                  5       (       d  M+  Uv   M1     g 7fr   )r  r  )r   rx   	df_pricess     r    r   r	    s-     S#4a	!8J8J8L8P8P8R#4s   *:	:z6[PERF] [WARN]  Tickers with no price data (excluded): z0[PERF] [ERROR] No tickers with valid price data.c                   > U TR                   ;  a  g[        R                  " [        US5      (       a  UR	                  S5      O[        U5      SS 5      nTU    n[        SS5       Hb  nU[        R                  " US9-
  nXSR                  ;   d  M+  UR                  U   n[        R                  " U5      (       a  MW  [        U5      s  $    g)	z>Return closing price for ticker on or up to 10 days before ts.rz  r  r  Nr   r      r  )r  r  	Timestampr^   r  r  r  	Timedeltar  r  r  r  )rw   r  r  r  rK  r   rd   r	  s          r    
_get_priceEcalculate_portfolio_performance_from_transactions.<locals>._get_price  s    ***LLGB
4K4KZ0QTUWQXY\Z\Q]^1b\Ebll..CiiGGCLwwqzz 8O " r!   c                    > SnU  H4  nUS   S::  a  M  T" US   U5      nUS::  a  US   nX#S   XCS   -  -  -  nM6     U$ )u_  
Σ lot['eur_invested'] × (price_today / lot['buy_yf_price'])
All values are in the same EUR-equivalent unit, consistent within
this single yfinance download.

When price is unavailable for a given day (market closed, data gap),
we fall back to buy_yf_price so the lot contributes ratio=1.0 (neutral)
instead of 0, which would create a phantom loss.
rz  buy_yf_pricer   rw   eur_investedr   )	lots_listdate_dtr~   lpxr	  s        r    _portfolio_valueKcalculate_portfolio_performance_from_transactions.<locals>._portfolio_value  sf     A A%AhK1BQw~&~&"/@*@AAE  r!         ?r  r  r	  r  r|  rz  z[PERF] [WARN]  Skipping r
  r   z
: amount=0   z: no price found within ?30drQ  r	  )r   rw   rQ  r	  r	  r	  r	  c              3   B   >#    U  H  oS    T:X  d  M  US   v   M     g7f)r   rQ  Nr   )r   r	  r   s     r    r   r	  ?  s!     +[A6VZIZKAhKs   gMbP?r	  )rQ  r	  g      Y@r  rN  rR  z[PERF] [OK] TWR series: z pts (Oct 2025->today), final=r  rR  r  r  z"[PERF][DEBUG] Active lots at end: rw   r	  z[PERF][DEBUG]   rq  z	) buy_px=r	  z now_px=z ratio=z	 eur_inv=rr  r	  z.6fz [PERF][DEBUG] cumulative_factor=z[PERF][DEBUG] First point: z[PERF][DEBUG] Last  point: )&r`  r  r  r	   r  r   rZ  r3   r  r@  rs   rp   r  r
   r  r  r  r  renamer2   r	  r	  r  r  tz_localizer_   r   rv   r  r  r	  to_pydatetimer  r  r  r  r  r  ).
parsed_txsr	  rx   r	  r	  r	  r	  r	  r  r/  r  r	  r6   valid_tickersmissingr   r
  lotseventscumulative_factorsubperiod_start_mvdaily_seriesr	  r  r	  d_dtrw   r|  yf_pricefwdshares_internalshares_displayv_beforehprtotal_shares_held
sell_rationew_lotsr	  	remainingv_nowcurrent_hprtwr_pctpx_nowr  r	  r	  s.                  `                            @@r    1calculate_portfolio_performance_from_transactionsr!
  l  s   0 2v!+IAyL/Ha
I2v
(;<J3
33IAv&..d1UVde.fH''QqPQ'RH J0 
	*h!h:ID##&4 :4&AB	 ; 
+ :;2v3z((*+,G	LZ)3y>*::KG9
UVkk7|a'GWQZYB//9!,,
 ckk2==11GI#WI--w
6K-LII
 !'')InnY__5AA$GIO S9#4#4SSM%BgsM)AsgGBFwiPQ-7-=-=-?X-?	3CW)$)-?JX@A2v* DF
 LT"J>>!F)$$qy))*56==a@ 
 ]]cB

:&!J&6#b1aeeHc&: ;<&vqy9S=4QvYKqjQRs?$Q|#-fai)QTBU6U#V#a<!  ,  3 861TFJfgh  #)8"3 "'quuX';!!<!Q&%4NV9% 27IA7M#3D$#?'*<<@RR)cCi8)-5->* .4* KK(,(.(7(.(0!  MM5%+/6-;hZ`#b c vY&( 27IA7M#3D$#?'*<<@RR)cCi8) ),+[+[([%(1,%(;L)Lc%R
%(
!H!V9,(+j(8I(50 ( 1"1 1"45hK	4Q45n4E	4Q1" !#  1 %OOA. " $DMM5&+/6-;hZ`#b c
 -=dD-I*-1*{ '@ 4&&+=+A$T40E #559KKK(C+,=>DMGw9J KLS CV 
$S%6$7 80<<#G,%HK L 
.s4yk
:;AhK212>1BQ1F&1^,,A 62ak] ;.)#.hvcl CSk1^+<S*A!H+VYIZ\ 	]  
,->s,C
DE+LO+<=>+L,<+=>?Y J 
+	*:  8<=2v C YsY   \\&7\
A.\ 3(\ \ 	]!]]
 ]


\
]&\=7]=]z/api/performance/marketc                     ^ [        5       mU4S jn  [        R                  " U " 5       5      n[        U5      $ ! [         a"  n[        S[        U5      05      S4s S nA$ S nAff = f)Nc                  @  >#     TR                  SS5      I S h  vN n TR                  SS5      I S h  vN nTR                  5       I S h  vN   XS.$  N: N" N! [         a6  n[        SU 35        TR                  5       I S h  vN    / / S.s S nA$ S nAff = f7f)NzIE00B53SZB19.TIBr  zLU1681046931.TIB)r  cac40z#Error fetching market performance: )r(  r   r2   r3   )
res_nasdaq	res_cac40r6   r   s      r    
fetch_data*get_market_performance.<locals>.fetch_data  s     		/$BBCUW[\\:#AABTVZ[[9'<< ][ 	/7s;<,,.   2..	/sr   BA AA AA AA BA A A 
B%!BB		BBBBBr   r7  )rk  r   runr   r2   r  )r'
  r5   r6   r   s      @r    get_market_performancer*
  {  sX    F
//{{:<(t} /Q()3../s   %9 
A%A A% A%z/api/portfolio-chartc                      [         R                  R                  SS5      R                  5       n 1 SknX;  a  [	        SS05      S4$ [
        R                  U 5      nUc  [	        SS05      S4$ [	        U5      $ )	zIProxy TR portfolio chart API for a given range (1d, 5d, 1m, 6m, 1y, max).r  r  >   r  ru  r  r  rw  r  r   zinvalid rangerI	  fetch_failed  )r   r9  rv   r=   r   r   r  )r  allowedr5   s      r    get_portfolio_chartr/
    sw     !!'40668J3G 12C77''
3D|013664=r!   z/api/tr/refresh-sessionc                  t    [         R                  5       n U (       a  [        SSS.5      $ [        SSS.5      S4$ )z@Force a session token refresh using the stored tr_refresh token.okzSession refreshed successfully.r8  r   u2   Refresh failed — no refresh token or TR refused.rI	  )r   r  r   )r1
  s    r    tr_refresh_sessionr2
    s=     
	%	%	'B	$3TUVVg2fghjmmmr!   z/api/tr-cookiesc                     [         R                  " SS9=(       d    0 n U R                  SS5      R                  5       nU(       d  [	        SS05      S4$ [
        R                  R                  S5      (       d  [
        R                  R                  S5        [
        R                  R                  SS	U5        [        [
        R                  S
5       n[
        R                  R                  U5        SSS5         SSKnUR                  SU5      nU(       a3  UR                  S5      R                  5       [
        l        S[
        l        [	        SS05      $ ! , (       d  f       Nl= f! [$         a     N*f = f)zLSave the full browser cookie string (copied from DevTools) for TR API calls.Tr  r  r  r   zempty cookiesrI	  r   r  r  Nr   ztr_session=([^;]+)r  r   r1
  )r   get_jsonrv   r  r   r   r   r  r  r  r   r   r   r  r  r  r   rx  r2   )r  
cookie_strr   _rerc  s        r    save_tr_cookiesr7
    s    4(.BD)R(..0J12C77==$$X..!!(+
MMh 4jA	f  #	&!A 
'JJ,j9#$771:#3#3#5F $(F! Hd#$$ 
'	&  s    E;AE) 
E&)
E65E6z/api/portfolio/performancec                      Sn [        SU  35        [        S[        R                  " 5       R                  S5       35        [        S[	        [
        R                  5       35        [        U 5        0 nSSS.n[        S	5        UR                  5        GH  u  p4 [        R                  " US
SSS9nUR                  (       Gd  Sn[        UR                  [        R                  5      (       aL   US   n[        U[        R                  5      (       a&  XFR                  ;   a  Xd   OUR                   SS2S4   nO(SUR                  ;   a  US   OUR                   SS2S4   nUb  UR                  (       d  UR#                  5       nUR$                  R&                  b  UR$                  R)                  S5      OUR$                  Ul        UR                  (       dc  UR                  5        VVs0 s H   u  pxUR                  S5      [+        U5      _M"     snnX'   [        SU SU S[-        X   5       S35        GM  GM  GM  GM  GM     / n
/ n[
        R                  (       d  [        S5        Oc[        S5        S n [0        R2                  " 5       n[0        R4                  " U5         UR7                  U" 5       5      u  pUR9                  5         U
(       Ga0  U
S   S/   nU
S   S0   nUS1:w  a=  U
 Vs/ s H  nUS0   [U        US/   U-
  S25      S3.PM     n
n[        S4U* S5 S6US5 S735        0 nUR                  5        H  u  nn[W        URY                  5       5      nU(       d  M(  SnU H  nUU::  a  UU   nM    O   Ub  US:X  a  UUS      nU Vs/ s H&  nUU:  d  M  U[U        UU   U-
  U-  S8-  S25      S3.PM(     snUU'   UU   (       d  M  UU   S9   S/   n[        SU S:U S[-        UU   5       S;US5 S<3	5        M     UnO0 nUR                  5        Hg  u  nn[W        URY                  5       5      nU(       d  M(  UUS      nUS:X  a  M8  U Vs/ s H  nU[U        UU   U-
  U-  S8-  S25      S3.PM      snUU'   Mi     UnSn [Z        R\                  R_                  [Z        R`                  S:  5      Rc                  5       n U (       aA  [e        S= U  5       5      n![e        S> U  5       5      n"U"U!-
  n#U#S:  a  [U        U!U#-  S8-  S?5      n[        S@U SAU (       a  W#OSSB SCU (       a  W"OSSB SD35        [        SF[g        URY                  5       5       SG[-        U
5       SHU
(       a  U
S   S0   OSI SJU
(       a  U
S9   S/   OSI SK[-        U5       3
5        [        U  S35        [i        SLUU
UUSM.SN.5      $ !   UR                   SS2S4   n GNt= fs  snnf ! [.         a  n	[        SU SU	 35         Sn	A	GMn  Sn	A	ff = f! UR9                  5         f = f! [.         Ga  n[        SU 35        [:        R<                  " 5         [        S5        [>        R@                  RC                  S5      nU(       dU   [
        RD                  RG                  [
        RH                  5        [
        RD                  RC                  SSSS 9nO!    O= fU(       a  S!U 3OS"n[K        U/ 5      =(       d    [K        S"/ 5      n[        S#U(       a  [-        U5      OS S$35        U(       a  / nU Hc  n[M        U5      nUS%   (       d  M  US&   S';   d  M%  [O        US(   5      nU(       d  M<  URQ                  UUS&   US%   US)   US*   US+   S,.5        Me     [        S-[-        U5       S.35        U(       a  [S        U5      u  p SnAGNSnAff = fs  snf s  snf s  snf ! [.         a  n$[        SEU$ 35         Sn$A$GNSn$A$ff = f! [.         aF  n	[        SOU	 35        [:        R<                  " 5         [i        SP[k        U	5      SQ.5      SR4s Sn	A	$ Sn	A	ff = f)Sz
Returns portfolio performance curve reconstructed from real trade history
fetched live via WebSocket (timelineTransactions + timelineDetailV2),
the same channel used by the cash-flow analysis.
Also returns BUY/SELL event markers for the chart.
z<============================================================r$  z[PERF] Request at %H:%M:%Sz[PERF] Session token present: r?   r  )r  zCAC 40zG[PERF][BENCH] Downloading full benchmark history (weekly, from 1985)...z
1985-01-011wkF)r  rb  rc  Nrd  r   r  z[PERF][BENCH] rq  r  z ptsz%[PERF][BENCH] [ERROR] Error fetching rm   zE[PERF][PORTFOLIO] [WARN]  No session token - portfolio curve skipped.z6[PERF][PORTFOLIO] [PLUG] Connecting to TR WebSocket...c                  h  #    [        5       n U R                  5       I Sh  vN nU(       d  [        S5        / / 4$ [        S5        [        S5        [        U 5      I Sh  vN nU R	                  5       I Sh  vN   [        S5        U Vs/ s H4  nUR                  S5      S;   d  M  UR                  S5      (       d  M2  UPM6     nn[        S	[        U5       S
35        U(       d  [        S5        / / 4$ [        S5        [        U5      u  pV[        S U 5       5      n[        S U 5       5      n[        S[        U5       S[        U5       SU SU S3	5        U(       a>  [        SUS   S    SUS   S   S S35        [        SUS   S    SUS   S   S S35        XV4$  GN GNH GN3s  snf 7f)zHOpen a fresh WebSocket connection and pull the full transaction history.NzJ[PERF][PORTFOLIO] [ERROR] WebSocket connection failed. No portfolio curve.z+[PERF][PORTFOLIO] [OK] WebSocket connected.z][PERF][PORTFOLIO] [NET] Fetching transactions via timelineTransactions + timelineDetailV2 ...z*[PERF][PORTFOLIO] [PLUG] WebSocket closed.r
  r	  r	  r   [PERF][PORTFOLIO] [DATA] z# BUY/SELL stock transactions ready.zN[PERF][PORTFOLIO] [WARN]  No stock transactions found - empty portfolio curve.zK[PERF][PORTFOLIO] [UP] Building portfolio performance curve via yfinance...c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)r
  r	  r  Nr   r   r6   s     r    r   Jget_portfolio_performance.<locals>._fetch_via_websocket.<locals>.<genexpr>  s     Dv!6e1CAAvrU  c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)r
  r	  r  Nr   r?
  s     r    r   r@
    s     Ev!6f1DAAvrU  z[PERF][PORTFOLIO] [OK] Curve: z data points, z	 events (z BUY / z SELL)z[PERF][PORTFOLIO]    First: r   rN  r   rR  +.2fr  z[PERF][PORTFOLIO]    Last : r  )	rk  r   r3   r	  r   rv   rs   r!
  r  )	rQ	  r  r

  rx   	stock_txsrJ  r
  r.	  r/	  s	            r    _fetch_via_websocket7get_portfolio_performance.<locals>._fetch_via_websocket   s    &("%++-/	 fgr6MCDuv
 $ES#II
iik!!BC(2 T
1 !f @ EFUU6] 
	 T1#i.1AAdef jkr6Mcd!RS\!] DvDDEvEE6s6{m>VYtfGE7&J K869J8K1VTUYW^M_`dLeefgh8F9K8LAfUWjY`NabfMgghij~%G 0 J!TsR   F2F$>F2F' F27F*8F2F-(F- F-CF2'F2*F2-F2z2[PERF][PORTFOLIO] [ERROR] WebSocket fetch failed: zH[PERF][PORTFOLIO] [REFRESH] Falling back to cached transactions in DB...r  r   r  r   r  r  z[PERF][PORTFOLIO] [PKG] Found z cached transactions in DB.r   r{	  r<
  r:  rQ  r  r|  )rN  r
  r   rQ  r  r|  r=
  z% BUY/SELL transactions from DB cache.rR  rN  rz  r  r
  z([PERF] Portfolio normalized: shifted by rB
  z% (first point was z%, now 0.0%)r*  r  z rebased from z pts, final=r  c              3   ^   #    U  H#  n[        UR                  =(       d    S 5      v   M%     g7fr   N)r  rs  r   r  s     r    r   ,get_portfolio_performance.<locals>.<genexpr>  s!     %Y[ceCGG,@q&A&A[   +-c              3   ^   #    U  H#  n[        UR                  =(       d    S 5      v   M%     g7frG
  )r  r<  rH
  s     r    r   rI
    s!     %Y[ceCOO,@q&A&A[rJ
  r~  z[PERF] True P&L snapshot: z% (cost=rr  u    € value=u    €)z#[PERF] [WARN]  true_pnl_pct error: z[PERF] Summary -> benchmarks=z | portfolio_pts=z | portfolio_start=r  z | portfolio_final=z
%| events=r   )
benchmarksr  r
  true_pnl_pctr4  z[PERF] [ERROR] Fatal error: r   r8  r7  )6r3   r	   r  r  rq	  r   r   r_   rp   r  r  r  r  r  r  r  r
  r  r  tzr
  r  rs   r2   r   r   r   r   r   r   r   r   r   rv   r   r   r   r/   r	  ry	  r  r!
  r  r`  r  ro  r   r3  rp  r   r  r  r   r  )%sepcomparison_databenchmarks_tickersrA   r@   r5   rk  r	  r  r6   user_serieschart_eventsrD
  r   ws_errr.  r   raw_txsfallback_parsedr	  r  r  	first_twrportfolio_start_dateptrebased_benchmarks
price_dictsorted_dates	ref_pricer	  	final_valrM
  wallet_invstotal_pnl_eurtotal_value_eurtotal_cost_eurcal_errs%                                        r    get_portfolio_performancerd
    s   |D3%j"8<<>#:#::#F"GHI.tF4H4H/I.JKLc
 (/7CWY.446LDK{{6X]^zzz!F!$,,>>5%)']F)&",,??;A^^;SY_YdYdefhieiYj 3:T\\2IgtyyYZ\]Y])&,,!'IOIdv||'?'?'Ejpjvjv%|| 1750>HC !$Z 8%* D0>5O1 "N4&6(#c/J_F`Eaae"fg  , 3?) " 7> ##YZJK&&R,--/&&t,!040G0G,.1-K JJLV  $Aw/I#.q>&#9  C *)  Z%7i8OQR2ST)   @)D@Q R**3D)9G H
 "$$3$9$9$; j%joo&78# !	)E 44$.u$5		 * $	Q *<? ;I ".,
 ". 44!&!&
5(9I(E'RUX'XZ[!\ ".,"4( &d++ 24 8 <W EIN4&?S>TTV !3D!9:;<	RVGWWXZ [9 %<> 1O "$$3$9$9$; j%joo&78#&|A7	> "., ". ##Z%6%Bi$ORU$UWXY[!-,"4( %< 1O
 	C*00778H8Q8QTU8UVZZ\K"%%Y[%Y"Y"%%Y[%Y"Y"1M"A!A%#(-.*HC)OQR#SL.|n =-8>aD E.9?qEUL M 	-d?3G3G3I.J-K L!!$[!1 2 3#=H;q>&#9e"T U#?J;r?7#;PU"V Wl+,	. 	/
 	Rj!0!,!-!-	
  	k5%)YYq!t_F5
  K=dV2aSIJJK~ JJL #J6(ST##% `a++N;**6+=+=> & 1 1(NUY 1 Z8=,UG4CT)#r2\oFWY[6\6ws7|TU6VVqrs&(O%5b9V999)H )!K. 9A q / 6 6././	l./i./k./j./k8" !# & 5c/6J5KKpqr&4e+51C#d6,2,,  	C7yABB	C(  D,QC01'c!f=>CCDs>  B` AW 0A
V?:B4W .'W&W ;A`  +X ,X
 X "` 6"_A>` 
_$_` B` %_?` B/_ =B` ?WW  
X*X;` X` 
XX _
*A_?A[_[A4___(A_?` _

` 
_?&_:4` :_??` 
a;aaaz/api/auth/logoutc                  F    [         R                  S5        [        SS05      $ )Nr  r   T)r   r  r   r   r!   r    auth_logoutrf
    s     
b!It$%%r!   z/api/refresh/portfolioc                  Z  ^ [         R                  (       dU  [         R                  R                  [         R                  5        [         R                  R                  SSS S9[         l        [         R                  (       d  [        SSS.5      S4$ [        R                  " 5       mU4S jn [        R                  " U S	9nUR                  5          TR                  S
S9nU(       a  [        SSS.5      $ [        SSS.5      S4$ ! [        R                   a    [        SSS.5      s $ f = f)Nr   r   r   FzNot logged inr   r  c                    > [         R                  " 5       n [         R                  " U 5         U R                  [        R                  5       5      nU(       d"  TR                  S5        U R                  5         g TR                  S5        U R                  [        R                  5       5        U R                  [        R                  5       5        U R                  [        R                  5       5        U R                  5         g ! [         aY  n[        SU 35        TR                  5       (       a  TR                  S5        U R                  5          S nAg !     S nAg = fS nAff = f)NFTz'Error in background portfolio refresh: )r   r   r   r   r   r   putr   r}  r  r2   r3   r  )r   r  r6   conn_results      r    run_async_with_check5refresh_portfolio_route.<locals>.run_async_with_check  s    %%'t$	//0@AI&

 OOD! ##F$:$:$<=##F$8$8$:;##FLLN3JJL 	;A3?@  ""&D	s7   AD :B
D 
E(4E#EE E# E##E(r  r   r  TzPortfolio refresh started)r   rj  z#Connection failed (Session invalid)z)Refresh started (timeout waiting for ack))r   r   r   r   r   rv   r   queueQueuer  r  r  Empty)rk
  threadis_connectedrj
  s      @r    refresh_portfolio_routers
    s     6--.%}}00<RV0W5?CDcII ++-K4 %9:F
LLN
b"r2t8STUUu7\]^`ccc;; b 44_`aabs   #D 5D "D*)D*c                  V   [        S5        [        S5        [        S5        [        S[        R                  " 5        S[        R                  " 5        35        [        S[        R                  " 5        35        [        S[
        R                  " 5        35        [        (       a3  [        R                  " 5       R                  S-  n [        SU S	 S
35        O[        S5        [        (       a  [        S[        R                   35        [        R                  R                  5       n[        SU 35        U(       aU  [        S[        R                  R                  S5       35        [        S[        R                  R                  5        35        O[        S5        [        S5        g )Nz2==================================================zSYSTEM SPECIFICATIONSzOS: r   zProcessor: zCPU Cores: i   @zRAM: rr  z GBz-RAM: psutil not installed (cannot detect RAM)zPyTorch Version: zCUDA Available: zGPU: r   zCUDA Device Count: zPyTorch: Not installed)r3   r'  r%  release	processormultiprocessing	cpu_countpsutilvirtual_memoryr~   torch__version__cudais_availableget_device_namedevice_count)ram_gb
cuda_avails     r    print_system_specsr
    s;   	&M	
!"	&M	D"#1X%5%5%7$8
9:	K**,-
./	K1134
56v&&(..':fS\%&=>u!%"3"3!456ZZ,,.
 -.E%**44Q789:'

(?(?(A'BCD&'	&Mr!   c                  z   [         b  [         $ [        S5         Sn [        (       a0  [        R                  R	                  5       (       a  Sn [        S5        [
        (       a  [        c  [        S5        g [        SSU S9q [        S	5        [         $ ! [         a  n[        S
U 35        S q  S nA[         $ S nAff = f)Nz#Initialisation du modele FinBERT...r  r   zUtilisation du GPU pour FinBERTu6   [WARN] transformers not available — FinBERT disabledzsentiment-analysiszProsusAI/finbert)modeldevicezFinBERT charge avec succes.z&Erreur lors du chargement de FinBERT: )finbert_pipeliner3   r{
  r}
  r~
  TRANSFORMERS_AVAILABLEhf_pipeliner2   )r
  r6   s     r    load_finbertr
  1  s    #	
/0 5UZZ,,..F34%%)<JK&';CU^de+,    6qc:; s   AB 5B 
B:B55B:c                  f    [        5         [        R                  " [        SS9R	                  5         g )NTr  )r
  r  r  r
  r  r   r!   r    init_app_background_tasksr
  J  s!    L6<<>r!   c                     [         (       d  [         c   [         (       a  U (       d  g [        U SS 5      nUS   nSU;   a  [        US   5      US'   U$ ! [         a  n[        SU 35         SnAgSnAff = f)z,Analyse le sentiment d'un texte avec FinBERTN   r   rk  zErreur analyse FinBERT: )r
  r  r2   r3   )r   r  r\  r6   s       r    ry  ry  N  s      #4 #4:.ajc> W.CL
 (,-s   +A 
A6A11A6c                     [         R                  R                  U 5      (       a+  [        U SSS9 n[        R
                  " U5      sSSS5        $ 0 $ ! , (       d  f       0 $ = f! [         a  n[        SU  SU 35        0 s SnA$ SnAff = f)z-Charge un fichier JSON, retourne {} si absentrO  r  encodingNzErreur lecture rm   )r   r   r   r   r   loadr2   r3   )filenamer   r6   s      r    load_json_filer
  o  sw    77>>(##hg6!yy| 76	 76	 zA3/0	s@   /A% A	A% A% 
A"A% "A% %
B/BBBc                   8    \ rS rSrS rS rS rS rS rS r	Sr
g	)
YouTubeLiveStreami  c                 ^    Xl         [        R                  " SS9U l        SU l        S U l        g )Nr   )maxsizeF)r   rn
  ro
  frame_queuerunningcapture)r	  r   s     r    r<  YouTubeLiveStream.__init__  s&     ;;r2r!   c                     SSSS.n[         R                  " U5       nUR                  U R                  SS9nUS   sS S S 5        $ ! , (       d  f       g = f)Nzbest[height<=720]T)formatquietno_warningsF)r  r   )yt_dlp	YoutubeDLextract_infor   )r	  ydl_optsydlrr   s       r    get_stream_url YouTubeLiveStream.get_stream_url  sK    1DQUVh'3##DHHu#=D; (''s   A
Ac                    U R                  5       n[        R                  " U5      U l        U R                  R	                  5       (       d  [        S5      eSU l        [        R                  " U R                  SS9R                  5         U $ )Nu   Flux vidéo inaccessibleTr  )r
  cv2VideoCapturer
  isOpenedr2   r
  r  r  _capture_framesr  )r	  
stream_urls     r    r  YouTubeLiveStream.start  sl    ((*
''
3||$$&&677 4 4TBHHJr!   c                    U R                   (       a  U R                  R                  5       u  pU(       aV  U R                  R	                  5       (       a   U R                  R                  5         U R                  R                  U5        OB[        R                  " S5         U R                  5       n[        R                  " U5      U l        U R                   (       a  M  g g ! [        R                   a     Nf = f! [         a     N;f = f)Nrg   )r
  r
  r   r
  full
get_nowaitrn
  rp
  ri
  r  r  r
  r
  r
  r2   )r	  retframer
  s       r    r
  !YouTubeLiveStream._capture_frames  s    ll**,JC##((**((335   $$U+

1!%!4!4!6J#&#3#3J#?DL lll !;;  ! s$   C" "+C< "C98C9<
D	D	c                 j     U R                   R                  SS9$ ! [        R                   a     g f = f)Nr   r  )r
  rv   rn
  rp
  r  s    r    r   YouTubeLiveStream.read  s7    	##'''33{{ 		s    22c                 j    SU l         U R                  (       a  U R                  R                  5         g g )NF)r
  r
  ru
  r  s    r    stopYouTubeLiveStream.stop  s%    <<LL  " r!   )r
  r
  r
  r   N)r  r  r  r  r<  r
  r  r
  r   r
  r  r   r!   r    r
  r
    s     	$#r!   r
  c                     [         R                  5          [        SU S[        [        R                  " 5       5       3U[
        R                  " 5       SSUS9n[        R                  R                  U5        [        R                  R                  5         S S S 5        g ! , (       d  f       g = f! [         a  n[        SU 35         S nAg S nAff = f)NBloomberg Livebloomberg_live_r  rz  )rB  rC  r   rD  rE  rF  rG  rH  zDB Error save news: )r)   r.   r@  r  r  r	   r  r   r   r   r   r2   r3   )rC  ticker_fragments
ai_summaryr  r6   s        r    db_save_news_segmentr
    s    *__'%c$))+&6%78"%\\^# # 0	D JJNN4 JJ   *$QC())*s5   B0 B BB0 
B-)B0 -B0 0
C:CCc                 D    [         R                  5          [        R                  R	                  SS9R                  [        R                  R                  5       5      R                  U 5      R                  5       nU Vs/ s Hp  nUR                  (       a  UR                  R                  5       OSUR                  UR                  UR                  [        UR                  =(       d    / 5      S.PMr     snsS S S 5        $ s  snf ! , (       d  f       g = f!   / s $ = f)Nr
  )rB  r  )r:  
main_titler
  r
  fragment_count)r)   r.   r@  r   r  r  rE  r  rC  r   r  rC  rH  rD  rs   )rC  r_   r  s      r    db_get_news_segmentsr
    s    __^^--5E-FOOPXPePePjPjPlmsstyz~~  AU  1 =>NNann668PR ww%&%6%6 yy#&q'8'8'>B#?   	s<   D A*D A7D7D9	D D
DD D Dc                   0    \ rS rSrSS jrS rS rS rSrg)	
NewsLoggeri  c                     Xl         g r   	json_file)r	  r
  s     r    r<  NewsLogger.__init__  s    "r!   c                     S[        5       0$ )NrL  )r
  r  s    r    	load_dataNewsLogger.load_data  s    !5!788r!   c                     g r   r   r  s    r    	save_dataNewsLogger.save_data      r!   c                     [        XU5        g r   )r
  )r	  rC  r
  r
  s       r    add_news_segmentNewsLogger.add_news_segment  s    UjAr!   r
  N)r  )	r  r  r  r  r<  r
  r
  r
  r  r   r!   r    r
  r
    s    #9Br!   r
  c                       \ rS rSrSr0 SS_SS_SS_S	S
_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS _S!S"_S#S$_S%S&S'S(S)S*S+S,S-S..	ErS/ rS0 rS1 rS2 r	S3 r
S4 rS5 rSDS6 jrS7 rS8 rS9 rSES; jrSES< jrS= rS> rSES? jrSES@ jrSA rSB rSCrg:)FCapitolTradesScraperi  u@   Scraper pour Capitol Trades - Trades des politiciens au CongrèszAT&T IncTzAbbott LaboratoriesABTzAdvanced Micro Devicesr  r  BABAzAlphabet IncGOOGLr  AMZNz	Apple IncAAPLzBroadcom IncAVGOzChevron CorporationCVXzCisco SystemsCSCOz	Eli LillyLLY
ExxonMobilXOMzGE AerospaceGEzIntel CorporationINTCzJPMorgan Chaser  zJohnson & JohnsonJNJzMeta PlatformsMETAMSFTNVDAPGTSLAKOHDDISWMTV)	r  NvidiazProcter & Gamblez	Tesla InczThe Coca-Cola CompanyzThe Home DepotzThe Walt Disney CompanyzWalmart InczVisa Incc                     SU l         SS0U l        SU l        SU l        U R	                  5       U l        U R                  5       U l        g )Nzhttps://www.capitoltrades.comr   r   zcapitol_trades_cache.jsonzall_issuers.json)r;  r   
cache_fileall_issuers_file_load_cache
cache_data_load_all_issuersall_issuersr  s    r    r<  CapitolTradesScraper.__init__  sM    7  L
 6 2**,113r!   c                 @    [         R                  R                  U R                  5      (       a5  [	        U R                  SSS9 n[
        R                  " U5      sSSS5        $  / $ ! , (       d  f       / $ = f! [         a  n[        SU 35         SnA/ $ SnAff = f)u%   Charge la liste complète des issuersrO  r  r
  Nz,[ERROR] Erreur chargement all_issuers.json: )	r   r   r   r
  r   r   r
  r2   r3   )r	  r   r6   s      r    r
  &CapitolTradesScraper._load_all_issuers  s    	Fww~~d3344$//wG199Q< HG 5
 		 HG 	  	F@DEE		Fs6   AA: A(	A: (
A72A: 7A: :
BBBc                 "    [        S0 0 SS.5      $ )z"Charge le cache local depuis la DBcapitol_trades_cacheN)issuersissuers_indexrU  )r/   r  s    r    r
   CapitolTradesScraper._load_cache%  s    52XZlp7qrrr!   c                 0    [        SU R                  5        g)z$Sauvegarde le cache local dans la DBr
  N)r9   r
  r  s    r    _save_cache CapitolTradesScraper._save_cache)  s    .@r!   c                     U(       d  gU R                   R                  5        HM  u  p#UR                  5       UR                  5       ;   d$  UR                  5       UR                  5       ;   d  MK  Us  $    g)u2   Extrait le ticker à partir du nom de la compagnieN)NAME_TO_TICKERr_   r=   )r	  r  rA   rw   s       r    _match_ticker_from_name,CapitolTradesScraper._match_ticker_from_name-  s\     !//557LDzz||1133|7I7I7Ktzz|7[ 8 r!   c                     UR                  SSS9n[        R                  " SU[        R                  S9nU(       a  [	        UR                  S5      5      $ g)u$   Détecte la pagination 'Page X of Y'r   Tr  zPage\s+\d+\s+of\s+(\d+))flagsr  )r\  r  r  
IGNORECASEr  r  )r	  ra  r   rc  s       r    _get_total_pages%CapitolTradesScraper._get_total_pages9  sC    }}S}-II0$bmmLqwwqz?"r!   c           	      \   / nUR                  SSS9 H  nUS   n[        R                  " SUR                  5       5      nU(       d  M6  UR	                  S5      nUR                  SSS9=(       d    S	nS	nUR                  5       n	U	(       aO  [        R                  " S
U	R                  SSS95      n
U
(       a#  U
R	                  S5      R                  S5      S   nUR                  UUUU R                   U 3S.5        M     0 nU H
  nXUS   '   M     [        UR                  5       5      $ )z9Extrait tous les issuers visibles depuis une page /tradesr  Threfr  z^/issuers/(\d+)$r  r   r  Nz([A-Z.\-]+:[A-Z]{2}):r   )	issuer_idrA   rw   r   r  )r  r  r  r  r  r\  find_parentr  r  r  r;  r  r@  )r	  ra  r
  r  r  rc  r  rA   rw   parenttmatchby_idits                r    _extract_trades_page_issuers1CapitolTradesScraper._extract_trades_page_issuersA  s   s.AV9D,djjl;AqGGAJ	zz#Tz2:d YY'>PS[_@`aF!'a!6!6s!;A!>!* $"mm_TF3	   /. B%'"[/" ELLN##r!   c           	      d   U R                    S3n [        SU S35        [        R                  " X0R                  SS9nUR                  5         [        UR                  S5      n[        S5        U R                  U5      nUb  [        Xq5      n[        SU 35        / nUR                  U R                  U5      5        [        S[        U5       S35        [        SUS-   5       H  n	U SU	 3n
 [        SU	 S35        [        R                  " XR                  SS9nUR                  5         [        UR                  S5      nU R                  U5      nUR                  U5        [        SU	 S[        U5       S35        [        R                   " U5        M     0 nU H
  nXUS   '   M     [        S[        U5       35        [#        UR%                  5       5      $ ! [         a  n[        SU S	U 35        / s S
nA$ S
nAff = f! [         a  n[        SU	 SU 35         S
nAGMD  S
nAff = f)uL   Parcourt /trades pour récupérer automatiquement les issuers avec leurs IDsz/trades?assetType=stockz[SCRAPER] Fetching r   r  r   rQ  z"[SCRAPER] Got response, parsing...z[ERROR] Echec d'acces rm   Nz[SCRAPER] Total pages: z[SCRAPER] Page 1: found z issuersr  r  z&page=z[SCRAPER] Fetching page z[SCRAPER] Page z: found z[WARN] Page trades z
 ignoree: r  z [SCRAPER] Total unique issuers: )r;  r3   r   rv   r   r  r   rP  r2   r	  r  rn  r  rs   r  r  r  r  r@  )r	  	max_pagesdelaybase_trades_urlr   ra  r6   total_pagesr
  r1  page_urlrO  psouppage_issuersr  r  s                   r    collect_issuers_from_trades0CapitolTradesScraper.collect_issuers_from_tradesa  s   !]]O+BC	''8<=<<rRD!!# }=D68
 ++D1 k5K'}564<<TBC([)9(:(CD ![1_-D)*&7H0c:;LL<<L""$%aii?#@@G""<0vXc,6G5HQR

5! .  B%'"[/"  	0U=>ELLN##I  	*?*;2aSABI	4  +D6A3?@s7   AG 1B'H
H(H :H H
H/H**H/c                     U(       d  / $ UR                  5       n/ nU R                   Hx  nUR                  SS5      R                  5       nUR                  S5      (       a   UR                  SS5      R                  5       OSnX&:X  d  X%;   d  Mg  UR                  U5        Mz     U(       dP  [	        SU S35        U R                  U5      nU(       a)  [	        S[        U5       S35        UR                  U5        USS	 $ )
zUCherche les issuers par nom ou ticker (case-insensitive, partial match) + Live SearchrA   r  rw   z[SCRAPER] No local match for 'z', trying LIVE search...z[SCRAPER] Found z live resultsNr   )r=   r
  rv   r  r3   _search_live_issuerrs   rn  )r	  search_termsearch_lowerr  issuerrA   rw   live_resultss           r    search_issuer_by_name*CapitolTradesScraper.search_issuer_by_name  s    I"((* &&F::fb)//1D9?H9M9MVZZ"-335SUF %)=v& ' 3K=@XYZ 44[A\)#l*;)<MJK- s|r!   c                 p  ^  U R                    SU 3n[        R                  " X R                  SS9nUR                  S:w  a  / $ [        UR                  S5      n/ nUR                  SSS9nU GH  nUS	   nUR                  S
5      (       d  M!  [        UR                  S5      5      S:X  d  MA  UR                  S5      S   n	U	(       a  [        U	5      S:  a  Mm  UR                  SS9n
SnU
R                  5       nUR                  5       nSnX;   a  SnU(       d  U
R                  S5      S   R                  5       nU R                  R                  U5      nU(       d<  U R                  R                  5        H  u  nnUR                  5       U;   d  M  Un  O   U(       a  UR                  5       U:X  a  SnU(       d  SU
;   a  UR!                  5       U
;   a  SnU(       d  GMx  UR!                  5       nSU
;   aO  U
R                  S5      n[        U5      S:  a.  US   R                  S5      S   nUR#                  5       (       a  UnO	U(       a  UnU
U	USS.m[%        U4S jU 5       5      (       a  GM
  UR'                  T5        GM     U$ ! [(         a  n[+        SU 35        / s SnA$ SnAff = f)z<Recherche 'live' sur CapitolTrades si le cache ne donne rienz/issuers?q=r   r   r   rQ  r  Tr  r  	/issuers/r  r}  r  r  FNr   r   r  US)rA   r  rw   ra   c              3   8   >#    U  H  oS    TS    :H  v   M     g7f)r  Nr   )r   r   r  s     r    r   ;CapitolTradesScraper._search_live_issuer.<locals>.<genexpr>  s     #]Q\AkNd;6G$GQ\s   z[SCRAPER] Live search error: )r;  r   rv   r   r   r   rP  r  r$  rs   r  r\  r=   r  r  r_   r'  isupperr  r  r2   r3   )r	  r   r   rO  ra  found_itemslinksr  r  r  	name_textmatch_found
name_cleanquery_lowerknown_ticker
first_wordr   r  rw   r  	pre_colonr6   r  s                         @r    r"  (CapitolTradesScraper._search_live_issuer  s{   U	mm_Kw7Sc<<DQ$!!))];T[ ]]3T]2UVOOK00SC5IQ5N!%C!4Y &Y!);X!%T!:Y $)["+//"3Z#(;;=[$(\ $1'+ (&/ooc&:1&=&H&H&J(,(;(;(?(?
(K !--1-@-@-F-F-Hc$'IIK:$=47\%* .I
 )\-?-?-A[-P+/[ (C9,<!KKMY6+/[# #(++-9,%.__S%9U #E
Q-21X^^C-@-D$-$5$5$7$7.7V*&2V &/*3'-(,	! !$#]Q\#] ] ]'..t4E H   	1!56I	sF   AJ AJ J 0C#J AJ 'BJ 9J 
J5J0*J50J5c           
         U(       d  gUR                  5       nU R                   H  nUR                  S5      (       aQ  UR                  S5      R                  5       U:X  a.  [        SU SUR                  S5       SUS    S35        US   s  $ UR                  SS	5      R                  5       nUR	                  U5      (       d  X$;   d  M  [        S
U SUR                  S5       SUS    S35        US   s  $    [        SU S35        g)u%   Récupère l'issuer_id pour un tickerNrw   z#[SCRAPER] Found exact ticker match rm   rA   z (ID: r  r
  r  z[SCRAPER] Found name match z
[SCRAPER] z
 not found)r=   r
  rv   r3   r$  )r	  rz  r#  r%  rA   s        r    get_issuer_id_for_ticker-CapitolTradesScraper.get_issuer_id_for_ticker  s    $))+&&Fzz(##

8(<(B(B(D(S;M?"VZZX^M_L``fgmnygzf{{|}~k** ::fb)//1D{++{/B3M?"VZZPVEWDXX^_efq_r^sstuvk** ' 	
=/45r!   Nc                    U R                    SU 3n [        R                  " X0R                  SS9nUR	                  5         [        UR                  S5      nU R                  XR5      nU R                  U5      nU R                  U5      nUUU[        R                  " 5       R                  5       S.n	U(       aQ  XR                  S   U'   [        R                  " 5       R                  5       U R                  S'   U R                  5         U	$ ! [        R                  R                    aU  n
[#        SU
 35        U(       a6  X R                  R                  S0 5      ;   a  U R                  S   U   s S	n
A
$  S	n
A
g	S	n
A
ff = f)
u.   Scrape les données d'un émetteur spécifiquer*  r   r   rQ  r%  r  
statistics
scraped_atr
  rU  Erreur Capitol Trades: Nr;  r   rv   r   r  r   rP  _extract_issuer_info_extract_trades_extract_statisticsr	   r  r  r
  r   r  RequestExceptionr3   r	  r  rz  r   r   ra  issuer_datar  rm  r  r6   s              r    scrape_issuer"CapitolTradesScraper.scrape_issuer  H   y4"	||CrJH%%' !1!1=AD 33DHK ))$/F ,,T2E & #&lln668	F <B	*=92:,,.2J2J2L/  "M""33 	+A3/0//2E2EiQS2T!Ty1-@@	   C9D F +AE;0F ;F c                 h   USSS.nUR                  S5      nU(       a  UR                  R                  5       US'   UR                  S[        R
                  " S5      S9nU H  nUR                  5       nS	U;   a;  [        R                  " S
U5      nU(       a  [        UR                  S5      5      US'   SU;   a2  [        R                  " SU5      n	U	(       a  U	R                  S5      US'   SU;   a  SUS'   SU;   d  M  SU;   a"  UR                  S5      S   R                  5       OSUS'   M     U$ )0   Extrait les informations de base sur l'émetteurNrQ   rw   rA   ra   h1rA   divzissuer|cardr  z
Last Pricez([\d.]+)r  rW  r  z([\d.]+[BMK])
market_capCountryra   r3  r/  )r  r   r  r  r  r	  r\  r  r  r  r  )
r	  ra  rz  issuer_inforC  info_sectionsr  r   price_match	cap_matchs
             r    rB  )CapitolTradesScraper._extract_issuer_infoG  s"    $&
 		$"'**"2"2"4K eBJJ}4MN$G##%Dt# iiT:05k6G6G6J0KK-t#II&6=	090BK-D )8I&$IPTXtzz'':1'='C'C'E^bG$! %$ r!   c                    / nUR                  S5      nU(       d  U$ UR                  S5      SS nU GH:  nUR                  S5      n[        U5      S:  d  M&  0 nUS   R                  S5      nU(       a?  UR                  R	                  5       US	'   U R
                  UR                  S
S5      -   US'   US   R                  5       n	SU	;   a  SUS'   OSU	;   a  SUS'   SU	;   a  SUS'   OSU	;   a  SUS'   [        R                  " SU	5      n
U
(       a  U
R                  S5      US'   US   R                  R	                  5       US'   US   R                  R	                  5       US'   US   R                  R	                  5       n[        R                  " SU5      nU(       a  [        UR                  S5      5      US'   US   R                  R	                  5       R                  5       US'   US   R                  R	                  5       US'   [        U5      S:  a  US   R                  S5      OSnU(       a"  U R
                  UR                  S
S5      -   US'   UR                  U5        GM=     U$ ) *Extrait toutes les transactions du tableaur  r  r  Nr  r  r   r  politician_namer  r  politician_url
RepublicanpartyDemocratHousechamberSenate(House|Senate)([A-Z]{2})r  r/  r  tradedr}  (\d+)filed_after_daysr~  r
  rg   size
detail_urlr  r  rs   r   r  r;  rv   r\  r  r  r  r  r=   r  )r	  ra  r  r  r  r  r  r  politician_link
party_infostate_matchfiled_after
days_matchdetail_links                 r    rC  $CapitolTradesScraper._extract_tradesk  sK    		'"M~~d#AB'C<<%D4yA~ #'q',,s"3"/>/C/C/I/I/KE+,.2mmo>Q>QRXZ\>].]E*+ "!W--/
:-%1E'N:-%/E'Nj('.E)$+'/E)$ !ii(CZP%0%6%6q%9E'N &*!W\\%7%7%9k" #'q',,"4"4"6h #1gll002YYx=
03J4D4DQ4G0HE,- !%Q 2 2 4 : : <f !%Q 2 2 4f 47t9q=d1gll3/d*.--+//&RT:U*UE,'e$g j r!   c                    SSSS.SSSS.SSSSS.nUR                  5       n[        R                  " SU[        R                  5      nU(       a`  [	        UR                  S5      5      US   S'   [	        UR                  S	5      5      US   S
'   [	        UR                  S5      5      US   S'   [        R                  " SU[        R                  5      nU(       a`  [	        UR                  S5      5      US   S'   [	        UR                  S	5      5      US   S
'   [	        UR                  S5      5      US   S'   [        R                  " SU5      nU(       a:  [	        UR                  S5      5      US'   [	        UR                  S	5      5      US'   [        R                  " SU5      nU(       a  UR                  S5      US'   [        R                  " SU5      nU(       a  [	        UR                  S5      5      US'   U$ )!Extrait les statistiques globalesr   r~   r  r  N)	democratsrepublicanstotal_tradestotal_filingstotal_volumetotal_politicians;Trades by Democrats\s*(\d+)\s*Trades.*?Buy(\d+).*?Sell(\d+)r  rs  r~   r  r  r}  r  =Trades by Republicans\s*(\d+)\s*Trades.*?Buy(\d+).*?Sell(\d+)rt  z (\d+)\s*Trades\s*(\d+)\s*Filingsru  rv  z\$([\d.]+M)rw  z(\d+)\s*Politiciansrx  r\  r  r  DOTALLr  r  )	r	  ra  rm  r   	dem_match	rep_matchtotal_matchvolume_match	pol_matchs	            r    rD  (CapitolTradesScraper._extract_statistics  s    $%Q:%&q!< !"
 }} II\^bdfdmdmn	*-iooa.@*AE+w'(+IOOA,>(?E+u%),Y__Q-?)@E+v& II^`dfhfofop	,/	0B,CE- )*-iooa.@*AE- '+.yq/A+BE- ( ii CTJ$'(9(9!(<$=E.!%():):1)=%>E/" yy6$0$6$6q$9E.! II4d;	),Y__Q-?)@E%&r!   c                    U R                    SU 3n [        R                  " X0R                  SS9nUR	                  5         [        UR                  S5      nU R                  XR5      nU R                  U5      nU R                  U5      nUUU[        R                  " 5       R                  5       S.n	U(       aQ  XR                  S   U'   [        R                  " 5       R                  5       U R                  S'   U R                  5         U	$ ! [        R                  R                    aU  n
[#        SU
 35        U(       a6  X R                  R                  S0 5      ;   a  U R                  S   U   s S	n
A
$  S	n
A
g	S	n
A
ff = f)
uH   Scrape les données d'un émetteur spécifique (ex: AT&T avec ID 429914)r*  r   r   rQ  r=  r
  rU  r@  NrA  rF  s              r    rH  rI    rJ  rK  c                 |    USSS.nUR                  S5      nU(       a  UR                  R                  5       US'   U$ )rM  NrQ   rN  rO  rA   )r  r   r  )r	  ra  rz  rS  rC  s        r    rB  rW    sC     $&
 		$"'**"2"2"4Kr!   c                 L   / nUR                  S5      nU(       d  U$ UR                  S5      SS nU GH  nUR                  S5      n[        U5      S:  d  M&  0 nUS   R                  S5      nU(       a?  UR                  R	                  5       US	'   U R
                  UR                  S
S5      -   US'   US   R                  5       n	SU	;   a  SUS'   OSU	;   a  SUS'   SU	;   a  SUS'   OSU	;   a  SUS'   [        R                  " SU	5      n
U
(       a  U
R                  S5      US'   US   R                  R	                  5       US'   US   R                  R	                  5       US'   US   R                  R	                  5       n[        R                  " SU5      nU(       a  [        UR                  S5      5      US'   US   R                  R	                  5       R                  5       US'   US   R                  R	                  5       US'   UR                  U5        GM     U$ )rY  r  r  r  Nr  r  r   r  rZ  r  r  r[  r\  r]  r^  r_  r`  ra  rb  r  r/  r  rc  r}  rd  re  r~  r
  rg   rf  rh  )r	  ra  r  r  r  r  r  r  ri  rj  rk  rl  rm  s                r    rC  ro    s	    		'"M~~d#AB'C<<%D4yA~ #'q',,s"3"/>/C/C/I/I/KE+,.2mmo>Q>QRXZ\>].]E*+ "!W--/
:-%1E'N:-%/E'Nj('.E)$+'/E)$ !ii(CZP%0%6%6q%9E'N &*!W\\%7%7%9k" #'q',,"4"4"6h #1gll002YYx=
03J4D4DQ4G0HE,- !%Q 2 2 4 : : <f !%Q 2 2 4fe$] ` r!   c                 x   SSSS.SSSS.SSS.nUR                  5       n[        R                  " SU[        R                  5      nU(       a`  [	        UR                  S5      5      US   S'   [	        UR                  S5      5      US   S	'   [	        UR                  S
5      5      US   S'   [        R                  " SU[        R                  5      nU(       a`  [	        UR                  S5      5      US   S'   [	        UR                  S5      5      US   S	'   [	        UR                  S
5      5      US   S'   U$ )rq  r   rr  )rs  rt  ru  rx  ry  r  rs  r~   r  r  r}  r  rz  rt  r{  )r	  ra  rm  r   r}  r~  s         r    rD  r  O  s%    $%Q:%&q!<!"	
 }} II\^bdfdmdmn	*-iooa.@*AE+w'(+IOOA,>(?E+u%),Y__Q-?)@E+v& II^`dfhfofop	,/	0B,CE- )*-iooa.@*AE- '+.yq/A+BE- (r!   )r
  r
  r;  r
  r
  r   )r  r	  r   )r  r  r  r  rf  r  r<  r
  r
  r   r  r	  r  r  r'  r"  r:  rH  rB  rC  rD  r  r   r!   r    r
  r
    sb   JCu 	!% 	6	
 	 	& 	V 	 	u 	 	U 	e 	 	V 	%  	U!" 	&#$  !%#(5N:4sA
$@.$`:Wr0&P"H@D,\&P;zr!   r
  c                 j    SR                  S U R                  5        5       5      R                  5       $ )Nr  c              3   |   #    U  H2  oR                  5       (       d  UR                  5       (       d  M.  Uv   M4     g 7fr   isalnumisspacer	  s     r    r   normalize.<locals>.<genexpr>p  "     IliikkQYY[11l   -<	<r  r=   r  r   s    r    r  r  o  &    77IdjjlIIOOQQr!   c                 <    [        S X5      R                  5       U:  $ r   r   r  r  brG  s      r    
is_similarr  r      4&,,.::r!   c                  "   Sn [        S5      q[        S5        [        U 5      R	                  5       q[        S5        [        R                  " S/SSS9nSnSn/ nS	n[        S
5         [
        (       Gaz  [
        R                  (       Gad  [
        R                  5       nUc  [        R                  " S5        MQ  US-  nUS-  S	:w  a  Ma  UR                  u  pxn	[        US-  5      [        US-  5      p[        US-  5      [        US-  5      pXjU2X24   n[        R                  " U[        R                   5      n[        R"                  " USS[        R$                  5      u  n	n[        US-  5      [        US-  5      nn[        US-  5      nUUU2UU24   n[        R                  " U[        R                   5      n[        R"                  " USS[        R$                  5      u  n	n UR'                  USS9nUR'                  USS9nSnU(       a  / nU H  n[+        U5      S:  d  M  [+        U5      S:X  a  US   OUS	   n[+        U5      S:X  a  US   OUS   nUR-                  5       nUR/                  5       S;  d  Ml  US:  d  Mt  [+        U5      S:  d  M  UR1                  U5        M     SR3                  U5      n/ nU H  n[+        U5      S:  d  M  [+        U5      S:X  a  US   OUS	   n[+        U5      S:X  a  US   OUS   nUS:  d  MN  [+        UR-                  5       5      S:  d  Mm  UR1                  UR-                  5       5        M     SR3                  U5      n U(       a  [+        U5      S :  a  [5        [7        U5      [7        U5      5      (       d  U(       ai  [+        U5      S:  aZ  [        S!5        SR3                  U5      n!S"U S#U! S$3n" [9        S%S&S'.S(U"S'./SS)S*9n#[        R;                  X$U#5        [        S+5        [<        R>                  " 5       RA                  S-5      n%[        S.U% S/35        [        S0U S135        / nUnU (       aW  [+        U 5      S:  aH  [5        [7        U 5      [7        U5      5      (       d%  [        S2U SS3  S435        UR1                  U 5        U n[        R                  " S55        [
        (       a  [
        R                  (       a  GMd  [
        (       a  [
        RC                  5         gg! [(         a     GM  f = f! [(         a  n$[        S,U$ 35         Sn$A$GN.Sn$A$ff = f! [(         a  n$[        S6U$ 35         Sn$A$NvSn$A$ff = f! [
        (       a  [
        RC                  5         f f = f7z"Worker pour le flux Bloomberg Livez+https://www.youtube.com/watch?v=iEpJwprxDdkr  z Demarrage flux Bloomberg Live...zInitialisation OCR...r@  F)gpuverboser  r   zSurveillance Bloomberg active
Nrg   r  r4  g(\?gQ?r  gffffff?r     g{Gz?g\(\?r  r*  )	paragraphr  r}  )	bloombergradiolivetvr  r   r	  r  z
[BOT] Generation resume IA...zTITRE: z
FRAGMENTS: u;   

Résume en 3-5 points clés les actualités financières.r%  u/   Tu es un expert en news financières Bloomberg.r&  r(  r7  )temperaturer)  z[OK] Resume sauvegarde
z[ERROR] Erreur resume: z%Y-%m-%d %H:%M:%Sz
? NOUVEAU []z   r$  z[DATA] r   r   r  zErreur Bloomberg Live: "r
  bloomberg_loggerr3   r
  r  bloomberg_streameasyocrReaderr
  r   r  r  shaper  r
  cvtColorCOLOR_BGR2GRAYrG  THRESH_BINARYreadtextr2   rs   r  r=   r  r  r  r  r.  r
  r	   r  r  r
  &r   readerlast_main_titlelast_ticker_textticker_bufferframe_countr
  r)  r  r   title_y1title_y2title_x1title_x2	title_roi
title_graytitle_processed	ticker_y1	ticker_y2	ticker_x1
ticker_roiticker_grayticker_processedtitle_resultsticker_resultsr
  title_partsr  r   prob
text_cleanticker_partsticker_textcombined_textpromptr
  r6   r:  s&                                         r    bloomberg_live_workerr  u  s    8C!"78	
,-(-335	
!"^^TFu=FOMK	
+,k$#3#;#;#;$))+E}

11KR1$kkGA! "%QXAHh!$QXAHhx/1BBCIi1C1CDJ!$z3SEVEV!WA $'q4x=#a$h-yIAHIy2IaK?@J,,z33E3EFK"%--S#sGXGX"YA &5 Q!'1AU!S
 J )D4yA~*-d)q.tAwd1g*-d)q.tAwd1g%)ZZ\
%++-5YY#czc*o.A + 2 2: > * !XXk2
 L&t9>&)$i1n47$q'D&)$i1n47$q'Dczc$**,&7!&;$++DJJL9 ' ((<0K c*o2!)J"7?9STT '3}+=+A?@(+(?%,_,= >? :"=
	A)6)1>o p)/F C8 ,/3*@J
 -==o^hi!$<> !) 7 78K LIM)A67C
|2./$&M&0O s;/"4!)K"8)DT:UVVGK$4#5S9:!((5'2$JJsOI #3#;#;#;R !!# U  h  ) A!$;A3"?@@A&  -'s+,,- !!#    (FU + T U ,AU U U :U 6U U 4B(U 4T! CU 
TU TU !
U+T?9U ?UU 
U)U$U, $U))U, ,"Vc           
          0 nU (       d  0 $ [        S[        U 5       SU  35         [        R                  " U U S3SSSSSS	9nUb  UR
                  (       a4  [        S5        [        S0 5      nU  Vs0 s H  ofU;   d  M
  XeU   _M     sn$ U  GHO  n [        U 5      S:X  a  UnO"XsR                  R                  S   ;  a  M5  X7   nUb!  UR
                  (       d  SUR                  ;  a  M_  UR                  S/S9nUR
                  (       a  M  [        US   R                  S   5      n	[        U5      S:  a  [        US   R                  S   5      OU	n
U
S:  a
  X-
  U
-  S-  OSn/ nUR                  5        H4  u  pUR                  UR                  S5      [        US   5      S.5        M6     U	UU[        R                   " 5       R#                  5       S.X''   GMR     U(       a)  [        S0 5      nUR%                  U5        ['        SU5        U$ ! [         a  n[        S
U 35        Sn SnAGNSnAff = fs  snf ! [         a  n[        SU SU 35         SnAGM  SnAff = f! [         aH  n[        SU S35        [        S0 5      nU  Vs0 s H  ofU;   d  M
  XeU   _M     Os  snf sns SnA$ SnAff = f)u   
Récupère les prix actuels ET historiques (derniers jours) pour une liste de tickers en mode groupé.
Le cache est utilisé en repli si Yahoo Finance échoue.
z[PRICES] Fetching z tickers in bulk: r  r  rw   FTr   )rg  rb  group_byrc  r	  r   z[WARN] yf.download failed: Nz?[WARN] Yahoo Finance returned empty data. Returning DB cache...live_prices_cacher  r   rd  subsetr  r*  r  )rN  r  )r  r\  
historicalrw  zError processing ticker rm   z#Global error in fetch_live_prices: z. Returning DB cache...)r3   rs   rp   r  r2   r  r/   r  ry  r  r  r
  r  r  r  r	   r  r  r1   r9   )r  r  pricesall_datadownload_errr   rx   rw   r  r  
price_prevr  r  rN  r  item_err
full_cacher6   s                     r    fetch_live_pricesr    s   
R>I"3w<.0B7)LM	{{qz!H x~~ST$%8"=F*1A'Q&[LAayL'AAF'w<1$#D%5%5%<%<Q%?? #+D <4::1L{{7){4:: d7m0045 >AY]U4=#5#5a#89PU
JTWX.u1Z?#E^_

!%ID%% $j 9!&s7|!4'  "1 #(",#+<<>#;#;#=	"A T ()<bAJf%/<s  	/~>?H	 BP  08*EF  >3A36MNO !4b9&-=gf!9g==>s   
I, I, H /I, 4	H=	H=
I, I, .II, (I,I, .!II, CI6I, 
H:H5/I, 5H::I, 
I)I$I, $I))I, ,
J>6J9	J,"	J,+J93J>9J>c                     Sn Sn [         R                  " U SSU0S9nUR                  5         UR                  5       n[	        U[
        5      (       a  UR                  S/ 5      OUn[        R                  " 5       R                  5       USS S	.n[        S
U5        U$ ! [         a>  n[        SU 35        [        R                  " 5       R                  5       / S	.s SnA$ SnAff = f)u&   Récupère le calendrier Forex Factoryz7https://nfs.faireconomy.media/ff_calendar_thisweek.jsonz5Mozilla/5.0 (X11; Linux x86_64) FFCalendarFetcher/1.0r   r   )r   r   r
  Nr   )r:  r
  forex_calendarzErreur Forex: )r   rv   r  r   r  r  r	   r  r  r9   r2   r3   )FF_JSON_URLUAr   r5   r
  r  r6   s          r    fetch_forex_calendar_apir  Y  s    KK	@BG<<R,PRAST!!#}}+5dD+A+A(B't "113Sbk
 	(&1 Gqc"#%\\^5572FFGs   BB 
C&(3C!C&!C&c                   f    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
 rS rS rS rS rS rSrg)MacroEconomicDataScraperiv  uq   
Scraper de données macro-économiques sans clé API
Sources: FRED, Investing.com, Trading Economics, ECB, etc.
c                     SSSSSS.U l         [        R                  " 5       U l        U R                  R                   R	                  U R                   5        [
        R                  " 5       U R                  l        g )Nr   rO  zen-US,en;q=0.9r*  r,  )r   r   r   r1  r3  )r   r   r   r   r1   certifirH  verifyr  s    r    r<  !MacroEconomicDataScraper.__init__|  s]     LW/2&
  '')##DLL1%mmor!   c                     SU 3n[         R                  " U[        R                  " 5       SS9nUR	                  5         [
        R                  " [        UR                  5      5      nUR                  (       a  gSUR                  ;  a1  SUR                  ;  a!  S/[        UR                  SS 5      -   Ul
        U$ ! [         a  n[        SU S	U 35         SnAgSnAff = f)
u2   Lit un CSV FRED avec gestion d'erreurs amélioréez3https://fred.stlouisfed.org/graph/fredgraph.csv?id=r  )r  r   NDATErN  r  zErreur lecture FRED rm   )r   rv   r  rH  r  r  read_csvr   r   r  r  r  r2   r3   )r	  	series_idr   r   r  r6   s         r    _read_fred_csv'MacroEconomicDataScraper._read_fred_csv  s    	G	{SC<<GMMORHD!!#Xdii01B xx RZZ'F"**,D$XRZZ^(<<
I 	(2aS9:	s   A8B> ;AB> >
C#CC#c                 8   0 n U R                  S5      nUbV  UR                  (       dE  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SSS.US	'    SnU R                  R                  USS9n[        UR                  S5      nUR                  S5      nU(       a  UR                  S5      n	U	SS  Hu  n
U
R                  S5      n[        U5      S:  d  M%  US   R                  R                  5       R!                  SS5      R!                  SS5      n [        U5      SSS.US'   Mw      SnU R                  R                  USS9n[        UR                  S5      nUR#                  5       n[$        R&                  " SU5      nU(       a!  [        UR)                  S5      5      SSS.US '    S"S#S$S%S&.US''   [*        R,                  " 5       R/                  5       US)'   U$ ! [
         a  n[        S
U 35         SnAGNSnAff = f!    GMZ  = f! [
         a  n[        SU 35         SnAGNSnAff = f! [
         a  n[        S!U 35         SnANSnAff = f! [
         a  n[        S(U 35         SnANSnAff = f)*u@   Récupère les taux directeurs des principales banques centralesFEDFUNDSNr  r  r   rv  zFederal Funds Rate)r  rN  r}  rA   FEDzErreur FED: zchttps://www.ecb.europa.eu/stats/policy_and_exchange_rates/key_ecb_interest_rates/html/index.en.htmlr  r  rQ  r  r  r  r  r  r  r  r|  r{  zMain Refinancing Operations)r  r}  rA   ECBzErreur ECB: zKhttps://www.bankofengland.co.uk/monetary-policy/the-interest-rate-bank-ratezBank Rate is (\d+\.?\d*)%GBPz	Bank RateBoEzErreur BoE: r  JPYzPolicy Rateu+   Donnée approximative - vérifier BoJ.or.jp)r  r}  rA   noteBoJzErreur BoJ: r:  )r  r  r
  r  r  r2   r3   r   rv   r   rP  r  r  rs   r   r  r  r\  r  r  r  r	   r  r  )r	  ratesr  latestr6   r   r   ra  r  r  r  r  	rate_textr   r  s                  r    get_interest_rates+MacroEconomicDataScraper.get_interest_rates  s|   	&$$Z0B~bhh!&++a.1A/ %0	 e	&wC||''R'8H !1!1=AD IIg&E~~d+!9C<<-D4yA~$(GLL$6$6$8$@$@b$I$Q$QRUWZ$[	!(-i(8,1(E,E%L % 	&_C||''R'8H !1!1=AD==?DII:DAE!%++a.1 %' e		& !%E	E%L &\\^557ku  	&L$%%	&.!  	&L$%%	&"  	&L$%%	&  	&L$%%	&s   A*G= /BH, 4=H, 2H#H, 	BI 
I7 =
H HH #H)%H, ,
I6I

I
I4I//I47
JJJc                    0 n U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S	   5      S
S.US'    U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S	   5      SS.US'    U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S	   5      SS.US'   [        R                  " 5       R                  5       US'   U$ ! [         a  n[        SU 35         SnAGNSnAff = f! [         a  n[        SU 35         SnAGN#SnAff = f! [         a  n[        SU 35         SnANSnAff = f)u%   Récupère les taux d'inflation (CPI)CPIAUCSLNr  r  ir  r*  r  r   zConsumer Price Index)rR  
yoy_changerN  rA   US_CPIzErreur US CPI: CPILFESLzCore CPI (ex food & energy)US_Core_CPIzErreur US Core CPI: PCEPIz'Personal Consumption Expenditures (PCE)US_PCEzErreur US PCE: r:  r  r  rs   r
  r  r  r  r2   r3   r	   r  r  )	r	  	inflationr  r  previous_year
latest_valprev_valr  r6   s	            r    get_inflation_data+MacroEconomicDataScraper.get_inflation_data  s   		)$$Z0B~bhh3r7b= ""6;;q>2
 !3!3A!67)4@CG
 ("'
A"6A/2	'	(#	.$$Z0B~bhh3r7b= ""6;;q>2
 !3!3A!67)4@CG
 ("'
A"6A/9	,	-(	)$$W-B~bhh3r7b= ""6;;q>2
 !3!3A!67)4@CG
 ("'
A"6A/E	'	(# "*!9!9!;	+]  	)OA3'((	)*  	.(,--	.*  	)OA3'((	)sJ   B6I ;B6I6 2B6J 
I3I..I36
J JJ
J>&J99J>c                 |   0 n U R                  S5      nUbU  UR                  (       dD  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SS.US'    U R                  S
5      nUb^  UR                  (       dM  UR                  S   n[        [        UR                  S   5      5      [	        UR                  S   5      SS.US'    U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[        UR                  S   5      [        UR                  S   5      -
  n[        UR                  S   5      [        US5      [	        UR                  S   5      SSS.US'   [        R                  " 5       R                  5       US'   U$ ! [
         a  n[        S	U 35         SnAGN~SnAff = f! [
         a  n[        SU 35         SnAGN1SnAff = f! [
         a  n[        SU 35         SnANSnAff = f)u   Récupère les taux de chômageUNRATENr  r  r   zUS Unemployment Rater  rN  rA   r+  zErreur US Unemployment: ICSAzInitial Jobless Claims (weekly)rR  rN  rA   US_Jobless_ClaimszErreur Jobless Claims: PAYEMSr  r  zNonfarm Payrolls (thousands)zThousands of jobs)rR  
mom_changerN  rA   ro  US_Nonfarm_PayrollszErreur Payrolls: r:  )r  r  r
  r  r  r2   r3   r  rs   r  r	   r  r  )r	  unemploymentr  r  r6   previousr\  s          r    get_unemployment_data.MacroEconomicDataScraper.get_unemployment_data4  s   
	2$$X.B~bhh!&++a.1A/2&T"
	1$$V,B~bhh v{{1~!67A/=501	+$$X.B~bhh3r7a<772;v{{1~.x}}Q7G1HH #6;;q>2"'"2A/:/723 %-LLN$<$<$>[!I  	2,QC011	2  	1+A3/00	1&  	+%aS)**	+sJ   A)G .A2G3 !CH 
G0G++G03
H=HH
H;#H66H;c                 .   0 n U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S   5      S	S
S.US'    U R                  S5      nUbU  UR                  (       dD  UR                  S   n[	        UR                  S   5      [        UR                  S   5      SS.US'   [        R                  " 5       R                  5       US'   U$ ! [         a  n[        SU 35         SnANSnAff = f! [         a  n[        SU 35         SnANjSnAff = f)u   Récupère les données de PIBGDPNr  r  r  r  r*  r   zBillions of DollarszUS GDP)rR  
qoq_changerN  ro  rA   r+  zErreur US GDP: A191RL1Q225SBEAz"US Real GDP Growth Rate (Annual %)r	  	US_GrowthzErreur US GDP Growth: r:  r   )	r	  gdpr  r  r  r  r  r  r6   s	            r    get_gdp_data%MacroEconomicDataScraper.get_gdp_dataj  sw   	)$$U+B~bhh3r7a<772;"6;;q>2
 q!12)4@CG
 ("'
A"6A/1$D	
	0$$%67B~bhh!&++a.1A/@$K  $<<>335K
#  	)OA3'((	)  	0*1#.//	0s1   B7E <A)E2 
E/E**E/2
F<FFc                 t   0 n U R                  S5      nUbU  UR                  (       dD  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SS.US'   [        R                  " 5       R                  5       US
'   U$ ! [
         a  n[        S	U 35         SnANESnAff = f)u   Récupère les indices PMIMANEMPNr  r  r   z"ISM Manufacturing Employment Indexr  US_ISM_ManufacturingzErreur PMI: r:  
r  r  r
  r  r  r2   r3   r	   r  r  )r	  pmir  r  r6   s        r    get_pmi_data%MacroEconomicDataScraper.get_pmi_data  s    
	&$$X.B~bhh"6;;q>2A/@/*+ $<<>335K
	  	&L$%%	&s   A)B 
B7B22B7c                    0 n U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S   5      S	S
S.US'   [        R                  " 5       R                  5       US'   U$ ! [         a  n[        SU 35         SnANESnAff = f)u    Récupère les ventes au détailRSXFSNr  r  r  r  r*  r   zMillions of DollarszUS Retail Sales)rR  r  rN  ro  rA   r+  zErreur Retail Sales: r:  r   )	r	  retailr  r  r  r  r  r  r6   s	            r    get_retail_sales)MacroEconomicDataScraper.get_retail_sales  s    	/$$W-B~bhh3r7a<772;"6;;q>2
 q!12)4@CG
 ("'
A"6A/1- t 'lln668{	  	/)!-..	/s   B7C# #
D-D  Dc                    0 n U R                  S5      nUbU  UR                  (       dD  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SS.US'    U R                  S
5      nUbU  UR                  (       dD  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SS.US'   [        R                  " 5       R                  5       US'   U$ ! [
         a  n[        S	U 35         SnANSnAff = f! [
         a  n[        SU 35         SnANjSnAff = f)u5   Récupère les indices de confiance des consommateursUMCSENTNr  r  r   z)University of Michigan Consumer Sentimentr  US_MichiganzErreur Consumer Confidence: CSCICP03USM665SzConsumer Confidence IndexUS_Conference_BoardzErreur CCI: r:  r  )r	  r  r  r  r6   s        r    get_consumer_confidence0MacroEconomicDataScraper.get_consumer_confidence  s*   

	6$$Y/B~bhh"6;;q>2A/G-
=)
	&$$%67B~bhh"6;;q>2A/75
01 #+,,.":":"<
;#  	60455	6  	&L$%%	&s1   A)C? .A)D$ ?
D!	DD!$
E.EEc                    0 n U R                  S5      nUbV  UR                  (       dE  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SSS.US	'    U R                  S5      nUbV  UR                  (       dE  UR                  S   n[        UR                  S   5      [	        UR                  S   5      SSS.US'   [        R                  " 5       R                  5       US'   U$ ! [
         a  n[        S
U 35         SnANSnAff = f! [
         a  n[        SU 35         SnANjSnAff = f)u%   Récupère les données immobilièresHOUSTNr  r  r   zHousing Starts (thousands)zThousands of Units)rR  rN  rA   ro  Housing_StartszErreur Housing Starts: EXHOSLUSM495SzExisting Home SalesMillionsExisting_Home_SaleszErreur Home Sales: r:  r  )r	  housingr  r  r6   s        r    get_housing_data)MacroEconomicDataScraper.get_housing_data  s0   	1$$W-B~bhh"6;;q>2A/80	-()	-$$_5B~bhh"6;;q>2A/1&	2-.  (||~779%  	1+A3/00	1  	-'s+,,	-s1   A*D /A*D& 
D#DD#&
E0EEc                    0 n U R                  S5      nUb  UR                  (       d  [        U5      S:  a  UR                  S   nUR                  S   n[	        UR                  S   5      n[	        UR                  S   5      nXV-
  U-  S-  nU[        US5      [        UR                  S   5      S	S
.US'   [        R                  " 5       R                  5       US'   U$ ! [         a  n[        SU 35         SnANESnAff = f)u%   Récupère la production industrielleINDPRONr  r  r  r  r*  r   zIndustrial Production Index)rR  r  rN  rA   r+  zErreur Industrial Production: r:  r   )	r	  
industrialr  r  r  r  r  r  r6   s	            r    get_industrial_production2MacroEconomicDataScraper.get_industrial_production  s    
	8$$X.B~bhh3r7a<772;"6;;q>2
 q!12)4@CG
 ("'
A"6A/9	$
4  #+,,.":":"<
;	  	821#677	8s   B6C" "
D,C??Dc                 "   0 n SnU R                   R                  USS9n[        UR                  S5      n/ n[        R
                  " 5       R                  nUR                  SSSU 305      nU(       aE  UR                  SSS	9nUS
S  H,  n	U	R                  SS9n
U
(       d  M  UR                  U
5        M.     UUSUS.US'   [        R
                  " 5       R                  5       US'   U$ ! [         a  n[        SU 35         S
nANES
nAff = f)u+   Récupère le calendrier des réunions FOMCz?https://www.federalreserve.gov/monetarypolicy/fomccalendars.htmr  r  rQ  rP  r-  zmeeting-calendars-zfomc-meeting__dater  NrB  Tr  Federal Reserve)upcomingre  rB  r   FOMC_meetingszErreur FED Calendar: r:  )r   rv   r   rP  r	   r  re  r  r  r\  r  r2   r3   r  )r	  r  r   r   ra  meetingsr  
year_paneldate_elementselem	date_textr6   s               r    get_fed_calendar)MacroEconomicDataScraper.get_fed_calendar-  s   	/SC||''R'8H !1!1=ADH $<<>..L543El^1T*UVJ * 3 3EBV 3 W)"1-D $D 9I y 	2 . %$+	)H_% !) 8 8 :	  	/)!-..	/s   BC, %C, ,
D6D		Dc                    [        S5        U R                  5       U R                  5       U R                  5       U R	                  5       U R                  5       U R                  5       U R                  5       U R                  5       U R                  5       U R                  5       [        R                  " 5       R                  5       S.nU$ )u$   Récupère toutes les données macroz4[DATA] Recuperation des donnees macro-economiques...)interest_ratesr  r  r  r   retail_salesconsumer_confidencer5  industrial_productionfed_calendarr:  )r3   r  r  r  r  r!  r&  r-  r6  r;  rF  r	   r  r  )r	  r5   s     r    get_all_macro_data+MacroEconomicDataScraper.get_all_macro_dataS  s    DE #557002 668$$&$$& 113#'#?#?#A,,.%)%C%C%E 113!113
 r!   r  N)r  r  r  r  rf  r<  r  r  r  r  r  r!  r&  r-  r6  r;  rF  rN  r  r   r!   r    r  r  v  sQ    

..IZDP2l(X,<F!F:"Lr!   r  c                     [         R                  5          [        R                  R	                  U S9R                  5       nU(       d)  [        XS9n[        R                  R                  U5        O Xl	        [        R                  " 5       Ul        [        R                  R                  5         SSS5        g! , (       d  f       g= f! [         a  n[        SU  SU 35         SnAgSnAff = f)zSave macro data category to DB)r  )r  r5   NzDB Error save macro rm   )r)   r.   r  r   r  r  r   r   r   r5   r	   r   r   r   r2   r3   )r  r  r   r6   s       r    db_save_macro_datarQ  g  s    6__OO--x-@FFHE!8D

u%&
#+??#4 JJ   6$XJb4556s5   C
 BB90C
 9
CC
 C
 

C/C**C/c                  2    [         R                  R                  5       n U  Vs0 s H  oR                  UR                  _M     nn[        S[        UR                  5       5       35        U$ s  snf ! [         a  n[        SU 35        0 s SnA$ SnAff = f)zLoad all macro data from DBzDEBUG: Loaded macro data keys: zDB Error load macro: N)	r  r   r   r  r5   r3   r  r  r2   )	all_macrorc  r  r6   s       r    db_load_macro_datarT  v  s    OO'')	.78i**aff$i8/V[[]0C/DEF 9  %aS)*	s.   "A2  A-(A2 -A2 2
B<BBBc                      [        5       n U R                  5       nUR                  5        H  u  p#US:w  d  M  [        X#5        M     [	        S5        g)z%Worker function to refresh macro datar:  z[OK] Macro data updated in DBN)r  rN  r_   rQ  r3   )r  r5   r  category_datas       r    rk	  rk	    sF    &(G%%'D#'::<{"x7 $0 

)*r!   c                    S n0 nU  H  nU" U5      nU(       d  M   [         R                  " 5       [        SS9-
  n/ nU H6  n [         R                  " US   S5      nX:  a  UR	                  U5        M6  M8     UR                  S SS9  UR                  S	 SS9  US
S US.X#'   M     U(       a  [        U5        U$ !    M  = f! [         a  n	[        SU SU	 35         S
n	A	M  S
n	A	ff = f)u8   Récupère les transactions d'insiders via Yahoo Financec                     [         R                  " U 5      nUR                  nUb  UR                  (       a  / $ / nUR	                  5       nUR                  5        GH  u  pE UR                  S5      nSn[        US5      (       a  UR                  S5      nO[        U5      n[        UR                  SS5      5      nSU;   a  SO	SU;   a  SOS	n	S
n
 [        R                  " SU5      nU(       a  [        US   5      n
UR                  SS5      nUR                  SS5      n[        R                  " U5      (       a  Sn[        R                  " U5      (       a  SnU
S:X  a  US:w  a  [        X-  S5      n
UR!                  [        UR                  SS5      5      [        UR                  SS5      5      UU	U
[#        U5      [#        U5      S[        UR                  SS5      5      S.	5        GM     U$ !    N= f! [$         a  n S nAGM  S nAff = f! [$         a  n['        SU  SU 35        / s S nA$ S nAff = f)Nz
Start Dater  r  	%b %d '%yr  OptionzOption ExecuteSalero  rz  zprice\s+([\d\.]+)r   r  r  r  r  rh   r  OfficerURL)	r  r  rN  rO  rP  rQ  rR  rS  rT  zError YF Insiders rm   )rp   rq   insider_transactionsr  reset_indexr  rv   r^   r  r  r  r  r  r  r  r  r  r  r2   r3   )rw   rx   r  rX  r   r  date_valr  raw_texttxn_typerP  matchesrQ  rR  row_er6   s                   r    get_insider_data_yf/fetch_insiders_api.<locals>.get_insider_data_yf  s   D			&!A''BzRXX	L !B++-."ww|4H!Hx44#+#4#4[#A#&x=  #37762#67H3;x3G/X^bjXjfpuH D!"$**-A8"L"#(#4D !WWXq1FGGGQ/Ewwu~~quwwv qyVq[$U^Q7 ''#&swwy)'D#E(+CGGJ	,J(K ('/ $"%f+!$U()$'r(:$;
) 
G (b  5 !D. ! 
  	&vhb45I	s`   7H (H #A0G>,G7 C0G>0H 7G;9G>>
HH HH 
H>!H93H>9H>r   r  rN  rY  c                 6    [         R                  " U S   S5      $ NrN  rY  r	   r  r  s    r    r  $fetch_insiders_api.<locals>.<lambda>  s    0A0A!F)[0Yr!   Tr^  c                 6    [         R                  " U S   S5      $ rh  ri  r  s    r    r  rj    s    h&7&7&	;&Or!   Nr   r  zError filtering insiders rm   )	r	   r  r
   r  r  r	  r2   r3   r  )
r  re  r  rw   r  r  recentrx   deduced_datesort_es
             r    fetch_insiders_apiro    s   EN H.v6	B\\^iR&88FF%#+#4#4QvY#LL#-a( .	 & !!&Ycg!hKKOY]K^ (, & H/ B "O'   	B-fXRx@AA	Bs/   &C0B>42C>C C
C,C''C,c                      [        S5      n 0 n/ nSnU (       ay  U R                  S5      nU R                  S5      (       aR  U S    HI  nUR                  S5      (       a  XAUS   '   UR                  SS5      S:  d  M8  UR                  U5        MK     S	[        l        S
n [
        R                  " USS	0[        R                  " 5       SS9nUR                  5         [        R                  " UR                  5      n[        US5      (       a  UR                  O/ n	/ n
[        5       nU	SS  GH  nUR                  SS5      R!                  5       nUR#                  U5        UR                  SS5      R!                  5       UUR                  SS5      [$        R&                  " 5       R)                  5       UR                  SS5      UR                  S/ 5       Vs/ s HC  n[+        U[,        5      (       d  M  UR                  S5      (       d  M2  UR                  S5      PME     snUR                  S/ 5       Vs/ s HC  n[+        U[,        5      (       d  M  UR                  S5      (       d  M2  UR                  S5      PME     snS.nX;   aK  X   nUR                  S5      (       a  UR                  S5      US'   / SQnU H  nUU;   d  M  UU   UU'   M     U
R                  U5        GM     U H  nUS   U;  d  M  U
R                  U5        M!     U
R/                  S SS9  S[$        R&                  " 5       R)                  5       [1        U
5      U
US .n[3        SU5        U$ ! [         a/  n[        SU 35        [        R                  " U5      n SnAGNSnAff = fs  snf s  snf ! [         aP  n[        S!U 35        [        S5      =(       d&    / [$        R&                  " 5       R)                  5       S".s SnA$ SnAff = f)#u    Récupère le flux RSS BloombergrK  Nreportr_   r  rn  r   r  Mozilla/5.0z,https://feeds.bloomberg.com/markets/news.rssr   r  )r   r  r   zErreur fetch RSS via requests: r  r   r  rC  r  rD  authorsrA   tagsterm)rC  r  r  published_isorD  rs  rt  rv  )	rl  rt  ru  rn  ro  rs  rx  polymarket_datatemp_bert_resultc                 &    U R                  SS5      $ )Nrv  r  r  r  s    r    r  )fetch_bloomberg_rss_api.<locals>.<lambda>Z  s    aeeOR&@r!   Tr^  zBloomberg Markets)
feed_titler!  r  r_   rq  zErreur RSS: )r_   r!  )r/   rv   r  
feedparser
USER_AGENTr   r  rH  r  parserP  r2   r3   r^   r  r  r  r   r	   r  r  r  r  r	  rs   r9   )existing_dataexisting_items_mapcached_critical_itemsexisting_reportr  _rss_url	_rss_respfeed_rss_errr  
normalized
seen_linksr6   r  r  rx   new_itemr  keys_to_preserverc   r#	  r  s                         r    r-  r-    s   ck'8 "+//9O  )))'2Dxx'';?4<8 xx 3Q71<-44T: 3 !.
A	. %}5}}	I &&(##I$5$56D
 #*$	":":$,,
U
"A55$**,DNN4  w+113UU;3!)!9!9!;55B/3455B3G E3Ga(D1 *67eeFm *AEE&M3G E01fb0A B0A1%a. '3455= 'v0A B
H )-3 <<0008_0MH_-$ 
 *AH}&.qk * h'G N *DF|:-!!$' * 	@$O .",,.224_%
 	0C  	.3H:>?##H-D	.&EBZ  kQC !/jRx||~OgOgOi3jjks   A8N+ >"N+ !AM% =CN+ N!7N!N!$N+ :N&N&/N&AN+ .N+ ?A%N+ %
N/$NN+ NN+ +
P5AP :P Pc                     SU  S3nSSSSSSS	S
S.n[         R                  " XSSS.SS9nUR                  5         UR                  5       nU(       a  SU;  a  0 $ US   nUR                  SU 5      UR                  SS5      UR                  SS5      UR                  SS5      [        R
                  " 5       R                  5       S.nUR                  S0 5      nUR                  S/ 5      nU(       d  U0 S.$ / n	/ n
U GHS  nUR                  S5      (       a  UR                  S5      (       d  M2  UR                  SS5      nUR                  SS5      nU(       d  M_  U	R                  UUUR                  S S5      UR                  S!S5      UR                  S"S5      UR                  S#S5      UR                  S$S5      UR                  S%S5      S&.5        U
R                  UUUR                  S'S5      UR                  S(S5      UR                  S)S5      UR                  S*S5      UR                  S+S5      UR                  S,S5      S&.5        GMV     [        R                  " U	5      n[        R                  " U
5      n/ S-QnU H  nUUR                  ;   aC  UU   R                  / S.Q[        R                  5      UU'   [        R                  " UU   S/S09UU'   UUR                  ;   d  Mh  UU   R                  / S.Q[        R                  5      UU'   [        R                  " UU   S/S09UU'   M     UR                  S1S25      n[        R                  " S3U5      nU(       a*  [!        UR#                  S45      R                  S5S5      5      OSnUS6   R%                  5       nUS6   R%                  5       nUS7   R%                  5       nUS7   R%                  5       nUS:  a  UU-  OS8nUS:  a  UU-  OS8nU(       a  US9:  a  S:nS;nOU(       a  US<:  a  S=nS>nOS?nS@nUR'                  5       nSAUSB'   UR'                  5       nSCUSB'   [        R(                  " UU/5      nUUS7   S:     R'                  5       n U R+                  S5      R-                  SDSDSE.5      R/                  5       n!U!U!S   U:     R'                  5       n"U!U!S   U:     R'                  5       n#U"R1                  S7SFSG9R3                  SH5      n"U#R1                  S7SFSG9R3                  SH5      n#[5        U"R7                  5       5       V$V%Vs/ s HS  u  n$u  n%n[!        US   5      [9        US7   5      [9        US6   5      [;        US   U-
  U-  SI-  SJ5      U$S:X  a  SKOSLSM.PMU     n&n%n$n[5        U#R7                  5       5       V$V%Vs/ s HS  u  n$u  n%n[!        US   5      [9        US7   5      [9        US6   5      [;        UUS   -
  U-  SI-  SJ5      U$S:X  a  SNOSOSM.PMU     n'n%n$nUSP   USQ   -
  USR'   USP   USQ   -
  USR'   USR   R=                  5       n(USR   R=                  5       n)U(U)-   SJ-  n*[        R>                  " U*5      (       a  U*SS:  a  STn+SUn,OU*S9:  a  SVn+SWn,O	SXn+SYn,OSn+Sn,URA                  SHS65      n-URA                  SHS65      n.U-R7                  5        V%Vs/ s HN  u  n%n[        R>                  " US6   5      (       d  M&  US6   S:  d  M1  [!        US   5      [9        US6   5      SZ.PMP     n/n%nU.R7                  5        V%Vs/ s HN  u  n%n[        R>                  " US6   5      (       d  M&  US6   S:  d  M1  [!        US   5      [9        US6   5      SZ.PMP     n0n%nUS6   US7   R                  SS45      -  US['   US6   US7   R                  SS45      -  US['   XS[   S\:     RA                  S]S65      n1XS[   S\:     RA                  S]S65      n2U1R7                  5        V%Vs/ s Hh  u  n%n[        R>                  " US6   5      (       d  M&  US6   S:  d  M1  [!        US   5      [9        US6   5      [9        US7   5      [!        US[   5      S^.PMj     snn%U2R7                  5        V%Vs/ s Hh  u  n%n[        R>                  " US6   5      (       d  M&  US6   S:  d  M1  [!        US   5      [9        US6   5      [9        US7   5      [!        US[   5      S^.PMj     snn%S_.n30 n4US`   RC                  5        H  n[        RD                  " U5      (       d  US:X  a  M&  XS`   U:H     n5XS`   U:H     n6U5S6   R%                  5       n7U6S6   R%                  5       n8[9        U75      [9        U85      [9        U7U8-   5      U7S:  a  [!        U8U7-  5      OS8UU-   S:  a  [!        U7U8-   UU-   -  SI-  5      OSSa.U4U'   M     [G        [I        U4RK                  5       Sb ScSd95      n9SeSF0n:U9(       aA  [M        U9RO                  5       5      S   n;U9U;   n<U<Sf   Sg:  a  ScU;[!        U<Sf   5      ShU; Si3Sj.n:U UUS1   USk   UUU(       a  [;        USJ5      OSU(       a  [;        USJ5      OS[9        U5      [9        U5      [9        U5      [9        U5      Sl.U&U'Sm.U+U,[        R>                  " U(5      (       a  [;        [!        U(5      SJ5      OS[        R>                  " U)5      (       a  [;        [!        U)5      SJ5      OSSn.U:R                  SeSF5      U:R                  SoS5      U:R                  SpS5      U:R                  SqSr5      [M        U9RK                  5       5      S8SH  V=Vs/ s H:  u  n=nU=USs   [;        USf   S45      USt   b  [;        USt   SJ5      OS8USu   USv   Sw.PM<     snn=Sx.U3U/U0S_.Sy.
n>[Q        SzU  3U>5        U>$ s  snn%n$f s  snn%n$f s  snn%f s  snn%f s  snn%f s  snn%f s  snn=f ! [R         a/  n?[U        S{U? 35        SS8K+n@U@RX                  " 5         0 s S8n?A?$ S8n?A?ff = f)|u8   Récupère et analyse complètement la chaîne d'optionsz!https://api.nasdaq.com/api/quote/z/option-chainrN  z!application/json, text/plain, */*zfr,fr-FR;q=0.9,en;q=0.8zhttps://www.nasdaq.comzhttps://www.nasdaq.com/r  r  r  )r   r   r   r   r   r5  r6  r7  r   r   )rC  
assetclassr   rD  r5   r@   	lastTrader  r\  totalRecordr   )r@   last_trade_pricelast_trade_changetotal_recordsr:  r  r  )metadatasentiment_marcheexpirygroupr  
expiryDater  c_Lastc_Changec_Bidc_Askc_Volumec_Openinterest)expiry_dater  r  r\  r  r  r  open_interestp_Lastp_Changep_Bidp_Askp_Volumep_Openinterest)r  r  r\  r  r  r  r  )z--r  r   Nr  r  r  r  z\$?([\d,]+\.?\d*)r  r  r  r  Nr
  BAISSIERz[DOWN]ffffff?HAUSSIERz[UP]NEUTREu   ➡️Calloption_typePutr  )r  r  Fr  rg   r*  r  u   Résistance forteu   Résistance)r  r  r  distance_pctr
  zSupport fortSupportr  r  r  g       @u   ÉLEVÉEu   Forte incertitude du marchéu	   MODÉRÉEu   Volatilité normaleFAIBLEu   Marché calme)r  r  volume_to_oi_ratior	  r}  )r  r  r  r  )r  r  r  )call_volume
put_volumerw  put_call_ratiovolume_pct_of_totalc                     U S   S   $ )Nr  rw  r   r  s    r    r  )fetch_options_chain_api.<locals>.<lambda>k   s    QqT.5Ir!   Tr^  detectedr  r  zForte concentration sur z% - Position institutionnelle probable)r  expiration_dominanteconcentration_pctr  r:  )rF  emojiput_call_ratio_volumeput_call_ratio_oitotal_call_volumetotal_put_volumer;  r<  )resistancessupports)attenter  spread_moyen_callsspread_moyen_putsr  r  r  zPas de signal clairrw  r  r  r  )
expirationrw  
volume_pctr  r  r  )signal_detecter  r  r  repartition_par_expiration)
rw   rr  
last_trader:  r  zones_prix_clesvolatilite_anticipeeflux_institutionnelsactivite_inhabituelletop_strikes_volumeoptions_zErreur Options: )-r   rv   r  r   r	   r  r  r  r  r  r  r  NAr  r  r  r  r  r  r  r  r	  r  r_  r  head	enumerater  r  r  r  r  r  r'  r  r  r`  r_   r  r  r9   r2   r3   r   r   )Arw   r   r   r   r>  r5   r  r  r  
calls_data	puts_datar  exp_dater  df_callsdf_putsnumeric_colsr  last_price_strr  rr  r  r  r;  r<  
pcr_volumepcr_oirF  r  calls_with_typeputs_with_typeall_strikessignificant_oistrike_summaryr  r  r  r   resistance_levelssupport_levelsavg_call_spreadavg_put_spread
avg_spread
volatility
vol_interpr  r  most_active_callsmost_active_putsunusual_callsunusual_putsunusual_activity	exp_stats	exp_callsexp_putsr  r  exp_stats_sortedinstitutional_signaldominant_expdominant_datar'  r  r6   r   sA                                                                    r    r  r  r  s&   H1&GX98.0%$)	
 <<rYa=blno!!#==?61I hhx0 $e <!%(E!:!XXmQ7!113
 '2&zz&"% (bAA
	Cww}%%cggh.?.?ww|R0HWWXr*F ' "-''*b1www+www+''*b1!$)92!>	 	 ' "-''*b1www+www+''*b1!$)92!>	 	/ F <<
+,,y) ]Ch&&& ( 5 56KRUU S "hsmH Mgoo%&s|334I255Q!}}WS\(K   "&8#>		.?BGekk!n44S"=>Q %X.224"8,002 1557/335=NQR=R%(99X\
1>1B- *s*"IEJ,"IE IE #--/)/& (-}%ii. AB$[%AA%EFKKM'//9=="?
  ;= 	
 %^H%=%MNSSU!.":]"JKPPR!--o-OTTUVW''5'INNqQ  ))=)=)?@	
  A8As  H.!$S%9!:c(m, %s8}}'D&UX[&[]^ _/0Av+=  A 	 	
&  )):):)<=	
  >8As  H.!$S%9!:c(m, %}s8}'D&UX[&[]^ _*+q&i  > 	 	
 &e_x>#ENWU^;"8,113 *//1%6!;
88JC'
;
c!(
2
%
,
JJ %%a2	##Ax0 $,,.
.3xxH& K+.x=1+< KuS]+s3x=7IJ. 	 
 #++-
-3xxH& K+.x=1+< KuS]+s3x=7IJ- 	 
 *2();h>W>_>_`acd>e)e%&(/(9GO<T<\<\]^`a<b(b$% *>!?#!EFOOPQS[\';<sBCLLQPXY ,446	 7FAs88CM* 038}q/@#CM2!#h-0%(_)=%>"3';#<=	 7	" +335	 6FAs88CM* 038}q/@#CM2!#h-0%(_)=%>"3';#<=	 6	
0 	 /668Hwwx  HN -!8H!DEI}5ABH *..0Hx(,,.G  #8}!'l #Hw$6 7?G!|%((:";QU wH  K[  w[  _`  v`uh.@EVYiEi-jmp-p'q  fg#Ih 9$  y'8+I/3!5 6
 !+E2 0 5 5 78;L,\:M23b8 $,8).}=R/S)T(@Ns&t	($ *"#56!+. 'AKz1)=QR9?U61%5Q%():%;$'(8$9!$]!3 #L 1	!  1*  &",JL((SbJcJceE/,BA&FijHJQ_H`H`U5+@!%Dfg	% #7":"::u"M(<(@(@AWY^(_%9%=%=>QST%U"6":":;KMb"c &**:*@*@*B%CBQ%G
/ &H	T '*(,^(<&+D1F,G&KNRScNdNp%5E0F*Jvz'+M':&*<&8 &H
/%$ &6 +(#c5
p 	(6(+V4u	
	
J

		j
/2   $%		s   Ap
 Bp
 9G4p
 1I
p
 ;Ao!p
 6Ao%B?p
 %o,8o,!o,$p
 :%o2#o2.!o2Bp
 %o8>o8	;o8p
 %o>o>;o>	I6p
 ?Ap p
 ,p
 

q$p>8q>qc                      SSSS.n SS[         R                  " 5       R                  5       U S.0 0 0 S.nU R                  5        HD  u  p#[        R
                  " USSS	S
9nUR                  (       a  M/  [        U5      SSS.US   U'   MF     [        SU5        U$ ! [         a  n[        SU 35        0 s SnA$ SnAff = f)u$   Analyse de saisonnalité des indicesrR   r?   r  )rS   r  z	Dow Jonesz
2004-01-01z
2024-12-31)
start_dateend_dategenerated_atr  )r  data_summaryday_of_weekmonthly_cyclesF)r  ra  rc  r  g      .@)
total_daysavg_daily_return_pctvolatility_pctr  r  zErreur Saisonnalite: N)r	   r  r  r_   rp   r  r  rs   r9   r2   r3   )r  r  rA   r@   r5   r6   s         r    r  r     s    #
 +( ( 8 8 :"	  

 $MMOLD;;v\|V[\D:::"%d),0&*0~&t,	 , 	v. %aS)*	s$   A.B 4&B 
B?%B:4B?:B?c                    [        S5        SnSU 3n [        R                  " USS9n[        R                  " [        UR                  5      5      nUR                  (       Gd  SUR                  ;   Ga  [        R                  " US   5      US'   [        R                  " 5       nU[        R                  " U S9-   nXDS   U:  US   U:*  -     nUR                  S5      nU/ SQ   R                  5       n/ S	QUl        US
   R                  R!                  S5      US
'   US   R"                  SS US'   SUS'   UR%                  S5      n/ n	U H  n
0 nU
R'                  5        H{  u  p[        R(                  " U5      (       a  SX'   M&  [+        U[,        5      (       a<  [.        R0                  " U5      (       d  [.        R2                  " U5      (       a  SX'   Mw  XU'   M}     U	R5                  U5        M     [        R                  " 5       R7                  5       U [9        U	5      U	S.n[;        SU5        U$ / SS.$ ! [<         a#  n[        SU 35        [?        S5      s SnA$ SnAff = f)uG   Récupère les earnings à venir via Alpha Vantage (Calendrier complet)z,Recuperation des earnings (Alpha Vantage)...demozShttps://www.alphavantage.co/query?function=EARNINGS_CALENDAR&horizon=3month&apikey=r   r  
reportDater  )r@   rA   r  r  r}  )rw   rA   rN  r  r}  rN  r  rA   Nr  r  r`   r  )r   
days_aheadr  r5   earnings_cachezErreur API Alpha Vantage: r   )r5   r  ) r3   r   rv   r  r  r   r   r  r  r  r	   r  r	  r  r  r  r  r  r  r_   r  r  r  mathisnanisinfr  r  rs   r9   r2   r/   )r  api_keyr   r   r  r^  future_date	result_dfearnings_datacleaned_datar  
clean_itemrc   rd   r  r6   s                   r    fetch_earnings_apir	     s<   	
89 G_`g_h
iC<1<<R0 [[(--01xxxLBJJ6!~~b.>?B| LLNE",,J"??K%.2l3C{3RSTB -B STYY[I VI !*& 1 4 4 = =j IIf !*& 1 5 5cr :If #(Ih &--i8M L%
 JJLDAwwqzz(,
#Au--4::a==DJJqMM)-()1 ) ##J/ & 'lln668(\*$	F ,f5M ##  1*1#.//001s   H"H< <
I)I$I)$I)c                   $    \ rS rSrSrS rS rSrg)TokenBucketi:!  z%Simple Token Bucket for Rate Limitingc                     Xl         Xl        X l        [        R                  " 5       U l        [
        R                  " 5       U l        g r   )capacitytokensrefill_rater  last_refillr  r   lock)r	  r  r  s      r    r<  TokenBucket.__init__<!  s.     &99;NN$	r!   c                 j   U R                      [        R                  " 5       nX R                  -
  n[        U R                  U R
                  X0R                  -  -   5      U l        X l        U R
                  U:  a  U =R
                  U-  sl         S S S 5        g S S S 5        g! , (       d  f       g = f)NTF)r  r  r  r  r  r  r  )r	  tokens_neededr  elapseds       r    consumeTokenBucket.consumeC!  s    YY))+C,,,G dmmT[[7EUEU;U-UVDK"{{m+}, Y  YYs   BB$B$$
B2)r  r  r  r  r  N)r  r  r  r  rf  r<  r  r  r   r!   r    r  r  :!  s    /%r!   r  i  )r  r  c           
      B   [         R                  " U 5      n[        U5      S-  nSn[        R	                  U5      (       d>  US-  nUS:  a  g[
        R                  " S5        [        R	                  U5      (       d  M>  Sn[        U5       H  n [        R                  " [        S[         3S	S
.[        U UUS.SS9n	U	R                  S:X  a<  U	R                  5       n
SU
;   a"  [        U
S   5      S:  a  U
S   S   S   S   s  $ Ss  $ U	R                  S:X  a'  XS-
  :X  a    g[
        R                  " U5        US-  nM  SU	R                   3s  $    g! [         a?  nXS-
  :X  a  S[        U5       3s SnAs  $ [
        R                  " S5         SnAGM  SnAff = f)u:   Appel à l'API Groq avec retry exponentiel et Token Bucketr}  r   r  r4  z)Erreur API: Rate Limit Internal - Skippedr  r  zBearer rB  )Authorizationr  )r
  r6  r  r)  r  )r   r   r   r   choicesrj  rP  u   Erreur API: Réponse videi  z%Erreur API (429): Rate Limit Exceededr  zErreur API: zErreur: Nz Erreur API: Max retries exceeded)r   rS  rs   groq_rate_limiterr  r  r  r  r   r_  GROQ_API_URLr  
GROQ_MODELr   r2   r  )r6  r  r)  r   
input_textestimated_tokenswait_attemptsbackoffattemptr   r5   r6   s               r    r.  r.  T!  s    H%J:* M''(8992?

3  ''(899 G>#	}}'.|n%=$6
 ( (#.",	 H ##s*}}$T)_)=)A	?1-i8CC67%%,k)B 

7#3%h&:&:%;<<? "L .  	A+%!#a&**JJqMM		s=   A3EE
E$EE
FF4F<FFc                   ,    \ rS rSrS rS rS rS rSrg)r  i!  c                     / U l         g r   r  r  s    r    r<  BankForecastScraper.__init__!  s	    r!   c                     [        SU S35         UR                  USSS9  [        R                  " S	5         UR                  S
5      R                  R                  SS9  / nU H  n UR                  U5      R                  5       nUSS  HS  n	U	R                  5       R                  5       n
U
(       d  M*  [        U
5      S:  d  M;  X;  d  MB  UR                  U
5        MU     M     U(       d   S H~  nUR                  U5      R                  5       nUSS	  HS  n	U	R                  5       R                  5       n
U
(       d  M*  [        U
5      S:  d  M;  X;  d  MB  UR                  U
5        MU     M     U/ 4$ ! [         a  n[        SU SU 35         SnAGNwSnAff = f!    GNE= f!    GMJ  = f!    NB= f! [         a  n[        SU SU 35        / / 4s SnA$ SnAff = f)u"   Helper générique avec Playwrightz   Getting r   i0u  domcontentloaded)r   
wait_untilz   Navigation Warning for rm   Nrg   zMbutton:has-text('Accept'), button:has-text('Allow'), button:has-text('Agree')i  r  r  r   )h2h3h4z   Error scraping )r3   gotor2   r  r  locatorr  clickr   
inner_textr  rs   r  )r	  r1  r   title_selectorslink_selectorsnav_etitlesselelementseltxttagr6   s                r    _scrape_page BankForecastScraper._scrape_page!  s   (	KuC()C		#u9K	L JJqMlmssyy  CGy  H F&!#||C0446H&sm mmo33533s8b=S5F"MM#. , ' 1$(LL$5$9$9$;#+BQ<R#%==?#8#8#:S #C2#:K!'s!3 $0  2 2:A  C23%r%ABBC D !   	&se2aS12r6M	s   F: E9 F: (F" "F: *A
F*8F*	F*F*%F: 1AF3 F3 F3 F3 5F: 9
FFF: FF: "F'$F: *F0,F: 3F75F: :
G#GG#G#c                   ^ / n/ SQn/ SQnU R                    GHJ  nUR                  S/ 5      nU(       dg  SU;   aa  US   R                  S5      (       aH  US   R                  S5       Vs/ s H)  ofR	                  5       (       d  M  UR	                  5       PM+     nnU(       d  M  SR                  U5      R                  5       m[        U4S jU 5       5      n[        U4S jU 5       5      nS	n	Xx:  a  S
n	OX:  a  Sn	Sn
U	S
:X  a  Sn
OU	S:X  a  Sn
OSn
UR                  UR                  S5      U	S[        U5       S3U
SU	R                  5        SU SU SU
 3S.5        GMM     U$ s  snf )z#Simple heuristic analysis of titles)r  
croissanceopportunityu   opportunitébullrallystrongfortr  r  rQ  	improvingupside)	recessionu
   récessionriskrisquebearcrashdownsidebaissierr  crisiscriseweakfaibleslowdownr4  rD  
- r   c              3   6   >#    U  H  oT;   d  M
  S v   M     g7fr  Nr   r   r  r   s     r    r   7BankForecastScraper.analyze_articles.<locals>.<genexpr>!       C1dQQ   		c              3   6   >#    U  H  oT;   d  M
  S v   M     g7frS  r   rT  s     r    r   rU  !  rV  rW  r  rg  ri  r  uW   Focus sur la croissance et les opportunités d'investissement. Le narratif est positif.uM   Prudence recommandée face aux risques macroéconomiques et aux incertitudes.uM   Approche équilibrée, surveillance des indicateurs clés sans biais marqué.rX  u   Analyse basée sur 
 articles.u   Le ton général relevé est rq  z vs z). )rX  rF  rD  r  analysis_text)
r  rv   r$  r  r  r  r=   r  r  rs   )r	  analysesbullish_termsbearish_termsr\  r4  rx   
bull_score
bear_scorerF  r  r   s              @r    analyze_articles$BankForecastScraper.analyze_articles!  s}    f m<<CWWXr*F#I(A(A&(I(I14Y1E1Ef1M[1MAQXQXQZiaggi1MF[88F#))+DCCCJCCCJ!I&I	(i)NI%!zi'!p!pOO&0VZH"0#@AR@SSUV`Uaaefpeqqt  vD  uE  "F 5  D ; \s   *E)E)c                    SS/ SQS.SS/ SQS.SS	/ S
QS.SS/ SQS.SS/ SQS.SS/ SQS.SS/ SQS.SS/ SQS.SS/ SQS.SS/ SQS./
n [        5        nUR                  R                  S S!9nUR                  S"S#S$S%.S&9n[	        S'5        U H  n[	        S(US)    S*35        U R                  XES+   US,   / 5      u  pgU(       aI  U R                  R                  US)   US+   U[        R                  " 5       R                  5       S-.5        M  [	        S.US)    35        M     UR                  5         S S S 5        [	        S0[        U R                  5       S135        [        S2U R                  5        / n	U R                   Hn  n
S3S3R                  U
R!                  S4/ 5      5      -   nU	R                  U
R!                  S)5      U
R!                  S+5      U
R!                  S55      US6S7S S S8.5        Mp     [#        U	5        U R                  $ ! , (       d  f       N= f! [         a  n[	        S/U 35        / s S nA$ S nAff = f)9NJPMorganz9https://www.jpmorgan.com/insights/global-research/outlook)r*  r+  .article-title.card-title)rX  r   	selectorszBNP Paribasz1https://globalmarkets.cib.bnpparibas/markets-360/)r*  r+  z.post-titlerd  u   Société Généralez-https://insight-public.sgmarkets.com/insights)r*  r+  z.insight-titlere  Deloittezmhttps://www.deloitte.com/us/en/insights/industry/financial-services/financial-services-industry-outlooks.html)r*  r+  z.promo-titlerd  McKinseyzChttps://www.mckinsey.com/industries/financial-services/our-insights)r*  r+  rd  z.content-card h3z.item-titleBarclaysz4https://www.ib.barclays/research/global-outlook.html)r*  r+  .titlere  	BlackRockzOhttps://www.blackrock.com/us/individual/insights/blackrock-investment-institute)r*  r+  re  rd  r,  zGoldman Sachsz%https://www.goldmansachs.com/insights)r*  r+  z.ti-card-titlezspan.h3z.card__titlezMorgan Stanleyz&https://www.morganstanley.com/insights)r*  r+  rd  rj  UBSzLhttps://www.ubs.com/global/en/wealth-management/chief-investment-office.html)r*  r+  z.feature-titlez.teaser-titleT)headlessr   i   i   widthheight)
user_agentviewportz1[START] Starting Bank Scrape (Playwright Mode)...z	Scraping rX  r   r   rf  )rX  r   r4  r:  z[WARN] No titles found for z![HOT] Critical Playwright Error: z#[DATA] Bank Scrape complete. Found rY  bank_raw_scraperQ  r4  r:  r     Voir DétailsrX  r   rN  rD  rF  rY  rw   rZ  )r$   chromiumlaunchnew_pager3   r:  r  r  r	   r  r  r   r2   rs   r9   r  rv   r  )r	  targetsr  r&  r1  rx   r4  r   r6   formatted_for_dbr\  rD  s               r    r  BankForecastScraper.scrape_all!  s    #RJ &JJ /FJ # GK #\^ #MB $hP (>V )?E eL]3
l	 "a**++T+:''  Q'+s; ( 
 IJ AIai[45 $ 1 1$%!K.RT UIF++$%fI#$U8&,)1)A)A)C	-   ;AfI;GH ! / #8 	3C4E3FjQR 	)4<<8 <<Cv{{3778R+@AAG##wwu~,"&"1 $	% 	   	/0||g #"0  	5aS9:I	s=   

H CH
3H 

HH H 
H?%H:4H?:H?r%  N)	r  r  r  r  r<  r:  r`  r  r  r   r!   r    r  r  !  s    *X*Xlr!   r  c                 j    SR                  S U R                  5        5       5      R                  5       $ )Nr  c              3   |   #    U  H2  oR                  5       (       d  UR                  5       (       d  M.  Uv   M4     g 7fr   r  r	  s     r    r   r  a"  r  r  r  r  s    r    r  r  `"  r  r!   c                 <    [        S X5      R                  5       U:  $ r   r  r  s      r    r  r  c"  r  r!   c                  "   Sn [        S5      q[        S5        [        U 5      R	                  5       q[        S5        [        R                  " S/SSS9nSnSn/ nS	n[        S
5         [
        (       Gaz  [
        R                  (       Gad  [
        R                  5       nUc  [        R                  " S5        MQ  US-  nUS-  S	:w  a  Ma  UR                  u  pxn	[        US-  5      [        US-  5      p[        US-  5      [        US-  5      pXjU2X24   n[        R                  " U[        R                   5      n[        R"                  " USS[        R$                  5      u  n	n[        US-  5      [        US-  5      nn[        US-  5      nUUU2UU24   n[        R                  " U[        R                   5      n[        R"                  " USS[        R$                  5      u  n	n UR'                  USS9nUR'                  USS9nSnU(       a  / nU H  n[+        U5      S:  d  M  [+        U5      S:X  a  US   OUS	   n[+        U5      S:X  a  US   OUS   nUR-                  5       nUR/                  5       S;  d  Ml  US:  d  Mt  [+        U5      S:  d  M  UR1                  U5        M     SR3                  U5      n/ nU H  n[+        U5      S:  d  M  [+        U5      S:X  a  US   OUS	   n[+        U5      S:X  a  US   OUS   nUS:  d  MN  [+        UR-                  5       5      S:  d  Mm  UR1                  UR-                  5       5        M     SR3                  U5      n U(       a  [+        U5      S :  a  [5        [7        U5      [7        U5      5      (       d  U(       ai  [+        U5      S:  aZ  [        S!5        SR3                  U5      n!S"U S#U! S$3n" [9        S%S&S'.S(U"S'./SS)S*9n#[        R;                  X$U#5        [        S+5        [<        R>                  " 5       RA                  S-5      n%[        S.U% S/35        [        S0U S135        / nUnU (       aW  [+        U 5      S:  aH  [5        [7        U 5      [7        U5      5      (       d%  [        S2U SS3  S435        UR1                  U 5        U n[        R                  " S55        [
        (       a  [
        R                  (       a  GMd  [
        (       a  [
        RC                  5         gg! [(         a     GM  f = f! [(         a  n$[        S,U$ 35         Sn$A$GN.Sn$A$ff = f! [(         a  n$[        S6U$ 35         Sn$A$NvSn$A$ff = f! [
        (       a  [
        RC                  5         f f = fr  r  r  s&                                         r    r  r  f"  s    8C!"78	
,-(-335	
!"^^TFu=FOMK	
+,k$#3#;#;#;$))+E}

11KRA%kkGA! "%QXAHh!$QXAHhx/1BBCIi1C1CDJ!$z3SEVEV!WA $'q4x=#a$h-yIAHIy2IaK?@J,,z33E3EFK"%--S#sGXGX"YA &5 Q!'1AU!S
 J )D4yA~*-d)q.tAwd1g*-d)q.tAwd1g%)ZZ\
%++-5YY#czc*o.A + 2 2: > * !XXk2
 L&t9>&)$i1n47$q'D&)$i1n47$q'Dczc$**,&7!&;$++DJJL9 ' ((<0K c*o2!)J"7?9STT '3}+=+A?@(+(?%,_,= >? :"=
	A)6)1>o p)/F C8 ,/3*@J
 -==o^hi!$<> !) 7 78K LIM)A67C
|2./$&M&0O s;/"4!)K"8)DT:UVVGK$4#5S9:!((5'2$JJsOI #3#;#;#;R !!# U  h  ) A!$;A3"?@@A&  -'s+,,- !!# r  z/api/bloomberg-live/startc                  l   [         (       a"  [         R                  (       a  [        SS05      $  [        R                  " [
        SS9n U R                  5         [        S[        R                  " 5       R                  5       S.5      $ ! [         a"  n[        S[        U5      05      S4s S	nA$ S	nAff = f)
u'   Démarre la surveillance Bloomberg Liver   already_runningTr  startedr   r:  r   r7  N)r  r
  r   r  r  r  r  r	   r  r  r2   r  )rq
  r6   s     r    start_bloomberg_liver  "  s    
 ,44"3455/!!)>tL!113
  	  /Q()3../s   AB 
B3B.(B3.B3z/api/bloomberg-live/stopc                      [         (       aE  [         R                  5         Sq [        S[        R                  " 5       R                  5       S.5      $ [        SS05      $ )u&   Arrête la surveillance Bloomberg LiveNstoppedr  r   not_running)r  r
  r   r	   r  r  r   r!   r    stop_bloomberg_liver  "  sU    
 !113
  	
 Hm,--r!   z/api/bloomberg-live/statusc                      [         SL=(       a    [         R                  n Sn[        (       a  [        [	        5       5      n[        U U[        R                  " 5       R                  5       S.5      $ )zStatut du flux Bloomberg LiveNr   )r
  segments_capturedr:  )	r  r
  r  rs   r
  r   r	   r  r  )
is_runningsegments_counts     r    bloomberg_live_statusr  #  s_    
 "-J2B2J2JJN 134+\\^--/  r!   z/api/refresh/insidersc                  @    [         R                  " 5       =(       d    0 n U R                  S/ SQ5      n[        U5      n[	        SS[
        R                  " 5       R                  5       UUS.5      $ ! [         a"  n[	        S[        U5      05      S4s SnA$ SnAff = f)	u>   Rafraîchit les données insiders pour les tickers spécifiésr  r
  r
  r
  TSMr
  r   r   )r   	data_typer:  tickers_processedr5   r   r7  N)
r   r4
  rv   ro  r   r	   r  r  r2   r  )r5   r  r  r6   s       r    refresh_insidersr  #  s    /!'R((9&NO#G,#!113!(
  	  /Q()3../s   A.A1 1
B;BBBz/api/healthc                  x    [        S[        R                  " 5       R                  5       [        SSSSSS.S.5      $ )u"   Vérifie que le serveur fonctionner1
  r   )r   r   r  r  r  )r   r:  ws_errorservices)r   r	   r  r  r  r   r!   r    health_checkr  2#  sB     \\^--/
	  r!   c                     [         R                  5          U R                  5        H  u  p[        R                  R                  US9R                  5       nU(       d(  [        US9n[        R                  R                  U5        UR                  SS5      Ul        UR                  SS5      Ul        UR                  S/ 5      Ul        [        R                  " 5       Ul        M     [        R                  R#                  5         S S S 5        g ! , (       d  f       g = f! [$         a  n['        SU 35         S nAg S nAff = f)N)r`  average_performancer   r  r   zDB Error save sector trends: )r)   r.   r_   r_  r   r  r  r   r   r   rv   ra  rb  rc  r	   r   rU  r   r2   r3   )r5   r`  rc  rh  r6   s        r    db_save_sector_trendsr  C#  s    3__(,

$#))333LRRT'K@EJJNN5)&-kk2G&K#%,[[!%<" 'Hb 9%-__%6" )5 JJ   3-aS1223s5   D! C1DD! 
DD! D! !
E+D>>Ec                  V    [         R                  5          [        R                  R	                  5       n 0 nU  HI  nUR
                  UR                  UR                  UR                  UR                  S.XR                  '   MK     UsS S S 5        $ ! , (       d  f       g = f!   0 s $ = f)N)ra  stocks_analyzedrb  rc  r   )	r)   r.   r_  r   r   ra  rb  rc  r`  )r_   r  r  s      r    r  r  U#  s    __%%))+EF%&__'(~~$%NN yyii)}}%   	s)   B" A1B	B" 
BB" B" "B(c            
          [         R                  5          [        R                  R	                  [        R
                  R                  5       5      R                  5       n U  Vs/ s HK  nUR                  UR                  UR                  UR                  UR
                  R                  5       S.PMM     snsS S S 5        $ s  snf ! , (       d  f       g = f!   / s $ = f)N)rX  rC  r   rm  r:  )r)   r.   rl  r   r  r:  r  r   rX  rC  r   rm  r  )r_   r  s     r    db_load_bank_analysesr  f#  s    __ &&//0F0F0K0K0MNRRTE  ! uuJJ[[224   	s<   C AC$AC6C8	C C
CC C Cz/api/debug/metadata/cachec                  b    [            [        [        5      sSSS5        $ ! , (       d  f       g= f)zInspect memory cacheN)rn   r   ro   r   r!   r    debug_get_metadata_cacher  t#  s     
' 
s    
.z/api/debug/clear-metadatac                  v    [            0 qSSS5        [        S5        [        SS05      $ ! , (       d  f       N&= f)uA   Vide le cache de métadonnées pour forcer un re-téléchargementNz&[DEBUG] Metadata cache cleared via APIr   cleared)rn   ro   r3   r   r   r!   r    debug_clear_metadatar  z#  s2     
 
	
23Hi()) 
s   *
8z/api/data/allc                    ^ U4S jm [        5       n / nU (       aO  SU ;   aI  U R                  S/ 5       Vs/ s H,  o"R                  S5      (       d  M  UR                  SS5      PM.     nn0 nU(       a   [        U5      nU U[        S5      [	        5       [        S5      [        S5      [        S5      [        S	5      [        5       [        5       [        S
5      [        S5      [        5       [        R                  " 5       R                  5       S.n [        S5      =(       d    / nU(       Ga  US   (       d  S/ 0US'   [        US   [        5      (       Gai  SUS   ;  a  / US   S'   / nU GH8  nUR                  SS5      R                  5       nU(       d  UR                  S5      (       a  SnUSS [        U5      S:  a  SOS-   n	UR                  UR                  S[        R                  " 5       R                  5       5      UU(       a  U	OSSUR                  S5      [!        UR                  SS5      5      UR                  S5      UR                  S/ 5      UUR                  S5      UR                  S5      UR                  S5      UR                  S5      S.5        GM;     US   S   R#                  U5        [)        T" U5      5      $ s  snf !    GN\= f! [$         a  n
['        SU
 35         Sn
A
N;Sn
A
ff = f! [$         a0  n
['        S U
 35        [)        S![!        U
5      05      S"4s Sn
A
$ Sn
A
ff = f)#uL   Récupère toutes les données en cache + prix en temps réel + données SQLc                   > [        U [        5      (       a,  U R                  5        VVs0 s H  u  pUT" U5      _M     snn$ [        U [        5      (       a  U  Vs/ s H  nT" U5      PM     sn$ [        U [        5      (       a9  [
        R                  " U 5      (       d  [
        R                  " U 5      (       a  gU $ U $ s  snnf s  snf )Nrz  )r  r  r_   r  r  r   r  r  )objrc   rd   sanitize_nans      r    r  "get_all_data.<locals>.sanitize_nan#  s    c4  3699;?;41A|A&;??T""-01SLOS11U##zz#$**S//J
 @1s   CCr  rw   r  r  rK  r  r  r  r  r  )r  live_pricesr   r   r  r  r  r  r   r  r  r  r.  r:  rV  rL  rP  rZ  Nr   r   r2  z(Post sans texte)r   r[  rW  rY  rl  ro  rn  rs  )r:  ra  rC  rB  r   r[  rY  rZ  r
  rl  ro  rn  rs  z+[WARN] Error injecting Truth Social posts: zError in get_all_data: r   r7  )r  rv   r  r/   r  r  r  rT  r	   r  r  r  r  r  rs   r  r  rn  r2   r3   r   )r  r  r  r  r5   truth_postsformatted_social_postsr_  rP  display_titler6   r  s              @r    get_all_datar  #  s   	R/,.		14=MM+r4Rf4RqV[V[\dVe*quuXr*4RGf /8 #&$%56(*#O4-.>?&~6*=92446,_='(89,.!113
$,	E).9?RK,-.=r-BD)*d#34d;;&d3C.DDBD-.? .0* +"&((9b"9"?"?"A&488G+<+<&(G )0WPRARXZ([.55)-,@X@X@Z)[(/6=]CV&4#'88E?&)$((8=N*O&P&*hhx&8%)XXgr%:*1 /3hh7G.H/3xx8I/J15:M1N,0HH^,D7  !,< )*?;BBCYZ |D)**S g D~  	E?sCDD	E  /'s+,Q()3../sx   -L KK)L 5K  BL F/K L L KL 
L)K<7L <LL 
L>%L93L>9L>z/api/data/<data_type>c                    U S:X  a  [        [        5       =(       d    / 5      $ U S:X  a  [        [        5       =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    / 5      $ U S	:X  a  [        [        S	5      =(       d    0 5      $ U S
:X  a  [        [        S5      =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    0 5      $ U S:X  a  [        [        S5      =(       d    / 5      $ [        SS05      S4$ )u*   Récupère un type de données spécifiquer   r  r   r  r  rK  r  rV  r  r  r  r  r  r  r   u   Type de données invaliderI	  )r   r  r  r/   )r  s    r    get_specific_datar  #  s>   
 J')/R00K/17R88G'78>B??F7=2>>$$'78>B??N"~6<"==M!}5;<<I~6<"==J'78>B??O#7=2>>G89:C??r!   c                    [        U [        5      (       a/  U R                  5        VVs0 s H  u  pU[        U5      _M     snn$ [        U [        5      (       a  U  Vs/ s H  n[        U5      PM     sn$ [        U [
        5      (       a7  [        R                  " U 5      (       d  [        R                  " U 5      (       a  gU $ s  snnf s  snf )u9   Nettoie les données pour JSON (NaN -> None, Inf -> None)N)	r  r  r_   r  r  r  r   r  r  )r5   rc   rd   s      r    r  r  $  s    $15>>!$$>>	D$		+/04aq!400	D%	 	 ::dtzz$//K ?0s   CC
z/api/sector-trendsc                      [         R                  5          [        R                  R	                  5       n U (       a  0 nU  Hh  nUR
                  UR                  UR                  =(       d    / UR                  (       a  UR                  R                  5       OSS.XR                  '   Mj     [        [        U5      5      sSSS5        $ [        S:X  a4  [        S5        [        R                   " ["        SS0S9R%                  5         SSS5        0 n[        [        U5      5      $ ! , (       d  f       N$= f! [&         a  n[        S	U 35         SnANDSnAff = f)
uC   Récupère les tendances sectorielles (mensuelles) pour le frontendr  )ra  r  rc  rU  Nr  z>[WARN] Sector Trends DB empty. Triggering background update...forceT)r  r   zDB Error get sector trends: )r)   r.   r_  r   r   ra  rb  rc  rU  r  r`  r   r  r  r3   r  r  r  r  r2   )r  r  rx   r6   r5   s        r    get_sector_trendsr  $  s   2__ &&**,FA)*+,>>#$99?FGnn(@(@(BZ\	-F==)   ~f56  )F2\]&&.JT[]aSbciik! * D >$'((1 "  2,QC0112sA   D6 B)D%?	D6 	>D%D6 %
D3/D6 3D6 6
E EEr  c                    U (       d  gU R                  5       n U R                  5       S:X  d  SU R                  5       ;   a  gU R                  SS5      R                  SS5      R                  5       R                  SS5      R                  SS5      n [        U5      n[        R
                  " U5      (       a  gU$ ! [         a     gf = f)z=Clean and convert string values to float for sector analysis.rz  nan   €r  r  r|  r  )r  r=   r  r  r   r  ru   )r   r}	  r  s      r    parse_sector_valuer  1$  s    ::<Dzz|u 5 LL#++C4::<DDS"MUUVY[^_EEl::c??
 s   &B< :B< <
C	C	c                  @   [        S5        [        5       n / n [        R                  " 5       n[        R                  " U5        U R
                  R                  U R                  5        U R
                  R                  SSSS9nU(       a  X0l	        U R                  (       d  [        S5        0 $ UR                  U R                  5       5      n UR                  U R                  5       5        UR                  5         [        S	[!        U5       S
35        0 nU H  nUR                  S5      nUR                  S5      n	UR                  S/ 5      n
SnU
 H+  nUR                  S5      S:X  d  M  UR                  S5      n  O   X;  a	  USS/ S.Xk'   Xk   S==   S-  ss'   Xk   S   R#                  UU	SSS.5        M     [        S5        S n/ nUR%                  5        H  u  nnUR'                  US   5        M     0 n[)        SS9 n[+        [-        UR/                  X5      [!        U5      SS95      nU H  u  n	nUUU	'   M     SSS5        / nUR%                  5        HI  u  nnUS    H:  nUR                  US   5      US'   US   (       d  M&  UR#                  US   5        M<     MK     [        S[!        U5       S35        0 nS n[1        [+        [3        U5      5      5      n[5        S[!        U5      U5       GH  nUUUU-    n [        S!U S"U[!        U5      -    S#[!        U5       S$35        [6        R8                  " US%S&SS&S'9n[!        U5      S:X  a  US   nUR:                  (       d  [!        U5      S(:  a}   US)   nUR<                  S   nUR<                  S*   n[?        US+5      (       a  URA                  5       n[?        US+5      (       a  URA                  5       nUS:  a  UU-
  U-  S,-  n U UU'   OOU H  n UURB                  RD                  S   ;   a  UU   n!OM)  U!RG                  S)/S-9n!U!R:                  (       d  [!        U!5      S(:  a  U!S)   R<                  S   nU!S)   R<                  S*   n[?        US+5      (       a  URA                  5       n[?        US+5      (       a  URA                  5       nUS:  a  UU-
  U-  S,-  n U UU'   M  M  M  M     [H        RJ                  " S.5        GM     UR%                  5        Hd  u  nnSn"Sn#US    H<  nUR                  S5      nU(       a  UU;   a  UU   n$U$US1'   U"U$-  n"U#S-  n#M7  SUS1'   M>     U#S:  a
  U"U#-  US2'   M_  SUS2'   Mf     [        S35         [M        U5        [        S55        [1        UR%                  5       S6 S7S89n&U& H#  u  nn[        US9 S:US   S; S<US2   S= S>35        M%     U$ !    GN= f! [         a/  n[        SU 35        SSKnUR                  " 5         0 s SnA$ SnAff = f! , (       d  f       GN= f!    GNU= f! [         a  n SnAGMH  SnAff = f! [         a  n[        S/U S0U 35         SnAGMu  SnAff = f! [         a  n%[        S4U% 35         Sn%A%GNSn%A%ff = f)?z[
Scrape sector data using Trade Republic API (WebSocket).
Replaces Playwright methodology.
z;[START] Starting Sector Discovery via TR API (WebSocket)...r   r   Nr   zR[ERROR] Cannot scrape sectors: Not logged in. Please login via Web Terminal first.z[ERROR] API Fetch failed: r   z[DATA] Processing z stocks into sectors...rA   r   rt  u   Non classér
  r`   rz  )r`  r  r  r   r  r  r   )rA   r   rw   performancezL[START] Enriching sector data (Tickers + Performance)... this may take time.c                      [         R                  5          [        U S   5      nU S   U4sS S S 5        $ ! , (       d  f       g = f! [         a  nU R	                  S5      S 4s S nA$ S nAff = f)Nr   )r)   r.   r   r2   rv   )r  rx   r6   s      r    resolve_ticker_wrapper3scrape_sectors_data.<locals>.resolve_ticker_wrapper$  s\    	-"(v7fq) #""  	-IIf%t,,	-s6   A 5	A 
AA A 
A-A("A-(A-rg   r  zResolving Tickers)r~   r  rw   z [DOWN] Fetching performance for  tickers...r   zDownloading batch z to z of r   r`  F)rg  rc  r  r	  r  rd  r  r  r*  r  r	  zBatch download error for batch rm   r  r  $[SAVE] Saving Sector Trends to DB..."Error saving sector trends to DB: z,
=== [DATA] SECTOR TREND SUMMARY via API ===c                     U S   S   $ )Nr  r  r   r  s    r    r  %scrape_sectors_data.<locals>.<lambda>%  s    1Q4=r!   Tr^  <40z
 | Count: z>5z | Avg Perf: rr  r  )'r3   rk  r   r   r   r   r   r   rv   r   r   r   r   r2   r   r   rs   r  r_   rn  r   r  r   rZ  r`  r  r  rp   r  r  r
  r^   r  r  ry  r  r  r  r  )'	local_apistocks_listr   r  r6   r   all_sector_datar  rA   r   rt  r`  r9  r  all_stocks_flats_names_dataisin_mapr  r  rw   r
  ticker_perf_map
BATCH_SIZEsorted_tickersr  batchr5   rx   rk  start_pend_prf  df_t
total_perf
count_perfr  db_errsorted_sectorss'                                          r    scrape_sectors_datar  C$  s   
 

GH !"IK%%'t$ 	i334  $$X|d$K',$&&fgI--i.R.R.TU	$$Y__%67

 
s;/00G
HIO yy yy yy$#Cwwv(*!ggfo 
 -*'*	,O( 	$W-2-$X.55	7
 	) 8 

XY- O)//1vh/0 2 H		*htHLL)?QY\]lYm  uH  I  J#LD&#HTN $ 
+ M)//1H%E&ll5=9E(OX$$U8_5 & 2 
,S-?,@
LMOJD]!345N1c.):6q:.4	>&qcaE
l^4N@S?TTWXY ;;uUUX_deD 5zQ!Hzzc$i1n!!%g"(++a. &B #7F33w||~W"5&115::<5"Q;%*W_$?3#FD15OA. A 3 3A 66$(GT%#{{7){<#zzc$i1n&*7m&8&8&;G$(M$6$6r$:E&w777<<>&uf55uzz|u&{).G(Cs'J59 2  + /=z . JJsOg 7t *//1

H%E		(#AQ/)#A&'(m$a
a
'*m$ & >,6,CF(),/F()# 2& 
02=o. 

9:O1139PZ^_N$
dc
*T']2$6mDI^D_`cCddefg % S 	  *1#./		t 
+	*\ !D* %   	>3A3b<==	>6  =26(;<<=s   BW! /W! W .W! 	>X
A6YA;X/<Y#X7'Y)B,X7 Y>Y: WW! !
X+$XXX
X,/X41Y7
YYYY
Y7Y22Y7:
ZZZc                     SSK n SSKnSSKJn  SnSn[	        S5        0 nU" 5        nUR
                  R                  USSS	S
.S/ SQSS9nUR                  (       a  UR                  S   OUR                  5       n[	        S5        UR                  S5        UR                  S5        UR                  " S5        [	        S5         UR                  SSS9n	U	R                  5       (       d  [	        S5        UR                  SSS9n	U	R                  R                  5         UR                  " S5        UR                  S5      R%                  5       n/ nU HU  nUR                  S5      R'                  5       nUR                  S5      R)                  S5      nUR+                  XS.5        MW     [	        S [-        U5       S!U Vs/ s H  nUS"   PM
     sn 35        UR.                  R1                  S#5        UR                  " S5        / S$QnU GH  nUS"   nUU;   a  [	        S%U 35        M  [	        S&U 35        U	R                  5         UR                  " S'5         UR                  S(S)S9nUR3                  5       (       a"  UR                  5         UR                  " S*5        UR                  SUS9R                  nUR                  5         UR                  S(S+S9nUR3                  5       (       a  UR                  5         OUR.                  R1                  S#5        UR                  " S,5        SnS-nSnUU:  a  UR                  S.5      R                  5       nUU:  a@  UnUS/-  S:X  a  [	        S0U S135        UR5                  S25        UR                  " S35        SnOUS-  nUR                  " S'5        US:  a  OUU:  a  M  UR                  S.5      R%                  5       n/ n[	        S4[-        U5       S535        U GH  n UR                  S65      nUR                  S75      nUR                  5       S:  a  UR'                  5       OS8nUR                  5       S:  a  UR'                  5       OS8n UR                  S95      n!U!R                  5       S:  a  U!R'                  5       OS:n"U!R                  5       S:  a  U!R)                  S5      OS;n#UR                  S<5      R%                  5       n$S=n%[-        U$5      S:  a  U$S   R'                  5       n% [7        U"5      n&[8        R:                  " U&5      (       a  S>n&U#(       a,   [=        U#5      S/-  n'[8        R:                  " U'5      (       d  U'n&UR+                  UU U%U&S?.5        GM     U(       as  [?        S@ U 5       5      [-        U5      -  n)URA                  SA SSB9  [	        SCU)SD SE35        [	        SFUS   S"    SGUS   SH   SD SI35        U)[-        U5      USJ.UU'   GM  SS/ SJ.UU'   GM     [	        SK5         [C        U5        [	        SM5        [	        SN5        [E        URG                  5       SO SSB9n+U+ H3  u  nn,[	        USP SQU,SR   SS STU,SU   (       a  U,SU   S   S"   OS= 35        M5     UR#                  5         SSS5        U$ ! [          a3  n
[	        SU
 35        UR#                  5         0 s Sn
A
sSSS5        $ Sn
A
ff = fs  snf !    GNV= f!   S>n& GN= f!    GN= f! [          a  n( Sn(A(GM  Sn(A(ff = f! [          a  n*[	        SLU* 35         Sn*A*GNSn*A*ff = f! , (       d  f       U$ = f)VzG
Scrape sector data using Playwright.
Integrated from fetch_sectors.py
r   Nr#   z./browser_sessionr  z)[START] Starting Sector Trend Analyzer...Ti  i8  rn  r?  )	z---disable-blink-features=AutomationControlledrZ  z--disable-setuid-sandboxr[  z--disable-accelerated-2d-canvasz--disable-gpuz--window-size=1920,1080z--start-maximizedz--lang=fr-FRr   )user_data_dirrm  rr  localer9  rq  z$? Navigating to Stock Browse page...z*https://app.traderepublic.com/browse/stocknetworkidler}  z"[SEARCH] Opening Sectors filter...zbutton.filterSectionSecteurs)has_textz0[WARN] 'Secteurs' not found, trying 'Sectors'...Sectorsr  z-[ERROR] Could not find Sector filter button: z%.filterSection__popover .filterOptionz.filterOption__nameinputrR  )rA   rR  z[LOG] Found z
 sectors: rA   Escape)z
Large CapszMid Capsz
Small CapszLarge/Mid CapszMid/Small Capsz
Micro Capsz? Skipping excluded sector: z
[NEW] Analyzing Sector: r	  z.filterSection__popover buttonEffacerr  	Appliquerr  r   z.instrumentTableWrapper__rowr*  z   Loading more... (z items)z.window.scrollTo(0, document.body.scrollHeight)r  z	   Found z total stocks (Scrolled).z.instrumentResult__namez.instrumentResult__detailsrh   zdata.performance__relativez0%r  z
.tableCellr  rz  )rA   r   
price_textr  c              3   *   #    U  H	  oS    v   M     g7f)r  Nr   r   r   s     r    r   5old_scrape_sectors_data_playwright.<locals>.<genexpr>%  s     F1r  c                     U S   $ )Nr  r   r  s    r    r  4old_scrape_sectors_data_playwright.<locals>.<lambda>%  s    <r!   r^  z   Avg Performance: rr  r  z   Top Mover: rq  r  rr  )r  r  r   r  r  z*
[OK] Analysis complete. Data saved to DB.z$
=== [DATA] SECTOR TREND SUMMARY ===c                     U S   S   $ )Nr  r  r   r  s    r    r  r  %  s    qtLaGbr!   r  z | Avg: r  z>6.2fz	% | Top: r   )$r   r  playwright.sync_apir$   r3   rv  launch_persistent_contextpagesrx  r-  wait_for_load_stater  r.  r  r  r/  r2   r   r   r0  get_attributer  rs   keyboardpress
is_visibleevaluater  r   r  r  r  r	  r  r`  r_   )-r   r  r$   USER_DATA_DIROUTPUT_FILEr  r  r&  r1  
sector_btnr6   sector_optionssectors_listoptrA   	input_valr   EXCLUDED_SECTORSr`   r`  	clear_btnopt_locator	apply_btn
last_countMAX_SCROLL_ATTEMPTSattempts
rows_countr  sector_stocksr  name_elisin_elr   perf_elchange_pct_textchange_val_attrcellsr  r  r  row_erravg_perfr  r  r5   s-                                                r    "old_scrape_sectors_data_playwrightr	  %  sM    3'M&K	
56O		a**66'#t4
 I! 7 
& $+==w}}Qg6F6F6H45		>?  /

1 	23	&<zRJ##%%HI!\\*@9\U
""$JJqM &MNRRT!C;;45@@BDG,::7CI BC	 " 	S./zl:[l1V9l:[9\]^ 	H%

1

 #F .K..5k]CD.{m<= JJsO LL)IT]L^	''))OO%JJsO
 ,,'NYd,ekkK %EP[\I##%%!$$X. JJqM J"$H00!\\*HIOOQ

*!+J!C'1, 4ZLHI MM"RSJJsO HMHJJsO1}# 00( << >?CCEDMIc$i[(ABC3!kk*CDG!kk*FGG 4;==?Q3F7--/ID3:==?Q3F7--/ID "kk*FGG>EmmoPQ>Qg&8&8&:W[OHOZ[H[g&;&;G&DadO  KK599;E!&J5zA~%*1X%8%8%:
)%7%H
::j11),J
 '!"'"83">C#'::c??-0
 "(( $ $&0&0	* Y n FFF]I[[""'@$"O,XcN!<=}Q'7'?&@=QRCST`CabeBffhij ,4 /+0, ,- 0,S #` 	46	A!/2 	;= 	56 5 5 7=blpq(JD$T#Jht,A'B5&Iptu}p~SWX`SabcSdekSl  EJ  SK  L  M ) 	C 
F y  	A!EFMMOIU 
	N	 ;\@\)%(
!  ! :  	A6vh?@@	Ak 
	F s   B]A,Z22B][2B]A[7&D"]
?]
D\([?\
+\	5\B]$\*/A9]2
[/<[*[/]*[//]7[<9]?\	\	\	\
\'	]"\'	']*
]4]]]]
]c                 N   [         R                  SS9(       d  [        S5        0 $  U (       d   [        R	                  5          [
        R                  R                  5       nUS:  aE  [        SU S35        Sq[        SS5        [        5       sS	S	S	5         [         R                  5         $  S	S	S	5        [        S5        Sq[        SS5        [        5       nU(       d0  [        S5        Sq[        SS5        0  [         R                  5         $ Sq[        SS5        [        5        [         R                  5         $ ! [         a     $ f = f! , (       d  f       N= f! [         a  n[        S
U 35         S	nANS	nAff = f! [         a     $ f = f! [         a     $ f = f! [         aM  n[        SU 35        Sq[        SS5        0 s S	nA [         R                  5         $ ! [         a     $ f = fS	nAff = f!  [         R                  5         f ! [         a     f f = f= f)u   
Recalcule les tendances mensuelles via Browser Automation (Scraping du site).
Remplace la méthode PDF+Yahoo qui causait des problèmes de catégorisation ('Others').
F)blockingz>[WARN] Sector analysis already running. Skipping this request.r   z [OK] Sector Trends exist in DB (z5 records). Skipping massive update (User Preference).r   r   Nz'Error checking existing sector trends: z7[START] Starting Sector Trends Update (Browser Mode)...scrapingr
  z*[ERROR] Browser scraping returned no data.r   z [ERROR] Error in sector update: )r  acquirer3   r)   r.   r_  r   r  r  r   r  ru
  RuntimeErrorr2   r  )r  r  r6   r5   s       r    r  r  &  s     &&&6NO	(	E__&'--335Eqy @G|}~/8,+OYG46 '&B	'')A ! ' 	GH)OY7"$?@$+! ':	'')  )OY7$&	'') 		G '&  E?sCDDE8  		| 		  045&OW5		'') 			'') 		s   F# E AE	E D=.E 6AF# ;FF# (F=
E
	E

EE F# E 
F (E;6F# ;F  F# 
FF
F F #
G:-G5
G:G= G%%
G21G25G::G= =H$?HH$
H!H$ H!!H$z/api/sector-trends/refreshc                       S n [         R                  " U S9nUR                  5         [        SSS.5      $ ! [         a#  n[        S[        U5      S.5      S4s SnA$ SnAff = f)	uJ   Recalcule les tendances mensuelles (yfinance) basé sur sector_trends.jsonc                  x     [        SS9  [        S5        g ! [         a  n [        SU  35         S n A g S n A ff = f)NTr  zUpdate Sector Trends FinishedzError in background update: )r  r3   r2   r:   s    r    
run_update)refresh_sector_trends.<locals>.run_updateD&  s;    :,4856 :4QC899:s    
949rm
  r   u3   Mise à jour des tendances lancée en arrière-planr8  r   r7  N)r  r  r  r   r2   r  )r  rq
  r6   s      r    refresh_sector_trendsr  ?&  sd    D	: !!4)8mnoo D'c!f=>CCDs   47 
A$AA$A$z/api/pdf/refreshc                      [        S5        [        5         [        5       n [        S[	        U 5      [	        U 5       S3S.5      $ ! [
         a1  n[        SU 35        [        S[        U5      S.5      S4s S	nA$ S	nAff = f)
u7   Télécharge le PDF TradeRepublic et extrait les stocksz"Lancement de la mise a jour PDF...r1
  z instruments extraits du PDF)r   r  rj  zErreur update PDF: r   r8  r7  N)r3   r   r   r   rs   r2   r  )r   r6   s     r    refresh_pdf_datar  T&  s|    D23(*$VCPVK=XtIuvww D#A3'('c!f=>CCDs   AA 
B &A;5B ;B r  msftr  aaplnvidianvdateslatslar  amznr  facebookalphabetr  googlr  nflxamdintelintcfedzfed-interest-ratezfederal reservezfed interest ratezs&p 500zsp-500r  spyr  qqqr  zgold-pricesoilbitcoinbtcethereumethsolanatsmcasml)r-  solr.  r/  c                   <    \ rS rSrS rS rS
S jrS rS rS r	S	r
g)PolymarketServicei&  c                 &    SU l         SSS.U l        g )Nz https://gamma-api.polymarket.comr   rB  rP  r;  r   r  s    r    r<  PolymarketService.__init__&  s    : L(
r!   c                    SU 3n [         R                  " X R                  SS9nUR                  5          SSKJn  U" UR                  S	5      nUR                  S
SS9nU(       d  / $ [        R                  " UR                  5      nUS   S   S   S   S   S   S   S   n	/ n
[        5       nU	 GH0  nUR                  S/ 5       GH  nUR                  SS5      nX;   a  M  UR                  U5        UR                  SS5      n[        UR                  SS5      =(       d    S5      n[        UR                  SS5      =(       d    S5      nUR                  S5      nSU 3nUR                  S/ 5      n[!        U5      S:X  GaI  US   n [#        UR                  S5      [$        5      (       a/  [        R                  " UR                  SS 5      =(       d    S 5      OUR                  S5      =(       d    / n[#        UR                  S!5      [$        5      (       a/  [        R                  " UR                  S!S 5      =(       d    S 5      OUR                  S!5      =(       d    / n['        [)        [!        U5      [!        U5      5      5       Vs/ s H  nUU   UU   S".PM     nnUR                  S#5      =(       d    UnU(       a  US   OS$nO/ nUnS$nU H  n [#        UR                  S5      [$        5      (       a/  [        R                  " UR                  SS 5      =(       d    S 5      OUR                  S5      =(       d    / nUR                  S%5      =(       d    UR                  S#5      =(       d    SnU(       a  US   OS$nUR+                  UUS".5        M     UR-                  S& S'S(9  U(       a  US   S)   nU
R+                  UUUUUUUUSS*.	5        GM     GM3     U
R-                  S+ S'S(9  U
$ ! [         a  n[        SU SU 35        / s SnA$ SnAff = f! [         a  n[        SU SU 35        / s SnA$ SnAff = f! [         a    / / nn GNf = fs  snf ! [         a    / n GN-f = f),u   
Scrape directement https://polymarket.com/predictions/<slug>
en parsant __NEXT_DATA__ — MÊME données que le site officiel.
Retourne la liste des events avec markets, volume, liquidity, endDate.
z#https://polymarket.com/predictions/rA  r   zPolymarket scrape error (r  Nr   r   rQ  script__NEXT_DATA__)r-  props	pagePropsdehydratedStatequeriesr/  r5   r  zPolymarket parse error (r  slugr  rC  r  	liquidityendDatehttps://polymarket.com/event/marketsr  outcomePrices[]outcomesrA   r  questionr  groupItemTitlec                 0    [        U S   =(       d    S5      $ )Nr  r   )r  r  s    r    r  ;PolymarketService.scrape_predictions_page.<locals>.<lambda>&  s    %'
a:Pr!   Tr^  r  	rF  probabilityrD  
volume_usdr>  r  r   
event_slugrelevance_scorec                     U S   $ NrL  r   r  s    r    r  rI  &  s    1\?r!   )r   rv   r   r  r2   r3   bs4r   r   r  r   r  r<  r  r   r  rs   r  r  r  r  r  r	  )r	  r=  r   r   r6   _BSra  nd_tagndr  r  
seen_slugsr1  eventrM  event_title	event_vol	event_liq	event_end	event_urlsub_marketsrc  r  namesr  formatted_outcomesrF  probar   	yes_prices                                 r    scrape_predictions_page)PolymarketService.scrape_predictions_page&  s    4D6:	<<\\2FD!!#
	0tyy-0DYYxOY<F	FMM*B[-)++46679!!'))02E U
D)R0"YYvr2
+z*#ii4#EIIh$:$?a@	#EIIk1$=$BC	#ii	2	 =j\J	#ii	26
 {#q(#AA/U_`a`e`efu`vx{U|U|AEE/4,H,PD!Q  DE  DI  DI  JY  DZ  D`  ^`PZ[\[`[`ak[lnqPrPrAEE*d,C,Kt!Lyzy~y~  @J  zK  zQ  OQ [``cdghndoqtuzq{`|Z})~Z}UV58fQi*PZ}&)~ uuZ0?KH)/F1ISE *,&*HE((Ycdedidijydz|  ZA  ZATZZot0L0TPT%U  HI  HM  HM  N]  H^  Hd  bdF !"&6 7 R155;L RPR17F1IS	*11592UV ) '++0PZ^+_) 21 5g > (#( 2"+!* )$",'+
  
] 1 x 	2DAe  	-cU#aS9:I	  	,SEQC89I	< % /(*B/)~  ) (%'F(sl   /O9 1P# ):P# CQQ"A-Q'9
P PP P #
Q
-Q?Q
Q
QQ'Q7	6Q7	Nc                 ~  ^ Uc  U/n[        [        R                  U/[        U5      -   5      5      nU Vs/ s H  oDR                  5       PM     nn[	        5       n/ nU GH@  n [
        R                  " U R                   S3U R                  USSSSS.SS9n	U	R                  5         U	R                  5       =(       d    / n
U
 GH  nUR                  SS5      nX;   a  M  UR                  S/ 5      nU(       d  M8  / nU GHY  nUR                  S5      =(       d    SR                  5       m[        U4S jU 5       5      (       d  MH  [        UR                  SS5      5      nUS:  a  Mk   [        R                  " UR                  SS5      5      n[        R                  " UR                  SS5      5      n[!        [#        [%        U5      [%        U5      5      5       Vs/ s H  nUU   UU   S.PM     nnUR'                  UR                  S5      U(       a  US   OSUU[        UR                  SS5      5      UR                  S5      SU 3USS.	5        GM\     U(       d  GM  UR)                  U5        UR+                  S SS9  UR-                  U5        GM     GMC     [	        5       n/ n[/        US SS9 H3  nUS   U;  d  M  UR)                  US   5        UR'                  U5        M5     U$ s  snf ! [         a  n[        S	U S
U 35         SnAGM  SnAff = f! [         a    / / nn GN~f = fs  snf )u   
Recherche TOUS les marchés actifs liés à une entité (entreprise, ticker...).
Utilise plusieurs requêtes textuelles et filtre UNIQUEMENT sur le titre de la question.
Equivalent à ce qu'affiche polymarket.com/predictions/<slug>.
N/eventsfalser*  
volume24hr)r0  r0  rC  r  r  rB  rD  z Polymarket entity search error (r  r=  r  rA  rF  c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   )r   tokquestion_lowers     r    r   5PolymarketService.search_by_entity.<locals>.<genexpr>'  s     Mn4r  r  r   rB  rC  rD  rE  r  r>  r?  r@  rJ  c                     U S   $ rP  r   r  s    r    r  4PolymarketService.search_by_entity.<locals>.<lambda>7'      <r!   Tr^  c                     U S   $ rP  r   r  s    r    r  rl  ='  s    qr!   )r  r  fromkeysr=   r  r   rv   r;  r   r  r   r2   r3   r  r  r  r  r  rs   r  r   r	  rn  r`  )r	  entity_namesearch_terms	all_termsrx   match_tokensrU  r  ru  r   r5   r6   rV  r=  markets_listvalidr  r  r  r]  r  r^  seen_qdedupedrc  ri  s                            @r    search_by_entity"PolymarketService.search_by_entity&  s    '=L}tL7I'IJK	+459a	95U
D#<<}}oW- LL!%3%1I ))+}},"
 yy,%$yyB7# *F&,jj&<&B%I%I%KNMMMM 

8Q 78CQw /!%FJJ,M!N $

6::j$+G H
 "'s3v;E
'C!D*!DA "'qF1I>!D ' * LL$*JJz$:4:vay$6&)%*6::k1+E%F$*JJy$9!>tfE&*+/
" 
# +:  t$

8$
Gu%a  D %>MA}F*

1Z=)q! N
 ] 6   8c!EF4 % /(*B/*s7   K6%AK;,AL%!L:
;
L"LL"%L7	6L7	c                 "    U R                  X/S9$ )z9Kept for backwards compat. Delegates to search_by_entity.rq  )rx  )r	  tag_slugs     r    search_by_tagPolymarketService.search_by_tagD'  s    $$XJ$GGr!   c           
         U(       d  U$ [        U5       VVs/ s H  u  p4X4S   S.PM     nnnSU SU S[        R                  " USS9 S3n [        S	US
./SSS9nUR	                  SS5      R	                  SS5      R                  5       n[        R                  " SU[        R                  5      nU(       aw  [        R                  " UR                  S5      5      n	U	 V
s0 s H  n
SU
;   d  M  SU
;   d  M  U
S   U
S   _M     nn
[        U5       H  u  p4UR                  US5      US'   M     UR                  S SS9  U$ s  snnf s  sn
f ! [         a  n[        SU 35         SnAU$ SnAff = f)u   
Soumet les titres des marchés à Groq (LLM) pour scorer leur pertinence financière (0-10).
Retourne la liste avec 'relevance_score' rempli, triée par score desc.
rF  )r-  rC  z-You are a financial analyst. The user holds "z" in their portfolio.
Below are prediction market titles from Polymarket. Score each one's FINANCIAL RELEVANCE for someone holding z stock (0-10):
- 9-10: Direct stock price impact (earnings, CEO change, major acquisition)
- 7-8: Significant indirect impact (regulatory, macro competitor)
- 4-6: Related but minor
- 0-3: Tangential or noise

Markets:
F)ensure_asciizL

Return ONLY a JSON array: [{"id": 0, "score": 8},...] with no explanation.r(  r&  iX  rz  r)  r  r*  r  r+  \[.*\]r   r-  rk  rN  c                 6    U R                  S5      =(       d    S$ )NrN  r   r  r  s    r    r  ;PolymarketService.score_markets_with_groq.<locals>.<lambda>d'  s    quu->'?'D1'Dr!   Tr^  zGroq scoring error: N)r  r   rS  r.  r  r  r  r  r|  r  r  rv   r	  r2   r3   )r	  rA  asset_contextr  rc  r4  r  r	  r  scoredr   	score_mapr6   s                r    score_markets_with_groq)PolymarketService.score_markets_with_groqH'  s   
 N@I'@RS@Rz]3@RS;M? K##0/ 2
 F?@ A[\ 		.&V!D ERUcfgC++i,44UB?EEGCIIibii8EEKKN3:@_&QDAI0RY]^R^0QtWaj0&	_%g.DA+4==A+>A'( /LLDdLS 1 T$ `  	.(,--	.s<   EBE #
E
1E
9E
<E 
E 
E2E--E2c                   ^^ U R                    S3nTSSSSS.n [        R                  " X R                  USS9nUR	                  5         UR                  5       nU(       d  / $ / nTR                  5       R                  5       nU GH  n/ n	UR                  S/ 5      n
UR                  S	S
5      R                  5       nUR                  SS
5      R                  5       nU
 GH  nUR                  SS
5      R                  5       mUR                  S	S
5      R                  5       nT SU 3nT SU SU SU 3nSnSnU H  nUU;   a  US-  nUU;   d  M  SnM     US:X  a  M  U(       d  M  [        U5      S:  a  U[        U5      :  a  M  / SQn[        U4S jU 5       5      (       a*  [        U4S jU 5       5      (       d  [        ST 35        M  [        UR                  SS5      5      nUS:  a  GM   [
        R                  " UR                  SS5      5      n[
        R                  " UR                  SS5      5      n/ n[        [        U5      [        U5      5      n[        U5       H  nUR                  UU   UU   S.5        M     U(       a  US   OSnU	R                  UR                  S5      UUUUR                  S5      SUR                  S5       3UR                  S5      S .5        GM     U	(       d  GM  U	R!                  S! SS"9  U	S   nUR                  U5        GM     UR!                  S# SS"9  US$S $ !   / n/ n GN= f! ["         a  n[        S%U 35        / s S$nA$ S$nAff = f)&u   
Recherche des marchés sur Polymarket via l'API Gamma.
Fallback sur /events avec filtrage client strict car /markets?q renvoie 422.
rd  r*  re  rf  )r0  rC  r0  r  r  r  rD  rA  ru  r  rC  rF  r   r   Fr  T)z
logan paul	charizardpokemonboxingz	jake paulmikaylahzdemi lovatoc              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   )r   badrF  s     r    r   3PolymarketService.search_markets.<locals>.<genexpr>'  s     Dms(?mr  c              3   H   >#    U  H  oTR                  5       ;   v   M     g 7fr   )r=   )r   r  r   s     r    r   r  '  s!     Pq~jmX]XcXcXeQeq~   "z$[BLOCK] [FILTERED] Garbage content: r  r   rB  rC  rD  rE  r  r?  r@  r=  )rF  rK  rD  rL  r  r   rM  c                     U S   $ rP  r   r  s    r    r  2PolymarketService.search_markets.<locals>.<lambda>'  s    Q|_r!   r^  c                     U S   $ rP  r   r  s    r    r  r  '  s    qr!   NzErreur API Polymarket: )r;  r   rv   r   r  r   r=   r  rs   r  r3   r  r  r  r  r  r	  r2   )r	  r   endpointrE  r   r5   r  query_wordsrV  event_matchesrA  event_descriptionrW  r  market_descprimary_search_textfull_search_textmatch_countprimary_matchr  garbage_termsr  r  r]  r^  rC  r  r_  best_marketr6   rF  s    `                            @r    search_markets PolymarketService.search_marketsi'  s|    mm_G, ! 
j	||Hll6[\]H%%'==?D	G++---/K
 !#))Ir2$)IImR$@$F$F$H!#ii4::<%F%zz*b9??AH"(**]B"?"E"E"GK .6Ja}*E'*21[MCTBUUVWbVc'd$"#K$)M( 00'1,K 33,0M	 ) #a' )( ;'!+c+>N0N  %}MDmDDDSPq~PMM DXJOP  #6::h#:;F{H#!%FJJ,M!N $

6::j$+G H *,&FSZ8E"5\*11$)!H%+AY3  * *0F1ISE!(($*JJz$:',$6&,$*JJy$9!>uyy?P>QR&+ii&7* y &N !=!&&+Dd&S"/"2KNN;/k p LL6LE3B<M#!# "L  	+A3/0I	sM   AM $C,M B#M 8AMB<M AM MM 
M7M2,M72M7r4  r   )r  r  r  r  r<  ra  rx  r}  r  r  r  r   r!   r    r2  r2  &  s'    
\|ZxHB|r!   r2  z/api/predictions/portfolioc            	          [        5       n [        5       n0 SSS/_SSS/_SSS	/_S
SS/_SSS/_SSS/_S/ SQ_S/ SQ_SSS/_SS/_SSS/_SSS /_S!S"/_S#S$S%/_S&S'S(/_S)S*S+/_n/ nS,/ S-Q4S.S.S//4S0S0S1/4S2/ S3Q4S4S4S5/4S6S7S8/4S9S9S:/4/n[        S;5        U H  u  pV[        R	                  UR                  5       5      nU(       a  U R                  U5      nOU R                  XVS<9nU H<  n	U	S=   U;  d  M  S>U	S?'   XYS@'   UR                  U	5        UR                  U	S=   5        M>     M     UR                  SA SBSC9  USDSE n/ n
 [        R                  R                  [        R                  R                  5       5      R!                  SF5      R#                  5       n/ nU H  nUR$                  (       d  M  UR$                  R'                  SGSH5      R)                  5       nU(       d  MI  USI   n[+        U5      SJ::  a  [+        U5      SK:  a  USI    SLUSK    3nUR                  5       SM;   a  M  UR                  U5        M     [-        [        U5      5      n[        SNU SO35        U GHB  nUR                  5       n/ n[        R	                  U5      nU(       a,  U R                  U5      n[        SPU SQ[+        U5       SR35        U(       d>  UR	                  UU/5      nU R                  UUS<9n[        SSU SQ[+        U5       ST35        U(       d  M  U R/                  UU5      nU V	s/ s H$  oR	                  SU5      =(       d    SISV:  d  M"  U	PM&     sn	SDSW nU(       d  USDSJ nU H=  n	U	S=   U;  d  M  SXU	S?'   UU	S@'   U
R                  U	5        UR                  U	S=   5        M?     GME     U
R                  SY SBSC9  U
SDSF n
[3        S[UU
S\.S].5      $ s  sn	f ! [0         a  n[        SZU 35         SDnAN3SDnAff = f! [0         a1  n[        S^U 35        [3        S_[5        U5      S`.5      Sa4s SDnA$ SDnAff = f)bu   
Remplacer la logique news-based par une logique portfolio-based + Macro.
Utilise le code de test 'correct' intégré dans PolymarketService.
Retourne des résultats séparés: Macro vs Portfolio.
r  r
  r
  r  r  r
  r  r  r
  r  r  r
  r  r  r
  r  r  r
  r  )Alphabetr  r
  r  r  r  NFLXr"  r  r#  r  r
  r.  TSMCr  r/  r  r)  r  BTCr+  r  ETHr-  SolanaSOLzFed Interest Rate)Fedr>  zInterest RateNasdaqQQQrc  XAUrS   )rS   r  SPY	RecessionzUS RecessionzUS Inflation	InflationCPIr  zEuropean Central Bankz%? Polymarket Search: Macro targets...r{  rF  Macrosource_categorysource_keywordc                     U S   $ rP  r   r  s    r    r  +get_portfolio_predictions.<locals>.<lambda>!(  rm  r!   Tr^  NrB  r  r  r  r   r}  r  r   )r;  eurousdeurrX  z? Polymarket (scrape+NLP): r   z  [WEB] Scrape 'z': z eventsz  [SEARCH] Entity 'z marches brutsrN  rg   r  	Portfolioc                 Z    U R                  S5      =(       d    SU R                  SS5      4$ )NrN  r   rL  r  r  s    r    r  r  Y(  s(    !%%8I2J2OaQRQVQVWcefQg1hr!   z"Error getting portfolio keywords: r   )r   r  )r   r  z(Error extracting portfolio predictions: r   r8  r7  )r2  r  r3   POLYMARKET_PAGE_SLUGSrv   r=   ra  rx  r  r   r	  ro  r   r  r<  r  rC  r   rA   r  r  rs   r  r  r2   r   r  )serviceseen_questionsENTITY_SEARCH_MAPmacro_resultsmacro_targetsr   terms	page_slugrA  rc  portfolio_resultsr  portfolio_keywordsr  r  	candidatetarget_original	tgt_lowerrq  relevantr6   s                        r    get_portfolio_predictionsr  '  sA   }D#%
x(
gv&
 gv&
 +v.	

 x(
 VV$
 7
 5
 	6*
 E7
 gv&
 VUO
 VH
 	5)
 U+
  x'!
(  "MN8U"3465/2";<;"?@;"675*A"BC
 	57)LE-11%++-@I!99)D!2252MZ=6+2A'(*/&'!((+"&&q}5  * 	8$G%bq) 6	<*0099:J:V:V:[:[:]^ddeghllnK!#"888HH,,S"5;;=E ( %aI9~*s5zA~',Qxj%($<	 (,UUW_&--i8 # "&c*<&=!>/0B/C3GH#5+113	 255i@	%==iHG,YKs3w<.PQ #4#8#8_DU#VL%66Ua6bG//@CL>Q_`a "99'?S'.Ww!559J3K3PqUV2VAwWXZYZ[&r{H!A}N:/:+,.=*+)003&**1Z=9 "3 $6B ""'hrv"w 1#2 6 &.
  	) X  	<6qc:;;	<  D8<='c!f=>CCDsv   C4P :AP 	A.O! ;E5O! 0!OOO! =AO! P O! !
P+O>9P >PP 
Q&P<6Q<Qz/api/predictions/tagc                     [         R                  R                  S[         R                  R                  SS5      5      R                  5       n [         R                  R                  SS5      R                  5       n[         R                  R                  SU 5      nU (       d  [	        SSS.5      S	4$ U(       aF  UR                  S
5       Vs/ s H)  o3R                  5       (       d  M  UR                  5       PM+     snOSn [        5       n[        R                  U R                  5       5      nU(       a  UR                  U5      nO/ nU(       d  UR                  XS9nU(       d  UR                  U 5      nUR                  Xr5      n[	        SU U[        U5      US.5      $ s  snf ! [         a1  n[        SU 35        [	        S[!        U5      S.5      S4s SnA$ SnAff = f)ua   
Recherche polymarket par entité: ?entity=Microsoft&terms=Microsoft,MSFT&context=Microsoft MSFT
entityr9  r  r  contextr   z%Missing 'entity' or 'tag' query paramr8  rI	  r  Nr{  r   )r   r  r  r~   rA  z!Error in get_predictions_by_tag: r7  )r   r9  rv   r  r   r  r2  r  r=   ra  rx  r  r  rs   r2   r3   r  )	r  	terms_rawr  rx   rq  r  r  rA  r6   s	            r    get_predictions_by_tagr  n(  s   
 \\h(8(8(CDJJLF  "-335Illy&1G'6]^_adddMVys';I';!wwyIAGGI';I\`LD#%)--flln=	55i@GG..v.QG,,V4G11'C"\
  	! J.  D1!56'c!f=>CCDs+   F#(F#B F( (
G#2&GG#G#z/api/news/analyze-sentimentc                    ^C  [        S5      n [        S5      =(       d    / nU (       d  U(       d  [        SSS.5      S4$ U R                  S/ 5      nU R                  S/ 5      n[        S	 U 5       5      n/ nU H  nUR                  S
5      nU(       a  Xt;   a  M"  UR	                  SUR                  SS5       3UR                  SS5      UR                  SS5      SUUR                  S5      S.UR                  5        VV	s0 s H  u  pUR                  S5      (       d  M  X_M!     sn	nE5        M     X5-   n
X*-    Vs/ s H  nSU;  d  M  UPM     nn/ nSnSn/ SQnU(       Ga-  U GH  nUR                  SS5       SUR                  SS5      =(       d    UR                  SS5       3mCUR                  S5      S:H  n[        TC5      n[        UC4S jU 5       5      nSnU(       a1  UR                  SS5      R                  5       nUS:w  a  US   S :  a  S!nU(       a  S!US'   S"US#'   U(       a   UR                  SS5      R                  5       OSnUUS$'   UR                  S5      US%'   UR                  S5      =(       d    UR                  S5      US&'   S'U 3US('   S)S*/US+'   S!nUS,-  nGMJ  U(       d  U(       a  UUS-'   UR	                  U5        GMq  S!US'   S.US#'   U(       a   UR                  SS5      R                  5       OSUS$'   S/US('   S%U;  a1  UR                  S5      US%'   UR                  S5      =(       d    S0US&'   S!nUS,-  nGM     U(       Ga4  U VVs/ s HT  nUR                  S
5      U
 Vs1 s H,  nUR                  S5      (       d  M  UR                  S
5      iM.     sn;   d  MR  UPMV     nnnU(       a  U
 Vs0 s H,  nUR                  S5      S:X  d  M  UR                  S
5      U_M.     nnU Hs  nUR                  S
5      U;   d  M  UUR                  S
5         nUR                  S5      (       d  MF  UR                  S1 Vs0 s H  oU;   d  M
  UUU   _M     sn5        Mu     [        SU5        [        SU 5        [        U5      [        U
5      -   n[        X*-    Vs/ s H  oR                  S5      (       d  M  UPM     sn5      nUS2S3 nU(       Ga  / n [        U5       H  u  n!nUR                  SS5      =(       d    UR                  SS5      =(       d    Sn"UR                  S-5      n#U#(       a  U#R                  SS45      OS4n$S5U$ S63n%S7U! S8U% SUR                  SS5       S9U"S2S:  3n&U R	                  U&5        M     S;R                  U 5      n'S<S=S>.S?U'S>./n([        U(S@SASB9n)SCU);   a  GO U)R!                  SDS5      R!                  SES5      R#                  5       n*U*R                  SF5      (       d:  SS2Kn+U+R&                  " SGU*U+R(                  5      n,U,(       a  U,R+                  S5      n*[,        R.                  " U*5      n-U- V.s0 s H)  n.U.R                  SH5      c  M  U.R                  SH5      U._M+     n/n.[        U5       H  u  n!nU!U/;   d  M  U/U!   n0U0R                  S%UR                  S5      5      US%'   U0R                  S&UR                  S5      5      US&'   U0R                  SIS5      US#'   U0R                  SJSK5      R                  5       US$'   U0R                  SLS5      US('   U0R                  S+/ 5      US+'   S!US'   S-U;   a  US-	 US,-  nM     X*-    Vs/ s H  oR                  S5      (       d  M  UPM     n2nU2(       Ga,  U2R3                  SM S!SN9  U2 Vs/ s H2  oR                  S$5      SO:X  d  M  UR                  S#5      SP:  d  M0  UPM4     snS2SQ n3U2 Vs/ s H2  oR                  S$5      SR:X  d  M  UR                  S#5      SP:  d  M0  UPM4     snS2SQ n4 [5        5       n5U3U4-    H  nSSU;  d  M  UR                  S+/ 5      n6U6(       d%  UR                  SS5      n7U7R7                  5       S2S3 n6[9        U6[:        5      (       a  SR                  U65      O
[=        U65      n8U5R?                  U85      n9U9USS'   M     U
 Vs/ s H  oR                  S5      S:X  d  M  UPM     n;n[        U2S2ST  Vs/ s H  oR                  S$S5      SR:X  d  M  UPM     sn5      n<[        U2S2ST  Vs/ s H  oR                  S$S5      SO:X  d  M  UPM     sn5      n=[@        RB                  " 5       RE                  5       U<U=:  a  SUOSVU3U4[        U;5      U;(       a  U;S   R                  S&5      OS2SW.SX.n>U>U SY'   U(       a  SZ[G        5       ;   a  [        SU 5        U(       d  [        SU 5        [        U5      [        U
5      -   n?[        X*-    Vs/ s H  oR                  S5      (       d  M  UPM     sn5      n@U?U@-
  nAS[nBU?S:  a  [I        W@U?-  S[-  5      nB[        S\UWAWBU S].5      $ s  sn	nf s  snf s  snf s  snnf s  snf s  snf s  snf s  sn.f ! [0         a  n1 S2n1A1GNHS2n1A1ff = fs  snf s  snf s  snf ! [0         a  n: S2n:A:GNS2n:A:ff = fs  snf s  snf s  snf s  snf ! [0         a1  n1[K        S^U1 35        [        S[=        U15      S.5      S_4s S2n1A1$ S2n1A1ff = f)`zJAnalyse le sentiment, la pertinence et traduit les news avec FinBERT + LLMrK  rV  r   zNo news data foundr8  r>  r_   rL  c              3   r   #    U  H-  oR                  S 5      (       d  M  UR                  S 5      v   M/     g7f)r   Nr  r  s     r    r   )analyze_news_sentiment.<locals>.<genexpr>(  s&     P.?55<e.?s   77r   zTRUTH SOCIAL: r[  zDonald TrumprP  r  r2  )rC  ra  rD  rB  r   r2  ai_rl  Fr   )rv  r  POWELLr  	INFLATIONRATEEARNINGSr  APPLETESLAWARCHINAOILGOLDr  r  rC  r   rD  ra  rB  c              3   H   >#    U  H  oTR                  5       ;   v   M     g 7fr   )r'  )r   rc   text_ens     r    r   r  (  s     !R@Q1w}}"6@Qr  r   rj  rk  g      ?Trm  rn  ro  rt  ru  rp  rs  rv  rw  rx  r  rx  r  z%Automated Filter: Low semantic impactzInfo mineure (Non traduite))rl  rt  ru  rn  ro  rs  Nrg   r>   z[Hint: FinBERT sees r  zID rm   z |    r$  r%  aL  
                Analyze financial news for a French trader.
                JSON LIST ONLY: [{"id":0,"title_fr":"..","summary_fr":"..","relevance_score":8,"sentiment":"bullish","reasoning":"..","search_keywords":["Trump", "Warsh"]}]
                
                SCORING RULES:
                - 0-3 (Noise): Gossip, Local Sports, Celebrities.
                - 4-6 (Sector/Mild): Winter Storms (unless shutting down NYSE/Oil), Earnings of small caps, New Product launches, General Tech.
                - 7-10 (Critical): FED Rate Decisions, POWELL speech, MAJOR Wars (affecting Oil/Chips), TRUMP Executive Orders, CPI/Inflation Data.
                
                IMPORTANT:
                - Downgrade 'Storms/Weather' to max 6 unless it explicitly mentions "Oil Refinery Shutdown" or "Global Supply Chain".
                - Downgrade "Power Outages" to 5.
                - "search_keywords": Extract 2-3 MAIN English keywords (Entities, Events) for searching Prediction Markets (Polymarket). E.g. "Trump Warsh" for nomination, "Fed Rate" for checks. Avoid generic words.
                r&  r(    r  r  Erreurr*  r+  [r  r-  rN  rF  r  rN  c                 &    U R                  SS5      $ )Nrn  r   r  r  s    r    r  (analyze_news_sentiment.<locals>.<lambda>i)  s    /BA)Fr!   r^  rX  r  r}  rR  rw  r4  rg  ri  )r  	latest_fr)r  market_moodtop_threatstop_opportunitiestrump_monitorrq  r\  r*  r   )r   analyzed_countremaining_countprogress_pctr5   zErreur endpoint sentiment: r7  )&r/   r   rv   r  r  r_   r$  ry  r  r=   r1   r9   rs   r  r  r.  r  r  r  r  r|  r  r   r  r2   r	  r2  r  r  r  r  r  r	   r  r  rr  r  r3   )D	news_data
truth_datar_   existing_segments	seen_urlstruth_segmentsr_  r   rc   rd   segmentsr  all_unanalyzedgroq_candidatesnoise_or_truth_processedr  priority_keywordsr  is_truthr~  has_keywordis_significant_sentiment
sent_labelr  r   rx   truth_to_saver   seg_mapr~   doneprocessing_queueitems_inputr	  summary_textbert_resbert_sentimenthintr8  joined_inputr6  raw_responsejson_strr  r  results_listrO  
result_mapr\  r6   	all_validr  top_oppspoly_servicer  title_enr   oddse_polytrump_activitybullish_countbearish_countrq  total_items_countcurrently_analyzedr  r  r  sD                                                                      @r    analyze_news_sentimentr  (  s_   [D#O4	$^4:
w;OPQSVVVgr* &MM/2> P.?PP	 D((5/Cs'!!)$((8^*L)MN HHY388Ir2("hh|4# #'**,F,31!,,u2E313,F#   %5 &+%5S%59IQR9R!%5S #(  h '!XXgr231TXXi5L5hPTPXPXYcegPh4ij HHX..@ 8@ "!R@Q!RR+0(!,)!D!J!J!LJ!Y.;w3G$3N370-1D)*01D,-MXkoogyAGGI^gG.5D*+'+xx'8D$)-))<)T@TD&-PQXPY+ZD(/6.GD*+/3,"a'N $</:D+,#**40 .2D)*01D,-]hkoogy.Q.W.W.YnwD*++RD(!-+/88G+<Z(-1XXi-@-aDa\*/3,"a'NW '\ (,6  !GJq!%%,ai  KFai\]mnmrmr  tD  nE<155QV<ai  KF  ;FJ  !G 7?ex!155?VdCdoaeeElAox7e&q%%,'1&quuU|41ee$455 xx  ;Z  )e  ;ZQ  cd  ^dAaD  ;Z  )e   f	 '
 #>:>  ; E
S]*u/K/!559I3JA/KL
 +2A. K&'78	T#xx	26X$((:r:RXVX88$67EMgy!AS\-n-=Q?C54&$((7B*?)@LQURUDVCWX""3' 9  99[1L " /   L9H& )dPSTL <' +33IrBJJ5RTU[[]H#..s33! "		)Xryy I (-AX#'::h#7L ;G!b,Q!%%PT+.!%%+q.,J!b%./?%@	T*,",S/C/2wwz488GCT/UD,14txxPYGZ1[D.8;@QST8UD!4569ggk96U6[6[6]D!233677;3KD069gg>OQS6TD!2359D!121T9$();$<*a/N &A* !& 0L 01EE:J4KQ 0	LNNFPTNU&/}i559J3Ky3X1]^]b]bcv]w{|]|1i}  A  @A  BK#,z9a6G0HI0UZ[Z_Z_`sZtxyZy9z{}|}~H02'(2D(4#'88,=r#B  ('+xx'<H (0~~'7';H6@46P6P 2VYZbVc+::5A26./ 3( *2WAUU8_5VaNW  IcrN oNqeeDUW`>aen>nN opMIcrN oNqeeDUW`>aen>nN opM !) 8 8 :,9M,Iyy*%- 0HV!2!6!6|!D\`"	F #)Ih  1_i8  OY7  JX6 U-=!Y-=GWAX!-=!YZ+.@@q  25F F#MNL,.(
  	k G T~ KF  !G f
 )e L~ "c$ ! 
 M ~z,   X !p o0 "Z  D+A3/0'c!f=>CCDs  <l  Cl j$j*l 
jjHl 'jjj4j<jl j-jl !(l l 	j!
)
j!
3Al 8j&j&C1l Bj0 'j+j+j0 2Cj0 8l >kk!l  kk3k9
l kk6k<l k B	k &l *k/k/l k47k4=l k9-k93B:l -k>
k>5l l jl +j0 0
k:l  kl 
k,!l 'k,,l 
l>&l93l>9l>z/api/optionsc                  j    [         R                  R                  SS5      R                  5       R	                  5       n U (       d  [        SSS.5      S4$ [        U 5      nU(       d  [        SSS.5      S4$ [        S	US
.5      $ ! [         a#  n[        S[        U5      S.5      S4s SnA$ SnAff = f)uW   Récupère et renvoie l'analyse complète de la chaîne d'options pour un ticker donnérw   r  r   missing_tickerr   r   rI	  no_datar7  r1
  r4  N)	r   r9  rv   r  r'  r   r  r2   r  rw   r  r6   s      r    get_optionsr  )  s    
B!!(B/557==?g8HIJCOO(0g	BCSHH$788 B'CF;<cAABs*   AB !B 7B 
B2B-'B2-B2z/api/refresh/optionsc                      [         R                  " 5       n U R                  SS5      R                  5       R	                  5       nU(       d  [        SSS.5      S4$ [        SU 35        [        U5      nU(       d  [        SSS.5      S	4$ [        S
US.5      $ ! [         aF  n[        SU 35        [        R                  " 5         [        S[        U5      S.5      S	4s SnA$ SnAff = f)uB   Force le rafraîchissement de l'analyse des options pour un tickerrw   r  r   r  r  rI	  z'Rafraichissement options demande pour: analysis_failedr7  r   r4  zErreur refresh options: r8  N)r   r4
  rv   r  r'  r   r3   r  r2   r   r   r  )r5   rw   r  r6   s       r    refresh_optionsr   )  s    D!(B'--/557g8HIJCOO7x@A(0g8IJKSPP)V<== D(,-'c!f=>CCDs*   AB /B B 
C*$;C%C*%C*c                    #    SSS.$ 7f)u1   Logique asynchrone pour récupérer les dérivés
deprecatedz,Use /api/tr/navigate with browser automationr  r   r  s    r    get_derivatives_asyncr#  )  s     !.\]]s   z/api/derivativesc                  ,    [         R                  R                  SS5      R                  5       R	                  5       n U (       d  [        SSS.5      S4$ [        R                  S:X  a)  [        R                  " [        R                  " 5       5        [        R                  " [        U 5      5      nSU;   a  [        SUS   S.5      S4$ [        S	US
.5      $ ! [         a1  n[        SU 35        [        S[        U5      S.5      S4s SnA$ SnAff = f)uC   Récupère les produits dérivés (Turbos, Facteurs) pour un tickerrw   r  r   r  r  rI	  win32r7  r   r4  zErreur endpoint derives: r8  N)r   r9  rv   r  r'  r   sysr'  r   set_event_loop_policyWindowsSelectorEventLoopPolicyr)
  r#  r2   r3   r  r  s      r    get_derivativesr)  )  s    D!!(B/557==?g8HIJCOO <<7"))'*P*P*RS26:;fgwHI3NN)V<== D)!-.'c!f=>CCDs+   AC A4C 
C 
D"&DDDz/api/pricesc            
      (    [         R                  R                  SS5      R                  5       n [	        [         R                  R                  SS5      5      nU (       aU  U R                  S5       Vs/ s H7  o"R                  5       (       d  M  UR                  5       R                  5       PM9     nnGO[        5       n/ nU(       Ga  SU;   af  UR                  S/ 5       Vs/ s HH  oUR                  S5      (       d  M  UR                  SS5      R                  5       R                  5       PMJ     nnOSU;   a  UR                  S/ 5       H  nSU;   d  M  UR                  UR                  S/ 5       Vs/ s HH  oUR                  S5      (       d  M  UR                  SS5      R                  5       R                  5       PMJ     sn5        M     U Vs/ s H  o"(       d  M  UPM     nnU(       d5  [        S	[        R                  " 5       R                  S
5       S35        / SQn[        S	[        R                  " 5       R                  S
5       SU SU S35        [        X1S9n[        S[        R                  " 5       R                  5       U[!        U5      US.5      $ s  snf s  snf s  snf s  snf ! ["         aQ  n[        SU 35        [        S[%        U5      [        R                  " 5       R                  5       S.5      s SnA$ SnAff = f)u3   Récupère les prix en temps réel pour des tickersr  r  r  rg   r  r  rw   r  r  r9
  z8] [PRICES] No tickers found in portfolio, using defaults)r
  r
  r
  r
  r  z] Fetching prices for: rq   days)r  r1
  )r   r:  r  r  r  zError in get_prices: r   r   r   r:  N)r   r9  rv   r  r  r  r'  r  rn  r3   r	   r  r  r  r   r  rs   r2   r  )	tickers_paramr  rx   r  r  r  r   r  r6   s	            r    
get_pricesr.  *  s   /((B7==?7<<##FA./2?2E2Ec2JX2JQggi(qwwy(2JGXG ,-IG )+LUMMZegiLj~Ljqnsnst|n}BquuXr288:@@BLjG~G)+"+--	2">&&0#NNY_YcYcdoqsYt  ,IYtTUx}x}  G  yH,OAEE(B,?,E,E,G,M,M,OYt  ,I  J #?
 &+g1g+Ahlln--j9::rst?G(,,.))*566MgYVXY]X^^def"76!113[
  	7 Y 
 ,I ,"  %aS)*V!113
  	st   A1J6 3J""J"12J6 #J' 2J'2"J6 J6 7J,
2J,
J6 
J1#J1)B8J6 "J6 6
L ALLLz/api/prices/historyc                  
    [         R                  R                  SS5      R                  5       n [         R                  R                  SS5      nU (       d2  [	        SS[
        R                  " 5       R                  5       S.5      S4$ U R                  S	5       Vs/ s H7  o"R                  5       (       d  M  UR                  5       R                  5       PM9     nn[        S
[
        R                  " 5       R                  S5       SU SU S35        0 nU GH3  n [        SU S3SS9  [        R                  " U5      nUR                  US9nUR                  (       Gd  / nUR!                  5        H  u  pUR#                  U	R                  S5      [%        U
S   5      [%        U
S   5      [%        U
S   5      [%        U
S   5      [&        R(                  " U
S   5      (       a  [+        U
S   5      OSS.5        M     SU[-        U5      UR.                  S   R                  S5      UR.                  S   R                  S5      [%        US   R0                  S   5      [%        US   R0                  S   5      [&        R(                  " US   R3                  5       5      (       a  [%        US   R3                  5       5      OS[&        R(                  " US   R5                  5       5      (       a  [%        US   R5                  5       5      OS[%        US   R0                  S   US   R0                  S   -
  5      US   R0                  S   S:w  aD  [%        US   R0                  S   US   R0                  S   -
  US   R0                  S   -  S-  5      OS[&        R(                  " US   R7                  5       5      (       a  [%        US   R7                  5       5      OSUS .XE'   [8        R:                  " XE   S!   5      (       a  SXE   S!'   [        S"[-        U5       S#35        OS$S%S&.XE'   [        S'5        [<        R>                  " S(5        GM6     [	        S+[
        R                  " 5       R                  5       UU[-        URE                  5        Vs/ s H  oR                  S,5      (       d  M  UPM     sn5      S-.5      $ s  snf ! [@         a*  nS$[C        U5      S&.XE'   [        S)U 35         S*nAGM  S*nAff = fs  snf ! [@         aQ  n[        S.U 35        [	        S[C        U5      [
        R                  " 5       R                  5       S.5      s S*nA$ S*nAff = f)/uJ   Récupère l'historique détaillé des prix (derniers jours/semaines/mois)r  r  rg  30dr   z&tickers parameter required for historyr,  rI	  r  r  r9
  z] Fetching history for: z
 (period: r
  z
[HISTORY] r   r   )ra  r  r  r  ru  rt  rd  Volumer   )rN  r   highlowr   r  Tr  rz  r*  )r   rg  data_pointsr  r  price_start	price_end
price_high	price_lowr\  r  
avg_volume
daily_datar  zOK (r+  Fr  r   zERROR: no_datar	  zERROR: Nr1
  r   )r   r:  rg  rY  r  zError in get_prices_history: )#r   r9  rv   r  r   r	   r  r  r  r'  r3   r  rp   rq   rY  r  r  r  r  r  r  r  rs   r  r
  r  r  r  r   r  r  r  r2   r  r@  )r-  rg  rx   r  rY  rw   r5   r  r:  rN  r  r6   r)  s                r    get_prices_historyr;  I*  s   M((B7==?!!(E2!A%\\^557  	  /<.A.A#.FT.F'')$1779??$.FT(,,.))*566NwiWabhaiijklF,%
6(#.C8yy(||6|2zzz!#J%)]]_	"))$(MM*$=$)#f+$6$)#f+$6#(U#4%*3w<%8<>HHS]<S<Sc#h-&8YZ+  &5 $("('*:&*jjm&<&<Z&H$(JJrN$;$;J$G',T']-?-?-B'C%*4=+=+=b+A%BCE88DQWLL\L\L^C_C_eDL,<,<,>&?ehAC$u+//J[A\A\U4;??+<%=be"'W(:(:2(>gASASTUAV(V"W @D  EL  @M  @R  @R  ST  @U  YZ  @ZeT']-?-?-Cd7mFXFXYZF[-[_cdk_l_q_qrs_t,twz,z&{  `cFHhhtT\~ObObOdFeFeeDN,?,?,A&Bkn&0'GO zz'/,"?@@8;5DZ 18927)&LGO*+

3U ^ !113W^^%5J%5y9I!%5JK
  	i U`  %.3c!f"Esm$$% K -aS12V!113
  	s|   BT 	T S 8"S AT L.S
AT S<-S<3T  T 
S9S4-T 4S99T 
UAUUUz/api/senator-trades/searchc                      [         R                  R                  SS5      R                  5       n U (       a  [	        U 5      S:  a  [        SS/ S.5      $ [        5       nUR                  U 5      n[        SU [	        U5      U[        R                  " 5       R                  5       S.5      $ ! [         aS  n[        S	U 35        [        S[        U5      [        R                  " 5       R                  5       S
.5      S4s SnA$ SnAff = f)z/Cherche les issuers par nom (pour autocomplete)r0  r  r  r   z#Query must be at least 2 characters)r   r   r  r1
  )r   r   r  r  r:  z Error in search_senator_trades: r,  r7  N)r   r9  rv   r  rs   r   r
  r'  r	   r  r  r2   r3   r  )r   r  r  r6   s       r    search_senator_tradesr=  *  s      b)//1E
Q!>   '(//6\!113
  	  045V!113
  	 	s&   AB+ AB+ +
D5AD=DDz/api/senator-tradesc                  (    [         R                  R                  SS5      R                  5       n [         R                  R                  SS5      R                  5       nU (       d9  U(       d2  [	        SS[
        R                  " 5       R                  5       S.5      S4$ [        5       nUR                  5       nXR                  S0 5      ;   al  [        S	[
        R                  " 5       R                  S
5       SU  S35        [	        S[
        R                  " 5       R                  5       U US   U    SS.5      $ U(       a  [        S	[
        R                  " 5       R                  S
5       SU 35        UR                  X5      nU(       d1  [	        SS[
        R                  " 5       R                  5       S.S5      $ [	        S[
        R                  " 5       R                  5       U UUS.5      $ [        S	[
        R                  " 5       R                  S
5       SU  S35        UR                  U 5      nU(       d6  [	        SU  SU  3[
        R                  " 5       R                  5       S.S5      $ [        S	[
        R                  " 5       R                  S
5       SU S35        UR                  XP5      nU(       d1  [	        SS[
        R                  " 5       R                  5       S.S5      $ [	        S[
        R                  " 5       R                  5       U UUS.5      $ ! [         ah  n[        SU 35        [        R                   " 5         [	        S[#        U5      [
        R                  " 5       R                  5       S.5      S4s SnA$ SnAff = f)u>   Récupère les trades des sénateurs pour un nom/ticker donnérw   r  r  r   z&ticker or issuer_id parameter requiredr,  rI	  r
  r  r9
  z] Capitol Trades z found in cacher1
  T)r   r:  r#  r5   
from_cachez%] Scraping Capitol Trades for issuer zFailed to scrape Capitol Tradesr7  )r   r:  r#  r  r5   z] Looking up z in all_issuers...z< not found. Try searching with /api/senator-trades/search?q=r>  z] Found issuer_id z, scraping Capitol Trades...zError in get_senator_trades: N)r   r9  rv   r  r   r	   r  r  r
  r
  r3   r  rH  r:  r2   r   r   r  )r#  r  r  r
  r5   found_issuer_idr6   s          r    get_senator_tradesrA  *  s6   Rll&&x4::<LL$$["5;;=	9!A%\\^557  	  '( ((*
..B77Ahlln--j9::KK=Xghi%\\^557*"9-k:"   Ahlln--j9::_`i_jkl((@D%>!)!9!9!;  	  %\\^557*&   	(,,.))*56mK=Pbcd!::;G!'=(depdqr%\\^557 	  	(,,.))*566HHYYuvw$$_B!:%\\^557 	  !113&(
  	  -aS12V!113
  	 	sG   BL BL 9BL <1L .BL 0A<L -1L 
N)ANNNz/api/senator-trades/summaryc                      [        5       n U R                  5       n[        UR                  S0 5      5      UR                  S5      0 S.nUR                  S0 5      R	                  5        GH8  u  p4U(       d  M  SU;   d  M  US   nU Vs/ s H  ofR                  S5      S:X  d  M  UPM     nnU Vs/ s H  ofR                  S5      S:X  d  M  UPM     nnU Vs/ s H  ofR                  S5      S	:X  d  M  UPM     n	nU Vs/ s H  ofR                  S5      S
:X  d  M  UPM     n
nUR                  S0 5      R                  S5      [        U5      [        U5      [        U5      [        U	5      [        U
5      U(       a  US   S   OSUR                  S0 5      S.US   U'   GM;     [        S[        R                  " 5       R                  5       US.5      $ s  snf s  snf s  snf s  snf ! [         aS  n[        SU 35        [        S[        U5      [        R                  " 5       R                  5       S.5      S4s SnA$ SnAff = f)u.   Retourne un résumé des trades des sénateursr
  rU  )total_issuersrU  r
  r  r]  r^  r\  r
  r  r  r%  rA   r   rc  Nr>  )rA   ru  democrat_tradesrepublican_trades
buy_tradessell_tradesr  r>  r1
  )r   r:  rD  z%Error in get_senator_trades_summary: r   r,  r7  )r
  r
  rs   rv   r_   r   r	   r  r  r2   r3   r  )r  r
  rD  rw   rG  r  rx   rD  rE  rF  rG  r6   s               r    get_senator_trades_summaryrH  +  s   *&(((*
 !	2!>?&NN>:
 $.>>)R#@#F#F#HF{x;6$X..4"Ufg*8T1f"U06$Y1%%.L:XQ!$Y)/JA55=E3Ia
J*0L&QEE&MV4Kq&L (OOHb9==fE$'K'*?';),->)?"%j/#&{#39?&)H"5T"-//,"C	.	"6* $I& !113
  	! #V$YJL&  5aS9:V!113
  	 	sz   A3G+ 9G+ 	G+ 
G&G,G+ 2GGG+ G!6G!<G+ G&G&$B2G+ G+ +
I5AI=IIz/api/bank-forecasts/scrapec                      [        S[        R                  " 5       R                  S5       S35        [	        5       n U R                  5       n[        S[        R                  " 5       R                  5       [        U5      US.5      $ ! [         aS  n[        SU 35        [        S[        U5      [        R                  " 5       R                  5       S.5      S	4s S
nA$ S
nAff = f)u+   Lance le scraping des prévisions bancairesr  r9
  z,] Demarrage scraping previsions bancaires...r   )r   r:  sources_foundr5   zErreur scraping: r   r,  r7  N)r3   r	   r  r  r  r  r   r  rs   r2   r  )r  r  r6   s      r    scrape_bank_forecastsrK  A+  s    (,,.))*566bcd%'$$& !113 \	
  	  !!%&V!113
  	 	s   BB 
C$ACC$C$z/api/bank-forecasts/analyzec                  H    [        S5      n U (       d  [        SS05      S4$ [        5       nXl        UR	                  5       n[        SU5        [        S[        U5      US.5      $ ! [         a0  n[        SU 35        [        S[        U5      05      S	4s S
nA$ S
nAff = f)u6   Lance l'analyse IA des articles bancaires récupérésrs  r   z$No raw data found. Run scrape first.r>  r  r   )r   r  r[  zErreur analyse: r7  N)
r/   r   r  r  r`  r9   rs   r2   r3   r  )r>  r  r[  r6   s       r    analyze_bank_articlesrM  [+  s    /"#45G%KLMsRR%'" ++- 	2] 
  	
  / $%Q()3../s#    A' AA' '
B!1%BB!B!z/api/bank-forecastsc            	         [        5       n SnSn [        R                  5          [        R                  R                  SS9R                  5       nU(       ac  UR                  (       aR  UR                  R                  5       n[        R                  " 5       UR                  -
  R                  5       S-  nUS:  nSSS5        SnU(       a3  [        (       d(  S n[        R                  " USS	9R!                  5         Sn[#        [        R$                  " 5       R                  5       UU=(       d    [        U ['        U 5      S
.5      $ ! , (       d  f       N= f! [         a     Nf = f)u   
Retourne les prévisions bancaires depuis la DB.
Si les données ont plus de 6h, lance un re-scrape en arrière-plan
et retourne refreshing=true pour que le frontend re-fetche.
NTrs  r    r  Fc                  $  ^ Sq  [        R                  5          [        S5        [	        S [
        R                  R                  [
        R                  5      R                  5        5       5      m[        5       n U R                  5       =(       d    / n[        U4S jU 5       5      nU(       a  [        SU S35        O[        S5        S S S 5        S	q g ! , (       d  f       N= f! [         a  n[        SU 35         S nAN1S nAff = f! S	q f = f)
NTzK[BANK] [REFRESH] Perspectives bancaires > 6h - re-scrape en arriere-plan...c              3   `   #    U  H$  nUR                   (       d  M  UR                   v   M&     g 7fr   r   rb	  s     r    r   9get_bank_forecasts.<locals>._bg_scrape.<locals>.<genexpr>+  s'      (W ,/>> 'Wrd	  c              3   l   >#    U  H)  oR                  S 5      (       d  M  US    T;  d  M%  Sv   M+     g7f)r   r  Nr  )r   rO  rf	  s     r    r   rR  +  s)     #gu!eA5YfIfAAus   44	4z[BANK] [NEW] z+ nouveaux articles detectes et sauvegardes.z.[BANK] [OK] Aucun nouvel article. Base a jour.z![BANK] [ERROR] Erreur re-scrape: F)_bank_scrape_in_progressr)   r.   r3   r  rW  r   re	  r\  r   r  r  r  r2   )r  fresh	new_countr6   rf	  s       @r    
_bg_scrape&get_bank_forecasts.<locals>._bg_scrape+  s    '+$1__&gh$' ($**889P9PQUUW( %M
 23G#..06BE ##gu#g gI i[8cdeNO '" ,1(# '&  ?9!=>>? ,1(sM   C& B1C
C& 
C#C& "D #C& &
D0D>D DD Dr  )r:  last_scraped_at
refreshingr  r  )r  r)   r.   r   r   r  r  r   r  r	   r   total_secondsr2   rT  r  r  r  r   r  rs   )r  rY  is_stalecache_entry	age_hoursrZ  rW  s          r    get_bank_forecastsr_  y+  s)    %&G OH__$**449J4KQQSK{55"-"8"8"B"B"D%__.1G1GGVVX[__	$q=  J00	1, 	
48>>@
\\^--/* <$<W  I   s/   E BE:E 
EE E 
E$#E$z/api/bank-analysesc                  J    [        S5      n U c  [        / 5      $ [        U 5      $ )u*   Récupère les analyses bancaires en cacher  r/   r   r5   s    r    get_bank_analysesrc  +  s'     ?+D|r{4=r!   z/api/earningsc                  p    [        S5      n U (       aT  SU ;   aN  [        R                  " U S   5      n[        R                  " 5       U-
  R	                  5       S:  a  [        U 5      $ [        [        5       5      $ ! [         a0  n[        SU 35        [        S[        U5      05      S4s SnA$ SnAff = f)u3   Récupère les earnings (cache ou refresh si vieux)r  r   i  zErreur endpoint earnings: r   r7  N)
r/   r	   r,  r  r[  r   r	  r2   r3   r  )r   rw  r6   s      r    get_earningsre  +  s    / 01\U*"00|1DEK,;;=	Iu~% )+,, /*1#./Q()3../s$   A%A; (A; ;
B5%B0*B50B5z/api/refresh/earningsc                       [        [        5       5      $ ! [         a"  n [        S[        U 5      05      S4s Sn A $ Sn A ff = f)u'   Force le rafraîchissement des earningsr   r7  N)r   r	  r2   r  r:   s    r    refresh_earningsrg  +  s?    /)+,, /Q()3../    
A<AAz/api/refresh/forexc                       [        [        5       5      $ ! [         a"  n [        S[        U 5      05      S4s Sn A $ Sn A ff = f)u.   Force le rafraîchissement du calendrier Forexr   r7  N)r   r  r2   r  r:   s    r    refresh_forexrj  +  s?    //122 /Q()3../rh  z/api/portfolio-eventsc            
      Z  ^^  [         R                  " SS9=(       d    0 n U R                  S5      =(       d    /  Vs/ s H)  o(       d  M  UR                  5       R	                  5       PM+     nnU(       d  [        S/ 05      $ [        R                  " S5      n/ nU Hn  nUR                  U5      (       aD  [        U5      nU(       a!  UR                  UR	                  5       5        ML  [        SU S35        M]  UR                  U5        Mp     [        [        R                  U5      5      nU(       d  [        S/ 05      $ / n[        R                   " 5       R#                  5       mT[%        SS	9-   m[        S
['        U5       SU 35        UU4S jn[)        SS9 n	U Vs0 s H  oR+                  X5      U_M     n
nU
 HA  n UR-                  SS9nUR/                  U5        [        SX    S['        U5       S35        MC     SSS5        UR3                  S S9  [        SU05      $ s  snf s  snf ! [0         a  n[        SX    SU 35         SnAM  SnAff = f! , (       d  f       N`= f! [0         a0  n[        SU 35        [        S[5        U5      05      S4s SnA$ SnAff = f)zMFetch upcoming earnings & dividends for a list of tickers from the portfolio.Tr  r  r
  r	  z*[portfolio-events] Could not resolve ISIN z
, skippingr  r  z[portfolio-events] Processing z
 tickers: c                   > / n [         R                  " U 5      nU n0 n UR                  =(       d    0 nUR                  S5      =(       d    UR                  S5      =(       d    U nSn UR                  SS9nUb  UR                  (       d  UR                   H  n [        US5      (       a  UR                  5       O0[        R                  " [        U5      S S S5      R                  5       nT#Us=::  a  T"::  a-  O  Mg  UR                  XUR                  5       S	S
S S.5        Sn  OM     U(       Gd   UR                  n	U	Gb  [!        U	["        5      (       a  U	O0 n
[        U	S5      (       aJ  [!        U	["        5      (       d5   U	R                  (       d!  U	R$                  S S 2S4   R'                  5       O0 n
U
R                  S5      =(       d)    U
R                  S5      =(       d    U
R                  S5      nU(       a  [!        U[(        5      (       a  UOU/nU H  n [        U5      S S n[        R                  " US5      R                  5       nT#Us=::  a  T"::  ad  O  MH  U
R                  S5      =(       d    U
R                  S5      nUR                  XUS	S
U(       a  [+        [-        U5      S5      OS S.5        Sn  OM     U(       d  SU ;   a  U R/                  S5      S   n [         R                  " U5      nUR                  SS9nUb  UR                  (       d  UR                   H  n [        US5      (       a  UR                  5       O0[        R                  " [        U5      S S S5      R                  5       nT#Us=::  a  T"::  a+  O  Mg  UR                  XUR                  5       S	S
S S.5          OM     Sn UR                  S5      =(       d    UR                  S5      nU(       a  [!        U[0        [,        45      (       a%  [        R2                  " U5      R                  5       nO1[        R                  " [        U5      S S S5      R                  5       nT#Us=::  a  T"::  ao  O  OlUR                  S5      =(       d    UR                  S5      nUR                  XUR                  5       SSU(       a  [+        [-        U5      S5      OS S.5        SnU(       Gd   UR4                  nUGb  [7        U5      S:  Gat  UR9                  5       nUR;                  S5      n/ nUR                   He  n UR                  [        US5      (       a  UR                  5       O0[        R                  " [        U5      S S S5      R                  5       5        Mg     [7        U5      S:  a  [=        [7        U5      S-
  5       Vs/ s H  nUUS-      UU   -
  R>                  PM     nn[1        [A        U5      [7        U5      -  5      nUS    [C        US!9-   nT#Us=::  a  T"::  aT  O  U$ [-        UR$                  S    5      n UR                  XUR                  5       SS"U (       a  [+        U S5      OS S.5        U$  U$ ! [         a     GN+f = f! [         a     GM  f = f! [         a     GNf = f! [         a    0 n
 GNf = f! [         a     GM  f = f! [         a     GN!f = f! [         a     GM  f = f! [         a     GNKf = f! [         a     GN<f = f! [         a     GM  f = fs  snf ! [         a     U$ f = f! [         a  n![E        S#U  S$U! 35         S n!A!U$ S n!A!ff = f)%N	shortNamelongNameFrA  )rC  rN  r   r  r  u   Résultats trimestriels)rw   rA   rN  r
  r   r  Tr  r   r  r  r  r  r  r  r|  r  r  r  r  dividend	Dividender}  )rw   rA   rN  r
  r   r  r  r  r  r  u   Dividende (estimé)[portfolio-events] rm   )#rp   rq   rr   rv   r2   get_earnings_datesr  r  r^   rN  r	   r  r  r  r  r  r  r  r
  r  r  r  r  r  r  r  	dividendsrs   
sort_indexr  r  r  r  r
   r3   )$rw   r  r  rA   rr   earnings_addededsr	  r  r"  r  r#  ed_valsr  ed_stred_dater  baseobj2eds2dividend_addedr  ddr  divsdivs_sortedlast_fewr  r  r  r  	next_datelast_amtr6   horizonr^  s$                                     r    fetch_events_for.get_portfolio_events.<locals>.fetch_events_for+  s   FN;ii' 88>rD88K0RDHHZ4HRFD
 "'00r0:Csyy#&99C%29#v2F2FCHHJHL]L]^abe^fgjhj^kmwLxL}L}L#(A#8#8$*MM2801z1J8<	3& %' 6:N$) $9 $-$ &!ll?+5c4+@+@CbE&sI66z#t?T?T!/LOIICHHQTN,B,B,D[]E #())O"< #@		.@Y #@%*YY%? !0:2t0D0D"2$.5F%-14VSb1A2:2C2CFJ2W2\2\2^+0G+Fw+F6;ii6O6kSXS\S\]jSkG,2MM:@8>
9R\ceGnVW@Xim	;. -/ >BN,1 ,G	 /6( &#-!<<,Q/D!yy#66R6@+DJJ'+zz!)6=c66J6J
PXPaPabefibjknlnboq{P|  QB  QB  QDA','<W'<(.6<45KKM:5N<@	7* )+ ). (= (2$ "'#xx7U488DT;UH%he==!)!7!7!A!F!F!HB!)!2!23x="3Ez!R!W!W!YB B1'1&*hh~&>&_$((K^B_G"MM*0(2[OV5w3K\`+ 
 .2N
 &"}}+D	Q*.//*;K'2'7'7':H$&E%-^^!)$)LLWQ=O=OU]UfUfgjklgmnqoqgrt~U  VE  VE  VG  %H &4
  #5zQSXY\]bYcdeYeSf,gSfaeAaCj58.C-I-ISf	,g/23y>C	N3R/S,1"I	|8T,T	#(I#@#@ M 05X]]25F/GH$*MM28090C0C0Ez1FQY51;M_c	3& %' M; &: MM ! ( $- % $%   (1 !/,.E!/( ,5 %-(,%-$ , (1 !)$(!)$ ( !  (1 !)$(!) -h %  M  ;+F82aS9::M;s  ] AZ '] *2Z( A!Z>Z(  'Z'Z( (] )Z( -] 6A[ 4Z9 :A'[ "A[$[ &A[[ ] [ 
!] ,A\ 5A![/\ %[/=\ >] ?\ ] B0\ 6] 7A,\ #] ,A\: ?A!\# ,\: "\5.A \: 0A\: 
Z] Z] 
Z% Z( $Z%%Z( (
Z62] 5Z66] 9[	[ [		[ 
[[ [[ 
[,(] +[,,] /
[>9\ =[>>\ 
\] \] 
\ ] \  ] #
\2-\: 1\22\: :
]] ]] 
]1],,]1r  r  r4  r  rq  rm   z	 event(s)z$[portfolio-events] future error for Nc                     U S   $ r	  r   r  s    r    r  &get_portfolio_events.<locals>.<lambda>,  s    !F)r!   r  z[portfolio-events] error: r   r7  )r   r4
  rv   r  r'  r   r  r	  r  r   r  r3   r  r  ro  r	   r  rN  r
   rs   r   r  r  rn  r2   r	  r  )r  rx   raw_ids_isin_rer  r  r/  r
  r  r  r  r  r\  r6   r  r^  s                 @@r    get_portfolio_eventsr  +  sg   ~/d+1r/3xx	/B/Hb/HO/HQ$1779??$/HOHb>** ::78D~~d##*40NN399;/FtfJWXt$  t}}W-.Hb>**##%),,.s7|nJwiPQQ	f  A.(HOP1'7;Q>GP!Y ---3CMM#&//@3s8*IVW	 " / 	+,&)**q P\ Q ! Y@@QQSTUSVWXXY /.  /*1#./Q()3../s   9I0 
H*"H*-I0 B=I0 AI0 I!H/<I=H4I$I0 *I0 /I4
I>IIII
I-)I0 0
J*:%J%J*%J*rB  r  r  )15mz1 jourr  )1hz5 joursr  )r  z	1 semaineN)r  z1 moisr`  )r  r  1wr`  c                 ~   U (       d  g  [        U 5      nUR                  c  UR                  [        R                  S9nUR                  [        R                  5      $ ! [         a     Of = fS HJ  n [        R                  " U S S U5      R                  [        R                  S9s  $ ! [         a     MH  f = f   g )Nrv	  )%Y-%m-%d %H:%Mz%Y-%m-%dT%H:%M:%Sr     )	_rfc2822_parserw	  r  r   utc
astimezoner2   r	   r  )r  r  fmts      r    _nc_parse_dater  ,  s    DH%992::X\\:#Bb}}X\\**dB	$$Xcr]C8@@@UU$ C s$   AA 
A+*A+44B++
B98B9c                     [         R                  " U [        R                  " 5       SSS0S9nUR	                  5         [
        R                  " UR                  5      n/ nUR                  S [        S-    H[  n[        USS5      n[        USS5      =(       d    [        US	S5      n[        US
S5      nU(       d  MG  UR                  XXxS.5        M]     U$ ! [         a  n	[        SU SU	 35        / s S n	A	$ S n	A	ff = f)NrA  r   z#Mozilla/5.0 (compatible; NCBot/1.0))r  r   r   r}  rC  r  r  updatedr  rB  rC  rN  r   z[news-correlator][z] )r   rv   r  rH  r  r|  r~  r   r  _NC_MAX_NEWSr  r  r2   r3   )
r   rB  rO  r  r  r6   rC  pubr  exs
             r    _nc_rss_fetchr  ,  s    LLW]]_b".0U!VX	'/|a/0AAw+EA{B/L71i3LCAvr*Du

fcWX 1 
 "6("RD12	s$   B7C =C 
C>!C93C>9C>c                     [         R                  " SSU 5      nUR                  5       U R                  5       :w  a3  UR                  5       UR                  5       :w  a  [        U5      S:  a  UOUnX#4$ )a  Return (search_ticker, search_company) cleaned for news queries.
Strips exchange suffixes (.F, .KS, .PA, .L, .TO, .AX, .SW, .HK, .SI, .KQ, .T)
so Google News can actually find results.
If company differs from ticker, prefer company name as the main search term.
z\.[A-Z]{1,2}$r  r}  )r  r  r=   rs   )rw   rK  rz  	search_cos       r    _nc_search_termsr  ,  sb     66"B/D#MMOv||~= '4::< ? #Gq 0 7;  ?r!   c                     UR                  S5      oCR                  S5      n[        X5      u  pgUR                  SS5       SU SU 3n[        SU S3S5      $ )	Nr  r   ++after:+before:%https://news.google.com/rss/search?q=&hl=en-US&gl=US&ceid=US:enzGoogle Newsr  r  r  r  	rw   rK  d_fromd_tod1d2rz  r  r0  s	            r    _nc_google_datedr  ,  sh    		$B==+Db&v7ODc3'(t8B4	@A
/s2LM r!   c                     UR                  S5      oCR                  S5      n[        X5      u  pgSUR                  SS5       SU SU 3n[        SU S3S	5      $ )
Nr  zsite:reuters.com+r   r  r  r  r  r  Reutersr  r  s	            r    _nc_reuters_datedr  ,  sj    		$B==+Db&v7ODY..sC89HRD	QA
/s2LM r!   c                     UR                  S5      oCR                  S5      n[        X5      u  pgSUR                  SS5       SU SU 3n[        SU S3S	5      $ )
Nr  zsite:marketwatch.com+r   r  r  r  r  r  MarketWatchr  r  s	            r    _nc_marketwatch_datedr  ,  sl    		$B==+Db&v7OD !2!23!< =WRDQSPT	UA
/s2LM r!   c                 X    [        X 5      u  p[        SUR                  5        S3S5      $ )Nz)https://seekingalpha.com/api/sa/combined/z.xmlzSeeking Alpha)r  r  r'  )rw   rz  r   s      r    _nc_seeking_alphar  ,  s0    v.GD
3DJJL>F r!   c                 (    [         R                  " U 5      R                  =(       d    / n/ nUS [        S-    GH-  nUR	                  S0 5      =(       d    0 nUR	                  S5      =(       d    UR	                  SS5      nUR	                  S5      =(       d    UR	                  SS5      n[        U[        [        45      (       a2  [        R                  " U[        R                  S9R                  S5      nUR	                  S	0 5      n[        U[        5      (       a  UR	                  S
S5      O
U=(       d    SnU(       d  GM  UR                  SU[        U5      US.5        GM0     U$ ! [          a  n	[#        SU	 35        / s S n	A	$ S n	A	ff = f)Nr  rP  rC  r  pubDateproviderPublishTimerN
  r  clickThroughUrlr   zYahoo Financer  z[news-correlator][Yahoo] )rp   rq   r  r  rv   r  r  r  r	   r  r   r  r  r  r  r  r2   r3   )
rw   r_   r  r  rP  rC  r  cur   r6   s
             r    _nc_yahoo_newsr  ,  sD   		&!&&,"+<!+,Dhhy"-3Gkk'*Cdhhw.CEkk),S9NPR0SC#U|,,,,SX\\BKKL\]++/4B'1"d';';"&&#"(Cu

o$'HS: ; - 
 )!-.	s$   E E- %E- -
F7FFFc           
        ^
^ / [         R                  " 5       smm
U
U4S jnU  VVs/ s H  u  p#[         R                  " XU4SS9PM     nnnU H  oUR                  5         M     U H  oUR	                  SS9  M     [        5       / pvT HP  nUS   R                  5       R                  5       S S n	X;  d  M.  UR                  U	5        UR                  U5        MR     U$ s  snnf )Nc                 j   > U " U6 nT   TR                  U5        S S S 5        g ! , (       d  f       g = fr   )rn  )fnr9  r_   r  r  s      r    r)
  _nc_parallel.<locals>.run-  s!    D	7>>%(TTTs   $
2T)r  r9  r  r  r  rC  r  )
r  r   r  r  r  r  r=   r  r   r  )fns_and_argsr)
  r  r9  r	  rx   seenr'  r  r   r  r  s             @@r    _nc_parallelr  -  s    	(MGT)  ,-+82 sdDI+  -ggiWffRf(W5"&7m!!#))+CR0?HHSM6==.  M-s   #Cc                   ^
 [        5       nU(       an   U" U SS 5      n[        U[        5      (       a  US   OUnUS   R                  5       n[	        US   5      nSSS.R                  US	5      nU[        US
5      US.$ U R                  5       m
/ SQn/ SQn[        U
4S jU 5       5      [        U
4S jU 5       5      -
  n	U	S:  a  SSSS.$ U	S:  a  SSSS.$ SSS	S.$ ! [         a     Nmf = f)z?Use existing FinBERT pipeline; returns {label, score, display}.Nr
  r   r   rk  HaussierBaissier)rQ  rW  Neutrer}  )r   rk  display)surgesoarbeatr	  r@  rL  riseboostupgradeprofitrz  r  
outperformacquisitionapproveddealraises)dropfallplungemisscut	downgraderM  declinerI  investigationfinelayofflawsuitwarnfraudmissedslumpc              3   6   >#    U  H  oT;   d  M
  S v   M     g7frS  r   r   r  rx   s     r    r    _nc_sentiment.<locals>.<genexpr>/-  s     )w!q&AAwrW  c              3   6   >#    U  H  oT;   d  M
  S v   M     g7frS  r   r  s     r    r   r  /-  s     /M7a1f7rW  rQ  g333333?rW  rj  r	  )	r
  r  r  r=   r  rv   r  r2   r  )rC  piper\  r  lblscrr  bull_kwbear_kwr   rx   s             @r    _nc_sentimentr  -  s   >D	ds$C'T223q6D=&&(Cg'C#-:FJJ3PXYG 5a=WMM 	AYGZG)w))C/M7/M,MMA1uzCJOO1uzCJOOBB $s   A,C" "
C/.C/c           
         U[         :  a  / S4$ U[        SS9-
  nU[        SS9-   n[        [        XXE44[        XXE44[
        XXE44[        U 44[        U 44/5      n/ nU H  n[        UR                  SS5      5      n	U	c.  UR                  0 UESSUR                  SS5      SS S	.E5        MO  [        X-
  R                  5       5      [        R                  5       ::  d  M  UR                  0 UES
U	R                  5       U	R                  S5      S	.E5        M     U(       d-  U V
s/ s H   n
0 U
ESSU
R                  SS5      SS S	.EPM"     nn
US[          S
4$ s  sn
f )z.Fetch + filter articles for a historical move.Fr}  r  r  rN  r  Nr   )date_okdate_parseddate_displayTr  )_NC_GOOGLE_MAXr
   r  r  r  r  r  r  r  rv   r  r  r[  _NC_DATE_TOLr  r  r  )rw   rK  move_dtage_daysr  r  r	  filteredartr  r  s              r    _nc_fetch_for_mover  4-  s   . 5yya((Fya((D
	& ?@	& ?@	& ?@		*		* C HSWWVR01;OO Hs Hu-1.1ggfb.A#2.FH I #-..01\5O5O5QQOO Hs Ht-0]]_.1ll:.FH I  FIKFI=q =U4%&UU62%6s%;=FI 	 KM\"D((Ks   ('Ez/api/news-correlatorc                  $    [         R                  R                  S5      =(       d    SR                  5       R	                  5       n [         R                  R                  S5      =(       d    SR                  5       R                  5       n[        [         R                  R                  S5      =(       d    S5      nU (       d  [        SS05      S	4$ U[        ;  a"  [        SS
U S[        [        5       305      S	4$ [        U   u  p4n U(       a  [        R                  " XUSSS9nOF[        R                  " [        R                  S9nU[!        SS9-
  n[        R                  " XXsSSS9n Ub  UR$                  (       a  [        SS05      S4$ US   R'                  5       n
[        U
R(                  S   5      n[        U
R(                  S   5      nU(       a
  X-
  U-  S-  OSn [        R*                  " U 5      R,                  nUR                  S5      =(       d    UR                  S5      =(       d    U n/ n[/        S[1        U
5      5       H  n[        U
R(                  US-
     5      n[        U
R(                  U   5      nUS:X  a  M>  UU-
  U-  S-  n[3        U5      U:  d  MZ  U
R4                  U   n[7        US 5      (       a  UR9                  5       n[7        US!5      (       a*  UR:                  c  UR=                  [        R                  S"9nUR?                  UUUUS#.5        M     [        R                  " [        R                  S9n[1        U5      SSSSS$.n/ nU GH2  nUS%   nUU-
  R@                  nUS&;  a  URC                  S'5      OURC                  S(5      nU[E        US)   S*5      [E        US+   S,5      [E        US-   S,5      UU[F        :  / SSSSSS..nU[F        :  a   US/==   S-  ss'   UR?                  U5        M  [I        XUU5      u  nnU(       d   US0==   S-  ss'   UR?                  U5        M  / nU Hj  n [K        U S1   5      n!UR?                  U S1   U S2   U R                  S3S5      U R                  S4S5      U!S5   U!S6   U!S7   U R                  S8S5      S9.5        Ml     U V"s/ s H  n"U"S8   (       d  M  U"PM     n#n"U#(       a  U#OUn$[M        S: U$ 5       5      n%[M        S; U$ 5       5      n&[1        U$5      U%-
  U&-
  n'US)   S:  n(U(=(       a    U%U&:  =(       d    U((       + =(       a    U&U%:  n)URO                  UU%U&U'U)[1        U#5      S<.5        U)(       a  US===   S-  ss'   OUS>==   S-  ss'   UR?                  U5        GM5     US=   US>   -   US0   -   n*U*S:  a  [E        US=   U*-  S-  5      OSUS?'   [        U UUUU[E        US,5      [E        US,5      [E        US*5      [1        U
5      UUS@.5      $ ! ["         a  n	[        SSU	 305      S4s Sn	A	$ Sn	A	ff = f! ["         a    U n GN
f = fs  sn"f ! ["         a7  n	[P        RR                  " 5         [        S[U        U	5      05      S4s Sn	A	$ Sn	A	ff = f)Au   
Analyse les mouvements de prix significatifs et corrèle avec les actualités.
Params:
  ticker    (str)   - ex: NVDA, 000660.KS
  period    (str)   - 1d | 5d | 1w | 1mo
  threshold (float) - seuil de move en % (défaut: 1.0)
rw   r  rg  r`  rG  r
  r   zticker manquantrI	  zperiode invalide: z. Valeurs: FT)rg  rb  rc  r	  r  r  r  )r  ra  rb  rc  r	  z
yfinance: r7  Nu#   Pas de données de prix disponiblesr>  rd  r   r  r*  rz  rm  rn  r  r	
  rw	  rv	  )r:  
price_fromprice_tor  )r~   
correlated	divergentno_newstoo_oldr:  )r  r:
  r  r  r  r  r  r~  r  )r:  r  r  r  r  r  articlesr?  rH  rj  is_correlateddate_confirmedr  r  rC  rB  r  r   r   r  rk  r  )rC  rB  rN  r   rF  sentiment_displayrG  r  c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)rF  rQ  r  Nr   r   r  s     r    r   "news_correlator.<locals>.<genexpr>-       L8a~/K8rU  c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)rF  rW  r  Nr   r  s     r    r   r  -  r  rU  )r   r?  rH  rj  r  r  r  r  r  )rw   rK  rg  period_labelrG  r5  r6  	total_pctcandlesmovesrm  )+r   r9  rv   r  r'  r=   r  r   _NC_PERIOD_MAPr  rp   r  r	   r  r   r  r
   r2   r  squeezer
  rq   rr   r  rs   r  r  r^   r	
  rw	  r  r  r  r  r  r  r  r  r  r1   r   r   r  )+rw   rg  rG  rb  label_h	yf_periodr  ra  r  r6   rk  p_startp_endr
  rr   rK  	raw_movesr  r[  r  r]  r  now_utcrm  	moves_outmover  ts_str
move_entryarticles_rawr   articles_outr  sentr  	confirmedeval_setr?  rH  neutis_upis_corranalyzeds+                                              r    news_correlatorr"  S-  sV   Q/\\%%h/52<<>DDF\\%%h/85??AGGI',,**;7>3?	G%678#=='G'9&TR`MaLb%cdegjjj'5f'=$9	=[[H*/TC !5iQ//[[#*/TC
 :G%JKLcQQG$$&A'B(9@U_/#5c		ii',,Dhh{+Mtxx
/CMvG
 	q#f+&AQU+,DU6;;q>5Jdqy($;$&,C3x9$\\!_2//b6F6F6H2x((RYY->8<<8B  r.2#"G H ' ,,(,,/i.!-	DK(B"**H9A9V$45[[4  %#D$6:#D$6:#D$4:&&7 1!&"#J .(i A%   ,0"hOOL!i A%   ,L#$S\2##"%g,"%h-"%''.""="%''%"4"&w-)-i)-g"%'')U";	% 	 $ %1ALqAiLLIA%.	LHL8LLDL8LLDMD(4/D&*E,Le)2KtG#/#'#'#'#*#&y>  l+q0+k*q0*Z(A D &{);;eI>NNGORS|eL1H<sBCYZf!"!#$ !, !, A.v;$ 
  	U  	=Gz!%567<<	=  	G	H BJ  /Q()3../s   CY +Y =Y 
X (Y )AX .#Y AY )AX6 ;A-Y ,HY <Y	Y	D8Y 
X3X.(X3)Y .X33Y 6YY YY 
Z,Z
Z
Zz/api/watchlistc                  @    [        S5      =(       d    / n [        U 5      $ )zReturn the saved watchlist.	watchlistra  rb  s    r    get_watchlistr%  -  s     ;'-2D4=r!   c                  *  ^  [         R                  " SS9=(       d    0 n U R                  S5      =(       d    SR                  5       R	                  5       mT(       d  [        SS05      S4$ [        S5      =(       d    / n[        U4S	 jU 5       5      (       a  [        S
US.5      $ Tn [        R                  " T5      R                  =(       d    0 nUR                  S5      =(       d    UR                  S5      =(       d    TnUR                  TU[        R                  " 5       R                  5       S.5        [!        SU5        [        SUS.5      $ ! [         a     N\f = f! [         a"  n[        S[#        U5      05      S4s SnA$ SnAff = f)zAdd a ticker to the watchlist.Tr  rw   r  r   zticker requiredrI	  r$  c              3   2   >#    U  H  oS    T:H  v   M     g7f)rw   Nr   )r   r  rw   s     r    r   #add_to_watchlist.<locals>.<genexpr> .  s     8i{f$is   already_existsr   r$  rm  rn  )rw   rA   added_ataddedr7  N)r   r4
  rv   r  r'  r   r/   r  rp   rq   rr   r2   r  r	   r  r  r9   r  )r  r$  rA   rr   r6   rw   s        @r    add_to_watchlistr-  -  sG   /d+1r((8$*11399;G%678#==#K06B	8i888&6YOPP	99V$))/RD88K(JDHHZ,@JFDFDhllnF^F^F`abY/'	BCC $  /Q()3../sP   A(E& ,;E& (E& +AE AE& 
E# E& "E##E& &
F0FFFz/api/watchlist/<ticker>DELETEc                 <    U R                  5       R                  5       n [        S5      =(       d    / nU Vs/ s H  o"S   U :w  d  M  UPM     nn[        SU5        [	        SUS.5      $ s  snf ! [
         a"  n[	        S[        U5      05      S4s SnA$ SnAff = f)z#Remove a ticker from the watchlist.r$  rw   rU	  r*  r   r7  N)r  r'  r/   r9   r   r2   r  )rw   r$  r  r6   s       r    remove_from_watchlistr0  .  s    /%%'#K06B	 )C	1x[F-BQ		CY/))DEE D  /Q()3../s4   6A/ A*A*A/ *A/ /
B9BBBz/api/watchlist/pricesc                    ^  [         R                  " SS9=(       d    0 n U R                  S5      =(       d    /  Vs/ s H)  o(       d  M  UR                  5       R	                  5       PM+     nnU(       d  [        0 5      $ 0 nS m[        SS9 nUR                  U4S jU5       H	  u  pVXcU'   M     SSS5        [        U5      $ s  snf ! , (       d  f       N= f! [         a"  n[        S	[        U5      05      S
4s SnA$ SnAff = f)z>Get live prices for a list of tickers (for watchlist display).Tr  r  c                 >    [         R                  " U 5      nUR                  =(       d    0 nUR                  S5      =(       d)    UR                  S5      =(       d    UR                  S5      nUR                  S5      =(       d    UR                  S5      nU(       a!  U(       a  US:  a  [	        X4-
  U-  S-  S5      OS nU U(       a  [	        [        U5      S5      OS UUR                  S5      =(       d    UR                  S	5      =(       d    U UR                  S
5      =(       d    SUR                  S5      UR                  S5      (       a$  [	        [        UR                  S5      5      S5      OS S.4$ ! [         a  nU S[        U5      04s S nA$ S nAff = f)Nr  regularMarketPricepreviousCloseregularMarketPreviousCloser   r*  r  rm  rn  r`   r  	marketCap
trailingPEr  )r  r  rA   r`   rQ  rW  r   )rp   rq   rr   rv   r  r  r2   r  )rw   rx   rr   r  r[  chg_pctr6   s          r    fetch_price)get_watchlist_prices.<locals>.fetch_price%.  sH   1IIf%vv|0oDHH=Q4RoVZV^V^_nVoxx0ZDHH=Y4ZCHTVZ]^V^% 5 ;Q?dh7<U5<3$") HH[1STXXj5ISV"hhx06B"&((;"7EIXXlE[E[%dhh|&< =qAae     1Q0001s   E6E9 9
FFFFrB  r  c                    > T" U 5      $ r   r   )rx   r9  s    r    r  &get_watchlist_prices.<locals>.<lambda>7.  s	    {1~r!   Nr   r7  )
r   r4
  rv   r  r'  r   r   rZ  r2   r  )	r  rx   r  r  r  rw   r5   r6   r9  s	           @r    get_watchlist_pricesr=  .  s    /d+1r/3xx	/B/Hb/HO/HQ$1779??$/HO2;	1"  A.( (-Ew O!%v !P / v1 P* /.  /Q()3../sR   9C 
C
"C,C  C $C
2C C 

CC 
D%D<DDz/api/watchlist/searchc                  .   [         R                  R                  S5      =(       d    SR                  5       n [	        U 5      S:  a  [        / 5      $  SnU SSSSS	.nS
SS.n[        R                  " XUSS9nUR                  (       a  UR                  5       O0 nUR                  S5      =(       d    / n/ nU H  nUR                  S5      =(       d    SR                  5       n	UR                  S5      =(       d    UR                  S5      =(       d    U	n
UR                  S5      =(       d    SnUR                  S5      =(       d    SnU	(       d  M  UR                  XXS.5        M     [        U5      $ ! [         a  n[        / 5      s SnA$ SnAff = f)z<Search tickers/company names via Yahoo Finance autocomplete.r0  r  r  z2https://query2.finance.yahoo.com/v1/finance/searchr   r   re  tss_match_phrase_query)r0  quotesCount	newsCountenableFuzzyQueryquotesQueryIdrr  rB  rP  rg   )rE  r   r   r   r@   longname	shortname	quoteTyperu  )rw   rA   r
  ru  N)r   r9  rv   r  rs   r   r   r1
  r   r'  r  r2   )r0  r   rE  r   rO  r5   r   r  r  rx   rA   qtyperu  r6   s                 r    search_watchlist_tickersrH  >.  sP    
		#		$"++-A
1vzr{B!QX  lD  E!.:LMLLWaH44qvvxR(#)rD(#)r002A88J'E488K+@EADHH[)/RExx
+1rHq!5_`  w r{s%   C<E5 "E5 5
F?
F	FFz/api/user/financial-configc                  R    [        S5      n U c  [        SS/ S.5      $ [        U 5      $ )z%Retrieve user financial configurationuser_financial_configr   )budgetsavings_goalrk  ra  rb  s    r    get_user_financial_configrM  X.  s;     23D|
  	
 4=r!   c                       [         R                  n [        SU 5        [        SU S.5      $ ! [         a"  n[        S[        U5      05      S4s SnA$ SnAff = f)z!Save user financial configurationrJ  r   r4  r   r7  N)r   r   r9   r   r2   r  r4   s     r    save_user_financial_configrO  e.  sT    /||/6)T:;; /Q()3../s   ), 
AAAAc                     / SQn Sn[         (       a   [        S[        R                  " 5       R	                  S5       S35         [        5          [        S5        [        5         U(       d  [        S	5         [        U 5        S
n[        [        R                  " 5       5      S-  S:  a
  [        5         [        R                  " S5        [         (       a  M  gg!    N= f! [         a  n[        SU 35         SnANSnAff = f! [         a  n[        SU 35         SnANSnAff = f! [         a.  n[        SU 35        [        R                  " S5         SnANSnAff = f)u'   Boucle de rafraîchissement automatiquer  Fr  r9
  z!] Rafraichissement automatique...zUpdating Truth Social posts...zTruth Social Error: Nz6[START] Chargement unique des Insiders (Background)...TzErreur insiders background: rO  r   r  zErreur background: )background_tasks_runningr3   r	   r  r  r-  r  r2   ro  r  r  r  r  )r  static_insiders_runr6   s      r    background_refresh_looprS  s.  s2    7G  
"
"	Ahlln--j9::[\]')267)+
 'NO>&w/*.'
 499;$&+(*JJsO; #
" D  2,QC0112 ! >8<==>  	's+,JJrNN	s~   1D* 
C C  %D* 8D AD* CD*  
D*C=8D* =DD* 
D'D"D* "D''D* *
E"4$EE"z/api/background/startc                      [         (       dZ  Sq [        R                  " [        SS9n U R	                  5         [        S[        R                  " 5       R                  5       S.5      $ [        SS05      $ )u   Démarre les tâches de fondTr  r  r  r   r  )	rQ  r  r  rS  r  r   r	   r  r  )rq
  s    r    start_background_tasksrU  .  s\    
 $##' !!)@N)(,,.:R:R:TUVVH/011r!   z/api/background/stopc                  d    Sq [        S[        R                  " 5       R	                  5       S.5      $ )u   Arrête les tâches de fondFr  r  )rQ  r   r	   r  r  r   r!   r    stop_background_tasksrW  .  s)      %ihlln6N6N6PQRRr!   z/api/analyze-fundamentalsc            
      	  ^^ [         R                  R                  S/ 5      n U (       d  [        S/ 05      $ / n0 mS n[	        SS9 nUR                  X 5      nU H&  nU(       d  M  Uu  pgUR                  U5        UTU'   M(     SSS5         [        5         [        [        U5      5      nUSS n	[        U5      S	:*  m/ n
 [        S
[        U	5       S35        U	(       d  [        S/ 05      $ [        R                  " U	SSSSSS9n/ nU	 GH  n [        UR                   ["        R$                  5      (       a#  XR                   R'                  S5      ;   a  X   nO[        U	5      S:  a  X   nOUnUR)                  SS9n[        U5      S:  a  M  US   R*                  S   n[        U["        R,                  5      (       a  UR*                  S   n[        U5      S:  a  US   R*                  S   OUS   R*                  S   n[        U["        R,                  5      (       a  UR*                  S   n[        U5      S:  a  US   R*                  S   OUS   R*                  S   n[        U["        R,                  5      (       a  UR*                  S   n[        U5      S:  a  US   R*                  S   OUS   R*                  S   n[        U["        R,                  5      (       a  UR*                  S   n[        U5      S:  a  US   R*                  S    OUS   R*                  S   n[        U["        R,                  5      (       a  UR*                  S   nUU-
  U-  nUU-
  U-  nUU-
  U-  nUU-
  U-  nUS:  =(       a    US:  nS!nU(       d  T(       d  U(       a  UR                  UUUUUS".S#.5        GM  GM     [        S$[        U5       S%35        UU4S& jn[	        S'S9 n[        [/        UR                  UU5      [        U5      S(S!S)95      nSSS5        W Vs/ s H
  nUc  M  UPM     n
nU
R3                  S- S!S.9  [        SU
05      $ ! , (       d  f       GN= f! [         a  n[        SU 35         SnAGNSnAff = f! [         a  n SnAGM  SnAff = f! , (       d  f       N= fs  snf ! [         a0  n[        S*U 35        [        S+[1        U5      05      S,4s SnA$ SnAff = f)/z0Analyse technique (3 timeframes) et fondamentaler  r  c                     U (       d  g [         R                  " SU 5      (       a6  [        U 5      nU(       a#  UR                  SS5      R	                  5       nX 4$ g U R                  SS5      R	                  5       nX 4$ )Nz^[A-Z]{2}[A-Z0-9]{9}\d$r   r  )r  r  r   r  r'  )rx   resolvedr}	  s      r    process_one_ticker0analyze_fundamentals.<locals>.process_one_ticker.  sq    88.22+A.H ((b1779z!  		#r"((*zr!   r   r  Nz$Warning: Failed to save ISIN cache: i'  rg   zDownloading history for r  r  r  rw   Fr*  )rg  rb  r  rc  r	  r   r  r   howr4  rd  r  r  irn  i=   irp  iT)r  ru  rv  rw  )r@   perfszTechnical filter passed: z' stocks. Launching parallel analysis...c                 (  > U S   n [         R                  " U5      nUR                  nU(       a  SU;  a  SU;  a  SU;  a  g UR                  SS5      =(       d    SnUR                  SS5      =(       d    SnUR                  SS5      =(       d    SnUR                  S	S5      =(       d    SnUR                  S
5      nUR                  S5      n	UR                  S5      n
UR                  S5      =(       d    SnUR                  S5      =(       d    UR                  S5      =(       d    UnUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUS:  =(       d    US:  n/ nSU;   a  US   (       a~  SS KnUR                  R                  US   5      nUR                  R                  5       nUU-
  R                  nSUs=::  a  S::  a&  O  O#UR                  SUR                  S5       35         UR                  nU(       a  US S  H  nUR                  SS5      R                  5       nS U;   a  UR                  S!5        S"U;   d  S#U;   a  UR                  S$5        S%U;   a  UR                  S&5        S'U;   d  S(U;   d  M|  UR                  S)5        M     [        [        U5      5      nUR                  SS5      =(       d    SnUS*:  =(       d    US*:  nUS:  nUR                  S+5      =(       d    UR                  S,5      nUR                  S-5      nUR                  S.5      n Sn!U(       d  U(       a  S/OS0n"U(       d  U(       a  S1OS2n#U(       a  SUs=:  a  U":  a  O  OU!S3-  n!U(       a  SUs=:  a  S4:  a  O  OU!S3-  n!U (       a  SU s=:  a  U#:  a  O  OU!S3-  n!UR                  S	S5      =(       d    SnUR                  S
5      nSn$US5:  a  U$S3-  n$US5:  a  U$S3-  n$U(       a  US6:  a  U$S3-  n$Sn%US7:  a  U%S3-  n%US7:  a  U%S3-  n%U(       a  U%S3-  n%U!U$-   U%-   n&/ n'U S8   S9   S:  a  U'R                  S:5        U S8   S;   S:  a  U'R                  S<5        U(       a  U'R                  S=5        OU%S3:  a  U'R                  S>5        US:  a/  U S8   S;   S:  a  U'R                  S?5        OU'R                  S@5        U!S:  a  U'R                  SA5        U(       a  U'R                  SB5        U S8   S9   S:  a  S3OSU S8   SC   S:  a  S3OS-   U S8   S;   S:  a  S3OS-   n(U&U(       a  SOS4:  n)U(S4:H  =(       a    U&S3:  n*T,(       d  U)(       d  U*(       Ga9  0 SU_SDSE_SFU&U(-   _SG[        [        U'5      5      _SHU_SI[        UXvXHUUUUUUSJ.5      _S8[        U S8   5      _SKUR                  S5      =(       d    UR                  S5      =(       d    U_SLUR                  SLSM5      _SNUR                  S5      _SOUR                  S5      _SPUR                  S5      =(       d    UR                  SQ5      _SRUR                  SR5      _SSUR                  SS5      _STUR                  SU5      _SUR                  S5      _SVT-R                  U5      _$ g !    GN= f! [         a
  n+ S n+A+g S n+A+ff = f)WNr@   r3  r  r4  revenueGrowthr   earningsGrowthprofitMarginsreturnOnEquitydebtToEquityrU  rV  longBusinessSummaryzAucune description disponible.rn  rm  r  dividendYieldr  payoutRatior6  fiftyTwoWeekHighfiftyTwoWeekLowr  ir   zEx-Div: z%d/%mr  rC  r  ro  zNews: Dividender  r  u   News: Résultatsr  zNews: Splitr  mergerz	News: M&Ar  rR  r7  rS  priceToBookr  r   r  r~  r  r}  r     r  r`  r  z	Wkly Bullrv  zQtr BullzHigh Growth [START]
Croissanceu   Trend Spéculatif [WARN]zNon RentablezValo.u   Quality 💎ru  isValidatedTrk  validationsr
  metrics)rW  roemarginr  debtr  rh  ri  r  rj  rk  rA   r}  r{  targetPricerY  ru  shortBusinessSummaryr`   ri   	employeesfullTimeEmployeesr   )rp   rq   rr   rv   r	   r  r  r  r  r  r  r=   r  r  r  r2   ).r  r@   r  rr   r  earn_growthprofit_marginrs  ru  rZ  rY  ru  rA   r  rh  r  ri  r6  rj  rk  is_high_growthevents_foundr	   ex_divr  	diff_daysr  r  rC  is_high_qualityrW  rX  pb
val_pointspe_limitpb_limitqual_pointsgrowth_pointstotal_scorerq  r0	  
pass_fundapass_tech_mixedr6   is_manual_moder	  s.                                               r    process_one_stock/analyze_fundamentals.<locals>.process_one_stockF/  sK   (^Fq		&)zz 4D @^[_E_ds{d "XXoq9>Q
"hh'7;@q $! < Ahh/38qxx/#xx(9:!%*=!>"hh'<=aAaxx
+Ntxx/DN  $xx: $! <!%*:A!>"hh}a8 !HH[!4	 $(88,>#B "&((+<a"@
 #-t"3!Lt9K  " $t+5E0F#%..<<TBR=STF"++//1C!'# 3 3Ii-2-$++hvw7O6P,QR
 ::D!%bqA$%EE'2$6$<$<$>E)U2L4G4GHY4Z)U2h%6GI\I\]oIp&%/1D1D]1S,5U9JLL_L_`kLl "*  $C$56 !%! < A",t"3!Lt9K#04#7
 XXk*Ddhh|.Dhhz*XXm,
"0O2""0O2!!b+8+Z1_Z1s;Q;
a
!b+8+Z1_Z hh/38qxx/:{a/{ 4')9D3Jq(8 !"$mq&8m%}'9}!=A#5=(;6F !=&*K,>,>{,K=&*K,>,>z,J!;#5#56K#L"a'););L)I !1$Wd+d2$++,FG$++N;?K$6$6w$?"K$6$6~$F $(=#6#:a4PW=Y]K^abKbahijswx  tA  BF  tG  JK  tKno  QR  S
 *>aqI
#-?#G{a7G!Z? &%t  z!9 &tC,<'=	
 !, ">"$S*4,8-:+6.<0@/>	3 	$   W!>!"  4 W8M WQW#$ #DHHZ$?%& &txx0A'B'( )$((3F*G)* &txx0E'F'j$((SiJj+, !$((8"4-. #DHHZ$8/0 $TXX.A%B12 $TXXk%:34 
v 65  4CWP  s8   ;[= H
[= B[5 #[5 8O;[= 5[:7[= =
\\r   zFundamental Analysis)r~   r  disablezGlobal analysis error: r   r7  c                     U S   $ )Nrk  r   r  s    r    r  &analyze_fundamentals.<locals>.<lambda>0  s    qzr!   r^  )r   r   rv   r   r   rZ  r  r;   r2   r3   r  r  rs   rp   r  r  r  r  r  get_level_valuesr  r
  r  r   r  r	  )tickers_inputclean_tickersr[  r  future_resultsr\  r}	  origr6   candidates_tickersr  history_datastrong_trend_tickersrw   r  rr  price_1wprice_1mprice_3mprice_6mperf_1wr  r  r	  passed_trend_checkforce_include_allr  parallel_resultsrO  r  r	  s                                @@r    analyze_fundamentalsr  .  s    LL$$Y3M	2'' MJ* 
	+x!&8H!Cs!$$U+$(
5!	 " 
,: ]+,M 'v. -(A-NGU/ 	(-?)@(AMN!YO,, {{#5dT\dot  B  C!(FC l22BMMBBvQeQeQvQvwxQyGy%-B+,q0&.R%B YY5Y)r7R< !#7 0 0 4mRYY77I[I[\]I^ 47r7a<2g;++B/R[EUEUVWEXh		22x}}Q?OH 58GrM2g;++C0r'{GWGWXYGZh		22x}}Q?OH 58GrM2g;++C0r'{GWGWXYGZh		22x}}Q?OH 69W^2g;++D1GIYIYZ[I\h		22x}}Q?OH )83x?(83x?(83x?(83x? '.k&Agk" %)!$:L)00#)#*#*#*#*	#2  ;Mo )N 	)#.B*C)DDklms	l  B/8  $D6GI])^fij~f  G]  gk  %l   m 0
 /@.!1.@ LL)4L8Iw'((k	 
,	+  :4QC899:|  | 0/
 A /'s+,Q()3../s   Q'Q
Q% +R: .!R: B RR: H%R70R: '/R$R: "R5-R53R: 
Q"%
R/RR
R!R: R!!R: $
R2.R: :
S4%S/)S4/S4c                  ~   [        S5        [        5       n Sn  U R                  R                  U R                  5        U R                  R                  SSSS9nU(       d[  [        S5        U R                  5       (       a  U R                  n[        S5        O#[        S	5        [        R                  " S
5        M  U(       a  X l        [        R                  " 5       n[        R                  " U5         UR                  U R                  5       5      nU(       ar  UR                  U R                  5       5        US-  S:X  a*  [        S5        UR                  U R!                  5       5        UR                  U R#                  5       5        O#[        S5        SU l        U R                  5          UR#                  5         O US-  n[        R                  " S5        GM  ! [$         a  n[        SU 35         SnANMSnAff = f! UR#                  5         f = f! [$         a  n[        SU 35         SnANuSnAff = f)u   Boucle dédiée au rafraîchissement du portfolio Trade Republic toutes les 5 minutes.
Fetch history (transactions) runs every 30 minutes so new purchases appear on the graph.
Auto-refreshes the session token via tr_refresh when expired.zK[START] Auto-refresh Portfolio loop started (5 min prices / 30 min history)r   r   r   Nr   zL[Background TR] No session token - attempting auto-refresh via tr_refresh...z,[Background TR] [OK] Auto-refresh succeeded.zD[Background TR] [WAIT] Auto-refresh failed - waiting for user login.r   r  z@[Background TR] Refreshing transaction history (30 min cycle)...zI[Background TR] Login failed or session invalid - trying token refresh...zBackground TR Error: zBackground TR Loop Error: r  r  )r3   rk  r   r   r   rv   r  r   r  r  r   r   r   r   r   r}  r  r   r2   )r  _cycler  r   r  r6   s         r    background_tr_portfolio_loopr  0  s    

WX !"IF
+	5!!)"7"78$$((<$(OEde2244%33EHJ`aJJrN+0(..0''-" $ 7 7	8I8I8K LI //	0I0I0KL!A:?!"de 33I4K4K4MN//	0ABij26	/!779 ZZ\ 
 	!

3a F " 821#6778 ZZ\
  	5/s344	5sg   B H <8H 5BG  H "G  /H 0H  
H*G=8H =HH HH 
H<$H77H<z/api/loading/statusc                       [        [        5      $ r   )r   r   r   r!   r    get_loading_statusr  K0  s    =!!r!   z/api/wallet/investmentsc                      [         R                  R                  5       n / nU  H  nUR                  UR                  UR
                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  S.5        M     [        U5      $ ! [          a"  n[        S[#        U5      05      S4s S nA$ S nAff = f)Nrm  r   r7  )ro  r   r   r  r   rA   rp  rq  rr  r<  rs  rt  ru  rv  rw  r   r2   r  )r  r5   r  r6   s       r    get_wallet_investmentsr  O0  s    /&,,002CKKLL ]]!$!2!2"ww"LL"%"5"5   t} /Q()3../s   B>C 
C-C("C-(C-c                     [        S5        [        SS5        [        SS5         [        R                  5          [        R
                  R                  5       n U S:  a%  [        SU  S35        [        SS5         S	S	S	5        g	[        S
5        [        SS5        S	S	S	5        g	! , (       d  f       g	= f! [         a$  n[        SU 35        [        SS5         S	nAg	S	nAff = f)u/   Vérifie que le portefeuille est présent en DBz,[REFRESH] Verification portefeuille en DB...r   r   r   r
  r   z [OK] Portefeuille trouve en DB (z positions).NzN?? Portefeuille absent de la DB. En attente de synchronisation Trade Republic.zError checking DB for wallet: r   )r3   r   r)   r.   ro  r   r  r2   )r  r6   s     r    import_wallet_jsonr  f0  s    	
89
I.),/__$**002Eqy8|LM#Hi8  bc)4   /.qc23Hg../sA   B4 AB#:B4 B#B4 #
B1-B4 1B4 4
C">CC"c                      [        S5         [        S5      n U (       a  [        S[        U 5       S35        g[        S5        g! [         a  n[        SU 35         SnAgSnAff = f)u(   Vérifie que les transactions sont en DBz,[REFRESH] Verification transactions en DB...r  ri  z transactions trouvees en DB.z?? Aucune transaction en DB.z$Error checking DB for transactions: N)r3   r/   rs   r2   r4   s     r    import_transactions_jsonr  {0  s`    	
89:01E#d)$ABC01 :4QC899:s   *A A 
A&A!!A&c                  x   [         R                  " S5        [        SS5        [        5         [        SS5         [        R                  5          [        S5      (       a  [        SS5        O3[        R                  " [        SS9R                  5         [        SS5        S	S	S	5        [        SS5         [        R                  5          [        R                  R                  5       S:  a  [        S5        [        SS5        O/ SQn[         R                  R#                  5       nU(       a?  U H9  n[%        UR&                  5      nU(       d  M!  XA;  d  M(  UR)                  U5        M;     [        SUS	S  S35        [+        US	S 5        [        SS5        S	S	S	5        [        SS5         [-        5         [        SS5        [        SS5        [        R                  5          [.        R                  R                  5       nUS:  a  [        SS5        O[0        R2                  R5                  [0        R6                  5        [0        R2                  R9                  SSS	S9(       a?  [        S5        [        SS5        [        R                  " [:        SS9R                  5         O[        S5        S	S	S	5        [        SS5        [        R                  5          Sn[<        R                  R                  5       S:  aF  [<        R                  R?                  S5      R#                  5       n[A        S U 5       5      (       a  SnU(       d  [        S 5        [        SS5        S! n[        S"5      n	U	(       a  [        S#5        U" U	5        Sn
[<        R                  R                  5       S:  aF  [<        R                  R?                  S5      R#                  5       n[A        S$ U 5       5      (       a  Sn
U
(       aE  [        S%5         [C        5       nURE                  5       nU(       a  [        S&[G        U5       S'35        [<        R                  R                  5       S:  a  [        S)5        [        SS5        O[        S*5        [        SS5        S	S	S	5        [        S+S5         [        R                  5          [H        R                  R                  5       S:  a  [        S,5        [        S+S5        O![        S-5        [K        5         [        S+S5        S	S	S	5        S[L        S/'   [        S05        g	! , (       d  f       GN= f! [         a%  n [        S
U  35        [        SS5         S	n A GNS	n A ff = f! , (       d  f       GN= f!   [        SS5         GN= f!   [        SS5         GN= f! , (       d  f       GN= f! [         a  n [        S(U  35         S	n A GNS	n A ff = f! , (       d  f       GN_= f! , (       d  f       N= f! [         a%  n [        S.U  35        [        S+S5         S	n A GNS	n A ff = f)1uJ   Lance les tâches de chargement initial et s'assure que la DB est peupléer  r   r   r   r
  rK  Tr  NzError in initial RSS task: r   r   r   z[OK] Insiders already in DB.)r
  r
  r
  r  r  r
  r
  r
  z"?? Scraping context initial pour: rB  r   r   r   r   r   r   r   r   zH[WAIT] Sectors empty but logged in. Triggering background calculation...z+?? Sectors empty. Waiting for user login...r   Frg   c              3   v   #    U  H/  oR                   =(       a    [        UR                   5      S :  v   M1     g7frG
  )rD  rs   r  s     r    r   ,run_initial_loading_tasks.<locals>.<genexpr>0  s'     DV993QYY!!33Vs   79zP[WAIT] Perspectives bancaires vides ou incompletes. Tentative de recuperation...c                    / nU  Hn  nSSR                  UR                  S/ 5      5      -   nUR                  UR                  S5      UR                  S5      UR                  S5      USSS S S.5        Mp     [        U5        g )	NrQ  r4  rX  r   r:  r  rt  ru  )r  rv   r  r  )r>  	formattedr\  rD  s       r    format_and_save_raw6run_initial_loading_tasks.<locals>.format_and_save_raw0  s}    	#C$v{{3778R3H'IIG$$ #"wwu~ # 4#*%.*9"&(,	& 	 $ 'y1r!   rs  zI[PKG] Chargement des perspectives depuis le cache SQL (avec formatage)...c              3   8   #    U  H  oR                   v   M     g 7fr   )rD  r  s     r    r   r  0  s     26a		6s   z;[WEB] Recuperation en direct des perspectives (Scraping)...ri  z sources bancaires recuperees.z&[ERROR] Erreur scraping perspectives: z#[OK] Perspectives bancaires pretes.z?[WARN] Aucune perspective bancaire trouvee, passage a la suite.r   z[OK] Macro data already in DB.z3[WEB] Recuperation des donnees macro-economiques...zError in initial macro task: r   z [OK] Chargement initial termine.)'r  r  r   r  r)   r.   r/   r  r  r-  r  r2   r3   rJ  r   r  ro  r   r   r   r  ro  r  r_  r   r   r   r   rv   r  rW  rC  r  r  r  rs   r  rk	  r   )r6   r  invsr  rx   r  has_valid_datasampler  r	  still_emptyr  r  s                r    run_initial_loading_tasksr  0  s   JJqM 
I.  y),__//$UI6 !!)@NTTV$UI6  
I.1__!''--/!345#J	: Z'--113#0:1!17>>!3D  $ :72A;-sKL"73B<0#J	: ( +. "GY/
 3		!!'')19; MMv112}}  <$ Gab$_i@!!)EdSYY[DE 
  Y/		##%)!''--a0446FDVDDD!%deY72" ""34Cab#C( K!!'')A-&,,221599;26222%KSTH13G%002G c'l^3QRS ##%)78Y7STY7y 
~ +.__$$&*67#GY7KL!##GY7  !%M*	
,-[   ,+A3/0E7++,  1J0.GW- 
	J ! HB1#FGGHi 
	B   .-aS12GW--.s   U AT1U 4V BU5U5AU5V ,V "CV/D-W'9W>AW'$X
 8AW9X
 1
U ;U  U 
U2U--U25
V?V V VV,/
V>
W$WW'W$$W''
W69
XX
 X
 

X9X44X9c                   2   ^  \ rS rSrSrU 4S jrS rSrU =r$ )NoCacheHTTPHandleri#1  zRSimpleHTTPRequestHandler with Cache-Control: no-store to always serve fresh files.c                    > U R                  SS5        U R                  SS5        U R                  SS5        [        TU ]	  5         g )Nr8  z.no-store, no-cache, must-revalidate, max-age=0r  r  Expiresr  )send_headersuperend_headers)r	  	__class__s    r    r  NoCacheHTTPHandler.end_headers%1  s?    *Z[:.C(r!   c                     g r   r   )r	  r
  r9  s      r    log_messageNoCacheHTTPHandler.log_message*1  r
  r!   r   )	r  r  r  r  rf  r  r  r  __classcell__)r  s   @r    r  r  #1  s    \
 r!   r  c                  (   Sn S[         R                  l         [         R                  " SU 4[        5       n[	        SU  35        UR                  5         SSS5        g! , (       d  f       g= f! [         a  n[	        SU 35         SnAgSnAff = f)zgLance un serveur HTTP simple sur le port 8080 pour servir les fichiers statiques (terminal.html, etc.).i  Tr  z7[NET] Serveur HTTP statique lance sur http://localhost:Nz;[ERROR] Erreur lors du lancement du serveur HTTP statique: )socketserver	TCPServerallow_reuse_addressr  r3   serve_foreverr2   )PORThttpdr6   s      r    run_static_http_serverr  -1  s    D15L.Q##RJ0BCuKD6RS! DCC  QKA3OPPQs4   A/ AA/ 
A,(A/ ,A/ /
B9BB__main__zF======================================================================z BACKEND API - TERMINAL FINANCIERzEndpoints disponibles:z:  GET  /api/health                     - Statut du serveurz;  GET  /api/data/all                   - Toutes les donneesz<  GET  /api/data/<type>                - Donnees specifiquesz5  GET  /api/prices                     - Prix actuelsz<  GET  /api/prices/history             - Historique detaillez=  GET  /api/senator-trades             - Trades des senateursz@  GET  /api/senator-trades/summary     - Resume trades senateursz;  POST /api/refresh/<type>             - Rafraichir donneesz5  POST /api/chat                       - Assistant AIz>  POST /api/analyze                    - Analyse personnaliseez>  POST /api/background/start           - Demarrer auto-refreshz=  POST /api/background/stop            - Arreter auto-refreshzS  POST /api/bank-forecasts/scrape     - Lancer le scraping des previsions bancaireszR  POST /api/bank-forecasts/analyze    - Lancer l'analyse IA des articles bancaireszK  GET  /api/bank-forecasts             - Recuperer les previsions bancaireszI  GET  /api/bank-analyses              - Recuperer les analyses bancaireswerkzeugz;[START] Lancement du chargement initial (Loading Screen)...c                        \ rS rSrS rS rSrg)	PDFReportix1  c                     g r   r   r  s    r    r  PDFReport.headery1  s    r!   c                     U R                  S5        U R                  SSS5        U R                  SSS5        U R                  SSS[        R
                  " 5       R                  S	5       3SSS
5        g )NiArialr  rB     r   r   zReleve de compte | z%d/%m/%Yr8  )set_yset_fontset_text_colorcellr	   r  r  r  s    r    footerPDFReport.footer|1  sb    JJsOMM'2q)S#.IIa28<<>3J3J:3V2WXZ[]^`cdr!   r   N)r  r  r  r  r  r  r  r   r!   r    r  r  x1  s    		er!   r  z/api/report/portfolio_pdfc            
          [        5       n U (       a  U R                  S/ 5      O/ nU Vs/ s H+  o"R                  S5      (       d  M  UR                  S5      PM-     nn[        U5      n/ nSnUR                  5        H  u  pxUR                  SS5      n	UR                  S/ 5      n
UR                  SS5      nXk-  nSU	;   d  U
(       d  [	        U5      S	:  d  M]  UR                  UU
(       a  U
S   O	US
:  a  SOSUS.5        M     US:  a  SOSnSU SUS S3nU(       aB  U[        U5       S3-  n[        US S9SS nU H  nUSUS    SUS    SUS   S S3-  nM     OUS-  nUS-  n[        5       nUR                  5         UR                  S S!S"5        UR                  SSS5        UR                  SS#S$SS%S&5        U R                  S'S5      nUR                  S S!S(5        UR                  SS#US) S*3SS%S&5        U R                  S+S5      nUU-
  S:w  a  UUU-
  -  S,-  OSnUR                  S S!S-5        US:  a  UR                  S.S/S05        OUR                  S1S2S25        US:  a  S3OSnUR                  SS4U US) S5U US6 S73SS%S&5        UR                  S85        UR                  S9S:S;5        UR                  S9S:S;5        UR!                  S8UR#                  5       S<S=S>5        UR%                  S#UR#                  5       S?-   5        UR                  S S!S@5        UR                  SASBSC5        UR                  SDS?SESS5        UR                  S SS@5        UR                  SSS5        UR'                  SFSG5      R)                  SF5      nUR                  SS?USS%5        UR                  S#5        UR                  S S!S@5        UR                  SHS/SI5        UR                  SJS4SKSS5        UR                  SLS4SMSSSN5        UR                  SLS4SOSSSN5        UR                  S=S4SPSS%SQ5        UR                  SRSSST5        UR+                  S8UR#                  5       SUUR#                  5       5        UR                  S5        U GH$  nUR                  SS5      nUR                  SVSW5      nUR                  SXS5      nUR                  SYS5      nUR                  U0 5      nUR                  SZU5      nUR                  SS[5      nUR                  S/ 5      n
UR#                  5       nUS\:  a   UR                  5         UR#                  5       nUR                  SSS5        UR!                  S8US-   S8S8S]5        UR                  S^S^S^5        UR                  S S!S_5        USS R-                  5       nUR/                  S-US4-   U5        UR%                  SDUS%-   5        UR                  SSS5        UR                  S S!S85        UR                  S`S?USSD SS5        UR                  S SS45        UR                  SHS/SI5        UU-  nUR                  S`SaU SbUS Sc3SS5        UR%                  S,USd-   5        UR                  SSS5        UR                  S S!S85        UR                  SLS4US6 Sc3SSSN5        UR%                  SeUSd-   5        US:  a  UR                  S.S/S05        S3nOUR                  S1S2S25        SnUR                  S S!S85        UR                  SLS4U US6 Sf3SSSN5        UR%                  SgUS?-   5        U
(       a  UR                  S1S2S25      OUR                  S.S/S05        UR                  S S!S=5        UR                  S=SaShSSSQ5        UR                  S-5        GM'     Si[1        [2        R2                  " 5       5       Sj3n UR5                  U 5        [7        U SkSl[8        R:                  " 5       R=                  Sm5       Sj3Sn9$ s  snf ! [>         a6  n![@        RB                  " 5         [E        So[G        U!5      Sp.5      s Sn!A!$ Sn!A!ff = f)qz[
Generates a 'Trade Republic' style PDF Report
with AI-driven Market Intelligence Summary.
r  rw   r   trend_labelr  	red_flagsdaily_change_pctri  g      @zChute brutaleu   Volatilité)rw   r  rf  r  r  u#   Le sentiment de marché global est rq  z.1fu   % agrégé). z' actifs sous surveillance prioritaire. c                     U S   $ )Nrf  r   r  s    r    r  (generate_portfolio_pdf.<locals>.<lambda>1  s    6r!   r  Nr  r  z] montre des signes de r  rf  z%). u1   Aucune anomalie majeure de structure détectée. uh   L'analyse prédictive suggère une rotation sectorielle imminente basée sur les flux Insiders récents.r  Brj	  r  Portefeuiller  Lr<      z,.2fz EUR	total_pnlr*  rA        J      &   r  rB  z EUR (rr  z%) Aujourd'huir               r4  FDrg   rm  r  U   c   r  zMARKET POINTzlatin-1r        r  TITREr  PRIXRzAUJOURD'HUIALERTEr8           r   rA   rh   r  r  rr  rz  i  Fr  r  r  r~  z	 units | z eurr}     r     r|  report_z.pdfTGenerationalWealth_Report_z%Y%m%d)as_attachmentdownload_namer   r8  )$r  rv   _generate_deep_analysis_datar_   r  r  rs   r`  r  add_pager  r  r  lnset_fill_colorset_draw_colorrectget_yset_xyrT  rU  liner'  r   r  r  r  r   r	   r  r  r2   r   r   r   r  )"r  r  r  r  analysis_datacritical_assetsmarket_mood_scorerw   r5   rh  r  
daily_perfmarket_directionai_texttop_critassetpdfr	  pnl_valpnl_pctarrowclean_ai_textrx  rA   r  r  rr  daily_changestart_yinitials
market_valsignr
  r6   s"                                     r    generate_portfolio_pdfr   1  s]   u	C02I:C	k26I09M	1UU8_quuX	GM 9AM !O ! - 3 3 53b1!XX&8!<
!/!%#j/C2G#**"(.3%(ZZ\_/bo *,  !6 .?-Bz
;<L;MRPabeOffstGc/233Z[[!/7JKBQO%E5?"33J5QY?J[[]^cdj^klo]pptuuG & NN  B  BG +CLLN LL#r*q!Q'HHQNAq#6 "mQ7ILL#r*HHQy.d3Q3?  mmK3GBKgBUZ[A[w)g"56<abGLL#r*!|S//C<$$S"b1 #a<CREHHQeWWTN&}N[]^`acfgFF2J sC-sC-HHRc2t4JJr399;?+LL#q)r2r*HHRNAq1LL"a(q!Q'#NN9i@GG	RMHHQ=!Q/FF2J LL#q)sC-HHRGQ*HHRFAq#.HHRM1a5HHRHaC0 sC-HHRc399;7FF1I 2.wwvy1ggeQ'GGJ2	$((4 $) D#xx(:C@b1 ))+ S=LLN!iikG ""1a+Wq["b#6""3S1Wc1-8>>+Wq[(3 

2w{+""1a+Wc2.QSb	1a0Wb!,""3S1 =0
Q3%yC0@ Eq!L 

3!,""1a+Wc2.Q="5T :Aq#F 

3!,1$&&r33D&&sB3DWc2.Q4&c(:! <aCH 

3!,38""3B/c>P>PQSUXZ\>]Wc2.QQ3/ r
A !J !TYY[!1 2$7HJJx XTKefnfrfrftf}f}  G  gH  fI  IM  JN  O  O[ N^  	C!g#a&ABB	Cs<   )`" ``A:`" ]`" `" "
a",+aa"a"c                    0 nU (       d  0 $  [         R                  " U SSSS9n[        5       =(       d    / nU  GHS  n/ SSSSS.n S	n[        U[        R
                  5      (       ar  [        UR                  [        R                  5      (       aG   [        U5      (       a  UR                  US
S
S9OX$   nXBR                  R                  S   ;   a  X$   nOUnUb  UR                  (       d  UR                  SS9n[        U5      S:  a}  US   R                  S   nUS   R                  S   n[        US5      (       a  UR!                  5       n[        US5      (       a  UR!                  5       nXuS'   US:  a  Xx-
  U-  S-  US'   XQU'   GMV     U$ !   XBR                  ;   a  X$   n N= f! ["         a  n	[%        SU SU	 35         S	n	A	NES	n	A	ff = f! ["         a   n	[&        R(                  " 5          S	n	A	U$ S	n	A	ff = f)z6Helper to generate analysis data for a list of tickersr  FT)rg  rc  r	  r  rz  r   )r  r  r  rr  rg  Nr  )rt  ri  r   r   r]  r  rd  r  r  r  rr  r*  r  zData Error rm   )rp   r  r  r  r  r  r  r  level_checkxsry  r  r  rs   r
  r^   r  r2   r3   r   r   )
r  r  r  r   rw   t_resr  
last_close
prev_closer6   s
             r    r  r  ?2  s   r	6	";;wteTRD')/RH!&(X[nqz|}(7B!$55%dllBMMBBMITUYIZIZTWWV!1W%E`d`l#)\\-@-@-C#C)-B
 "&B~bhhYY5Y1r7a<)+G)9)9")=J)+G)9)9")=J  'z6::IZJ&z6::IZJ5?/2)A~>H>UYc=cgj<j&8 9 #(] "f KM#)\\#926 ! 7Kxr!5667  	"!!	"s\   8G A
F-AFB2F-	G F*(F--
G7GG GG 
G?G::G?c                     g)NTr   )r  s    r    r"  r"  ~2  s    r!   c                 	  #    [        S5        U R                  SS9I Sh  vN n/ n/ SQn/ SQnS[        5       ;   a
  [        USS	9OUnU GH  nUR	                  S
5      n[        UR	                  SS5      5      R                  5       n[        UR	                  SS5      5      R                  5       n	U	(       d)  [        UR	                  SS5      5      R                  5       n	US-   U	-   R                  5       n
SnU H  nX;   d  M
  Sn  O   U H  nX;   d  M
  Sn  O   U(       d  M  USSSSSSSUS.	nUR	                  S5      nU(       a  [        R                  " US-  5      US'    UR	                  S0 5      R	                  S0 5      n[        UR	                  SS5      5      US'   UR	                  SS5      nU(       a2  [        R                  " SU5      nU(       a  UR                  S5      US'   SnU(       Ga  U(       Ga   [        R                  " S5      I Sh  vN   U R!                  U5      I Sh  vN nS nUS   (       d7  U" USS /5      nU(       a%  UR#                  S5      S!   R                  5       US'   U" U/ S"Q5      nU(       aH  S#U;   a  UR#                  S5      S!   nUR%                  S$S%5      R                  5       n[        U5      US&'   U" U/ S'Q5      nU(       aN  UR%                  S(S5      R%                  S)S5      R%                  S$S%5      R                  5       n[        U5      US*'   U" U/ S+Q5      nU(       aO  UR%                  S(S5      R%                  S)S5      R%                  S$S%5      R                  5       n[        U5      US,'   O S/U
;   =(       d    S0U
;   nU(       a  S1US2'   OS3US2'   [)        US&   5      US&'   US&   S!:X  a)  US*   S!:  a   US   S!:w  a  [)        US   5      US*   -  US&'   UR+                  U5        GM     [        S4[-        U5       S535        U$  GN!    GN= f!    GN= f GN' GN!    GNv= f!    GN= f!    N= f! [&         a  n[        S-U S.U 35         SnANSnAff = f7f)6z
Fetches ALL transactions, filters for relevant types (trade, savings_plan),
fetches details if missing (shares/price), and parses into a clean structure.
Input: api_instance (TradeRepublicAPI object)
Output: List of dicts
z0[START] Starting fetch_and_parse_transactions...Fr	  N)
r  r  r  r  r  r  r	  zorder executedu   ausführungexecuted)ro  deposit
withdrawalu   ausschüttung
einzahlung
auszahlunginterestzinsenr   zParsing Transactions)r  r-  rC  r  r	  rw  r   Trz  )	r-  rN  r
  r   rQ  r  r|  feerA   r:  ru	  rN  r5   r|  rR  r  z([A-Z]{2}[A-Z0-9]{9}\d)r  r   r  c                     U R                  5        H;  u  p#UR                  5       U Vs/ s H  oDR                  5       PM     sn;   d  M9  Us  $    g s  snf r   )r_   r=   )r  r  rc   rd   r   s        r    get_val-fetch_and_parse_transactions.<locals>.get_val2  sE     !	779D(ADqD(AA#$H !*   )Bs   AISIN
Instrumentr   )r  u   StückAnteileAnzahlStkr  r|  rQ  )zPrice per sharePriceKursu   Ausführungskursr{  r  r  )zService costsFremdkostenzuschlagu   GebührzExternal costsKostenr0  z[WARN] Detail fetch failed for rm   r  r	  r	  r
  r	  z[OK] Parsed z transactions.)r3   r  r-   r   rv   r  r  r=   r	   r  r  r  r  r  r   r  r  r  r  r2   r  r  rs   )api_instanceraw_transactionsr	  RELEVANT_KEYWORDSEXCLUDE_KEYWORDSiteratorr	  r  rC  rw  r	  is_relevantr  kexparsedr  r	  icon_urlr  need_detailsrc  r2  r  r}	  r6   r	  s                             r    fetch_and_parse_transactionsrG  2  s~     

<= *777NN
 @ GMPWPYFYt$+AB_oHvvd|BFF7B'(..0rvvnb1288:Cz2(>$?$E$E$GS[8+224	 #B" $
 $C# $
  

 VVK "*"8"8f"E	ffVR(,,Xr:G$W[[#%>?F8
 66&"%II8(CEu{{1~fVn D-EmmC((( !- F Ft LL  f~!'FL+ABCSYYs^A->-D-D-FF6N g'PQ|399S>!+<SKKS1779E,1%L) g'_`KKr2::5"EMMcSVW]]_E+0< g'vwKKr2::5"EMMcSVW]]_E).u  I%?i)?#F6N"F6N vh/0x (q VG_q%8VH=MQR=R"6(#34vgFF8""6*{ ~ 
L012.
AB_ On D 	 ) M, !D !D !D E7vRsCDDEs   RP3C!RR3RP6(A P>(ARQ#Q Q#8Q	9BQ#QAQ#-Q;AQ#QBR6P;8R>Q RQ#	Q#QQ#QQ#Q Q#R Q##
R-R>RRRc                 p   U (       d  / $ U  Vs/ s H  oR                  S5      (       d  M  UPM     nnU(       d  / $ UR                  S S9  US   S   n[        R                  " 5       n[	        S U 5       5      nU(       d  / $ [        S[        U5       SUR                  S5       S	35        0 n/ nU H-  n [        U5      n	U	(       a  XU'   UR                  U	5        M-  M/     [        [	        U5      5      n[        R                  " 5       n
U(       aA   U[        S
S9-
  R                  S5      n[        R                  " X{SSS9nSU;   a  US   n
OUn
 [        R"                  " X4SS9n [%        U
[        R&                  5      (       a  U
R)                  US   S9n
U
R+                  USSS9R-                  5       n
/ n[.        R0                  " [2        5      n[.        R0                  " [        5      nU H+  nUS   R                  S5      nUU   R                  U5        M-     U GHI  nUR                  S5      nUU;   ar  UU    Hi  nUS   (       d  M  [5        US   5      nUS   S:X  a  UUS   ==   U-  ss'   M8  US   S:X  d  MC  UUS   ==   U-  ss'   UUS      S:  d  Ma  SUUS   '   Mk     SnUR7                  5        H  u  nnUS::  a  M  SnUR                  U5      n	U	(       aX  U
R8                  (       dG   XR:                  ;   a7  U
R<                  UU	4   n[        R>                  " U5      (       d  [3        U5      nUUU-  -  nM     UR                  U[A        US5      S .5        GML     U$ s  snf !    GM  = f! [          a  n[        SU 35         SnAGNKSnAff = f!    GN= f!    Nq= f)!z
Generates a daily portfolio value series.
Input: List of parsed transactions
Output: List of dicts [{"date": "YYYY-MM-DD", "value": 1234.56}, ...]
rN  c                     U S   $ r	  r   r  s    r    r  -calculate_portfolio_history.<locals>.<lambda>43  s    &	r!   r  r   c              3   B   #    U  H  oS    (       d  M  US    v   M     g7fr	  r   r	  s     r    r   .calculate_portfolio_history.<locals>.<genexpr>93  s     98ay	&	8s   z[DATA] Calculating history for r	  r  r   rg   r  FT)r  rc  r	  rd  z[ERROR] Price fetch error: Nr  r	  r  r9  r}  )r	  rC  r   rQ  r
  r	  r	  rz  gư>r  r
  )!rv   r	  r	   r  r  r3   rs   r  r   r  r  r  r  r
   rp   r  r2   r	  r  r  to_framereindexr	  collectionsr   r  r  r_   r  r  r  r  r  )rX  rx   valid_txr  r  isinsr	  r  r   r/  
price_datafetch_startr5   r6   full_idxportfolio_historyholdingstx_mapr	  current_dater  daily_totalrQ  r  r  s                            r    calculate_portfolio_historyrZ  '3  s     (9<a55=<H9BYMM)M*!V$J||~H 9899E)	+CJ<|JDWDWXbDcCddg
hi J	&t,C#&4  '', 	  C 012J	5%	q(99CCJOK;;/U\`aD $!']
!

 }}:#FHj")),,#,,2B12E,FJ  ''!'LRRT
 &&u-H $$T*F&	"":.uQ  !%%j1 F?E]y(!H+&V9%QvY'3.'vY&(QvY'3.'&	*Q.a60C # $NN,LD&!8E..&C:++000(nn\3->?!wws||$)#JE FUN+K# -& 	  ;*"
 	I !R W :0 	"  	5/s344	5 DR sN   M5M58'M:<N N ,AN) >AN1:N 
N&N!!N&)N.1N5c                  N   SSK n [        S5        U R                  S5          [        R	                  5          [        5       nUR                  5       nSU;   a  [        SUS   5        SU;   a  [        SUS   5        S	U;   a  [        S
US	   5        SU;   a  [        SUS   5        [        S[        R                  " 5       R                  S5       35        SSS5        U R                  S5        M  ! , (       d  f       N!= f! [         a  n[        SU 35         SnANASnAff = f)zSRefreshes market data every 30 s so the ticker tape and Vue Globale stay live 24/7.r   Nz:[NET] Background market refresh thread started (every 30s)r   r{  r?	  r   r@	  r  r  r  r  z[OK] Market cache refreshed at r9
  z)[ERROR] Background market refresh error: r   )r  r3   r  r)   r.   rL  r  r9   r	   r  r  r2   )_timer  r5   r6   s       r    background_market_refreshr]  3  s	   	
FG	KKO

	C")+113 D(o>RTXYfTg.hd?ondSZm.\$,o>OQUVgQh.i$o>NPTU^P_.`78O8OPZ8[7\]^ # 	B ""  	C=aSABB	Cs5   D BC1D 1
C?;D ?D 
D$DD$z0.0.0.0r;  )hostportdebuguse_reloader)r  )r}  r  )r7  r-
  i  r   )r   )g333333?)rg   )r  r  )r  r  r}  r  (W  r&  ior   flaskr   r   r   r   
flask_corsr   flask_sqlalchemyr   r   r  r  r	   r
   r   r  r   r   rQ  fpdfr   ImportErrorr3   r   r9  rQ  r   r|  yfinancerp   pandasr  numpyr  r   concurrent.futuresr   rO  r   r   difflibr   rn
  warningsr<  rK  rM  urllib.parser   urllib3.util.retryr   requests.adaptersr   r   xml.etree.ElementTreeetreeElementTreer  r   r  r  rr  logginghttp.serverr  r  email.utilsr   r  r  create_default_contextrH  r  
pdfplumberr   r
  CV2_AVAILABLEr  EASYOCR_AVAILABLEr
  YTDLP_AVAILABLEtransformersr"   r
  r
  r  r$   PLAYWRIGHT_AVAILABLEseleniumr%   !selenium.webdriver.chrome.optionsr&   r^  r]  filterwarningsr,   r0   r+   r7   r;   ro   rn   re   r|   r   r   r   r1   r   r   r   PDF_OUTPUT_FILEr   r   r   r   r  r)   r   r   r2   r6   r   after_requestr"  r  r$  r   r6  r@  rJ  rW  r_  r   rf  rl  ro  ry  r  r.   r
  r  r9   r/   r  r  r  r  r  r  environrv   r  r  r  
DATA_FILESr"  r  r  rq	  r7  rX  ri  rk  r   r  r  r  live_threadr  r  router6  r:  r<  r@  rJ  rL  r  r  r<  r>  r  r=	  rC	  rE	  rJ	  rL	  rN	  r[	  r_	  r]	  r^	  rn	  rs	  ry	  r	  r	  r	  r!
  r*
  r/
  r2
  r7
  rd
  rf
  rs
  r'  rw
  ry
  r{
  r
  r
  r
  r
  ry  rQ  r
  r
  r
  r
  r
  r
  r  r  r  r  r  r  r  r  rQ  rT  rk	  ro  r-  r  r  r	  r  r  r.  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r	  r  r  r  r  r  r2  r  r  r  r  r   r#  r)  r.  r;  r=  rA  rH  rK  rM  rT  r_  rc  re  rg  rj  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r"  r%  r-  r0  r=  rH  rM  rO  rS  rU  rW  r  r  r  r  r  r  r  serverSimpleHTTPRequestHandlerr  r  static_thread	getLoggersetLevelERROR	bg_thread	tr_threadloading_threadr  r   r  r"  rG  rZ  r]  r)
  r   r!   r    <module>r     s   
 	 	 4 4  '    2 2 	   >         1 * #         $ )  " "  
      ?  %%W]]_=-
$JMBCOL4!I3L"J& 	   ! 6  93 2>5p %&      D<)+ >D [.,()\  )3OP&1MN#.?@(3JK%0HI$-8PQ )4VW%0MN	 ) Ho,WCJJ()38CJJ/0 	/CJJ*+ 
CB	
23 SUY,-E J A288 AA A
" "	)rxx 	)C C
0288 
0!"(( !A A
Arxx A@288 @Arxx A"A AA A 	__MMO ^/D3=~ .D)V!/F0Y~ zz~~nb1@&
 7+)++1/.+)%%
(h hT7.zs sr	 .G&3lO  O h" 
	 -9x &6tD    {
 {
B %1: 2:8 /%AD BD .@
D A
D 1E7C	D D	D *UG<x+ =x+|f
 f
T| || %w7D 8D( )E7;ID <IDZU Un %w7D 8D< 1mD 2mD^ ug.
 /
 &2D 3D" vh/  0 D 0 1" !E73 4M` x0 1,M8A* x0 1 w// 0/2wtzxUpH ^ $ug6/ 7/. !E73	 4	 $vh7n 8n vh/% 0%. '%9CD :CDJ x0& 1& #fX63b 73br  <  2?6 ! 	23# 3#j*$B B&y	 y	x   R;$JW>~G:o ob6
	+ojekV 
J`
%VF$Z 0  2> 9.~H HT   R;$J &9/ :/" %x8. 9. '%9 :$ "VH5/ 6/$ =5'* + 3$" &8( 9(
 &9* :* ?UG,_/ -_/B "UG4@ 5@6	 %1) 2)D  $HTur  nn& 4n '&:D ;D( x0	D 1	D"%{   &w 	  &x	
 
  &w   &x   *6   ( 5<X   &y 
   &w 
1 1 1  h!  *1(!  >CH!" h#" */#$ m%& 
e'( i)( */	)* j+* */
+, '3 8c cJ '%9CD :CDL !E73"D 4"DJ (6(;]D <]D~ >E7+B ,B !F84D 5D*^L w/D 0D* =5'*1 +1f  5'2O 3Ob '%9 :>  5'2T 3Tl (5':, ;,\ '&: ;2 (6(;/ </6 !  5'27 37r %1 2 ?UG,/ -/  "VH5/ 6/ &2/ 3/ "VH5@/ 6@/N 1% &%%&	$( C.)> !E73Y/ 4Y/x eW- . fX./ //. $xj9	/ :	/ "VH5/ 6/B "UG4 52 '%9
 :
 '&:/ ;/)V "VH5
2 6
2 !F84S 5S &9T) :T)l
:@  5'2" 3" $ug6/ 7/,/*
:Z.x== 	Q z	&M	
,-	&M	
"#	
FG	
GH	
HI	
AB	
HI	
IJ	
LM	
GH	
AB	
JK	
JK	
IJ	
_`	
^_	
WX	
UV	&M	G  $$,B4PM j!**7==9  $  (?MIOO   (DTRIOO 

GH%%-FtTNeD e 	YY*UGY<zC =zCx=~ 
Zzun( z5dCIIKGGTGF }\  >D	
<=>`  -J	
+,-  $#$  J
CM	
HIJ  BG	
@AB  CFO	
ABC  LK"	
JKL  IO 	
GHI  LIM	
JK	Lh
  
	*1#
./# # 
B
h Rm  F  Es,  A@ 	A@ A@0 AA  AA #AA2 *AB 3AB$ <AB= .AAC =ADAD !AD) @A@@A@@A@-@,A@-@0	A@=@<A@=A AAAAAAAA/A.AA/A2ABBABBAB!B AB!B$AB:B9AB:B=ACCACCADCAD D ADD
ADDAD&D%AD&D)AD5D4AD5