o
    HiGV                    @   s  d Z ddlmZmZmZmZmZmZmZ ddl	m
Z
mZmZmZ ddlZddlmZmZ ddlm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Zdd	lm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+ e Z,e-e.Z/de0de1de1de1de1f
ddZ2e2dddddZ3e2dddddZ4dedee0 fddZ5dedee fdd Z6dedee fd!d"Z7d#ede0fd$d%Z8d&e
e0ef d'e0defd(d)Z9dedee: fd*d+Z;dedee1 fd,d-Z<d.e0de0fd/d0Z=d1edee0 fd2d3Z>dede0fd4d5Z?dedee0 fd6d7Z@d8ee
e0ef  dee
e0ef  fd9d:ZAd;e0de
e0ef fd<d=ZBd>e d.e0d?e0dee
e0ef  fd@dAZCdd.e0d?e0de
e0ef fdCdDZDdEe0de0fdFdGZEd.e0dee
e0ef  fdHdIZFdJe0dKe1dee0 fdLdMZGdNe0dee
e0ef  fdOdPZHd.e0dee
e0ef  fdQdRZId.e0dSee
e0ef  dTe
e0ef de
e0ef fdUdVZJdWee
e0ef  dXe
e0ef de0fdYdZZKde0de1fd[d\ZLe,jMd]d^d_d`da ZNe,jMdbdcd_eefdddeZOe,jMdfdgd_edhdidjeddkdjeejPfdle0dKe1fdmdnZQe,MdoeejPfdpdqZRe,jMdrdsd_edhdtdjeejPfdEe0fdudvZSe,jTdwdxd_eejPeefdydzZUe,jMd{d|d_edddd}d~eddddd~edddjeejPeefdKe1de1deVfddZWe,jTddd_edddjeejPeefdefddZXe,jTddd_ei deejPeefd.e0de
e0ef fddZYe,jMddd_edddjeejPeefdKe1fddZZe,jMddd_edddjeddddeejPfde0dKe1fddZ[e,jMddd_edddjeejPeefd.e0de1fddZ\e,jTddd_edeejPeefde
e0ef fddZ]e,jMddd_edddjedddjedddjedddjeddddedddeejPeefde0dee0 dee0 d;ee0 dKe1de1fddZ^e,j_ddd_edeejPeefde0de
e0ef fddZ`e,jaddd_eejPeefde0fddZbe,jMddd_edddjeejPeefd;ee0 fddÄZce,jTddd_edeejPeefde
e0ef fddǄZdde
e0ef de1dEe0de
e0ef fdd˄Zee,jTddd_ei dee3dddd~eddddd~eejPeefde
e0ef de1dKe1fdd҄Zfe,jMddd_edddjedddjedddjeejPeefdKe1d.ee0 dee0 fddڄZge,jTddd_edeejPeefd.e0de
e0ef fddބZhe,jTddd_edeejPeefd.e0de
e0ef fddZie,jMddd_edddjedddjeejPeefd.e0dKe1dee0 fddZje,jTddd_edeejPeefde
e0ef fddZke,jMddd_edddjedddjeejPeefdKe1dee0 fddZle,jMddd_edhdtdjedddjeejPeefdEe0dKe1fddZme,jMddd_ee4de4dd~eejPeefdKe1fddZne,jMddd_eejPeefd dZoe,jTddd_edeejPeefde0de
e0ef fddZpe,jTddd_edeejPeefde
e0ef fd	d
Zqe,jTddd_edeejPfde
e0ef fddZre,jTddd_edeejPfde
e0ef fddZsdS (  zm
Pure ChatGPT-based Trading Engine Router
No custom algorithms - all analysis delegated to OpenAI GPT models
    )	APIRouterDependsHTTPExceptionBodyQueryFile
UploadFile)DictAnyListOptionalN)datetime	timedelta)ObjectId)	UpdateOne)deque)database)get_current_userdetailsZerodhaClient)
DEFAULT_TIMEFRAMESget_zerodha_client_serviceget_market_movers_serviceanalyze_symbol_servicebulk_analyze_servicechat_with_stock_serviceplace_order_serviceget_user_signals_servicerefresh_instruments_servicevalidate_openai_setup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 r1   2/var/www/html/Trade-python/app/v1/routers/teGPT.py_env_int(   s   
r3    PORTFOLIO_LIVE_FRESHNESS_MINUTES
      <   )r"   r#   NIFTY50_MAX_ANALYSES2      r0   c                 C   s0   | d u rd S t | tr|  S t | tr| S d S N)
isinstancer   	isoformatr)   r0   r1   r1   r2   
_dt_to_isoC   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>   r1   r1   r2   	_parse_tsN   s   
rC   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)rC   r<   r)   r*   r   strptimer,   )r0   dtsfmtr1   r1   r2   _parse_ts_flexible\   s   rH   kc                 C   s$   t | tsdS tdd|   S )Nr&   z
[^a-z0-9]+)r<   r)   resubr*   lower)rI   r1   r1   r2   _norm_csv_keyy   s   
rM   rowkeysc                 G   s@   |D ]}t |}|sq|| v r| |dvr| |  S qd S )Nr%   )rM   get)rN   rO   rI   nkr1   r1   r2   _pick   s   rR   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,   )r0   nr1   r1   r2   _safe_float      (rY   c                 C   s    zt | W S  ty   Y d S w r;   )r+   r,   r>   r1   r1   r2   	_safe_int   s
   
