
    ij@                       d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZ ddlmZmZ ddlmZ ddlmZmZ ddlZ ej0                         ZddlmZmZ dd	lmZ dd
lm Z   ed      Z!e!dz  dz  Z"e!dz  Z#e!dz  Z$e!dz  Z%e!dz  Z&e!dz  Z'dZ(dZ) e*ejV                  jY                  dd            Z-dZ.e!dz  Z/e/dz  Z0d Z1 e1        ejV                  jY                  dd      Z2ejV                  jY                  dd      Z3 e4h d      Z5 e d      Z6d  Z7drd!Z8d" Z9d# Z:d$ Z;d% Z<d& Z=d' Z>d( Z?d) Z@d* ZAd+ ZBd, ZCd- ZDd. ZEd/ ZFd0 ZGd1 ZHd2 ZId3 ZJd4 ZKdsd5ZLdtd6ZMd7 ZNd8 ZOd9d9d:d;hd<ZPd= ZQ e4h d>      ZRd?ZSd@ ZTdsdAZUdB ZVdC ZWdD ZXdE ZYdF ZZdG Z[ e* e\dH      j!                  dIdJdKddd e\dH      j"                  j                  L      j                         dMz        Z_dN Z`dO ZadP ZbdQ ZcdudRZddS Zeh dTZfdU ZgdV ZhdW ZidX ZjdY ZkdZ Zld[ Zmd\ Znd] Zod^ Zpd_ Zqdvd`ZrdvdaZsdwdbZtdwdcZudd Zvde ZwdxdfZxdydgZydzdhZzdi Z{dj Z|dk Z}dl Z~dm Z G dn doe      Zdp Zedqk(  r e        yy){u   

v2_stats_dashboard.py — Stats Dashboard 2° account (port 5511, Basic Auth)

NO template engine: tutto render server-side in Python (niente {{}} / {% %} nel template).

    N)BytesParser)defaultdatetimetimezone)Path)BaseHTTPRequestHandlerThreadingHTTPServer)urlparseparse_qs)defaultdict)ZoneInfoz /opt/charter-live/live_deploy_v2logszwebhook_queue.dbzv2_stats_trade_policy.json#v2_classification_review_queue.json!v2_classification_review_evidencez+v2_classification_certification_audit.jsonlv2_stats_policy_backupsi  P i  @ V2_STATS_PORT5511z0.0.0.0zv2_stats_dashboard.logc                  t   t         dz  } | j                         r	 | j                         j                         D ]  }|j	                         }|j                  d      sd|vr)|j                  dd      \  }}|j	                         }|j	                         j	                  d      j	                  d      }|dk(  r3t        j                  j                  d      s|t        j                  d<   |dk(  st        j                  j                  d      r|t        j                  d<    y y # t        $ r Y y w xY w)	Nz.v2_stats_creds#=   "'V2_STATS_USERV2_STATS_PASS)ROOTexists	read_text
splitlinesstrip
startswithsplitosenvironget	Exception)
creds_filelinekvs       U/opt/charter-live/backups/review_navigation_counts_20260917_120941/candidate/stats.py_load_auth_from_envfiler-   U   s    ))J	",,.99; 4zz|??3'3d?zz#q)1GGIGGIOOC(..s3'

0O23BJJ//)"**..2Q23BJJ/)4	 4  		s   CD+ 4D+ D+ +	D76D7r   mattia_v2_statsr    >   classifyexclude_testneeds_reviewexclude_operationalzEurope/Romec                 l   | yt        |       j                         }|sy|j                         rBt        |      dk\  r4	 t	        |      }t        j                  |dz  t        j                        S 	 t        j                  |j                  dd            S # t        $ r Y yw xY w# t        $ r Y yw xY w)zBybit V5 closed-pnl restituisce createdAt/updatedTime in MILLISECONDI come stringa

    (es. "1785856148609"). Accetta anche ISO 8601 ("2026-08-05T20:39:31Z") o None/"".

    Ritorna datetime (UTC) oppure None se non parsabile.

    N
        @@tzZ+00:00)strr!   isdigitlenintr   fromtimestampr   utcr'   fromisoformatreplace)tssmss      r,   _parse_bybit_tsrF      s     
zBA 	yy{s1v|	QB))"v+(,,GG%%aiiX&>??  		  s#   2B 3$B' 	B$#B$'	B32B3c                 @    t        |       }|y|j                  |      S )zTRitorna una stringa formattata (UTC) per ts Bybit (ms o ISO). None se non parsabile.r/   )rF   strftime)rC   fmtdts      r,   _fmt_bybit_tsrK      s%     
	B	z;;s    c                 f    t        |       }|y|j                  t              j                  d      S )Nz--z%d/%m/%Y %H:%M)rF   
astimezoneREVIEW_TIMEZONErH   )rC   rJ   s     r,   _fmt_review_tsrP      s/    		B	z==)223CDDrL   c                 p   t        j                  t        j                        j	                         j                         }d| d|  }t        |d       	 t        j                  dd       t        t        dd      5 }|j                  |d	z          d d d        y # 1 sw Y   y xY w# t        $ r Y y w xY w)
N[z] T)flushparentsexist_okautf-8encoding
)r   nowr   r@   rN   	isoformatprintLOG_DIRmkdiropenLOG_FILEwriter'   )msgrC   r)   fs       r,   logrf      s    	hll	#	.	.	0	:	:	<Brd"SE?D	$d
dT2(C'2 	!aGGD4K 	! 	! 	!  s0   )B) ?BB) B&"B) &B) )	B54B5c                      t         j                         sg S 	 t        j                  t         j	                  d            } t        | t              r| S g S # t        $ r}t        d|        g cY d }~S d }~ww xY w)N	utf-8-sigrY   zreview queue read err: )	REVIEW_QUEUE_PATHr   jsonloadsr   
isinstancelistr'   rf   )dataexcs     r,   _load_review_queuerp      sn    ##%	
zz+55{5KL!$-t525 %cU+,		s#   :A A 	A8A3-A83A8c                    t         j                  dt         j                   dt        j                  d       d      }	 |j                  t        j                  | dd      d       t        j                  |d	       t        j                  |t                |j                         r|j                  d
       yy# |j                         r|j                  d
       w w xY w)zBScrittura atomica: la coda non modifica mai la policy certificata..   .tmpF   ensure_asciiindentrX   rY     T
missing_okN)ri   	with_namenamesecrets	token_hex
write_textrj   dumpsr$   chmodrB   r   unlink)itemstmps     r,   _save_review_queuer     s     
%
%
""#1W%6%6q%9$:$?C(JJu5;	 	 	
 	e


3)* ::<JJ$J' 3::<JJ$J' s   AB< <%C!c                      t         j                         si S t        j                  t         j	                  d            } t        | t              st        d      | S )Nrh   rY   zPolicy statistiche non valida)STATS_POLICY_PATHr   rj   rk   r   rl   dict
ValueError)rn   s    r,   _load_raw_stats_trade_policyr   1  sK    ##%	::'11;1GHDdD!899KrL   c                    t         j                  dd       t        j                  t         d       t        j                         rxt        j                  t        j                        j                  d      }t         d| dz  }|j                  t        j                                t        j                  |d       t        j                  dt        j                   dt        j                   d	       d
      }	 |j#                  t%        j&                  | dd      d       t        j                  |d       t        j(                  |t               |j+                  d       y# |j+                  d       w xY w)z@Backup e sostituzione atomica. Non modifica DB webhook o ordini.TrT     z%Y%m%d_%H%M%S_%fv2_stats_trade_policy_z.jsonry   rr   rs   rt   Fru   rv   rX   rY   rz   N)STATS_POLICY_BACKUP_DIRr`   r$   r   r   r   r   r\   r   r@   rH   write_bytes
read_bytesr|   r}   r~   r   r   rj   r   rB   r   )rn   stampbackupr   s       r,   _save_raw_stats_trade_policyr   C  s    !!$!>HH$e,!X\\*334FG(-CE7%+PP,779:


%
%
""#1W%6%6q%9$:$?C
$tzz$U1EPWX
e


3)* 	

d
#

d
#s   <AE( (E<c                    t        |       } | j                  dt        j                  t        j
                        j                                t        j                  t        t              t        j                  t        j                  z  t        j                  z  d      }t        j                  |dd      5 }|j                  t!        j"                  | dd      d	z          d d d        y # 1 sw Y   y xY w)
N	timestampry   rW   rX   rY   F),:)rw   
separatorsr[   )r   
setdefaultr   r\   r   r@   r]   r$   ra   r;   CERTIFICATION_AUDIT_PATHO_WRONLYO_CREATO_APPENDfdopenrc   rj   r   )eventfdhandles      r,   _append_certification_auditr   k  s    KE	[(,,x||"<"F"F"HI	$%
bjj 2;;.
B 
2sW	- ZTZZEjQTXXYZ Z Zs   9+C--C6c                 @   | j                  d      rM|j                  dd      }t        |d      }|j                         D ci c]  \  }}||r|d   nd c}}d fS | j                  d	      st	        d
      t        t              j                  d| j                  dd      z   dz   |z         }|j                         st	        d      i }d }|j                         D ]  }	|	j                  dd      }
|
s|	j                  d      xs d}|	j                         }|r=|
dk7  s|t	        d      t        |      t        |	j                         xs d      |d}~|	j!                         xs d}|j                  |d      |t        |
      <    ||fS c c}}w )Nz!application/x-www-form-urlencodedrX   stricterrorsT)keep_blank_valuesr/   zmultipart/form-dataz Formato richiesta non supportato)policys   Content-Type: asciis   
MIME-Version: 1.0

