o
    ̿Sia                     @   sD  d Z ddlmZ ddlmZmZmZmZ ddlmZ ddl	m
Z
 ddlZddlmZ ddlZddlmZ dd	lmZmZ d
ededededef
ddZedddddZdedee fddZdedee fddZdedee fddZdedefddZd eeef d!edefd"d#Zdedee fd$d%Zdedee fd&d'Zd(edefd)d*Z d+edee fd,d-Z!dedefd.d/Z"dedee fd0d1Z#d2eeeef  deeeef  fd3d4Z$d5edeeef fd6d7Z%d8ed(ed9edeeeef  fd:d;Z&d[d(ed9edeeef fd=d>Z'd?edefd@dAZ(d(edeeeef  fdBdCZ)dDedEedee fdFdGZ*dHedeeeef  fdIdJZ+d(edeeeef  fdKdLZ,d(edMeeeef  dNeeef deeef fdOdPZ-dQeeeef  dReeef defdSdTZ.dedefdUdVZ/dWeeef dXed?edeeef fdYdZZ0dS )\z}Helpers for platform teGPT routers.

NOTE: This file is a move-only extraction from `teGPT.py` to keep router modules small.
    )HTTPException)DictAnyListOptional)datetime)ObjectIdN)deque)ZerodhaClient)confidence_ranknormalize_confidencenamedefault	min_value	max_valuereturnc                C   sb   t | }|d u st| dkr|S z
tt| }W n ty(   | Y S w t|t||S N )osgetenvstrstripint	Exceptionmaxmin)r   r   r   r   rawv r   C/var/www/html/Trade-python/app/v1/routers/platform/teGPT_helpers.py_env_int   s   
r     PORTFOLIO_LIVE_FRESHNESS_MINUTES
      <   r   r   r   c                 C   s0   | d u rd S t | tr|  S t | tr| S d S N)
isinstancer   	isoformatr   r   r   r   r   
_dt_to_iso%   s   

r*   c                 C   sZ   | d u rd S t | tr| S t | tr+|  r+z
t| ddW S  ty*   Y d S w d S )NZz+00:00)r'   r   r   r   fromisoformatreplacer   r)   r   r   r   	_parse_ts0   s   
r.   c              	   C   sd   t | }|dur
|S t| tr|  sdS |  }dD ]}z	t||W   S  ty/   Y qw dS )znParse common CSV/export timestamp formats.

    Keeps behavior conservative: returns None if unparseable.
    N)	z%d-%m-%Y %H:%M:%Sz%d/%m/%Y %H:%M:%Sz%Y-%m-%d %H:%M:%Sz%Y/%m/%d %H:%M:%Sz%d-%m-%Y %H:%Mz%d/%m/%Y %H:%Mz%Y-%m-%dz%d-%m-%Yz%d/%m/%Y)r.   r'   r   r   r   strptimer   )r   dtsfmtr   r   r   _parse_ts_flexible>   s   r3   kc                 C   s$   t | tsdS tdd|   S )Nr   z
[^a-z0-9]+)r'   r   resubr   lower)r4   r   r   r   _norm_csv_key[   s   
r8   rowkeysc                 G   s@   |D ]}t |}|sq|| v r| |dvr| |  S qd S )Nr   )r8   get)r9   r:   r4   nkr   r   r   _picka   s   r=   c                 C   F   zt | }||kr|t dt dfvr|W S d W S  ty"   Y d S w Ninfz-inffloatr   )r   nr   r   r   _safe_floatk      (rD   c                 C   s    zt | W S  ty   Y d S w r&   )r   r   r)   r   r   r   	_safe_ints   s
   
rF   symbolc                 C   s   | pd   S r   )r   upper)rG   r   r   r   _norm_symbolz   s   rI   tagsc                 C   s   | d u rg S t | trdd | dD }dd |D S t | trUg }| D ]}t |tr9| r9||   q%t }g }|D ]}||v rHqA|| || qA|S g S )Nc                 S   s   g | ]}|  qS r   r   .0pr   r   r   
<listcomp>   s    z_norm_tags.<locals>.<listcomp>,c                 S   s   g | ]}|r|  qS r   )r7   rL   r   r   r   rO      s    )	r'   r   splitlistr   appendr7   setadd)rJ   partsouttseendedupedr   r   r   
_norm_tags~   s(   


r[   c                 C   s   | pd  S r   rK   r)   r   r   r   _norm_account_id   s   r\   c                 C   s   | d u rd S t |   }|dv rdS |dv rdS |dv r dS |dv r&dS |dv r,|S | dkr4dS | d	kr<dS |dkrBdS |dkrHdS d S )
N)BUYBr]   )SELLSr_   )zBUY PURCHASE)zSELL SALEr]   r_   buysell)r   r   rH   r7   )r   r1   r   r   r   
_norm_side   s$   rf   itemsc              
      s  dt ttf dtfdd}dtdtt fdd}g }i }t| dd	 d
