
    j$                    R   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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"dZ#dZ$ e%ejL                  jO                  dd            Z(dZ)edz  Z*e*dz  Z+d Z, e,        ejL                  jO                  dd      Z-ejL                  jO                  dd      Z. e/h d      Z0 ed      Z1d Z2d`dZ3d  Z4d! Z5d" Z6d# Z7d$ Z8d% Z9d& Z:d' Z;dad(Z<dbd)Z=d* Z>d+ Z?d,d,d-d.hd/Z@d0 ZA e/h d1      ZBd2ZCd3 ZDdad4ZEd5 ZFd6 ZGd7 ZHd8 ZId9 ZJd: ZK e% eLd;      j!                  d<d=d>ddd eLd;      j"                  j                  ?      j                         d@z        ZOdA ZPdB ZQdC ZRdD ZSdcdEZTdF ZUh dGZVdH ZWdI ZXdJ ZYdK ZZdL Z[dM Z\dN Z]dO Z^dP Z_dddQZ`dddRZadedSZbdedTZcdU ZddV ZedfdWZfdgdXZgdhdYZhdZ Zid[ Zj G d\ d]e      Zkd^ Zlemd_k(  r el        yy)iu   
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
HTTPServer)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_evidencei  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       5/tmp/v2_stats_dashboard.supertrend.20260821_174437.py_load_auth_from_envfiler,   &   s    ))J	",,.99; 
4zz|??3'3d?zz#q)1GGIGGIOOC(..s3'

0O23BJJ//)"**..2Q23BJJ/
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_tsrE   E   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.   )rE   strftime)rB   fmtdts      r+   _fmt_bybit_tsrJ   ]   s#    		B	z;;s    c                 f    t        |       }|y|j                  t              j                  d      S )Nz--z%d/%m/%Y %H:%M)rE   
astimezoneREVIEW_TIMEZONErG   )rB   rI   s     r+   _fmt_review_tsrO   e   s/    		B	z==)223CDDrK   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?   rM   	isoformatprintLOG_DIRmkdiropenLOG_FILEwriter&   )msgrB   r(   fs       r+   logre   l   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-sigrX   zreview queue read err: )	REVIEW_QUEUE_PATHr   jsonloadsr   
isinstancelistr&   re   )dataexcs     r+   _load_review_queuero   x   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..   z.tmpF   )ensure_asciiindentrW   rX     T
missing_okN)rh   	with_namenamesecrets	token_hex
write_textri   dumpsr#   chmodrA   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                 @   | 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-urlencodedrW   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 validorz   zcontent-disposition)header)decoderK   evidence_filezAllegato non valido)original_namecontent_typerm   )r!   r   r   r   
ValueErrorr   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partrz   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O!G" = 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 )Nrm   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sha256rm   )r%   r<   MAX_EVIDENCE_BYTESr   r!   r:   lowerr   rz   hashlibr   	hexdigest)r   rm   detected_typer   declared_types        r+   _validate_review_attachmentr      s2   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 rK   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 )
NTrS   i  r   rv   wbrm   rw   stored_name)REVIEW_EVIDENCE_DIRr_   r#   r   r`   r:   O_WRONLYO_CREATO_EXCLfdopenrb   r&   r   r   )	proposal_idr   r   targetfdhandler   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                     g }| j                  dg       D ]R  }t        |j                  d      xs d      j                         }|s2t        |      }d|d<   |j	                  |       T |S )Nunclassified_tradesorder_idr.   CLASSIFICATION_BLOCKEDanomaly_type)r%   r:   r    dictappend)rm   
candidatesrowr   items        r+   _review_candidatesr      sq    J xx-r2 $swwz*0b17799D#;D d#$ rK   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.   actionstrategyreasonevidencenotesz*Caso non presente tra le anomalie correntizAzione non validar/   z#Strategia obbligatoria o non validaz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)statuspendingr   r   Nr%   ).0r   r   r   s     r+   	<genexpr>z*_create_review_proposal.<locals>.<genexpr>  sZ        	i' 	)HHZ H,	)HHX&(	)s   A
Az:Esiste gia una proposta pendente identica per questo tradezreview-z%Y%m%d%H%M%S-r   r   r   symbolsideclosed_sizeqtyr   avg_entry_priceentry_price
entry_time
created_at
updated_atpnl_netpnlclassification_sourceoperational_reason)r   r   r   r   r   r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   trade_snapshotevidence_attachmentTrw   zreview proposal saved id=r   z order=z action=z
 strategy=)r:   r%   r    r   _canonical_strategyr   r   REVIEW_ACTIONSVALID_CLOSED_TRADE_STRATEGIESr   ro   anyr   r[   r   r?   rG   r{   r|   r\   r   r   r   r&   r   re   )r   rm   r   r   r   r   r   r   r   tradevalidated_attachmentqueuer   proposalattachment_pathr   r   r   s                   @@r+   _create_review_proposalr      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;Md;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
H0 O	+(?Ma(b%Ho.6H*+X5!
 
#H]$;#<GH: NHO#4	6 OC Ur  &""d"3s   "N!2N& &Oc                    d  t        |      j                  d      r|nd      }t        |       }t               }|D cg c]  }|j	                  d      dk(  s| }}dj                  fdt        t              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| 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+   <lambda>z)render_review_dashboard.<locals>.<lambda>?  s    C1B$KSWX rK   /r   r   r.   c              3   d   K   | ]'  }d  |       d |j                                d ) yw)z<option value=''>z	</option>N)upper)r   r   escs     r+   r   z*render_review_dashboard.<locals>.<genexpr>D  s9       #h-3x~~/?+@*AKs   -0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   r   r   r   r   )orderkindr   r   r   N)formatr%   	_fmt_usdtr   r   r  s     r+   r   z*render_review_dashboard.<locals>.<genexpr>H  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   r   r   r   r   r   r   r   r   r   r   r   r   )	r  r   r   r   entryopenedclosedr
  r   N)r  r%   rO   r  r  s     r+   r   z*render_review_dashboard.<locals>.<genexpr>R  s      	;;A6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>r   r.   r   r   r   r   r   r   r   r   r   r   zm<br><a class='evidence-link' href='review/evidence/{name}' target='_blank' rel='noopener'>Apri screenshot</a>)rz   )createdr   r   r   r   r
  r   r   N)r  r%   )r   r   r  s     r+   r   z*render_review_dashboard.<locals>.<genexpr>b  sA     ( '	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	 disableda  <!doctype html>
<html lang='it'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>
<title>V2 Gestione 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}
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 Gestione anomalie</h1><a id='mainDashboardLink' class='btn secondary' href='z'>Torna alla dashboard principale</a></div>
<p class='notice'>Le proposte vengono salvate in una coda di revisione. Non modificano policy, KPI, ordini o posizioni.</p>
z+
<section class='panel'><h2>Casi correnti (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>Nuova proposta</h2><form id='proposalForm' method='post' enctype='multipart/form-data'>
<div class='grid'><div><label>Caso anomalo</label><select name='order_id' required>zH</select></div>
<div><label>Azione</label><select name='action' requiredas  ><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>a<  </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'zt>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.getElementById('exportLink').href=p+'/export.json';
const mainLink=document.getElementById('mainDashboardLink');
const publicMain=p.endsWith('/review')?p.slice(0,-7):'';
if(mainLink&&publicMain){mainLink.href=publicMain;}
</script></main></body></html>)
r:   r!   r   ro   r%   joinsortedr   reversedr<   )rm   r   errormain_urlsafe_main_urlr   r   r   pending_queuestrategy_optionscandidate_optionsanomaly_rows
queue_rowsmessage_html
error_htmldisabledr  s                   @r+   render_review_dashboardr%  >  s   
XCCM$<$<S$AsKM#D)J E&+Odtxx/AY/NTOMOww <=   	  	  	 77    U 
U    ( ]+)  T* 
T+ , ?F%c'l^6:2L;@$SZL7bJ",{"He fsds tzl ++.z?*;  <K  LX  KY YSS[R\\]^o]p q99A
 C} ~N  }O O
 "
 #DDGDVCW  XY  Zd  Ye e1 "  "q 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&   re   )r(  ces      r+   get_bybit_positionsr0    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resultrl   coinwalletBalancezbybit balance err:         )r)  r*  r+  r:   r   r,  r(  _requestfloatr&   re   )r(  r.  br8  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}|j	                  ||      S )Nr.   _closeivptr3