zUpload multipart non validor}   zcontent-disposition)header)decoderL   evidence_filezAllegato non valido)original_namecontent_typern   )r"   r   r   r   r   r   email_policy
parsebytesencodeis_multipart
iter_parts	get_paramget_payloadget_filenamer;   get_content_typeget_content_charset)r   bodyrawvalueskeyvaluemessageform
attachmentpartr}   payloadfilenamecharsets                 r,   _parse_review_formr     s   BCkk'(k3#6BH,,.QJC%U2YR/QSWWW""#89;<< .99L///II
*	+-1	2G !677 DJ""$  G~~f-B~C""$"/63$$&&**@ !677 "%X #D$9$9$;$Ar BJ ..0;GG%nnWXnFDTOA GD y Rs   Fc                 l   | r| j                  d      sy | d   }t        |      t        kD  rt        d      |j	                  d      rd\  }}nF|j	                  d      rd\  }}n/t        |      dk\  r|d d d	k(  r|d
d dk(  rd\  }}nt        d      t        | j                  d      xs d      j                         }||dfvrt        d      t        t        | j                  d      xs d            j                  d d ||t        |      t        j                  |      j                         |dS )Nrn   z&Screenshot troppo grande: massimo 4 MBs   PNG

)	image/png.pngs   )
image/jpeg.jpg      s   RIFF   s   WEBP)
image/webp.webpz4Formato screenshot non valido: usare PNG, JPG o WEBPr   r/   zapplication/octet-streamz;Il tipo dichiarato dello screenshot non corrisponde al filer   
screenshot   )r   r   	extensionsizesha256rn   )r&   r=   MAX_EVIDENCE_BYTESr   r"   r;   lowerr   r}   hashlibr   	hexdigest)r   rn   detected_typer   declared_types        r,   _validate_review_attachmentr     s6   Z^^F3fD
4y%%ABB+,#6 y		)#7 y	TbT"1X0T!BZ75J#8 y OPP
~6<"=CCEM],FGGVWW c*.."A"Q\RSXXY]Z]^%D	..&002 rL   c                 X   t         j                  dd       t        j                  t         d       |  |d    }t         |z  }t        j                  t        |      t        j                  t        j                  z  t        j                  z  d      }	 t        j                  |d      5 }|j                  |d          d d d        |j                         D ci c]  \  }}|dk7  s|| }}}||d	<   ||fS # 1 sw Y   ;xY w# t        $ r |j                  d        w xY wc c}}w )
NTrT   r   r   ry   wbrn   rz   stored_name)REVIEW_EVIDENCE_DIRr`   r$   r   ra   r;   r   r   O_EXCLr   rc   r'   r   r   )	proposal_idr   r   targetr   r   r   r   metadatas	            r,   _save_review_attachmentr     s   dT:HH %( M*["9!:;K ;.F	VbkkBJJ6BE	JB
YYr4  	-FLLF+,	- .8-=-=-?QzsE3&=U
QHQ)H]V	- 	-  &	 Rs0   D +C: D D&)D&:D?D D#c                  8   t               D  ch c]  } | j                  d      dk(  rl| j                  d      dk(  rXt        | j                  d      xs d      j                         r,t        | j                  d      xs d      j                          c} S c c} w )Nstatuspendingactioncertification_rejectedorder_idr/   rp   r&   r;   r!   items    r,   _rejected_order_idsr   %  s     '(	 88H*HHX"::$*+113 	DHHZ &B'--/  s   BBc                    t        t              }| j                  di       j                  |g       D ]2  }t        |j                  d            }|t        v s&||xx   dz  cc<   4 t        t        |j                         d             S )Nasset_trade_detailsstrategyr   c                     | d    | d   fS )Nr   r    r   s    r,   <lambda>z._strategy_history_for_symbol.<locals>.<lambda>E  s    $q'478K rL   r   )r   r>   r&   _canonical_strategyVALID_CLOSED_TRADE_STRATEGIESr   sortedr   )rn   symbolcountsrowr   s        r,   _strategy_history_for_symbolr   9  s{    Fxx-r266vrB "&swwz':;448!" v||~+KLMMrL   c                      t               D  ch c]V  } | j                  d      dk(  r@| j                  d      dk(  r,t        | j                  d      xs d      j                         X c} S c c} w )zDCurrent cases cleared by the operator; new order IDs remain visible.r   archivedr   clear_reviewr   r/   r   r   s    r,   _archived_review_order_idsr  K  sg     '(	
 88H+HHX.0 	DHHZ &B'--/
 
 
s   AA+c           
         t               }t               }g }| j                  dg       D ]  }t        |j                  d      xs d      j	                         }|r||v s||v r;t        |      }t        |j                  d      xs d      j                         }t        | |      }t        t        |            }	d}
d}g }|rt        t        |            }
t        |j                               }||
   }t        |      dk(  r
|	|
k(  rdnd}n||d	z  kD  rd}nd}|j                  d
dj!                  d |j#                         D              z          |	t$        v rA|j                  d|	j                                 |
s|	}
d}n|	|
k7  rd}|j                  d       |
s|j                  d       |j'                  d|
|dj!                  |      t)        |      d       |j                  |        |S )z2Genera suggerimenti, mai attribuzioni automatiche.unclassified_tradesr   r/   r   LOWr   HIGHMEDIUMru   zstorico asset: , c              3   L   K   | ]  \  }}|j                          d |   yw)r   Nupper).0r}   counts      r,   	<genexpr>z,_certification_candidates.<locals>.<genexpr>  s*      9.9dE4::<.%)9s   "$zconfig attuale: zconflitto storico/configz.nessuna prova storica o configurazione univocaPENDING_CERTIFICATIONz; )anomaly_typeproposed_strategyproposal_confidenceproposal_evidenceproposal_alternatives)r   r  r&   r;   r!   r   r  r   r   get_strategy_for_symbolnextitersumr   r=   appendjoinr   r   updaterm   )rn   rejectedr   
candidatesr   r   r   r   history
configuredproposed
confidencereasonstotal	top_counts                  r,   _certification_candidatesr%  _  s    #$H)+HJxx-r2 R swwz*0b17798x/8x3GCyTXXh'-2.446.tV<()@)HI

DM*H()E)I7|q '1X'=V8
UQY&%
 #
NN,tyy 9=D]]_9 0   66NN-j.>.>.@-ABC%%
x'"
9:NNKL3!)#-!%7!3%)']
 	 	$eR h rL   c                    t               }t               }g }| j                  dg       D ]\  }t        |j                  d      xs d      j	                         }|s2||v s7||vs<t        |      }d|d<   |j                  |       ^ |S )zESolo casi rifiutati: i nuovi trade restano nella coda certificazioni.r  r   r/   PROPOSTA_RIFIUTATAr  )r   r  r&   r;   r!   r   r  )rn   r  r   r  r   r   r   s          r,   _review_candidatesr(    s     #$H)+HJxx-r2 
$swwz*0b1779H,1I9D#7D d#
$ rL   c                     t        |xs d      j                         }| j                  dg       D ]5  }t        |j                  d      xs d      j                         |k(  s3|c S  t        d      )Nr/   r  r   z1Trade non presente tra le classificazioni sospese)r;   r!   r&   r   )rn   r   r   s      r,   _current_unclassifiedr*    sk    8>r"((*Hxx-r2 swwz"(b)//1X=J	 H
IIrL   c                     t        j                  t        j                        j	                         }| D ]6  }|j                  d      dk(  s|j                  d      |k(  s-||d<   ||d<   8 | S )Nr   r   r   resolved_at)r   r\   r   r@   r]   r&   )queuer   r   r\   r   s        r,   _resolve_queue_for_orderr.    sg    
,,x||
$
.
.
0C &88H*txx
/Cx/O#DN"%D& LrL   c                   
 t        | j                  d      xs d      j                         
t        | j                  d            }|t        vrt        d      t        |
      }t        
fdt        |      D        d       }|t        d      t               }|j                  di       }|j                  di       }t        |j                  
            }|r||k7  rt        d	      ||
<   d
|
<   t        |       t        t               
d      }	t        |	       t        dt         
|j                  dd      |j                  dd      ||j                  dd      |j                  dd      d       t#        d
 d|        y )Nr   r/   r   #Strategia obbligatoria o non validac              3   L   K   | ]  }|j                  d       k(  s|  ywr   Nr&   r  r   r   s     r,   r  z!_certify_trade.<locals>.<genexpr>  "     [377:;NRZ;Z[   $$z*Caso gia rifiutato o non piu certificabilestrategy_by_closed_order_id(classification_source_by_closed_order_idz.Order ID gia certificato con strategia diversa!operator_certified_from_dashboard	certified	CERTIFIEDr   r  r  r  )r   operatorr   r   r  chosen_strategyr!  evidenceztrade certified order=
 strategy=)r;   r&   r!   r   r   r   r*  r  r%  r   r   r   r.  rp   r   r   	AUTH_USERrf   )r   rn   r   tradeproposalr   mappingsourcesexistingr-  r   s             @r,   _certify_traderF    s   488J'-2.446H"488J#78H44>??!$1E[1$7[	H EFF)+F =rBG JBOG"7;;x#89HH(IJJ GH;GH ($%7%98[QEu))Hb)%\\*=rB#ll#8"=LL!4b9!! ( 
 
*XJ?@rL   c                 ~   t        | j                  d      xs d      j                         t        |      }t	               v rt        d      t        fdt        |      D        d       xs i }t               }|j                  dt        j                  t        j                        j                  d       dt        j                   d       t        j                  t        j                        j#                         d	d
dd|j                  dd      dt%        |      |j                  dd      |j                  dd      |j                  dd      dd       t'        |       t)        dt*        |j                  dd      |j                  dd      |j                  dd      d       t-        d        y )Nr   r/   z!Trade gia presente nelle anomaliec              3   L   K   | ]  }|j                  d       k(  s|  ywr2  r3  r4  s     r,   r  z(_reject_certification.<locals>.<genexpr>U  r5  r6  zreject-%Y%m%d%H%M%S-r   r   r   PROPOSTA_RIFIUTATA_DA_OPERATOREr  z'Da approfondire nella gestione anomalier  r  )r   r!  r>  )r   
created_atr   r   r   reasonr>  notesr   trade_snapshotproposal_snapshotREJECTED_TO_ANOMALYr   )r   r<  r   r   r  r!  z trade rejected to anomaly order=)r;   r&   r!   r*  r   r   r  r%  rp   r  r   r\   r   r@   rH   r~   r   r]   r   r   r   r@  rf   )r   rn   rA  rB  r-  r   s        @r,   _reject_certificationrR  I  s   488J'-2.446H!$1E&((<==[1$7[	  
   E	LL hll!;!D!D^!T UUVW^WhWhijWkVlmll8<<0::<*3LL!4b9:u+ !%8"=",,'<bA %8"=
-   D u&))Hb)%\\*=rBll#8"=!   
*8*56rL   c                    t        | j                  d      xs d      j                         t        | j                  d      xs d      j                         j                         t	        | j                  d            }t        | j                  d      xs d      j                         }t        | j                  d      xs d      j                         }t        | j                  d      xs d      j                         }t        |      D ci c]  }t        |j                  d            | }}|j                        }	|	t        d      t        vrt        d	      d
k(  r|t        vrt        d      d
k7  rd}|st        d      t        |      }
|s|
t        d      t               }t        fd|D              rt        d      dt        j                  t        j                        j!                  d       dt#        j$                  d       }|t        j                  t        j                        j'                         d|||||	j                  dd      |	j                  dd      |	j                  dd      |	j                  d|	j                  dd            |	j                  d|	j                  dd            |	j                  dd      |	j                  dd      |	j                  dd      |	j                  d |	j                  d!d            |	j                  d"d      |	j                  d#d      d$d%
}d }	 |
t)        ||
      \  }}||d&<   |j+                  |       t-        |       t3        d)|d*    d+ d, d-|xs d        |S c c}w # t.        $ r ||j1                  d'(        w xY w).Nr   r/   r   r   rM  r>  rN  z*Caso non presente tra le anomalie correntizAzione non validar0   r0  zMotivo obbligatorioz:Inserire una prova testuale oppure allegare uno screenshotc              3      K   | ]D  }|j                  d       dk(  xr* |j                  d      k(  xr |j                  d      k(   F yw)r   r   r   r   Nr3  )r  r   r   r   s     r,   r  z*_create_review_proposal.<locals>.<genexpr>  s\      
  	i' 	)HHZ H,	) HHX&(		)
s   A
Az:Esiste gia una proposta pendente identica per questo tradezreview-rI  rJ  r   r   r  r   sideclosed_sizeqtyr   avg_entry_priceentry_price
entry_timerL  
updated_atpnl_netpnlclassification_sourceoperational_reason)r  r   rU  rV  rX  rZ  rL  r[  r\  r^  r_  )
r   rL  r   r   r   rM  r>  rN  r   rO  evidence_attachmentTrz   zreview proposal saved id=r   z order=z action=r?  )r;   r&   r!   r   r   r(  r   REVIEW_ACTIONSr   r   rp   anyr   r\   r   r@   rH   r~   r   r]   r   r  r   r'   r   rf   )r   rn   r   r   rM  r>  rN  r   r  rA  validated_attachmentr-  r   rB  attachment_pathr   r   r   s                   @@r,   _create_review_proposalre    s   488J'-2.446H(#)r*00288:F"488J#78H(#)r*002F488J'-2.446H!'R(..0E <Nd;STC#cggj)*C/TJTNN8$E}EFF^#,--0M M>??.//6zB,4UVV  E
 
 
 
 UVV HLL6??OPPQRYRcRcdeRfQghK #ll8<<0::< "IInb9ii"-IIfb) 99]EIIeQ4GH$yy):EIImUV<WX))L"5))L"5))L"5yyEIIeQ,?@%*YY/F%K"')),@""E-
).H` O+(?Ma(b%Ho.6H*+X5! 
#H]$;#<GH: NHO#4	6 OE Ud  &""d"3s   "N!2N& &Oc                    d  t        |      j                  d      r|nd      }t        |       }t        |       }t	               }|D cg c]  }|j                  d      dk(  s| }	}d fd	dj                  fd|D              xs d}
dj                  fd	|D              }dj                  fd
|D              xs d}dj                  fdt        |	      D              xs d}|rd |       dnd}|rd |       dnd}|sdnd}d| d| | dt        |       d|
 dt        |       d| d| d| d| d         d| dt        |	       d| dS c c}w )!Nc                 J    t        j                  t        | | nd      d      S )Nr/   Tquote)htmlescaper;   r   s    r,   r   z)render_review_dashboard.<locals>.<lambda>1  s    C1B$KSWX rL   /r   r   r/   c                 V     dj                   fdt        t              D              S )Nr/   c           
   3   x   K   | ]1  }d  |       d|k(  rdnd d |j                                d 3 yw)z<option value='r   z	 selectedr/   >z	</option>Nr
  )r  r   escselecteds     r,   r  zDrender_review_dashboard.<locals>.strategy_options.<locals>.<genexpr>?  sP      
 	 c(m_AX=QkWY-ZZ[8>>#$%Y0
s   7:)r  r   r   )rr  rq  s   `r,   strategy_optionsz1render_review_dashboard.<locals>.strategy_options=  s)    ww 
 ##@A
 
 	
rL   c              3     K   | ]G  }d j                   t        |j                  d                   |j                  dd             |j                  dd             |j                  d|j                  dd                   t        |j                  d|j                  d	d                        d
z    |j                  dd             t	        |j                  dd            j                                |j                  dd             |j                  dd             |j                  dd            
       J yw)a-  <tr><td>{closed}</td><td><b>{symbol}</b></td><td>{side}</td><td>{qty}</td><td>{pnl}</td><td><span class='confidence {confidence_class}'>{confidence}</span></td><td>{evidence}</td><td><form class='inline certify-form' method='post'><input type='hidden' name='order_id' value='{order}'><select name='strategy' required>{options}</select><button type='submit'>Certifica</button></form><form class='inline reject-form' method='post'><input type='hidden' name='order_id' value='{order}'><button class='danger' type='submit'>No, anomalia</button></form></td></tr>r[  r   r/   rU  rV  rW  r   r\  r]  z USDTr  r  r  r   r  )
closedr   rU  rW  r]  r!  confidence_classr>  orderoptionsN)formatrP   r&   	_fmt_usdtr;   r   )r  r   rq  rs  s     r,   r  z*render_review_dashboard.<locals>.<genexpr>I  s-     *!P M	V W]V\~cggl&;<=swwx,-SWWVR()CGGM3775!+<=>Icggi1BCDEO377#8%@A SWW-BE%J!K!Q!Q!ST!4b9:cggj"-.$SWW-@"%EF) W] W
$	
*!s   EEzH<tr><td colspan='8' class='muted'>Nessun trade da certificare.</td></tr>c              3   X  K   | ]  }d j                   |j                  dd             |j                  dd             |j                  dd             |j                  dd             t        |j                  d|j                  dd                        	        y
w)zR<option value='{order}'>{kind} | {symbol} | {side} | {order} | {pnl} USDT</option>r   r/   r  r   rU  r\  r]  r   )rw  kindr   rU  r]  N)ry  r&   rz  r  r   rq  s     r,   r  z*render_review_dashboard.<locals>.<genexpr>u  s          	]cccggj"-.SWW^R01swwx,-SWWVR()Icggi1BCDE 	d 	
 s   B'B*c              3     K   | ]A  }d j                   |j                  dd             |j                  dd             |j                  dd             |j                  d|j                  dd                   |j                  d|j                  d	d                   t        |j                  d
      xs |j                  d                   t        |j                  d                   |j                  dd             t        |j                  d|j                  dd                        	       D yw)z<tr><td>{kind}</td><td>{symbol}</td><td>{side}</td><td>{qty}</td><td>{entry}</td><td>{opened}</td><td>{closed}</td><td class='mono'>{order}</td><td>{pnl}</td></tr>r  r/   r   rU  rV  rW  r   rX  rY  rZ  rL  r[  r   r\  r]  )	r|  r   rU  rW  entryopenedru  rw  r]  N)ry  r&   rP   rz  r}  s     r,   r  z*render_review_dashboard.<locals>.<genexpr>  s     8 5	; <B6SWW^R01swwx,-SWWVR()CGGM3775!+<=>cgg/1JKL~cggl&;&Tsww|?TUV~cggl&;<=cggj"-.Icggi1BCDE% <B <
		
s   EEzI<tr><td colspan='9' class='muted'>Nessun caso anomalo corrente.</td></tr>c              3     K   | ]:  }d j                   |j                  dd             |j                  dd             |j                  dd             |j                  dd             |j                  di       j                  dd             |j                  dd             |j                  d	d             |j                  d
d            |j                  di       j                  d      r8dj                   |j                  di       j                  dd                  ndz          = yw)z<tr><td>{created}</td><td>{status}</td><td>{action}</td><td>{strategy}</td><td>{symbol}</td><td class='mono'>{order}</td><td>{reason}</td><td>{evidence}</td></tr>rL  r/   r   r   r   rO  r   r   rM  r>  r`  r   zm<br><a class='evidence-link' href='review/evidence/{name}' target='_blank' rel='noopener'>Apri screenshot</a>)r}   )createdr   r   r   r   rw  rM  r>  N)ry  r&   )r  r   rq  s     r,   r  z*render_review_dashboard.<locals>.<genexpr>  sE     *P M	bbhbhr23txx"-.txx"-.*b12txx 0"599(BGHdhhz2./txx"-. DHHZ,- xx 5r:>>}M D  K  K *?!D!H!HXZ![\ K  TV% ci "c
$	
*s   EEzH<tr><td colspan='8' class='muted'>Nessuna proposta registrata.</td></tr>z<div class='ok'></div>z<div class='err'>z	 disabledaU  <!doctype html>

<html lang='it'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>

<title>V2 Certificazioni e anomalie</title><style>

body{margin:0;background:#0d1117;color:#e6edf3;font-family:Arial,sans-serif}main{max-width:1500px;margin:auto;padding:20px}

h1{color:#58a6ff;font-size:25px}h2{font-size:17px;margin-top:0}.bar{display:flex;gap:10px;align-items:center;justify-content:space-between}

.panel{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:16px;margin:14px 0}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}

label{display:block;color:#9fb3c8;font-size:12px;margin-bottom:5px}input,select,textarea{width:100%;box-sizing:border-box;background:#0d1117;color:#e6edf3;border:1px solid #3d4856;border-radius:4px;padding:9px}

textarea{min-height:76px;resize:vertical}button,.btn{display:inline-flex;align-items:center;background:#238636;color:white;border:0;border-radius:4px;padding:9px 13px;text-decoration:none;font-weight:700;cursor:pointer}button:disabled{opacity:.45;cursor:not-allowed}.btn.secondary{background:#1f6feb}

button.danger{background:#da3633}.inline{display:inline-flex;gap:6px;align-items:center;margin:2px 5px 2px 0}.inline select{width:190px}

.confidence{font-weight:700;padding:4px 7px;border-radius:4px}.confidence.high{background:#173c24;color:#56d364}.confidence.medium{background:#3b2e0b;color:#e3b341}.confidence.low{background:#3d1618;color:#ff7b72}

table{width:100%;border-collapse:collapse;font-size:12px}th,td{padding:8px;border-bottom:1px solid #30363d;text-align:left;vertical-align:top}th{color:#8fb2d9}.mono{font-family:Consolas,monospace;word-break:break-all}.muted{color:#8b949e}.ok{padding:10px;border:1px solid #2ea043;background:#102819;color:#56d364}.err{padding:10px;border:1px solid #f85149;background:#351315;color:#ff7b72}.notice{color:#d29922;font-size:13px}

@media(max-width:800px){.grid{grid-template-columns:1fr}.scroll{overflow:auto}}

</style></head><body><main>

<div class='bar'><h1>V2 Certificazioni e anomalie</h1><a id='mainDashboardLink' class='btn secondary' href='z'>Torna alla dashboard principale</a></div>

<p class='notice'>Il sistema propone l'abbinamento. Solo Certifica aggiorna la policy e i KPI; No sposta il caso nelle anomalie. Nessun effetto su ordini o posizioni.</p>

z-

<section class='panel'><h2>Da certificare (z)</h2><div class='scroll'><table><thead><tr><th>Chiusura</th><th>Asset</th><th>Side</th><th>Qty</th><th>Net</th><th>Confidenza</th><th>Prova proposta</th><th>Decisione</th></tr></thead><tbody>zM</tbody></table></div></section>

<section class='panel'><h2>Anomalie reali (z)</h2><div class='scroll'><table><thead><tr><th>Tipo</th><th>Asset</th><th>Side</th><th>Qty</th><th>Entry</th><th>Apertura (Roma)</th><th>Chiusura (Roma)</th><th>Order ID</th><th>Net</th></tr></thead><tbody>z</tbody></table></div></section>

<section class='panel'><h2>Risoluzione manuale anomalia</h2><form id='proposalForm' method='post' enctype='multipart/form-data'>

<div class='grid'><div><label>Caso anomalo</label><select name='order_id' requiredrp  zI</select></div>

<div><label>Azione</label><select name='action' requiredat  ><option value='classify'>Abbina a strategia</option><option value='exclude_test'>Escludi: test</option><option value='exclude_operational'>Escludi: anomalia operativa</option><option value='needs_review'>Richiede verifica</option></select></div>

<div><label>Strategia (obbligatoria solo per abbinamento)</label><select name='strategy'><option value=''>Seleziona</option>aA  </select></div>

<div><label>Motivo</label><input name='reason' maxlength='240' required placeholder='Motivo della decisione'></div>

<div><label>Prova / fonte testuale</label><input name='evidence' maxlength='500' placeholder='Alert TV, order ID, log, verifica manuale'></div>

<div><label>Screenshot (PNG, JPG o WEBP; massimo 4 MB)</label><input type='file' name='evidence_file' accept='image/png,image/jpeg,image/webp'></div>

<div><label>Note</label><textarea name='notes' maxlength='1200' placeholder='Dettagli aggiuntivi'></textarea></div></div>

<p><button type='submit'zu>Registra proposta</button></p></form></section>

<section class='panel'><div class='bar'><h2>Proposte da risolvere (aA  )</h2><a id='exportLink' class='btn secondary' href='export.json' download='v2_classification_review_queue.json'>Esporta audit JSON</a></div><div class='scroll'><table><thead><tr><th>Creata</th><th>Stato</th><th>Azione</th><th>Strategia</th><th>Asset</th><th>Order ID</th><th>Motivo</th><th>Prova</th></tr></thead><tbody>a  </tbody></table></div></section>

<script>

const p=location.pathname.replace(/\/$/,'');

document.getElementById('proposalForm').action=p+'/proposals';

document.querySelectorAll('.certify-form').forEach((form)=>form.action=p+'/certify');

document.querySelectorAll('.reject-form').forEach((form)=>form.action=p+'/reject');

document.getElementById('exportLink').href=p+'/export.json';


</script></main></body></html>)r/   )	r;   r"   r%  r(  rp   r&   r  reversedr=   )rn   r   errormain_urlsafe_main_urlcertifications	anomaliesr-  r   pending_queuecertification_rowscandidate_optionsanomaly_rows
queue_rowsmessage_html
error_htmldisabledrq  rs  s                    @@r,   render_review_dashboardr  /  sU   
XCCM$<$<S$AsKM.t4N"4(I E&+Odtxx/AY/NTOMO

  *!P "Q*! * *TT 
TU X     !  ( 77 8 9  U< 
U= @  *P ]+Q* * *TT 
TU X ?F%c'l^6:2L;@$SZL7bJ"+{Hm4 n{l{ | zl ,,/,?+@  AA  BT  AU U,,/	N+;  <K  LX  KY YS T\R\\]^o]p q99A
 C} ~N  ~P  }Q 
Q "
 #DDGDVCW  XY  Zd  Ye emE" E"A Ps   E$(E$c                      	 t         j                  j                  dt        t                     ddlm}   |        }|j                         S # t        $ r}t        d|        g cY d }~S d }~ww xY w)Nr   BybitDemoClientzbybit positions err: )
syspathinsertr;   r   bybit_demo_clientr  fetch_positionsr'   rf   )r  ces      r,   get_bybit_positionsr  (  s\    3t9%5  "" #A3'(		s   A	A 	A/A*$A/*A/c                  ,   	 t         j                  j                  dt        t                     ddlm}   |        }|j                  ddddid      }|d	   d
   d   d   d   }t        |d         S # t        $ r}t        d|        Y d }~yd }~ww xY w)Nr   r  GETz/v5/account/wallet-balanceaccountTypeUNIFIEDTsignedresultrm   coinwalletBalancezbybit balance err:         )r  r  r  r;   r   r  r  _requestfloatr'   rf   )r  r  br  r  s        r,   get_bybit_balancer  >  s    3t9%5JJu:%y1$  @ {6"1%f-a0T/*++ !!%&	s   A/A2 2	B;BBT))VIRTUALUSDT     p@)NEARUSDT33333@r  )symbols_qtysymbolsc                     t        | xs d      j                         j                         }|j                  d      r|d d }|j                  d      rdddddddd	d	d
dddd}|j	                  ||      S )Nr/   _closeivptr3
rettangolorettangolo_simplersi_swing_breakoutma_trailing	range_fibadxsupertrend_boswmanuale)vptr_v3rettangolo_v2rettangolo_tv_simplerett_simplezrettangolo semplicezrsi swing breakoutzma trailingrangez	range fibadx_dmi_bb_volzsupertrend extensionszsupertrend boswmanual)r;   r!   r   endswithr&   )r   r   aliasess      r,   r   r   t  s    	rN  "((*E
..
"cr
 ..
" % 3*22$ !2,5G< ;;ue$$rL   >
   r  sqwr  r  r  r  r  r  r  r  unclassifiedc                     t               i g g i g i d} t        j                         s| S 	 t        j                  t        j                  d            }|j                  dg       D ch c]4  }t        |      j                         rt        |      j                         6 }}|j                  di       j                         D ci c]L  \  }}t        |      j                         r.t        |      r#t        |      j                         t        |      N }}}i }|j                  di       }t        |t              ry|j                         D ]f  \  }}	t        |xs d      j                         }|s&t        |	t              rt        |	      ||<   Edt        |	xs d      j                         i||<   h i }
|j                  d	i       j                         D ]  \  }}	t        |xs d      j                         j                         }|rt        |	t              sDt        |	j                  d
      xs d      j                         }t        |      t        d|        |t        |	j                  d      xs d      j                         dd|
|<    |||j                  dg       D cg c]  }t        |t              r| c}|j                  dg       D cg c]  }t        |t              r| c}||j                  dg       D cg c]4  }t        |t              r"t        |j                  d            t         v r|6 c}|
dS c c}w c c}}w c c}w c c}w c c}w # t"        $ r}t        d|        | cY d}~S d}~ww xY w)zBRegole storiche per orderId. Non modifica il DB operativo webhook.)excluded_closed_order_ids%operational_excluded_closed_order_idsexcluded_trade_fingerprints'operational_excluded_trade_fingerprintsr7  strategy_by_trade_fingerprintblocked_assetsrh   rY   r  r7  r  r/   rM  r  effective_fromNz9blocked asset policy ignored: invalid effective_from for blocked_assetnew_entries)r  rM  scoper  r  r  r   zstats trade policy err: )setr   r   rj   rk   r   r&   r;   r!   r   r   rl   r   r  rF   rf   r   r'   )emptyrn   r   excludedr   r   rC  operational_by_order_idraw_operational_idsruler  r   r  r   ro   s                  r,   _load_stats_trade_policyr    s}    &)U13')35'))+E$ ##%tzz+55{5KL "=rB	
 5z!	 J
 
 '+hh/Lb&Q&W&W&Y	
 #(8}""$)<X)F	 M!#6x#@@
 
 #%"hh'NPRS)40"5";";"= \$x~2.446dD)8<T
+H5 :B3tzr?CXCXCZ8[+H5\   HH%5r:@@B 	LFD2&,,.446FD$!7 *:!;!ArBHHJN~.6OPVxXY #1dhhx0CODJJL&&N6"!	8 *25L "&*G!L,dD) , "&*SUW!X8dD) 8 ,3 "&*I2!N.dD)'(<=A^^	 . -E$
 $	
M

D,8.  &se,-	sa   =M% '9M %M% AMFM% -MM% M
5M% 9M M% M% %	N.N=NNc                 
   	 t        |       } t        |      }|dvr	 t        t        |            }nt	        dt        |      dz        }t        | |z
        |k  S # t        t        f$ r Y yw xY w# t        t        f$ r Y yw xY w)NFNr/   :0yE>ư>)r  	TypeErrorr   absmax)actualexpectedexplicit_tolerance	tolerances       r,   _fingerprint_float_equalr  R  s    v? +	E"456I c(md23	v !Y..% z"  :& 		s"   A A0 A-,A-0BBc                    d}t        fd|D              ryt        | j                  d      xs d      j                         j	                         t        d         j                         j	                         k7  ryt        | j                  d      xs d      j                         j	                         t        d         j                         j	                         k7  ryt        | j                  d      d         syt        | j                  d	      d
   j                  d            syj                  d      dvrt        | j                  d      d         syj                  d      dvr/t        | j                  d      d   j                  d            syj                  d      sj                  d      r	 t        t        | j                  d      xs | j                  d      xs d            }|syj                  d      rQt        t        j                  t        d         j                  dd            j                         dz        }||k  ryj                  d      rQt        t        j                  t        d         j                  dd            j                         dz        }||kD  ryyy# t        t        t        f$ r Y yw xY w)zLConfronta l'intero trade. Non consente mai una regola basata sul solo asset.)r   rU  rV  rX  c              3   D   K   | ]  }j                  |      d v   yw)r  Nr3  )r  r   fingerprints     r,   r  z-_matches_trade_fingerprint.<locals>.<genexpr>x  s     
B#;??3:-
Bs    Fr   r/   rU  
closedSizerV  avgEntryPricerX  avg_entry_price_toleranceavg_exit_pricer  avgExitPrice
closed_pnl	closedPnlclosed_pnl_toleranceclosed_at_fromclosed_at_toupdatedTime	createdAtr   r9   r:     T)rb  r;   r&   r!   r  r  r>   r  r   rA   rB   r   r  r   OverflowError)closed_itemr  required	closed_msstart_msend_mss    `    r,   _matches_trade_fingerprintr  r  s    DH

B
BB
;??8$*+11399;sH@ egeeg	 
;??6"(b)//1779SF> egeeg	 #%{='A #(%&34 '(
:C['5E)FD |$J6?W$L!./@ '(KOON,K*	E+//-"@"eKOOT_D`"edefgI/0**K(89:BB3Q  ikD	) x' ~.**K78@@hO  ikD	) v%  	 :}5 		s    <K A!K *A!K K%$K%c                 F    |D cg c]  }t        | |      s| c}S c c}w N)r  )r  fingerprintsr   s      r,   _matching_fingerprintsr     s!    )[T-GUY-ZD[[[s   c                    | rt         j                         syd}	 t        j                  t               }|j	                  dt        |       f      j                         }|r|d   rt        |d         nd	 ||j                          S S # t        $ r.}t        d|  d|        Y d}~||j                          yyd}~ww xY w# ||j                          w w xY w)z@Usa esclusivamente la strategia registrata sullo stesso orderId.r/   NzGSELECT strategy FROM orders WHERE order_id = ? ORDER BY id DESC LIMIT 1r   z"strategy order lookup err orderId=: )DB_PATHr   sqlite3connectexecuter;   fetchoner   closer'   rf   )r   connr   ro   s       r,   _strategy_from_order_dbr
    s     7>>+Dw'llU]	
 (* 	 /2c!f"3q6*"D JJL   0
"SEBC JJL  JJL s*   AB	 		C B;#C ;C  C Cc                    t        | xs d      j                         } | st        dfS t        |j	                  |             }|t
        v r|dfS t        t        |             }|t
        v r|dfS |s|rt        dfS t        dfS )zFClassifica solo con prova univoca per orderId, mai in base al simbolo.r/   missing_order_idcertified_order_idexact_order_id_dbinvalid_strategy_for_order_idorder_id_not_registered)r;   r!   UNCLASSIFIED_STRATEGYr   r&   r   r
  )r   certified_mappingr:  recordeds       r,   _strict_closed_trade_strategyr    s     8>r"((*H$&888 $$5$9$9($CDI11... ##:8#DEH00,,, H$&EEE ";;;rL   c           
      t   t        | j                  d      xs d      j                         }|rd}	 t        j                  dt
         dd      }t        j                  |_        |j                  d      j                         }|r!|j                  d	|f      j                         nd}	 ||j                          	 |t        | j                  d      xs d      j                         j                         }t        | j                  d      xs d      j                         j                         }|dk(  rdn|dk(  rdnd}	 t        t        | j                  d      xs d            }	t        | j                  d      xs d      }
t        t        |d   xs d            }t        |d   xs d      }t%        |d         }t'        |d         }t        |d   xs d      j                         j                         |k(  xr t        |d   xs d      j                         j                         |k(  xrW t        ||	z
        t)        d|	dz        k  xr7 t        ||
z
        t)        dt        |
      dz        k  xr |duxr |t*        v }|syt        |d   xs d      j                         d|t        |d   xs d      |d d!fS t
        j-                         sy"t        | j                  d      xs d      j                         j                         }t        | j                  d      xs d      j                         j                         }|dk(  rdn|dk(  rdnd}t%        | j                  d#      xs | j                  d$            }	 t        t        | j                  d      xs d            }t        | j                  d      xs d      }|r|r|
|dk  s|dk  ry&d}	 t        j                  dt
         dd      }t        j                  |_        |j                  d'||f      j/                         }	 ||j                          	 t)        d|dz        }t)        dt        |      dz        }g }|D ]+  }t        |d   xs d      j                         }t        |d*   xs d      j                         }|r|d+v rK|j1                         j3                  d,      rkt%        |d-         }|||kD  r	 t        t        |d   xs d            }t        |d.   xs d      }t        ||z
        |kD  rt        ||z
        |kD  rt'        |      }|t*        vr|j5                  |t        |d/   xs d      j                         |t        |d-   xs d      |d        . t7        |      d0k7  rdd1t7        |       fS |d   d2fS # t        $ r.}t        d
| d|        Y d}~||j                          yyd}~ww xY w# ||j                          w w xY w# t         t"        f$ r Y yw xY w# t         t"        f$ r Y y%w xY w# t        $ r.}t        d(| d|        Y d}~||j                          y)y)d}~ww xY w# ||j                          w w xY w# t         t"        f$ r Y 4w xY w)3zJTrova una sola entrata usando l'intera firma del trade, mai il solo asset.orderIdr/   Nzfile:z?mode=roT)urizUSELECT 1 FROM sqlite_master WHERE type='table' AND name='closed_trade_entry_evidence'zSELECT close_order_id, entry_order_id, symbol, open_side, qty, entry_price, strategy, opened_at, source FROM closed_trade_entry_evidence WHERE close_order_id = ?z(exact entry evidence lookup err orderId=r  )Nexact_entry_evidence_db_errorr   rU  SELLBUYr  r   r  rW  rY  )N$exact_entry_evidence_invalid_numeric	opened_atr   	open_sider  r  g|=g-C6
?)N'exact_entry_evidence_signature_mismatchentry_order_id)r  
request_idrZ  entry_time_rawr   !exact_closed_order_entry_evidence)Nentry_db_missingr  r  )Nentry_signature_invalid)Nentry_signature_incompletezSELECT order_id, request_id, symbol, side, qty, price, strategy, created_at FROM orders WHERE UPPER(symbol) = ? AND UPPER(side) = ? ORDER BY id DESCz"entry lifecycle lookup err symbol=)Nentry_db_errorr   >   no_positionanti_dup_skiprender_blockedrender_short_blockedr  rL  pricer   r   entry_lifecycle_candidates_unique_entry_lifecycle)r;   r&   r!   r  r  r  Rowrow_factoryr  r  r'   rf   r  r  r  r  r  r   rF   r   r  r   r   fetchallr   r  r  r=   )r  close_order_id
exact_conntable_exists	exact_rowro   r   
close_sideexpected_open_side
closed_qtyclosed_entry
stored_qtystored_entryr  r   validr  close_dtrW  rY  r	  rowsqty_toleranceprice_tolerancer  r   raw_strategyr   entry_dtrow_qty	row_prices                                  r,    _unique_entry_lifecycle_evidencerD  >  s    39r:@@BN
$	# 5	)BMJ%,[[J"%--9 hj $ ) #**L  !
 hjd ( %  " 28b9??AGGIF[__V4:;AACIIKJ*4*>j\aNaFgiD {|'D'I!JK
$[___%E%JK y'7'<1!=>
$Y}%=%BC (	+(>?I*9Z+@AH Ih'-2.446<<>&H 
>	+.4"5;;=CCEI[[
> 
Z/0Cj4>O4PP	
> |34E3|CTW[C[8\\
> T)
>  ==   F #&i0@&A&GR"H"N"N"P '"%i&<&B"C$ 33 3  >>' *0b1779??AF[__V,2399;AACJ#v-Z5=P6VXI&F+//+*FH/%5:;<KOOO<AB h&6#(kUVFV1 Dwix8dC";;||W Y
 (* 	$ JJL cDj)M%[!1D!89OJ <3z?0b1779s:,"-3358 (
 
 ((2"3|#45x(2	%E
a01Gc'l/a0I w}-y;&'/9&|488&c,/526<<>"!#l"3"9r: 
 	a<@ :!23z?2CDDDa=222q  	9:>:J"SERS8 %  " &	9 %  " &, z* DCDH z" /./<  &03%@A% JJL & JJL T :& 		s   A8W A2X( AX= -AY -Z$	XX0X XX X%(X:9X:=YY	Z	Z,Z Z		Z Z!$Z76Z7c                 @   t        | j                  d      xs d      j                         }|j                  di       j                  |      }|8t        |j                  d      xs d      j                         }t        dd|dd	S t	        | |j                  d
g             }|r;t        |d   j                  d      xs d      j                         }t        dd|dd	S t        ||d         \  }}t        |       \  }}	t        | j                  d      xs d      j                         j                         }
|j                  di       j                  |
      }|rit        |d         }t        | j                  d      xs | j                  d            }|,|||k\  r%|t        d|	 dddd	S |d   |k\  rt        ddd|d	S t	        | |j                  dg             }|D ch c]  }t        |j                  d             }}|t        v r||}}n|t        |      dk(  r@|j                         }t        |d   j                  d      xs d      j                         }n.t        |      dkD  r	t        d}}n||d   |	}}nt        | d|	 }}||dd|d	S c c}w ) zLClassifica il trade e applica il blocco all'ora di entrata, non di chiusura.r  r/   r  NrM  APPROVED_OPERATIONAL_EXCLUSION%operational_exclusion_closed_order_idT)r   sourceperformance_excludedr_  entry_evidencer  r   #UNAUTHORIZED_ORDER_WITHOUT_TV_ALERT!operational_exclusion_fingerprintr7  r   r  r  r  r  zblocked_asset_entry_unverified:FrZ  "blocked_entry_after_effective_fromBLOCKED_ASSET_ORDER_LEAKr  r   r   rH  certified_trade_fingerprintconflicting_trade_fingerprintsr   )r;   r&   r!   r  r   r  rD  r  rF   r   r   r=   pop)r  r   r1  exact_operationalrM  operational_matchesexact_strategyexact_sourcerJ  entry_sourcer   
block_ruleblocked_fromr<  fingerprint_matchesr   fingerprint_strategiesr   rH  s                      r,   _classify_closed_itemr[  @  s#    39r:@@BN

#JBOSS $!!(+O/O
 %'	 	 .=$("("
 	
 1VZZ I2N "&&x0Y4Y
 %'	 	 .9$("("
 	
  $A,-	$ NL $DK#P NL*0b1779??AF,b155f=J &z2B'CD"OOM*Jkook.J
 #)9X=U% !6 ?~N,1*,&*  l+|; !6B,0*D&4   1VZZ ?D ?R6:DHHZ01  66)<&	#	$	))--/"&&x0Q4Q
 %'	 	 
#	$q	(02R&		#)*5|& 1\N!L>2R&  % ( Is   '!Jr     r   r   )tzinfor  c                    | j                  dd      }t        | j                  dd      xs d      }||ft        d   v r||ft        d   v ryt        | j                  dd      xs d      }|dk(  r#t        |d	z
        d
k  rt        |dz
        dk  ry|dk(  rt        |dz
        dk  ry|dk(  rt        |dz
        d
k  ryy)zCTrue se il trade chiuso Bybit corrisponde a un MIO test Pine-style.r   r/   r  r   r  Tr  r        ?r  r  {Gz?r  r  BTCUSDTZd;O?F)r&   r  MY_TEST_FILTERr  )rA  symrW  	avg_entrys       r,   is_mio_test_traderf  	  s     ))Hb
!C
		,*/a
0CSz^M22Sz^TaEb7beii38q9I mIO 4t ;C&L@QTX@X
jSu-4
iCe,t3rL   c                     | j                  dd      }	 t        | j                  dd      xs d      }|dk(  rt	        |dz
        dk  ry	|d
k(  rt	        |dz
        dk  ry	y# t        t        f$ r Y yw xY w)u   True se la posizione aperta e' un MIO test Pine-style.

    FIX 2026-08-10 (Mattia): rimosso BTCUSDT 0.023 dal filtro perche' era una posizione reale

    del 2° account, non un test. Tenuto NEARUSDT 599.9 e VIRTUALUSDT 1500 (quei SI sono test).r   r/   r   r   Fr  r  r`  Tr  r  )r&   r  r  r   r  )posrd  r   s      r,   is_mio_test_positionri  &	  s     ''(B
CSWWVQ',1- jS.5
mD6M 2T 9 z" s   A" "A43A4c                  *   g } t               }|d   }|j                  dg       }|d   }	 t        j                  j	                  dt        t                     ddlm}  |       }t        t        d      j                  j                  t        d      j                  j                        j                         dz        }d}t         }	|	|k  rt#        |	|z   |      }
d	|	|
d
d}|j%                  dd|d      }|j                  d      xs i j                  dg       xs g }|D ]:  }|j                  dd      }t        |j                  d      xs d      j'                         }||v st)        ||      rSt+        ||      }|d   }|d   }|j                  d      xs i }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      }t-        |j                  dd      xs d      xs ||z   }||z   }t/        ||z        }|dkD  r||z  dz  nd}|dkD  r||z  dz  nd}| j1                  i d|d |j                  d d      d!|d"|d#|d$|d%|d&|d'|d(|d)|d|d*|t2        k7  rd+nd,d-|d.|d.   d/|d/   d0|j                  d0d      |j                  d1d      ||j                  d2d      |j                  d3d      d4       = |
d5z   }	|	|k  r| S # t4        $ r} t7        d6|         | cY d7} ~ S d7} ~ ww xY w)8u  Legge TUTTI i trade chiusi da Bybit API (closed-pnl endpoint), filtra dal 1° agosto,

    esclude MIEI test Pine-style.

    FIX 08/08 (Mattia): NO cursor-based paging perche' bybit_demo_client._request calcola

    firma sul cursor RAW ma `requests.get` ri-encoda il `%3A` -> err 10004.

    Uso finestre di 1 giorno: ~5 trade/giorno, no rischio limite 50.

    FIX 12/08 (Mattia, REVISIONE FINALE #3): closed_trade.strategy = CLOSED_TRADES_STRATEGY_OVERRIDE

    (hardcoded, esplicito) per i simboli in cui il CSV NON riflette la SOURCE Pine TV al momento:

    - WIF: CSV dice rsi_swing ma Pine WIF = RETTANGOLO (Python/SL engine, non Pine RSI swing)

    - VIRTUAL: VPTR3 enabled=false ma Pine VIRTUAL = VPTR3 (aperti quando era attivo)

    - AEO: CSV dice rsi_swing ma Pine AEO = RSI swing SOLO con SL/TP (per Mattia lo conteggia RSI swing)

    Per TUTTI gli altri simboli: get_strategy_for_symbol (CSV con priorita').r  r  r7  r   r  r   r  i \&linear2   )category	startTimeendTimelimitr  z/v5/position/closed-pnlTr  r  rm   r   r/   r  r   rH  rJ  r  r  r  r  openFeecloseFeetotalFeed   rU  rW  rY  
exit_pricer]  r\  	pnl_grossfeepnl_pct_grosspnl_pct_netclassification_status
classifiedr  r^  rI  r_  r  r!  r  r  )rZ  r   rL  r[  r   zbybit closed trades err: N)r  r&   r  r  r  r;   r   r  r  r>   
__import__r   r\   r   r@   r   SINCE_DATE_MSminr  r!   r   r[  r  r  r  r  r'   rf   )!outr   excluded_order_idsexcluded_fingerprintsstrategy_by_order_idr  r  now_ms	WINDOW_MScurrent_start
window_endparamsrr   itsym_rawr1  classificationstratattribution_sourcerJ  qty_tentry_texit_tnet_pnlopen_fee	close_fee	total_fee	gross_pnlnotional_entryrx  ry  r  s!                                    r,   get_closed_trades_bybitr  F	  sV   0 C%'F ;<"JJ'DbI!"?@T3t9%5 Z
+4488J9O9X9X9\9\]ggilppq ,	%f$]Y6?J %*%
F 

5";VD
QAUU8_*//;ArE d&&2.!$RVVI%6%<"!=!C!C!E!%77;Q-< !6r6!B&z2%3H%="!/!3!34D!E!Kbff\15:; : ?a@rvvna8=A>{A 6 ;!< !	1!5!:;!"&&Q"7"<1=	 ""&&Q"7"<1=W(YBV	 $i/	 "%Wu_!5FTWXFX^!;c!A^_BPSTBTw7#=Z[

 0g0 BFF62.	0 50 "70 !&0 70 w0   !0$ 9%0( $])0, ";-00 104 ,(-1F(FN90@ ,-?A0D +N;Q,RE0H ).9M*NI0L %n&8&89I2&NM0P #1"4"45Er"J ."$&&b"9"$&&";]0 0idL 'NMu f$x 
 's+,
	s$   MM/ -M/ /	N8NNNc                  X    t               } | D cg c]  }t        |      r| c}S c c}w )z>Legge posizioni aperte da Bybit, ESCLUDE MIEI test Pine-style.)r  ri  )r   ps     r,    get_open_positions_bybit_no_testr  
  s(     
C:!"6q"9A:::s   ''c                    g }t         j                         s|S 	 t        j                  t               }t        j                  |_        |j                         }|j                  d|| f       |j                         D ]  }|j                  t        |              |j                          |S # t        $ r}t        d|        Y d}~|S d}~ww xY w)uP   Carica ordini dal DB, filtrati per data >= since_date (default 1° agosto 2026).zSELECT order_id, symbol, side, qty, price, notional, strategy, created_at FROM orders WHERE created_at >= ? ORDER BY id DESC LIMIT ?zorders load err: N)r  r   r  r  r.  r/  cursorr  r0  r  r   r  r'   rf   )rp  
since_dater  r	  curr   r  s          r,   
get_ordersr  
  s     C>>
%w'";;kkmI 	
 <<> 	"CJJtCy!	" 	

 J	  %s#$$J	%s   BB- -	C6C

Cc                     t         j                         sdddddS 	 t        j                  t               } | j	                         }|j                  d       ddddd}|j                         D ]  \  }}|||<   |dxx   |z  cc<    | j                          |S # t        $ r}t        d|        dddddcY d }~S d }~ww xY w)Nr   )r   	completedfailedr#  z2SELECT status, COUNT(*) FROM queue GROUP BY statusr#  zqueue stats err: )
r  r   r  r  r  r  r0  r  r'   rf   )r	  r  statsr   r  r  s         r,   get_queue_statsr  :
  s    >>1AFFGw'kkmHIAQG \\^ 	$MFE!E&M'Ne#N		$ 	

 Gs#$1AFF	Gs   A<B 	C#B=7C=C>   $2cd6e92c-b82b-4814-808e-e23579f1a533$2d2e625b-d3b2-4d87-931a-9b378cf8db93$31a9c2fd-540e-45a5-b44f-fe2f8fdb4495$44e4a3ad-23ec-4b7f-b6f8-35778858e5bf$4c8a4478-377e-4b8c-b371-44c64090e26d$4cbb1304-8020-42bd-bcad-8e5d0f19caed$514f5553-6aa3-4148-8e1a-82961c47310b$5c53a9ef-dcab-469e-bbd1-3057fe2746d9$79969acc-3e4b-4101-91bc-69eede1ef6aa$7ed5cc82-3a99-4978-8ae3-c295e82f4609$8a53e7b1-c7d4-4e5a-b67b-4e4fbf4c0977$b426dc94-b72f-427b-b2f2-7e021f5da985$c60d098a-1ec5-4101-9e77-966f67f4f393$e45f561b-c4d8-4045-a2fe-581140fadac1$f79ab621-dc17-488e-950e-e984fc0d9e43c                    t        | j                  dd            }|t        v ry| j                  dd      }	 t        | j                  dd      xs d      }t        | j                  dd      xs d      }|d	k(  rt        |d
z
        dk  ry|dk(  r|dk\  ry|dk(  rt        |dz
        dk  ryy# t        t
        f$ r Y yw xY w)zpTrue se l'ordine e' un MIO test Pine-style (placeholder price=1.0, NEAR 599.9, o order_id in MY_TEST_ORDER_IDS).r   r/   Tr   rW  r   r+  Fr  r_  &.>r    ra  rb  r  )r;   r&   MY_TEST_ORDER_IDSr  r  r   r  )ooidrd  rW  r+  s        r,   is_mio_testr  
  s     aeeJ#
$C

%%"
CAEE%O(q)aeeGQ',1- mECK 04 7 jSCZ iCe,t3- z" s   >B0 0CCc                 R   t        t              }t        | d       D ]d  }|j                  dd      }|s|j                  dd      }|dv r/|j                  dd      dk  rEt	        |      rQ||   j                  |       f g }|j                         D ]  \  }}g }|D ]~  }|j                  d	d      j                         }t        |j                  dd      xs d      }	t        |j                  d
d      xs d      }
|j                  dd      }|j                  dd      }|dk(  r)t        |
dz
        dk  }|j                  |	|
|||d       |dk(  s|s|	}|dkD  s|s|d   }t        ||d         }|
|d
   z
  |z  }|d
   dkD  r|
|d
   z
  |d
   z  dz  nd}|j                  dd      xs t        |      dkD  }|j                  |d||d
   |
|||d   |d   ||d       ||z  }|dxx   |z  cc<   |d   dk  r|j                  d       |dkD  s||r  |S )zMatcha buy+sell FIFO per symbol. Esclude trade che coinvolgono MIEI test Pine-style

    (placeholder price=1.0 o order_id in MY_TEST_ORDER_IDS).c                 &    | j                  dd      S )NrL  r/   r3  xs    r,   r   z$compute_trade_pnls.<locals>.<lambda>
  s    !%%b*A rL   r   r   r/   r   )r'  r(  r/   NrW  r   rU  r+  r   rL  buyr_  r  )rW  r+  r   rC   placeholdersellrt  r  F   longrC   )r   rU  rW  rY  ru  r]  pnl_pctr   entry_tsexit_tswarn)r   rm   r   r&   r  r  r   r   r  r  r~  rQ  )orders	by_symbolr  rd  r  tradesords	open_buysrU  rW  r+  r  rC   r  qty_to_closer  matchedr]  r  r  s                       r,   compute_trade_pnlsr  
  sq    D!IF AB !eeHb!eeJ#<<55?a q>#a 1!4 F__& <)	T	 8	)A55$**,DeQ,1-C!%%+0q1EEE*b)E|R(Bu}!%#+.5  u%WYju!vwI""Q&9#A,C!,E
;G 3w</7:CORSZ|^_O_G 4GDKefG 77=%8MCL2<MDMM"%v&s7|SX"w$'
OTWY $#  !G+LJ')J5zT)!a(E #Q&9-8	)	<)| MrL   c           
      .   t        |       }|dk(  rIi ddddddddddddd	dd
ddddddddddddddddt        |      dd|ddddddddS | D cg c]*  }|j                  d|j                  dd            dkD  s)|, }}| D cg c]*  }|j                  d|j                  dd            dk  s)|, }}t        d | D              }t        d | D              }t        d | D              }	t        d | D              }
t        t        d |D                    }d}|D ]%  }	 |t	        |j                  dd      xs d      z  }' ||	z
  }d}| D ]<  }t        |j                  d      xs |j                  d             }|3|||k  s;|}> |ldd!lm}m} |j                  |j                        }|j                  |j                        j                  d"      }||z
  }t        d#|j                  d#z         }nd}d}t        d$ |D              }t        d% |D              }|dk  r|t        |      z  }n
|dkD  rd&}nd}d}d}i d|dt        |      dt        |      d|rt        |      |z  d'z  ndd|d|d	|d
|	d|
d|d|d|r||z  ndd|r||z  ndd| rt        d( | D              ndd| rt        d) | D              nddt        |      d||||z   ||z   |||||d*S c c}w c c}w # t
        $ r Y w xY w)+zcCalcola KPI da trade chiusi Bybit (gia filtrati per data e test) + posizioni aperte (gia filtrate).r   n_tradeswinslosseswinrater  	total_pnltotal_pnl_nettotal_pnl_gross
total_feestotal_notionaltotal_lossespnl_realizedavg_pnlavg_pnl_gross
best_tradeworst_tradeopen_positionsunrealized_pnlr/   )balancetotal_pnl_with_unrealizedtotal_pnl_gross_with_unrealizedtrading_daysprofit_factorfirst_trade_datesharpe_ratiosortino_ratior\  r]  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr\  r]  r   Nr3  r  ts     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>B  s%     Qaiua9Q   ,.c              3   @   K   | ]  }|j                  d d        yw)rv  r   Nr3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>D  s     GA!%%Q/G   c              3   @   K   | ]  }|j                  d d        yw)rw  r   Nr3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>F  s     <QUU5!_<r  c           
   3      K   | ]L  }t        t        |j                  d d      xs d      t        |j                  dd      xs d      z         N yw)rY  r   rW  N)r  r  r&   r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>J  sF     wdeU155#:#?a@5uVWI]\]C^^_ws   AAc              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr  r3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>P  s%     M155AEE%O<Mr  unrealisedPnlNr[  rL  r   %Y-%m-%dr   c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr  r3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     Haiua9Hr  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr  r3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     Kqy!%%q/:Kr  g(\X@rt  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr  r3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     S!%%	155?;Sr  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywr  r3  r  s     r,   r  z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     T155AEE%O<Tr  )r  r  r  r  r  r  r  r  )r=   r&   r  r  r  r'   rF   r   r   r\   r@   rN   rH   r  daysr~  )closed_trades	positionsr  nr  r  r  r  r  r  r  r  
unrealizedr  r  first_trade_dtrC   _dt_tznow_utcr  deltar  total_win_pnltotal_loss_pnlr  r  r  s                               r,   compute_kpis_from_bybitr    s    	MAAv

!1
&.
3<c
 	
 .s	
 s
 %1#
 8H
 C
 "0
 s
 ,S
 #
  -c
 c)n
 /?
  S/2#-
 	
4 %N!iua(IA(MANDN&QA!%%	155?*Kq*PaQFQQ=QQMGGGO<m<<J wivwwN sMfMMNLJ 	%oq 9 >Q??J	 #Z/L N $QUU<0GAEE,4GH>%n)<!#$ ! 	>''#''")44SWW=FFzR.( 1ejj1n-  H4HHMKFKKN%N(;;		   LM4A4 	D		4 	#f+4 	ACIMC'34 	]4 	4 	?4  	j!4$ 	.%4( 	)4, 	-40 	=1$s144 	1,s548 	WdcS]SSjm94< 	XesTmTTkn=4@ 	#i.A4D 	*E4H %2Z%?+:Z+G$,&$&e4 4Y OQ4  		s*   *K=	K=*L>L/"L	LLc                    | s	g g g ddddS | j                  d        t        |t        d | D              z
  d      }g g g df\  }}}}| D ]h  }||d   z  }|j                  d      xs |j                  d	      xs d
}|j	                  |       |j	                  ||z          |j	                  |       j |r|d   nd}	d}
d}|D ]%  }||	kD  r|}	|	|z
  }||
kD  s|}
|	dkD  r||	z  dz  nd}' |||t        |       |
|dS )zCalcola equity curve da trade chiusi Bybit (gia filtrati).

    Ritorna anche max_dd_usdt e max_dd_pct (FIX 07/08 Mattia: drawdown real come Dash 5511).

    FIX 12/08 (Mattia): aggiunto cum_pnl (PnL cumulativo progressivo) per grafico equity.

    r   r  )datesequitycum_pnltrades_countmax_dd_usdt
max_dd_pctc                 R    | j                  d      xs | j                  d      xs dS Nr[  rL  r/   r3  r  s    r,   r   z1compute_equity_curve_from_bybit.<locals>.<lambda>  s#    QUU<%8%UAEE,<O%USU rL   r   c              3   &   K   | ]	  }|d      ywr]  Nr   r  s     r,   r  z2compute_equity_curve_from_bybit.<locals>.<genexpr>  s     &GAqx&G   r]  r[  rL  r/   rt  )sortr  r  r&   r  r=   )r  r  initial_equityr  r	  r
  cumr  rC   peakr  r  r+   dds                 r,   compute_equity_curve_from_bybitr    sE    rb!\_orssUV3&G&G#GGKN"$b"a-E67C 
qxUU< =AEE,$7=2Rns*+s
 6!9ADKJ >t8DAXK.2Qh"t)c/AJ>  &WcR_N`"*	 rL   c                    t        d       }| D ]  }|j                  dt              }|t        k(  r#|j                  d|j                  dd            }||   dxx   dz  cc<   |dkD  r||   dxx   dz  cc<   ||   dxx   |z  cc<   ||   d	xx   |j                  d	d      z  cc<   ||   d
xx   |j                  dd      z  cc<   ||   d   j                  |        g }|j	                         D ]  \  }}|d   r|d   |d   z  dz  nd}|d   }|d   }	|dk\  rt        |	      |z  t        fd|	D              |dz
  z  }