D ]}t|d}t	|d}||d}|du rG||d}d}	d}
d}|rY|rY|dksY|du r||}||pdt
 }tdd |D }| d} r fdd|D }tdd |D }|rtdd |D | }t|}|ddd||d || q$|dkr|n| }||}||t
 }t|}|dkr-|dkr|r|d d dk r|d }t||d  }|	|d | | 7 }	|
|7 }
|||d  7 }|d  |7  < ||8 }|d dkr|  |dkr|r|d d dk s|dkr,|||d nh|dkr|r|d d dkr|d }t||d }|	||d  | 7 }	|
|7 }
|||d  7 }|d  |8  < ||8 }|d dkrv|  |dkr|r|d d dks>|dkr|| |d tdd |D }| d} rŇ fdd|D }tdd |D }|rtdd |D | }t|}|t|	d t|
|
rt||
 d!ndt||durt|d!ndd || q$|S )"a  Compute gross realized P&L using FIFO matching.

    - Works on execution-level rows (BUY/SELL, qty, price).
    - Returns per-row: realized_pnl, matched_qty, matched_avg_entry_price, position_after, open_avg_price.
    - This is gross P&L (fees/taxes not included).
    itr   c                 S   sl   |  dpd  |  dpd|  dpd|  dp%|  di  dp%d|  dp4|  di  dp4dfS )NrG   r   productexchangesegmentr   seriesr;   r   rH   )rh   r   r   r   key_of   s   z(_compute_fifo_enrichment.<locals>.key_ofr   c                 S   r>   r?   rA   )r   fr   r   r   num   rE   z%_compute_fifo_enrichment.<locals>.numc                 S   s   |  dptjS )Nts)r;   r   r   )xr   r   r   <lambda>   s    z*_compute_fifo_enrichment.<locals>.<lambda>)keytransaction_typequantitypriceNaverage_priceg        r   c                 s       | ]}|d  V  qdS qtyNr   rM   lr   r   r   	<genexpr>       z+_compute_fifo_enrichment.<locals>.<genexpr>c                    $   g | ]}|d  dk dkkr|qS r{   r   r   r|   open_qtyr   r   rO         $ z,_compute_fifo_enrichment.<locals>.<listcomp>c                 s       | ]	}t |d  V  qdS rz   absr|   r   r   r   r~          c                 s   $    | ]}t |d  |d  V  qdS r{   rw   Nr   r|   r   r   r   r~         " )realized_pnlmatched_qtymatched_avg_entry_priceposition_afteropen_avg_pricer]   r{   )r{   rw   c                 s   ry   rz   r   r|   r   r   r   r~     r   c                    r   r   r   r|   r   r   r   rO     r   c                 s   r   rz   r   r|   r   r   r   r~     r   c                 s   r   r   r   r|   r   r   r   r~     r         )r   r   r   tupler   rB   sortedrf   r;   rF   r	   sumdictupdaterS   
setdefaultr   r   popleftroundr   )rg   rn   rp   enrichedlots_by_keyrh   sideqty_ipxrealizedr   matched_entry_valr4   dqposopen_avgsamedenomrW   signed	remaininglotcovercloser   r   r   _compute_fifo_enrichment   s   	
	
" 
""

	r   
account_idc                 C   sN   t | }|sddddiiddiddigiS dd|idddiiddiddigiS )zvMatch portfolio docs for the given account.

    Backward compatible: include docs with missing/empty account_id.
    z$orr   z$existsFr   N)r\   )r   aidr   r   r   _portfolio_account_match+  s   
r   zerodha_clientrj   c              	   C   sH  t |}|pd  }g }|r|| dD ]}||vr"|| q|D ]|}| d| }z*| |g}	t|	tr?|	|nd }
t|
trW|
drW|
d||dW   S W n	 tya   Y nw z6t	| dd }|d u roW q%|
|g}t|tr||nd }
t|
tr|
dr|
d||dW   S W q% ty   Y q%w d S )NNSE)r   BSE:instrument_token)r   rj   tradingsymbolkite)rI   r   rH   rS   	get_quoter'   r   r;   r   getattrltp)r   rG   rj   symexattemptsfallbackexchrt   qdr9   r   ldr   r   r   *_resolve_instrument_token_via_user_zerodha>  sN   