rettangolorettangolo_simplersi_swing_breakoutma_trailing	range_fibadxsupertrend_bosw)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)r:   r    r   endswithr%   )r   r   aliasess      r+   r   r     s    	rN  "((*E
..
"cr
 ..
" % 3*22$ !2,G ;;ue$$rK   >	   rM  sqwrG  rL  rH  rK  rN  rI  rJ  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_fingerprintsstrategy_by_closed_order_idstrategy_by_trade_fingerprintblocked_assetsrg   rX   rZ  r^  r[  r.   r   r`  effective_fromNz9blocked asset policy ignored: invalid effective_from for blocked_assetnew_entries)ra  r   scoper\  r]  r_  r   zstats trade policy err: )setSTATS_POLICY_PATHr   ri   rj   r   r%   r:   r    r   r   rk   r   r  rE   re   r   r&   )emptyrm   r   excludedr   r   mappingoperational_by_order_idraw_operational_idsruler`  r   ra  r   rn   s                  r+   _load_stats_trade_policyrm    sn    &)U13')35'))+E ##%: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59A3tzr?CXCXCZ8[+H5\  HH%5r:@@B 	LFD2&,,.446FD$!7 *:!;!ArBHHJN~.6OPVxXY"0dhhx0CODJJL&&N6"	 *25L!%*G!L,dD) ,
 "&*SUW!X8dD) 8 ,3!%*I2!N.dD)'(<=A^^ .
 -#
 	
G


B,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_equalry  2  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   r   r   r   c              3   D   K   | ]  }j                  |      d v   yw)ro  Nr   )r   r   fingerprints     r+   r   z-_matches_trade_fingerprint.<locals>.<genexpr>E  s     
B#;??3:-
Bs    Fr   r.   r   
closedSizer   avgEntryPricer   avg_entry_price_toleranceavg_exit_pricero  avgExitPrice
closed_pnl	closedPnlclosed_pnl_toleranceclosed_at_fromclosed_at_toupdatedTime	createdAtr   r8   r9     T)r   r:   r%   r    r  ry  r=   r<  r   r@   rA   	timestamprr  r   OverflowError)closed_itemr|  required	closed_msstart_msend_mss    `    r+   _matches_trade_fingerprintr  B  s   CH

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&   re   )r   connr   rn   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_mapping	certified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 ";;;rK   c           
         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|j+                         j-                  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/        |      }|t0        vr|j3                  |t        |d"   xs d      j	                         |t        |d   xs d      |d#       . t5        |      d$k7  rdd%t5        |       fS |d
   d&fS # 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 w xY w)'zJTrova una sola entrata usando l'intera firma del trade, mai il solo asset.)Nentry_db_missingr   r.   r   SELLBUYr  r  r}  r   r~  )Nentry_signature_invalidN)Nentry_signature_incompletezfile:z?mode=roT)urizSELECT 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=r  )Nentry_db_errorrp  rq  g|=g-C6
?r   r   >   no_positionanti_dup_skiprender_blockedrender_short_blockedrF  r   r   price
request_id)entry_order_idr  r   entry_time_rawr   r   entry_lifecycle_candidates_unique_entry_lifecycle)r  r   r:   r%   r    r  rE   rs  r<  rr  r   r  r  Rowrow_factoryr  fetchallr&   re   r  rt  r   rU  r   r   r   r<   )r  r   
close_side	open_sideclose_dtr   r   r  rowsrn   qty_toleranceprice_tolerancer   r   raw_strategyr   entry_dtrow_qty	row_pricer   s                       r+    _unique_entry_lifecycle_evidencer    s   >>'*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: 
 	1@ :!23z?2CDDDa=222w z" /./  &03%@A%JJL 	& JJL * :& 		sP   AL
 !AL 8-M1
LL	M(M9M MM M.1NN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.orderIdr.   r[  Nr   APPROVED_OPERATIONAL_EXCLUSION%operational_exclusion_closed_order_idT)r   sourceperformance_excludedr   entry_evidencer]  r   #UNAUTHORIZED_ORDER_WITHOUT_TV_ALERT!operational_exclusion_fingerprintr^  r   r`  ra  r  r  zblocked_asset_entry_unverified:Fr   "blocked_entry_after_effective_fromBLOCKED_ASSET_ORDER_LEAKr_  r   r   r  certified_trade_fingerprintconflicting_trade_fingerprints:)r:   r%   r    r  r  r  r  r  rE   r   r   r<   pop)r  r   close_order_idexact_operationalr   operational_matchesexact_strategyexact_sourcer  entry_sourcer   
block_ruleblocked_fromr  fingerprint_matchesr   fingerprint_strategiesr   r  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% 5 ?~N,1*,&*  l+|; 5B,0*D&4  1VZZ ?D ?R6:DHHZ01  66)<&	#	$	))--/"&&x0Q4Q

%' 	 
#	$q	(02R&		#)*5|&0\N!L>2R&  % ( %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   rC  Tr~  r?        ?rq  r@  {Gz?rA  rB  BTCUSDTZd;O?F)r%   r<  MY_TEST_FILTERrs  )r   symr   	avg_entrys       r+   is_mio_test_trader  V  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rK   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   FrA  rB  r  Tr?  r@  )r%   r<  rr  r   rs  )posr  r   s      r+   is_mio_test_positionr  g  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').rZ  r\  r^  r   r'  r   r  i \&linear2   )category	startTimeendTimelimitr2  z/v5/position/closed-pnlTr5  r7  rl   r   r.   r  r   r  r  r}  r~  r  r  openFeecloseFeetotalFeed   r   r   r   
exit_pricer   r   	pnl_grossfeepnl_pct_grosspnl_pct_netclassification_status
classifiedrX  r   r  r   r  r  r  r  )r   r   r   r   r   zbybit closed trades err: N)rm  r%   r)  r*  r+  r:   r   r,  r(  r=   
__import__r   r[   r   r?   r  SINCE_DATE_MSminr;  r    r  r  r<  rs  r   r  r&   re   )!outr   excluded_order_idsexcluded_fingerprintsstrategy_by_order_idr(  r.  now_ms	WINDOW_MScurrent_start
window_endparamsrr   itsym_rawr  classificationstratattribution_sourcer  qty_tentry_texit_tnet_pnlopen_fee	close_fee	total_fee	gross_pnlnotional_entryr  r  r/  s!                                    r+   get_closed_trades_bybitr   w  s9    C%'F ;<"JJ'DbI!"?@J3t9%5Z
+4488J9O9X9X9\9\]ggilppq+	%f$]Y6?J$*%	F 

