
    /jk             	         d Z ddlm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mZmZ ddlmZmZ ddlmZmZmZ  ed      Zed	z  Zej7                  d
       edz  Zedz  Zedz  Zedz  Z ej@                  ejB                  d ejD                  ed       ejF                         g        ejH                  d      Z% e	jL                         Z'd Z(dZ)ejT                  jW                  dd      jY                         Z-e-r?e-j]                  d      D  ch c]#  } | jY                         s| jY                         % c} Z/ne)hZ/e)Z0ejT                  jW                  dd      jY                         xs dZ1i Z2ejT                  jW                  dd      jY                         Z3e3rQe3j]                  d      D ]=  Z4de4v se4j]                  dd      \  Z5Z6e6jY                         e2e5jY                         <   ? dZ7d Z8d!Z9d"Z: e;d# e<ejT                  jW                  d$d%                  Z=d
Z>d&Z?d'Z@d(ZAd)hZBd)hZCd* ZDe(d+        ZEe(dQdRd,       ZFe(d-        ZGe(dSdTd.       ZHe(dUd/       ZIe(dVdUd0       ZJd1 ZKe(e=fdWd2       ZLe(e=f	 	 	 dXd3       ZMe(d4        ZNe(d5        ZOe(dYd6       ZPe(d7        ZQdZd8ZRd[d9ZSd\d:ZTd]d;ZUdZd<ZVdZd=ZWe(	 d^	 	 	 	 	 d_d>       ZXe(d`d?       ZYe(d`d@       ZZe(dadA       Z[e(dbdcdB       Z\e(dC        Z]e(dddD       Z^e(dE        Z_da`dF ZadedGZbdfdHZc G dI dJe      ZddK ZedgdLZfdM ZgdN ZhdO ZiejdPk(  r ee        yyc c} w )hu  
webhook_receiver.py — Webhook async per TV → Bybit V5.

ARCHITETTURA (fix del bug timeout):

    TradingView  ──HTTP POST──>  webhook
                                    │
                                    ├── validate secret + campi (~1ms)
                                    ├── enqueue su SQLite (persistente)
                                    ├── ritorna HTTP 200 IMMEDIATAMENTE  ← chiave!
                                    │
                                    └── background worker thread
                                            │
                                            ├── fetch prezzo Bybit
                                            ├── auto-bump qty
                                            ├── set leva
                                            ├── place order
                                            ├── log su orders.log UNICO
                                            ├── email notification
                                            └── mark completed su DB

PERCHÉ:
- TradingView timeout = 5-10s
- HTTP response deve tornare in <1s
- Tutto il resto (chiamate Bybit lente) avviene in background
- Se webhook crasha, la coda SQLite recupera gli ordini pending al restart
- PID file garantisce UNA SOLA istanza attiva (no race condition)

ENDPOINTS:
- POST /webhook   — riceve alert TV (fast, <100ms)
- GET  /health    — health check
- GET  /status    — stato coda (pending, completed, failed)
    )annotationsN)Path)datetimetimezone	timedelta)BaseHTTPRequestHandlerThreadingHTTPServer)time_guard_errorMAX_AGE_SECONDSMAX_FUTURE_SECONDSz /opt/charter-live/live_deploy_v2logsT)exist_okzwebhook_receiver.logz
orders.logzwebhook_queue.dbzwebhook_receiver.pidz1%(asctime)s [%(levelname)s] %(name)s: %(message)sutf-8encoding)levelformathandlerswebhookc                      fd}|S )Nc                 L    t         5   | i |cd d d        S # 1 sw Y   y xY wN)DB_LOCK)argskwargsfuncs     webhook_receiver.pywrapperzdb_serialized.<locals>.wrapperQ   s(     	)((	) 	) 	)s   # )r   r   s   ` r   db_serializedr    P   s    ) N    TV_2026_MATTIA_DEMOWEBHOOK_SECRETS ,WEBHOOK_DEFAULT_STRATEGYvptr3WEBHOOK_SECRET_STRATEGY_MAP:   z0.0.0.0i  g      @g333333?<   V2_PENDING_MAX_AGE_SECONDS6002   240d   VIRTUALUSDTc                    t         j                         rl	 t        t         j                         j	                               } ddl}|j                  |       r+t        j                  d|        t        j                  d       t         j                  t        t        j                                       t        j#                  dt        j                                 y# t        t        f$ r Y jw xY w)u>   Se c'è già un'istanza attiva, esci. Previene race condition.r   Nu/   ALTRO webhook_receiver già attivo PID=%d, escor*   zPID file scritto: %d)PID_FILEexistsint	read_textstrippsutil
pid_existslogerrorsysexitImportError
ValueError
write_textstrosgetpidinfo)old_pidr8   s     r   check_singletonrF      s    	(,,.4467G  )		KWU BIIK()HH#RYY[1 Z( 		s   A+C C,+C,c                 \   t        j                  t        dd      } | j                  d       | j                  d       	 | j                  d       | j                  d       | j                  d       | j                          t        j                  d	t               | S # t        $ r Y Yw xY w)
z.Inizializza DB SQLite per la coda persistente.F
   )check_same_threadtimeoutzPRAGMA journal_mode=WALah  
        CREATE TABLE IF NOT EXISTS queue (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            request_id TEXT UNIQUE NOT NULL,
            received_at TEXT NOT NULL,
            payload TEXT NOT NULL,
            status TEXT NOT NULL DEFAULT 'pending',
            error TEXT,
            order_id TEXT,
            processed_at TEXT
        )
    z=ALTER TABLE queue ADD COLUMN tunnel_pending INTEGER DEFAULT 0a  
        CREATE TABLE IF NOT EXISTS orders (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            request_id TEXT NOT NULL,
            order_id TEXT NOT NULL,
            symbol TEXT NOT NULL,
            side TEXT NOT NULL,
            qty REAL NOT NULL,
            price REAL,
            notional REAL,
            strategy TEXT,
            created_at TEXT NOT NULL
        )
    aL  
        CREATE TABLE IF NOT EXISTS position_ownership (
            symbol TEXT PRIMARY KEY,
            strategy TEXT NOT NULL,
            side TEXT NOT NULL,
            entry_request_id TEXT,
            entry_order_id TEXT,
            opened_at TEXT NOT NULL,
            source TEXT NOT NULL DEFAULT 'webhook'
        )
    zDB inizializzato: %s)sqlite3connectDB_PATHexecute	Exceptioncommitr:   rD   )conns    r   init_dbrR      s     ??7eRHDLL*+LL  	TU 	LL  	 	LL 
 
	 	KKMHH#W-K;  s    B 	B+*B+c                   t        t        j                               }| j                  d|t	        j
                  t        j                        j                         t        j                  |      |rdndf       | j                          |S )z/Inserisce richiesta nel DB. Ritorna request_id.zXINSERT INTO queue (request_id, received_at, payload, tunnel_pending) VALUES (?, ?, ?, ?)r*   r   )rA   uuiduuid4rN   r   nowr   utc	isoformatjsondumpsrP   )rQ   payloadtunnel_pending
request_ids       r   enqueue_requestr^      sf     TZZ\"JLLb	X\\(,,/99;TZZ=P!	%
 	KKMr!   c           	        t        t        j                               }t        j                  t
        j                        j                         }| j                  d||t        j                  |      d||f       | j                          |S )NzrINSERT INTO queue (request_id,received_at,payload,status,error,processed_at,tunnel_pending) VALUES (?,?,?,?,?,?,0)failed)rA   rT   rU   r   rV   r   rW   rX   rN   rY   rZ   rP   )rQ   r[   reasonr]   rV   s        r   record_time_rejectionrb      sf    TZZ\"J
,,x||
$
.
.
0CLL|	C