r   r   c                 C   s   t |}|stddd|pd  }| d ||dp&| d d|i}t|ts8tdd	| d
| d|dsm|ddurmzt|d}| d 	d|d idd|ii ||d< W |S  t
yl   Y |S w |S )zRead-only stock lookup.

    Non-negotiable: no manual stock creation.
    Stocks are created ONLY from Zerodha instruments via the stocks master refresh.
    i  zsymbol is required)status_codedetailr   stocksrG   rj   rG   i  z'Stock not found in stocks master list: r   stock_id_idNz$set)rI   r   r   rH   find_oner'   r   r;   r   
update_oner   )dbrG   rj   r   stocksidr   r   r   _ensure_stock_identityo  s$   &
 
r   moverc                 C   s8   | pd   }|dv rdS |dv rdS |dv rdS dS )Nr   )gainersgainerztop-gainersGAINER)losersloserz
top-losersLOSER)bothallBOTH)r   r7   )r   r   r   r   r   _normalize_mover_param  s   r   c                 C   s>   |pd   }|sd S | d |ddp| d d|iS )Nr   r   r   r   rG   )r   rH   r   )r   rG   r   r   r   r   _get_stock_by_symbol  s   &r   
mover_typelimitc                 C   s   i }|dv r
||d< t | d |ddg|}dd |D }|s&g S t | d d	d
|iiddd}dd |D }g }|D ]}	||	}
|
rP||
 qB|S )N)r   r   r   live_movers)rankr#   )last_updatedc                 S   s    g | ]}| d r| d qS )r   )r;   )rM   dr   r   r   rO          z1_get_symbols_from_live_movers.<locals>.<listcomp>r   r   z$inr#   )r   rG   c                 S   s*   i | ]}| d | dpd  qS )r   rG   r   rm   )rM   r1   r   r   r   
<dictcomp>  s   * z1_get_symbols_from_live_movers.<locals>.<dictcomp>)rR   findsortr   r;   rS   )r   r   r   qlive	stock_idsr   by_idrW   r   r   r   r   r   _get_symbols_from_live_movers  s    ""

r   r   c                 C   s    |sd S | d j d|idgdS )Nstock_analysis_snapshotsr   )	timestampr   )r   )r   )r   r   r   r   r    _get_latest_snapshot_by_stock_id  s   r   c                 C   s,   t | |}|r|dsd S t| |dS )Nr   )r   r;   r   )r   rG   r   r   r   r   _get_latest_snapshot_by_symbol  s   
r   r   snapc           	      C   s$  | dpi }t|tsi }| dp| dpd}t| dp$| d| d| dd	}| d
}t|trD| dpB| d}n| d}| dpTt| d| pWd  |d uret| nd||| d|t| dtr|| d nd d}|r| d|d< | d|d< |S )NanalysisdecisionactionHOLD
confidenceconfidence_leveldecision_probabilityscorer   r   targetsentry_priceentryanalysis_idr   r   	stop_lossr   )r   rG   r   r   r   r   r   r   r   r   )	r;   r'   r   r   r   r   rH   r   r(   )	rG   r   r   r   r   r   r   r   rW   r   r   r   _extract_analysis_fields  s4   



 r   prevcurrc                 C   s   | sdS g }|  d| dkr!|d|  d d| d  |  d| dkr<|d|  d d| d  dD ]}|  || |krY| |d urY|| d q>|rad	|S d