|
dkD  rt        j                  |
      nd}|dkD  r|z  nd}t        d |	D              }|dkD  rt        j                  ||z        nd}|dkD  r|z  nd}ndx}}|j                  |||d   ||d   |d	   |d
   ||d	        |j                  d d       |S )Nc                      dddddg dS )Nr   r  )r  r  r]  rv  feespnlsr   r   rL   r,   r   z0compute_by_strategy_from_bybit.<locals>.<lambda>(  s    AcPS]`jl#m rL   r   r\  r]  r   r  r   r  rv  r  rw  r  rt  ru   c              3   .   K   | ]  }|z
  d z    yw)ru   Nr   )r  r  means     r,   r  z1compute_by_strategy_from_bybit.<locals>.<genexpr>R  s     4!q4xAo4   r  c              3   :   K   | ]  }t        d |      dz    yw)r  ru   N)r~  )r  r  s     r,   r  z1compute_by_strategy_from_bybit.<locals>.<genexpr>X  s     6As3{a'6s   )	r   r  r  r  r]  rv  r  sharpesortinoc                     | d   S Nr]  r   r  s    r,   r   z0compute_by_strategy_from_bybit.<locals>.<lambda>h  
    1U8 rL   Tr   reverse)	r   r&   r  r  r   r  mathsqrtr  )r  by_stratr  rD   pnl_nr  dwrr  r  varstdr"  ddsqr  r#  r  s                   @r,   compute_by_strategy_from_bybitr2  &  s'   mnH *EE*34%%iua1CA19QK1$Ee#K AEE+q$99 FquuUA.F""5)-*0 C  ";1+,S6ai!C& 3&q cFy6t9q=D4t44A>C$'!G$))C.C#&7TCZF666D(,q4!8$cB#%6dRisG  #"FW

1V9U8!K.!F)$	: 	;=";H HH#TH2JrL   c                    t        d       }| D ]  }|j                  dd      }|s|j                  d|j                  dd            }||   dxx   dz  cc<   |dkD  r||   d	xx   dz  cc<   ||   dxx   |z  cc<   ||   d
xx   |j                  d
d      z  cc<   ||   dxx   |j                  dd      z  cc<   ||   dxx   |j                  dd      |j                  dd      z  z  cc<    g }|j                         D ]F  \  }}|d   r|d	   |d   z  dz  nd}|j                  ||d   |d	   ||d   |d
   |d   |d   d       H |j	                  d d       |S )Nc                      dddddddS )Nr   r  )r  r  r]  rv  r  volumer   r   rL   r,   r   z-compute_by_asset_from_bybit.<locals>.<lambda>r  s    AcPS]`lo#p rL   r   r/   r\  r]  r   r  r   r  rv  r  rw  r5  rW  rY  rt  )r   r  r  r  r]  rv  r  r5  c                     | d   S r%  r   r  s    r,   r   z-compute_by_asset_from_bybit.<locals>.<lambda>  r&  rL   Tr'  )r   r&   r   r  r  )r  by_assetr  rW   r,  r  r-  r.  s           r,   compute_by_asset_from_bybitr8  p  s   pqH KEE(Biua1CA19QK1$Ee#K AEE+q$99 FquuUA.Hua1553J!JJ-K0 C  m1+,S6ai!C& 3&q

