o
    j                     @   s   d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlm Z  ddl!Z!G dd dZ"dS )uG  
V12 — Bot Momentum Taker con Confirmación.

Ciclo por ventana de 5min o 15min:
  1. Descubrir mercado y obtener tokens + strike
  2. Conectar CLOB websocket para best_ask real de YES y NO
  3. Monitorear precio Binance cada segundo
  4. Cuando |price/strike - 1| > MOMENTUM_THRESHOLD durante CONFIRM_TICKS
     ticks consecutivos en la misma dirección → tomar posición al ask real
  5. Al final: esperar settle oficial, calcular PnL

Cambios vs V11:
  - Confirmación de momentum: filtra spikes transitorios ("chop")
  - Aggressive bump reducido: ask+0.01 en vez de ask+0.02
    N)datetime)Path   )ConfigCLOB_WSMOMENTUM_THRESHOLDCONFIRM_TICKSAGGRESSIVE_BUMPENTRY_SIZE_USDTAKER_FEE_RATEOUTCOME_MAX_WAITLOSS_STREAK_MAXLOSS_STREAK_COOLDAILY_LOSS_LIMITBLOCKED_HOURS_UTC
write_json)BinanceFeedCLOBFeed)Market)Logger)Executor)MomentumStrategyc                   @   s   e Zd ZdefddZdd Zdd Zdd	 Zd
d Zde	de
fddZde
fddZdefddZdd Zdd ZdedB fddZd)ddZdd Zd d! Zd"ededB fd#d$Zd%d& Zd'd( ZdS )*Botcfgc                 C   sh  || _ t | _| jjddi d| _t|| _t	|| _
t|| _t|j| _d | _d | _d | _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _g | _d| _d| _ |j!j"d | _#|j!j"d | _$d| _%t&' (d	| _)d| _*|j!d
 | _+|j,rdnd}t-d| d|j./  d|j0 d t-d|j1dd|j2 d|j3dd| j j4 dt5d
 d S )N
User-AgentMozilla/5.0F         r   zglobal_cooldown.jsonzglobal_trades.jsonl%Y-%m-%ddd_resetLIVEPAPERz![*] V12 Momentum Taker + Confirm z [z] minz    threshold: .4% | confirm: s | bump: +$.2f
 | size: $z | fee: z.0%)6r   requestsSessionsessionheadersupdate_stopr   loggerr   strategyr   executorr   
binance_wsbinanceclob_yesclob_nomarket_entered_entry_side_entry_price_entry_size_entry_cost_entry_move_entry_token_fill_verified_bal_before_windows_count_trades_count_trade_history_loss_streak_cooldown_leftlog_dirparent_global_cooldown_file_global_trades_file
_daily_pnlr   utcnowstrftime_daily_date_dd_stopped_dd_reset_fileliveprintassetupperwindowmomentum_thresholdconfirm_ticksaggressive_bumpentry_size_usdr   )selfr   live_tag rY   +/var/www/html/MetaHedge/POLYBOT1/v12/bot.py__init__&   sX   




zBot.__init__c                 C   sD   d| _ d| _d| _d| _d| _d| _d| _d| _d| _| j	
  d S )NFr   r   )r6   r7   r8   r9   r:   r;   r<   r=   r>   r/   resetrW   rY   rY   rZ   _reset_window_state]   s   zBot._reset_window_statec              
   C   sD  ddl }| jj}| sdS zyt|j}||}|D ]X}|d|jkr&q|ddv rsd| _|d | _	t
|d | _t
|d | _t
|d	d| _t
|d
d| _td|d  d|d  d|d  d  W d   W dS qW d   W dS 1 sw   Y  W dS  ty } ztd|  W Y d}~dS d}~ww )z9Restaurar entrada de trades.csv si existe para este slug.r   Nslugside)YESNOTpricesizecostmove_pctz  [RESTORED] entry  @ z x z sh (de CSV)z%  [warn] no se pudo restaurar entry: )csvr   
trades_csvexistsopen
DictReadergetr_   r6   r7   floatr8   r9   r:   r;   rO   	Exception)rW   mrh   pathfreaderrowerY   rY   rZ   _restore_entry_from_csvj   s:   