r[   symbolc                 C   s   | pd   S r%   )r*   upperr\   r1   r1   r2   _norm_symbol   s   r_   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 r1   r*   .0pr1   r1   r2   
<listcomp>   s    z_norm_tags.<locals>.<listcomp>,c                 S   s   g | ]}|r|  qS r1   )rL   rb   r1   r1   r2   re      s    )	r<   r)   splitlistr*   appendrL   setadd)r`   partsouttseendedupedr1   r1   r2   
_norm_tags   s(   


rq   c                 C   s   | pd  S r%   ra   r>   r1   r1   r2   _norm_account_id   s   rr   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Brs   )SELLSru   )zBUY PURCHASE)zSELL SALErs   ru   buysell)r)   r*   r]   rL   r0   rF   r1   r1   r2   
_norm_side   s$   r}   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 )Nr\   r&   productexchangesegmentr/   seriesrP   r*   r]   )r   r1   r1   r2   key_of   s   z(_compute_fifo_enrichment.<locals>.key_ofr0   c                 S   rS   rT   rV   )r0   fr1   r1   r2   num   rZ   z%_compute_fifo_enrichment.<locals>.numc                 S      |  dptjS NtsrP   r   r.   xr1   r1   r2   <lambda>       z*_compute_fifo_enrichment.<locals>.<lambda>keytransaction_typequantitypriceNaverage_price        r   c                 s       | ]}|d  V  qdS qtyNr1   rc   lr1   r1   r2   	<genexpr>       z+_compute_fifo_enrichment.<locals>.<genexpr>c                    $   g | ]}|d  dk dkkr|qS r   r   r1   r   open_qtyr1   r2   re         $ z,_compute_fifo_enrichment.<locals>.<listcomp>c                 s       | ]	}t |d  V  qdS r   absr   r1   r1   r2   r          c                 s   $    | ]}t |d  |d  V  qdS r   r   Nr   r   r1   r1   r2   r         " realized_pnlmatched_qtymatched_avg_entry_priceposition_afteropen_avg_pricers   r   )r   r   c                 s   r   r   r1   r   r1   r1   r2   r   1  r   c                    r   r   r1   r   r   r1   r2   re   5  r   c                 s   r   r   r   r   r1   r1   r2   r   6  r   c                 s   r   r   r   r   r1   r1   r2   r   8  r         )r	   r)   r
   tupler   rW   sortedr}   rP   r[   r   sumdictupdateri   
setdefaultr   r.   popleftroundr+   )r~   r   r   enrichedlots_by_keyr   sideqty_ipxrealizedr   matched_entry_valrI   dqposopen_avgsamedenomrm   signed	remaininglotcovercloser1   r   r2   _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.
    $orr   $existsFr&   N)rr   )r   aidr1   r1   r2   _portfolio_account_matchH  s   
r   zerodha_clientr   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   r   tradingsymbolkite)r_   r*   r]   ri   	get_quoter<   r   rP   r,   getattrltp)r   r\   r   symexattemptsfallbackexchr   qdrN   r   ldr1   r1   r2   *_resolve_instrument_token_via_user_zerodha[  sN   

r   r   c                 C   s  t |}|stddd|pd  }t }| d ||dp*| d d|i}|sE||dd	|d
}| d |}i |d|ji}|	dset
|	d}| d d|d idd|ii ||d< | d dt| ddd|dddddddddd}	|	r|		dr|		d|		dp||		d|		d|		d|		d|		dp||d}
| d d|d id|
i |dd  |
 D  |S )!zREnsure `stocks` has a stable identity row with `stock_id` and instrument metadata.  zsymbol is requiredstatus_codedetailr   stocksr\   r   r\   NT)r\   r   sector	is_active
created_at_idstock_id$setzerodha_instruments^$iz$regexz$options)r   r   r   r6   )r   r   r   r    r   	tick_sizelot_sizer   r   r   r    r   r   r   r   )r   r   r    r   r   r   r   instrument_updated_atc                 S   s   i | ]\}}|d ur||qS r;   r1   )rc   rI   r0   r1   r1   r2   
<dictcomp>  s    z*_ensure_stock_identity.<locals>.<dictcomp>)r_   r   r*   r]   r   utcnowfind_one
insert_oneinserted_idrP   r)   
update_onerJ   escaper   r~   )dbr\   r   r   nowstock	stock_docinsertedsidinstpatchr1   r1   r2   _ensure_stock_identity  sX   &
 
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*   rL   )r  r0   r1   r1   r2   _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   r\   )r*   r]   r   )r   r\   r   r1   r1   r2   _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)rankr6   )last_updatedc                 S       g | ]}| d r| d qS r   rP   rc   dr1   r1   r2   re          z1_get_symbols_from_live_movers.<locals>.<listcomp>r   r   $inr6   )r   r\   c                 S   s*   i | ]}| d | dpd  qS )r   r\   r&   r   rc   rF   r1   r1   r2   r     s   * z1_get_symbols_from_live_movers.<locals>.<dictcomp>)rh   findsortr  rP   ri   )r   r  r  qlive	stock_idsr   by_idrm   r  r   r1   r1   r2   _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   r1   r1   r2    _get_latest_snapshot_by_stock_id  s   r,  c                 C   s,   t | |}|r|dsd S t| |dS )Nr   )r  rP   r,  )r   r\   r   r1   r1   r2   _get_latest_snapshot_by_symbol  s   
r-  r   snapc           	      C   s&  | dpi }t|tsi }| dp| dpd}| dp%| dp%d}| d}t|tr;| d	p9| d
}n| d	}| dpKt| d| pNd  |d ur\t| nd|d urgt| 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LOWtargetsentry_priceentryanalysis_idr   r&   	stop_lossr*  )r9  r\   r0  r3  r7  r:  r6  r*  r   r   )rP   r<   r   r)   r*   r]   r   r=   )	r\   r   r.  r/  r0  r3  r6  r7  rm   r1   r1   r2   _extract_analysis_fields  s,   



 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Newr0  z	decision u   →r3  zconfidence )r7  r:  z updatedz; -)rP   ri   join)r<  r=  rl   r   r1   r1   r2   _what_changed  s   """rA  c                 C   s$   | pd   }dddd|dS )Nr&      r   r6   )HIGHMEDIUMr5  r   )r*   r]   rP   r|   r1   r1   r2   _confidence_score-  s   rE  z/healthz,Health check and OpenAI configuration status)summaryc                     s   t  } dd| d | d dS )z,Check system health and OpenAI configurationokzChatGPT Trading Engine
configuredmessage)statusserviceopenai_configuredopenai_message)r   )openai_statusr1   r1   r2   health_check3  s   rO  z/configzGet current configurationc                    s"   t | ddddddddS )z Get current system configurationr   zgpt-4o-miniT)bulk_analysisinteractive_chatorder_placementreal_time_data)user_idmodelfeatures)r)   rP   )current_userr1   r1   r2   
get_config>  s   rX  z/moverszGet market top gainers/losersr  zType: gainers, losers, or both)descriptionzMaximum number of symbolstypec              
      s   z0t | }g }|dkrt|d|t|d| }|d| }nt|||}d| |dt ddW S  tyJ } ztd	 td
t|dd}~ww )zDB-only movers endpoint.

    IMPORTANT: This endpoint must NOT trigger ET scraping, Zerodha calls, or GPT.
    Background workers populate `live_movers` and `stocks`.
    r  r
  r  Nsuccessr   )rZ  symbolssourcer*  )rJ  datazFailed to get DB movers  r   	r  r'  r   r   r,   logger	exceptionr   r)   )rZ  r  r   r  r\  er1   r1   r2   get_market_moversN  s(   	
rd  z/movers/live-modelc                 C   s   t | d i }dd |D }g }|r#t | d ddt |ii}i }|D ]}| d jd|idgd	}|r;|||< q'|||d
S )zMReturn current STOCK + live_movers + latest analysis for debugging (DB-only).r  c                 S   s    h | ]}| d r| d qS r  r  )rc   docr1   r1   r2   	<setcomp>v  r  z'get_live_model_state.<locals>.<setcomp>r   r   r  r(  r)  r+  )r  r   latest_analysis)rh   r!  r   )r   r$  r%  r   rg  r  r.  r1   r1   r2   get_live_model_stateq  s"   
rh  z/movers/top10z1Get top 10 market movers (frontend compatibility)zgainers or losersc              
      s   z)t | }|dkrt|ddt|dd dd }nt||d}d|dt dW S  tyC } ztd	 td
t|dd}~ww )z0DB-only top10 movers endpoint used by Stream UI.r  r
  r5   r  NrG  r   )rJ  top10r]  r*  zFailed to get top10 moversr_  r   r`  )r  r   r  r\  rc  r1   r1   r2   get_top10_movers  s    "