aafaiBU8!K.!F)_`ai_jl 	m	m HH#TH2JrL   c                    t        t              }| D ]  }t        |j                  d      xs d      j	                         }|s3t        |j                  d      xs d      }|j                         dk(  rdn|j                         dk(  rdnd}t        |j                  d	            }t        |j                  d
      xs |j                  d            }||   j                  |r|j                         j                  d      nd|r|j                         j                  d      ndt        |j                  d      xs d      j	                         |t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d|j                  dd                  t        |j                  d      xs d      d        |j                         D ]  }|j                  d d        t        |      S )z<Movimenti certificati che compongono il saldo di ogni asset.r   r/   rU  r  LONGr  SHORTrJ  rZ  r[  rL  %Y-%m-%d %H:%Mr   rW  rY  ru  rv  rw  r\  r]  r   r   )r  	closed_atr   	directionrW  r  exitgrossrw  netr   c                     | d   S Nr=  r   r   s    r,   r   z-compute_asset_trade_details.<locals>.<lambda>      #k"2 rL   Tr'  )r   rm   r;   r&   r  r   rF   r  rN   rH   _safe_floatr   r  r   )	r  detailsrA  r   r5  r>  r  ru  r=  s	            r,   compute_asset_trade_detailsrH    s    $G (UYYx(.B/5576*0b1
(..0F:F:K[K[K]afKflo	 <!89 <!8!SEIIl<STKQ**,556FGWZKQ**,556FGWZEIIj17R8>>@"uyy/0 =!9:		, 78 ;!78uyy/0uyyEIIeQ4GHIEIIj17R8- 
 	!(T   B		2D	AB =rL   c                    t        t              }| D ]	  }t        |j                  d      xs t              }|t        k(  r0t        |j                  d      xs d      }|j                         dk(  rdn|j                         dk(  rdnd}t        |j                  d	            }t        |j                  d
      xs |j                  d            }||   j                  |r|j                         j                  d      nd|r|j                         j                  d      ndt        |j                  d      xs d      j                         |t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d            t        |j                  d|j                  dd                  t        |j                  d      xs d      d        |j                         D ]  }|j                  d d        t        |      S )z@Movimenti certificati che compongono il saldo di ogni strategia.r   rU  r/   r  r:  r  r;  rJ  rZ  r[  rL  r<  r   rW  rY  ru  rv  rw  r\  r]  r   r   )r  r=  r   r>  rW  r  r?  r@  rw  rA  r   c                     | d   S rC  r   rD  s    r,   r   z0compute_strategy_trade_details.<locals>.<lambda>
  rE  rL   Tr'  )r   rm   r;   r&   r  r   rF   r  rN   rH   r  rF  r   r  r   )	r  rG  rA  r   r5  r>  r  ru  r=  s	            r,   compute_strategy_trade_detailsrK    s    $G (uyy,E0EF,,6*0b1
(..0F:F:K[K[K]afKflo	 <!89 <!8!SEIIl<ST  KQ**,556FGWZKQ**,556FGWZ%))H-34::<"uyy/0 =!9:		, 78 ;!78uyy/0uyyEIIeQ4GHIEIIj17R8-"
 	!(T   B		2D	AB =rL   c                    t        d       }| D ]  }|j                  dd      }|j                  dt              }|r	|t        k(  r7|j                  d|j                  dd            }||f}||   dxx   d	z  cc<   |dkD  r||   d
xx   d	z  cc<   ||   dxx   |z  cc<   ||   dxx   |j                  dd      z  cc<   ||   dxx   |j                  dd      z  cc<    g }|j                         D ]F  \  \  }}}|d   r|d
   |d   z  dz  nd}	|j	                  |||d   |d
   |	|d   |d   |d   d       H |j                  d d       |S )a  FIX 11/08 (Mattia): aggrega per (symbol, strategy) per evitare abbinamenti errati

    tipo AEO RSI swing classificato come VPTR3, oppure WIF RSI swing classificato come RETTANGOLO.

    Ogni entry: {symbol, strategy, n, wins, winrate, pnl, pnl_gross, fees}.c                      ddddddS )Nr   r  )r  r  r]  rv  r  r   r   rL   r,   r   z6compute_by_asset_strategy_from_bybit.<locals>.<lambda>  s    a3SZ] ^ rL   r   r/   r   r\  r]  r   r  r   r  rv  r  rw  rt  )r   r   r  r  r  r]  rv  r  c                     | d   | d   fS )Nr]  r  r   r  s    r,   r   z6compute_by_asset_strategy_from_bybit.<locals>.<lambda>@  s    AeHaf- rL   Tr'  )r   r&   r  r   r  r  )
r  by_asr  rW   rD   r,  r   r  r-  r.  s
             r,   $compute_by_asset_strategy_from_bybitrP    s    ^_E .EE(BEE*34A..iua1!fc
3119#Jv!#c
5U"c
;155a#88c
6aeeE1o-1.4 C[[] V	A+,S6ai!C& 3&q

aQQsVQvY[]U8!K.!F)U 	V	V HH-tH<JrL   c           
         t        d      D cg c]  }dgdz  
 }}t        d      D cg c]  }dgdz  
 }}t        d      D cg c]  }dgdz  
 }}t        d      D cg c]  }dgdz  
 }}t        d      D cg c]  }dgdz  
 }}g d}| D ]*  }t        |j                  d      xs |j                  d            }	|	4|	j                         }
t	        |j                  d|j                  d	d                  }|
j                         }|
j                  }||   |xx   t	        |j                  d
|            z  cc<   ||   |xx   t	        |j                  dd            z  cc<   ||   |xx   |z  cc<   |dkD  r||   |xx   dz  cc<   |dk  r||   |xx   dz  cc<   ||   |xx   dz  cc<   - |t        t        d            |||||dS c c}w c c}w c c}w c c}w c c}w )aB  Heatmap WIN/LOSS per giorno x ora. Ritorna matrix_w (vittorie) e matrix_l (loss).

    FIX 07/08: prima la heatmap mostrava solo il conteggio totale senza distinguere

    W da L. Adesso separa W (verde) e L (rosso) cosi' VIRTUAL che ha 1 loss -25.47

    a Ven 02 appare in rosso, non in verde come tutti gli altri.

       r      r  )LunMarMerGioVenSabDomr[  rL  r\  r]  rv  rw  r   )r  hoursmatrix_wmatrix_lmatrix_grossmatrix_fees
matrix_net)r  rF   r&   rN   rF  weekdayhourrm   )r  _r\  r]  r^  r_  r`  r  r  rJ   local_dtr]  d_idxrb  s                 r,   compute_heatmap_from_bybitrf  H  s    #((+Qb+H+"'(+Qb+H+(-a11SEBJ1L1',Qx0!C52:0K0&+Ah/3%"*/J/<D $'QUU<0GAEE,4GH: ==?!%%	155?;<  "}}UD![{C1H%II!E4 KeQ$@@ 5$3&7UOD!Q&!1WUOD!Q&! UOD!Q&!I$'P tE"IHRZ$[PZ	 e ,+10/s   GG"G'"G,>G1c                 4   t        d       }| D ]  }t        |j                  d      xs |j                  d            }|4|j                         j	                  d      }||   }|dxx   dz  cc<   |j                  d|j                  dd	            }|d	kD  r|d
xx   dz  cc<   |dxx   |j                  dd	      z  cc<   |dxx   |j                  dd	      z  cc<   |dxx   |z  cc<   |j                  dd      }|s||d   vs|d   j                  |        g }t        |j                         d      D ]U  }||   }|j                  ||d   |d
   |d   r|d
   |d   z  dz  nd	|d   |d   |d   dj                  |d         d       W |S )zIRaggruppa trade chiusi per giorno, calcola Gross/Fee/Net per ogni giorno.c                      dddddg dS )Nr   r  )r  r  rv  r  r\  r  r   r   rL   r,   r   z'compute_trades_by_day.<locals>.<lambda>  s    q!#s_boq!r rL   r[  rL  r  r  r   r\  r]  r   r  rv  r  rw  r   r/   r  Tr(  rt  r  )dater  r  r  rv  r  r\  r  )	r   rF   r&   rN   rH   r  r   keysr  )	r  by_dayr  rJ   day_keyr-  r,  rd  r  s	            r,   compute_trades_by_dayrn    s    rsF %QUU<0GAEE,4GH:--/**:67O	#!iua119fINI	+!%%Q//	&	QUU5!_$		)eeHb!3a	l*iL$=%@ C&++-6 7O

3fI56sV&	AcF*S0;fI|yy9.!
 		0 JrL   c                 H   ddl m }m}m} t        t              }| D ]  }t        |      r|j                  dd      }|j                  dd      xs dj                         }	 t        |j                  dd      xs d      }	t        |j                  dd      xs d      }
|	dk  s|
dk  r|dk7  r|j                  d	d      }|s|d
d }||   j                  ||	|
|d        	  |j                  |      j                         } |j                  |j                         j                         }|}||k  r+|j#                         }||vrg ||<   | |d      z  }||k  r+g }t%        |j'                         d      D ]\  }||   }|r3dj)                  |D cg c]  }|d    d|d   dd|d   dd c}      nd}|j                  |t+        |      |d       ^ |S # t        t        f$ r Y w xY w# t        $ r  |ddd      j                         }Y w xY wc c}w )a  FIX 07/08 v3: conta le APERTURE (entry Buy) per giorno, NON le posizioni ancora

    aperte. Un ordine Buy = un'apertura, anche se poi chiusa in piu' tranche.

    Esclude ordini 'no_pos' e 'anti_dup_skip' (qty=0 o price=0) E MIEI test (is_mio_test).

    FIX 07/08 v4 Mattia 14:40: escludi NEARUSDT 600 (test Pine) e popola con 0 i giorni

    dal since_date a oggi che non hanno entry (trasparenza).

    r   )r   r   	timedeltar   r/   rU  rW  r+  r  rL  Nr5   )r   rW  r+  rC   r\  r   r   )r  Tri  r   (,.0f@.4f)   —rj  r  r  )r   r   rp  r   rm   r  r&   r   r  r  r   r  rA   rj  r'   r\   r@   r]   r   rk  r  r=   )r  r  r   r   rp  rl  r  rd  rU  rW  r+  rC   daystarttodayr  r-  r  entriesr  symbols_strs                        r,   compute_entries_by_dayr}    sI    76F $Rq>eeHb!fb!'R..0	eQ,1-C!%%+0q1E !8uz5=UU<$"gsc#RPQI$RP,&&&z2779 HLL&++-E
C
,MMOF?F1Iya   , CfkkmT2 +krdii^e fYZAhK=1U8D/1W:cBRRS!T fgx}

W"
 	  JA :& 		8  ,q!$))+,0 !gs*   ">G!' G7 H
!G43G47!HHc           	         t        t              }|D ]  }|j                  dd      }|j                  dd      xs dj                         }	 t	        |j                  dd      xs d      }t	        |j                  dd      xs d      }|dk  s|dk  r|dk(  s||   j                  |||j                  dd      d	        t        d
       }	| D ]  }
|
j                  dd      }t        |
j                  d            }t        |
j                  d            }|r|dk  rQ|j                  |g       }|sd}n+t        |d       }|j                  dd      xs ddd }|sd}|	|   dxx   dz  cc<   |	|   d   j                  | d|dd|dd        g }t        |	j                         d      D ]1  }|	|   }|j                  ||d   dj                  |d         d       3 |S # t
        t        f$ r Y w xY w)u  DEPRECATED dopo v3: contava le posizioni ANCORA APERTE per giorno di entry.

    Usava FIFO su DB orders, ma non vedeva le chiusure automatiche di Bybit TP/SL

    (es. WIF 10765 chiusa da TP ma DB diceva ancora aperto). Sostituita da

    compute_entries_by_day (aperture totali per giorno) che è piu' utile per Mattia.

    Mantenuta per retrocompatibilita' se Mattia la vuole di nuovo.

    r   r/   rU  rW  r   r+  r  rL  )rW  r+  rC   c                      dg dS )Nr   )r  r  r   r   rL   r,   r   z5compute_open_positions_by_entry_day.<locals>.<lambda>n  s    qR!8 rL   r   avgPricezN/Dc                 &    | j                  dd      S )NrC   r/   r3  r  s    r,   r   z5compute_open_positions_by_entry_day.<locals>.<lambda>  s    quuT2 rL   r   rC   Nr5   r  r   r  rq  rr  rs  rt  ru  Tri  r  rw  )r   rm   r&   r   r  r  r   r  rF  r  r   rk  r  )bybit_positions	db_ordersr  buys_by_symbolr  rd  rU  rW  r+  rl  rh  r   	avg_pricebuysrx  last_buyr  r-  s                     r,   #compute_open_positions_by_entry_dayr  @  s.    !&N eeHb!fb!'R..0	eQ,1-C!%%+0q1E !8uz5=3&&UeeL"-	( -< 89F Nggh#3776?+
 34	dai!!#r*C 4%>?H<<b)/R"5CsCAsI%%RT{!Ic?!&LM=N@ CfkkmT2 3K

3yy9.
 		 JI :& 		s   >G--H ?H c                 
   t        |       }|D cg c]  }|j                  dd      dkD  s| }}|j                  d d       |d| }i }| D ]N  }|j                  dd      }|j                  d	|j                  dd            }	|	dk  s=||vs	|	||   k  sJ|	||<   P g }
|D ]=  }|j                  d      |v st        |      }||d      |d
<   |
j	                  |       ? |
j                  d        |
d| }||dS c c}w )ae  Top N best (asset con pnl > 0, ordinati per pnl desc) + Top N worst

    (asset che hanno ALMENO 1 singola loss, ordinati per worst_single_loss asc).



    FIX 07/08: prima il 'bad' richiedeva len(by_asset) > top_n, quindi con <= 5 asset

    il worst restava vuoto anche se c'erano loser.

    FIX 07/08 (2): il 'best' filtra solo asset con pnl > 0.

    FIX 07/08 (3): il 'worst' ora include asset che hanno almeno 1 singola loss,

    indipendentemente dal pnl aggregato. Cosi' VIRTUAL (pnl aggregato +18.47) compare

    perche' ha una loss singola da -25.47. Ordinato per worst_single_loss ascendente.

    r]  r   c                 &    | j                  dd      S )Nr]  r   r3  r  s    r,   r   z,compute_top_bad_from_bybit.<locals>.<lambda>  s    quuUA rL   Tr'  Nr   r/   r\  worst_single_lossc                 &    | j                  dd      S )Nr  r   r3  r  s    r,   r   z,compute_top_bad_from_bybit.<locals>.<lambda>  s    !%%(;Q"? rL   r   )topbad)r8  r&   r  r   r  )r  top_nr7  rW   winnersr  asset_worst_lossr  rd  r]  
worst_lista2r  s                r,   compute_top_bad_from_bybitr    s9   , +=9H #:QaeeE1o&9q:G:LL.L=
&5/C  
,eeHb!eeIquuUA/7**c4DS4I.I(+ %
, J "55?..aB&6q{&CB"#b!" OO?O@
Ve
Cs##Y ;s
   D D c                    | D cg c]*  }|j                  d|j                  dd            dk  s)|, }}|j                  d        g }|d| D ]  }t        |j                  d      xs |j                  d            }|j                  |j                  d	d
      |j                  dd
      |j                  dd      |j                  dd      |j                  dd      |j                  d|j                  dd            |j                  dd      |j                  dd      |r|j	                  d      nd
d	        |S c c}w )zTop N peggiori trade SINGOLI (per pnl_net ascendente).

    FIX 07/08: serve perche' VIRTUAL aggregato e' +18.47 ma ha una singola loss -25.47

    che non comparirebbe mai in 'by_asset' worst. Mostra le singole chiusure peggiori.

    r\  r]  r   c                 F    | j                  d| j                  dd            S )Nr\  r]  r   r3  r  s    r,   r   z+compute_top_single_losses.<locals>.<lambda>  s    aeeIquuUA? rL   r   Nr[  rL  r   r/   rU  rW  rY  ru  rv  rw  r<  )	r   rU  rW  rY  ru  r\  rv  rw  date_fmt)r&   r  rF   r  rH   )r  r  r  losersr  rJ   s         r,   compute_top_single_lossesr    s%    'PA!%%	155?*Ka*OaPFP
KK?K@
CFU^ QUU<0GAEE,4GH

eeHb)EE&"%55?552%%a0uuYeQ8{A.55?9;$45%
 		4 JA Qs
   *EEc           	         | j                         }t        dz  }t        dz  }t        dz  }t        dz  }ddl}ddd	d
dd}g }||||fD ]  }	|	j                         s	 t	        |	dd      5 }
|j                  |
      }|D ]  }|j                  d      s|d   j                         j                         |k(  s:t        |j                  dd            j                         dk(  sg|j                  dd      j                         j                         }|dk(  rd}|j                  |d      }|j                  ||f        	 ddd        |sy|j                  d d       |d   d   S # 1 sw Y   +xY w# t        $ r Y >w xY w)a  Replica la logica di sltp_engine.get_strategy_for_symbol per le 4 strategie v2.

    FIX 11/08 (Mattia): scorre TUTTI i CSV e ritorna lo strategy con priorita' piu' alta.

    Priorita': rsi_swing_breakout > rettangolo_simple > rettangolo > ma_trailing > vptr3.

    Necessario perche' WIFUSDT e' sia in rettangolo_assets.csv (strategy=rettangolo) che

    in RETTANGOLO_SIMPLE_ASSETS.csv (strategy=rsi_swing_breakout), e la versione specifica

    RSI swing deve avere priorita' sulla generica rettangolo.zVPTR_V3_ASSETS.csvzrettangolo_assets.csvzRETTANGOLO_SIMPLE_ASSETS.csvzMA_TRAILING_ASSETS.csvr   Nrl  (   r     r5   )r  r  r  r  r  r  rX   rY   r   enabledtruer   r/   r  r  r  c                     | d   S )Nr   r   r  s    r,   r   z)get_strategy_for_symbol.<locals>.<lambda>x  s
    !A$ rL   Tr'  r   )r  r   csvr   ra   
DictReaderr&   r!   r;   r   r  r'   r  )r   rd  	vptr3_csvrett_csvrett_simple_csvma_csvcsvmodPRIORITYr  csv_pathre   readerr   rD   prios                  r,   r  r  "  s    ,,.C++I--H;;O,,F !H J/6B " 	hg6 9!**1-! 9C778, 8}**,224;swwy&9:@@BfL #
B 7 = = ? E E GA I~$+#+<<1#5D&--tQi8%9	9"H  OOO5a=I9 90  		s8   E;-AE/;,E/(AE/E;/E8	4E;;	FFc            	      ~   ddl } t        dz  }|j                         si S 	 t        |dd      5 } | j                  |      }|j                         D ci c]5  \  }}t        |t              s|j                         |j                         7 c}}cddd       S c c}}w # 1 sw Y   yxY w# t        $ r i cY S w xY w)a]  FIX 11/08 (Mattia): per le POSIZIONI LIVE, legge un mapping esplicito

    symbol -> strategy per gestire il mismatch tra CSV e SOURCE Pine.

    Caso tipico: WIF ha chart Pine TV = RSI swing MA le posizioni live sono state

    aperte da Python (SL/TP engine) con strategy=rettangolo. Il CSV dice rsi_swing

    ma la SOURCE reale e' Python/rettangolo. Stessa cosa per AERO (VPTR3 senza SL/TP).

    File: live_deploy_v2/position_strategy_override.json

    Formato: {"WIFUSDT": "rettangolo", "AEROUSDT": "vptr3"}

    Se il symbol non e' nel file, fallback a get_strategy_for_symbol (CSV con priorita').r   Nzposition_strategy_override.jsonr  rX   rY   )rj   r   r   ra   loadr   rl   r;   r  r   r'   )rj   r  re   rn   r*   r+   s         r,   get_position_strategy_overrider    s    $ 33D;;=	
$g. 	Y!499Q<D59ZZ\XTQZPQSVEWAGGIqwwy(X		Y 	Y Y		Y 	Y  	sF   B. &B"B.!BB"	B. B""B+'B. +B. .B<;B<c                 D    	 t        |       d| dS # t        $ r Y yw xY w)Nz,.re   z0.00r  r'   r+   decimalss     r,   rz  rz    s0    (2hZq.)*     	c                 D    	 t        |       d| dS # t        $ r Y yw xY w)Nrr   re   z0.0r  r  s     r,   _fmt_pctr    s0    (1XJa-() r  c                 D    	 | t        |       S |S # t        $ r |cY S w xY wr  r  )r+   r   s     r,   rF  rF    s.    =uQx5g5 s     c                 h   | syt        |       dk(  rt        | d         S t        |       dz
  t        |      z  }t        t        j                  |            }t        t        j
                  |            }||k(  rt        | |         S ||z
  }t        | |         d|z
  z  t        | |         |z  z   S )z<Percentile lineare deterministico, senza dipendenze esterne.r  r   r   r_  )r=   r  r>   r)  floorceil)sorted_values
percentilepositionr   r  weights         r,   _percentiler    s     
=Q]1%&&M"Q&%
*;;H