7+HVC@ 	KKMr!   c           	         |rdnd}| j                  d|||t        j                  t        j                        j                         |f       | j                          y)z5Marca richiesta come processata (completed o failed).	completedr`   zQUPDATE queue SET status=?, order_id=?, error=?, processed_at=? WHERE request_id=?NrN   r   rV   r   rW   rX   rP   )rQ   r]   order_idr;   statuss        r   mark_processedrh      sN     %[(FLL[	5	hll	#	-	-	/	=
 	KKMr!   c                    | j                  d|t        j                  t        j                        j                         |f       | j                          y)z<Chiude definitivamente una richiesta filtrata o idempotente.zbUPDATE queue SET status='skipped', error=?, processed_at=? WHERE request_id=? AND status='pending'Nre   rQ   r]   ra   s      r   mark_skippedrk      @     	LL	2	hll+557D
 	KKMr!   c                    | j                  d|t        j                  t        j                        j                         |f       | j                          y)zNMette in quarantena una richiesta troppo vecchia; non potra essere rieseguita.zbUPDATE queue SET status='expired', error=?, processed_at=? WHERE request_id=? AND status='pending'Nre   rj   s      r   mark_expiredrn      rl   r!   c                    	 t        j                  t        |       j                  dd            }|j                  r|S |j                  t
        j                        S # t        t        f$ r Y y w xY w)NZz+00:00)tzinfo)	r   fromisoformatrA   replacerq   r   rW   	TypeErrorr?   )valueparseds     r   _parse_queue_timerw     s_    ''E
(:(:3(IJvOFNN(,,N,OOz" s   ;A A A0/A0c                   t        j                  t        j                        }g }| j	                  d      j                         }|D ]  \  }}t        |      }|||z
  j                         |kD  s*|dn$t        t        ||z
  j                                     }d| d| }	t        | ||	       |j                  |       t        j                  d||	        |S )zETerminalizza i pending scaduti. Mai rieseguire un vecchio segnale TV.z@SELECT request_id, received_at FROM queue WHERE status='pending'unknownz expired_pending_ttl age_seconds=z limit=z-PENDING EXPIRED/QUARANTINED: request_id=%s %s)r   rV   r   rW   rN   fetchallrw   total_secondsrA   r5   rn   appendr:   r;   )
rQ   max_age_secondsrV   expiredrowsr]   received_atreceivedagera   s
             r   expire_stale_pendingr     s     ,,x||
$CG<<Jhj 	 $( [
K$[1h==?/Q'/)ScHn=[=[=]9^5_C7uGOCTUFz62NN:&IIEzSYZ[ Nr!   c                   | j                  d|f      j                         }|st        j                  d|       y|\  }}}|dk7  rt        j	                  d||       yt        t        j                  |            }|r&t        | ||       t        j                  d||       yt        |      }|7t        j                  t        j                        |z
  j                         |kD  r#t        | |       t        j                  d|       yy	)
z@Difesa in profondita prima di qualsiasi chiamata ordine a Bybit.zASELECT status, received_at, payload FROM queue WHERE request_id=?z6QUEUE STATE MISSING: request_id=%s; processing blockedFpendingz,QUEUE TERMINAL SKIP: request_id=%s status=%sr;   z%s request_id=%s; order blockedz1STALE REQUEST BLOCKED before Bybit: request_id=%sT)rN   fetchoner:   r;   warningr
   rY   loadsrh   rw   r   rV   r   rW   r{   rn   )	rQ   r]   r}   rowrg   r   stored_payloadra   r   s	            r   request_is_fresh_pendingr   &  s     ,,Kj]hj  		JJW*-'FKBJPVWdjj89FtZv6		3VZH -HHLL6APPRUddT:&		EzRr!   c                    | j                  d      j                         }|D cg c]  }|d   t        j                  |d         f! c}S c c}w )z4Ritorna richieste pending (per recovery al startup).zRSELECT request_id, payload FROM queue WHERE status='pending' ORDER BY id LIMIT 100r   r*   )rN   rz   rY   r   rQ   r   rs      r   get_pendingr   A  sK     <<\hj 	 /33QqT4::ad#$333s   $Ac                    t        |        | j                  d      j                         }|D cg c]  }|d   t        j                  |d         f! c}S c c}w )a  FIX 2026-07-19 (Mavis handoff TAILSCALE_WATCHDOG): ritorna solo richieste
    pending NON bloccate da tunnel_pending=1. Il worker processa queste;
    le richieste con tunnel_pending=1 restano in coda finche' il tunnel
    non torna su (segnalato da set_tunnel_state).zgSELECT request_id, payload FROM queue WHERE status='pending' AND tunnel_pending=0 ORDER BY id LIMIT 100r   r*   )r   rN   rz   rY   r   r   s      r   get_pending_unblockedr   J  sS     <<qhj 	 /33QqT4::ad#$333s   $Ac                R    | j                  d      j                         }|r|d   S dS )zAFIX 2026-07-19: conta richieste in attesa che il tunnel torni su.FSELECT COUNT(*) FROM queue WHERE status='pending' AND tunnel_pending=1r   rN   r   )rQ   r   s     r   count_pending_tunnel_blockedr   W  s2     ,,Phj  3q6ar!   c                   t        |        | j                  d      j                         }|D cg c]  \  }}|	 }}}d}|r.dj                  d |D              }| j                  d| d|      }| j	                          ||j
                  nd}|t        |      k7  r t        j                  dt        |      |       |D cg c]  \  }}|t        j                  |      f c}}S c c}}w c c}}w )	zGSblocca solo richieste fresche e le restituisce per la coda in memoria.zgSELECT request_id, payload FROM queue WHERE status='pending' AND tunnel_pending=1 ORDER BY id LIMIT 100Nr%   c              3      K   | ]  }d   yw)?Nr   ).0_s     r   	<genexpr>z-unblock_all_tunnel_pending.<locals>.<genexpr>k  s     99s   zaUPDATE queue SET tunnel_pending=0 WHERE status='pending' AND tunnel_pending=1 AND request_id IN ()r   z2TUNNEL UNBLOCK count drift: selected=%d updated=%d)r   rN   rz   joinrP   rowcountlenr:   r   rY   r   )	rQ   r   r]   r   request_idscurplaceholdersupdatedr[   s	            r   unblock_all_tunnel_pendingr   `  s     <<	L hj 	 488-*a:8K8
Cxx9[99ll77CnAG

 	KKM!ocll1G#d)H#d)U\]IMN2E*gZG,-NN 9 Os   C)!C/c                    dj                  t        | xs d      j                         j                  dd      j                  dd      j	                               S )N r$   r   -)r   rA   lowerrs   split)ru   s    r   _normalized_markerr   x  sF    88C$**,44S#>FFsCPVVXYYr!   c                4     dt         fddD              S )zBRiconosce in modo uniforme tutte le forme Pine note per le uscite.)zmax exitz	exit barszopposite signalz
exit shortz	exit longz
short exitz	long exitztrailing shortztrailing longztrailing exitzclose entryzstrategy closec              3  J   K   | ]  t        fd D                yw)c              3  V   K   | ]   }|t        j                              v  " y wr   )r   get)r   markerfieldr[   s     r   r   z5payload_has_close_intent.<locals>.<genexpr>.<genexpr>  s%     SF(U);<<Ss   &)Nany)r   r   markersr[   s    @r   r   z+payload_has_close_intent.<locals>.<genexpr>  s$       	S7SSs   #)commentalert_messagerf   r   )r[   r   s   `@r   payload_has_close_intentr   |  s&    G
  =  r!   c                :   ddl }t        | j                  dd            dk7  rt        | j                  d            }t        | j                  d            }t        | j                  d      xs d      j	                         }	 t        | j                  d	            }|dk(  xr# |xr |dkD  xr d|v xr |dk(  xs d|v xr |dk(  }|ryydD ]A  }t        | j                  |      xs d      j	                         }	|	r	d|	v sd|	v s:dd| fc S  t        | j                  d      xs d      j	                         dk7  ry	 t        | d	         }
t        | d         }|j                  |
      r|j                  |      r|
dk  ryt        | j                  dd            j                         }|dk(  r|dk  s|dk(  r|dk\  s
|dk(  r|dk7  ry ddddddd"}t        | j                  d            }t        | j                  d#            }|j                  |      }|j                  |      }||y$ddd%}ddd%}|dk(  r"||v r||   }||k(  rd&d'| fS dd'| d(| d)| fS ||v r"|dk(  r||   }||k(  rd*| d+fS d| d,| d)| fS ||v r!||k(  r|||   k(  r
d-| d.| d/fS d0| d.| d1fS ||v r+||v r'||k7  r"||   }||k(  r	d2| d.| fS d| d.| d(| d)| fS dd3| d.| d4| fS # t        t        f$ r d
}Y aw xY w# t        t        t        f$ r Y y!w xY w)5zIClassifica l'ordine TV dalla transizione, senza dedurlo dal testo libero.r   Nschema_versionr$   2strategyr   symbolqty        zsupertrend boswbullflipbuybearflipsell)LEGACYz(validated supertrend_bosw bull/bear flip)INVALIDz6schema_version 2 required; legacy alerts are ambiguous)r   r   rf   z{{z}}r   zmissing or unresolved intent_sourcemarket_position_transition)r   z0intent_source must be market_position_transitionposition_size)r   zinvalid numeric payloadmarket_positionlongshortflat)r   z%position size contradicts target side)r   z"missing or invalid numeric payload)r   r   r   zmarket position flatzmarket position longzmarket position shortprev_market_position)r   z/missing or invalid schema-2 position transition)r   r   ENTRYzflat->z requires side=z, got 	FULL_EXITz->flatz->flat requires side=PARTIAL_EXITz->z opposite-side orderSCALE_INz same-side orderREVERSALzunsupported transition z side=)mathrA   r   r   r7   floatrt   r?   isfiniter   KeyError)r[   sider   r   r   r   r   legacy_supertrendr   ru   amountsizetargetaliasescurrent_rawprevious_rawcurrentprevious
entry_side	exit_sideexpecteds                        r   classify_position_intentr     s%   
7;;',-4%gkk*&=>$W[[%;<W[[*0b1779	E*+C )) @@a@ '9DEM ?7*=tv~ 	 GR3 ?GKK&,"-335 6ug>>>? 7;;'-2.446:VVL	?wu~&W_-.}}V$DMM$,?6Q;7W[[!2B78>>@f'0AdaiU[_eUejnrsjsE  &!(G
 %W[[1B%CDK%gkk2H&IJLkk+&G{{<(H(*K&1J%0I6g3g&040@6'+, 	
yzvNG
 	
 9F!2X&59X5Ez01 	
(#8
&OL
 	
 9H!49X&&!hZr':N#OOOhZr'2BCCC9J!67h;Ng&9=9I
xj7)45 	
(2gYohZvdVTP
 	
 /zG9F4&QQQ{ :& 	C	4 i, ?>?s,   K+ AL AL +L ?L LLc                    	 t        t        | j                  d                  }||z   }||z  }d|cxk  rdk  r|S  dS # t        t        t
        f$ r Y yw xY w)z@Quota della posizione TV precedente chiusa dall'ordine parziale.r   r   r   r*   )absr   r   rt   r?   ZeroDivisionError)r[   r   	remainingbeforefractions        r   partial_exit_fractionr     si    gkk/:;<	S< 8(q(81(c1 z#45 s   -? AAc                v    t        |       }|dv ry|dv ry|dv ry|dv ry|d	v ry
|j                  dd      xs dS )zBNome stabile usato per impedire chiusure incrociate tra strategie.)r'   zvptr v3r'   )zma trailingzma trailing closema_trailing)z	rsi swingzrsi swing breakout	rsi_swing)zrettangolo tv simplezrettangolo simplezrett simplerettangolo_simple)
rettangolozrettangolo v2r   r   r   ry   )r   rs   ru   raws     r   canonical_strategy_namer     s^    
U
#C
""
22
11
JJ"
--;;sC -I-r!   c                n    t        | xs d      j                         j                         }|dv ry|dv ryy)Nr$   r   r   r   r   r   r   ry   )rA   r7   r   r   s     r   canonical_position_sider     s<    
ekr

 
 