rj  z/instruments/refreshz$Refresh instrument data from Zerodhac              
      s`   zt | |}t| |}d|d |d dW S  ty/ } ztd tdt|dd}~ww )	z+Refresh instrument master data from Zerodhar[  countr*  )rJ  updatedr*  zFailed to refresh instrumentsr_  r   N)r   r   r,   ra  rb  r   r)   )r   rW  r   resultrc  r1   r1   r2   refresh_instruments  s   


rn  z/learning/transactionsz/Get user's recent Zerodha transactions (trades)zMax rows to return)gelerY  x   im  z"How many days of history to returnTz9Sync today's Zerodha trades/orders into DB before listingdayssyncc                    sL  zt |d|d  t t|d }t|dddg d|rd}zt||}W n ty<   d d Y nw d	t d
t	t t
f ddf fdd}|durz | }t|trst|d< |D ]}	t|	trr|d|	 qfW n ty   d d Y nw z | }
t|
trt|
d< |
D ]}	t|	tr|d|	 qW n ty   d d Y nw dd|iiddidddiigd}t| td|d } |ddiddg|}t|}g }|D ]}|i d	|d	pdd|dpdd |d d!|d!d"|d"d#|d#d$|d$d%|d%d&|d&d'|d'd(|d(d|dp@|d)d*t|dpPt|d)d+|d+d,|d,d-|d-d.|d.d/t|d/trx|d/ni i qt|}t|d0d1 d2d3}g }|d|  D ]}	t|	d#}t|	d$}|du rt|	d%}|r|durt|pd|pd4 d5nd}|i d	|	d	pdd|	dpdd |	d d!|	d!d"t|	d"d#|	d#d$|	d$d%|	d%d&|	d&d'|	d'd(|	d(d*|	d*d+|	d+d.|	d.p0|	d/p-i d.d,|	d,pB|	d/p?i d,d-|	d-pT|	d/pQi d-d6||	d7|	d8|	d9|	d:|	d;d< q |}d=d>|t||d?W S  ty     ty } zt !d@ tdAt |dBd}~ww )CzPersonal endpoint: last N transactions across months.

    Zerodha's official API typically exposes only today's tradebook/orders.
    To support multi-month history, we persist daily syncs into Mongo.
    r   learning_transactions)rr  r   )	attemptedtrades_seenorders_seenupsertserrorsNry  zerodha_client_unavailablekindr   r$   c           	         s  | dp| dp| dp| d}t|}| dp#| dp#d  }t }|p/|}i dd	| d|d
| d
d| dd| dpMd pQd dt| ddt| ddt| dd| dd| dd| dd|dt| dp| dd|d|}| dkr| drd| dd}n| dr| | dd}n| ||d} j||dt iddd d   d!7  < d S )"Nexchange_timestamporder_timestampfill_timestampr*  r   r\   r&   rT  r{  r   r   r   r   r   r   trade_idorder_idrJ  r   r   tokenr/   
updated_attraderT  r{  r  rT  r{  r  )rT  r{  r\   r   r   r   z$setOnInsertTupsertrx  r6   )	rP   rC   r*   r]   r   r   r[   rY   r   )	r{  r   ts_rawts_dtr\   r   effective_tsre  r   colsync_reportrT  r1   r2   
upsert_one  sf   
 

	




z-get_learning_transactions.<locals>.upsert_onerv  r  trades_sync_failedrw  orderorders_sync_failedr   $gter   F)rT  r   i  r9   )r   r6   )r  r6   u   —r\   r&   r   r   r   r   r   r   r  r  rJ  r  r|  r   r   r   isinr/   c                 S   r   r   r   r   r1   r1   r2   r   @  r   z+get_learning_transactions.<locals>.<lambda>T)r   reverser   r   valuer   r   r   r   r   r   r[  db_learning_transactions)rJ  r]  rr  totalrs  r~   z%Failed to fetch learning transactionsr_  r   )"r)   rP   r   r   r   boolr   r,   ri   r	   r
   
get_tradesr<   rh   lenr   
get_ordersr-   r.   r!  r"  r  r?   r   r   r[   rY   r   r}   count_documentsr+   r   ra  rb  )r  rr  rs  r   rW  cutoffr   r  tradesr   ordersr#  compute_capcurdocs
base_itemsr  enriched_allenriched_all_sortedr~   r   r   r  r  rc  r1   r  r2   get_learning_transactions  s>  &+







	 






	






 
.





	




"""

r  z/learning/transactions/importz0Import (backfill) learning transactions from CSV.z$CSV export (tradebook/contract note)filec           &         s  zt |d}|d  |  I dH }|stdddz|d}W n ty2   |d}Y nw tt	|}|j
sDtdd	dd
}d
d
}g }	g d}
dH fdd}|D ]V}|d7 }i }|pgi  D ]\}}t|}|suqjt|t r~| n|||< qjtt t|ddddpd}|s|d7 }q[t|dddddd}|durt |  ndpd}tt|dd}tt|ddd}tt|d d!d"}t|d#}t|d$}t|d%}t|d&}t|d'}t|d(}t|d)d*}t|d+d,}t|d-d.d/}t|d0d1d2d3d4} t| pt|}!|!du rt }!t }"i d5|d6d7d|d#|d$|d%|d&|d'|d(|d|d|d|d |d)|d+|d8|!d9|d:|"i}#|r_|d7|d;}$n|ri|d7|d<}$n
|d7||!|||d=}$zt|$|#d>|"id?d@dA t|
kr|  W q[ ty }% zt|	dBk r|	|t |%dC W Y d}%~%q[d}%~%ww z|  W n% ty }% zt|	dBk r|	|dD|% dC W Y d}%~%nd}%~%ww dE|||	dFW S  ty     ty }% ztdG tdt |%dd}%~%ww )IzBackfill multi-month history.

    Zerodha APIs generally don't provide months of tradebook history.
    This endpoint lets the user import/exported transactions into Mongo.
    r   rt  Nr   z
Empty filer   z	utf-8-sigzlatin-1zCSV has no headerr   r_  r$   c                      s.   sd S  j dd t7   d S )NF)ordered)
bulk_writer  clearr1   r  opsrx  r1   r2   	flush_ops  s
   z3import_learning_transactions_csv.<locals>.flush_opsr6   r   trading_symbolr\   
instrumentr&   r   transactiontype
trade_type	tradetypebuy_sellr   r   r   r   
tradepricerater   avgpriceaveragepricer   r   r   r   r  auctionr  tradeidr  orderid
trade_date	tradedatedateorder_execution_timeorderexecutiontimeexecutiontimer*  timerT  r{  importr   r/   r  r  r  )rT  r{  r\   r   r   r   r   r   r  Tr     )rN   errorzbulk_write_failed: r[  )rJ  	processedrx  skippedry  z*Failed to import learning transactions CSV)r$   N)r)   rP   readr   decoder,   csv
DictReaderioStringIO
fieldnamesr~   rM   r<   r*   r_   rR   r]   r[   rY   rH   r   r   ri   r   r  ra  rb  )&r  r   rW  rT  	raw_bytestextreaderr  r  ry  
batch_sizer  rN   nrowrI   r0   rQ   r\   r   	side_normr   r   avgr   r   r   r   r  r  r  r  r  	exec_timer  r   re  r   rc  r1   r  r2    import_learning_transactions_csvu  s<  
	 	





	
	



r  z/analyze/{symbol}z#Analyze single symbol using ChatGPT)r!   payloadc           	   
      s   zRt || }|stddd|dpi }t|trM|d| p!d   |d}t|tr9|d|	  d|vrM|d}t|trM|rM||d< d	| |d
W S  ty[     t
yt } ztd|  tdt|dd}~ww )zDB-only analysis endpoint used by Stream UI.

    IMPORTANT: This endpoint must NOT call Zerodha or GPT.
    It returns the latest persisted analysis snapshot from
    `stock_analysis_snapshots` for the requested symbol.
      z"No analysis snapshot available yetr   r/  r\   r&   r*  market_datar[  )rJ  r\   r/  z+Failed to fetch DB analysis snapshot for %sr_  N)r-  r   rP   r<   r   r   r*   r]   r   r=   r,   ra  rb  r)   )	r\   r  r   rW  r.  r/  r   mdrc  r1   r1   r2   analyze_symbol(  s.   




r  z/alerts-legacyz*Get user-specific alerts (legacy, DB-only)r  zMax items per sectionc               
      sf  zt |d}t|d |ddddi}dd |D }|s0d	g g g g d
t dW S t|d dd|iidddd}dd |D  t|d dd|iidddd}dd |D } fdd|D }	i }
|	rd| v r|d |d|	iddg}|D ]}|dpd 	 }|r||
vr||
|< qg }g }g }g }|D ]} |}|sq|dpd 	 }|sqt|d d|idg
d}|sqt|||d }t|dkrt|||d nd}t|||d< ||pi }|d |d < |d!|d!< |
|}|r4|d"pd 	 }|d#v r)|| q|d$v r4|| q|d%p;d& 	 }t|d'pHd}|d(v rZ|dkrZ|| q|| qd)tt tf fd*d+}||||fD ]	}|j|d, qqd	|d|  |d|  |d|  |d|  d
t dW S  ty } ztd- td.t |d/d}~ww )0zDB-only alerts endpoint.

    Builds user-specific opportunities from:
    - `user_likes` (is_active=True)
    - latest `stock_analysis_snapshots`
    - optional `orders` for Triggered/Closed bucketing

    IMPORTANT: Must NOT call Zerodha or GPT.
    r   
user_likesT)rT  r   r   r6   c                 S   r  r  r  r  r1   r1   r2   re   c  r  z#get_user_alerts.<locals>.<listcomp>rG  )top_signals
monitoring	triggeredclosed)rJ  r^  r*  r   r  )r   r\   r   c                 S   "   i | ]}| d r| d |qS r  r  r   r1   r1   r2   r   n     " z#get_user_alerts.<locals>.<dictcomp>r  )r   r  r  c                 S   r  r  r  rc   rr1   r1   r2   r   s  r  c                    s4   g | ]}  |p
i  d r  |pi  d qS r^   r  )rc   r  by_stock_idr1   r2   re   v  s    r  rT  r\   r   r  r\   r&   r(  r)  r   r   Nwhat_changedr  r  rJ  )PLACEDOPEN	TRIGGERED)COMPLETECLOSED	CANCELLEDREJECTEDr0  r2  r3  ry   rN   c                 S   sL   |  d}t|trt|nd}t|  dpd}|  dpd}| ||fS )Nr  i'  r3  r&   r*  )rP   r<   r+   rE  )rN   r  rank_valconf_valr   r1   r1   r2   sort_key  s
   
z!get_user_alerts.<locals>.sort_keyr   zFailed to build alertsr_  r   )r)   rP   rh   r!  r   r   list_collection_namesr"  r*   r]   r  r;  r  rA  ri   rE  r	   r
   r,   ra  rb  r   ) r  r   rW  rT  likesr%  r   	live_rowslive_by_stock_idr\  latest_order_by_symbolr  or   r  r  r  r  r  r   r\   snapsr=  r<  r$  r  rJ  r0  confr  arrrc  r1   r  r2   get_user_alertsP  s   
 
$ 










r  z/stocks/searchzSearch stocks (shared catalog)r&   zSearch by symbol/name)ro  rp  r#  c              
      st   | pd  }|sdg dS t|dd}|d dd|id	|id
|igiddddddd|}dt|dS )Nr&   rG  )rJ  r~   r   r   r   r   r\   r    r   r   r6   r   r   r\   r   r   r    )r*   rJ   r   r!  r  rh   )r#  r  r   queryrxr  r1   r1   r2   search_stocks  s   
r  z/stocks/{symbol}zGet stock info (no analysis)z!1 to fetch live quote via Zerodhainclude_quotec                    s4  t || }d|d|d|d|d|d|d|d|d	|d
dd	d d}|dkrt||}t| }|dpEd  }|| d| g}	t|	trd|	| d| nd |d< |dst|dtr|d d}
|
r|d 	d|did|
t
 di |
|d d< |S )NrG  r   r\   r   r   r    r   r   r   r   T)	r   r\   r   r   r    r   r   r   r   )rJ  r   quoter6   r   r   r  r   r   r   )r   r   r   )r  rP   r   r_   r*   r]   r   r<   r   r   r   r   )r\   r  r   rW  r   rm   r   r   r   r   r  r1   r1   r2   get_stock_info  s<   


&r  z/portfolio/itemszAdd/Upsert portfolio itemc                    s  t |d}t|d}t| dp|}t| dr+|r+||kr+tdddt| d}| dp8d  }| d	pCd
  }t| d}	| dpUd pYd }
| dp`d pdd }|dvrotdddt|||d}|dszt	||}t
|||}W n ty   d }Y nw |r|dr|d d|did|d|dp|dp||dp|dp|t di |d|d< |dr|d|d< |dr|d|d< ntdddt }|||d|d|dp|||	|
||d
}|d ||ddt|}|rH|r.t|ds.||d< |d d|d id|i t |d }|d}n|d i |d|i}t |j}|}d|||d|d|dpn||d|d||	|
|||d d!S )"Nr   r     &account_id does not match current userr   r\   r   r   rJ  ACTIVEr`   nicknamer&   notesr  INACTIVEr   !status must be ACTIVE or INACTIVE)r   r   r   r   r   )r   r   r   r   zInstrument token not found for symbol in your Zerodha session. Verify the symbol/exchange and that your Zerodha connection is active.r   )
rT  r   r   r\   r   rJ  r`   r	  r
  r  user_portfolio_itemsrT  r   r   rG  r    portfolio_item_idr   r   r\   r   r   r    rJ  r`   r	  r
  r   r  rJ  item)r)   rP   rr   r   r_   r*   r]   rq   r  r   r   r,   r   r   r   r   r   r   r   )r  r   rW  rT  user_account_idr   r\   r   rJ  r`   r	  r
  r   r   resolvedr   re  existingitem_idr   r  r1   r1   r2   upsert_portfolio_item  s   




r  zList portfolio itemszSearch symbol/nicknamezFilter by tagzACTIVE or INACTIVEz5Account scope (defaults to current user's account_id))ro  tagrJ  skipc                    s  t |d}t|d}	t|p|	}
t|r%|	r%|
|	kr%tdddd|i}t|
g}|rD|  }|dvr@tdd	d||d
< |rP|pId  |d< | pSd }|rmt	|dd}|
dd|id|igi |rs||d< |d |ddg||}t|}dd |D }t|d dd|iiddddd}dd |D }g }|D ]M}|d}||pi }|
t |d|dp|
pd ||d|d |d!|d"|d
|dpg |d|d#|d$|d%d& q|d |}d'||d(S ))Nr   r   r  r  r   rT  r  r   r  rJ  r&   r`   r   r   r   r\   r	  z$andr  r  r  r  c                 S   r  r  r  rc   r   r1   r1   r2   re     r  z(list_portfolio_items.<locals>.<listcomp>r   r   r  r   r6   )r   r   r   r    c                 S   r  r  r  r   r1   r1   r2   r     r  z(list_portfolio_items.<locals>.<dictcomp>r   r   r    r
  r   r  r  rG  )rJ  r  r~   )r)   rP   rr   r   r   r*   r]   rL   rJ   r   ri   r!  r"  r  r  rh   r  )r#  r  rJ  r   r  r  r   rW  rT  r  effective_account_idr   and_clausesstr  r  r  r~   r%  r   r&  rm   r   r  r   r  r1   r1   r2   list_portfolio_itemsm  sn   

 
