
    /L_jb                     &   d Z ddlZddlZddlZddlZddlZddlmZmZ ddlm	Z	 ej                  j                  d e e	e      j                               ddlmZ ddlmZmZmZmZ ddlmZ ej0                  j3                  dd	      Zej0                  j3                  d
d      ZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ' e	d      Z(dZ)d Z*de+fdZ,de+ddfdZ-d Z.dedefdZ/de0fd Z1d! Z2d" Z3d# Z4d$ Z5d*d%Z6d*d&Z7d' Z8d( Z9e:d)k(  r e9        yy)+aV  
SL/TP Engine - REGOLE UNIFICATE (Rettangolo + VPTR3)
======================================================
Per ogni posizione aperta su Bybit Demo, calcola SL/TP usando la strategia
corrispondente (Rettangolo o VPTR3) e li applica via webhook (con fallback
diretto Bybit se il webhook e' giu').

MAPPING STRATEGIA (rettangolo_assets.csv colonna 'strategy'):
  - 'rettangolo': calcola SL/TP con compute_signal() del Quadrato + trailing
  - 'vptr3': SL hard -3%, TP parziale +5% (50% size), TP finale +3% addizionale

REGOLE RETTANGOLO (compute_signal):
  - Range = high/low candela daily precedente
  - SL iniziale = estremo Hammer +/- 1% buffer
  - TP = MID range (fisso)
  - Trailing SL: si attiva SOLO DOPO +1.5% dal entry (LONG) o -1.5% (SHORT)

REGOLE VPTR3 (estese, la strategia Pine non le ha):
  - SL hard: se PnL <= -3% e strategia non ha chiuso, chiude tutta la posizione
  - TP parziale: se PnL >= +5% e strategia non ha chiuso, chiude 50% della size
  - TP finale: dopo TP1, aspetta +3% addizionale dal prezzo TP1, chiude resto
  - Trailing SL: simile al rettangolo, si attiva a +/-1.5% dal entry
    N)datetimetimezone)Path)BybitDemoClient)compute_signalis_dojihas_hammer_bullishhas_hammer_bearish)load_assetsWEBHOOK_URLzhttp://127.0.0.1:5580WEBHOOK_SECRET z/webhook/sltpg{Gz?gQ?gQ?gQg?i,        g{Gzt?zC/opt/charter-live/live_deploy/webhook_listener/logs/sltp_state.jsonzC/opt/charter-live/live_deploy/webhook_listener/logs/sltp_engine.logc                    t        j                  t        j                        j	                         j                         }d| d|  }t        |d       	 t        j                  t        j                  j                  t              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exist_okautf-8encoding
)r   nowr   utc
astimezone	isoformatprintosmakedirspathdirnameLOG_FILEopenwrite	Exception)msgtslinefs       ,/opt/charter-live/live_deploy/sltp_engine.pylogr-   A   s    	hll	#	.	.	0	:	:	<Brd"SE?D	$d
BGGOOH-=(C'2 	!aGGD4K 	! 	! 	! s1   A
C
  B>5C
 >CC
 C
 
	CCreturnc                      t         j                         si S 	 t        t         dd      5 } t        j                  |       cddd       S # 1 sw Y   yxY w# t
        $ r i cY S w xY w)zBCarica stato persistente (es. VPTR3 TP1 gia' eseguito per symbol).rr   r   N)
STATE_FILEexistsr%   jsonloadr'   )r+   s    r,   
load_stater5   M   sY    	*cG4 	 99Q<	  	  	  	s-   A A		A 	AA A A#"A#statec                     	 t        j                  t        j                  d       t	        t        dd      5 }t        j                  | |dt               ddd       y# 1 sw Y   yxY w# t        $ r}t        d	|        Y d}~yd}~ww xY w)
zSalva stato persistente.Tr   wr   r      )indentdefaultNzWARN save_state: )
r    r!   r1   parentr%   r3   dumpstrr'   r-   )r6   r+   es      r,   
save_stater@   X   sr    %
J%%5*cG4 	7IIeQq#6	7 	7 	7 %s#$$%s4   7A, A A,  A)%A, )A, ,	B5BBc           
      <   | j                  |||      }g }|D ]  }t        |d         |d   |d   |d   |d   f\  }}}	}
}|j                  |t        j                  |dz  t
        j                        j                         j                         ||	|