5";VD
QAUU8_*//;ArE 2&&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[

 gBFF62. 5 "7	
 !& 7 w   9 $] ";  ,(-1F(FN  ,-?!" +N;Q,R#$ ).9M*N%& %n&8&89I2&N'( #1"4"45Er"J ."$&&b"9"$&&";/ 52f 'NM{ f$| 
 '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.)r0  r  )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  r  r   r   r  r&   re   )r  
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failedtotalz2SELECT status, COUNT(*) FROM queue GROUP BY statusr,  zqueue stats err: )
r  r   r  r  r%  r  r  r  r&   re   )r  r'  statsr   countr/  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   r   r   r  Fr?  r  &.>rA    r  r  rq  )r:   r%   MY_TEST_ORDER_IDSr<  rr  r   rs  )ooidr  r   r  s        r+   is_mio_testrE    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 )Nr   r.   r   xs    r+   r  z$compute_trade_pnls.<locals>.<lambda>2  s    !%%b*A rK   r   r   r.   r   )r  r  r.   Nr   r   r   r  r   r   buyr  r@  )r   r  r   rB   placeholdersellr  rL  F   longrB   )r   r   r   r   r  r   pnl_pctr   entry_tsexit_tswarn)r   rl   r  r%   rE  r   r   r   r<  rs  r  r  )orders	by_symbolrC  r  rD  tradesords	open_buysr   r   r  r  rB   rL  qty_to_closerK  matchedr   rP  rS  s                       r+   compute_trade_pnlsr[  .  sk    D!IF AB !eeHb!eeJ#<<55?aq>#a ! F__& )	T	 	)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(# #Q&9	))> MrK   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   Nr   r   ts     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>u  s%     Qaiua9Q   ,.c              3   @   K   | ]  }|j                  d d        yw)r  r   Nr   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>v  s     GA!%%Q/G   c              3   @   K   | ]  }|j                  d d        yw)r   r   Nr   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>w  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)r   r   r   N)rs  r<  r%   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>y  sF     wdeU155#:#?a@5uVWI]\]C^^_ws   AAc              3   `   K   | ]&  }|j                  d |j                  dd             ( ywrw  r   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>|  s%     M155AEE%O<Mrz  unrealisedPnlNr   r   r   %Y-%m-%dr   c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywrw  r   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     Haiua9Hrz  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywrw  r   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     Kqy!%%q/:Krz  g(\X@r  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywrw  r   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     S!%%	155?;Srz  c              3   `   K   | ]&  }|j                  d |j                  dd             ( ywrw  r   rx  s     r+   r   z*compute_kpis_from_bybit.<locals>.<genexpr>  s%     T155AEE%O<Trz  )rn  ro  rp  rq  rs  rr  rt  ru  )r<   r%   sumrs  r<  r&   rE   r   r   r[   r?   rM   rG   rt  daysr  )closed_trades	positionsrn  nry  r^  r_  rb  rc  rd  re  rf  
unrealizedr"  rg  first_trade_dtrB   _dt_tznow_utcrs  deltarq  total_win_pnltotal_loss_pnlrr  rt  ru  s                               r+   compute_kpis_from_bybitr  b  sn   MAAv

!1
&.
3<c

-s
 s
 %1#
 8H
 C	
 "0	

 s

 ,S
 #
  -c
 c)n
 /?
 S/2#
 	
 %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AD	 	#f+ 	ACIMC'3	
 	] 	 	? 	j 	. 	 	 	=1$s 	1,s 	WdcS]SSjm 	XesTmTTkn  	#i.!" 	*#$ %2Z%?+:Z+G$,&$&3 m OQ  		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   r   r.   r   ry  s    r+   r  z1compute_equity_curve_from_bybit.<locals>.<lambda>  s#    QUU<%8%UAEE,<O%USU rK   rJ  c              3   &   K   | ]	  }|d      ywr   N rx  s     r+   r   z2compute_equity_curve_from_bybit.<locals>.<genexpr>  s     &GAqx&G   r   r   r   r.   r  )sortrt  r  r%   r   r<   )r  rn  initial_equityr  r  r  cumry  rB   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`"* rK   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   r  feespnlsr  r  rK   r+   r  z0compute_by_strategy_from_bybit.<locals>.<lambda>  s    AcPS]`jl#m rK   r   r   r   r   r  r   r^  r  r  r   r  r  rs   c              3   .   K   | ]  }|z
  d z    yw)rs   Nr  )r   rI  means     r+   r   z1compute_by_strategy_from_bybit.<locals>.<genexpr>  s     4!q4xAo4s   r:  c              3   :   K   | ]  }t        d |      dz    yw)r:  rs   N)r  )r   rI  s     r+   r   z1compute_by_strategy_from_bybit.<locals>.<genexpr>   s     6As3{a'6s   )	r   r  r^  r`  r   r  r  sharpesortinoc                     | d   S Nr   r  rH  s    r+   r  z0compute_by_strategy_from_bybit.<locals>.<lambda>  
    1U8 rK   Tr   reverse)	r   r%   r  r   r   r  mathsqrtr  )r  by_stratry  rC   pnl_nr  dwrr  r  varstdr  ddsqr  r  r  s                   @r+   compute_by_strategy_from_bybitr    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)* 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)$: 	;;$ HH#TH2JrK   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   r  r  volumer  r  rK   r+   r  z-compute_by_asset_from_bybit.<locals>.<lambda>  s    AcPS]`lo#p rK   r   r.   r   r   r   r  r   r^  r  r  r   r  r   r   r  )r   r  r^  r`  r   r  r  r  c                     | d   S r  r  rH  s    r+   r  z-compute_by_asset_from_bybit.<locals>.<lambda>  r  rK   Tr  )r   r%   r   r   r  )r  by_assetry  rV   r  r  r  r  s           r+   compute_by_asset_from_bybitr    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 C  m1+,S6ai!C& 3&q

aafaiBU8!K.!F)_`ai_jl 	mm HH#TH2JrK   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   r  r  r  r  rK   r+   r  z6compute_by_asset_strategy_from_bybit.<locals>.<lambda>'  s    a3SZ] ^ rK   r   r.   r   r   r   r   r  r   r^  r  r  r   r  )r   r   r  r^  r`  r   r  r  c                     | d   | d   fS )Nr   r  r  rH  s    r+   r  z6compute_by_asset_strategy_from_bybit.<locals>.<lambda>:  s    AeHaf- rK   Tr  )r   r%   r  r   r   r  )
r  by_asry  rV   rC   r  r   r  r  r  s
             r+   $compute_by_asset_strategy_from_bybitr  #  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-. C[[] V	A+,S6ai!C& 3&q

aQQsVQvY[]U8!K.!F)U 	VV HH-tH<JrK   c                    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            }|3|j                         }|j                  d|j                  dd            }|dkD  r)||j	                            |j
                  xx   d	z  cc<   |dk  r)||j	                            |j
                  xx   d	z  cc<   ||j	                            |j
                  xx   d	z  cc<    |t        t        d            ||d