&zBot._restore_entry_from_csvc                 C   sX   t  d}|| jkr*| jdk rtd| j d| jdd || _d| _d| _d	S d	S )
z(Reset daily PnL counter at UTC midnight.r   r   z
  [DAILY RESET] z
 PnL was $+.2fz, resettingr   FN)r   rI   rJ   rK   rH   rO   rL   )rW   todayrY   rY   rZ   _check_daily_reset   s   



zBot._check_daily_resetc                 C   s^   | j sdS | j r-z| j  W n	 ty   Y nw d| _ d| _d| _d| _td dS dS )z/Check if dashboard sent a manual resume signal.NFr   r   z:
  [RESUMED] drawdown stop cleared manually from dashboard)	rL   rM   rj   unlinkOSErrorrH   rB   rC   rO   r]   rY   rY   rZ   _check_dd_resume   s   
zBot._check_dd_resumepnl_netwonc                 C   s   |rd| _ n|  j d7  _ | j tkr!t| _td| j  dt d |  j|7  _| jt krD| jsFd| _td| jdd	td
d dS dS dS )z7Update streak and daily drawdown after a trade settles.r   r   z
  [COOLDOWN] z losses in a row -> pausing z windowsTz
  [DD STOP] daily PnL $rw   z hit limit -$.0fz> -> STOPPED
  Resume from dashboard or wait until next UTC dayN)rB   r   r   rC   rO   rH   r   rL   )rW   r}   r~   rY   rY   rZ   _update_defense_after_settle   s   

z Bot._update_defense_after_settlec                 C   sx   z1t tt | jj|d}t| jd}||d  W d   W dS 1 s*w   Y  W dS  t	y;   Y dS w )z2Append trade result to shared global_trades.jsonl.)tsrP   r~   a
N)
jsondumpsinttimer   rP   rk   rG   writero   )rW   r~   entryrr   rY   rY   rZ   _log_global_trade   s   
&zBot._log_global_tradereturnc                 C   s   z7| j  s	W dS t| j  }|dd}t |k r.t|t  | jj	 d }|W S | j j
dd W dS  tyA   Y dS w )z_Check if global cooldown is active.
        Returns windows remaining, or 0 if not in cooldown.r   until_tsr   T)
missing_ok)rF   rj   r   loads	read_textrm   r   r   r   win_secsrz   ro   )rW   datar   	remainingrY   rY   rZ   _check_global_cooldown   s   
zBot._check_global_cooldownc              
   C   s   t | jj }tt | }z#t|| jjtt d}| j	| t
dt  d| d W dS  tyK } zt
d|  W Y d}~dS d}~ww )z6Activate global cooldown for LOSS_STREAK_COOL windows.)r   triggered_bytriggered_atzM
  [GLOBAL COOLDOWN] 3 consecutive losses across all bots -> pausing ALL for z
 windows (zs)z!  [GLOBAL COOLDOWN] write error: N)r   r   r   r   r   r   r   rP   rF   
write_textrO   ro   )rW   cooldown_secsr   r   ru   rY   rY   rZ   _trigger_global_cooldown   s$   
zBot._trigger_global_cooldownc              	   C   s   zU| j  s	W dS | j   d}t|dkr|dd n|}d}t|D ] }zt|}|	ds9|d7 }nW  nW q' t
yG   Y  nw |tkrS|   W dS W dS  t
y_   Y dS w )zCRead last N trades from global file and trigger cooldown if needed.Nr   
   ir   r~   r   )rG   rj   r   stripsplitlenreversedr   r   rm   ro   r   r   )rW   linesrecentstreakliner   rY   rY   rZ   _check_global_streak   s,   



zBot._check_global_streakNc                 C   sJ   | j rdS | jdkrdS |  }|dkrdS tr#t j}|tv r#dS dS )z:Return reason to skip this window, or None if OK to trade.
DD_STOPPEDr   COOLDOWNGLOBAL_COOLDOWNBLOCKED_HOURN)rL   rC   r   r   r   rI   hour)rW   gchour_utcrY   rY   rZ   _should_skip_window   s   

zBot._should_skip_windowc                 C   s  | j jdd}|  }|r| }n| jrd}n|dkrd}n
| jdkr'd}nd}t| jjt	t

 |r7|jnd|r=|jnd|rC|jnd|rRtd|jt	t

  nd|rX|jnd| jjd| jjd	 d