r   z$/portfolio/items/{portfolio_item_id}zUpdate portfolio itemr  c                    s  t |d}t|d}zt| }W n ty"   tdddw |d ||dt|}|s9tdd	dd
t	 i}|rLt|dsL||d< d|v ri|dpVd
  }	|	dvretddd|	|d< d|v rvt|d|d< d|v r|dpd
 }
|
pd |d< d|v r|dpd
 }|pd |d< |d ||dt|d|i |d ||dt|}dt |d|dp|pd |d|d|d|d|dpg |d|d|d|d
ddS )Nr   r   r   Invalid portfolio_item_idr   r  r   rT  r  Portfolio item not foundr  rJ  r&   r  r  r`   r	  r
  r   rG  r   r\   r   r   )r  r   r   r\   r   rJ  r`   r	  r
  r   r  r  )r)   rP   rr   r   r,   r   r   r   r   r   r*   r]   rq   r   )r  r  r   rW  rT  r   oidr  r  r  nickr
  rl  r1   r1   r2   update_portfolio_item  sd   r&  zDelete portfolio itemc                    s   t |d}t|d}zt| }W n ty"   tdddw |d ||dt|}|jdkr<td	d
ddddS )Nr   r   r   r!  r   r  r"  r6   r  r#  rG  T)rJ  deleted)	r)   rP   rr   r   r,   r   
delete_oner   deleted_count)r  r   rW  rT  r   r$  resr1   r1   r2   delete_portfolio_item   s   

