o
    ]i^                  
   @   s  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	 d dl
Z
d dlZd dlZd dlZd dlmZ e  dZdZdZdZd	Zd
Zd8ddZe Zedee  zd dlZeje de de dddZW n e y   ed e!d Y nw dd Z"dd Z#dd Z$dd Z%dd Z&dd  Z'd!d" Z(d#d$ Z)d%d& Z*d8d'd(Z+d)d* Z,d+d, Z-d-d. Z.d/d0 Z/d1d2 Z0d3d4 Z1e2d5krze1  W dS  e3y   ed6 Y dS  e4y Z5 zed7e5  W Y dZ5[5dS dZ5[5ww dS )9    N)load_dotenv)datetime	timedelta)Pathz#/var/www/html/flask_project/chains/      x   z09:29:00z16:02:00c                 C   s   | du rt  j}||d g} td}t }| D ]6}| d}| d}|j||d}tdd |D }tj||d	}	|	D ]}
|
	 |vrN|
|
d
 q>q|S )u   
    Retorna un set de fechas feriadas del NYSE en formato MM/DD/YYYY.
    Por defecto cubre el año actual y el siguiente.
    Se actualiza automáticamente con la librería pandas_market_calendars.
    N   NYSEz-01-01z-12-31)
start_dateend_datec                 s   s    | ]}|  V  qd S N)date).0d r   0/var/www/html/process/gettingChains_outliers4.py	<genexpr>0   s    z$get_nyse_holidays.<locals>.<genexpr>)startend%m/%d/%Y)r   nowyearmcalget_calendarset
valid_dayspdbdate_ranger   addstrftime)yearscurrent_yearnyseholidaysr   r   r   r   valid_dates	all_bdaysdayr   r   r   get_nyse_holidays   s"   



r(   z[INFO] Feriados NYSE cargados: appKey	appSecretcallbackUrlT)verbosez'Error: No se pudo importar 'schwabdev'.r	   c                 C   s   t tD ]?}ztj| |||d}| W   S  tjtjfyC } ztd|d  dt d|  d|  t	
t W Y d}~qd}~ww td|  d	t d
 td|  )zJ
    Obtiene la cadena de opciones del cliente Schwab con reintentos.
    )fromDatetoDatestrikeCountz[WARN] Intento r	   /z fallido para : Nz*[ERROR] No se pudo obtener la cadena para z tras z
 intentos.z(Fallo definitivo al obtener cadena para )rangeMAX_RETRIESclientoption_chainsjsonJSONDecodeErrorrequestsRequestExceptionprinttimesleepRETRY_DELAY_SECONDSRuntimeError)symbol	from_dateto_datetotal_strikesintentoresponseer   r   r   obtener_cadena_con_reintentoP   s   $rF   c                 C   sz  i }t tdd}| dd}|rtt|dnd}dD ]}|| v r| |  D ]\}}| D ]\}}|D ]y}	|	dd}
|
dur|
|vr^|||
ddddddddddddd	||
< |d
kr||
 	|	dd|	dd|	dd|	dd|	dd|	ddd q:|dkr||
 	|	dd|	dd|	dd|	dd|	dd|	ddd q:q4q,q t
| S )zn
    Extrae los datos relevantes de la cadena de opciones,
    incluyendo Open Interest, Gamma y Volumen.
    zAmerica/New_York%Y-%m-%d %H:%M:%SunderlyingPrice r   N)callExpDateMapputExpDateMapstrikePrice)	timestampunderlying_pricestrikebid_callask_call
delta_call
gamma_callopen_interest_callvolume_callbid_putask_put	delta_put	gamma_putopen_interest_put
volume_putrJ   bidaskdeltagammaopenInteresttotalVolume)rP   rQ   rR   rS   rT   rU   rK   )rV   rW   rX   rY   rZ   r[   )r   r   pytztimezoner    getroundfloatitemsupdatelistvalues)option_dataextracted_datarM   rN   option_typedate_keystrikesrO   detailsdetailstrike_pricer   r   r   extract_datab   sf   













)rs   c                 C   s   d}| D ]<}| ddpd}| ddpd}| ddpd}| ddp%d}|| ||  d }|s4|r6|nd|d< ||d 7 }q|| fS )u   
    Calcula el Gamma Exposure (GEX) por cada strike.
    Devuelve también el valor total de GEX (versión simplificada).
    r   rS   rY   rT   rZ   d   gex_per_strikerd   )data	total_gexrowrS   rY   rT   rZ   gexr   r   r   calculate_gex   s   r{   c                 C   s   d}d}d}| D ]@}| ddpd}| ddpd}| ddp!d}| ddp)d}	|| ||	  | | | }