|| j| jt|d| j| j|trzt jtv nd
t| jd| j| jdd dS )z>Write state.json with defense info (for dashboard visibility).T	use_cache
dd_stoppedr   global_cooldowncooldownidler   d   F   loss_streakcooldown_leftglobal_cooldown_leftblocked_hour	daily_pnlr   
daily_date)r   r_   start_tsend_tst_leftstrikerc   rf   	thresholdenteredphasewindowstrades_totalbalancedefenseN)r0   get_balancer   lowerrL   rC   r   r   
state_jsonr   r   r_   r   r   maxr   r2   last_pxrS   r?   r@   roundrB   r   r   rI   r   rH   rK   )rW   rp   skip_reasonbalgc_leftr   rY   rY   rZ   _write_defense_state  sF   




zBot._write_defense_statec           #      C   s  | j }|sd S | jj}|dkrd S td|jtt  }|jr(||j |j nd}| jr1| jj	nd}| j
r:| j
j	nd}| jj||j||j|j||| jd}|rtd|j d|jdd|dd|jdd	|jd
d|j d | j|j|j|jd|j \}}	}
}|rd| _|j| _|
| _|j| _t|
|j d| _|j| _|j| _|  j d7  _ | j!j"rtt }| j# }d}t$dD ]}t%|dkrdnd | jj&| j'|j|d}|r?|d dkr?| j}| j}|d |jd kr|d | _|d dkr|d | _t| j| j d| _t(|)dg }td|j d|d  d| jd
d| jdd|dd|dd | d! d} ntd"|d  d# q|| _*|s| j+|	 |  j d8  _ | j# }|| }td$|j d%| d& td' td(|dd)|dd*|dd+ t,|d,krtd-|d
d. | j*s| j!j"s| j-.|j/|j| j| j| j|jd/ddd
 n	 d/}| jrd0| j d1| jd
}d/}|dks|dkrd2|d
d3|d
}| j!j0}| j!j1}||  ko|kn  }|r| jsd4nd/}| jrd5}n||krd6}n||k rd7}d/}| js?|r?| jj}| j!j2}| jj3}|dkr?d8| d9| |r;|d nd/ }| j!j"rFd/nd:} t45 6d;}!td<|! d=|d>d?|d@d|dAdB| | | | |  dCdD tt dE dkr| jj#ddF}"t7| j!j8i dGtt dH|j/dI|j9dJ|jdK|dL|jdM|dNt|dO ddP| j!j:dO dQ|dR|dS| jdT| jdU| jdV| jdW|; dX| j<| j t|"d| jj| j!j2| jj3dY| j=| j>| ? t@rt4A jBt@v ndt| jCd| jD| jEdZd[ d S d S )\Nr   )rc   r   r   	token_yestoken_nobest_ask_yesbest_ask_noalready_enteredz
  [SIGNAL]  | move=+.4fz% | price=$,.2fz vs strike=$z | ask=r&   z | confirmed=tzMOM Tr   r   F      )order_tsrd   g      ?	avg_price	tx_hashesz  [FILL VERIFIED] z
 (attempt z): sh @ .4fz (was z.1fz) [z tx confirmed]z  [verify retry z/5] no confirmed fill yet...z  [PHANTOM] u    — CLOB dijo 'z7' pero NO hay fill confirmado on-chain tras 5 intentos.z5  [PHANTOM] Orden cancelada. Trade NO contado en PnL.z  [PHANTOM] Balance delta: $z
 (before=$z	, after=$)      ?z   [!! WARNING] Balance dropped $u1    without confirmed fill — investigate manually!r   z | POS=rg   z | aY=z aN=SCANNINGHOLDINGWARMUPCUTOFFz | cfm=/z [PAPER]z%H:%M:%S[z] t-3dzs | $z,.0fz+.4%z | )end   r   r   r_   r   r   r   r   rc   rf   r   r   ask_yesask_nor   
entry_sideentry_price
entry_sizer   r   )countneededr`   r   )r   r   confirmr   )Fr5   r2   r   r   r   r   r   r   r3   best_askr4   r/   check_signalr   r   r6   rO   r`   rf   rc   confirm_countr0   place_taker_ordertoken_idrd   r7   r8   r9   r   r:   r;   r<   r@   r   rN   r   rangesleepverify_fillr*   r   rm   r=   cancel_orderabsr.   	log_trader_   signal_start_tleftsignal_stop_tleftrT   confirm_sider   nowrJ   r   r   r   rS   r   r?   rB   rC   r   r   rI   r   rH   rL   rK   )#rW   rp   rc   r   mover   r   sigokoid
fill_pricefill_statusr   
bal_beforeverifiedattemptposold_pold_ntx_count	bal_after	bal_delta	entry_tagask_tagsssesignal_zonezone_tagconfirm_tagccctcspapernow_strr   rY   rY   rZ   tick8  s  