r+  z/portfolio/tagszList user's tagsc                    s   t |d}t|d}t| p|}t| r%|r%||kr%tddddd|it|idd	id
d	ddididdddig}t|d |}ddd |D dS )Nr   r   r  r  r   z$matchrT  z$unwindz$tagsz$groupz$sumr6   )r   rk  z$sortr  )rk  r   r  rG  c                 S   s.   g | ]}| d r| d | dddqS )r   rk  r   )r  rk  r  r  r1   r1   r2   re   '  s   . z'list_portfolio_tags.<locals>.<listcomp>)rJ  r`   )r)   rP   rr   r   r   rh   	aggregate)r   r   rW  rT  r  r  pipelinerowsr1   r1   r2   list_portfolio_tags  s   r/  z/analyze/bulkzBulk analyze multiple symbolsc                    s   z.t ||}t||| dg | dd| dt| ddt|dd}d	t||d
W S  tyH } ztd t	dt|dd}~ww )z
    Bulk analyze multiple symbols
    Payload: {
        "symbols": ["RELIANCE", "TCS", "INFY"],
        "analysis_type": "short_sell" | "long_buy" | "general",
        "timeframes": ["5minute", "15minute"],
        "max_concurrent": 5
    }
    r\  analysis_typegeneral
timeframesmax_concurrent   r   r   r   r\  r0  r2  r3  rT  r[  )rJ  analyzedresultszBulk analysis failedr_  r   N)
r   r   rP   r   r)   r  r,   ra  rb  r   r  r   rW  r   rm  rc  r1   r1   r2   bulk_analyze)  s$   




	
r9  r/  r  c                 C   s&  |  dpd  }|  d}d }t|ttfr|r|d }i 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g d|  di d|  di d|  d|  dp|dd|  dd|S )Nr\   r&   r6  r   r  r0  r2  r3  r5  r   r7  r:  price_targetrisk_reward_ratiocurrent_pricemetrics)r0  r3  	rationalerV  technical_indicatorsr8  exitr*  r  )rP   r*   r]   r<   rh   r   )r/  r  r  r\   raw_targetsexit_targetr1   r1   r2   _format_analysis_for_stream_rowL  s\   





	




rD  z/portfolio/livez!On-demand portfolio live analysisz/Use cached analysis if within this many minutesz(Max ACTIVE portfolio symbols to considerfreshness_minutesc                    sZ  t |d}t|d}t tt|d }t|d |ddt	|
ddg|}|sAd	d
g dd
d
|t dS dd |D }	t|d dd|	iid
dddddd}
dd |
D }i }|	r|d d|	id|idd
dddd
dg}|D ]\}|d}||pi }|dpd  }|r||v rq|d}t|tsq|d| |d}t|tr|d|  |dd u r|dd ur|d|d< |||< qg }g }|D ]1}|d}||pi }|dp|dpd  }|sq|| ||vr|| q|rt||}t|||| d!p*d"| d#p1tt| d$p9d%|d&}t }|pFg D ]}t|tsQqG|dpXd  }|sbqGd }|D ]}|dpod  |kr~|d} nqf|sqGt|d'tr|d'nd }|r|d
 nd }|||d(|d)|d*|d+|d,p|d-p||d.d/||d0|d1d2}z	|d | W n ty   td3| Y nw |||< qGg }d}|D ]!}||}|rt|tsq|t||dd4 |d7 }qd	t||dt|t| t||t dS )5aR  Portfolio streaming endpoint.

    - Reads ACTIVE portfolio items for the current user/account.
    - Uses recent `stock_analysis_snapshots` (<= freshness_minutes) when available.
    - Otherwise calls the existing analysis engine (Zerodha + GPT) and persists a new snapshot.

    NOTE: This is intentionally NOT the movers endpoint.
    r   r   )minutesr  r  )rT  rJ  r  r  r[  r   	portfolio)rJ  scannedr7  r]  cachedcomputedrE  r*  c                 S   r  r  r  r  r1   r1   r2   re     r  z+portfolio_live_analysis.<locals>.<listcomp>r   r   r  r6   r  c                 S   r  r  r  r   r1   r1   r2   r     r  z+portfolio_live_analysis.<locals>.<dictcomp>r(  r  )r   r*  r   r   r*  r/  r)  r\   r&   r/  r*  r   Nr0  r1  r2  r3  r4  r5  r6  r0  r3  r7  r:  r:  targetr>  	PORTFOLIOr  rV  )r   r*  r0  r3  r8  r:  rL  reasonr]  r/  r  rV  z+Failed to persist portfolio snapshot for %sr  r  )r)   rP   rr   r   r   r   r+   rh   r!  r   r"  r  r*   r]   r<   r   r   r=   ri   r   r   r   r   r,   ra  rb  rD  r  )r  rE  r  r   rW  rT  r   r  r~   r%  r   r&  cached_by_symbolr  r.  r  r   r   r/  r   portfolio_symbols
to_computer   r   computed_resultsr   r6  primary_targetsnapshot_docformatted_resultsr  r1   r1   r2   portfolio_live_analysiso  s  








 





 
rW  z/signalsz"Get user's latest signals/analysiszMaximum number of signalszFilter by symbolz#Filter by decision: BUY, SELL, HOLDr0  c              
      s^   zt |t|d| ||d}d|dW S  ty. } ztd tdt|dd}~ww )	z7Get user's latest trading signals from ChatGPT analysisr   )r   rT  r  r\   r0  r[  )rJ  signalszFailed to get signalsr_  r   N)r   r)   rP   r,   ra  rb  r   )r  r\   r0  r   rW  rm  rc  r1   r1   r2   get_signals  s   	
rY  z/chat/{symbol}z(Interactive chat about a specific symbolc                    s   z&t ||}t||| |ddt|d|d|ddd}d|d	W S  tyC } ztd
|   tdt|dd}~ww )z
    Interactive chat about a symbol with real-time market data
    Payload: {
        "message": "What's the RSI looking like?",
        "include_fresh_data": true,
        "conversation_id": "optional-uuid"
    }
    rI  r&   r   conversation_idinclude_fresh_dataTr   r   r\   rI  rT  rZ  r[  r[  rJ  responsezChat failed for symbol r_  r   N)r   r   rP   r)   r,   ra  rb  r   )r\   r  r   rW  r   rm  rc  r1   r1   r2   chat_with_symbol,  s$   


	r_  z/learning/chat/{symbol}z:Learning chat about a trade/symbol (no fresh Zerodha data)c              
      sv   zt |d| |ddt|d|ddd}d|d	W S  ty: } ztd
|   tdt|dd}~ww )zLearning chat that stays within /learning.

    This endpoint does NOT require Zerodha access_token because it forces
    include_fresh_data=False and relies on DB snapshots + user-provided context.
    NrI  r&   r   rZ  Fr\  r[  r]  z Learning chat failed for symbol r_  r   )r   rP   r)   r,   ra  rb  r   )r\   r  r   rW  rm  rc  r1   r1   r2   learning_chat_with_symbolL  s"   
	r`  z/chat/{symbol}/historyzGet chat history for a symbolzMaximum messageszOptional conversation idrZ  c           
   
      s   z5t |d}|| d}|r||d< t|d |dd|}|D ]
}t |d |d< q&d|dW S  tyR }	 ztd	|   t	d
t |	dd}	~	ww )z&Get chat history for a specific symbolr   r  rZ  chatsr   r  r[  )rJ  historyzFailed to get chat history for r_  r   N
r)   rP   rh   r!  r"  r  r,   ra  rb  r   )
r\   r  rZ  r   rW  rT  r#  ra  chatrc  r1   r1   r2   get_chat_historyg  s   	
 re  z/order/placez%Place order based on ChatGPT analysisc                    s   z5t ||}t||t|d| d| d| d| dd| d| d| d	d