"
(
(
*C
o
r!   c                    | j                  d|t        |      t        |      ||t        j                  t
        j                        j                         |f       | j                          y )NaS  INSERT INTO position_ownership (symbol,strategy,side,entry_request_id,entry_order_id,opened_at,source) VALUES (?,?,?,?,?,?,?) ON CONFLICT(symbol) DO UPDATE SET strategy=excluded.strategy,side=excluded.side,entry_request_id=excluded.entry_request_id,entry_order_id=excluded.entry_order_id,opened_at=excluded.opened_at,source=excluded.source)	rN   r   r   r   rV   r   rW   rX   rP   )rQ   r   r   r   r]   rf   sources          r   set_position_ownerr     sZ     	LL	> 
(24KD4Q	Xx||HLL9CCEv	O	 	KKMr!   c                    | j                  d|f      j                         }|sy |d   |d   |d   |d   |d   |d   dS )	NzlSELECT strategy,side,entry_request_id,entry_order_id,opened_at,source FROM position_ownership WHERE symbol=?r   r*               )r   r   entry_request_identry_order_id	opened_atr   r   )rQ   r   r   s      r   get_position_ownerr    s^    
,,	139) hj  FCFAa&s1vQ r!   c                J    | j                  d|f       | j                          y )Nz-DELETE FROM position_ownership WHERE symbol=?rN   rP   )rQ   r   s     r   clear_position_ownerr    s    LL@6)LKKMr!   c                    t        | |      }t        |      }t        |      }|dd| dfS |d   |k7  rdd|d    d| |fS |d   |k7  rdd|d    d	| |fS d
d|fS )zFFail-closed: una strategia chiude solo la posizione che le appartiene.NFz position_owner_missing incoming=r   zposition_owner_mismatch owner=z
 incoming=r   zposition_side_mismatch owner=z bybit=Tposition_owner_match)r  r   r   )rQ   r   r   position_sideownerincomingactual_sides          r   position_owner_allows_closer    s     tV,E&x0H)-8K}8
CTIIZH$,U:->,?z(T 	 V}#+E&M?'+O 	 '..r!   c                T    | j                  d|rdnd|f       | j                          y)zFIX 2026-07-19: marca una richiesta come bloccata (tunnel_pending=1)
    o sbloccata (tunnel_pending=0). Usato in do_POST quando tunnel e' giu'.z4UPDATE queue SET tunnel_pending=? WHERE request_id=?r*   r   Nr  )rQ   r]   blockeds      r   set_tunnel_block_on_requestr  -  s*     	LL>1j) 	KKMr!   c	                    t        j                  t        j                        j	                         }	d|	 d| d| d| d| d| dt        |d       d| }
t        j                  d	|
       | j                  d
|||||||||	f	       | j                          	 t        t        dd      5 }|j                  |
dz          ddd       y# 1 sw Y   yxY w# t        $ r }t        j                  d|       Y d}~yd}~ww xY w)zBRegistra prima nel DB; il file testuale e' un audit non bloccante.[z
] orderId=r   z qty=z price=z
 notional=r   z
 strategy=z	ORDER: %szINSERT INTO orders (request_id, order_id, symbol, side, qty, price, notional, strategy, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)ar   r   
Nz1ORDERS_LOG append failed (DB order preserved): %s)r   rV   r   rW   rX   roundr:   rD   rN   rP   open
ORDERS_LOGwriteOSErrorr;   )rQ   r]   rf   r   r   r   pricenotionalr   tslinefexcs                r   log_order_unifiedr  8  s	    
hll	#	-	-	/Brd*XJaxqeC5wjY^_gijYkXllvw  wA  BDHH[$ 	LL 	Q	XvtS%8RP 	KKML*cG4 	!GGD4K 	! 	! 	! L		EsKKLs6   C *C?C CC C 	C=C88C=c                D    | j                  d|f      j                         S )Nz<SELECT status, order_id, error FROM queue WHERE request_id=?r   )rQ   r]   s     r   get_request_statusr!  L  s$    <<F	 hjr!   c                ^   dD ci c]'  }|| j                  d|f      j                         d   ) }}| j                  d      j                         D cg c]!  }|d   |d   |d   |d   |d   |d	   |d
   d# }}| j                  d      j                         d   |d<   ||fS c c}w c c}w )N)r   rd   r`   skippedr~   z)SELECT COUNT(*) FROM queue WHERE status=?r   ztSELECT symbol,strategy,side,entry_request_id,entry_order_id,opened_at,source FROM position_ownership ORDER BY symbolr*   r   r   r   r      )r   r   r   r   r   r  r   r   tunnel_blocked)rN   r   rz   )rQ   rg   countsr   ownerss        r   get_queue_status_snapshotr(  T  s     O	  	7&

(*Q 	F  <<G
 (*
 	 !f#a&#a& #A#a&Q3q6	

F 
  $||P hj F 6>)
s   ,B%&B*c                 ^    t         "ddlm}  ddlm}  |t
        dz          |        a t         S )Nr   )BybitDemoClient)load_dotenvzAPI_KEY_BYBIT.env)_bybitbybit_demo_clientr*  dotenvr+  LIVE_DEPLOY)r*  r+  s     r   	get_bybitr0  q  s(    ~5&K"556 "Mr!   c                   t         j                  d       	 	 |j                         }|y|\  }}	 t        | ||       |j                          	 9# t        $ rI}t         j                  d||       	 t        | |t        |             n# t        $ r Y nw xY wY d}~_d}~ww xY w# |j                          w xY w# t        $ r5}t         j                  d|       t        j                  d       Y d}~d}~ww xY w)zPWorker che processa la coda in background. UN solo worker per evitare conflitti.zWORKER started (background)NzWorker error on %s: %sr   zWorker loop error: %sr*   )r:   rD   r   process_orderrO   	exceptionrh   rA   	task_donetimesleep)rQ   in_queueitemr]   r[   es         r   worker_loopr:  ~  s    HH*+
	<<>D|"&J	%dJ8 ""$   6
AF"43q6B  	 ""$ 	MM115JJqMM	st   B: B: A B: 	B"B1B	B		BBBBB% B""B% %B77B: :	C8+C33C8c                8  qr t        | |      syt        j                  d||j                  d      |j                  d      |j                  d             t	        |j                  dd            j                         }|j                  dd      j                  dd      j                         rrj                  d	      s	d	rvrrd	z   rt	        |j                  dd            j                         j                         }|d
vrt        d|      	 t        |j                  dd            }t        |j                  dd      xs d      }|dk  s|dkD  rd}d } ||j                  d            } ||j                  d            }	 ||j                  d            }
|j                  d      }|Ft	        |      j                         dk(  s*t	        |      j                         j                         dk(  rdt	        |j                  dd            j                         }t        j                  |t              }t        j!                  dr|||r|dd nd       nt	        |      j                         }t#        |      }|j                         dk(  rt        j                  dr|       d}t	        |j                  dd            }t	        |j                  d d            }t%               }t'        ||      \  }}t        j                  d!|||       |d"v r>d#| d$| }t        j)                  d%|||j                  d&      |       t+        | ||       y|d'k(  }|d(k(  xs |d)k(  xr |dk  xs t-        |      }d*}t        | |      sy|d+k(  r|j/                         }t1        rfd,|D        d      }|t	        |j                  d-d            j                         j                         }|d.k(  rd/nd0}	 t3        t        |j                  d1d      xs d            }|dk  s||k7  r:d2}t        j)                  d3||r||j                  d1      |       t+        | ||       yt        j!                  d4r||       |}d5}nt	        |j                  dd            j                         }||k(  r)d6}t        j!                  d7||r|       t+        | ||       yt5        | r|t	        |j                  dd                  \  }}} |s+d8| }t        j)                  d9|||        t+        | ||       yt        |j                  d:d      xs d      }t        j                  d;r|||       |r@|dkD  r;t        j                  d<||j                  d=d      |j                  d&d      |||       |s|r|dkD  rt        j                  d>r|||       t        j                  d?r||       	 |j/                         }t1        rfdA|D        d      }|Ft        j                  dBr       t;        | r       t=        | |dCr|ddd| dD	       t+        | |dC       yt        |d:         }"t	        |j                  ddE            }t5        | r||      \  }}} |s,t        j)                  dF|r||||        t+        | |dG|        y|dEk(  rdHndE}#||#j                         k7  r-dI| dJ| }t        j)                  dK||       t+        | ||       y|rWt?        ||      }$d|$cxk  rdk  s:n dL}t        j)                  dM||||j                  d1             t+        | ||       y|"|$z  }%n|"}%|r|jA                  r|%      }%|%dk  rt        dN| dO|"       	 |jC                  r      }&t        j                  dQ|r||"|#|%       t        | |      sy	 |jE                  dRdSdTr|#dUt	        |%      dVdWdXdWY      }'|'xs i j                  d[      xs% |'xs i j                  d\i       j                  d[      }(|(st9        d]|'       |%|&z  })t        j                  d^|||(|#|%|"       |rd_nd`}*t=        | ||(r|#j                         |%|&|)| da|* 	       |r|%|"k\  rt;        | r       tG        | ||(b       y|dk(  r)dc}t        j!                  d7||r|       t+        | ||       yrddk(  r	 |j/                         }+t1        rfde|+D        d      },|,r)t	        |,j                  dd            j                         nd}-|,=|-|k7  r8t        j                  dfr||-t        |,j                  d:d      xs d             n{d*}.	 t        |jC                  r      xs d      }.tI        jJ                  tL        jN                        jQ                         r||||t	        |j                  d=d            t	        |j                  d&d            ||dg	|.|,r1|,j                  d      t        |,j                  d:d      xs d      dhnddidj| dkdl}/tR        dmz  }0|0jT                  jW                  dWdWn       tY        |0dodpq      5 }1|1j[                  t]        j^                  |/drs      dtz          ddd       t        j!                  dur||||,       t=        | |dvr|||xs dd| dw	       t+        | |dv       dxdydzd{fS 	 	 |j/                         }+t1        rfd}|+D        d      },|,bt	        |,j                  dd            j                         d.k(  r6t        j                  d~rt        |,j                  d:d      xs d             nwd*}.	 t        |jC                  r      xs d      }.tI        jJ                  tL        jN                        jQ                         r||||t	        |j                  d=d            t	        |j                  d&d            ||dg	|.|,r1|,j                  d      t        |,j                  d:d      xs d      dhnddiddl}/tR        dz  }0|0jT                  jW                  dWdWn       tY        |0dodpq      5 }1|1j[                  t]        j^                  |/drs      dtz          ddd       t        j!                  dr||||,       t=        | |dr|||xs dd| d	       t+        | |d       dxdydd{fS 	 	 |j/                         }t1        rfd|D        d      }2|2|d+k7  r|2j                  dd      j                         }-t        |2j                  d:d      xs d      }3t        |2j                  dd      xs |2j                  dd      xs d      }4t        j!                  dr|||-|3|4       t=        | |dr|||xs dd| d	       t+        | |d|-        dxdydr d|- d|3 dd{fS |)	 |jC                  r      }t        j                  dr|       d}5d}6	 |jC                  r      }6dr}7|6rn|6dkD  rit3        ||5z
        dk  r*t3        |6|5z
        dkD  rdW}7t        j                  d|6       n.|dkD  r)||6dz  kD  s||6dz  k  rdW}7t        j!                  d||6       |7r|6r|6}||z  }8|8td        k  rFtd        tf        z  |z  }9|jA                  r|9      }9t        j!                  d||9|8td               |9}||z  }8	 |ji                  r|       t        j                  dr|||||	|