|d        |S )	Nr      r9         i  )tz)r)   dater%   highlowclose)	fetch_ohlcvintappendr   fromtimestampr   r   r   r   )clientsymbolintervallimitrawoutrowts_msohlcs               r,   fetch_klines_dictrZ   b   s    


VXu
5C
C AKQQQQGq!Q

**54<HLLITTV``bqQ
 	 J    rO   c                     | j                         }t               D ]   }|d   |k(  s|d   s|d   }|dk(  rd}|c S  t               D ]  }|d   |k(  s|d   s|d   c S  y)us  Ritorna 'rettangolo' o 'vptr3' per il symbol.
    FIX 2026-07-18 (Mattia BREAKING POINT): VPTR3 ha file dedicato VPTR_V3_ASSETS.csv
    (NO contaminazione con rettangolo_assets.csv). Legge PRIMA vptr3, POI rettangolo.
    Rispetta campo 'enabled': se disabled in vptr3, salta e cerca in rettangolo.
    Se symbol NON in nessun file â†’ 'rettangolo' (default legacy).rO   enabledstrategyvptr_v3vptr3
rettangolo)upperload_vptr3_assetsr   )rO   symbol_uassetr^   s       r,   get_strategy_for_symbolrf   o   s     ||~H #$ ?h&5+;Z(H9$"O  %?h&5+;$$% r[   c                  6   g } t        t              j                  dz  }|j                         sg S 	 ddl}t        |dd      5 }|j                  |      }|D ]  }|j                  d      s|j                  dd	      }| j                  |d   j                         j                         ||j                  d
d      j                  dd      j                  dd      t        |j                  dd            j                         dk(  |j                  dd      j                         j                         |j                  dd      j                         d        	 ddd       | S # 1 sw Y   | S xY w# t        $ r}t        d|        Y d}~| S d}~ww xY w)u&  Carica VPTR3 assets da VPTR_V3_ASSETS.csv (separato da rettangolo_assets.csv).
    FIX 2026-07-18 (Mattia BREAKING POINT): strategie separate, NO contaminazione.
    Ritorna lista di dict {symbol, timeframe, tf_min, enabled, strategy, notes}.
    Se file non esiste o vuoto â†’ ritorna [].zVPTR_V3_ASSETS.csvr   Nr0   r   r   rO   	timeframe30mr   rW   Hr]   truer^   r`   notes)rO   rh   tf_minr]   r^   rm   zWARN load_vptr3_assets: )r   __file__r<   r2   csvr%   
DictReadergetrL   striprb   replacer>   lowerr'   r-   )rS   csv_pathcsvmodr+   readerrT   tfr?   s           r,   rc   rc      sv   
 CH~$$';;H??	,(C'2 	a&&q)F wwx(WW[$/

!(m11399;!# jjb199#rBJJ3PRS"3779f#=>DDF&P #
G < B B D J J L WWWb1779 		  J!	  J  ,&qc*++J,s6   E6 DE)E6 )E3.E6 3E6 6	F?FFc                    	 t        | |dt              }t        |      dk  ry|d   }t        | ||t              }t        |      dk  ryt        |      dkD  r|dd n|}	t        |	      dk  ryt	        d| d| d	t        |	       d
|d   j                  dd       d	       d}
d}t        dt        |	            D ]  }|	|   }||   }|dk(  rB|d   |d   k  r6t        |      st        |      r t        |d   |z
         t        |d      z  }nCT|d   |d   kD  r6t        |      st        |      r t        |d   |z
         t        |d      z  }n||kD  s|}|}
 |
y||
   }|d   }|d   }||z   dz  }|dk(  r|d   }|dt        z   z  }n|d   }|dt        z
  z  }|dk(  rC||k\  r>t	        d| d| d| d       |dt        z
  z  }|}||k\  r^t	        d| d| d| d       y|dk(  rC||k  r>t	        d| d| d| d       |dt        z   z  }|}||k  rt	        d| d| d| d       y|dk(  r&|dz  }||k  rFt	        d| d |d!d"|d!d#       |}|}n*|dk(  r%|d$z  }||kD  rt	        d| d%|d!d&|d!d'       |}|}|dk(  r	||z
  |z  }n||z
  |z  }|t        k\  r?|dk(  r|||z
  d(z  z   }t        ||d)z        }n|||z
  d(z  z
  }t        ||d*z        }|}d+}n|}d,}t        |d-      t        |d-      t        |d-      d.|
 d/| d|t        |d0z  d1      |||||d2S # t         $ r}t	        d| d3|        Y d}~yd}~ww xY w)4a
  Calcola SL/TP per posizione RETTANGOLO.
    Ritorna dict {sl_price, tp_price, sl_ref, source, breakeven} o None.
    Trailing: attivato SOLO se current_price in profitto di >= 1.5% dal entry.
    Una volta attivato, SL segue il prezzo (high per SHORT, low per LONG).Dr9   NrB   zcompute_sltp_rettangolo  z: scanning z. CLOSED candles (excluded last live candle ts=time?)SellrI   r%   rG   &.>rH   Buy  z: SL iniziale z
 >= entry z( (LONG), fallback su prev_daily.low*0.99z: SL fallback z ancora >= entry z, ritorno None (skip)z
 <= entry z* (SHORT), fallback su prev_daily.high*1.01z ancora <= entry g
ףp=
?z: P006 CLAMP LONG: SL iniziale z.6fz sotto cap -3% (z), clampato a -3%g{Gz?z : P006 CLAMP SHORT: SL iniziale z sopra cap +3% (z), clampato a +3%g      ?g+?gjt?TF   zcompute_signal(hammer@idx=z, tf=d   rC   )sl_pricetp_pricesl_refsourcetrailing_active
profit_pctrng_toprng_botrng_mid_side_entry_pricez%: compute_sltp_rettangolo exception: )rZ   DAILY_LIMITlenINTRADAY_LIMITr-   rr   ranger   r
   absmaxr	   RETTANGOLO_SL_BUFFER_PCTRETTANGOLO_TRAILING_TRIGGER_PCTminroundr'   )rN   rO   sideentry_pricecurrent_pricerh   daily
prev_dailyintraintra_closedbest_idx
best_scoreibarscorehammerr   r   r   r   
sl_initial
p006_floorp006_ceilingr   sl_trailingslr   r?   s                               r,   compute_sltp_rettangolor      s   
A!&&#{Cu:>2Y
!&&)^Lu:> &)Z!^uSbz|q &vhav[\AR@S  TB  CH  IK  CL  CP  CP  QW  Y\  C]  B^  ^_  `  	a 
q#l+, 	Aq/C(Cv~w<#f+-73<CUVYCZ V}!<==MSW@XXEw<#f+-73<CUVYCZ Um!;<<s=RV?WWEz!"
	" xV$U#W$)6>F^F1'?#?@JE]F1'?#?@J 5=Z;6"VHN:,jMuvw A(@$@AJF[(bzl:KK=XmnoV^
k 9"VHN:,jMwxy A(@$@AJF[(bzl:KK=Xmno 5=$1JJ&b ?
3?OO_`jkn_o  pA  B  C'
$V^&(3LL(b @C@PP`amnq`r  sD  E  F)
$ 5='+5DJ%5DJ 88 u})][-HC,OO!+}u/DE)[=-HC,OO!+}u/DEB"OB#O b!gq)FA&28*E)AN.
S 0!47w'

 
	
  b=aSABsD    L% %L% 	#L% -C(L% L% BL% &AL% .C6L% %	M	.MM	c                 ,    | dk(  r||z
  |z  S ||z
  |z  S )Nr    )r   r   r   s      r,   compute_pnl_pctr   5  s)    u}+{::m+{::r[   c                    t        |||      }|j                  |i       }|t        k  rdd|d|dz  ddt        dz   di dS |j                  d	d
      }	|	sh|t        k\  r_ddt	        |dz  d      d|dz  ddt        dz   d|d|t        j                  t        j                        j                         |||didS |	ra|j                  d|      }
|dk(  r|
dt        z   z  }n|
dt        z
  z  }|dk(  r||k\  s
|dk(  r"||k  rdd|d| d|ddt        dz   d|
 d	i dS |dk(  r|dt        z
  z  }n|dt        z   z  }dt	        |d      dd|dz  ddi dS )a  Processa posizione VPTR3.
    Logica:
    - Se PnL <= -3% (VPTR3_SL_HARD_PCT) e strategia Pine non ha chiuso -> SL hard, chiude TUTTO
    - Se PnL >= +5% (VPTR3_TP_PARTIAL_PCT) e TP1 non ancora eseguito -> TP parziale, chiude 50% size
    - Se TP1 eseguito e PnL >= +3% addizionale al prezzo TP1 -> TP finale, chiude il resto
    - Altrimenti: imposta SL trailing a -1.5% sotto il current (per LONG) o +1.5% sopra (per SHORT)

    Ritorna dict con:
    - 'action': 'hold' | 'close_full' | 'close_partial' | 'update_sl'
    - 'sl_price': nuovo SL (se update_sl o close_full)
    - 'tp_price': None (non usiamo TP su Bybit, gestiamo via riduzione size)
    - 'close_size': size da chiudere (per close_partial)
    - 'reason': descrizione per log
    - 'new_state': aggiornamento stato TP1
    
close_fullNzVPTR3 SL hard: PnL=r   .2fz% <= %)actionr   
close_sizereason	new_statetp1_doneFclose_partialr9   r   zVPTR3 TP parziale: PnL=z% >= +T)r   	tp1_pricetp1_tsr   r   original_sizer   r   rB   r   zVPTR3 TP finale: current=z >= target=z.4fz (+z% addizionale al TP1 @ r   	update_slzVPTR3 trailing: PnL=z%, SL a -1.5% dal current)r   rr   VPTR3_SL_HARD_PCTVPTR3_TP_PARTIAL_PCTr   r   r   r   r   r   VPTR3_TP_FINAL_ADD_PCTVPTR3_TRAILING_TRIGGER_PCT)rN   r6   rO   r   r   r   sizepnl_pct	sym_stater   r   targetr   s                r,   process_vptr3_positionr   <  s     dK?G		&"%I ##"+GCK+<EBSTWBWAXXYZ
 	
 }}Z/H#77%q!,/C/@G[\_G_F``ab $!.&ll8<<8BBD#. %)	
 	
$ MM+{;	5=!&<"<=F!&<"<=FEMmv546>m_eNe& "5m_KPVWZ|[^_uvy_y^z  {R  S\  R]  ]^  _  u}#q+E'EF#q+E'EF+q)(S(99RS r[   c                     	 t        j                  t         t         t        | ||dd      }|j
                  dk(  d|j
                   d|j                  dd  fS # t        $ r}dd	| fcY d}~S d}~ww xY w)
z;Prova a chiamare webhook /webhook/sltp. Ritorna (ok, body).)secretrO   r   r   r   )r3   timeoutr   zHTTP : NFzwebhook err: )requestspostr   WEBHOOK_SLTP_PATHr   status_codetextr'   )rO   r   r   r0   r?   s        r,   apply_via_webhookr     s    ,MMm-./( $$	 	
 $amm_Bqvvds|n&MNN ,qc*++,s   AA 	A7&A2,A72A7c                     	 | j                  |||      }|j                  d      dk(  d|j                  d       d|j                  d       fS # t        $ r}dd| fcY d	}~S d	}~ww xY w)
z4Fallback diretto via Bybit API (bypassa il webhook).r   r   retCoder   zBybit retCode=r   retMsgFzBybit err: N)set_trading_stoprr   r'   )rN   rO   r   r   r0   r?   s         r,   apply_via_bybitr     sz    *##FX#Qi A%i8H7IAEERZOK\']^^ *QC())*s   AA 	A*A%A*%A*c                 |    t        |||      \  }}|rdd| fS t        d| d|dd  d       t        | |||      S )	zAApplica SL/TP: tenta webhook, se fallisce fallback Bybit diretto.Tz	webhook: r   z: webhook fallito (Nr   z), fallback Bybit direttor   )r   r-   r   )rN   rO   r   r   okbodys         r,   
apply_sltpr     sY     8<HB		$())"VH'Tc
|3LMN66HxPPr[   c                     	 |dk(  rdnd}| j                  |||      }|j                  d      dk(  d|j                  d       d|j                  d       fS # t        $ r}dd	| fcY d
}~S d
}~ww xY w)z<Chiude parzialmente una posizione (market order reduceOnly).r   r   r   r   zretCode=r   r   Fzerr: N)create_market_orderrr   r'   )rN   rO   r   r   
close_sider0   r?   s          r,   apply_partial_closer     s    $"fnU&
&&vz:Fi A%!%%	2B1C2aeeHoEV'WXX $qc{##$s   AA 	A2!A-'A2-A2c                  	   t         s t        d       t        j                  d       t	               } t        dt
         d       	 	 t               }t        |      }| j                         }|st        d       nft        t        |       d       |D ]I  }|d   }|j                  dd	      }|j                         d
v rdnd}t        |j                  dd      xs d      }|dk  rV	 t        |j                  dd      xs d      }	|	dk  r|	 | j                  ddd|dd      }
t        |
d   d   d   d         }t#        |      }t%               D ci c]  }|d   |d    }}|j                  |d      }t'        ||	|      }t        d| d| d| d| d |	 d!| d"|d#z  d$d%       |d&k(  rt)        | ||||	||      }t        d| d'|d(           |d)   r|j+                  |d)          n||v r|d*   d+k(  r|j-                  |d        |d*   d+k(  r't/        | |||d,         \  }}t        d| d-|        |d*   d.k(  r-t/        | |||d,         \  }}t        d| d/|d,    d0|        |d*   d1k(  st1        | ||d2   d 3      \  }}t        d| d4|d2    d5|d d#  d6       t3        | |||	||      }|t        d| d7       >t        d| d8|d2    d9|d:    d;|j                  d<              |j                  d=d	      }|j                  d>d	      }	 |rt        |      nd }|rt        |      nd }|d u xs( t5        ||d2   z
        t7        |d2   d@      z  t8        kD  }|d u xs( t5        ||d:   z
        t7        |d:   d@      z  t8        kD  }|s|r.t1        | ||d2   |d:   3      \  }}t        d| dA|d dB         ;t        d| dC       L ||k7  rt;        |       t=        j>                  t
               # t        t        f$ r d}	Y w xY w# t         $ r}t        d| d|        Y d }~d }~ww xY wc c}w # t        t        f$ r	 d?\  }}Y 'w xY w# t         $ r}t        dD|        Y d }~d }~ww xY w)ENzLERRORE: WEBHOOK_SECRET non settata. Export WEBHOOK_SECRET prima di lanciare.rB   z=== SLTP ENGINE AVVIATO (loop zs, rettangolo+VPTR3) ===zno open positions, skipz open positionsrO   r   r   )buylongr   r   r   r   avgPriceGETz/v5/market/tickerslinear)categoryrO   F)signedresultlist	lastPricer   z: ticker fetch fallito: rn   60z
 strategy=z side=z size=z entry=z	 current=z PnL=r   r   r   r`   z	 [VPTR3] r   r   r   r   r   z [VPTR3] CLOSE FULL -> r   z [VPTR3] CLOSE PARTIAL 50% (z) -> r   r   r   z [VPTR3] SL -> z (r   z7 [RETTANGOLO] compute_sltp non ha prodotto valori, skipz [RETTANGOLO] sl=z tp=r   z
 trailing=r   stopLoss
takeProfitNNr   z [RETTANGOLO] SL/TP apply -> r   z" [RETTANGOLO] gia' allineato, skipzloop exception: ) r   r-   sysexitr   LOOP_INTERVAL_SECr5   dictfetch_positionsr   rr   ru   float	TypeError
ValueError_requestr'   rf   r   r   r   updatepopr   r   r   r   r   ALIGN_TOLERANCE_PCTr@   r   sleep)rN   r6   r   	positionsposrO   side_rawr   r   	avg_pricetickerr   r?   r^   r   tf_dictry   r   r   r   r   sltpcur_slcur_tpcur_sl_fcur_tp_f
sl_changed
tp_changeds                               r,   	main_loopr    s   Z[F
():(;;STU
Z	(LEUI..0I-.s9~&o67$ JQC ]F"wwvr2H$,NN$4$G5VD !3!8q9Dqy &$)#''*a*@*EA$F	 !A~ !!'8L@HTZ3[:? "1 "A ).fX.>v.Fq.I+.V(W
  7v>HALOAq{AhK7OGO VT2B-dI}MG"VHJxjtfF4&PWXaWbbklykzz  AH  IL  AL  MP  @Q  QR  S  T7*!7vtU^`mos!tb	&2B1CDE!+.%,,VK-@A#y0VH5E5U%MM&$7!(+|;':664QWXdQe'fHB"VH,CD6 JK#H-@':664QWXdQe'fHB"VH,HP\I]H^^cdhci jk#H-<'1&&6R\K]hl'mHB"VHOF:<N;OrRVW[X[R\Q]]^ _`  7vvtYXegij<"VH,c de$b(9$z:J9K4PTU_P`Oaaklpltlt  vG  mH  lI  J  K "%R!8!$r!:<8>uV}DH8>uV}DH &.%5  &NXZHX=X9Y\_`deo`prv\w9w  {N  :N
%-%5  &NXZHX=X9Y\_`deo`prv\w9w  {N  :N
%'1&&4PZK[fjkufv'wHB"VH,I$tPS* VW"VH,N OPUJQZ E!9% 	

$%y & &z2 &$%	& % !b(@DE !
 PP !*:6 <1;.Hh<  	("1#&''	(s   B#Q+ *P	Q+ /P#?Q+ Q&DQ+ <B%Q+ "Q B0Q+ P Q+ P  Q+ #	Q,Q=Q+ QQ+ Q($Q+ 'Q((Q+ +	R4RR__main__r   );__doc__r    r   r   r3   r   r   r   pathlibr   r"   insertr>   ro   r<   bybit_demo_clientr   rettangolo_strategyr   r   r	   r
   rettangolo_configr   environrr   r   r   r   r   r   RETTANGOLO_SL_HARD_PCTr   r   r   r   r   r   r   r   r1   r$   r-   r   r5   r@   rZ   rf   r   rc   r   r   r   r   r   r   r   r  __name__r   r[   r,   <module>r     sb  . 
 
    '  3tH~,,- . - _ _ ) jjnn],CD 0"5#    "'      "    XY
Q	D %d %t %
C C .4 DFZ;Nj,$*Q$c&L zK r[   