d
}d|dW S  ty>     tyV } ztd tdt|dd}~ww )aq  
    Place trading order with ChatGPT risk validation
    Payload: {
        "symbol": "RELIANCE",
        "action": "BUY" | "SELL",
        "quantity": 10,
        "order_type": "MARKET" | "LIMIT",
        "price": 2500.0,  // Required for LIMIT orders
        "analysis_id": "optional-analysis-reference",
        "confirm": true  // Required for execution
    }
    r   r\   r1  r   
order_typeMARKETr   r9  confirmF)
r   r   rT  r\   r1  r   rf  r   r9  	confirmedr[  )rJ  r  zOrder placement failedr_  r   N)r   r   r)   rP   r   r,   ra  rb  r8  r1   r1   r2   place_trading_order  s.   



rj  z/ordersGet user's order historyzMaximum orderszFilter by statusc           	   
      s   z4t |d}d|i}|r||d< t|d |dd| }|D ]
}t |d |d< q%d|dW S  tyN } ztd	 t	d
t |dd}~ww )rk  r   rT  rJ  r  r   r  r[  )rJ  r  zFailed to get ordersr_  r   Nrc  )	r  rJ  r   rW  rT  r   r  r  rc  r1   r1   r2   r    s    
r  z/livez(Legacy compatibility - get live analysiszNumber of symbols to analyzec                    s   zt | }|dkrt|d|t|d| d| }nt|||}|s*ddg dW S g }|D ]}t||}|s8q.|dp>i }	t|	tsEq.|	d	}
d}t|
ttfrY|
rY|
d }|i d
|	d
pc|	 
 dt|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ddddd