|	       d}:d};||z  }<t3        |<|:z
        |:z  |;kD  r8|:|z  }9|jA                  r|9      }9t        j!                  dr||9|<|:       |9}||z  }8|j                  dd      j                         }=|=dv rrrj                         tj        vr\|}>tm        |>r||=      \  }?}@t        j                  dr||@       |?s/t        j!                  dr|@       t+        | |d|@        dxdy|@d{fS |=dv r$rj                         tn        vr	 ddl8}A|Ajr                  ju                  dt	        tw        tx              j{                         jT                  jT                               ddl>m?}B |=j                  d      rdnd}C B|r|C      }D|Dj                  d      Dd   dnd}Et        j                  dr|CDd   |Dd   |E|Dd          |Dd   rJt        j!                  dr|Dd   |Dd   E|Dd          d|Dd    d|E d|Dd    d}Ft+        | ||F       dxdy|Fd{fS 	 	 d}Gd}H	 |j                  d      }I|It        I      }H|j                         dv rdnd}J	 HHdkD  rJdk(  reHdGz   z  }K||KkD  r>t        j)                  dr|KH|HG       d|dd|Kdd|Hdd}Ft+        | ||F       dxdy|Fd{fS t        j                  dr|KH       n|HdGz
  z  }L||Lk  r>t        j)                  dr|LH|HG       d|dd|Ldd|Hdd}Ft+        | ||F       dxdy|Fd{fS t        j                  dƉr|LH       nt        j                  dǉr|=       |}M|jA                  r|      }|dk  rt        dˉr dM d|       t3        |Mz
        dkD  rt        j!                  dωrM|       ||z  }8t        | |      sy|d+k(  rN|}|jA                  r||z         }||k  rt        d| d| d|       t        j                  dӉr|||       ||z  }8t        | |      sy|j                  r||ԫ      }'|'xs i j                  d[      xs% |'xs i j                  d\i       j                  d[      }(|(st9        d|'       t        | r||||(       |}Nd}O|}P|j                         dv rd.nd֊qt        d׫      D ]  }Q	 |j/                  r      }Rt1        qrfd؄|RD        d      }S|Srwt        Sj                  dd      xs Sj                  dd      xs |      }Nt        Sj                  dd      xs d      xs d}Ot        Sj                  d:d      xs |      }P n	 t        j                  d۫        O	 t        |j                  r            }Ot        j                  d݉r|(NOP       d}T|j                         dv r|	|
	 t	        t        jT                        }U|Utp        jr                  vr tp        jr                  ju                  dU       ddlHmI}V |Vj                  r      }W|W Wd   }X|Wd   }Yd|Wd    d|Wd    d|Wd    d}Znd}Xd}Yd}Zt        j!                  dr       |j                         dv rdnd}[N}\|	\d[Xz  z   z  }	|
\d[Yz  z   z  }
t        j                  dr|\|	|
ZXY	       |	WNU|j                         dv rdnd}J|J|	Nz
  z  |Nz  }]|]Tdz
  k  r,|	}^NdJTz  z   z  }	t        j)                  dr]|]dz  |^|	|N|       d}_|	|
-	 |j                  r|	|
       t        j                  dr|	|
       d}g	 t        |'t              r|'ni }ht        |hj                  dd      xs d      }it        hj                  dd      xs d      }jt        hj                  dd      xs d      }kidk  rkdkD  r
jdkD  rkjz  }iidkD  rX|d+k7  rSt3        i|:z
        |:z  }l|lgkD  r"t        j)                  drigdz  ldz  jk       nt        j                  drildz         t        j                  d||(       Nxs |}m||mz  }n|d+k(  r| dn|}ot=        | ||(r||mn|o	       tG        | ||(_       	 dd lNmO}p  |p|(r||||t        |8d׫      d||xs d|	|
||d       y# t        t        f$ r t        d|j                  d            w xY w# t        t        f$ r d*}Y w xY w# t6        $ r}!t9        d@r d$|!       d}!~!ww xY w# t6        $ r}!t9        dPr d$|!       d}!~!ww xY w# t6        $ r}!t9        dZ|!       d}!~!ww xY w# t6        $ r Y w xY w# 1 sw Y   xY w# t6        $ r#}!t        j)                  d|r||!       Y d}!~!d}!~!ww xY w# t6        $ r Y w xY w# 1 sw Y   xY w# t6        $ r#}!t        j)                  dr||!       Y d}!~!d}!~!ww xY w# t6        $ rH}!dta        |!      jb                   }t        j)                  d7||r|       t+        | ||       Y d}!~!yd}!~!ww xY w# t6        $ r}!t9        dr d$|!       d}!~!ww xY w# t6        $ r!}!t        j!                  d|!       Y d}!~!ed}!~!ww xY w# t6        $ r!}!t        j!                  d|!       Y d}!~!
d}!~!ww xY w# t6        $ r#}!t        j)                  dr||!       Y d}!~!d}!~!ww xY w# t        t        f$ r d}HY w xY w# t6        $ r<}!t        j)                  dȉr||!       d|! dʝ}Ft+        | ||F       dxdy|Fd{fcY d}!~!S d}!~!ww xY w# t6        $ r&}!t        j!                  dQdz   r|!       Y d}!~!d}!~!ww xY w# t6        $ r"}!t        j!                  d܉r|!       Y d}!~!d}!~!ww xY w# t6        $ r#}!t        j)                  dr||!       Y d}!~!d}!~!ww xY w# t6        $ r7}`t        j!                  dr`       	 Oxs t        |j                  r            }a|j                         dv rdnd}[|	}b|
}cNxs |xs a}db1[baz
  z  dk\  r&t        t3        bdz
        |dz  d      }ead[|ez  z
  z  }bc1[caz
  z  dk  r&t        t3        cdz
        |dz  d      }ead[|ez  z   z  }c|j                  rbc       |b|c}
}	t        j!                  dra|	|
       n:# t6        $ r.}fd`dfdd }_t        j)                  d||(r|_       Y d}f~fnd}f~fww xY wY d}`~`d}`~`ww xY w# t6        $ r!}!t        j!                  d|!       Y d}!~!d}!~!ww xY w# t6        $ r!}!t        j!                  d|!       Y d}!~!yd}!~!ww xY w(  u<   Processa un singolo ordine. Può richiedere diversi secondi.NzProcessing %s: %s %s qty=%sr   r   r   r$   z.Pz.PZUSDT)r   r   zInvalid side: r   zInvalid qty: leverager   r*   r0   c                L    	 | t        |       S d S # t        t        f$ r Y y w xY wr   )r   rt   r?   )vs    r   
safe_floatz!process_order.<locals>.safe_float  s1    	 }586$6:& 		s     ##r  sl_pricetp_pricer   ry   secretuQ   STRATEGY missing/unknown in payload for %s %s → using default=%s (secret=***%s)nonersi_swing_breakoutzCSTRATEGY mapping: RSI_SWING_BREAKOUT -> rettangolo_simple for %s %sr   tfr   z4INTENT CLASSIFIED: request_id=%s intent=%s reason=%s)r   r   zPROTOCOL_REJECTED intent=z: z/%s request_id=%s payload_order_id=%r comment=%rrf   r   r   r   r   r   c              3     K   | ]>  }|j                  d       k(  st        |j                  dd      xs d      dkD  s;| @ ywr   r   r   Nr   r   r   pr   s     r   r   z process_order.<locals>.<genexpr>  C     k!AEE(Ov,E%PQPUPUV\^_P`PedeJfijJjAk   A"A Ar   r   r   r   r   z@PROTOCOL_REJECTED REVERSAL_SOURCE_POSITION_ABSENT_INVALID_TARGETzM%s request_id=%s symbol=%s target_side=%s position_size=%r market_position=%rzSREVERSAL SOURCE ABSENT: %s is flat on Bybit; execute target as ENTRY side=%s qty=%sr   REVERSAL_ALREADY_APPLIEDz"%s request_id=%s symbol=%s side=%sz%PROTOCOL_REJECTED REVERSAL_OWNERSHIP z%s request_id=%s owner=%sr   z8REVERSAL VERIFIED: %s old_side=%s old_qty=%s new_side=%szqCLOSE INTENT detected via normalized marker: comment=%r alert_message=%r order_id=%r (qty=%s side=%s strategy=%s)r   uW   CLOSE INTENT (comment-based): %s side=%s qty=%s comment=%r → recupero posizione Bybitu<   CLOSE INTENT: %s side=%s qty=%s → recupero posizione Bybitz)CLOSE INTENT: cannot fetch positions for c              3     K   | ]>  }|j                  d       k(  st        |j                  dd      xs d      dkD  s;| @ ywrI  rJ  rK  s     r   r   z process_order.<locals>.<genexpr>  rM  rN  uD   CLOSE INTENT: no open position for %s → skip idempotent (HTTP 200)no_position_close_no_posBuyz]CLOSE BLOCKED OWNERSHIP: request_id=%s symbol=%s strategy=%s bybit_side=%s reason=%s owner=%szCLOSE_BLOCKED_OWNERSHIP SellzPROTOCOL_REJECTED exit side=z does not reduce Bybit side=z%s request_id=%sz4PROTOCOL_REJECTED PARTIAL_EXIT_INVALID_POSITION_SIZEz(%s request_id=%s qty=%s position_size=%rz*Exit qty invalid after normalization: raw=z
 position=z%CLOSE INTENT: cannot fetch price for uQ   %s: %s current pos side=%s size=%s → placing %s qty=%s reduceOnly=True @ marketPOSTz/v5/order/createlinearMarketGTCT)categoryr   r   	orderTyper   timeInForce