8$%E		(#$E~]5)**Fu%&#,7%e@T:UX^:^^^rL   c           
      "   	 t        dt        t        t        |                         }t        |d      \  }}t        |d      \  }}t        |d      \  }}|r| d| d| dS |r| d| dS |r| d	| d
S | d
S # t        t
        f$ r Y yw xY w)Nr   rv  iQ i  <   zg zh mzm rD   )r  r>   roundr  r  r   divmod)secondsr#  r  	remainderr[  minutessecss          r,   _fmt_durationr    s    As5w012 UE*OD)i.E99b)MGTr%7)1--7)1%%"TF!$$V1:- z" s   'A< <BBc                    g }t        t              }t        d       }g }g }d}| D ]y  }t        |j                  d            }t        |j                  d      xs |j                  d            }	||	|	|k  r|dz  }Z|	|z
  j	                         }
|j                  |
       t        |j                  d      xs d	      }t        |j                  d
      xs d	      j                         }||   j                  |
       |||f   }|d   j                  |
       t        |j                  d|j                  dd                  }|dkD  r'|j                  |
       |d   j                  |
       N|dk  sU|j                  |
       |d   j                  |
       | t        |      }d }g }t        |j                               D ]#  \  }} ||      }||d<   |j                  |       % g }t        |j                               D ]  \  \  }}}t        |d         }|d   }|d   }|j                  ||t        |      t        |      t        |      z  t        |d      |d   |d   t        |d      t        |d      t        |d      |rt        |      t        |      z  nd|rt        |      t        |      z  ndd        t        |       t        |      ||rt        |      t        |      z  ndt        |d      |r|d   nd|r|d   ndt        |d      t        |d      t        |d       ||       ||      ||dS )zIDurata apertura->chiusura per tutti i trade classificati inclusi nei KPI.c                      g g g dS )N)allr  r  r   r   rL   r,   r   z.compute_trade_duration_stats.<locals>.<lambda>  s    B2QS,T rL   r   rZ  r[  rL  Nr   r   unknownr   r  r\  r]  r  r  c                     t        |       } | sddddS t        |       t        |       t        |       z  t        | d      dS )Nr   r  )r  avg_secondsmedian_seconds      ?)r   r=   r  r  )r   s    r,   summaryz-compute_trade_duration_stats.<locals>.summaryR  sH    scJJ [v;V4)&$7
 	
rL   r  r         ?      ?g?)r   r   r  r  r  min_secondsmax_secondsp25_secondsp75_secondsp90_secondswinner_avg_secondsloser_avg_secondsr  )total_countr  missingr  r  r  r  r  r  r  r  r  by_strategyby_strategy_asset)r   rm   rF   r&   total_secondsr  r;   r  rF  r   r   r=   r  r  )r  samplesr  r  r  r  r  rA  r  ru  durationr   r   asset_bucketr]  orderedr  
strategiesr   r   strategy_assetsbuckets
win_valuesloss_valuess                           r,   compute_trade_duration_statsr    sI    Gd#K#$TUGFG &4 <!89 <!8!SEIIl<ST>V^vqLGVO224x uyy,9	:UYYx(5I6<<>H$$X.((F);<U""8,%))Iuyy/BCD7NN8$#**841WMM(#"))(3M&4T WoG
( J";#4#4#67  &v#Z$  O'-.?.E.E.G'H "#6G'Y'
h' [v;V4)&$7!!9!":&vt4&vt4&vt4GQ#j/C
O"CW[HS[!1C4D!DY]1 
 	"P =)W6=s7|c'l23%gt4%,wqz#&-wr{3"7D1"7D1"7D17#&/!,9 rL   c           !      6Q   !"#$% | d   }| d   }| d   }| d   }| j                  di       }| j                  di       }| j                  di       }| d   d	   }| d   d
   }	| d   }
| d   }| d   }| d   }| j                  dg       }| j                  dg       }t        t        |             }t        t        |             }|rg }|D ]  }|j                  d|j                  dd            }|dkD  rdn|dk  rd
nd}|j	                  d|j                  dd       d|j                  dd       d|j                  dd       d|j                  dd       d| dt        |       d        dt        |       d dj                  |      z   d!z   }nd"}|rg }|D ]  }|j                  d|j                  dd            }|j	                  d|j                  d#d       d|j                  dd       d|j                  dd       d|j                  d$d       d|j                  dd       d|j                  d%d       d&t        |       d        d't        |       d(dj                  |      z   d!z   }nd}d}d}|d)   dk\  rdnd
}|d*   dk\  rdnd
}|d+   dkD  rd,nd}|d-   dk\  rdnd
}|d.   dk\  rdnd
}|d/   d0k\  rdn|d/   d1k  rd
nd}|d2   dk\  rdnd
}|j                  d3d4      }|d5k\  rd} n|d6k\  rd} n
|d7k\  rd} nd
} |d8k  r|d9nd:}!|j                  d;d      }"|j                  d<d      }#|"rd=|" d>nd?}$d4}%d4}&d}'d}(d})d}*|d*   }+|d+   },d,}|d@   }-d
}.|dA   }/|/dk\  rdnd
}0|/|-z   |,z   }1|1dk\  rdnd
}2|j                  dBd      }3|j                  dCd      }4|4dkD  r|3|4z  }5|5d9}6|5d5k\  rd}7n|5d7k\  rd}7nd
}7nd:}6d}7|d-   }8|8dk\  rdnd
}9|/|8z   }:|:dk\  rdnd
};|j                  d<d      xs d}#t        |#dD      }<|j                  dEd      rt        |j                  dEd      |<z  dF      nd}=|j                  dGd      |<z  }>|:|<z  }?|?dk\  rdnd
}@dH}A|?|Az  dIz  }B|Bdk\  rdnd
}C|:Az  dIz  }D|Ddk\  rdnd
}Edj                  g dJt        A|:z          dK|E dLDd9dM|dE    dN|$ dO|# dP| dLt        |d/          dQ|dB    dR|dC    dS|7 dL|6 dT|  dL|! dU|2 dLt        |1       dV| dWt        |,       dXt        |-       dY|0 dLt        |/       dZ|9 dLt        |8       d[|; dLt        |:       d\| dLt        |d2          d]t        |d^          d_|d`    da|= dbt        |>       dcC dLBd9dd@ dLt        |?       det        |df          dg|dh   d9di      }Fg }Gg }Hdj }I|j                  dg       D ]  }Jt        |Jdk         }Kdj                  dl |KD              }Ldm|L }MGj	                  dn|M d I|Kj                                do|Jdp    dt        |Jdq          dt        |Jdr          ds       g }N|j                  dtg       D Ocg c]%  }Ot        |Oj                  dk      xs d      Kk(  rO' }P}O|Pj                  du dvw       |PD ]  }Q|Qj                  dx      }R|Qj                  dy      }SNj	                  dz I|Qd          d{|Qdp    dt        |Qdq          dt        |Qdr          dt        |Qd|          dt        |Qd}          dt        |Qd~          dt        |Qd          dt        |Qd          d|Rt        R      nd dSt        S      nd ds        Hj	                  dM d IKj                                dJdp    dt        |Jdq          dt        |Jdr          ddj                  N      z   dz           dj                  g d|j                  d|j                  dpd      |j                  dd      z          d|j                  dpd       d|j                  dd       dt        |j                  dqd             dt        |j                  drd             dt        |j                  d|d             dt        |j                  d}d             dt        |j                  d~d             dt        |j                  dd             dt        |j                  dd             dt        |j                  di       j                  dqd             d|j                  di       j                  dpd       dt        |j                  di       j                  dqd             d|j                  di       j                  dpd       ddj                  G       ddj                  H       d      }T|d   dkD  r|d   }U|d   }V|U}Wt        |W      dFk\  rt        W      t        |W      }Y}Xt        |Y|Xz
  d      }Zd\  }[d}\g }]t        |W      D ]Q  \  }^}_\|^t        W      dDz
  z  [dF|\z  z
  z  z   }`|\z
  |_Xz
  Zz  dF|\z  z
  z  z
  }a]j	                  |`dd|ad       S dj                  ]      }bd}cWd   }d|Wd   }e|d|ez
  }f|edk7  rft!        e      z  dIz  nd}gfdk\  rdnd}hd}it        W      }jt        t#        ]|W            D ]  \  }k\  }l}m|lj%                  d      \  }n}o|kt        V      k  rVk   nd}pdkdDz    }q|prL	 t'        p      }r|rdkD  rrdz  }rddlm}sm}t |sj-                  r|tj.                        }u|uj1                  d      }qmWd   z
  }v|Wd   dk7  rvt!        Wd         z  dIz  nd}wdqj5                  dd      j5                  dd      z   dz   }xidn do dh dkdDz    d|x dmd9dvd9d|wd9d|kdDz    d|q d|md9dz  }i
 g }ydD ].  }zX|zZz  z   }{\z
  |zdF|\z  z
  z  z
  }|yj	                  |{||f       0 d}}d}~yD ]3  \  }{}|~d\ d||dd[|\z
   d||dd	z  }~}d|\dFz
   d||dz   dd|{d9dĝz  }}5 t        U      }|dk\  rddz  dF|z  dz  |dDz
  gnt7        t9                    }d}d}|D ]  }\|t        dDz
  dD      z  [dF|\z  z
  z  z   }`|t        V      k  rV   nd}pd}q|prJ	 t'        p      }|dkD  rdz  }ddlm}m} |j-                  |j.                        j1                  d      }qd`dd\ d|`dd|\z
   dƝ	z  }dk(  rdndDz
  k(  rdnd}|dk(  r`dFz   ndk(  r`dFz
  n`}d|dddz    d dq dĝ	z  } bd]d   j%                  t;        dͫ            d    d\z
   d|\ d|\z
   z   }ZdkD  r\z
  dXz
  Zz  dF|\z  z
  z  z
  n\z
  }dj                  g dΑ[ ddz    dБdz    dё~  dґ dӑh dԑ\ d|dd|[|\z
   d|ddՑb d֑|h dבi dؑ]d   j%                  t;        dͫ            d    d|]d   j%                  t;        dͫ            dD    dّ|h dڑ}  dۑWd   dܛdݑ|h dޑddܛdߑgdܛdt        |W       d|h d      }nUd   }_d|_d9d}t=        j>                  |      }nd}t=        j>                  g g g d4d4d      }|rg }g }d }|D ]  }|d   dk\  rdnd
}t        dk         }Kdj                  d |KD              }Ld|L }Mj	                  d|M d |K       do|d    d|dB    dt        |d/          dt        |d          dt        |d          d| dt        |d          d       g }|j                  |Kg       D ]  }|d   dk\  rdnd
}j	                  d |d          d ||d          d ||d          d ||d          d|d   dd|d   dd|d   ddt        |d          dt        |d          d| dt        |d          d ||d          d        d dj                        z   d!z   }j	                  dM d K       dd    d|dB    dR|d   |dB   z
   dt        |d/          dt        |d          dt        |d          d dt        |d          d	| d
        tA        d |D              }tA        d |D              }|rz  dIz  nd4}tA        d |D              }tA        d |D              }tA        d |D              }|dk\  rdnd
}dk\  rdnd
}j	                  d d dt               d dt               dt               d| dt               d       ddj                  |      z   dz   dj                        z   }nd}|rg }|D ]  }|d   }|j                  dd4      }|j                  dd4      }|dk   }|dk7  r!j5                  dd      jC                         nd}dFk\  rWd7k\  rdndk  rd
nd}d6k\  rdndk  rd
nd}d}d}d d ddB    d||dB   z
   d|d/   dd|d   d9d }ndx}}d!x}}d d d"}j	                  d# d$ d d% d& d' d( d)        d*dj                         d+}nd,}|r?g }g }d- }|D ]  }|d   dk\  rdnd
}t        d         j                         }dj                  d. |D              }d/| }Mj	                  d0|M d |       do|d    d|dB    dt        |d/          dt        |d          dt        |d          d| dt        |d          d       g }|j                  |g       D ]  }|d   dk\  rdnd
}j	                  d |d          d ||d          d ||dk          d ||d          d|d   dd|d   dd|d   ddt        |d          dt        |d          d| dt        |d          d ||d          d        d1dj                        z   d!z   }j	                  dM d2        dd    d|dB    dR|d   |dB   z
   dt        |d/          dt        |d          dt        |d          d dt        |d          d	| d
        d3dj                        z   dz   dj                        z   }nd4}d5 } ||d      } ||	d
      }| j                  d6g       }|rg }D ]  }j	                  d|j                  d7d       d|j                  dd       d|j                  d8d       d|j                  dd      d9d|j                  d:d      d;d|j                  d<d      d;d=|j                  dd      d9d>|j                  dd      d9ds        d?dj                        z   dz   }nd@}| j                  dAg       }|rlg }d}D ]2  }|d   z  }j	                  d|dB    dC|d    dD|dE    d       4 j	                  dF dG       dHdj                  |      z   dz   }ndI}|
j                  dJt9        dK      D cg c]	  }dgdLz   c}      #|
j                  dMt9        dK      D cg c]	  }dgdLz   c}       |
j                  dNt9        dK      D cg c]	  }d4gdLz   c}      |
j                  dOt9        dK      D cg c]	  }d4gdLz   c}      |
j                  dPt9        dK      D cg c]	  }d4gdLz   c}      !t9        dK      D cg c]-  }t9        dL      D cg c]  }#   |    |   |   z    c}/ c}}"dQ}tE        dR "D              r#"rt        dS "D              ndD}t        |dD      }g }dTg}|
dU   D ]  j	                  dVdWdX        j	                  dYdj                        z   dZz          t        |
d[         D ]  \  }}d\| d]g}t9        dL      D ]h  #      }[ |      }|[dk(  rdk(  rj	                  d^       3dkD  r[z  nd}dkD  rz  nd}tG        d_d0z  z         }tG        d`da|z  z         }tG        dbdc|z  z         }Đdd| d|Û d|ě d>}tG        d_de|z  z         }tG        d`df|z  z         }tG        dbd0|z  z         }Ȑdd|ƛ d|Ǜ d|ț d>} ddWdg[ dh }|dk(  r!j	                  diś djʛ dk[ dl       [dk(  r!j	                  diɛ djʛ dm dl       2dnś do|ś dpɛ dp|ɛ dq	}j	                  dr|˛ djʛ dk[ ds dl	       k j	                  dYdj                        z   dZz           dt}̐dudj                        z   d!z   |z   }͐dv g }t        |
d[         D ]s  \  }}tA        "|         }|sj	                  tA        #|         tA         |         tA        |         tA        |         tA        !|         dw       u g }t9        dL      D ]  tA        "fdxt9        dK      D              }|s'j	                  dWdytA        #fdzt9        dK      D              tA         fd{t9        dK      D              tA        fd|t9        dK      D              tA        fd}t9        dK      D              tA        !fd~t9        dK      D              d        t        ΐd       }t        |ΐd       }t        ϐd       }t        |ϐd       }Ӑd|Аd    dt        |d          d|ѐd    dt        |d          d|Ґd    dt        |d          d|Ӑd    dt        |d          d}Ԑd}g d%d $tI        t6              }|jK                         D ]O  \  }K}|D ]E  }	 t)        jL                  |d   d      }jU                            j	                  i |dkKi       G Q jW                         D ]  }|j                  d dvw        $%fdg }D ]  }J|Jd   }|Jd   dk\  rdnd
}g }j                  g       D ]  }|d   dk\  rdnd
}j	                  d $|d          d $|d          d $|d          d $t        |dk         j                                d $|d          d|d   dd|d   dd|d   ddt        |d          dt        |d          d| dt        |d          d $|d          d        j	                  d d $%|          dJd    d|JdB    dR|JdC    d|JdB   |Jd   z  dIz  ddt        |Jd          dt        |Jd          d dt        |Jd          ddj                        z   dz           dj                  fdD              }dj                  fdD              }Ԑdz   z   |z   dz   |z   |z   dz   dj                  ٫      z   }nd}| j                  dg       }|ܐrLg }D ]r  }|d   dk\  rdnd
}j	                  ddB    d|d    d|dB    d|d/   ddt        |d          dt        |d          d| dt        |d          d|dE    d       t tA        d D              }tA        d |D              }tA        d |D              }tA        d |D              }tA        d |D              }|rz  dIz  nd}dk\  rdnd
}j	                  d d dddt        ݫ       dt        ޫ       d| dt        ߫       d       ddj                  |      z   dz   }nd}d}ܐr~t        ܫ      dDk\  rotY        ܐd       }t        |      }|D cg c]  }|d   	 }}g }d4}|D ]  }_|_z  }j	                  |        t        t              d      }t        t        |      d      }t        ||z
  d      }||dz  z   }||dz  z
  }||z
  }t        t              d      }t        t        |      d      }t        ||z
  d      }||dz  z   }||dz  z
  }||z
  }d\  }[d\  }}}}|[|z
  |z
  }|z
  |z
  }g }dDkD  r.t9              D ]  }^j	                  |^dDz
  z  z  z          ! nj	                  dFz  z          t        t        dD      z  dz  dF      }d}t        t#                    D ]q  \  }^\  } }dDt        |d      z
  z  z
  z  z   }|dDt        |d      |z
  |z  z
  |z  z   }|dDd|z
  |z  z
  |z  z   }|dk\  r}}d}hn
}}d}hs g }t        t#                    D ]6  \  }^\  } }dD|z
  z  z
  z  z   }aj	                  | dd|ad       8 dj                        }	g }
t        t#                    D ]6  \  }^\  } }dD|z
  z  z
  z  z   }a
j	                  | dd|ad       8 dj                  
      }g }dD ])  }z|zz  z   }{dD|zz
  z  z   }|j	                  |{||f       + d}d}~D ]7  \  }{}|~d d||dd[z
   d||dd	z  }~d|dz
   d||dz   dd|{dܛdĝz  }9 g }dD ])  }z|zz  z   }{dD|zz
  z  z   }|j	                  |{||f       + d}D ]#  \  }{}|d[z
  dz    d||dz   dd|{dܛdĝz  }% d}dkD  r)t        dDdz        }t7        t9        d||            }nt7        t9                    }D ]0  }|k  s	   }`d|`ddz
  dz    d|   dB   dd   dĝz  }2 rd   j%                  d      nddg}d[ d dЉ d~ d d	 d|d    d|dD    d   d dd   dܛd}|rg }|D ]  }|d   dk\  rdnd
}j	                  dd    dC|dk    d{|d    d|d8   j[                          d|d8    d|d    d|d    d|d    d|d    d| d|d    dŐ|d    dǝ        ddj                        z   dz   }ndɐ}|r5g }|D ]  }|j                  dʫ      rdnd}j                  dd      }|j                  dd      }|j                  d|j                  dd            }|dkD  rdn	dk  rd
nd}j	                  dd    d|d    d|d8    d|d8    d|d    d|d     d|d    d|dk    dt               dt               d| dt               ds         r)dt               dҝdj                  |      z   dz   }n	dӐ}ndԐ}dj                  g dՑ| d֑| dב| dؑ| d| dّF dڑ dۑ dܑ dݑT dޑ dߑ d͛ d d d d d      }|S c c}Ow # t2        $ r prpd d ndkdDz    }qY hw xY w# t2        $ r t        p      d d }qY w xY wc c}w c c}w c c}w c c}w c c}w c c}w c c}}w # tN        tP        tR        f$ r Y Ow xY wc c}w (  Nkpisr	  r  r7  r   strategy_trade_detailstrade_duration_statstop_badr  r  heatmapr  recent_ordersgenerated_atr  operational_exclusionsr\  r]  r   goodr/   <tr><td>r[  	</td><td>r   r   r^  z</td><td class='pnl '> USDT</td></tr>zC<div class='classification-alert'><b>CLASSIFICAZIONE BLOCCATA:</b> z trade senza prova univoca. Sono inclusi nel PnL totale, ma esclusi dalle statistiche per strategia.<table><tr><th>Chiusura</th><th>Asset</th><th>Order ID</th><th>Motivo</th><th>Net</th></tr>z</table></div>z{<div class='classification-ok'><b>CLASSIFICAZIONE CERTIFICATA:</b> tutti i trade inclusi hanno una strategia provata.</div>rZ  r  r_  z</td><td class='pnl bad'>zB<div class='classification-alert'><b>TRADE OPERATIVI ESCLUSI:</b> z ingresso successivo al blocco asset. Visibile per audit, escluso da KPI, equity e classifiche.<table><tr><th>Entrata</th><th>Chiusura</th><th>Asset</th><th>Entry order ID</th><th>Close order ID</th><th>Motivo</th><th>Net</th></tr>r  r  r  r  r  r  r  rl  r  r  r  r  g       @g      ?r_  c   z.2fu   ∞r  r  zTrading days (dal ru  zTrading daysr  r  r  r  r   r  ru   r  g     @@rt  zi

  <div class="kpi"><div class="kpi-label">Saldo capitale (4.000 + Net P&L)</div><div class="kpi-value">z USDT</div></div>

  <div class="kpi kpi-roi"><div class="kpi-label">ROI su capitale iniziale (4.000 USDT)</div><div class="kpi-value ">zb%</div></div>

  <div class="kpi"><div class="kpi-label">Trade chiusi</div><div class="kpi-value">z8</div></div>

  <div class="kpi"><div class="kpi-label">z</div><div class="kpi-value">z\</div></div>

  <div class="kpi"><div class="kpi-label">Win rate</div><div class="kpi-value zB%<br><small style="color:#8b949e;font-size:11px;font-weight:400;">W / zhL</small></div></div>

  <div class="kpi"><div class="kpi-label">Win to Loss</div><div class="kpi-value za</div></div>

  <div class="kpi"><div class="kpi-label">Profit Factor</div><div class="kpi-value zf</div></div>

  <div class="kpi"><div class="kpi-label">Gross PnL (chiusi)</div><div class="kpi-value zc USDT</div></div>

  <div class="kpi"><div class="kpi-label">Fee totali</div><div class="kpi-value z">-zi USDT</div></div>

  <div class="kpi"><div class="kpi-label">Loss chiuse</div><div class="kpi-value bad">zv USDT</div></div>

  <div class="kpi"><div class="kpi-label">P&L Realized (Gross-Loss-Fee)</div><div class="kpi-value zg USDT</div></div>

  <div class="kpi"><div class="kpi-label">Unrealized PnL</div><div class="kpi-value zv USDT</div></div>

  <div class="kpi"><div class="kpi-label">Net P&L (Realized-Unrealized)</div><div class="kpi-value zb USDT</div></div>

  <div class="kpi"><div class="kpi-label">Avg trade</div><div class="kpi-value zi USDT</div></div>

  <div class="kpi"><div class="kpi-label">Best trade</div><div class="kpi-value good">r  zj USDT</div></div>

  <div class="kpi"><div class="kpi-label">Posizioni aperte</div><div class="kpi-value">r  zd</div></div>

  <div class="kpi"><div class="kpi-label">Trade al giorno</div><div class="kpi-value">zk</div></div>

  <div class="kpi"><div class="kpi-label">Nozionale Bybit/giorno</div><div class="kpi-value">ze USDT</div></div>

  <div class="kpi"><div class="kpi-label">Day Profit %</div><div class="kpi-value zb%/gg</div></div>

  <div class="kpi"><div class="kpi-label">Day Profit</div><div class="kpi-value zn USDT/gg</div></div>

  <div class="kpi"><div class="kpi-label">Drawdown real</div><div class="kpi-value bad">r  z	 USDT<br>r  z%</div></div>