d|	dg d|	di d|	di d	|	d|dd |	d  q.dt||dW S  ty } ztd! td"t|d#d}~ww )$zDB-only legacy endpoint.

    IMPORTANT: Must NOT call Zerodha or GPT. Uses latest
    `stock_analysis_snapshots` for symbols in `live_movers`.
    r  r
  r  Nr[  r   )rJ  rH  r7  r/  r6  r\   r  r6   r0  r2  r3  r5  r   r7  r:  r:  r;  r<  r=  r   Fr&   )
r0  r3  volume_dropmomentum_dropema_gaprsi_divergencemacd_divergencewedgepivot_levelnear_upper_circuitr>  rV  r?  r@  r*  zLegacy live analysis failedr_  r   )r  r'  r-  rP   r<   r   rh   r   ri   r*   r]   r  r,   ra  rb  r   r)   )r  r  r   rW  r  r\  rV  r   r.  rm  rB  rC  rc  r1   r1   r2   get_live_analysis  s   "






	





!%
rt  z/nifty50/livez DB-only: latest NIFTY50 analysesz>Max NIFTY50 symbols to return (capped by NIFTY50_MAX_ANALYSES)c                    sj  z|d  ddi}t|tr|dnd}t|tr|s*ddg dt d	W S d
d |D }|dt|  }|sFddg dt d	W S t|d dd|iiddddddd}dd |D }dd |D   fdd|D }i }	|r|d dd|iiddddd	dg}
|
D ]\}|d}||pi }|dpd
  }|r||	v rq|d}t|tsq|d| |d}t|tr|d|  |ddu r|ddur|d|d< ||	|< qg }d}|D ]}|	|}|rt|tsq|t||dd |d7 }qdt||dt d	W S  ty4 } ztd tdt|d d}~ww )!zDB-only endpoint for the NIFTY50 tab.

    IMPORTANT:
    - Must NOT call NSE, Zerodha, or GPT.
    - Background loop populates `index_constituents` and writes snapshots.
    index_constituentsindexzNIFTY 50r\  Nr[  r   nifty50)rJ  rH  r7  r]  r*  c                 S   s(   g | ]}t | rt |  qS r1   )r)   r*   r]   r   r1   r1   r2   re   5  s   ( z$get_nifty50_live.<locals>.<listcomp>r   r\   r  r6   r  c                 S   r  r  r  r   r1   r1   r2   r   F  r  z$get_nifty50_live.<locals>.<dictcomp>c                 S   s6   i | ]}| d p
