o
    wiM                     @  s  d dl mZ d dlmZmZmZ d dlmZ d dlmZm	Z	m
Z
 d dlZd dlmZmZ d dlZd dlmZmZ edZd	Zh d
Z			dOdPdd ZdQd%d&ZdRd(d)ZdSd+d,ZdTd0d1ZdUd4d5ZdVd6d7ZdWd;d<ZdXd?d@ZdYdCdDZ dZdEdFZ!d[dHdIZ"d\dJdKZ#d]dMdNZ$dS )^    )annotations)datetime	timedeltadate)Path)ListDictOptionalN)ThreadPoolExecutoras_completed)requestjsonifyz"/var/www/html/flask_project/chainsz-optionChain_{symbol}_{yyyy}-{mm}-{dd}.parquet>   RUTSPXXSPF   dr   chain_symbolstr
entry_timestrategytarget_delta_absfloatwidth	contractsintslippageTPSLreturn_intradayboolfull_day_path	confirm_nc           <      C  s  t || }|sd|  iS t|}dD ]}tj|| dd||< q|d dk|d dk@ }|d dk|d	 dk@ }|d |d  d
 |dd|d< |d |d	  d
 |dd|d< tj|d dd|d< |jdgd}|d 	t
|d< t||}|du st|dkr|  ddS t||}|d |d }}t||d |d}t||d |d}||||d}t|||||}t|d |}t|d jd }d}d|jv rzt
|d jd }W n ty   d}Y nw |ddg }|jd }|||k }g }d} d}!d}"|}#t
|d }$d}%d}&t
|pd}t
|	p&d}	t|p-d}|dk r6d}d}'d|jv rWz|ddd }'W n tyV   d}'Y nw d}(|j|d d dd})|j|d d dd}*|j|d d dd}+|j|d d dd},|)d }-|*d }.|+d }/|,d }0|D ]}1z|-|1d|.|1d |/|1d |0|1d d  | }2W n ty   d}2Y nw t
|d! |2 }3|3}(d}4|'dur|'|1}5|5durt
|5nd}4|
s|r|t|1t |2d"t |3d"|4d# |2}$|1}#|r| dkrq|dkr|3|kr|%d7 }%nd}%|	dkr.|3|	 kr,|&d7 }&nd}&| dkr_|dkrJ|%|krJd$} |1}!|3}"|sH nq|	dkr_|&|kr_d%} |1}!|3}"|s_ nqd}6|'durt|'rz	t
|'jd& }6W n ty   d}6Y nw |"durt
|"}7|7}8n|6durt!||6|}$t
|d! |$ }7|7}8nt
|(}7|7}8|!dur|!n|#}9| d$krt
|}:n| d%krt
|	 }:nt
|7}:|  t||||t|t
|d'dt
|ddt
|d(dt
|d!dd)| t|9|9"d*t t
|:d"|6durt t
|6d"nd|!rt|!nd|!r"|!"d*ndt|#|#"d*t t
|$d"t t
|7d"t t
|8d"t
|t
|	t|d+|7dkrNd,n|7dk rUd-nd.|7dkt t
|7d"d/d0};|
rk||;d1< |;S )2ut  
    Ejecuta un solo día para Iron Condor / Iron Butterfly.

    Reglas:
    - confirm_n = cantidad de snapshots CONSECUTIVOS sobrepasando TP o SL para confirmar salida.
      * TP se confirma si pnl >= TP por confirm_n snapshots seguidos
      * SL se confirma si pnl <= -SL por confirm_n snapshots seguidos
      * si pnl vuelve a estar dentro del rango (no cumple), se resetea hits.

    - full_day_path = si True, siempre recorre hasta fin del día (EOD) y devuelve path completo,
      aunque el trade haya "salido" antes (trade_timestamp).

    - return_intraday = si True, incluye pnl_path (y underlying si existe).
    _missing)bid_callask_callbid_putask_putcoerceerrorsr$   r   r%   r&   r'         ?        call_midput_mid	timestamp)subsetstrikeNno_entry_snapshot)r#   _reason	call_sellput_sellcallput)r4   call_buyr5   put_buycredit_grossunderlying_priceEOD   )levelr8   r9   d   