c                 T    t        d      j                  t        | | nd      d      S Nrj  r/   Trh  r|  rk  r;   rl  s    r,   r   z"render_dashboard.<locals>.<lambda>0  s)    F!3!:!:3HYu_a;bjn!:!o rL   r   c              3   B   K   | ]  }|j                         s|  y wr  isalnumr  chs     r,   r  z#render_dashboard.<locals>.<genexpr>6  s     FrF   zduration-asset-detail-zJ<tr><td><button type='button' class='duration-strategy-link' data-dialog='</button></td><td>r  r  r  z
</td></tr>r  c                 &    | j                  dd      S )Nr  r   r3  r   s    r,   r   z"render_dashboard.<locals>.<lambda>N  s    TXXmQ%? rL   Tr'  r  r  <tr><td><b></b></td><td>r  r  r  r  r  rv  z<dialog id='zt' class='asset-dialog duration-asset-dialog'><div class='asset-dialog-head'><div><small>DURATA PER ASSET</small><h2>u   </h2></div><button type='button' class='dialog-close' aria-label='Chiudi' data-close-dialog>×</button></div><div class='asset-dialog-summary'><span>z trade</span><span>Media z</span><span>Mediana z</span></div><div class='asset-detail-scroll'><table><tr><th>Asset</th><th>Trade</th><th>Media</th><th>Mediana</th><th>Min</th><th>Max</th><th>P25</th><th>P75</th><th>P90</th><th>Media vincenti</th><th>Media perdenti</th></tr>z</table></div></dialog>zX

<div class="duration-grid">

  <div class="duration-card"><span>Trade totali</span><b>r  r  z</b><small>Durata disponibile: u    · Mancanti: zI</small></div>

  <div class="duration-card"><span>Durata media</span><b>z@</b></div>

  <div class="duration-card"><span>Mediana</span><b>zB</b></div>

  <div class="duration-card"><span>Min / Max</span><b>z</b><small>zF</small></div>

  <div class="duration-card"><span>P25 / P75</span><b>z@</small></div>

  <div class="duration-card"><span>P90</span><b>uV   </b></div>

  <div class="duration-card good-border"><span>Vincenti · media</span><b>r  u_    trade</small></div>

  <div class="duration-card bad-border"><span>Perdenti · media</span><b>r  z trade</small></div>

</div>

<table class="duration-table"><tr><th>Strategia</th><th>Trade</th><th>Media</th><th>Mediana</th></tr>u  </table>

<details class="duration-explanation">

  <summary>Come leggere P25, P75 e P90</summary>

  <div class="duration-explanation-body">

  <p>P25, P75 e P90 sono percentili della durata:</p>

  <ul>

    <li><b>P25:</b> il 25% dei trade è durato meno o uguale a questo valore. Il restante 75% è durato di più.</li>

    <li><b>P75:</b> il 75% dei trade si è concluso entro questa durata. Solo il 25% è durato di più.</li>

    <li><b>P90:</b> il 90% dei trade si è concluso entro questa durata. Solo il 10% ha superato quel valore.</li>

  </ul>

  <p><b>Esempio:</b> P25 = 30 minuti, P75 = 4 ore, P90 = 10 ore.</p>

  <p>Significa che:</p>

  <ul>

    <li>1 trade su 4 termina entro 30 minuti;</li>

    <li>3 trade su 4 terminano entro 4 ore;</li>

    <li>9 trade su 10 terminano entro 10 ore;</li>

    <li>soltanto 1 trade su 10 dura più di 10 ore.</li>

  </ul>

  <p>La fascia <b>P25–P75</b> rappresenta la durata del 50% centrale dei trade ed è meno influenzata da operazioni eccezionalmente lunghe rispetto alla media.</p>

  <p>Il <b>P90</b> è utile per stabilire quando un trade sta diventando insolitamente lungo. Non significa però che debba essere chiuso automaticamente: indica solamente che ha già superato la durata del 90% dei trade storici.</p>

  <p class="duration-warning"><b>Attenzione ai campioni piccoli:</b> se un asset ha uno o due trade, i percentili sono poco affidabili. Con un solo trade, P25, mediana, P75 e P90 coincidono tutti con la durata di quell’unica operazione.</p>

  </div>

</details>

z

r  r  r`  )i      r5   .1fr    r   z#3fb950z#f85149r   g   mBr6   r   r7   z%d/%m %H:%M   r   \z\\z\'z<circle class="eq-pt" cx="z" cy="z0" r="4" fill="#fff" fill-opacity="0.95" stroke="zJ" stroke-width="1.5" style="cursor:pointer" onmouseover="eqShowTip(event, r  zI)" onmousemove="eqMoveTip(event)" onmouseout="eqHideTip()"><title>Trade #z | z | PnL cum: z USDT</title></circle>
    )r  r  r  r  r_  z
<line x1="z" y1="z" x2="z" y2="z*" stroke="#21262d" stroke-width="1"/>
    z	<text x="z" y="   z\" text-anchor="end" font-size="11" fill="#c9d1d9" font-family="monospace" font-weight="600">z</text>
    r   zA" stroke="#21262d" stroke-width="1" stroke-dasharray="2,3"/>
    ry  endmiddler   z" text-anchor="zJ" font-size="11" fill="#c9d1d9" font-family="monospace" font-weight="600">,   zV<div style="background:#0d1117;padding:10px;border-radius:6px;">

  <svg viewBox="0 0    z>" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:zpx;">

    z<polygon points="z" fill="z'" fill-opacity="0.12"/>

    <line x1="zd" stroke="#8b949e" stroke-width="0.5" stroke-dasharray="2,2" opacity="0.5"/>

    <polyline points="z" fill="none" stroke="z" stroke-width="2"/>

    z

    <circle cx="z" r="4" fill="z	"/>

    z

  </svg>

  <div style="display:flex;justify-content:space-between;font-size:11px;color:#8b949e;margin-top:4px;">

    <span>Start: z+.2fz% USDT</span>

    <span style="color:z;font-weight:600;">End: z USDT (z%)</span>

  </div>

  <div style="display:flex;justify-content:space-between;align-items:center;font-size:11px;color:#8b949e;margin-top:2px;">

    <span>z trade chiusi</span>

    <span style="display:flex;gap:8px;align-items:center;">

      <span style="display:flex;align-items:center;gap:4px;"><span style="display:inline-block;width:16px;height:2px;background:a  ;"></span>Equity</span>

    </span>

  </div>

  <script>

  (function() {

    if (window._eqTipLoaded) return;

    window._eqTipLoaded = true;

    var t = document.createElement('div');

    t.id = 'eq-tooltip';

    t.style.cssText = 'display:none;position:absolute;background:#161b22;border:1px solid #30363d;color:#fff;padding:10px 14px;border-radius:6px;font-size:13px;pointer-events:none;z-index:10000;box-shadow:0 4px 12px rgba(0,0,0,0.5);font-family:monospace;line-height:1.5;';

    document.body.appendChild(t);

  })();

  function eqShowTip(e, n, date, eq, delta, deltaPct) {

    var t = document.getElementById('eq-tooltip');

    if (!t) return;

    var sign = delta >= 0 ? '+' : '';

    var pctSign = deltaPct >= 0 ? '+' : '';

    var color = delta >= 0 ? '#3fb950' : '#f85149';

    t.innerHTML = '<div style="font-weight:700;color:#fff;margin-bottom:4px;">Trade #' + n + '</div>' +

      '<div style="color:#8b949e;">Data: <span style="color:#c9d1d9;">' + date + '</span></div>' +

      '<div style="color:#8b949e;">Equity: <span style="color:#fff;font-weight:600;">' + eq.toFixed(2) + ' USDT</span></div>' +

      '<div style="color:#8b949e;">Delta: <span style="color:' + color + ';font-weight:600;">' + sign + delta.toFixed(2) + ' USDT (' + pctSign + deltaPct.toFixed(2) + '%)</span></div>';

    t.style.display = 'block';

    eqMoveTip(e);

  }

  function eqMoveTip(e) {

    var t = document.getElementById('eq-tooltip');

    if (t && t.style.display === 'block') {

      t.style.left = (e.pageX + 14) + 'px';

      t.style.top = (e.pageY + 14) + 'px';

    }

  }

  function eqHideTip() {

    var t = document.getElementById('eq-tooltip');

    if (t) t.style.display = 'none';

  }

  </script>

</div>zy<div style="background:#0d1117;padding:20px;border-radius:6px;text-align:center;color:#8b949e;">1 trade chiuso: equity = z USDT</div>uc   <div class="empty">Nessun trade chiuso dal 1° agosto. Aspetto chiusure Pine (Max exit bars).</div>)r  r	  r
  r  r  c                 T    t        d      j                  t        | | nd      d      S r  r  rl  s    r,   r   z"render_dashboard.<locals>.<lambda>  s)    Z%7%>%>sEL]5ce?fnr%>%s rL   c              3   B   K   | ]  }|j                         s|  y wr  r  r   s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     #J2RZZ\B#Jr  zstrategy-detail-zA<tr><td><button type='button' class='strategy-link' data-dialog='r  rq  zW)</td><td>z%</td><td class='pnl good'>rv  z</td><td class='pnl warn'>-r  rA  r  r=  r>  rW  ,.4fr  z,.6fr?  r@  z</td><td class='warn'>-rw  z</td><td><small>z</small></td></tr>z<div class='asset-detail-scroll'><table><tr><th>Apertura</th><th>Chiusura</th><th>Asset</th><th>Direzione</th><th>Qty</th><th>Entry</th><th>Exit</th><th>Gross</th><th>Fee</th><th>Net</th><th>Close Order ID</th></tr>zq' class='asset-dialog strategy-dialog'><div class='asset-dialog-head'><div><small>DETTAGLIO STRATEGIA</small><h2>z</h2></div><button type='button' class='dialog-close' aria-label='Chiudi' data-close-dialog>x</button></div><div class='asset-dialog-summary'><span>z trade</span><span>zL</span><span>WR z%</span><span>Gross z USDT</span><span>Fee -z USDT</span><strong class='z'>Net z USDT</strong></div>z	</dialog>c              3   &   K   | ]	  }|d      ywr  Nr   r  rD   s     r,   r  z#render_dashboard.<locals>.<genexpr>V  s     2af2r  c              3   &   K   | ]	  }|d      ywr  Nr   r  s     r,   r  z#render_dashboard.<locals>.<genexpr>X       8q68r  c              3   &   K   | ]	  }|d      ywrv  Nr   r  s     r,   r  z#render_dashboard.<locals>.<genexpr>\  s     >Q!K.>r  c              3   &   K   | ]	  }|d      ywr  Nr   r  s     r,   r  z#render_dashboard.<locals>.<genexpr>^  r  r  c              3   &   K   | ]	  }|d      ywr  r   r  s     r,   r  z#render_dashboard.<locals>.<genexpr>`  s     6Q%6r  zM<tr style='border-top:2px solid #58a6ff;font-weight:700;'><td>TOTALE</td><td>z%</td><td class='pnl zb<table><tr><th>Strategia</th><th>Trades</th><th>WR</th><th>Gross</th><th>Fee</th><th>Net</th></tr></table>z[<div class="empty">Nessun trade chiuso ancora. Aspetto chiusure Pine (Max exit bars).</div>r"  r#  r  rc  Unknownz.3fzStrategia: z
Trade: zW/zL)
WR: z%
Net: z USDT
Sharpe: mean/std (rf=0) - &gt;=1 buono, &lt;0 in perdita
Sortino: mean/downside_dev (rf=0) - &gt;=1.5 buono, &lt;0 in perditazn/az< trade: servono almeno 2 trade per calcolare Sharpe/Sortino)z<div class="kpi" title="z"><div class="kpi-label">zt)</div><div class="kpi-value z" style="font-size:18px;">Sh: z</div><div class="kpi-value z-" style="font-size:13px;margin-top:2px;">So: z</div></div>z<div class="kpi-grid">r  zw<div class="empty">Nessun trade chiuso ancora. Servono almeno 2 trade per strategia per calcolare Sharpe/Sortino.</div>c                 T    t        d      j                  t        | | nd      d      S r  r  rl  s    r,   r   z"render_dashboard.<locals>.<lambda>  s)    *V"4";";CIZ`b<cko";"p rL   c              3   B   K   | ]  }|j                         s|  y wr  r  r   s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     !F"!Fr  zasset-detail-z><tr><td><button type='button' class='asset-link' data-dialog='z<div class='asset-detail-scroll'><table><tr><th>Apertura</th><th>Chiusura</th><th>Strategia</th><th>Direzione</th><th>Qty</th><th>Entry</th><th>Exit</th><th>Gross</th><th>Fee</th><th>Net</th><th>Close Order ID</th></tr>z]' class='asset-dialog'><div class='asset-dialog-head'><div><small>DETTAGLIO ASSET</small><h2>z_<table><tr><th>Symbol</th><th>Trades</th><th>WR</th><th>Gross</th><th>Fee</th><th>Net</th></tr>3<div class="empty">Nessun trade chiuso ancora</div>c                    | syg }| D ]  }|j                  dd      }|j                  d      }|dk(  r5|3d}dt        |       dt        |       d}d	| d
| dt        |       d}n"|dkD  rdn|dk  rdnd}	d	|	 dt        |       d}|j                  d|d    d|d    dt        |d          d| d	        ddj	                  |      z   dz   S )a@  FIX 07/08: colore PnL DINAMICO basato sul segno (verde se >0, rosso se <0).

        cls_color indica sezione ('best' o 'worst'). Per Worst, se l'item ha

        'worst_single_loss', mostra quella al posto del pnl aggregato (perche'

        un asset puo' avere pnl aggregato positivo ma loss singola grossa).

        r#  r]  r   r  r  ztitle="Worst single: z USDT | PnL aggregato: z USDT"z<td class="pnl z" rp  z
 USDT</td>r  r/   r  r  r   r  r  r  z%</td></tr>zE<table><tr><th>Symbol</th><th>Trades</th><th>WR</th><th>PnL</th></tr>r  )r&   rz  r  r  r  )
r   	cls_colorr=  rW   r  wslwsl_clstitlepnl_cellrow_clss
             r,   
_top_tablez$render_dashboard.<locals>._top_table(  s%    H 	yAeQA %%+,CE!co  030@@WXabcXdWeelm,WIRwa	#?OzZ %&E&QB,WIR	!~ZPKK(1X;-y3	(STU^S_J`Iaaghpgqqvwx5	y8 WY[Y`Y`aeYffisssrL   single_lossesr  rU  ,.2frY  ,.5fru  z</td><td class="pnl bad">z  USDT</td><td class="pnl warn">-z|<table><tr><th>Data</th><th>Symbol</th><th>Side</th><th>Qty</th><th>Entry</th><th>Exit</th><th>Net PnL</th><th>Fee</th></tr>z><div class="empty">Nessuna singola loss. Vai tranquillo.</div>open_by_dayrj  z</td><td><b>z</b></td><td><small>r  zM<tr style="border-top:2px solid #58a6ff;font-weight:600;"><td>TOTALE</td><td>uL   </td><td><small>aperture totali (entry Buy) dal 1° agosto</small></td></tr>zS<table><tr><th>Data Entry</th><th>N. Aperture</th><th>Symbols (qty@price)</th></tr>z5<div class="empty">Nessuna apertura registrata.</div>r\  rR  rS  r]  r^  r_  r`  z;<div class="empty">Nessun dato statistico giorno/ora.</div>c              3   8   K   | ]  }t        |      d kD    yw)r   N)r  r  r   s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     
.C3s8a<
.s   c              3   2   K   | ]  }t        |        y wr  )r  r2  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     7SC7s   z'<th class='hm-corner'>Giorno / Ora</th>r[  z<th class='hm-h'>02dz:00</th>z<tr>r%  r  z<th class='hm-d'>z</th>z5<td class="hm-c hm-empty" title="Nessun trade">-</td>            9   zrgb(   @   z
:00 - Win z, Loss z#<td class="hm-c" style="background:z
;" title="z"><span class="hm-win">W z</span></td>z"><span class="hm-loss">L zlinear-gradient(to right, z 0%, z 50%, z 100%)z,<td class="hm-c hm-mixed" style="background:z</span><span class="hm-loss">L z<div class="hm-legend"><span><i class="hm-key hm-key-win"></i>W = trade positivi</span><span><i class="hm-key hm-key-loss"></i>L = trade negativi</span><span>Scorrere orizzontalmente per tutte le 24 ore</span></div>z)<div class='hm-scroll'><table class='hm'>c                     |r||z  dz  nd}|r||z  nd}|dk\  rdnd}	d|  d| d| d	| d
|ddt        |       dt        |       d|	 dt        |       d|	 dt        |       dS )Nrt  r  r   r  r  r  r  r  r  
L</td><td>r  
%</td><td> USDT</td><td class='warn'>- USDT</td><td class='pnl r  r  rz  )
labelr  r  r  r@  r  rA  r.  avgclss
             r,   _period_rowz%render_dashboard.<locals>._period_row  s    %&$(S.CB 37cC1H&%C!%aS	$tF8 Tc(*Yu-=,> ?))24(9 :&&)U"Ys^,< =&&)U"Ys^,<OM NrL   )	day_indexrB  r  r  r  r@  r  rA  c              3   .   K   | ]  }|        y wr  r   )r  r-  h
matrix_tots     r,   r  z#render_dashboard.<locals>.<genexpr>.  s     7JqM!$7r   z:00c              3   .   K   | ]  }|        y wr  r   )r  r-  rH  r\  s     r,   r  z#render_dashboard.<locals>.<genexpr>6  s     A1AAr   c              3   .   K   | ]  }|        y wr  r   )r  r-  rH  r]  s     r,   r  z#render_dashboard.<locals>.<genexpr>6  s     PrdeQYZ[Q\]^Q_Prr   c              3   .   K   | ]  }|        y wr  r   )r  r-  rH  r^  s     r,   r  z#render_dashboard.<locals>.<genexpr>8  s      Fa!3 Fr   c              3   .   K   | ]  }|        y wr  r   )r  r-  rH  r_  s     r,   r  z#render_dashboard.<locals>.<genexpr>8  s     SxjkT_`aTbcdTeSxr   c              3   .   K   | ]  }|        y wr  r   )r  r-  rH  r`  s     r,   r  z#render_dashboard.<locals>.<genexpr>:  s     BAz!}Q/Br   )rB  r  r  r  r@  r  rA  c                     | d   S NrA  r   r  s    r,   r   z"render_dashboard.<locals>.<lambda>@  s
    % rL   r   c                     | d   S rP  r   r  s    r,   r   z"render_dashboard.<locals>.<lambda>B  s
    5 rL   c                     | d   S rP  r   r  s    r,   r   z"render_dashboard.<locals>.<lambda>D  s
    !E( rL   c                     | d   S rP  r   r  s    r,   r   z"render_dashboard.<locals>.<lambda>F  s
    1U8 rL   zE<div class="period-highlights"><div><small>GIORNO MIGLIORE</small><b>rB  z</b><span class="good">z8 USDT</span></div><div><small>GIORNO PEGGIORE</small><b>z</b><span class="bad">z5 USDT</span></div><div><small>ORA MIGLIORE</small><b>z5 USDT</span></div><div><small>ORA PEGGIORE</small><b>z USDT</span></div></div>zx<tr><th>Periodo</th><th>Trade</th><th>W/L</th><th>WR</th><th>Gross</th><th>Fee</th><th>Net</th><th>Media/trade</th></tr>)u   Lunedìu   Martedìu
   Mercoledìu   Giovedìu   VenerdìSabatoDomenicac                 T    t        d      j                  t        | | nd      d      S r  r  rl  s    r,   r   z"render_dashboard.<locals>.<lambda>\  s)    Jv$6$=$=c5K\%bd>emq$=$r rL   r<  c                     | d   S rC  r   )rA  s    r,   r   z"render_dashboard.<locals>.<lambda>p  s    %*< rL   c                 F   | d   } |         }| d   r| d   | d   z  dz  nd}| d   r| d   | d   z  nd}| d   dk\  rdnd	}d
| d| d| d    d| d    d| d    d|ddt        | d          dt        | d          d| dt        | d          d| dt        |       dS )NrF  r  r  rt  r  rA  r   r  r  zV<tr><td><button type='button' class='weekday-detail-link' data-dialog='weekday-detail-r  r  r  r  r  r=  r  r>  r@  r?  r  r@  r  rA  )r   re  rB  r.  rC  rD  weekday_escweekday_namess         r,   _weekday_period_rowz-render_dashboard.<locals>._weekday_period_rowt  s   $Ee 45E36s8#f+C(3.B-0X3u:C(3CJ!O&C//4gRw ?3xj	#f+d3x=/ J#hj3w<)@(A B%%.s6{%;$< =""%b3u:)>(? @""%b3(8IrL   rF  z#<tr data-weekday-trade-row='1'><td>z<dialog id='weekday-detail-zt' class='asset-dialog weekday-dialog'><div class='asset-dialog-head'><div><small>TRADE CHIUSI NEL GIORNO</small><h2>z USDT</strong></div><div class='asset-detail-scroll'><table><tr><th>Apertura</th><th>Chiusura</th><th>Asset</th><th>Strategia</th><th>Direzione</th><th>Qty</th><th>Entry</th><th>Exit</th><th>Gross</th><th>Fee</th><th>Net</th><th>Close Order ID</th></tr>c              3   .   K   | ]  } |        y wr  r   )r  r   r[  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     I.s3Ir   c              3   .   K   | ]  } di |  y w)Nr   r   )r  r   rE  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     E3K.#.Er   zn<div class="period-tables"><div><h3>Risultati per giorno della settimana</h3><div class="table-scroll"><table>z`</table></div></div><div><h3>Risultati per ora di chiusura</h3><div class="table-scroll"><table>z</table></div></div></div>zD<div class="empty">Nessun dato heatmap. Aspetto chiusure Pine.</div>trades_by_dayz USDT</td><td><small>c              3   &   K   | ]	  }|d      ywr  r   r  r-  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     ?1+?r  c              3   &   K   | ]	  }|d      ywr  r   r`  s     r,   r  z#render_dashboard.<locals>.<genexpr>       9Qqy9r  c              3   &   K   | ]	  }|d      yw)r\  Nr   r`  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     ;qa	l;r  c              3   &   K   | ]	  }|d      ywr  r   r`  s     r,   r  z#render_dashboard.<locals>.<genexpr>  s     3qAcF3r  c              3   &   K   | ]	  }|d      ywr  r   r`  s     r,   r  z#render_dashboard.<locals>.<genexpr>   rb  r  zM<tr style='border-top:2px solid #58a6ff;font-weight:600;'><td>TOTALE</td><td>z USDT</td><td></td></tr>zm<table><tr><th>Data</th><th>Trades</th><th>WR</th><th>Gross</th><th>Fee</th><th>Net</th><th>Simboli</th></tr>u<   <div class="empty">Nessun trade chiuso dal 1° agosto.</div>z@<div class="empty">Nessun dato giornaliero per il grafico.</div>c                     | d   S )Nrj  r   )r-  s    r,   r   z"render_dashboard.<locals>.<lambda>  s
    1V9 rL   g?)i  i  )r  r  r5   #   g333333?   z\" text-anchor="end" font-size="10" fill="#3fb950" font-family="monospace" font-weight="600">z^" text-anchor="start" font-size="10" fill="#58a6ff" font-family="monospace" font-weight="600">r      z_" text-anchor="middle" font-size="10" fill="#8b949e" font-family="monospace" font-weight="600">0z

    <polyline points="zX" fill="none" stroke="#3fb950" stroke-width="2" opacity="0.85"/>

    <polyline points="zE" fill="none" stroke="#58a6ff" stroke-width="2.5"/>

    <circle cx="z" r="4" fill="#58a6ff"/>

    z

  </svg>

  <div style="display:flex;justify-content:space-between;align-items:center;font-size:11px;color:#8b949e;margin-top:4px;">

    <span>a   giorni di trading</span>

    <span style="display:flex;gap:14px;align-items:center;">

      <span style="display:flex;align-items:center;gap:4px;"><span style="display:inline-block;width:14px;height:2px;background:#3fb950;"></span>Daily PnL (asse sx)</span>

      <span style="display:flex;align-items:center;gap:4px;"><span style="display:inline-block;width:14px;height:2px;background:#58a6ff;"></span>Cumulativo (asse dx): <b style="color:#58a6ff;">z/ USDT</b></span>

    </span>

  </div>