d r| d pd  |qS )r\   r&   r   r   r1   r1   r2   r   G  s   6 c                    s2   g | ]}  |r |  d r |  d qS r  r  r   	by_symbolr1   r2   re   H  s   2 r(  r   rK  r)  r&   r/  r*  r   rO  zFailed to get NIFTY50 liver_  r   )r   r<   r   rP   rh   r   r   r+   r!  r"  r*   r]   r   r=   ri   rD  r  r,   ra  rb  r   r)   )r  r   rW  re  r\  r  r   r&  r%  rP  r  r.  r  r   r   r/  r   rV  r  rc  r1   rx  r2   get_nifty50_live  s   










rz  z/profilezGet Zerodha profile statusc              
      s   z+t | |}z| }dd|dW W S  ty, } zddddW  Y d}~W S d}~ww  ty[ } z#|jd	krEddd
dW  Y d}~S |jdkrVddddW  Y d}~S  d}~w tyy } ztd ddt|dW  Y d}~S d}~ww )z-Get Zerodha profile and authentication statusrG  T)rJ  authenticatedprofiler  FzZerodha authentication required)rJ  r{  rI  Nr  Zerodha settings not foundr  zZerodha not authenticatedzProfile check failed)r   r|  r,   r   r   ra  rb  r)   )r   rW  r   r|  rc  r1   r1   r2   get_profile{  s8   




r~  z/stream/feedback/{analysis_id}zProvide feedback on analysisr9  c              
      s  zg| d}|dvrtddd|d d| i}|s'|d dt| i}|s/tdd	d| d
}|s<tdddt| d}t }|dk}	|d j||d|	||dd|iddd d|||	dW S  typ     ty }
 zt	d tdt|
dd}
~
ww )a.  Provide thumbs up/down feedback on analysis.

    Stored in `user_likes` as a per-user preference signal:
    - feedback="up"   -> is_active=True
    - feedback="down" -> is_active=False

    We resolve `stock_id` by looking up the snapshot that contains
    `analysis.analysis_id == analysis_id`.
    feedback)updownr   zfeedback must be 'up' or 'down'r   r(  zanalysis.analysis_idr  zAnalysis snapshot not foundr   zSnapshot missing stock_idr   r  r  r  )r   last_feedbackr  r   r  Tr  rG  )rJ  r  r   r   zFeedback update failedr_  N)
rP   r   r   r)   r   r   r   r,   ra  rb  )r9  r  r   rW  r  r.  r   rT  r   r   rc  r1   r1   r2   stream_feedback  sF   



r  z	/callbackzZerodha OAuth callbackc           
   
      s   zS|  d}t| d}|stddd|d d|i}|s'tdd	dd
dlm} ||d |d }||}|d d|id|d t	 ddi dddW S  ty\     t
yt }	 ztd tdt|	dd}	~	ww )zHandle Zerodha OAuth callbackrequest_tokenr   r   zMissing request tokenr   zerodha_settingsrT  r  r}  r   r   api_key
api_secretr   access_tokenactive)r  
login_timerJ  	connectedz!Zerodha authentication successful)rJ  rI  zOAuth callback failedr_  N)rP   r)   r   r   app.v1.services.zerodha.clientr   generate_sessionr   r   r   r,   ra  rb  )
r  r   rW  r  rT  settingsr   clientsessionrc  r1   r1   r2   oauth_callback  s8   

	
r  z	/postbackzZerodha postback handlerc              
         z8d| t  d}|d | | d}|r5|d d|id| d| d	d
| dt  di ddiW S  tyR } ztd tdt	|dd}~ww )z%Handle Zerodha postback notificationszerodhar]  r  received_atzerodha_postbacksr  r  zerodha_order_idr   rJ  filled_quantityr   r   rJ  r  r   r  receivedzPostback processing failedr_  r   N
r   r   r   rP   r   r,   ra  rb  r   r)   )r  r   postback_docr  rc  r1   r1   r2   zerodha_postback  0   




r  z/webhook/zerodhazZerodha order update webhookc              
      r  )z$Handle Zerodha order update webhooksr  r  webhooksr  r  r  r   rJ  r  r   r   r  r  zWebhook processing failedr_  r   Nr  )r  r   webhook_docr  rc  r1   r1   r2   zerodha_webhook	  r  r  )r   )t__doc__fastapir   r   r   r   r   r   r   typingr	   r
   r   r   loggingr   r   bsonr   rJ   r  r  pymongor   collectionsr   r'   app.dbr   app.v1.dependencies.authr   r  r   app.v1.services.teGPTr   r   r   r   r   r   r   r   r   r   router	getLogger__name__ra  r)   r+   r3   (DEFAULT_PORTFOLIO_LIVE_FRESHNESS_MINUTESDEFAULT_NIFTY50_MAX_ANALYSESr?   rC   rH   rM   rR   rW   rY   r[   r_   rq   rr   r}   r   r   r   r  r  r  r'  r,  r-  r;  rA  rE  rP   rO  rX  get_mongo_dbrd  rh  rj  postrn  r  r  r  r  r  r  r  r  r   r  r&  deleter+  r/  r9  rD  rW  rY  r_  r`  re  rj  r  rt  rz  r~  r  r  r  r  r1   r1   r1   r2   <module>   s  $0

*{
"1=6* 



"

 C
 3
'
x

+
e




N
C

*"#
 %







&



Sc 
8
&
"