S )NNewr   z	decision u   →r   zconfidence )r   r   z updatedz; -)r;   rS   join)r   r   rV   rt   r   r   r   _what_changed  s   """r  c                 C   s   t | S r&   )r   r)   r   r   r   _confidence_score  s   r  r   r   c                    s  |  dpd  }dtttf dttttf  fdd}dttttf  dttttf  fdd	 d
ttttf  dttttf  dtt f fdd}dtdttttf  dtt dtt dtt dtt fdd}dtdttttf  dtt dtt fdd}|  d}d }	t	|t
tfr|r|d }	|| }
t	|  dtr|  dnd }||
|}t|  d}|d u rt	|
trt|
 d}|d u rt	|tr |}t	|trdD ]}| |}t	|t
r|rt|d pi  d}|d ur nqt	|  dtr	|  dnd }t|  d}t|  d}|d ur |n|}|t|  dd||d}|  d }g }t	|t
rCd!d" |D }|t|  dd|t|  dpZt|  d|pct|  d#|d$}i d|d%|d&|  d&pvdd|  ddd't|  d'|  d(|  d)d*d+|  d+d,|d|d-|  d-d.|  d.d|d |d/|  d/d|  dd#|  d#d0|  d0d1|  d1||  dd|  d'd2d3|  d4g |  d5i |  d6i |  d|  d0p|	d7|  d8|d9S ):NrG   r   ar   c                 S   sP   |  d}t|tr| d}t|tr|r|S |  d}t|tr&|r&|S d S )Nmarket_dataquote)r;   r'   r   )r  mdr   q2r   r   r   _extract_quote  s   



z7_format_analysis_for_stream_row.<locals>._extract_quoter  c                 S   sb   t | tr| s	d S | d}t |tr|r|S | d}t |tr/|d}t |tr/|r/|S d S )Ncandlesr  )r'   r   r;   )r  cnestedc2r   r   r   _pick_candles_dict  s   



z;_format_analysis_for_stream_row.<locals>._pick_candles_dictr  r  c                    sz  t | trl| rlt| d}t | dtr| dni }t|d}|d ur8|d ur8|dkr8|| | d S t| d}t|d}|d urX|d urX|dkrX|| d S |d url|d url|dkrl|| | d S  |}t |trw|syd S dD ]?}||}	t |	trt|	d	k rq{t|	d pi d}t|	d
 pi d}
|
d u s|d u s|dkrq{|
| | d   S d S )N
last_priceohlcopenr   g      Y@
net_changer   )5minute5min15minute15min30minute30minr   r   )r'   r   rD   r;   rR   len)r  r  lastr  open_pxnet
prev_closer  tfrl   
last_closer  r   r   _compute_change_pct  s2   
z<_format_analysis_for_stream_row.<locals>._compute_change_pctr   
entry_zoner   slr   c                 S   s  dd |D }d }t |tr<t|dp|d}t|dp$|d}|d ur<|d ur<|dkr<|dkr<|| d }|d urB|n|}	t|	}	t|}| pOd	  }
|	d u s`|d u s`|
d
vrf|d d S |
dkrn|	| n||	 }|d u sz|dkr|d d S t|dkr|
dkr|	| n|	| }|
dkr|	d|  n|	d|  }t|dt|dgS t|dkrt|d }|
dkrt	|| |	d|  }nt
|| |	d|  }|tt|d |d d S )Nc                 S       g | ]}t |d urt|qS r&   rD   rB   )rM   rX   r   r   r   rO   ?  r   zP_format_analysis_for_stream_row.<locals>._ensure_two_targets.<locals>.<listcomp>lowr7   highrH   r   g       @r   rc   r   r]   r#   )r'   r   rD   r;   r   rH   r  r   rB   r   r   rS   )r   r#  r   r$  r   rW   zone_midlohi	entry_refr   riskt1t2r   r   r   _ensure_two_targets7  s6   
  z<_format_analysis_for_stream_row.<locals>._ensure_two_targetsc           
      S   s  t |}|d u st|ts|S t |dp|d}t |dp%|d}|d u s7|d u s7|dks7|dkr9|S | p<d  }tdddd	d
}t|d }|dkrjt|d|  }|t|krc|S tt||S |dkrt|d|  }	|t|kr~|	S t	t||	S |S )Nr'  r7   r(  rH   r   r   ENTRY_SL_BUFFER_BPr"      r%   g     @r]   g      ?r_   )
rD   r'   r   r;   r   rH   r    rB   r   r   )
r   r#  r$  r*  r+  r   bufbuf_pctmax_okmin_okr   r   r   _ensure_sl_sideb  s*    z8_format_analysis_for_stream_row.<locals>._ensure_sl_sider   current_pricer  )r  r  dayr   r   exec_slr   )r   r#  r$  exec_targetsc                 S   r%  r&   r&  )rM   rr   r   r   r   rO     r   z3_format_analysis_for_stream_row.<locals>.<listcomp>r   )r   r#  r   r$  r   r   trend_labelr   r   r   r   r   
change_pctentry_trigger_reasonsignal_stateexec_rr_ratioprice_targetrisk_reward_ratioLOW)r   r   	rationalefeaturestechnical_indicators)r   exitr   )r8  metricsrD  rE  rF  r   r   r   )r;   r   rH   r   r   r   r   rB   r   r'   rR   r   r   rD   r   )r   r   r   rG   r
  r"  r0  r7  raw_targetsexit_targetr  md_for_changer=  r8  r  r  rl   r#  sl_execsl_fallbackr$  raw_exec_targetsr;  r   r!  r   _format_analysis_for_stream_row  s   &*6&
+




 














rO  )r   )1__doc__fastapir   typingr   r   r   r   r   bsonr   r5   collectionsr	   r   app.v1.services.zerodha.clientr
   app.v1.utils.confidencer   r   r   r   r    (DEFAULT_PORTFOLIO_LIVE_FRESHNESS_MINUTESr*   r.   r3   r8   r=   rB   rD   rF   rI   r[   r\   rf   r   r   r   r   r   r   r   r   r   r   r  r  rO  r   r   r   r   <module>   sb    
*|
 16*$.