"
	

zBot.tickc                 C   s  | j jr	| j  | jj}| jrtnd}td|j	 d| d| jr"dnd d | 
||}|sQtd|j	 d	t d
 | j||d| j| j| j| jddd
 dS | jsm| j|||ddddddd
 td| d dS | j jr| jstd|j	 d|  td| j d | j|||| j| j| j| jddd
 dS | j}| j}| j}|dkr|dkp|dko|dk}| j jr|rtd| | d}	nt| | d}	t|d|  | t d}
t|	|
 d}|rdnd}td|j	 d|  td| d|dd|d d!| jd"d#	 td$|d%d&| d'|	d%d(|
d d)	 nc|r+td| | d}	nt| | d}	t|d|  | t d}
t|	|
 d}|rLdnd}td|j	 d|  td| d|d*d|dd!| jd"d+	 td,|	d%d-|
d d.|d%d&|  | j|j	|||| j| j||	|
|
 | j||||||| j|	|
|
 | jtt |j	||||d/ | || | j jr| | |   | j jr| j }td0|d  dS dS )1z.Settle: esperar outcome oficial, calcular PnL.<   z

[settle] u$    — esperando outcome oficial (max zs, consinz posicion)...z  [!! OUTCOME DESCONOCIDO] u    — Polymarket no resolvio en sUNKNOWNr   Nr   z  [settle] u    — sin posicionz -> z  [PHANTOM SETTLE] u.    was NOT verified — skipping PnL calculationra   Uprb   Downr   r   WINLOSSz  z: r&   r   r   r   rw   z% [VERIFIED]z  PnL: $r    z
 (gross: $z, fee: $r   r   %z  PnL gross: $z	 | fee: $z	 | net: $)r   r_   r`   outcomer}   r~   z  [balance] $)r   rN   r0   
cancel_allr2   r   r6   r   rO   r_   _fetch_outcomer.   
log_windowr7   r8   r9   r;   r=   r   r   r   r:   rA   appendr   r   r   r   r   r   )rW   rp   price_finalwaitr)  npr`   r~   	pnl_grossfeer}   tagr   rY   rY   rZ   _settle_window  s   












zBot._settle_windowmax_waitc                 C   s   t   | }d}t   |k rP|d7 }|| j}|r'td| d| d |S |t    }|dkr4	 d S t   ||  dk r@dnd}t t|| t   |k sd S )	Nr   r   z  [OK outcome] z
 (intento r      r   r   )r   fetch_outcomer*   rO   r   r"   )rW   rp   r6  deadliner
  r)  r   r/  rY   rY   rZ   r+  l  s    zBot._fetch_outcomec              
      sR  t  t j fdd t  t j fdd tj jjddd  td  j	s= jj