credit_net   )tscredit_now_grosspnl
underlyingr   r   credit_pointsr   )r/   rG   r:   r   r@   z%H:%M)reasonr/   	time_hhmm	final_pnlunderlying_close_usedtrade_timestamptrade_time_hhmmpath_timestamppath_time_hhmmfinal_credit_now_grossfinal_pnl_tradefinal_pnl_eodtpslr"   WINLOSSFLAT)labelis_positiverD   )r   filer   underlying_entrylegsentryexitresultpnl_path)#find_parquet_for_day	isoformatpdread_parquet
to_numericwherefillnato_datetimedropnaastyper   find_snapshot_by_timelenfind_sell_strikes_by_deltapick_wing_strikecalc_ic_credit_grosscalc_entry_credit_netiloccolumns	Exception	set_index
sort_indexindexget_level_valuesuniquer   drop_duplicatesxsgetKeyErrorappendr   roundic_settlement_debit_grossstrftime)<r   r   r   r   r   r   r   r   r   r   r   r!   r"   pdfccall_okput_ok
snap_entrysellsr4   r5   r8   r9   r\   entry_gross	entry_netentry_tsr[   df_idxts_allr`   exit_reasonexit_ts_tradepnl_trade_exitexit_ts_pathfinal_credit_nowtp_hitssl_hitsu_maplast_pnlcs_rowsps_rowscb_rowspb_rowscs_midps_midcb_midpb_midrB   
credit_nowrD   underlying_nowvunderlying_closerQ   pnl_eodexit_ts_legacyfinal_pnl_legacyout r   0/var/www/html/neutralSigma/backtesting/engine.py_run_single_day   sp  
!
&&






















/r   r\   dictr   returnc                 C  s   t | d d }t | d d }t | d d }t | d d }||k r(||fn||f\}}||k r6||fn||f\}	}
td|| td||  }td|
| td|	|  }|| }t |d t| S )u[   
    Débito de cierre por liquidación (intrínseco),
    NO usa precios de opciones.
    r4   r1   r8   r5   r9   r,   g      Y@)r   maxr   )r\   r   r   cscbpspbcall_low	call_highput_lowput_high	call_intrput_intrdebit_pointsr   r   r   r   l  s   r   symbolc                 C  s   | t v r	d|  S | S )N$)INDEX_SYMBOLS)r   r   r   r   normalize_symbol_for_chain  s   r   sc                 C  s   t t| d S )Nz%Y-%m-%d)r   strptimer   r   )r   r   r   r   _parse_date  s   r   d0d1
List[date]c                 C  s@   | }g }||kr|  dk r|| |tdd7 }||ks|S )N   r=   )days)weekdayr}   r   )r   r   curr   r   r   r   list_weekdays  s   
r   dayOptional[Path]c                 C  s@   t j| |jd|jd|jdd}t|  }| r|S d S )N04d02d)r   yyyymmdd)FILE_PATTERNformatyearmonthr   BASE_DATA_DIRresolveexists)r   r   fnamer   r   r   r   ra     s   ra   c                 C  sH   t | s
t |rdS t| } t|}| dks|dkrdS | | d S )Nr,   r   g       @)rc   isnar   )bidaskr   r   r   	_safe_mid  s   r   r   pd.DataFramehhmmc                 C  s   t j| d dd}| }| std| j| } |j| }t|d d d t|dd   }|jjd |jj	 }|| 
  }| j|df }| | d |k S )Nr/   r(   r)   zAll timestamps invalidrA   <   r   )rc   rh   notnaany
ValueErrorlocr   dthourminuteabsidxmin)r   r   rB   goodtarget_minutesminutesidxsnap_tsr   r   r   rk     s   

$rk   snapr   c                 C  s   | }|d |   |d< |d   |   |d< |j|d   }|j|d   }t|d t|d t|d |d t|d t|d dt|d t|d t|d	 |d
 t|d	 t|d
 ddS )N
delta_call	call_diff	delta_putput_diffr1   r$   r%   r1   deltamidr   r   r&   r'   )r4   r5   )r   r   r   r   r   )r   r   r   call_rowput_rowr   r   r   rm     s$   







rm   sell_strikesidec                 C  s&  | }|d  t|d< |dkr|| n|| }|dkrW||d |k }|js3|j|d |    n|jd }t|d t|d t|d |d t|d t|d dS ||d |k }|jso|j|d |    n|jd }t|d t|d	 t|d
 |d t|d
 t|d dS )Nr1   r6   rF   r   r$   r%   r   r   r   r&   r'   )rj   r   emptyr   r   r   rq   r   )r   r   r   r   r   targetr   rowr   r   r   rn     s(   *



*



rn   c                 C  sJ   | d |d  |d  |d  }|d | }t t|dt t|ddS )Nr   r?      rA   )rG   r:   )r~   r   )r4   r5   r8   r9   r   rG   r:   r   r   r   ro      s   ro   r:   c                 C  s   | | }t |dt |ddS )NrA   )r   r@   )r~   )r:   r   r@   r   r   r   rp     s   rp   c           	        st    fdd}|||d d d}|||d d d}|||d d d}|||d	 d d}|| | | d
 | S )Nc                   sT   z j | |f }|dkrt|d |d W S t|d |d W S  ty)   Y dS w )Nr6   r$   r%   r&   r'   r,   )r   r   r|   )rB   r1   r   rr   r   r   r     s   z%credit_for_snapshot_fast.<locals>.midr4   r1   r6   r5   r7   r8   r9   r?   r   )	r   rB   r\   r   r   r   r   r   r   r   r   r   credit_for_snapshot_fast  s   	r   paramsc                   s  |  d}|  d|  ddd|rsdddS t|  d	}t|  d
}t|  dd}t|  dd
t|  ddt|  ddt|  ddt|  dd t|t||}dkrhdn	tdtd|d 	g g g }}}tdt	 pd}	t
|	dT 	
fdd|D }
t|
D ]4}z| }d|v r||d  n|| W q ty } z|dt|i W Y d }~qd }~ww W d    n1 sw   Y  d d!|	
t|t|||t|d"d# d$d%S )&Nr   r   r   ICr   Fzmissing symbol/entry_time)okerror	date_fromdate_tor   
   
width_call   r   r=   r   r,   rS   rT   IBr+   g{Gz?r?      rA   )max_workersc                   s2   i | ]} t|	
 d d |qS )F)submitr   ).0r   r   r   r   r"   r   r   executorr   r   r   r   r   r   
<dictcomp>H  s(    z'run_backtest_engine.<locals>.<dictcomp>r#   r   TENTRY_AND_PATHc                 S  s   | d S )Nr   r   )xr   r   r   <lambda>r  s    z%run_backtest_engine.<locals>.<lambda>)key)r   stepsymbol_inputsymbol_chainr   r   r   
days_totaldays_processedmissing_daysr*   per_day)r{   r   r   r   r   r   r   minos	cpu_countr
   r   r_   r}   rs   r   rl   sorted)r   
symbol_rawr   r   dnr   r  r  r*   r  futuresfuturereser   r  r   run_backtest_engine,  sb   



 
 r#  )FFr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r    r"   r   )r\   r   r   r   r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   )r   r   r   r   )r:   r   r   r   r   r   )r   r   r   r   )r   r   r   r   )%
__future__r   r   r   r   pathlibr   typingr   r   r	   pandasrc   concurrent.futuresr
   r   r  flaskr   r   r   r   r   r   r   r   r   r   ra   r   rk   rm   rn   ro   rp   r   r#  r   r   r   r   <module>   s<      
Y