S c c}w c c}w )a>  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      )LunMarMerGioVenSabDomr   r   r   r   r   )r  hoursmatrix_wmatrix_l)rS  rE   r%   rM   weekdayhourrl   )	r  _r  r  r  ry  rI   local_dtr   s	            r+   compute_heatmap_from_bybitr  >  s8    #((+Qb+H+"'(+Qb+H+<D =QUU<0GAEE,4GH:==?eeIquuUA/7X%%'(71<71WX%%'(71<7 X%%'(71<7= 4b	?V^__# ,+s
   EE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^  r  r  r   rD  r  r  rK   r+   r  z'compute_trades_by_day.<locals>.<lambda>Z  s    q!#s_boq!r rK   r   r   r  r  r   r   r   r   r^  r  r  r   r   r.   rD  Tr  r  , )dater  r^  r`  r  r  r   rD  )	r   rE   r%   rM   rG   r   r  keysr  )	r  by_dayry  rI   day_keyr  r  r  r  s	            r+   compute_trades_by_dayr  X  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.	
 		 JrK   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.   r   r   r  rK  r   Nr4   )r   r   r  rB   r  r   r   )r  Tr  r   (,.0f@.4f)   —r  r  rD  )r   r   r  r   rl   rE  r%   r   r<  rr  r   r   r@   r  r&   r[   r?   r\   r  r  r  r<   )rT  r&  r   r   r  r  rC  r  r   r   r  rB   daystarttodayr'  r  r  entriesr/  symbols_strs                        r+   compute_entries_by_dayr  {  sG    76F Rq>eeHb!fb!'R..0	eQ,1-C!%%+0q1E !8uz5=UU<$"gsc#RPQ%R(,&&&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 :& 		  ,q!$))+, !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.   r   r   r   r  rK  r   )r   r  rB   c                      dg dS )Nr   )r  rD  r  r  rK   r+   r  z5compute_open_positions_by_entry_day.<locals>.<lambda>  s    qR!8 rK   r   avgPricezN/Dc                 &    | j                  dd      S )NrB   r.   r   rH  s    r+   r  z5compute_open_positions_by_entry_day.<locals>.<lambda>  s    quuT2 rK   rJ  rB   Nr4   r  r   rD  r  r  r  r  r  Tr  r  r  )r   rl   r%   r   r<  rr  r   r   _safe_floatrt  r  r  r  )bybit_positions	db_ordersr&  buys_by_symbolrC  r  r   r   r  r  r  r   	avg_pricebuysr  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.
 	 JE :& 		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 )a\  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   r   rH  s    r+   r  z,compute_top_bad_from_bybit.<locals>.<lambda>  s    quuUA rK   Tr  Nr   r.   r   worst_single_lossc                 &    | j                  dd      S )Nr  r   r   rH  s    r+   r  z,compute_top_bad_from_bybit.<locals>.<lambda>  s    !%%(;Q"? rK   rJ  )topbad)r  r%   r  r   r   )r  top_nr  rV   winnersr  asset_worst_lossry  r  r   
worst_lista2r  s                r+   compute_top_bad_from_bybitr    s6    +=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##- ;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   r   rH  s    r+   r  z+compute_top_single_losses.<locals>.<lambda>  s    aeeIquuUA? rK   rJ  Nr   r   r   r.   r   r   r   r  r  r   %Y-%m-%d %H:%M)	r   r   r   r   r  r   r  r   date_fmt)r%   r  rE   r   rG   )r  r  ry  losersr  rI   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

 
	 J! 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   Nr  (   rN     r4   )rJ  rI  rH  rK  rG  r  rW   rX   r   enabledtruer   r.   rO  rG  rH  c                     | d   S )Nr   r  rH  s    r+   r  z)get_strategy_for_symbol.<locals>.<lambda>K  s
    !A$ rK   Tr  r   )r  r   csvr   r`   
DictReaderr%   r    r:   r   r   r&   r  )r   r  	vptr3_csvrett_csvrett_simple_csvma_csvcsvmodPRIORITYr   csv_pathrd   readerr   rC   prios                  r+   get_strategy_for_symbolr$     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	$ OOO5a=%9 9  		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)aV  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  rW   rX   )ri   r   r   r`   loadr   rk   r:   r  r   r&   )ri   r*  rd   rm   r)   r*   s         r+   get_position_strategy_overrider'  O  s     33D;;=	$g. 	Y!499Q<D59ZZ\XTQZPQSVEWAGGIqwwy(X	Y 	YX	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,.rd   z0.00r<  r&   r*   decimalss     r+   r  r  d  s0    (2hZq.)*     	c                 D    	 t        |       d| dS # t        $ r Y yw xY w)Nrq   rd   z0.0r)  r*  s     r+   _fmt_pctr.  k  s0    (1XJa-() r,  c                 D    	 | t        |       S |S # t        $ r |cY S w xY wr  r)  )r*   r   s     r+   r  r  r  s.    =uQx5g5 s     c                 3   | d   }| d   }| d   }| d   }| d   d   }| d   d   }| d   }| d	   }| d
   }	| d   }
| j                  dg       }| j                  dg       }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,   d-k\  rdn|d,   d.k  rdnd}|d/   dk\  rdnd}|j                  d0d1      }|d2k\  rd}n|d3k\  rd}n
|d4k\  rd}nd}|d5k  r|d6nd7}|j                  d8d      }|j                  d9d      }|rd:| d;nd<} d1}!d1}"d}#d}$d}%d}&|d'   }'|d(   }(d)}|d=   })d}*|d>   }+|+dk\  rdnd},|+|)z   |(z   }-|-dk\  rdnd}.|j                  d?d      }/|j                  d@d      }0|0dkD  r|/|0z  }1|1d6}2|1d2k\  rd}3n|1d4k\  rd}3nd}3nd7}2d}3|d*   }4|4dk\  rdnd}5|+|4z   }6|6dk\  rdnd}7|j                  d9d      xs d}t        |dA      }8|j                  dBd      rt        |j                  dBd      |8z  dC      nd}9|j                  dDd      |8z  }:|6|8z  };|;dk\  rdnd}<dE}=|;|=z  dFz  }>|>dk\  rdnd}?dj	                  g dGt        |dH          dI|dB    dJ|  dK| dL| dMt        |d,          dN|d?    dO|d@    dP|3 dM|2 dQ| dM| dR|. dMt        |-       dS| dTt        |(       dUt        |)       dV|, dMt        |+       dW|5 dMt        |4       dX|7 dMt        |6       dY| dMt        |d/          dZt        |d[          d\|d]    d^|9 d_t        |:       d`|? dM|>d6da|< dMt        |;       dbt        |dc          dd|de   d6df      }@|dg   dkD  r|d   }A|dh   }B|A}Ct        |C      dCk\  rt        C      t        |C      }E}Dt        |E|Dz
  di      }Fdj\  }G}Hdk}Ig }Jt        |C      D ]Q  \  }K}LI|Kt        C      dAz
  z  GdC|Iz  z
  z  z   }MH|Iz
  |LDz
  Fz  |HdC|Iz  z
  z  z
  }NJj                  |Mdldm|Ndl       S dnj	                  J      }Od}PCdo   }Q|Cd   }R|Q|Rz
  }S|Rdk7  rSt        R      z  dFz  nd}TSdk\  rdpndq}Ud}Vt        C      }Wt        t        J|C            D ]  \  }X\  }Y}Z|Yj                  dm      \  }[}\|Xt        B      k  rBX   nd}]drXdAz    }^|]rL	 t        ]      }_|_dskD  r_dtz  }_ddulm}`m}a |`j!                  _|aj"                  v      }b|bj%                  dw      }^ZCd   z
  }c|Cd   dk7  rct        Cd         z  dFz  nd}ddy^j)                  dzd{      j)                  dyd|      z   dyz   }eVd}[ d~\ dU dXdAz    d|e dZd6dcd6d|dd6d|XdAz    d|^ d|Zd6dz  }V
 g }fdD ].  }gD|gFz  z   }hHIz
  |g|HdC|Iz  z
  z  z
  }ifj                  |h|if       0 d}jd}kfD ]3  \  }h}ikdI d|idldG|Iz
   d|idld	z  }kjd|IdCz
   d|idz   dld|hd6dz  }j5 t        A      }l|ldk\  rdldz  dC|lz  dz  |ldAz
  gnt+        t-        l            }md}nd}o|mD ]  }pI|pt        ldAz
  dA      z  GdC|Iz  z
  z  z   }M|pt        B      k  rBp   nd}]d}^|]rJ	 t        ]      }q|qdskD  rqdtz  }qddulm}rm}s |rj!                  q|sj"                  v      j%                  dw      }^odMdldI d|MdldH|Iz
   d	z  }opdk(  rdnpldAz
  k(  rdnd}t|tdk(  rMdCz   ntdk(  rMdCz
  nM}und|udldHdz    dt d^ d	z  }n OdnJdo   j                  t1        d            d    dmHIz
   dn|I dm|H|Iz
   z   }vFdkD  rHIz
  dDz
  Fz  |HdC|Iz  z
  z  z
  nHIz
  }wdj	                  g dG dnHdz    d|Hdz    dk o dv dU dI d|wdld|G|Iz
   d|wdldO d|U dV dJdo   j                  t1        d            d    d~|Jdo   j                  t1        d            dA    d|U dj n dCd   dd|U dQddTddt        |C       d|U d      }xnAd   }Ld|Ld6d}xt3        j4                  |      }ynd}xt3        j4                  g g g d1d1d      }y|rVg }z|D ]q  }{|{d   dk\  rdnd}|zj                  d{d    d|{d    d|{d?    dt        |{d,          dt        |{d          dt        |{d          d|| dt        |{d          d       s t7        d |D              }}t7        d |D              }~|}r~}z  dFz  nd1}t7        d |D              }t7        d |D              }t7        d |D              }|dk\  rdnd}dk\  rdnd}zj                  d} d~ dt               d dt               dt               d| dt               d       ddj	                  |z      z   dz   }nd}|r g }|D ]  }{|{d   }l|{j                  dd1      }|{j                  dd1      }|{d   }|dk7  r j)                  ddn      j9                         nd}ldCk\  rOd4k\  rdndk  rdnd}d3k\  rdndk  rdnd}dʛ}dʛ}d dl d{d?    d|l|{d?   z
   d|{d,   dld|{d   d6dН}ndx}}dx}}d dl dҝ}j                  d d dl d d d d dٝ        ddj	                         d۝}nd}|rg }z|D ]q  }|d   dk\  rdnd}|zj                  dd    d|d    d|d?    dt        |d,          dt        |d          dt        |d          d|| dt        |d          d       s ddj	                  z      z   dz   }nd}d߄ } ||d      } ||d      }| j                  dg       }|rg }zD ]  }zj                  d|j                  dd       d|j                  dd       d|j                  dd       d|j                  dd      dd|j                  dd      dd|j                  dd      dd|j                  dd      d6d|j                  dd      d6d        ddj	                  z      z   dz   }nd}| j                  dg       }|rdg }zd}}D ].  }}|d   z  }}zj                  d|d    d|d    d|d    d       0 zj                  d} d       ddj	                  |z      z   dz   }nd}|j                  dt-        d      D cg c]  }dgdz  
 c}      }|j                  dt-        d      D cg c]  }dgdz  
 c}      }t-        d      D Hcg c]*  }t-        d      D Hcg c]  }H   |H   |   |H   z    c}H, }}}Ht;        d |D              rFrt        d D              ndA}t        |dA      }g }dg}|d   D ]  }Hj                  d |H d        j                  ddj	                        z   dz          t        |d         D ]  \  }}d| dg}t-        d      D ]^  }H   |H   }G|   |H   }|Gdk(  rdk(  rj                  d       1dkD  rGz  nd}dkD  rz  nd}t=        dd-z  z         }t=        dd	|z  z         }t=        d