reduceOnly)signedzCLOSE INTENT: order failed: orderIdresultz-CLOSE INTENT: order returned but no orderId: zE%s OK %s: orderId=%s side=%s qty=%s reduceOnly=True (position was %s)partial_exitcloser   )rf   zHSTRATEGY_ENTRY_BLOCKED rettangolo_simple disabled by operator 2026-09-09
RENDERUSDTc              3     K   | ]>  }|j                  d       k(  st        |j                  dd      xs d      dkD  s;| @ ywrI  rJ  rK  s     r   r   z process_order.<locals>.<genexpr>p  D     za155?f;TY^_`_d_dekmn_o_tstYuxyYyzrN  uh   RENDER TOTAL-BLOCK: %s side=%s ma c'e' posizione %s esistente size=%s → PASSA (chiusura pos esistente))	r   r   r   r  r   r   rf   r   rG  )r   r   )markopen_positionz0RENDER DEFINITIVELY blocked (2026-08-10, no new z% positions, only close intent passes))r  alertbybit_statera   zrender_blocked.jsonl)parentsr   r  r   r   F)ensure_asciir  u]   RENDER BLOCKED + LOGGED: %s side=%s qty=%s price=%s pos=%s → vedi logs/render_blocked.jsonlrender_blocked_render_blocked   r#  z;RENDER definitively blocked, logged to render_blocked.jsonl)rg   ra   zJRENDER TOTAL-BLOCK check exception for %s %s: %s (FAIL-OPEN, ordine passa)c              3     K   | ]>  }|j                  d       k(  st        |j                  dd      xs d      dkD  s;| @ ywrI  rJ  rK  s     r   r   z process_order.<locals>.<genexpr>  rd  rN  uc   RENDER SHORT-BLOCK: %s side=Sell ma c'e' posizione LONG esistente size=%s → PASSA (chiusura long)z:RENDER SHORT blocked (Long-only test 2026-08-09, log only)zrender_shorts_skipped.jsonluj   RENDER SHORT BLOCKED + LOGGED: %s side=%s qty=%s price=%s pos=%s → vedi logs/render_shorts_skipped.jsonlrender_short_blocked_render_short_blockedzLRENDER SHORT blocked (Long-only test), logged to render_shorts_skipped.jsonlzJRENDER SHORT-BLOCK check exception for %s %s: %s (FAIL-OPEN, ordine passa)c              3     K   | ]>  }|j                  d       k(  st        |j                  dd      xs d      dkD  s;| @ ywrI  rJ  rK  s     r   r   z process_order.<locals>.<genexpr>  sC     pqxF1JuUVUZUZ[acdUeUjijOknoOoprN  avgPrice
entryPriceus   ANTI-DOPPIA SKIP: %s side=%s qty=%s ma c'è GIA' posizione %s size=%s entry=%s (no pyramiding, no chiusura manuale)anti_dup_skip_anti_dup_skipanti_dup_skip_existing_z&ANTI-DOPPIA: posizione gia' aperta su z (side=z size=z2). Pine ha mandato alert a raffica, no pyramiding.z1PROTOCOL_REJECTED POSITION_PREFLIGHT_UNAVAILABLE z!Price fetched from Bybit: %s = %szCannot fetch price for g      ?z4Bybit market price fetch fallito (non bloccante): %sg&.>zQPine price=1.0 placeholder rilevato, uso Bybit market price=%.6f per sizing/SL/TPr   g      ?zUPine price=%.6f sospetto (Bybit=%.6f, ratio fuori 0.5-2x), uso Bybit per sizing/SL/TPu1   Auto-bump qty: %s → %s (notional %.2f$ < %.2f$)u8   set_leverage failed (potrebbe essere già impostata): %suS   ORDER → symbol=%s side=%s qty=%.4f price=%.4f leverage=%d SL=%s TP=%s strategy=%sg     p@g?zRSIZING ENFORCEMENT: %s qty=%.4f -> %.4f (nozionale %.2f -> %.2f USDT, target 1500)r'   vptr_v3zP007 regime check %s %s: %suH   P007 SKIP-REGIME ATTIVATO per %s %s: %s — ordine NON inoltrato a BybitzP007 SKIP-REGIME: )r'   rx  r   )classify_regimevptrr/   30adxz.1fr   z;P007b CHOP check %s %s tf=%s: regime=%s chop=%s adx=%s (%s)regimeis_chopra   ug   P007b SKIP-CHOP ATTIVATO per %s %s: regime=%s chop=%s adx=%s reason=%s — ordine NON inoltrato a BybitzP007b CHOP: regime=z adx=z (r   zBP007b CHOP check exception for %s %s: %s (FAIL-OPEN, ordine passa)g{Gz?sl_refr   zZONA-MID SKIP: %s LONG entry=%.6f > bottom_pattern*1.015 = %.6f (entry OLTRE 1.5%% dal bottom %.6f, NON si entra in zona mid). sl_ref=%.6f ZONA_ENTRY_PCT=%.3fzZONA-MID LONG: entry .6fz > bottom_pattern*1.015 (u   ) — OLTRE 1.5% dal bottom z, NO entry in zona midzJZONA-MID LONG OK: %s entry=%.6f <= %.6f (1.5%% UP dal bottom_pattern %.6f)zZONA-MID SKIP: %s SHORT entry=%.6f < top_pattern*0.985 = %.6f (entry OLTRE 1.5%% dal top %.6f, NON si entra in zona mid). sl_ref=%.6f ZONA_ENTRY_PCT=%.3fzZONA-MID SHORT: entry z < top_pattern*0.985 (u   ) — OLTRE 1.5% dal top zJZONA-MID SHORT OK: %s entry=%.6f >= %.6f (1.5%% DOWN dal top_pattern %.6f)zZONA-MID: sl_ref assente per %s (strategy=%s). ZONA-MID si applica SOLO al Rettangolo. VPTR3 (alert TV) non rientra. Lascio passare al filtro successivo.uv   ZONA-MID check FAILED for %s %s: %s — ordine SKIPPATO (fail-closed Mattia: meglio perdere occasione che aprire male)zZONA-MID check failed: z' (fail-closed, no entry in zona dubbia)zNormalized qty invalid for z: raw=z normalized=g-q=z,QTY-STEP NORMALIZED: %s raw=%s normalized=%sz(REVERSAL combined qty invalid: existing=z target=z
 combined=zGREVERSAL COMBINED ORDER: %s close_qty=%s target_new_qty=%s order_qty=%s)r   r   r   zOrder returned but no orderId: r   r   c              3    K   | ]  }t        |j                  d d            j                         k(  rRt        |j                  dd            j                         k(  r&t	        |j                  dd      xs d      dkD  r|  yw)r   r$   r   r   r   N)rA   r   upperr   r   )r   rL  expected_position_sider   s     r   r   z process_order.<locals>.<genexpr>  sx      7qh+,224>vr*+1137MM155+0q1A5  7s   BB		markPricez6POST-FILL position lookup attempt %d failed for %s: %sg      ?z+POST-FILL mark price unavailable for %s: %sz:POST-FILL REFERENCE %s: orderId=%s entry=%s mark=%s qty=%sgQ)SETUPS_BY_SYMBOLsl_clamp_maxtp2_pctzCharter P006 namez (clamp_min=sl_clamp_minz, clamp_max=g{Gzz3fallback -2%SL/+5%TP (symbol non in SETUPS Charter)uO   AUTO-FILL SL/TP: symbol %s NON in SETUPS Charter → fallback -2%% SL / +5%% TPz[AUTO-FILL SL/TP per %s %s @ entry=%.6f: SL=%.6f TP=%.6f source=%s (sl_pct=%.4f tp_pct=%.4f)u^   AUTO-FILL SL/TP FAILED for %s %s: %s — proceeding senza SL/TP (sltp_engine coprira' in 5min)gư>z{CHARTER P006 OVERRIDE: %s sl_loss_pct=%.4f (loss %.2f%%) > -3%% Charter hard cap, clampato SL da %s a %s (entry=%s side=%s))rA  rB  zTRADING STOP OK %s: SL=%s TP=%sz0set_trading_stop first attempt failed for %s: %sg~jth?z.TRADING STOP RECOVERED %s: mark=%s SL=%s TP=%szORDER_OPEN_UNPROTECTED first=z retry=i  z=ORDER_OPEN_UNPROTECTED request_id=%s orderId=%s symbol=%s: %sg?cumExecValue
cumExecQtyu   POST-ORDER SIZING MISMATCH: %s nozionale_effettiva=%.2f USDT (target 1500±%.0f%%), drift=%.1f%%, qty=%s, avgPrice=%s. POSSIBILE Pine price placeholder non rilevato o slippage estremo. CHARTER 500x3=1500 USDT VIOLATO.zTPOST-ORDER SIZING OK %s: nozionale_effettiva=%.2f USDT (drift=%.2f%%, in tolleranza)z)POST-ORDER check fallito (non blocca): %szORDER OK %s: orderId=%s	_reversal)rf   r;   )send_trade_email)r^  r   r   r   r  rr  notional_usdz
TV webhook)r   ra   stoptpr=  rG  )ordersignalz*Email notification failed (non blocca): %s)Qr   r:   rD   r   rA   r7   rs   r  endswithr   r?   r   rt   r5   SECRET_STRATEGY_MAPDEFAULT_STRATEGYr   r   r0  r   r;   rk   r   fetch_positionsnextr   r  rO   RuntimeErrorr  r  r   	round_qtyget_last_price_requestrh   r   rV   r   rW   rX   LOG_DIRparentmkdirr  r  rY   rZ   type__name__MIN_NOTIONAL_USDNOTIONAL_SAFETY_MARGINset_leverageEXCLUDED_FROM_REGIME_CHECKcheck_regime_ema50EXCLUDED_FROM_CHOP_CHECKr<   pathinsertr   __file__resolvecharter_core.market_regimery  
startswithcreate_market_orderr   ranger5  r6  get_mark_pricer/  charter_corer  set_trading_stopmax
isinstancedictemail_notifierr  r  )srQ   r]   r[   
symbol_rawr   r   r=  r@  r  rA  rB  strategy_rawsecr   strategy_ownerrG  r   bybitposition_intentintent_reasonra   is_partial_exitis_close_intentreversal_existing_size	positionspostarget_market_positionexpected_market_positiontarget_position_qtypos_sideowner_okowner_reasonr	  r9  pos_size
close_sider   	close_qtycurrent_pricer  rf   notional_closesuffixpositions_rbexisting_rbexisting_sidemark_rblog_entry_rbrb_log_pathr  existingexisting_sizeexisting_entryPINE_PLACEHOLDER_PRICEbybit_market_pricepine_price_suspiciousr  new_qtyTARGET_NOTIONAL	TOLERANCEcurrent_notionalstrategy_namebybit_for_regimeregime_passregime_reason_sysry  tf_chopregime_infoadx_strskip_reasonZONA_ENTRY_PCT_sl_ref_sl_ref_raw
_direction	_zona_max	_zona_minraw_qtyactual_entry_priceactual_mark_priceactual_position_qtyattemptpositions_afterposition_afterCHARTER_P006_SL_CAP_WS_ROOTr  setupsl_pcttp_pct	sl_source	directionentry_price_sl_loss_pct_old_slprotection_errorfirst_errormark_referenceretry_slretry_tp	referencedistanceretry_errorPOST_ORDER_TOLERANCE
order_respcum_exec_valuecum_exec_qtyavg_price_execdriftlogged_pricelogged_notionalexecution_strategyr  r  r   ss                                                                                                                    @@r   r2  r2    sl    #D*5HH*X.F0CW[[QVEWY W[[2./557Jb)11%<BBDF??6"vV';&w{{62&'--/557D?">$233AGKKq)* 7;;z1-23H!|x#~ w{{7+,E'++j12H'++j12H ;;z*Ls<0668B>#lBSBYBYB[BaBaBcgpBp'++h+,224&**30@AgD(CH	I |$**,,X6N ~~//VX^`de&	W[[y)	*B'++i,-GKE &>gt%L"O]HHCZQ`bop11,_,=RO		CVZ++j)7	4T:v.%7O;& 	]x'[SAX-Z9QRY9Z  !#D*5*$))+	kykmqr;%(5F)K%L%R%R%T%Z%Z%\"15vG$*&)%OQ0O0TST*U&V# #a'+AE]+][		i *fdGKK<XZprT:v6KKm&9;%C%O37762./557H43@&*V\^bcT:v6,Gfnc#''&"2E.F-)HlE @O		5vz5QT:v6%*37761+=+B%C"HHOQWYacy{  A37 018'++oWY:ZZ,c4	C /7HHnT31OQWY]_bc	Z--/I kykmqr;HH[]cd v.dJvtQPQSTYaXbboVpqz=9V%swwvu-.(C&.()
%, II3FNHlE
 z-El^+TU'50Ve
:##%%3D69UV^U_`FII(&*=z62,Wc:Hx$1$O		DfjZ]_f_j_jkz_{|T:v6 8+I I	:I>I#jYaXbcdd	V!008M 	d &(Hj)	U'j9	CNN6+=$
%c)n$D@ 	 # E KR$$Y/aEKR3D3DXr3R3V3VW`3a!NugVWW"]2X *h
Ix	Y#2$
Hfj>N>N>PR[]jlz  @H  I  IJ  KQ  JR  }S  	T)x"7 v.tZ(;
 ,,[8&*fVZ[T:v. (	u 002Lz<z  }A  BKITS!<=CCEZ^M&=D+@  D}eKOOFTU<V<[Z[6\^ #E$8$8$@$EAFG #,,x||4>>@"($sU#*S_^`Aa=b$'J(C$D$,B	 !( @K;??63JTYZeZiZijprsZtZyxyTz*{  QU$ !QQUPVV{|  &(>>""(((E+sW= QGGDJJ|%H4OPQ{"D#ukC!$
4DfdTWY^Ycbcefksjt  uD  iE  FT:/?@y>y{{{?^F'	u 002Lz<z  }A  BK&3{vr/J+K+Q+Q+SW\+\~{vq'A'FQ!GI #E$8$8$@$EAFG #,,x||4>>@"($sU#*S_^`Aa=b$'J(C$D$,B	 !( @K;??63JTYZeZiZijprsZtZyxyTz*{  QU$ [  &(EE""(((E+sW= QGGDJJ|%H4OPQ  I"D#ukC!$
4JFTXZ]_d_ihiklqypz  {P  oQ  RT:/EFy  =K  L  L  L?IV))+	pIprvwOz$A$LL4::<M!(,,vq"9">Q?M"8<<
A#>#d(,,|]^B_#dcdeNKK  Nc=-YdJsTYT^]^`afneoo}c~z-D]O+TU9:`ag`hhop}o~  E  FS  ET  TF  9G  H  H  H }	H((0EHH8&%H !O"11&9 "014u--.5#>PSi>i:jmq:q$(!HHhj|}QYE$6$::eFX[^F^>^$(!KKo13!3" U{H""#&<<E//&'2G(,<	>;S68,
 HHbT3x8XO OIU{
o-.@9L!E)//&'2hC*:O	M; KK
I6<<>M,,Ga1a %78H&RVXe%f"].mLKKbdjlpr  Az-?+OP9FFF ::v||~Um?m	mIIQDN$:$:$<$C$C$J$J KLB,77?eTG)%AK5@__U5K5WU+C0]`GHHRT7K,A;yCYk(35 9%  F"D+h*?YAWY`bmnvbwy 3K4I3J%PWyXZ[fgo[pZqqrsT:{;yKHHH & 	 NGkk(+"K(G jjlo52J)A7Q;Q#q>'9:	9$II @ %eY.Z %:%D]^ghk]l  mI  JQ  RU  IV  Vl  #mK z;?9 LLLe	7< $q>'9:	9$II @ %eY.Z %;5+E[\efi[j  kD  EL  MP  DQ  Qg  #hK z;?9 LLLe	7< HH  q], G
//&#
&C
ax6vhfWI\Z]Y^_``
3=E!BFGUXYU{H#D*5*$!oof&<?R&RS((:;Q:RRZ[nZooyz}y~  	Z/1Dc	K;#D*5%%V$C%HE  +]/@/@2/N/R/RS\/]H<UGDEEtV^T:xP &*jjlo&EU68 	j#33F;O!7O 7 N %*"&&z15 %)),:&"
 %*.*<*<[!*L*QPQ$R$ZVZ!&+N,>,>vq,I,PS&Q#  	

4+,  	R %e&:&:6&B C HHIX13DFY[B  ~~//X5EIY%	';--.Hsxx'8,5$((0E  ~.y),U6]O <++0+@*AeTbNcMddeg	
 Q	mouv "ZZ\_<"I,K&!i&.@*@A&!i&.@*@AHHrT;(IvW]_  2 >**,/9Qr
 "X0B%BCFXX-44G)Q>Q1Q-QRHII BlL3,>Segkm x3	J""6Hx"PHH6(S>  D(5U2
z~~na@EAFZ^^L!<ABz~~j!<ABQ>A#5,:J+l:NA/Z"?89OKE++		  v .2F2LeVYk[giwy oqw  zH  JO  RU  JU  V HH&
H= &.LL(O3Bj3PH:Y/V^dJ&$\Sbdvw4h>NO	E3&&$s!ueHVWFXZ (G4K|$H(RTV	
a z" A=U);(>?@@AP z* *&)#*P  	Z!J6(RTUVTWXYY	ZX  	V!FvhbQRPSTUU	V  	C!=aSABB	CT ! $Q Q  	uIIbdjlprstt	u ! $Q Q  	uIIbdjlprstt	u.  DT!WEUEUDVW		6
FTXYT:v.	  	H!81#FGG	H  OJANNO6  SNPQRRSF  	mIIZ\bdhjkll	m< z" N  A		  K$	#/s2YZT:{3yK@@@AD  	jKKPRY\]R]_eghii	j  	RKKEvqQQ	RP  	'IIvdA' '	'<  	JKKJFT_`J!2!YeE<P<PQW<X6Y!%!@Ab	##.I%I>	'IN9R,SWX,X"3x)';#<y#H%PH-Y5I1IJH'IN9R,SWX,X"3x)';#<y#H%PH-Y5I1IJH&&v8&T%-x(L"NHhH J3K?'+Y4$  		Y$h8HJ J	J%	J\  D?CCD*  E@!DDEsK  A^' 9(A_ 'A_/ A` &A`3 BAa/ /Aa C Aa/ -*Aa"AAa/ )BAb; 5Ab CAb; /*Ab.AAb; +C3Ac* "(Ad> Ae  -Af @$D
Af: D6Ag) E+AAh GA$Ah H'1Ah N;BAi	Q6Ai; SC/Aj) X,Ak YC"Ap ]42Aq	 ^'-A__A_,_+A_,_/	A`_8A`	`	A``	A`0`A`+`+A`0`3	Aa`<Aa
a
Aaa	AaaAa/ aAaaAa/ a"Aa,a'Aa/ a/	Aba8AbbAbb	Ab+b'Ab; b*Ab+b+Ab; b.Ab8b3Ab; b;	Ac'cAc"c"Ac'c*	Ad;c3>Ad6d6Ad;d>	AeeAeeAee 	Af
e)AffAf
f	Af7fAf2f2Af7f:	Ag&gAg!g!Ag&g)Ag>g=Ag>h	Aih
1Aih;AiiAii		Ai8iAi3i3Ai8i;	Aj&jAj!j!Aj&j)	Akj2AkkAkk
Apk"Apk:CAooApo	Apo$AppAppAppAppApp	Aqp%AqqAqq		Aq3qAq.q.Aq3c                  ,    e Zd ZdZdZd Zd Zd Zd Zy)WebhookHandlerNc                     y r   r   )selfr   r   s      r   log_messagezWebhookHandler.log_message  s    r!   c                   t        j                  |      j                  d      }	 | j                  |       | j	                  dd       | j	                  dt        t        |                   | j	                  dd       | j                          | j                  j                  |       y # t        $ r }t        j                  d|       Y d }~y d }~ww xY w)Nr   zContent-Typezapplication/jsonContent-Length
Connectionra  zSend failed: %s)rY   rZ   encodesend_responsesend_headerrA   r   end_headerswfiler  rO   r:   r   )r  coder[   bodyr9  s        r   
_send_jsonzWebhookHandler._send_json  s    zz'"))'2	.t$^-?@-s3t9~>\73JJT" 	.KK)1--	.s   BB+ +	C4CCc                   | j                   j                  d      d   }|j                  d      r|j                  dd      j	                         }|s| j                  dddi      S 	 t        | j                  |      }|s| j                  dd	|d
      S | j                  d||d   xs d|d   |d   d      S |dk(  rS| j                  ddddt        t        ddt        j                  t        j                        j!                         d      S |dk(  r_	 t#        | j                        \  }}| j                  dd|d   |d   |d   |d   |d   |d   | j$                  j'                         |d	      S | j                  dddi      S # t        $ r'}| j                  ddt        |      i      cY d }~S d }~ww xY w# t        $ r'}| j                  ddt        |      i      cY d }~S d }~ww xY w)Nr   r   z/webhook/status/r$     r;   zmissing request_id  zrequest_id not found)r;   r]   rm  r   r*   r   )r]   rg   rf   r;     z/healthTzbybit-webhookr  )enabledr}   max_future_secondsmissing_timestamp)okservice
time_guardr  z/statusrd   r`   r#  r~   r%  )	r'  queue_pendingqueue_completedqueue_failedqueue_skippedqueue_expiredqueue_tunnel_blockedqueue_size_in_memoryposition_owners	not found)r  r   r  rs   r7   r  r!  dbrO   rA   r   r   r   rV   r   rW   rX   r(  r7  qsize)r  r  r]   r   r9  r&  r'  s          r   do_GETzWebhookHandler.do_GET  s   yys#A& ??-.&8"=CCEJsW6J,KLL?(*=??3:P`j0klls",!!f1	 #A V	-   9??3*)-ew  MV  Wll8<<0::<	)   9?!:477!Cs%+I%6'-k':$*8$4%+I%6%+I%6,23C,D,0MM,?,?,A'-
- 
 
 sWk$:;;3  ?sWc!f,=>>?.  ?sWc!f,=>>?sC   ',F #F AF; 	F8F3-F83F8;	G+G& G+&G+c                   | j                   j                  d      d   }|dk(  r	 t        | j                  j	                  dd      xs d      }|r,| j
                  j                  |      j                  dd      nd	}t        j                  |      }t        |j	                  d
d            j                         j                         }|dvr| j                  dddi      S 	 t        dz  j                  |d       |dk(  rnt#        | j$                        }|D ]  }| j&                  j)                  |        t+        |      }t,        j/                  d|       | j                  ddd|d      S t1        | j$                        }	t,        j3                  d|	       | j                  ddd|	d      S |dk7  r| j                  dddi      S 	 t        | j                  j	                  dd      xs d      }|r,| j
                  j                  |      j                  dd      nd}	 t        j                  |      }t        |j	                  d!d            j                         }|t4        vrxt,        j3                  d"|j	                  d#      |j	                  d$      |j	                  d%      t7        d& |j9                         D                     | j                  d'dd(i      S |j	                  d#      s| j                  ddd)i      S |j	                  d$      s| j                  ddd*i      S |j	                  d+      |j	                  d+      dk(  r| j                  ddd,i      S t;        |      }|re	 t=        | j$                  ||      }t,        jA                  d1|||j	                  d#      |j	                  d%             | j                  d2||dd3      S d4}	 t        dz  jC                  d      j                         j                         }|dk(  }	 tG        | j$                  ||6      }|s| j&                  j)                  ||f       |rt,        j3                  d9|       t,        j/                  d:||j	                  d#      |j	                  d$      |j	                  d+      |rd;nd       | j                  dd|tI        jJ                  tL        jN                        jQ                         d<|d=      S # t         $ r Y w xY w# t         $ r'}
| j                  ddt        |
      i      cY d }
~
S d }
~
ww xY w# t         $ r(}
| j                  ddt        |
      d      cY d }
~
S d }
~
ww xY w# t         $ r(}
| j                  dd t        |
      d      cY d }