|s<|r>|
nd|d< ||d 7 }q|| fS )	zM
    Calcula el Gamma Exposure (GEX) preciso por cada strike y el total.
    r   rt   g{Gz?rS   rY   rT   rZ   gex_preciserv   )rw   rN   rx   
multiplierpercent_movery   rS   rY   oi_calloi_putrz   r   r   r   calculate_gex_precise   s&   r   c              
   C   s  t | dd }|dv r| rg d}}| D ]X}z|ddur*t|dnd}W n ty8   d}Y nw z|ddurHt|dnd}W n tyV   d}Y nw |dur_|dk sg|durl|dk rl|d	7 }q|| q|rtd
| d| d |} | std
| d dS t	
 d}td| d| d }	td| d| d }
g d}tj|	}t| \}} | D ]}||d< q| r| d ddnd}t| |\}} | D ]}||d< qzt|	ddd }tj||d}|s|  t|	d ||  W d   n	1 sw   Y  t| }tj|d dd|d< tj|d dd|d< tj|d dd|d< g d}|D ]}tj|| dd||< q<tj|
r`t|
}tj||gd d!}|j|
d"d#d$ W dS  ty } ztd%| d&|  W Y d}~dS d}~ww )'z
    Guarda la cadena de opciones procesada en CSV y Parquet,
    incluyendo GEX simple y preciso.
    Filtra SOLO en SPY/QQQ las filas con delta_put < -1000 o gamma_put < -1000.
    $rI   >   QQQSPYr   rX   NrY   ir	   [z] z1 filas descartadas (delta_put/gamma_put < -1000).u-   ] Snapshot vacío tras filtrar; no se guarda.%Y-%m-%doptionChain__.csvz.parquet)rM   rN   rO   rP   rQ   rV   rW   rR   rX   rS   rT   rU   rY   rZ   r[   ru   	gex_totalr|   gex_total_preciser   rN   r   a)modenewline)
fieldnamesi  rM   coerce)errorsrO   )rP   rQ   rV   rW   rR   rX   rS   rT   rU   rY   rZ   r[   ru   r   r|   r   Tignore_indexFzstd)indexcompressionu(   ❌ Error al guardar CSV o PARQUET para r1   ) strupperreplacestriprd   rf   	Exceptionappendr:   r   r   r    PATH_UBUNTUospathisfiler{   r   opencsv
DictWriterwriteheaderchmod	writerowsr   	DataFrameto_datetime
to_numericexistsread_parquetconcat
to_parquet)rw   r?   symfiltereddroppedrdpgpfecha_actualfilename_csvfilename_parquetheaderfile_existsrx   ry   rN   total_gex_precisefilewriterdf
float_colscoldf_oldrE   r   r   r   save_chain_to_cvs   sv   
$$ 




"r   c                 C   s<   t  d}| dddd |  D  }t| d S )N%H:%M:%Sz | c                 S   s    g | ]\}}| d |dqS )r1   z.3fr   )r   simboloprecior   r   r   
<listcomp>)  s     z-mostrar_precio_en_consola.<locals>.<listcomp>)r   r   r    joinrg   r:   )precios_por_simbolohora_actualsalidar   r   r   mostrar_precio_en_consola&  s
   r   c           	      C   s   t  d}| }}i }| D ]8}zt|||t}t|}|d d ||< t|| W q tyG } ztd| d|  W Y d }~qd }~ww t	| d S )Nr   r   rN   z
Error al procesar r1   )
r   r   r    rF   TOTAL_STRIKESrs   r   r   r:   r   )	symbolsr   r@   rA   r   r?   cadena_opcionesdatos_procesadosrE   r   r   r   procesar_simbolos.  s    r   c                 C   s4   t dt| }|r|d|d|dfS dS )Nz(\d{2,5})/(\d{2,5}) (PUT|CALL)r	      r   )rI   rI   rI   researchr   group)idea_strmatchr   r   r   extract_vertical_strikesA  s   r   c                 C   s<   t dt| }|r|d|d|d|dfS dS )Nz=\[CALLS (\d{2,5})/(\d{2,5})\] \+ \[PUTS (\d{2,5})/(\d{2,5})\]r	   r   r      )rI   rI   rI   rI   r   )textr   r   r   r   #extract_condor_strikes_from_verboseH  s   $r   c                  C   s  t | }t |}|jddd g }t|dD ]}t|}	t|	d |	d< |	d jd|	d< |	d jd|	d< |	d jd	|	d
< ||	d< d|	d< |r]|	|	d |k }	|	j	r]q|dkr|	d |	d< |	d 
tjjdddd}
|	|
  }	|	d dd |	g d< d|	d< |	g d }n|dkrg }|	 D ]\}}d }dD ]l\}}t||d}t|}t|r|dkr|}nNtt|d | tt|d | tt|d | tt|d | f}td|d  d |d  d!| d"| d#|d  d$|d  d%|d  d$|d    nq|d u r(td|d  d |d  d& qdd'lm} ||d dd(}d)|d  d | d*|d  d$|d  d+|d  d$|d  d,}||d |d |d d|d ||d |d |d |d |d- |d. |d
 d/ qt|}n
td0|   d S |j	s|| q|std1| d2| d3 d S tj|dd4}tjd5d6d7d8d	 }|D ]}||d
 |k }|j	sA| d9|d d d:| d;}t || }|jd
gd<}|r-| r-t|}||d j v rtd=| d>| d? qtj||gdd4}|j!|dd@ tdA| d"t"| dB q|j!|dd@ tdC| dDt"| dE qd S )FNT)parentsexist_okzprediction_*.csvrM   r   Dayz%H:%MHourz%H%MHourFileSymbolrI   RawVerticalIDEATradez\d{2,5}/\d{2,5} (?:PUT|CALL)F)regexnac                 S   s   t t| S r   )r   Seriesr   )xr   r   r   <lambda>k  s    z-procesar_por_horario_global.<locals>.<lambda>)Strike1Strike2Option_TypeName)r   r   r   r   r   r   r   r   r   score_30minmovimiento_esperador   Iron Condor))IDEA_ICr   )IDEA_IC_adj5   )IDEA_IC_adj10
   )IDEA_IC_adj15   r   r	   r   r   z[ADDPROFITS]  u$    — Conservador reconstruido desde z (+zpt): CALLS r0   z + PUTS u,    — Sin strikes en ningún nivel, se omite.)r   z%d %b %yzSELL -1 IRON CONDOR z [CALLS z
] + [PUTS z
] @0.0 LMTr   r   )r   r   r   r   r   r   Call_Strike1Call_Strike2Put_Strike1Put_Strike2r   r   r   z"[ERROR] Estrategia no reconocida: u-   [INFO] No se encontraron datos válidos para z - .r   z10:05z15:305min)freqr   	_strikes_r   )columnsz[INFO] Fecha z ya existe en z, no se agrega.)r   zActualizado: z filas nuevas)z
Guardado: z (z filas))#r   mkdirsortedglobr   read_csvr   dtr    emptyastyper   containscopyapplyiterrowsrd   r   allintrf   r:   r   strptimer   r   r   
date_rangetolistr   dropr   rj   to_csvlen) input_folderoutput_foldersymbol_value
name_valuefecha_filtro
input_pathoutput_pathall_datar   r   vertical_maskfinal_dfcondor_rowsr   ry   ro   r   despvalparsedr   	fecha_fmt	trade_strfull_dfhorarios_validoshr   filenamefilepathnew_dataexisting_dfcombined_dfr   r   r   procesar_por_horario_globalO  s   


P
>


r,  c              	   C   s   g d}ddg}t dd  t d|   t d  |D ])}d| }d| }t d	| d
 |D ]}t d|  t||||| d q3qt d dS )u   
    Se ejecuta automáticamente al cierre de cada jornada.
    Recibe la fecha del día que cerró para usarla como filtro exacto.
    )SPXr   r   RUTXSPr   r   
z2==================================================z6[ADDPROFITS] Iniciando procesamiento post-cierre para z4/var/www/html/backtestingmarket/predictor_data/data/z7/var/www/html/backtestingmarket/predictor_data/makekos/z
=== Procesando z ===z> Estrategia: )r  z'
[ADDPROFITS] Procesamiento completado.N)r:   r,  )	fecha_hoyr   estrategiasr  r  r  r  r   r   r   ejecutar_addprofits  s$   


r3  c           	      C   s   	 t  }|| kr
nG| | }t| }|dkrd}n	|dkr"d}nd}t|d\}}t|d\}}td|dd	|dd	|dd
| d d	dd t| qt  dS )z
    Espera activa con logs espaciados para no inundar el log.
    > 10 min: log cada 60s | 10 min - 60s: log cada 10s | < 60s: log cada 1s
    TiX  <   r   r	   i  u#   ⏳ Esperando próxima apertura en 02d:z  (destino: rG   ))r   N)	r   r   r  total_secondsdivmodr:   r    r;   r<   )	
destino_dtahoraresto	total_segstepr&  remmsr   r   r   esperar_hasta  s,   

rC  c                 C   s   |   dv rdS | d|vS )N)r      Fr   )weekdayr    )fechar$   r   r   r   es_habil  s   rG  c                 C   s*   | }t ||s|tdd7 }t ||r|S )Nr	   days)rG  r   )rF  r$   r   r   r   r   proximo_habil  s
   

rJ  c                 C   s   |   }t||st||}dt||t||fS t||}t||}| |k r0d||fS | |k r9d||fS t|tdd |}dt||t||fS )un  
    Devuelve (estado, apertura, cierre) donde estado ∈ {"esperar", "en_mercado"}.
    - Si hoy no es hábil              => esperar próxima apertura hábil.
    - Si ahora < apertura_hoy         => esperar apertura_hoy.
    - Si apertura_hoy <= ahora < cierre_hoy => en_mercado.
    - Si ahora >= cierre_hoy          => esperar apertura del próximo hábil.
    esperar
en_mercador	   rH  )r   rG  rJ  r   combiner   )r   hora_market_openhora_market_closer$   hoyr   apertura_hoy
cierre_hoyr   r   r   limites_sesion  s   



rS  c            	   
   C   s.  t d ttd } ttd }	 t }t|| |t\}}}|dkr:t d|	d  t
| t d qt 	d}t d	 t d
| d z?g d}t |k rzt| W n tyw } zt d|  W Y d}~nd}~ww td t |k sXW t d t| n	t d t| w q)uV  
    Daemon que NO termina:
    - Espera hasta apertura del próximo día hábil NYSE si el mercado está cerrado.
    - Procesa cadenas de opciones cada 10s mientras el mercado está abierto.
    - Al cierre de cada jornada dispara ejecutar_addprofits() con la fecha exacta.
    - Vuelve a esperar la próxima apertura automáticamente.
    z=Daemon iniciado. Controlando aperturas/cierres del mercado...r   TrK  u)   🔒 Mercado cerrado. Próxima apertura: rG   u,   🔓 Mercado abrió. Comenzando streaming...r   z0***** Mercado abierto. Iniciando streaming *****z***** Fecha de procesamiento: z *****)z$RUTz$XSPr   r   z$SPXz'
Error inesperado en ciclo de mercado: Nr   z.
***** Mercado cerrado (fin de jornada). *****)r:   r   r  	TIME_OPENr;   
TIME_CLOSEr   rS  HOLIDAYSr    rC  r   r   r<   r3  )	rN  rO  r<  estadoaperturacierrefecha_sesionr   rE   r   r   r   main(  s>   


r[  __main__u(   
Ejecución interrumpida por el usuario.u   Error crítico: r   )6r   sysr;   r6   rb   r   dotenvr   r   r   r8   r   pandasr   pandas_market_calendarsr   pathlibr   r   r3   r=   r   rT  rU  r(   rV  r:   r  	schwabdevClientgetenvr4   ImportErrorexitrF   rs   r{   r   r   r   r   r   r   r,  r3  rC  rG  rJ  rS  r[  __name__KeyboardInterruptr   rE   r   r   r   r   <module>   sz    

9_
u0