d|z  z         }d| dm| dm| d;}t=        dd|z  z         }t=        dd|z  z         }t=        d
d-|z  z         }d| dm| dm| d;}dk(  r#j                  d dG d dM|G d	       Gdk(  r$j                  d dG d dM| d	       $d d| d d| d	}j                  d| dG d d|G d| d       a j                  ddj	                        z   dz           d}ddj	                        z   dz   |z   }nd}| j                  dg       }|rIg }zD ]p  }|d   dk\  rdnd}|zj                  dd    d|d    d|d?    d|d,   dldt        |d          dt        |d          d|| dt        |d          d|d    d       r t7        d D              }t7        d |D              }t7        d  |D              }t7        d! |D              }t7        d" |D              }|rz  dFz  nd}dk\  rdnd}zj                  d# d ddldt               dt               d| dt               d$       d%dj	                  |z      z   dz   }nd&}d'}rFt              dAk\  r7t?        d( )      }t        |      }|D cg c]  }|d   	 }}g }d1}|D ]  }L|Lz  }j                  |        t        t              d      }t        t        |      d      }t        ||z
  di      }||Đd*z  z   }||Đd*z  z
  }||z
  }t        t              d      }t        t        |      d      }t        ||z
  di      }||ʐd*z  z   }||ʐd*z  z
  }||z
  }͐d+\  }G}Hd,\  }}}}|G|z
  |z
  }|H|z
  |z
  }g }dAkD  r.t-              D ]  }Kj                  |KdAz
  z  z  z          ! nj                  dCz  z          t        t        dA      z  d-z  dC      }d}t        t                    D ]a  \  }K\  }}dAt        |d      z
  z  z
  z  z   }|dAt        |d      |z
  |z  z
  |z  z   }|dAd|z
  |z  z
  |z  z   }|dk\  r}}dp}Un}}dq}Uc g }t        t                    D ]1  \  }K\  }}dA|z
  z  z
  z  z   }Nj                  |dldm|Ndl       3 dnj	                  ޫ      }g }t        t                    D ]1  \  }K\  }}dA|z
  z  z
  z  z   }Nj                  |dldm|Ndl       3 dnj	                        }g }dD ](  }g|gz  z   }hdA|gz
  z  z   }ij                  |h|if       * d}d}kD ]5  \  }h}ikdΛ d|idldGz
   d|idld	z  }kd|ΐd.z
   d|idz   dld/|hddz  }7 g }dD ](  }g|gz  z   }hdA|gz
  z  z   }ij                  |h|if       * d}D ]!  \  }h}idGz
  d.z    d|idz   dld0|hddz  }# d}ndkkD  r't        dAd1z        }t+        t-        d||            }mnt+        t-                    }mmD ]/  }p|pk  s	p   }Mnd|MdldHz
  d2z    d3|p   d   d.d   dz  }n1 rdo   j                  dm      nd4d4g}dG dnH d|H dk d5 d6 d7|d    d~|dA    d8  n d9 d:do   dd;}|rg }z|D ]w  }|d   dk\  rdnd}|zj                  dd    d|d    d<|d   jA                          d|d    d=|d>    d|d?    d|d@    d|dA    d|| d|dB    dC|dD    dE       y dFdj	                  z      z   dz   }ndG}|	rg }z|	D ]  }|j                  dH      rdInd}j                  dd      }|j                  dd      }|j                  d|j                  dd            }|dkD  rdndk  rdnd}zj                  ddJ    d|d    dK|d    d|d    d=|dL    d|dM     d|dN    d|d    dOt               dt               d| dt               d        zr'dPt        z       dQdj	                  |z      z   dz   }ndR}ndS}dT| dU|
 dV| dW| dX@ dYx dZ d[ d\ d] d^ d_ d` da db}|S # t&        $ r ]r]d dx ndrXdAz    }^Y w xY w# t&        $ r t/        ]      d dk }^Y w xY wc c}w c c}w c c}Hw c c}H}w c c}w (c  Nkpisr  by_strategyr  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 r  z 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>r   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>rb  rc  rd  rS  rm  ro  r`  r  r  rh  rr  r:  g       @g      ?r  c   z.2fu   ∞rs  rq  zTrading days (dal r  zTrading daysrf  rg  r^  r_  r   r]  rs   re  g     @@r  zO
  <div class="kpi"><div class="kpi-label">Balance</div><div class="kpi-value">rn  ze USDT</div></div>
  <div class="kpi"><div class="kpi-label">Trade chiusi</div><div class="kpi-value">z7</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;">zW / zgL</small></div></div>
  <div class="kpi"><div class="kpi-label">Win to Loss</div><div class="kpi-value z`</div></div>
  <div class="kpi"><div class="kpi-label">Profit Factor</div><div class="kpi-value ze</div></div>
  <div class="kpi"><div class="kpi-label">Gross PnL (chiusi)</div><div class="kpi-value zb USDT</div></div>
  <div class="kpi"><div class="kpi-label">Fee totali</div><div class="kpi-value z">-zh USDT</div></div>
  <div class="kpi"><div class="kpi-label">Loss chiuse</div><div class="kpi-value bad">zu USDT</div></div>
  <div class="kpi"><div class="kpi-label">P&L Realized (Gross-Loss-Fee)</div><div class="kpi-value zf USDT</div></div>
  <div class="kpi"><div class="kpi-label">Unrealized PnL</div><div class="kpi-value zu USDT</div></div>
  <div class="kpi"><div class="kpi-label">Net P&L (Realized-Unrealized)</div><div class="kpi-value za USDT</div></div>
  <div class="kpi"><div class="kpi-label">Avg trade</div><div class="kpi-value zh USDT</div></div>
  <div class="kpi"><div class="kpi-label">Best trade</div><div class="kpi-value good">rj  zi USDT</div></div>
  <div class="kpi"><div class="kpi-label">Posizioni aperte</div><div class="kpi-value">rl  zc</div></div>
  <div class="kpi"><div class="kpi-label">Trade al giorno</div><div class="kpi-value">zj</div></div>
  <div class="kpi"><div class="kpi-label">Nozionale Bybit/giorno</div><div class="kpi-value">zd USDT</div></div>
  <div class="kpi"><div class="kpi-label">Day Profit %</div><div class="kpi-value za%/gg</div></div>
  <div class="kpi"><div class="kpi-label">Day Profit</div><div class="kpi-value zm 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>
