o
    ̿SiD                     @   s  d dl Z d dlZd dlZd dlmZ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mZ eeZedd	 d
kZeddZeddZedd	 d
kZedd	 d
kZedd	 d
kZeddZeddZeddZeeddZedd	 d
kZ eeddZ!eeddZ"eedd d!Z#d"e$d#ee%eef  fd$d%Z&d#efd&d'Z'dUd(ee d#e$fd)d*Z(d(ed#e)fd+d,Z*d(ed#e$fd-d.Z+d/e$d#ee$ fd0d1Z,d2ed#e)fd3d4Z-d2ed#ee%eef  fd5d6Z.d2ed7ed#efd8d9Z/d2ed#ee fd:d;Z0d2ed#ee fd<d=Z1d>e$d#ee$ fd?d@Z2d>e$dAe$d#dfdBdCZ3d#e	fdDdEZ4dFe$d#e)fdGdHZ5dIe$d#e)fdJdKZ6dIe$d#dfdLdMZ7dFe$d#e)fdNdOZ8dPdQ Z9ddRdSdTZ:dS )V    N)datetime	timedeltatimezone)Optional)
Collection)get_mongo_db)_get_global_zerodha_client)build_early_movers_snapshotEARLY_MOVERS_VERBOSE_LOGS01EARLY_MOVERS_START_HHMMz20:00EARLY_MOVERS_END_HHMMz20:30EARLY_MOVERS_ENFORCE_WINDOWEARLY_MOVERS_WEEKDAYS_ONLY,EARLY_MOVERS_REQUIRE_STOCK_HISTORY_EOD_TODAYSTOCK_HISTORY_LAST_EOD_META_KEY"stock_history_refresh_last_eod_runEARLY_MOVERS_LAST_RUN_META_KEYearly_movers_last_run_ist_dateEARLY_MOVERS_LOCK_META_KEYearly_movers_snapshot_lockEARLY_MOVERS_LOCK_TTL_SECONDS1800+EARLY_MOVERS_ALLOW_RERUN_IF_SNAPSHOT_EXISTSEARLY_MOVERS_LOOP_SLEEP_SECONDS30$EARLY_MOVERS_SLEEP_AFTER_RUN_SECONDS600      )hoursminutesvreturnc                 C   sL   z| pd  }|sW d S |d\}}t|t|fW S  ty%   Y d S w )N :)stripsplitint	Exception)r#   shhmm r.   D/var/www/html/Trade-python/app/v1/background/early_movers_refresh.py_parse_hhmm+   s   r0   c                   C   s   t jtdS )N)tz)r   nowISTr.   r.   r.   r/   _ist_now6   s   r4   dtc                 C   s   | pt  }|dS )Nz%Y-%m-%d)r4   strftimer5   dr.   r.   r/   _ist_date_str:   s   

r9   c                 C   s   |   dv S )N)r               )weekday)r5   r.   r.   r/   _is_weekday_ist?   s   r?   c                 C   sL   |   }|  dkr|tdd }| S |  dkr"|tdd }| S )z=Return latest trading day key (weekends roll back to Friday).r   r:   days   r;   )dater>   r   	isoformatr7   r.   r.   r/   _latest_trading_day_key_istE   s   rE   date_keyc                 C   sl   zt t|   }W n
 ty   Y dS w |tdd }| dkr2|tdd }| dks%| S )z,Return next trading day key (skips Sat/Sun).Nr:   r@   r   )	r   fromisoformatstrr'   rC   r*   r   r>   rD   )rF   baser8   r.   r.   r/   _next_trading_day_keyO   s   rJ   now_istc                 C   st   t t}t t}|r|sdS | j|d |d ddd}| j|d |d ddd}||kr.dS ||   ko7|kS   S )NFr   r:   hourminutesecondmicrosecondr0   r   r   replacerK   stenstartendr.   r.   r/   
_in_window[   s   rX   c                 C   sd   t t}t t}|r|sd S | j|d |d ddd}| j|d |d ddd}||kr.d S ||fS )Nr   r:   rL   rQ   rS   r.   r.   r/   _window_boundsh   s   rY   
target_istc                 C   s6   z
t ||   }W n ty   d}Y nw td|S )Nr   r:   )r)   total_secondsr*   max)rK   rZ   secr.   r.   r/   _seconds_untilt   s   
r^   c                 C   sH   t | }|sd S |\}}| |kr|S | tdd j|j|jddd}|S )Nr:   r@   r   rL   )rY   r   rR   rM   rN   )rK   boundsrV   rW   next_dayr.   r.   r/   _next_window_start|   s    ra   c                 C   s:   t | }|sdS | dkr|tdd }| dks|S )u:   Return next window start on a trading weekday (Mon–Fri).Nr   r:   r@   )ra   r>   r   )rK   nxtr.   r.   r/   _next_weekday_window_start   s   rc   keyc                 C   s8   | d  d|i}|sd S |d}|d u rd S t|S )Nsystem_metard   value)find_onegetrH   )dbrd   docr#   r.   r.   r/   _get_system_meta_value   s   
rk   rf   c                 C   s,   | d j d|id||t didd d S )Nre   rd   $set)rd   rf   
updated_atTupsert)
update_oner   utcnow)ri   rd   rf   r.   r.   r/   _set_system_meta_value   s
   