</div>opened_at_fmtz</td><td><span class='badge z</span></td><td>size_fmt	entry_fmtmark_fmtsl_fmtpnl_fmtz USDT</td><td>levzx</td></tr>z<table class='positions-table'><tr><th>Symbol</th><th>Strategia</th><th>Apertura (Roma)</th><th>Side</th><th>Size</th><th>Entry</th><th>Mark</th><th>SL</th><th>PnL</th><th>Lev</th></tr>z1<div class="empty">Nessuna posizione aperta</div>r  u    ⚠️placeholdercreated_at_fmtqty_fmt	price_fmtnotional_fmtz</td><td class='pnl good'>a  <table><tr><th>Quando</th><th>Symbol</th><th>Side</th><th>Qty</th><th>Price</th><th>Notional</th><th>Strategy</th><th>Gross</th><th>Fee</th><th>Net</th></tr><tr><td colspan='10' style='text-align:center;color:#6e7681;font-size:11px;padding:4px;'>Trade chiusi Bybit (no miei test). z trade mostrati.</td></tr>zC<div class="empty">Nessun trade chiuso reale (solo miei test)</div>z,<div class="empty">Nessun trade chiuso</div>u  <!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>v2 Stats Dashboard — 2° Account</title>

<meta http-equiv="refresh" content="30">

<!-- Plotly rimosso: tutto render server-side -->

<style>

* { box-sizing: border-box; }

body { background: #0d1117; color: #c9d1d9; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; padding: 20px; }

h1 { color: #58a6ff; margin: 0 0 8px 0; }

h2 { color: #58a6ff; margin: 20px 0 10px 0; font-size: 16px; }

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-bottom: 20px; }

.kpi-roi { grid-column: 1; grid-row: 2; }

.kpi { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 12px 14px; }

.kpi-label { color: #8b949e; font-size: 11px; text-transform: uppercase; margin-bottom: 4px; }

.kpi-value { color: #f0f6fc; font-size: 22px; font-weight: 600; }

.kpi-value.good { color: #3fb950; }

.kpi-value.bad { color: #f85149; }

.duration-grid {display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:14px;}

.duration-card {background:#0d1117;border:1px solid #30363d;border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px;}

.duration-card span {color:#8b949e;font-size:11px;text-transform:uppercase;}

.duration-card b {color:#f0f6fc;font-size:20px;}

.duration-card small {color:#8b949e;font-size:11px;}

.duration-card.good-border {border-color:#238636;} .duration-card.bad-border {border-color:#da3633;}

.duration-table {margin-top:6px;}

.duration-explanation {margin-top:16px;padding:16px 18px;background:#0d1117;border:1px solid #30363d;border-left:4px solid #58a6ff;border-radius:8px;color:#c9d1d9;line-height:1.55;}

.duration-explanation summary {cursor:pointer;color:#58a6ff;font-size:15px;font-weight:700;user-select:none;}

.duration-explanation[open] summary {margin-bottom:10px;}

.duration-explanation-body {padding-top:2px;}

.duration-explanation p {margin:9px 0;}

.duration-explanation ul {margin:7px 0 12px;padding-left:22px;}

.duration-explanation li {margin:5px 0;}

.duration-explanation .duration-warning {margin-top:13px;padding:10px 12px;background:#251f12;border:1px solid #9e6a03;border-radius:6px;color:#e3b341;}

.duration-strategy-link {background:none;border:0;color:#58a6ff;font:inherit;font-weight:700;padding:0;cursor:pointer;text-decoration:underline;text-underline-offset:3px;}

.section { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 20px; margin-bottom: 20px; }

table { width: 100%; border-collapse: collapse; }

th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid #21262d; }

th { color: #8b949e; font-size: 11px; text-transform: uppercase; font-weight: 600; }

tr.good td.pnl { color: #3fb950; }

tr.bad td.pnl { color: #f85149; }

.positions-table td.pnl.good { color: #3fb950; font-weight: 700; }

.positions-table td.pnl.bad { color: #f85149; font-weight: 700; }

.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }

.badge.buy { background: rgba(63, 185, 80, 0.2); color: #3fb950; }

.badge.sell { background: rgba(248, 81, 73, 0.2); color: #f85149; }

.classification-alert { background:#2d1717; border:1px solid #f85149; color:#ffb3ad; border-radius:6px; padding:12px; margin:12px 0 20px; }

.classification-ok { background:#13251a; border:1px solid #3fb950; color:#8fe39d; border-radius:6px; padding:12px; margin:12px 0 20px; }

.empty { color: #6e7681; text-align: center; padding: 30px; font-style: italic; }

.footer { text-align: center; color: #6e7681; font-size: 12px; margin-top: 30px; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }

.hm-scroll {overflow-x:auto;border:1px solid #30363d;border-radius:4px;background:#0d1117;}

table.hm {border-collapse:separate;border-spacing:2px;font-size:11px;min-width:1240px;width:100%;padding:4px;}

table.hm th,table.hm td {text-align:center;height:34px;border-radius:3px;white-space:nowrap;}

table.hm th {background:#161b22;color:#c9d1d9;font-weight:700;}

table.hm .hm-corner {position:sticky;left:0;z-index:3;min-width:90px;border-right:1px solid #30363d;}

table.hm .hm-d {position:sticky;left:0;z-index:2;min-width:90px;border-right:1px solid #30363d;color:#f0f6fc;}

table.hm .hm-h {min-width:42px;font-size:10px;color:#8b949e;}

table.hm .hm-c {min-width:42px;color:#fff;font-weight:700;text-shadow:0 1px 2px #000;}

table.hm .hm-empty {background:#11161d;color:#484f58;text-shadow:none;font-weight:400;}

table.hm .hm-mixed {display:table-cell;}

.hm-win,.hm-loss {display:inline-block;padding:2px 3px;}

.hm-mixed .hm-win,.hm-mixed .hm-loss {width:50%;padding:0;}

.hm-legend {display:flex;gap:18px;flex-wrap:wrap;margin-top:10px;font-size:12px;color:#8b949e;align-items:center;}

.hm-legend span {display:inline-flex;align-items:center;gap:5px;}

.hm-key {display:inline-block;width:12px;height:12px;border-radius:2px;}

.hm-key-win {background:#3fb950;} .hm-key-loss {background:#f85149;}

.period-highlights {display:grid;grid-template-columns:repeat(4,minmax(150px,1fr));gap:10px;margin:18px 0 12px;}

.period-highlights div {display:grid;grid-template-columns:1fr auto;gap:4px 10px;background:#161b22;border:1px solid #30363d;border-radius:4px;padding:12px;}

.period-highlights small {grid-column:1/-1;color:#8b949e;font-size:10px;}

.period-highlights b {font-size:16px;color:#f0f6fc;} .period-highlights span {font-weight:700;}

.period-title {margin-top:20px;}

.period-tables {display:grid;grid-template-columns:1fr 1fr;gap:16px;}

.period-tables h3 {font-size:13px;color:#c9d1d9;margin:8px 0;}

.table-scroll {overflow:auto;max-height:430px;border:1px solid #30363d;border-radius:4px;}

.table-scroll table {min-width:720px;margin:0;} .table-scroll th {position:sticky;top:0;z-index:1;background:#161b22;}

@media(max-width:1100px) {.period-highlights {grid-template-columns:1fr 1fr;} .period-tables {grid-template-columns:1fr;}}

.asset-link,.strategy-link,.weekday-detail-link {background:none;border:0;color:#58a6ff;font:inherit;font-weight:700;padding:0;cursor:pointer;text-decoration:underline;text-underline-offset:3px;}

.asset-dialog {width:min(1500px,94vw);max-height:88vh;background:#0d1117;color:#c9d1d9;border:1px solid #58a6ff;border-radius:6px;padding:18px;}

.asset-dialog::backdrop {background:rgba(1,4,9,.78);}

.asset-dialog-head {display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #30363d;padding-bottom:10px;}

.asset-dialog-head small {color:#8b949e;font-size:10px;} .asset-dialog-head h2 {margin:2px 0 0;font-size:22px;}

.dialog-close {width:36px;height:36px;padding:0;background:#21262d;border:1px solid #30363d;color:#f0f6fc;border-radius:4px;font-size:24px;line-height:1;cursor:pointer;}

.asset-dialog-summary {display:flex;flex-wrap:wrap;gap:10px;margin:14px 0;}

.asset-dialog-summary span,.asset-dialog-summary strong {background:#161b22;border:1px solid #30363d;border-radius:4px;padding:8px 10px;}

.asset-detail-scroll {overflow:auto;max-height:58vh;border:1px solid #30363d;border-radius:4px;}

.asset-detail-scroll table {min-width:1280px;margin:0;} .asset-detail-scroll th {position:sticky;top:0;z-index:1;background:#161b22;}

</style>

</head>

<body>

<h1>📊 v2 Stats Dashboard — 2° Account <span style="font-size: 14px; color: #6e7681;">(U05gSwYlB5)</span>

<a id="anomalyReviewLink" href="/review" style="float:right;background:#1f6feb;color:#fff;text-decoration:none;font-size:13px;padding:9px 12px;border-radius:4px;">Da certificare z | Anomalie u>   </a></h1>

<div class="footer">Auto-refresh 30s • Generato: uE    • <a href="/json" style="color:#58a6ff;">/json</a> per API</div>

z

<div class="kpi-grid">uc   </div>

<div class="section">

  <h2>🎯 Sharpe / Sortino per Strategia (per-trade, rf=0)</h2>

  uA   

</div>

<div class="section">

  <h2>📈 Equity Curve</h2>

  uR   

</div>

<div class="section">

  <h2>📋 Posizioni Aperte (live Bybit)</h2>

  uV   

</div>

<div class="section">

  <h2>⏱ Durata statistica di tutti i trade</h2>

  uR   

</div>

<div class="grid-2">

  <div class="section"><h2>📊 Per Strategia</h2>u6   </div>

  <div class="section"><h2>💎 Per Asset</h2>ua   </div>

</div>

<div class="section">

  <h2>🔥 Heatmap Giorno × Ora (chiusure trade)</h2>

  zI

  <h2 class="period-title">Risultati numerici per giorno e ora</h2>

  uG   

</div>



<div class="section">

  <h2>📅 Trade per Giorno</h2>

  u[   

</div>

<div class="section">

  <h2>📊 Daily PnL (barre) + Cumulativo (linea)</h2>

  uO   

</div>

<div class="section">

  <h2>📜 Ordini Recenti (ultimi 20)</h2>

  u  

</div>

<div class="footer">v2_stats_dashboard.py — 2° account Bybit (U05gSwYlB5)</div>

<script>

// Equity: render server-side in HTML (vedi sopra)

// Heatmap e Equity: render server-side in HTML (no Plotly CDN necessario)

const reviewButton=document.getElementById('anomalyReviewLink');

if(reviewButton){reviewButton.href=location.pathname.replace(/\/$/,'')+'/review';}

document.querySelectorAll('.asset-link,.strategy-link,.duration-strategy-link,.weekday-detail-link').forEach((button)=>{

  button.addEventListener('click',()=>{

    const dialog=document.getElementById(button.dataset.dialog);

    if(dialog) dialog.showModal();

  });

});

document.querySelectorAll('[data-close-dialog]').forEach((button)=>{

  button.addEventListener('click',()=>button.closest('dialog')?.close());

});

document.querySelectorAll('.asset-dialog').forEach((dialog)=>{

  dialog.addEventListener('click',(event)=>{if(event.target===dialog) dialog.close();});

});

</script>

</body>

</html>).r&   r=   r%  r(  r  rz  r  r  r  r  r;   r  r  r  r~  	enumerater  zipr#   r  r   r   r?   r@   rH   r'   rB   rm   r  chrrj   r   r  r)  rb  r>   r   r   strptimeKeyErrorr  r   ra  r   r   r   (&  rn   r  r	  r  r7  r   r  duration_statsr  r  r  r  recentr  r  r  certification_countanomaly_countunclassified_rowsrA  r]  	pnl_classclassification_alert_htmlexclusion_rowsoperational_exclusions_htmlpgross_class
fees_class
upnl_class	tot_classwr_class	avg_classpfpf_class
pf_display
first_dater  
days_labelsharpe_v	sortino_vsharpe_classsortino_classsharpe_displaysortino_display
gross_baser  r  losses_classr  pnl_realized_classr@  gross_classn_winsn_losses_countwtlwtl_display	wtl_classr  unrealized_classr  	net_classtdtrades_per_daynotional_per_dayday_profit_absday_profit_classDAY_PROFIT_CAPITALEday_profit_pct_4000day_profit_pct_classroi_pct_4000roi_pct_classkpi_htmlduration_strategy_rowsduration_asset_dialogsduration_escr   r   strategy_safe	dialog_id
asset_rowsr   assetsasset
winner_avg	loser_avgduration_htmleq_ptseq_datescum_pnl_ptsmin_vmax_vrngwpadpointsir+   r  ysvg_linecum_pnl_svg_linelast_vfirst_vlast_change
change_pctcolorhover_pointsn_eqi_ppt_xyv_pcx_pcy_pdt_rawdt_labelts_valr   r  dt_objdelta_v	delta_pctdt_jsy_labelsfracv_labely_posy_label_svg
grid_h_svgr  x_idxx_label_svg
grid_v_svgidxts_v_dt2_tz2anchortxfill_ptszero_yequity_htmlequity_jsonr=  strategy_dialogsstrategy_escrD   rD  
trade_rowsnet_clsdetail_tabletotal_n
total_winstotal_wrtotal_grossr  	total_net	gross_clsstrategy_htmlboxesshsoname_raw	name_dispsh_clsso_clssh_dispso_dispr)  strategy_sharpe_htmlasset_dialogs	asset_escrW   r   symbol_safe
asset_htmlr,  top_htmlbad_htmlr-  r  single_losses_htmlr0  r-  open_by_day_htmlrc  rH  heatmap_stats_html	max_countheatmap_rowscellsre  rx  lintensity_wintensity_lrwgwbwcolor_wrlglblcolor_l
cell_titlebglegendaheatmap_html	day_stats
hour_statsbest_day	worst_day	best_hour
worst_hourr  r   weekday_trade_detailsr  closed_localweekday_dialogsday_rows	hour_rows_trades_by_day	tot_grosstot_feestot_nettot_ntot_winstot_wrtot_clstrades_by_day_htmldaily_chart_htmldays_sortedn_days	daily_pnlr
  runningd_maxd_mind_rngd_topd_botd_rng_totalc_maxc_minc_rngc_topc_botc_rng_totalpad_lpad_rpad_tpad_bplot_wplot_hx_positionsbar_wbars_svgxvdvy_topy_boty_zeroy1y2cum_ptscvcum_line	daily_pts
daily_liney_labels_left
y_left_svgy_labels_righty_right_svgsteplast_cum_ptr  positions_htmlr  r  rv  rw  r\  pnl_net_classorders_htmlrj  rE  r[  r_  r^  r]  r`  rI  r\  rY  rZ  s&                                                                                                                                                                                          `                                                                                                   @@@@@@@@@@r,   render_dashboardr]    sB   <D(^F}%KJH((#8"=!XX&>CXX4b9N
y/%
 C
y/%
 C9oG[!I/"F'L88126L!XX&>C7=>*401M ! 	E))Iuyy':;C"%'auRI$$599\267 8yy2./ 0yyR01 2yy!8"=> ?""+By~.>oO	, R< ! "// gg'(
)  	",G 	" + 	E))Iuyy':;C!!599\267 8yyr23 4yy2./ 0yy!1267 8yyR01 2yy!5r:; <''0~&6oG		0 Q)*+ ,]] ggn%
&  	$( ')# !#"$ /14%I!"3496uL-1rJ 01Q6EJ:;q@eIiB.vd9oPR>RUXZHy/Q.EI 
/3	'B	Sy	s	s  "RBs8UJ,b1J88NA.L7A%j\3~J HILMNO '(JDJ.!FL'L#/1#4% 6!D(E!QJ&EK XXfa FXXh*N~%S	#:ICZI I 	&'J!+qve Z'G!Q,EI 88NA.3!L	\1	B @Dxx
TU?VU488J2R7;\]N xx 0!4r9 r\N!/1!4v% !),??3F%8A%=6511S8L*a/FUM, , h ,hq  sF  IP  sP  iQ  hR,Rt, uB  tC	, CE	, FR  SV  EW	,WT	, UYYcTdSe,f+, ,6,, 7T, UaSa,bO, PXj, Y[, \ddhirds[tZu, vx, y}  ~D  yE  xF, FJ, KO  PX  KY  JZ,ZR, S\Q\, ]_, `k^k,lT, U]S], ^`, ak_k,lY,  ZeXe!,  fh!,  irrwhxgy!, zQ!,$ R\P\%,$ ]`%,$ ajjn`o_p%,$qW%,( XaagWhVi),(jd),, ewcw-,, xz-,, {D  EQ  {R  zS-,,SU-,0 VfTf1,0 gi1,0 jss}i~h1,0@d1,4 encn5,4 oq5,4 r{  |C  rD  qE5,4EP5,8 QZ{9,8 []9,8 ^ggklugv]w\x9,8yW9,< XaaefrasWtVu=,<vX=,@ Y]]mXnWoA,@pWA,D XfVfE,Dg^E,H _hhx^y]zI,H{SI,L ThRhM,L ikM,L l  @C  kDM,LDQM,P RbPbQ,P ceQ,P foo}e~dQ,P@YQ,T ZccijwcxYyXzU,T {DU,T EK  LX  EY  Z]  D^U,T^U,H`  oL!!-4 L
s:'FXFF,]O<	%%XYbXccefrs{  tB  tB  tD  gE  fF Fw<.	-M8J*K)L M %5!678
	D	
 
 ,//0CRH
488J'-2.(: 
 
 	?N 	E#78J		"56Il5?;<M%PW.IY Z$U=%9:;9]SXYiSjEkDl m$U=%9:;9]SXYfSgEhDi j$U=%9:;9]SXYfSgEhDi j$U=%9:; <4>4J}Z0PUV W3<3H}Y/eTT^`	0 	%%9+ &VVbckcqcqcsVtUu v7 8;7|n E(]);<= >*3/?+@AB CBB$ ggj!%"$ %>%>	
mL
\F F : F ;I:L:L]\j\n\novxy\z  ~L  ~P  ~P  QZ  \]  ~^  ]^  ;_  :`	F `	F @N  @R  @R  SZ  \]  @^  _	F _m	F n|  n@  n@  AJ  LM  nN  mO	FO:	F ;HHZHZ[hjkHl:m9nFo5F 6C>CUCUVfhiCj5k4lFm7F 8E^EWEWXeghEi7j6kF lwF xE  FT  FX  FX  Yf  hi  Fj  xk  wlFl7F 8E^EWEWXeghEi7j6kF lwF xE  FT  FX  FX  Yf  hi  Fj  xk  wlFl1F 2?~?Q?QR_ab?c1d0eFfKF  LYYgYkYkluwyYzY~Y~  @M  OP  ZQ  LR  KS!F  S^!F  _m  _q  _q  r{  }  _@  _D  _D  EL  NO  _P  ^Q!F QJ!F$ KXXfXjXjksuwXxX|X|  ~K  MN  YO  KP  JQ%F$ Q\%F$ ]k  ]o  ]o  px  z|  ]}  ]A  ]A  BI  KL  ]M  \N%F$Nf%F, gifmfm  oE  gF  fG-F,.G-FH 	  !IFH"IFMX n! !'?{q  {+S-=5EeemT*C DAqC F!+. 211K 01 45!a#g+FFGE	S0QS[AA3q3012 xx'H! _F!!nG 7*K?F!|+G4s:QRJ!,!1IyE L{#D%.s6;/G%H 6!\eS"[[-
d*-H*=#2 s1ug;J!&v!D=%+f_FM!$!2!26cgg!2!F#)??=#A A.EPQR^WXEXWs;q>'::S@^_	 h..tV<DDS%PPSVV0fTFBrsxry z5 69UG2eWBs3irRYZ]Q^^`ajkn`o p% &)UG3xjSI N&'M6t H3 2$*,C$!a#g+"66% 012 KJ"* {
3%veC[qugVTYZ]S^  _J  K  K
3q5'uQwsm  D`  ah  il  `m  mz   {  {	{ FA./1fQ1ac1fac*$uQx.EKJ "w3QUA.1q3w;??*-H*=#2 4$V}$;#'&=DO#'#5#5dtxx#5#H#Q#QR_#` 
1S'uF1S'PQRUPUw  WY  Z  Z
$'1HC1Q3J5H$/QUva!eTU2c(%"v_VH  U_  `h  _i  iv   w  wE"wL  AfRj&6&6s2w&?&B%C1QsUG1SEQRSTUXSXRY"ZZH GJAgQWUc 1a!c'kBBSTWZSZFj
 j
  j
Cj
j
2j
\j
]^_a]a\bj
cj
 L	j
 	j
 .	j
 /7Z	j
 8@	j
 AFw	j
G	j
 ej
 j
 !j
 &,j
 -.cE7j
 39j
 :@j
Ej
  jj
 !7j
 8=gj
>j
 Nj
j
 !!#b'*1-.j
 /5j
 6<BZ5E5Ec"g5Nq5Q4Rj
 Saj
 bg`gj
hj
 Mj
 j
j
( a.&)j
(')j
, w-j
, 7-j
, 8>dm-j
, DK-j
, LVVZJ[-j
,\-j
8 {
9j
8A9j
@ BG  AHAj
@JHAj
K` q	A V  WX  Y\  V]  ]h  iKjj( |jj2[^nq!rs s D	AeHM&uC1Z=)HGG#J#JJM*=/:IKKST]S^^`amnvaw`x yvhb6;x)7M6N O((1!K.(A'BB]^ghijphq^r]s t""%b1U8)<(=_N
 J/33HbA $)%LA$5&5!!|E+,>?@	,W\]hWiJjIk l'h89<PUVaPbCcBd e <-YuW~d6K9UZ[aUbcgTh i$U7^455LYW\]bWcMdLe f&&-Yb5<1H0IIYZfglmwgxZyYz  {MN	(N ''*%	& )9	9  ##yk *>>J8>T=U V; <=S6(BUVWX^V_U``defgjeklmntlueudv w$Qy\233G	RST_R`HaGb c'&	233NseSYZcdefkdlZmYn  oC.	+iD	L 2k228K88
3:J(3.>+>>8K88
6+66	)Q.FE	%N&"")"ZL 9H%& ''[9[+A*B C%%.z%:$; <%Yb9)=(>o
O	
$ qggdm()+-773C+DE 	 v  4	A#Ax%By#&B }H>F)>S((c288:YbIAv#%9BF5#%9BF5HH&xj	!BqykAPQRXPYM? [  !)S1!E(3 H`a #%$$))'%hZr!4pqLL*5' 2**3Bqc :))/0Nwi X))/0]^e]f gQ4	l "87GvN  Y p	 D	AeHM&uC8%++-F''!Fv!FFK'}5IKKPQZP[[]^ghn^o]p qvhb6;x)7M6N O((1!K.(A'BB]^ghijphq^r]s t""%b1U8)<(=_N
 J,00< $)%LA$5&5!!y{);<=YyQVWbQcGdFe f$U:%678	)ER]L^B_A` a <-YuW~d6K9UZ[aUbcgTh i$U7^455LYW\]bWcMdLe f&&-Yb5<1H0IIYZcdijtduZvYw  xJK	(N ''*%	& )9	9    yk *::CF:K9L M; <=S6(BUVWX^V_U``defgjeklmntlueudv w$Qy\233G	RST_R`HaGb c'&	233NseSYZcdefkdlZmYn  oC.	+iD	P nggdm()+-77=+AB 	 K
.td #v&H#u%H HH_b1M 	SAKK(155R#8"9155SUCVBWW`abafafgmoqar`ss|}~  ~C  ~C  DI  KL  ~M  NR  }S  S\  ]^  ]b  ]b  cp  rs  ]t  uy  \z  zC  DE  DI  DI  JV  XY  DZ  [_  C`  `y  z{  z  z  @I  KL  zM  NQ  yR  Rr  st  sx  sx  y~  @A  sB  CF  rG  GQ  R  S	S \  _a  _f  _f  gk  _l  l  oy  y ^ ((="-K 	xAqvGKK(1V9+\!C&AUVWXaVbUccuvw		x 	cdkcl  my  z  	{psuszsz{  tA  A  DN  N S {{:a'A1B'ABH{{:a'A1B'ABH;;~%(/KQb/KLL++ma-I1seBh-IJK\eAh+GSE"H+GHJPUVWPXY1E"IFq8A;q>HQKN2FYJV

.:
.. <FC7J771		1%	 ;;! 	>ALL,QsG8<=	> 	FRWWU^3g=>#GFO4 B	CJE3(U34E2Y <zUOA&UOA&6a1fLL!XY 4=q=!i-aK3<q=!i-aK R7k"99:BR8{"::;BR7k"99:B $RD"Qrd!4G R8{"::;BR7k"99:BR7k"99:B $RD"Qrd!4G$'5!C
1#WQC!HJ Av'J7)S]^h]i  jC  DE  CF  FR  &S  T a'J7)S]^h]i  jD  EF  DG  GS  &T  U  :'%yPVW^V__efmenntu'STVSWWablam  nG  HI  GJ  Ji  jk  il  lx  &y  zy<z|  7' ABEB	CLU CRWW\EZZ]mmpww	N( 	#GFO4 	JE3Ju%&A  !&1c(SX/FZfijrsxjyfz e!45s;uCU?V_bcmnsct_u	" 	 
r 	A7eAh77A!! !#wc]AaAASPrinopiqPrMr  FU1X FFPSSxotuvowSxPxBqBB
# 
	( y&89	'9:	
(:;	);<
55=g5F4GG^_hiqrwix_y^z {55>w5G4HH^_hirsxiy_z^{ |22;G2D1EE\]fgpqvgw]x\y z22<W2E1FF\]fgqrwgx]y\z {
 	  Lkr +D 1 6 < < > 	fHf 
f#+#4#4U;5GIY#ZL &l&:&:&<=DDEdEdz[cEde
f	f ,224 	LFKK<dKK	L	 	@  8	C$EJ!O&CJ.225"= $)%LA$5&5!!9+eKFX:Y9Z [&u['9:;9[QVW_Q`EaDb c&s5+<'='C'C'EFGyQ\]bcn]oQpPq r <-YuW~d6K9UZ[aUbcgTh i$U7^455LYW\]bWcMdLe f&&-Yb5<1H0I J""-eJ.?"@!AASU	, ""-eW 5 #=#789 :; <?s8* EVT#h-8I3v;Y\]`YaKadgKgilIm n(W677NyY\]cYdOeNf g""%fYs5z-B,C DUU, ''*%-&, )B-B=8	x 77IyIIGGE*EE	  b bdjkmuvy[[ ^d	d gp	ps	 ww/0 	 ^ XXor2N 	{AiLA-&5CKK(1V9+Yqvhb6;WXYbWcdgVh  iD  EN  OP  Q\  O]  E^  D_  _z  {D  EF  GM  EN  {O  zP  Pd  eh  di  ik  lu  vw  xA  vB  lC  kD  DY  Z[  \e  Zf  Yg  gy  z  {		{ ???	9.99;N;;3N339.99-2(U"S(#qL&ecdicjjlmulv  wB  CI  JM  BN  Ni  js  t}  j~  i  Z  [d  em  [n  Zo  oC  DK  CL  LN  OX  Y`  Oa  Nb  bz  {  	| M  PR  PW  PW  X\  P]  ]  `j  j \ Z#n-2^1DE[!+67aQy\7	7 	$AqLGNN7#		$ C	NA&C	NA&EEM4(##em CL!$CL!$EEM4(##em 1%3"ueUUU"UU" A:6] H""5A!,<+F#FGH uvz12 FS^+c115 $Si%@A 	KAxBQ#b!*u"4!CCvMMEQ#b!*u"4!CCvMMEa1u9";;vEEFQw! ! =	D $Sg%>? 	0KAxBb5jK776AAANNbXQqg./		0 88G$ 	$Si%@A 	2KAxBb5jK776AAA3xq301		2 XXi(
 / 	3Dd[00GQX//E  '5!12	3 

+ 	yNGUJugVE#;fQuWIVTYZ]S^  _J  K  KJIeAgYeE!GC=  A]  ^e  fj  ]k  kx  y  yJ		y / 	4Dd[00GQX//E!!7E"23	4 , 	~NGUYqwqykuQwsm  Db  cj  ko  bp  p}  ~  ~K	~ B;q&A+&Dq&$/0E v'E 	NCV|$1S'qwrzl  Cb  cn  or  cs  tz  c{  |}  |~  c  b@  @M   N  N	N 18gbk'',c3Z CqYZ[Y\ ]L !l #j !Q {1~&6 7Lk] + ( B CJ  KM  CN  OS  BT T1
H  	\AeHM&uCKK(1X;-|AjM?-XYZiXjWk  lH  IJ  KQ  IR  IX  IX  IZ  H[  []  ^_  `f  ^g  ]h  hx  yz  {E  yF  xG  GP  QR  S^  Q_  P`  `i  jk  lv  jw  ix  xA  BC  DL  BM  AN  Nb  cf  bg  gi  jk  lu  jv  iw  wE  FG  HM  FN  EO  OZ  [  \		\ U  XZ  X_  X_  `d  Xe  e  hr  r M  	SA+,55+?'RDk1-I%%q/CeeIquuUA7G&-kF!uQSMKK(1%5#6"7y8Mijklrjsittvwxy  xA  wB  BR  ST  U^  S_  R`  `i  jk  lw  jx  iy  z~  y  H  IJ  KY  IZ  H[  [d  ef  gq  er  ds  sM  NW  Xa  Nb  Mc  c~  H  IL  M  ~N  Nb  cp  bq  qs  t}  ~E  tF  sG  GQ  R  S	S  v  wz  {  w@  vA  A[  \  _a  _f  _f  gk  _l  l  oy  yK `K Ev v vs vl tG  sHmvl HTmvl Ub  Tcmvlc4mvp 5A>qvpBqvt  uvtuvx  yvxyv|  j}v|!}vH IvHIvX -YvXYvh ivhivx /yvx3yvD 4A/EvDB/EvH 0:lIvH;IvX .YvXYv` av`
avt uvtuvD EvDEvT -UvT,UvDp	 Ke9
p % J286#2;#a%kJl % 4#&v;s#34| (B'A/K-I+GFYX !)Z8 h 8s   *B`AB`7A	B`9]Ba
^Ba
^?Ba!
_0Ba&
`!Ba+
aBa5aBa0a3Ba5uBa;EBb`B`6`5B`6`9BaaBaa0Ba5a;BbbBbc                  	   t               } | D cg c]  }|j                  d      r| }}| D cg c]  }|j                  d      s| }}|D cg c]  }|j                  d      t        k(  r| }}|D cg c]  }|j                  d      t        k7  r| }}t               }t	               }t               }t        dd      }	t        |||      }
t        ||      }t        |      }t        |      }t        |      }t        |      }t        |      }t        |      }t        |d      }t!        |      }t#        |      }t%        |d      }t'        |	      }g }|D ]x  }t)        |j                  d            }t)        |j                  d	            }t)        |j                  d
            }t)        |j                  d            }t)        |j                  d            }t)        |j                  d      d      }|j                  dd      }t+               } |j-                         | v r| |j-                            }!nt/        |      }!dddddd}"|"j                  |!|!j-                               }#|j1                  ||#t3        |j                  d            |j                  dd      ||d||d||d||dkD  r|dnd||d|dkD  r|dndd       { g }$t5        |d  d!"      }%|%d#d$ D ]<  }&t7        |&j                  d%      xs |&j                  d&            }'|$j1                  |'r|'j9                  d'      nd|&j                  dd      |&j                  dd      |&j                  d(d      d|&j                  d)d      d|&j                  d(d      |&j                  d)d      z  d|&j                  dd      |&j                  d*d      |&j                  d+d      |&j                  d,|&j                  d-d            |&j                  d,|&j                  d-d            d.d!d.d/       ? i d0|