r  r  r  )i      r4   z.1f, r   z#3fb950z#f85149r   g   mBr5   r   r6   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:  g      ?g      ?g      ?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"/>
    r  endmiddler   z" text-anchor="zJ" font-size="11" fill="#c9d1d9" font-family="monospace" font-weight="600">,   zU<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="zc" 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  r   r  r  zW)</td><td>z%</td><td class='pnl good'>r  z</td><td class='pnl warn'>-r  c              3   &   K   | ]	  }|d      ywr  Nr  r   rC   s     r+   r   z#render_dashboard.<locals>.<genexpr>  s     2af2r  c              3   &   K   | ]	  }|d      ywr^  Nr  rI  s     r+   r   z#render_dashboard.<locals>.<genexpr>       8q68r  c              3   &   K   | ]	  }|d      ywr  Nr  rI  s     r+   r   z#render_dashboard.<locals>.<genexpr>  s     >Q!K.>r  c              3   &   K   | ]	  }|d      ywr  Nr  rI  s     r+   r   z#render_dashboard.<locals>.<genexpr>  rL  r  c              3   &   K   | ]	  }|d      ywr  r  rI  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  unknownr  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>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).
        rU  r   r   r  r  ztitle="Worst single: z USDT | PnL aggregato: z USDT"z<td class="pnl z" r  z
 USDT</td>r8  r.   r<  r9  r   r:  r  r`  z%</td></tr>zE<table><tr><th>Symbol</th><th>Trades</th><th>WR</th><th>PnL</th></tr>rR  )r%   r  r   r.  r  )
r   	cls_colorr  rV   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x	y WY[Y`Y`aeYffisssrK   single_lossesr  r   r   ,.2fr   ,.5fr  z</td><td class="pnl bad">z  USDT</td><td class="pnl warn">-r   z
</td></tr>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_dayr  z</td><td><b>z</b></td><td><small>rD  z</small></td></tr>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  r  r  r  c              3   8   K   | ]  }t        |      d kD    yw)r   N)r  r   r   s     r+   r   z#render_dashboard.<locals>.<genexpr>F  s     
.C3s8a<
.s   c              3   2   K   | ]  }t        |        y wr  )rt  rd  s     r+   r   z#render_dashboard.<locals>.<genexpr>H  s     7SC7s   z(<td class='hm-corner'>Giorno \\ Ora</td>r  z<td class='hm-h'>z</td>z<tr>rW  r  z<td class='hm-d'>z2<td class="hm-c" style="background:#0d1117;"></td>            9   zrgb(   @   z#<td class="hm-c" style="background:z;" title="W:z L:zlinear-gradient(to right, z 0%, z 50%, z 100%)z,"><span style="color:#fff;font-weight:600;">|z</span></td>a]  <div style="margin-top:8px;font-size:11px;color:#8b949e;"><span style="display:inline-block;width:12px;height:12px;background:rgb(63,185,80);margin-right:4px;"></span>Win <span style="display:inline-block;width:12px;height:12px;background:rgb(248,81,73);margin:0 4px 0 12px;"></span>Loss <span style="margin-left:12px;">Celle miste: W|L</span></div>z<table class='hm'>zD<div class="empty">Nessun dato heatmap. Aspetto chiusure Pine.</div>trades_by_dayz USDT</td><td><small>c              3   &   K   | ]	  }|d      ywrN  r  r   r  s     r+   r   z#render_dashboard.<locals>.<genexpr>  s     ?1+?r  c              3   &   K   | ]	  }|d      ywrP  r  rp  s     r+   r   z#render_dashboard.<locals>.<genexpr>       9Qqy9r  c              3   &   K   | ]	  }|d      yw)r   Nr  rp  s     r+   r   z#render_dashboard.<locals>.<genexpr>  s     ;qa	l;r  c              3   &   K   | ]	  }|d      ywrH  r  rp  s     r+   r   z#render_dashboard.<locals>.<genexpr>  s     3qAcF3r  c              3   &   K   | ]	  }|d      ywrK  r  rp  s     r+   r   z#render_dashboard.<locals>.<genexpr>  rr  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 )Nr  r  )r  s    r+   r  z"render_dashboard.<locals>.<lambda>  s
    1V9 rK   rJ  g?)i  i  )<   rw  r4   #   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="zW" fill="none" stroke="#3fb950" stroke-width="2" opacity="0.85"/>
    <polyline points="zD" 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>z </b></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><tr><th>Symbol</th><th>Strategia</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>rL  u    ⚠️placeholdercreated_at_fmtz</td><td><span class='badge 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 { 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; }
.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; }
.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; }
table.hm { border-collapse: collapse; font-size: 10px; width: 100%; }
table.hm td { padding: 2px; text-align: center; min-width: 18px; height: 18px; color: #fff; }
table.hm td.hm-corner, table.hm td.hm-h, table.hm td.hm-d { background: #161b22; color: #8b949e; font-weight: 600; }
table.hm td.hm-c { color: #0d1117; font-weight: 600; }
</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;">Gestione anomalie (u>   )</a></h1>
<div class="footer">Auto-refresh 30s • Generato: uD    • <a href="/json" style="color:#58a6ff;">/json</a> per API</div>
rZ   z
<div class="kpi-grid">u<   </div>
<div class="section">
  <h2>📈 Equity Curve</h2>
  ua   
</div>
<div class="section">
  <h2>🎯 Sharpe / Sortino per Strategia (per-trade, rf=0)</h2>
  uN   
</div>
<div class="section">
  <h2>📋 Posizioni Aperte (live Bybit)</h2>
  uO   
</div>
<div class="grid-2">
  <div class="section"><h2>📊 Per Strategia</h2>u5   </div>
  <div class="section"><h2>💎 Per Asset</h2>u]   </div>
</div>
<div class="section">
  <h2>🔥 Heatmap Giorno × Ora (chiusure trade)</h2>
  uB   
</div>

<div class="section">
  <h2>📅 Trade per Giorno</h2>
  uW   
</div>
<div class="section">
  <h2>📊 Daily PnL (barre) + Cumulativo (linea)</h2>
  uK   
</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';}
</script>
</body>
</html>)!r%   r<   r   r  r  rt  roundr.  r  	enumeraters  zipr"   r<  r   r   r>   r?   rG   r&   rA   rl   rS  r:   chrri   r~   r  r[  r   r=   r  r   )rm   r1  r  r2  r  r  r  r4  r  recentr6  rX  r7  anomaly_countunclassified_rowsr   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_daterq  
days_labelsharpe_v	sortino_vsharpe_classsortino_classsharpe_displaysortino_display
gross_baser  r_  losses_classrg  pnl_realized_classgross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kpi_htmleq_ptseq_datescum_pnl_ptsmin_vmax_vrngwhpadpointsir*   rI  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  rC   clstotal_n
total_winstotal_wrtotal_grossrd  	total_net	gross_clsnet_clsstrategy_htmlboxesshsoname_raw	name_dispsh_clsso_clssh_dispso_dispr[  strategy_sharpe_htmlrV   
asset_htmlr^  top_htmlbad_htmlr_  ry  single_losses_htmlrb  r  open_by_day_htmlr  r  r  
matrix_tot	max_countheatmap_rowscellsd_idxr  lintensity_wintensity_lrwgwbwcolor_wrlglblcolor_lbglegendaheatmap_html_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_htmlrC  rS  r  r   r   pnl_net_classorders_htmlr  s                                                                                                                                                                                                                                                      r+   render_dashboardrN  z  s-   <D(^F}%KJH
y/%
 C
y/%
 C9oG[!I/"F'L88126L!XX&>C%M! 		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
	 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?Cxx
TU?VU488J2R7;\]Nxx 0!4r9r\N!/1!4v% ),??3F%8A%=65  O OXY]^gYhOiNjkTTXYcTdSe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 VfTf gi jss}i~h@d encn oq r{  |C  rD  qEEP QZ{ [] ^ggklugv]w\xyW XaaefrasWtVuvX Y]]mXnWopW  XfVf! g^!" _hhx^y]z#"{S#$ ThRh%$ ik%$ l  @C  kD%$DQ%& RbPb'& ce'& foo}e~d'&@Y'( ZccijwcxYyXz)( {D)( EK  LX  EY  Z]  D^)(^)H0 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 !\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558UG2eWBs3irRYZ]Q^^`ajkn`o p% &)UG3xjSI N&'': 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#w&  AfRj&6&6s2w&?&B%C1QsUG1SEQRSTUXSXRY"ZZHFIAgQWUc 1a!c'kBBSTWZSZF5
 5
  5
C5
5
25
\5
]^_a]a\b5
c5
L5
5
-5
.6Z5
7?5
@Ew5
G5
 e5
 5
 !5
 &,5
 -.cE75
 395
 :@5
E5
  j	5
 !7	5
 8=g	5
>	5

 N5

5
 !!#b'*1-.5
 /55
 6<BZ5E5Ec"g5Nq5Q4R5
 Sa5
 bg`g5