~
S d }
~
ww xY w# t         $ r- t,        j?                  d-       | j                  d.d/dd0      cY S w xY w# tD        $ r Y t         $ r!}
t,        j3                  d5|
       Y d }
~
d }
~
ww xY w# t         $ r>}
t,        j?                  d7|
       | j                  dd8t        |
      d      cY d }
~
S d }
~
ww xY w)>Nr   r   z/tunnel-stater  0r   rs   )errorsz{}stater$   )updownr!  r;   zstate must be 'up' or 'down'ztunnel_state.txtr   r:  z4TUNNEL UP: sbloccate e accodate %d richieste frescherm  T)r'  r9  	unblockedz\TUNNEL DOWN: %d richieste gia' bloccate, nuove richieste saranno accettate ma non processater;  )r'  r9  already_blockedr#  z/webhookr"  r2  zread failed)r;   detailzinvalid JSONrC  z>REJECTED WRONG_SECRET: symbol=%r side=%r strategy=%r fields=%sr   r   r   c              3  l   K   | ],  }t        |      j                         d k7  s t        |       . yw)rC  N)rA   r   )r   keys     r   r   z)WebhookHandler.do_POST.<locals>.<genexpr>   s&     WC#c(..:Jh:Vs3xWs   !44i  WRONG_SECRETzmissing symbolzmissing sider   zmissing qtyz,Time rejection audit failed; request blockedi  TIME_GUARD_AUDIT_FAILED)r;   r  z&%s request_id=%s symbol=%s strategy=%si  )r;   r]   r  Fz'Marker tunnel_state.txt read failed: %s)r\   zQueue/persist failed: %szqueue failedzQTUNNEL DOWN: richiesta %s persistita ma NON accodata; attende tunnel UP entro TTLz$ACCEPTED %s: %s %s qty=%s (queued%s)z, tunnel_blockedz-Order queued, will be processed in background)r'  r]   	queued_atmessager%  ))r  r   r5   headersr   rfilereaddecoderY   r   rA   r7   r   r  r  r@   rO   r   r3  r7  putr   r:   rD   r   r   ALLOWED_SECRETSsortedkeysr
   rb   r3  r;   r6   FileNotFoundErrorr^   r   rV   r   rW   rX   )r  r  lengthr   datar9  unblocked_itemsr8  r<  nr9  received_secretra   r]   r%  r   s                   r   do_POSTzWebhookHandler.do_POST  s   yys#A& ?"?T\\--.>DIJSYdjjoof-44WY4O_czz#DHHWb1288:@@B.??3:X0YZZ11==eg=V D=&@&IO / 0))$/0 #O 4IHHSU^_??3tdYb0cdd4TWW=AKK ~  AB  C??3tfab0cdd :??3+(>??
	T))*:C@EAFFOU$**//&)000K[]C
	U::c?D
 dhhx45;;=/1 KKP"DHHV$4dhhz6JW499;WW
 ??3.(ABB xx!??32B(CDDxx??3.(ABB 88E?"dhhuo&;??3-(@AA!$'a2477D&I
 II>
TXT\T\]eTfhlhphpq{h|}??3j\`(abb 	F 22==w=OUUW]]_F#v-N	U($~VJ!!!:t"45
 KKk"$ 	7TXXh/&1A488E?'5#2	? s$!hll3==?F,%
  	} !   ?sWc!f,=>>?  	T??3-3q6(RSS	T  	U??3.CPQF(STT	U:  aLMs5NZ^,_``a ! 	 	FKKA1EE	F  	UMM4a8??3.CPQF(STT	Us   B<T $S8 >A2T 1A T AT; &U/ 5V# :W 7X 8	TT TT 	T8T3-T83T8;	U,U'!U,'U,/	V 8VV V #3WW	X(X0XX	Y3YYY)	r  
__module____qualname__r3  r7  r  r  r5  rS  r   r!   r   r  r    s"    	BH
.+<Ztr!   r  c                    t                t               } t        |       }t        j                         }|r8t
        j                  dt        |             |D ]  }|j                  |        nt
        j                  d       t        j                  t        | |fd      }|j                          | t        _        |t        _        t#        t$        t&        ft              t
        j                  d       t
        j                  d       t
        j                  dt$        t&               t
        j                  d       t
        j                  d	       t
        j                  d       fd
}t)        j(                  t(        j*                  |       t)        j(                  t(        j,                  |       	 j/                          	 t0        j3                          t
        j                  d       y # t4        $ r Y !w xY w# 	 t0        j3                          n# t4        $ r Y nw xY wt
        j                  d       w xY w)Nz8RECOVERY: %d pending items from previous run, re-queuingzNo pending items to recoverT)r   r   daemonz<============================================================zWEBHOOK READY (async pattern)zListening on %s:%dz,Fast path: <100ms (validation + queue + 200)z3Background worker: process order in separate threadc                P    t         j                  d       j                          y )NzShutdown signal received)r:   rD   shutdown)signumframeservers     r   rY  zmain.<locals>.shutdownf  s    +,r!   zServer stopped)rF   rR   r   queueQueuer:   r   r   rI  rD   	threadingThreadr:  startr  r3  r7  r	   LISTEN_HOSTLISTEN_PORTr  SIGINTSIGTERMserve_foreverr3   unlinkrO   )r3  r   r7  r8  workerrY  r\  s         @r   mainri  @  s    
B $B'G{{}HNPST[P\] 	DLL	 	./ [H~dSF
LLN N&N !+{!;^LFHHXHH,-HH!;<HH;<HHBCHHX MM&--*
MM&..(+#	OO 	!"  			OO 		!"sB   8H 	G3 3	G?>G?H>HH>	H%"H>$H%%H>c                    | rt        |       |k  ryd|dz   z  }t        | d|       |z  }| |d D ]  }||z  |d|z
  z  z   } |S )zCalcola EMA 50 su una lista di close. Ritorna float o None.
    Usa la formula standard EMA = close * k + prev_ema * (1-k), k=2/(period+1).
    Seed: SMA delle prime `period` candele. Gestione input insufficienti: None.Ng       @r*   )r   sum)closesperiodkemacs        r   compute_ema50rq  z  sh     S[6)vzA
fWfo

'CFG_ $!ecQUm#$Jr!   c                "   t        |       j                         j                         } | st        S | j	                  d      r| dd S | j	                  d      r	 t        t        | dd       dz        S | xs t        S # t        $ r	 t        cY S w xY w)zConverte '30m' -> '30', '4H' -> '240', '1h' -> '60', '3h' -> '180' per API Bybit.
    Gestisce case-insensitive. Default fallback: EMA50_DEFAULT_TIMEFRAME.mNr  hr+   )rA   r7   r   EMA50_DEFAULT_TIMEFRAMEr  r5   r?   )tf_strs    r   _tf_string_to_bybitrw    s     [ &&(F&&scr{s	+s6#2;'",-- ,,,  	+**	+s   A< <BBc                v   	 | dv rM	 ddl m}  |       D ];  }|d   |j                         k(  s|j                  dd      s-t        |d         c S  n| d	k(  rM	 dd
l m	}  |       D ];  }|d   |j                         k(  s|j                  dd      s-t        |d         c S  nQ| dk(  rL	 ddl m
}  |       D ];  }|d   |j                         k(  s|j                  dd      s-t        |d         c S  	 ddlm}  |       D ];  }|d   |j                         k(  s|j                  dd      s-t        |d         c S  	 t
        S # t        $ r# t        j	                  dt
               t
        cY S w xY w# t        $ r# t        j	                  dt
               t
        cY S w xY w# t        $ r# t        j	                  dt
               t
        cY S w xY w# t        $ r# t        j	                  dt
               t
        cY S w xY w# t        $ r*}t        j	                  d|t
               Y d}~t
        S d}~ww xY w)a  Ritorna il timeframe Bybit ('60'=1H, '240'=4H, '30'=30m, '180'=3H, '5'=5m, '15'=15m) per la strategia.
    - vptr3: legge da VPTR_V3_ASSETS.csv colonna timeframe
    - rettangolo: legge da rettangolo_assets.csv
    - rettangolo_simple: legge da RETTANGOLO_SIMPLE_ASSETS.csv
    - ma_trailing: legge da MA_TRAILING_ASSETS.csv
    - fallback: 4H (240) se read fallisce o simbolo non in lista.
    NOTA Coder 19/07 13:46: load_assets() per rettangolo NON esiste in sltp_engine.py
    (esiste solo load_vptr3_assets), quindi importiamo da rettangolo_config.py
    che e' il modulo canonico per la lettura di rettangolo_assets.csv.
    FIX 2026-08-05 (Mattia 4 strategie): supporto RETTANGOLO_SIMPLE + MA_TRAILING.
    rw  r   )load_vptr3_assetszWP007 get_strategy_timeframe: sltp_engine.load_vptr3_assets non importabile, fallback %sr   r$  T	timeframer   )load_rettangolo_simple_assetszWP007 get_strategy_timeframe: load_rettangolo_simple_assets non importabile, fallback %sr   )load_ma_trailing_assetszQP007 get_strategy_timeframe: load_ma_trailing_assets non importabile, fallback %s)load_assetszWP007 get_strategy_timeframe: rettangolo_config.load_assets non importabile, fallback %sz6P007 get_strategy_timeframe exception: %s, fallback %sN)sltp_enginery  r>   r:   r   ru  r  r   rw  r{  r|  rettangolo_configr}  rO   )r   r   ry  assetr{  r|  _load_rett_assetsr9  s           r   get_strategy_timeframer    s0   *j++/9
 +, C?flln49d9S.u[/ABBC ,,/E
 78 C?flln49d9S.u[/ABBC &/?
 12 C?flln49d9S.u[/ABBC	+J
 '( 	?EX&,,.0UYYy$5O*5+=>>	?
 #"O  /u35../  /u35../  /o35../  	+KKq/1**	+  jLaQhii""js   H E	  H H H H E8  H  H H #H +F' 1 H H %H 5H 7G = H H 1H H 	)E52H 4E55H 8)F$!H #F$$H ')GH GH )H?H HH 	H8H33H8c                   t         sy	 t        ||      }| j                  ||t              }|rt	        |      t
        dz   k  rBt        j                  d|||rt	        |      ndt
        dz          dd|rt	        |      nd dfS |dd	 D cg c]  }t        |d
          }}t	        |      t
        dz   k  ryt        |t
              }|d   }	|y|j                         dv r|	|k  r/dd|	dd|dfS |j                         dv r|	|kD  rdd|	dd|dfS dd|	dd|dfS c c}w # t        $ r'}
t        j                  d|
       dd|
 fcY d}
~
S d}
~
ww xY w)a  Controlla P007 regime EMA 50.
    Ritorna (pass, reason).
    - pass=True: regime OK, ordine puo' procedere
    - pass=False: regime KO, SKIP-REGIME
    - Se fetch klines fallisce o dati insufficienti: pass=True con reason warn
      (regola Mattia "MAI bloccare").
    Usa candela [-2] (P010 Charter, esclude candela in formazione).
    fetch_ohlcv ritorna lista [ts, o, h, l, c, v]; escludiamo l'ultima (live)
    e poi prendiamo close[-2] dalle klines chiuse.)TzP007 DISABLED via kill switchr   zKP007 SKIP-CHECK: klines insufficienti per %s tf=%s (%d<%d), regime IGNORATOr   Tz,P007 skip-check: dati insufficienti (klines=r   Nr  r   r*   )Tz6P007 skip-check: chiuse insufficienti post-filtro live)TzP007 skip-check: ema50 Noner   Fz!P007 SKIP-REGIME LONG: close[-2]=r  z < EMA50[-2]=r   z"P007 SKIP-REGIME SHORT: close[-2]=z > EMA50[-2]=zP007 OK: close[-2]=z vs EMA50[-2]=z8P007 check exception: %s, regime IGNORATO (MAI bloccare)zP007 skip-check: exception )EMA50_REGIME_ENABLEDr  fetch_ohlcvEMA50_LOOKBACK_CANDLESr   EMA50_PERIODr:   r   r   rq  r   rO   )clientr   r   r   rG  klinesrp  rl  ema50
last_closer9  s              r   r  r    s     69#Hf5##FB0FGV|a'77KKe6CKq,QRBRTHX^VdeHffghii'-cr{3!%!+33v;))Sfl3BZ
=8::<?*E!!B:cBRR_`efi_jkllZZ\..E!!CJsCSS`afgj`klmm+Js+;>%PSUVV 4  9NPQR3A37889sN   A;D( D( D#!D( 9D( "D( 4"D( D( #D( (	E1EEE__main__)F)r[   r  r\   boolreturnrA   )NN)r]   rA   rf   rA   r;   rA   )r]   rA   ra   rA   )expired_pending_ttl)r}   r5   )r]   rA   r}   r5   r  r  )r  r5   )r  rA   )r[   r  r  r  )r[   r  r   rA   r  ztuple[str, str])r[   r  r   r   r  r   )r   )r   rA   r   rA   r   rA   r]   rA   rf   rA   r   rA   )r   rA   )r   rA   r   rA   r  rA   )T)r]   rA   r  r  )r]   rA   )r7  zqueue.Queue)r]   rA   r[   r  )r.   )k__doc__
__future__r   rB   r<   rY   r5  r  loggingr_  r]  rK   rT   pathlibr   r   r   r   http.serverr   r	   alert_time_guardr
   r   r   r/  r  r  LOG_FILEr  rM   r3   basicConfigINFOFileHandlerStreamHandler	getLoggerr:   RLockr   r    _EXPECTED_DEFAULTenvironr   r7   _webhook_secrets_envr   rJ  EXPECTED_SECRETr  r  _map_envpairr  stratrb  rc  r  r  r  r5   PENDING_MAX_AGE_SECONDSr  r  ru  r  r  r  rF   rR   r^   rb   rh   rk   rn   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r!  r(  r,  r0  r:  r2  r  ri  rq  rw  r  r  r  )ss   0r   <module>r     s   D # 	 
          2 2 C R R
 56

 t ++|#

&
&++   
,,>Hw7 g	" )//
 * zz~~&7<BBD *>*D*DS*IWQQWWYqwwyWO()O#
 ::>>"<gFLLNYRY  ::>>7<BBDs# =$;C+JC/4{{}		,=
   b#bjjnn5QSX&Y"Z[ 
     ,_ )? 2$ 1 1h 	 	         6M  $ 4K.1PT 4 4 4 	4 	4     O O.Z
FRR2.  EN#&25?B  
 
  
 / /$   L L&    6 
0jE`t+ tt4#t
-"7#t$9N zF y4 Xs   /MM