rr   c                 C   s   | t dd S )N EARLY_MOVERS_SNAPSHOT_COLLECTIONearly_movers_snapshots)osgetenv)ri   r.   r.   r/   _snapshot_collection   s   rw   target_datec                 C   s&   t | dt|iddd}t|S )NrC   r:   )_idrC   )rw   rg   rH   bool)ri   rx   rj   r.   r.   r/   _snapshot_exists   s   r{   ownerc                C   sv   t  }|ttdttd }| d jtdd|iidddiid|igd	d
t|||didd}t|j	p:|j
dkS )zkAcquire a best-effort distributed lock in system_meta.

    Returns True if acquired, False otherwise.
    r    )secondsre   
expires_atz$ltz$existsFr|   )rd   z$orrl   )rd   r|   r~   rm   Trn   r:   )r   rq   r   r\   r)   r   rp   r   rz   upserted_idmodified_count)ri   r|   r2   expiresresr.   r.   r/   _acquire_lock   s&   

	r   c                C   sR   z| d  t|ddt t di W d S  ty(   tjddd Y d S w )Nre   )rd   r|   rl   )r~   rm   z"Early movers: error releasing lockTexc_info)rp   r   r   rq   r*   loggerdebug)ri   r|   r.   r.   r/   _release_lock   s   
r   c                 C   s   t | t}||kS N)rk   r   )ri   rx   r#   r.   r.   r/   _already_ran_for_target   s   
r   c                 C   s   t | }|s
td|S )Nz!Global Zerodha client unavailable)r   RuntimeError)ri   zr.   r.   r/   _make_zerodha_client   s   r   )appc                 C   s   dd }| S )Nc                     s  dt ttttf } td|   tdt tttt 	 zt }t	|}t rt
|}|s7ttI d H  W q|\}}tr^t|s^t|}|rTtt||I d H  W qttI d H  W q||k rott||I d H  W q||krt|}|rtt||I d H  W qttI d H  W qt strt|strtd|  ttI d H  W qt st rt|sttI d H  W qt }t|}d }	d}
t}dt  }d}zt|t}|stdt  trtdt t}ntrt|}t|t|krtd	| d
|  trtd|| t}d }|rtt|}|s&t}nt||rAtd|  tr<td| d}t}nt set!||ret"|t#| td|  tr`td| d}t}nit$||dstdt%  tr|tdt% t}nOzGt st!||rt"|t#| td|  d}t}n$t&|}td| d| d|  t'|||d}	t"|t#| d}
d}t}W t(||d nt(||d w W z|)  W n) t*y   tj+ddd Y nw z|)  W w  t*y   tj+ddd Y w w |
rtd|	  td|	 t r+|r+tt }|r+ttt |I d H  W qt|I d H  W n t*yK   t,d ttI d H  Y nw q)Nz^Early movers loop starting. enforce_window=%s window=%s-%s weekdays_only=%s require_history=%sz[EarlyMovers] Tz8Early movers skipped: not a trading weekday | now_ist=%sFzpid=z+[EarlyMovers] Skipped: missing system_meta.z9Early movers skipped: stock history EOD meta missing (%s)z4[EarlyMovers] Skipped: stale EOD history | last_eod=z
 expected=zAEarly movers skipped: stale EOD history | last_eod=%s expected=%sz1[EarlyMovers] Skipped: already ran | target_date=z2Early movers skipped: already ran | target_date=%sz5[EarlyMovers] Skipped: snapshot exists | target_date=z>Early movers skipped: snapshot already exists | target_date=%s)r|   z,[EarlyMovers] Skipped: lock busy | lock_key=z$Early movers skipped: lock busy (%s)zA[EarlyMovers] Skipped (post-lock): snapshot exists | target_date=z'[EarlyMovers] Running snapshot | owner=z target_date=z based_on_eod=)ri   zerodha_clientist_datez(Early movers: error closing DB generatorr   z[EarlyMovers] Snapshot done: zEarly movers snapshot done: %szEarly movers loop error)-r   r   r   r   REQUIRE_STOCK_HISTORY_EOD_TODAYprintr   infor4   r9   rY   asynciosleepSLEEP_SECONDS_IDLEr?   rc   r^   ra   r
   rD   rX   r   nextru   getpidrk   r   rE   rH   rJ   r   SLEEP_SECONDS_AFTER_RUNr   r{   rr   r   r   r   r   r	   r   closer*   r   	exception)msgrK   r   r_   rV   rW   rb   db_genri   resultransleep_secondsr|   done_for_targetlast_eod_keyexpectedrx   r   r.   r.   r/   _loop   s*  
	


 z(early_movers_refresh_loop.<locals>._loopr.   )r   r   r.   r.   r/   early_movers_refresh_loop   s    .r   r   );r   loggingru   r   r   r   typingr   pymongo.collectionr   app.db.databaser   !app.v1.background.global_intradayr   app.v1.services.early_moversr	   	getLogger__name__r   rv   r'   r
   r   r   r   r   r   r   r   r   r)   r   r   r   r   r3   rH   tupler0   r4   r9   rz   r?   rE   rJ   rX   rY   r^   ra   rc   rk   rr   rw   r{   r   r   r   r   r   r.   r.   r.   r/   <module>   sX    