h5
 M5
 5
5
 a.&5
'5
 w5
 75
 8>dm5
 DK5
 LVVZJ[5
\5
 {
5
A5
  BG  AH!5
 %H!5
Kp q	A V  WX  Y\  V]  ]h  iKjj({jj2[^nq!rs  	[AeHM&uCKK(1Z=/1S6("QvYK{[cdefodp[qZr  sN  OX  YZ  [f  Yg  Oh  Ni  iD  EN  OP  QW  OX  EY  DZ  Zn  or  ns  su  v  @A  BG  @H  vI  uJ  JY  Z  [	[ 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	
 }  @B  @G  @G  HL  @M  M  PZ  Zu  	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)	6 "87GvN  Y  	YAeHM&uCKK(1X;-y31V9+[YabcdmbnYoXp  qL  MV  WX  Yd  We  Mf  Lg  gB  CL  MN  OU  MV  CW  BX  Xl  mp  lq  qs  t}  ~  @E  ~F  tG  sH  HW  X  Y	Y wy{  zA  zA  BF  zG  G  JT  T
J
t2 #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R {{:a'A1B'ABH{{:a'A1B'ABHPUVWPXY1E"IFq8A;q>HQKN2FYJY

.:
..;EC7J771		1%	=>! 	7ALL,QCu56	7FRWWU^3g=>#GFO4  	CJE3(U34E2Y eUOA&UOA&6a1fLL!UV 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Av'J7)S_`a_bbefgehhjkljmmr%sta'J7)S_`a_bbefgehhjkljmmr%st  :'%yPVW^V__efmenntu'J2$l[\Z]]`ab`c  dP  QR  PS  ST  UV  TW  Wc  &d  e;e<  7' ABA 	CDS ,bggl.CCjPSZZ] 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!! 	" $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
$  	AeHM&uCKK(1X;-|AjM?Jjklmsktkzkzk|j}}  AB  CI  AJ  @K  K[  \]  ^h  \i  [j  js  tu  vA  tB  sC  CL  MN  OY  MZ  L[  [d  ef  go  ep  dq  qE  FI  EJ  JL  MN  OX  MY  LZ  Zh  ij  kp  iq  hr  r}  ~  	 e  hj  ho  ho  pt  hu  u  xB  BL  	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D(wP xE  wF F44@> B    j ! -     3 4A/ B//9l ; . 
     - 
YVDn KU % J286#2;#a%kJV % 4#&v;s#34J (B'AFY^ 8sc   =AAf2A	Af,Ag

:Ag
Ag.AgAgN AgfAf)f(Af)f,AggAggAg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| }}t               }t	               }t               }t        dd      }t        |||      }	t        ||      }
t        |      }t        |      }t        |      }t        |d      }t        |      }t        |      }t        |d      }t!        |      }g }|D ]_  }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'                               }|j+                  |||j                  dd      ||d||d||d||dkD  r|dnd||d|dkD  r|dndd       b g } t-        |d d !      }!|!d"d# D ]<  }"t/        |"j                  d$      xs |"j                  d%            }#| j+                  |#r|#j1                  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 d/|	d0|
d1|d2|d3|d4|d5|d6|d7|d8|d9|d:| d;|d<|d=|sd>nd?t3        |      t3        |      z
  t3        |      t3        |      d@dAdB|dCt5        j6                  t8        j:                        j=                         j1                  dD      S c c}w c c}w c c}w )Eu   Dati SOLO da Bybit (no webhook DB orders). Trade chiusi + posizioni aperte,
    filtrati dal 1° agosto ed escludendo MIEI test Pine-style.r  r     