dkr=td	  j	s= jj
dks/ jj} jjrGd
nd}td| d| d jj d td jjdd jj d jjdd jj d	 d} j	s'ztt }|||  }|| }|| dk r||7 }td|| d }td| d t|  j  t  _ jjddi t| j}| j jj
s|d7 }tdd| }	td| d|	 d t|	 W qvd}  j d7  _  !   "   #   $ }
|
d kr2  j%d8  _%|tt  }td! j% d"  j&|d#d$ ttd| W qv|
d%kr\|tt  } ' }td&| d'  j&|d(d$ ttd| W qv|
d)kr|tt  }td*t() j*d+d,  j&|d-d$ ttd| W qv|
d.kr|tt  }td/ j+d0d1  j	stt |k rʈ #   j,sn &| td  j	stt |k s j,rW qv -|  j.rވ j./   j0r j0/  t1|j2t3 _.t1|j4t3 _0tj j.jdd2  tj j0jdd2  td3 d4d5  j5D }t6d6d7 |D }t6d8d7 |D } j.j7} j0j7}d9} j8dkrB|d: j8 7 } j+dkrQ|d; j+d07 }td<d=  td>|j9  td?|j:d@dA|j; dB tdC| dD tdE jjdd jj d jjd tdF|ddG|d tdH j  dI j< |  |rt=|}tdJ|dKdL| dM| dA|| dN dOdP	 td=  | _> j	stt |j?k r @  td  j	stt |j?k sو j	s A| W n' tBy! } zdd lC}tdQ|  |D  tdR W Y d }~nd }~ww  j	rzd S d S )SNc                           S Nshutdown_r]   rY   rZ   <lambda>      zBot.run.<locals>.<lambda>c                     r:  r;  r<  r>  r]   rY   rZ   r@    rA  Tr2   )targetdaemonnamez&-> esperando primer tick de Binance...r   g?r    r!   z	-> modo: z | ventana: zs (zmin)z-> threshold: r#   r$   r%   r&   r'   z/trader7  r   z
-> proxima ventana en zs...r   r   r   z([!] No se pudo cargar la ventana (fail #z), retry en r   z
  [COOLDOWN] skipping window (z more after this)r   )r   r   u=   
  [GLOBAL COOLDOWN] 3+ losses across all bots — skipping (z windows left)r   r   z
  [BLOCKED HOUR] 02du!   :00 UTC — low WR hour, skippingr   r   z
  [DD STOPPED] daily PnL $rw   u'    — waiting for resume or UTC midnight)rB  rC  r   c                 S      g | ]}| d dvr|qS r)  )r"  Nrm   .0r   rY   rY   rZ   
<listcomp>      zBot.run.<locals>.<listcomp>c                 s       | ]	}|d  rdV  qdS r~   r   NrY   rI  rY   rY   rZ   	<genexpr>      zBot.run.<locals>.<genexpr>c                 s       | ]}|d  V  qdS r}   NrY   rI  rY   rY   rZ   rO        r   z
 | streak=z | day=$r   zH========================================================================z  Ventana    : z  Strike     : $r    (r   z  Modo       : z | V12 MOMENTUM TAKER + CONFIRMz  Threshold  : z  CLOB asks  : YES=z NO=z  Stats      : windows=z trades=z  PnL acum.  : $r   z | WR=r   r   r   %)z
[!! ERROR] r   )EsignalSIGINTSIGTERM	threadingThreadr2   runstartrO   r-   r   r   r   r   r   rN   rR   rS   rT   rU   rV   r   r   r*   closer(   r)   r+   r,   r   
fetch_datar"   r?   r^   ry   r|   r   rC   r   r   r   rI   r   rH   rL   rv   r3   stopr4   r   r   r   r   rA   sumr   rB   r_   r   strike_sourcer@   r   r5   r   r  r5  ro   	traceback	print_exc)rW   wsrX   _consecutive_failsr  r   r   r/  rp   delayskipr   r   knownwinspnlask_yask_n
def_statusnkru   rb  rY   r]   rZ   r[  ~  s>  

 























 zBot.runc                 C   s  | j rd S d| _ td | jjr| j  | j  | jr"| j  | j	r*| j	  dd | j
D }|rtdd |D }t|}ttdd |D d}td	d
  td td| j  td| j  |r}td| d| d|| d dd td|d td
  d S d S )NTz
-> shutdown...c                 S   rF  rG  rH  rI  rY   rY   rZ   rK  ,  rL  z Bot.shutdown.<locals>.<listcomp>c                 s   rM  rN  rY   rI  rY   rY   rZ   rO  /  rP  zBot.shutdown.<locals>.<genexpr>c                 s   rQ  rR  rY   rI  rY   rY   rZ   rO  1  rS  r   r   z2==================================================z&  RESUMEN V12 MOMENTUM TAKER + CONFIRMz  Ventanas   : z  Trades     : z  Win rate   : r   rT  r   r   rU  z  PnL total  : $r   )r-   rO   r   rN   r0   r*  r2   r_  r3   r4   rA   r`  r   r   r?   r@   )rW   rh  ri  rn  rj  rY   rY   rZ   r=    s2   



&zBot.shutdown)NN)__name__
__module____qualname__r   r[   r^   rv   ry   r|   rn   boolr   r   r   r   r   r   strr   r   r  r5  r+  r[  r=  rY   rY   rY   rZ   r   %   s(    7
, Li "r   )#__doc__r   rV  rY  r   r   pathlibr   configr   r   r   r   r	   r
   r   r   r   r   r   r   r   feedsr   r   r5   r   r.   r   r0   r   r/   r   r(   r   rY   rY   rY   rZ   <module>   s     <	