d1|d2|d3|d4|d5|d6|d7|d8|d9|d:|d;|d<|d=|d>|$d?|d@||sdAndBt;        |      t;        |      t=        dC |D              t;        |      dDdE|t?        j@                  tB        jD                        jG                         j9                  dF      dGS c c}w c c}w c c}w c c}w )Hu   Dati SOLO da Bybit (no webhook DB orders). Trade chiusi + posizioni aperte,

    filtrati dal 1° agosto ed escludendo MIEI test Pine-style.rI  r     
2026-08-01)rp  r  rh  )r  r   r  	markPricestopLossr  leverager   r   r/   VPTR3
RETTANGOLORETT_SIMPLEMA_TRAILINGSUPERTREND_BOSW)r  r  r  r  r  createdTimerU  r  r/  r   rv  r.  z.0f)r   r   rk  rU  r   rl  r  rm  markrn  slro  r]  rp  rq  c                 R    | j                  d      xs | j                  d      xs dS r  r3  r  s    r,   r   zassemble_data.<locals>.<lambda>&  s"    aeeL)FQUU<-@FB rL   Tr'  Nr  r[  rL  r<  rW  rY  rv  rw  r\  r]  F)rr  r   rU  rs  rt  ru  r   rv  rw  r\  r]  r  is_realis_testr  r	  r  r7  r   r  r  by_asset_strategyr  r  r^  r-  r0  r  r  r  r  OKWARNINGc           
   3   r   K   | ]/  }t        |j                  d |j                  dd                   1 ywr  )rF  r&   )r  rA  s     r,   r  z assemble_data.<locals>.<genexpr>~  s5      (  EIIi5!1DEF(s   57(exact_order_id_or_unique_entry_lifecycle)r   r{  r  pending_net_excludedoperational_excludedr  %Y-%m-%d %H:%M:%S)classification_integrityqueue_statsr  )$r  r&   r  r  r  r  r  r  r  r2  r8  rH  rK  r  rP  r  rf  rn  r  r}  rF  r  r  r  r  rP   r   rF   rH   r=   r  r   r\   r   r@   rN   )(all_closed_tradesrA  r  performance_candidatesr  r  r  r  rx  r  r  r	  r  r7  r   r  r  ro  r  r  r^  r-  r0  positions_fmtr  r   r  rj  rk  r]  rq  rd  pos_overrider  strat_labelsstrat_labelr|  closed_trades_sorted_recentr  _tss(                                           r,   assemble_datar    s    01 -99+, 	  -yy/0 	  299Z $99 	  299Z $99 	M  12I!G!#K ,?I #=)WED,]GDF0?K*=9H5mD;MJ7F<]K(a@G(7G)-8M-m1EM(3K M @155=)AEE*-.155-.z*+!%%01!%%
+Q/eeHb! 6799;,& -E ,C0E L!.}0
 #&&uekkm<#+AEE-,@AEE&"%dE$<dQ2d)Ec$Z#&7c#Y)
 	U@T F"(F# )"- "aeeL1HQUU<5HI@Ccll+;<eeHb)EE&"%%%q/$/EE-3D9 uuUA}a1HHNj"-{A.55?uuYeQ855AEE%O4 9
 		"L>> 	&	> 	{> 	H> 	2> 	!"8> 	 4>  	.!>$ 	7%>( 	7)>, 	->0 	1>4 	{5>8 	]9>< 	=>@ 	2A>D 	!"8E>L #6d9m, 34$' ( 1	( % %((>$?>%%
, # X\\2==?HHI\]y> >Us   SS$!S)6!S.c                   J    e Zd Zd Zd Zd ZddZd Zd Zd Z	d	 Z
d
 Zd Zy)StatsHandlerc                      y r  r   )selfrI   argss      r,   log_messagezStatsHandler.log_message  s    rL   c                    t         j                  j                  dd      j                         j	                         dvst
        sy| j                  j                  dd      }|j                  d      sy	 d	d l}|j                  |d
d        j                  dd      }d|vry|j                  dd      \  }}t        j                  |t              xr t        j                  |t
              S # t        $ r Y yw xY w)NV2_STATS_AUTH_ENABLEDrj  >   1yesr  TAuthorizationr/   zBasic Fr   rs   rX   ignorer   r   r   )r$   r%   r&   r!   r   	AUTH_PASSheadersr"   base64	b64decoder   r#   hmaccompare_digestr@  r'   )r  authr  decodedur  s         r,   _check_authzStatsHandler._check_auth  s     ::>>137==?EEGOcckt||4x(	&&tABx0777QG'!==a(DAq&&q)4Z9L9LQPY9ZZ 		s   5-C. #A
C. .	C:9C:c                     | j                  d       | j                  dd       | j                  dd       | j                          | j                  j	                  d       y )Ni  zWWW-AuthenticatezBasic realm="v2-stats"Content-Typez
text/plains   401 Unauthorized)send_responsesend_headerend_headerswfilerc   r  s    r,   _send_unauthorizedzStatsHandler._send_unauthorized  sQ    3+-EF6

,-rL   Nc                    t        j                  |t        d      j                  d      }| j	                  |       | j                  dd       | j                  dt        t        |                   | j                  dd       |r(| j                  d	d
| d       | j                  dd       | j                          | j                  j                  |       y )NF)r   rw   rX   r  zapplication/json; charset=utf-8Content-LengthCache-Controlno-storeContent-Dispositionzattachment; filename="r   X-Content-Type-Optionsnosniff)
rj   r   r;   r   r  r  r=   r  r  rc   )r  codern   attachment_namer   s        r,   
_send_jsonzStatsHandler._send_json  s    zz$%@GGP4 )JK)3s4y>:*526L_L]]^4_`5yA

rL   c                 .   |j                  d      }| j                  |       | j                  dd       | j                  dt        t	        |                   | j                  dd       | j                          | j                  j                  |       y )NrX   r  ztext/html; charset=utf-8r  r  r  )r   r  r  r;   r=   r  r  rc   )r  r  r   
body_bytess       r,   
_send_htmlzStatsHandler._send_html  sw    [[)
4 )CD)3s:+?@*5

$rL   c                    d}||v r|j                  |d      d   nd}|r|t        |      j                  k7  r| j                  dddi      S t        |z  }|j                         s| j                  dddi      S |j                  j                         }ddd	d
j                  |      }|| j                  dddi      S |j                         }| j                  d       | j                  d|       | j                  dt        t        |                   | j                  dd       | j                  dd       | j                  dd       | j                          | j                  j!                  |       y )N/review/evidence/r   r/     r  evidence_not_foundr   r   r   )r   r   r   r  r  r  r  zprivate, no-storer  inliner  r  )r#   r   r}   r  r   is_filesuffixr   r&   r   r  r  r;   r=   r  r  rc   )r  r  markerr   r   r  r   r   s           r,   _send_evidencezStatsHandler._send_evidence  sX   $28D.djj+A.bkT+->-C-CC??32F(GHH${2~~??32F(GHH$$& +\LY]]^de??32F(GHH  "36)3s4y>:*=>.919=

rL   c                 &   | j                         s| j                         S t        | j                        j                  j	                  d      dk(  r| j                  dddd      S t        5  | j                         cd d d        S # 1 sw Y   y xY w)Nrm  /healthzr  okv2-stats-dashboardr   service)r  r  r   r  rstripr  DATA_REQUEST_LOCK_do_GET_datar  s    r,   do_GETzStatsHandler.do_GET&  s|    !**,,DII##**3/:=??3$BV(WXX  	'$$&	' 	' 	's   -BBc                 Z   | j                         s| j                         S t        | j                        j                  j	                  d      }d|v r| j                  |      S |dk(  xs |j                  d      }|dk(  xs |j                  d      }	 t               }|rP| j                  d	t        j                  t        j                         j#                         d
dt%               dd      S |rt'        t        | j                        j(                        }|j+                  d      dgk(  rd}n2|j+                  d      dgk(  rd}n|j+                  d      dgk(  rd}nd}| j,                  j+                  d      dk(  rdnd}	| j                  d	t/        |||	            S |dv s|j                  d      r| j                  d	t1        |            S |dk(  r>t3        t5        |            t3        t7        |            d|d<   | j                  d	|      S |d k(  r| j                  d	d!d
d"      S | j9                  d#       | j;                          | j<                  j?                  d$       y # t        $ r2}dd l	}| j                  dd|j                          d      cY d }~S d }~ww xY w)%Nrm  r  z/reviewz/review/export.jsonr   r  z<h1>500</h1><pre>z</pre>r  r  none_pending_review)r  r  policy_effect	proposalsr   )r  r:  r  z*Trade certificato. Statistiche aggiornate.r  z-Proposta rifiutata e spostata nelle anomalie.r  z,Proposta registrata nella coda di revisione.r/   X-Dashboard-Base/v2-monthly/
/v2-stats/)r   r  )r/   rm  z/indexz	/v2-statsz/json)r  r  review_countsr  r  r  r  s   404) r  r  r   r  r  r  r  r  r'   	tracebackr  
format_excr  r   r\   r   r@   r]   rp   r   queryr&   r  r  r]  r=   r%  r(  r  r  r  rc   )
r  r  	is_reviewis_review_exportrn   r  r  r  r   r  s
             r,   r  zStatsHandler._do_GET_data8  s   !**,,		"''..s3$&&&t,,I%Ay)A	#88`DMMJ_<`	\ ?D ??3 (X\\ : D D F/!6/1
)  E # 
F 
F Xdii0667Eyy%#.F:&3%/I9%#.H )-)9)9:L)MQ_)_~eqH??3(?g`h(ijj((DMM+,F??3(8(>??W_7:;TUY;Z7[jm  oA  BF  oG  kH  %ID!??3--Z??34DX(YZZ s#JJV$  	\??3*;I<P<P<R;SSY(Z[[		\s   
I/ /	J*8'J%J*%J*c                 Z    t         5  | j                         cd d d        S # 1 sw Y   y xY wr  )r  _do_POST_datar  s    r,   do_POSTzStatsHandler.do_POST  s&     	(%%'	( 	( 	(s   !*c           
         | j                         s| j                         S t        | j                        j                  j	                  d      }d}dD ]  \  }}||k(  s|j                  |      s|} n |s| j                  dddi      S | j                  j                  dd      j                         }| j                  j                  dd      j                         }|r,t        |      j                  |k7  r| j                  d	dd
i      S 	 t        | j                  j                  dd            }|dk  s	|t        kD  r| j                  dddi      S 	 | j                  j                  |      }t!        | j                  j                  dd      |      \  }	}
t#               }|dk(  r|
t        d      t%        |	|       n-|dk(  r|
t        d      t'        |	|       nt)        |	||
       | j7                  d        |dk(  rd!n|dk(  rd"nd#}| j9                  d$d%|        | j9                  d&d'       | j;                          y # t        $ r | j                  dddi      cY S w xY w# t        $ r}	 t#               }|j+                  dd      d   }| j                  j                  d      dk(  rdnd}| j-                  dt/        |t1        |      |            cY d }~S # t2        $ r% | j                  ddt1        |      i      cY cY d }~S w xY wd }~wt2        $ r,}t5        d|        | j                  dddi      cY d }~S d }~ww xY w)(Nrm  r/   ))z/review/proposalsrB  )z/review/certifycertify)z/review/rejectrejecti  r  method_not_allowedOriginHosti  origin_not_allowedr  rj  i  invalid_content_lengthr   i  invalid_payload_sizer  r  z1Allegato non previsto nella certificazione rapidar  z(Allegato non previsto nel rifiuto rapido)r   r   r  r  r  )r  r  zreview proposal err: r  review_save_failedi/  zcertified=1z
rejected=1z	created=1Locationz
../review?r  r  )r  r  r   r  r  r  r  r  r&   r!   netlocr>   r   MAX_REVIEW_BODY_BYTESrfilereadr   r  rF  rR  re  rsplitr  r  r;   r'   rf   r  r  r  )r  r  r   r  r}   originhostlengthr   r   r   rn   ro   review_pathr  result_flags                   r,   r  zStatsHandler._do_POST_data  s9   !**,,		"''..s3
 	LFD v~v!6	  ??32F(GHH!!(B/557||+113hv&--5??32F(GHH	M))*:C@AF Q;&#88??32H(IJJ0	I::??6*D1$,,2B2B>SU2VX\]D* ?D")$%XYYtT*8#)$%OPP%dD1 (dzJ0 	3'-':mPVZbPbhsz+%?@*5E  	M??32J(KLL	MH  	AA$"kk#q1!4-1\\-=-=>P-QUc-c>ius,CDPSTWPXck,lmm AsWc#h,?@@A  	I'u-.??32F(GHH		Isb   %I	 BI, 	I)(I),	M6A'K#M#&L	L
MLLM !MMMr  )__name__
__module____qualname__r  r  r  r  r  r  r  r  r  r  r   rL   r,   r  r    s9    D
.0%$(X'$S%n(lrL   r  c                  D   t        dt         dt                t        dt                t        dt        rdnd        t        t        t        ft              } 	 | j                          | j                          y # t        $ r Y w xY w# | j                          w xY w)Nzv2 stats dashboard avviato su r   zDB: zAuth: 	abilitataz"disabilitata (no password settata))
rf   LISTEN_HOSTPORTr  r  r
   r  serve_foreverKeyboardInterruptserver_close)httpds    r,   mainr  	  s    
(Qtf=>$wi&	/STUVd 3\BE
 	   	s$   A> >	B
B 	B

B B__main__)rv  r  )r/   r/   rm  )r_  r`  )r`  )rh  )ru   )r   )r  )__doc__r$   r  rj   r)  r  r  r~   stringrj  r   email.parserr   email.policyr   r   r   r   pathlibr   http.serverr	   r
   	threadingRLockr  urllib.parser   r   collectionsr   zoneinfor   r   r  r   ri   r   r   r   r  r   r>   r%   r&   r  r  r_   rb   r-   r@  r  	frozensetra  rO   rF   rK   rP   rf   rp   r   r   r   r   r   r   r   r   r   r  r%  r(  r*  r.  rF  rR  re  r  r  r  rc  r   r   r  r  r  r  r   r
  r  rD  r[  r|  r@   r   r}  rf  ri  r  r  r  r  r  r  r  r  r  r2  r8  rH  rK  rP  rf  rn  r}  r  r  r  r  r  rz  r  rF  r  r  r  r]  r  r  r  r  r   rL   r,   <module>r     s   
 
         $ 0 '  C  $IOO%  + #  ./
-,
,77 @@ @@ "OO !:: ' $ 
2::>>/623
--- H  JJNN?,=>	JJNN?B/	  
 
 =)*`
 E0,(D$"$PZ0DT0lD(N$(^H8
J $BAPH7\Rpq"r,H "&! 	0&%X !* + ! 0 ' Nh/@pl\"P <L|3Dx| Jz*33D!Q1aPZ[ePfPoPoPsPs3t~~  A  DH  H  ID@vx;&XGH" P(\bPBP<DDT(\4t4t0lDT@LbP`LF$X*`X|$T_<DdXx"@FPpk) kb4 zF rL   