2026-08-01)r  r&  ry  )r  r   r  	markPricestopLossr  leverager   r   r.   VPTR3
RETTANGOLORETT_SIMPLEMA_TRAILINGSUPERTREND_BOSW)rG  rH  rI  rK  rN  r   z,.4fra  r   r  r`  z.0f)r   r   r   r   r|  r  r}  markr~  slr  r   r  r  c                 R    | j                  d      xs | j                  d      xs dS r  r   r  s    r+   r  zassemble_data.<locals>.<lambda>	  s"    aeeL)FQUU<-@FB rK   Tr  Nr  r   r   r  r   r   r  r   r   r   F)r  r   r   r  r  r  r   r  r   r   r   rL  is_realis_testr1  r  r2  r  by_asset_strategyr3  r4  rn  r_  rb  r  r5  r   r7  classification_integrityOKWARNING(exact_order_id_or_unique_entry_lifecycle)r   r  rX  operational_excludedrl  queue_statsr6  %Y-%m-%d %H:%M:%S)r   r%   r  r#  r>  r/  r(  r  r  r  r  r  r  r  r  r  r  r  r'  r  r$  r   r  rE   rG   r<   r   r[   r   r?   rM   )$all_closed_tradesr   r7  r  r   r  rn  re  r  r1  r  r2  r  r_  r3  r4  rn  r_  rb  positions_fmtr"  r   r  rZ  r[  r   r  r  pos_overrider  strat_labelsstrat_labelr  closed_trades_sorted_recentry  _tss$                                       r+   assemble_datarn  	  s    01,99+, 	 
 -yy/0 	M 
 )99Z $99 	  12I!G!#K,?I"=)WED,]GDF0?K*=9H<]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<#EE&"%dE$<dQ2d)Ec$Z#&7c#Y

 
	+H 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 
 	&& 	{ 	H	
 	. 	7 	7 	 	 	{ 	] 	 	2 	!"8 	#"5d9m,s3F/GG 34$'(>$?>%
, 	{-. 	X\\2==?HHI\]/ ws   Q3Q8!Q=c                   >    e Zd Zd Zd Zd Zd
dZd Zd Zd Z	d	 Z
y)StatsHandlerc                      y r  r  )selfrH   argss      r+   log_messagezStatsHandler.log_message	  s    rK   c                 ~   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)NTAuthorizationr.   zBasic Fr   rr   rW   ignorer   r  r   )	AUTH_PASSheadersr%   r!   base64	b64decoder   r"   hmaccompare_digest	AUTH_USERr&   )rr  authrz  decodedur"  s         r+   _check_authzStatsHandler._check_auth 
  s    ||4x(	&&tABx0777QG'!==a(DAq&&q)4Z9L9LQPY9ZZ 		s   -B0 %A
B0 0	B<;B<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wfilerb   )rr  s    r+   _send_unauthorizedzStatsHandler._send_unauthorized
  sQ    3+-EF6

,-rK   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   rt   rW   r  zapplication/json; charset=utf-8Content-LengthCache-Controlno-storeContent-Dispositionzattachment; filename="r   X-Content-Type-Optionsnosniff)
ri   r~   r:   r   r  r  r<   r  r  rb   )rr  coderm   attachment_namer   s        r+   
_send_jsonzStatsHandler._send_json
  s    zz$%@GGP4 )JK)3s4y>:*526L_L]]^4_`5yA

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

$rK   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   rz   r  r   is_filesuffixr   r%   
read_bytesr  r  r:   r<   r  r  rb   )rr  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=

rK   c                    | 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 |rrt'        t        | j                        j(                        }|j+                  d      dgk(  rdnd}|d t-        d        xs d}	| j                  d	t/        |||	            S |dv s|j                  d      r| j                  d	t1        |            S |dk(  r| j                  d	|      S |dk(  r| j                  d	dd
d      S | j3                  d       | j5                          | j6                  j9                  d       y # t        $ r2}dd l	}| j                  dd|j                          d      cY d }~S d }~ww xY w)Nr  r  /reviewz/review/export.jsonr   rA  z<h1>500</h1><pre>z</pre>r=  zv2-stats-dashboardnone_pending_review)r6  servicepolicy_effect	proposalsr   )r  r  1z,Proposta registrata nella coda di revisione.r.   )r   r  )r.   r  z/indexz	/v2-statsz/jsonz/healthzok)r   r  r  s   404)r  r  r   r*  rstripr  rU  rn  r&   	tracebackr  
format_excr  r   r[   r   r?   r\   ro   r   queryr%   r<   r%  rN  r  r  r  rb   )
rr  r*  	is_reviewis_review_exportrm   r/  r  r  r   r  s
             r+   do_GETzStatsHandler.do_GETB
  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7EHM		R[H\ad`eHeDkmG,c)n_-4H??3(?g`h(ijj((DMM+,F??3(8(>??W_??3--Z??34DX(YZZs#JJV$1  	\??3*;I<P<P<R;SSY(Z[[	\s   
H 	H>'H93H>9H>c           
         | j                         s| j                         S t        | j                        j                  j	                  d      }|dk(  s%|j                  d      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#               }t%        |||       | j3                  d       | j5                  dd       | j5                  dd       | j7                          y # t        $ r | j                  dddi      cY S w xY w# t        $ r}		 t#               }|d t'        d        }
|
d t'        d        xs d}| j)                  dt+        |t-        |	      |            cY d }	~	S # t.        $ r% | j                  ddt-        |	      i      cY cY d }	~	S w xY wd }	~	wt.        $ r,}	t1        d|	        | j                  dddi      cY d }	~	S d }	~	ww xY w)Nr  z/review/proposalsi  r  method_not_allowedOriginr.   Hosti  origin_not_allowedr  r{  i  invalid_content_lengthr   i  invalid_payload_sizer  )r   z
/proposalsr  )r  r  zreview proposal err: rA  review_save_failedi/  Locationz../review?created=1r  r  )r  r  r   r*  r  rU  r  ry  r%   r    netlocr=   r   MAX_REVIEW_BODY_BYTESrfilereadr   rn  r   r<   r  r%  r:   r&   re   r  r  r  )rr  r*  originhostlengthr   r   r   rm   rn   review_pathr  s               r+   do_POSTzStatsHandler.do_POSTf
  s   !**,,		"''..s3++t}}=P/Q??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	I::??6*D1$,,2B2B>SU2VX\]D* ?D#D$:F 	3%:;*5/  	M??32J(KLL	M  	AA$"#6S%6$67&'7Y8?Cs,CDPSTWPXck,lmm AsWc#h,?@@A 	I'u-.??32F(GHH	Isb   <%G& AH	 &HH		KAI+%K+&JJKJJK(!K	KKr  )__name__
__module____qualname__rt  r  r  r  r  r  r  r  r  rK   r+   rp  rp  	  s+     .
%,"%H#rK   rp  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))
re   LISTEN_HOSTPORTr  rx  r
   rp  serve_foreverKeyboardInterruptserver_close)httpds    r+   mainr  
  s    
(Qtf=>$wi&	/STUVT*L9E 	   	s$   A> >	B
B 	B

B B__main__)rf  r  )r.   r.   r  )rP  rQ  )rQ  )ry  )rs   )r   )r:  )n__doc__r#   r)  ri   r  r  r|  r{   stringr  r   email.parserr   email.policyr   r   r   r   pathlibr   http.serverr	   r
   urllib.parser   r   collectionsr   zoneinfor   r   r  rf  rh   r   r  r   r=   r$   r%   r  r  r^   ra   r,   r~  rx  	frozensetr   rN   rE   rJ   rO   re   ro   r   r   r   r   r   r   r%  r0  r>  r  r   r   r  rm  ry  r  r  r  r  r  r  r  r?   r  r  r  r  r   r#  r(  r/  rB  rE  r[  r  r  r  r  r  r  r  r  r   r  r  r$  r'  r  r.  r  rN  rn  rp  r  r  r  rK   r+   <module>r     s   
 
         $ 0 '  : + #  ./
-,
,77 @@ @@ ' $ 
2::>>/623
---$  JJNN?,=>	JJNN?B/	   =)0E	(""J6"
IX]"B$ "&! 		%* !* 
+ 
!  ' GT/ 8v\(<&I3X\~ Jz*33D!Q1aPZ[ePfPoPoPsPs3t~~  A  DH  H  I" [|;,G$ (.1haHB"J.6`4 F1h0f#$L0,^*CNwvM) M`
 zF rK   