o
    ̿Si3                     @   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mZ ddl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 ddl m!Z!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/e,j0dddedddddedddddedddedddeej1eefde2de2dee3 de4fd d!Z5e,j6d"d#ded$d%deej1eefd&efd'd(Z7e,j0d)d*deddd+d,dedddd-dedddd.dedddd/dedd0dedd1deej1eefd2e2d3e2dee2 de2dee3 d4ee3 fd5d6Z8e,j6d7d8ded$eej1eefd9e
e3ef fd:d;Z9e,j0d<d=dedd>deej1eefdee3 fd?d@Z:e,j0dAdBdeej1eefdCe3fdDdEZ;e,j0dFdGdeej1eefdHdIZ<e,j=dFdJded$eej1eefd9e
e3ef fdKdLZ>e,j0dMdNdeddddOdeej1eefde2fdPdQZ?e,j6dRdSded$eej1eefdTe3d9e
e3ef fdUdVZ@dS )WzLLearning routes for platform teGPT.

NOTE: Move-only split from `teGPT.py`.
    )	APIRouterDependsHTTPExceptionBodyQueryFile
UploadFile)DictAnyListOptionalN)datetime	timedelta)ZoneInfo)ObjectId)	UpdateOne)database)get_current_userdetails)get_zerodha_client_servicechat_with_stock_service   )_compute_fifo_enrichment
_dt_to_iso_norm_account_id_norm_csv_key
_norm_side_norm_symbol	_parse_ts_parse_ts_flexible_pick_safe_float	_safe_intz/learning/transactionsz/Get user's recent Zerodha transactions (trades))summary2      zMax rows to return)geledescriptionx   im  z:How many days of history to return (ignored if day is set)z5IST date YYYY-MM-DD (filters transactions to one day))r'   Tz9Sync today's Zerodha trades/orders into DB before listinglimitdaysdaysyncc           )         s  zt |d|d tddt ffdd |pd }|r9zt|d W n ty8   td	d
dw d}t t	|d }  }|pJ|}	|	|k}
t
|oT|
}t
|dddg d|rj|
sjd d |rd}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rz | }t|trt|d< |D ]}t|tr|d| qW 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 |rhz-t|djddddd}|t	dd }|tdjdd }|tdjdd }W n tyB   d}d}Y nw d!|ig}|rb|rb|d"||d#i |d$||d#i |d%}nd"d&|iid"did"d'd(iigd%}t| |rd)ntd)|d* }|ddid+d,g|}t|}g }|D ]}|i d|dpd-d.|d.pdd/|d/d0|d0d1|d1d2|d2d3|d3d4|d4d5|d5d6|d6d7|d7d"|d"p|d$d8t|d"p	t|d$d9|d9d:|d:d;|d;d<|d<d=t|d=tr1|d=ni i qt|}t|d>d>d>ddd?}|D ]s}t|d1}t|d2p[d}t |d3} | du rot |d4} t!|t!| pwd> }!|d@kr|dA  |!7  < |dB  |7  < n|dCkr|dD  |!7  < |dE  |7  < t |dF}"|"dur|dF  t!|"7  < qIdGD ]}#t"t!||# dH||#< qt#|dIdJ dKdL}$g }%|$d|  D ]}t|d2}t |d3} | du rt |d4} |r| durt"|pd| pd> dHnd}&|%i d|dpd-d.|d.p&dd/|d/d0|d0d1t|d1d2|d2d3|d3d4|d4d5|d5d6|d6d7|d7d8|d8d9|d9d<|d<p||d=pyi d<d:|d:p|d=pi d:d;|d;p|d=pi d;dM|&|dF|dN|dO|dP|dQdR q߈$|}'dSdT||pd|t%|'|%dUW S  ty     ty }( zt&'dV tdWt |(dd}(~(ww )XzPersonal 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.
    _idlearning_transactionsAsia/Kolkatareturnc                      sF   zt  jtdd dW S  ty"   t  d Y S w )NUTCtzinfo%Y-%m-%d)r   utcnowreplacer   
astimezonestrftime	Exceptionnow )istr;   D/var/www/html/Trade-python/app/v1/routers/platform/teGPT_learning.py_today_ist_date>   s
   "z2get_learning_transactions.<locals>._today_ist_date r4      Invalid day; expected YYYY-MM-DDstatus_codedetailr*   r   )	attemptedtrades_seenorders_seenupsertserrorsrJ   !historical_day_sync_not_supportedNzerodha_client_unavailablekinditc           
         s  | dp| dp| dp| d}t|}| dp#| dp#d  }t }|p/|}z|jtdd		d
}W n t
yL     }Y nw i dd| d|d| dd| dd| dpjd pnd dt| ddt| ddt| d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_timestamp	timestamptradingsymbolsymbolr?   r1   r2   r4   user_idrM   exchangeproducttransaction_typequantitypriceaverage_pricetrade_idorder_idstatustsist_dateinstrument_tokentokenraw
updated_attraderU   rM   r\   rU   rM   r]   )rU   rM   rT   r_   
created_at$setz$setOnInsertTupsertrI   r   )getr   stripupperr   r5   r6   r   r7   r8   r9   r!   r    
update_one)
rM   rN   ts_rawts_dtrT   r:   effective_tsr`   dockeyr>   colr<   sync_reportrU   r;   r=   
upsert_onek   st   
  


	




z-get_learning_transactions.<locals>.upsert_onerG   re   trades_sync_failedrH   orderorders_sync_failedhourminutesecondmicrosecondr3   r   r1   r2   r`   r_   $gtez$ltrd   )rU   z$orr   z$existsFi  r#   )r_   r   )rd   r   u   —rT   rV   rW   rX   rY   rZ   r[   r\   r]   r^   rO   ra   segmentseriesisinrc           )rowsrealized_pnl	buy_value
sell_valuebuy_qtysell_qtyBUYr   r   SELLr   r   r   )r   r   r      c                 S   s   |  dptjS )Nr_   )rm   r   min)xr;   r;   r=   <lambda>  s    z+get_learning_transactions.<locals>.<lambda>T)ru   reversevaluematched_qtymatched_avg_entry_priceposition_afteropen_avg_price)r   r   r   r   r   successdb_learning_transactions)r^   sourcer*   r+   r"   totalr,   itemsz%Failed to fetch learning transactions  )(strrm   r   rn   r   strptimer9   r   r5   r   boolappendr   r	   r
   
get_trades
isinstancelistlendict
get_ordersr6   r7   maxr   findsortr)   r   r   r   r!   r    floatroundsortedcount_documentsintlogger	exception))r)   r*   r+   r,   dbcurrent_userday_normcutoff	today_istrequested_daycan_sync_requested_daysync_effectivezerodha_clientry   tradesrN   ordersday_start_istday_end_istday_start_utcday_end_utcorsqcompute_capcurdocs
base_itemsdenriched_allr"   sideqtypxvalrpkenriched_all_sortedr   r   r   er;   rv   r=   get_learning_transactions*   s  *
2









	 






	

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




"""


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-   r.   Nr@   z
Empty filerB   z	utf-8-sigzlatin-1zCSV has no headerr   r   r0   c                      s.   sd S  j dd t7   d S )NF)ordered)
bulk_writer   clearr;   rw   opsrI   r;   r=   	flush_opsk  s
   z3import_learning_transactions_csv.<locals>.flush_opsr   rS   trading_symbolrT   
instrumentr?   rX   transactiontype
trade_type	tradetypebuy_sellr   rY   r   rZ   
tradepricerater[   avgpriceaveragepricerV   rW   r   r   r   auctionr\   tradeidr]   orderid
trade_date	tradedatedateorder_execution_timeorderexecutiontimeexecutiontimerR   timerU   rM   importr_   rc   rd   rf   rg   )rU   rM   rT   r_   rX   rY   rZ   rh   ri   Trk      )rowerrorzbulk_write_failed: r   )r^   	processedrI   skippedrJ   z*Failed to import learning transactions CSV)r0   N)r   rm   readr   decoder9   csv
DictReaderioStringIO
fieldnamesr   r   r   rn   r   r   ro   r!   r    r   r   r5   r   r   r   r   r   )&r   r   r   rU   	raw_bytestextreaderr   r   rJ   
batch_sizer   r   nrowr   vnkrT   r   	side_normr   rZ   avgrV   rW   r   r   r   r   r\   r]   r   	exec_timerr   r:   rt   ru   r   r;   r   r=    import_learning_transactions_csvF  s<  
	 	





	
	



r  z/learning/paper-tradesz)Get user's paper trades (simulation only)i z1-indexed pagezRows per pagez(legacy) Max rows to returnz"How many days of history to returnz3Filter to a single day (YYYY-MM-DD) in Asia/Kolkataz Filter by status: OPEN or CLOSEDpage	page_sizer^   c                    s  zt |d}t|d}	td}
|r`ztt | }W n ty/   tdddw |j	dddd|
d}|t
d	d
 }|tdj	d d}|tdj	d d}|||dd}nt t
|d
 }|d|id}|	rv|	|d< |rt |  |d< t|tr|dkrd	} t|}tdt| d	 t| }|d |dg|t|}t|}g }|D ]}|i d|dpt |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"t|d"t|d#t|d$|d%|d&|d'|d(|d)|d*|d+|d,|d-t|d.|d/d0 q|d |}t|dkrtt|t| d	 t| nd	}d1d2||rt | nd t|t| t|t||d3	W S  ty } ztd4 td5t |dd }~ww )6Nr-   
account_idr/   r@   rA   rB   r   r}   r   rE   r1   r2   r   )rU   rh   r   r^   paper_trades)rh   paper_trade_idrT   stock_id	directionr   	signal_idsnapshot_idsignal_strengthdecision_probabilityentry_price	stop_losstargetrY   trade_valuereserved_amountrh   	opened_at	closed_at
exit_priceexit_reasonr   realized_pnl_per_unitcurrent_unrealized_pnlcurrent_unrealized_pnl_per_unitmax_favorable_movemax_adverse_movelast_price_closelast_candle_tslast_candle_timeframe)r  r  r  r  r   r  r  r  r  r   r!  r"  r#  r   db_paper_trades)	r^   r   r*   r+   r   r  r  total_pagesr   z%Failed to fetch learning paper tradesr   )r   rm   r   r   r   fromisoformatrn   r9   r   r6   r   r7   r5   ro   r   r   r   r   r   skipr)   r   r   r   r   r   r   )r  r  r)   r*   r+   r^   r   r   rU   r	  tzbasestart_local	end_local	start_utcend_utcr   r   r'  r   r   r   r   r   r%  r   r;   r;   r=   get_learning_paper_trades  s   &







	







#2
r.  z/learning/paper-trades/manualzCreate a manual paper tradepayloadc                    s  zt |d}t|d}t | dpd  }t | dp)| dp)d  }| d}| d}| d	}	| d
}
| d}| d}ddlm} ||||||t|	t|
t|t||d urmt |nd |d urvt |nd d}t	|t
r|dsdt	|t
r|ddW S ddW S d|ddW S  ty     ty } ztd tdt |dd }~ww )Nr-   r	  rT   r?   r  r   r  r  r  r  r  rY   r   )create_manual_paper_trade)
rU   r	  rT   r  r  r  r  rY   r  r  okr   reasonFAILED)r^   r   r   r  )r^   r  z#Failed to create manual paper trader   rB   )r   rm   r   rn   ro   app.v1.services.paper_tradingr0  r   r   r   r   r   r9   r   r   )r/  r   r   rU   r	  rT   r  r  r  r  r  r  rY   r0  resr   r;   r;   r=   "create_manual_paper_trade_endpoint[  sH   $





&
r6  z/learning/paper-dayz*Paper trades + balance statement for a dayz*YYYY-MM-DD in Asia/Kolkata (default today)c              	      s  t |d}t|d}|stdddtd}t jtdd|}| rJzt	t | 
 }W n tyB   tdd	dw |j|d}n|}|jd
d
d
d
d}	|	tdd }
|	tdjdd}|
tdjdd}|	d}|	tdd d}d
dlm}m} ||||d}|| |||dpi }|| |||dpi }|d}|du r|d}|du r|d}||||dd}t|d |ddd}d}d
}|D ]0}t |dpd dkr|d7 }|d}z||durt|nd7 }W q ty   Y qw d}z|durt|t| nd}W n ty-   d}Y nw d||t||t|t|d |d!|d"|d#|dd$d%S )&zDay-based view for intraday-only paper trading.

    Returns a statement:
    - start balance (previous day close if available)
    - realized pnl for the day (closed trades)
    - end balance (= start + realized)
    - trades created that day
    r-   r	  r@   account_id missingrB   r/   r1   r2   rA   r   )r~   r   r   r   r   rE   Nr4   )get_or_create_paper_accountPAPER_BALANCE_DAILY_COLLECTIONrU   r	  )rU   r	  r+   balance_openbalance_closestarting_balancer   rU   r	  rh   r
  )r   r^   r   r^   r?   OPENr   r   )r;  pnl_day_realizedr<  r   open_tradesbalancereserved_balanceavailable_balancerB  rC  rD  r=  )r^   r+   	statementaccount)r   rm   r   r   r   r   r5   r6   r7   r&  rn   r9   r   r8   r4  r8  r9  find_oner   r   ro   r   r   r   )r+   r   r   rU   r	  r(  	now_localr)  	day_localr*  r+  r,  r-  day_keyprev_keyr8  r9  accdailyprevstart_balancer   r   realized
open_counttpend_balancer;   r;   r=   get_paper_day_statement  s~   




"rV  z-/learning/paper-trades/snapshot/{snapshot_id}z.Get stored analysis snapshot for a paper trader  c                    s  t |d}t|d}| pd }|stddd||d}|r(||d< |d |dd	i}|s:td
ddzt|}W n tyM   tdddw |d d|i}	|	s_td
ddt|	dt	rl|	dni }
t|	dt	rt|
dt	s|	d|
d< t|	dt	rt|
dt	s|	d|
d< |
dpd 
 }|sz%|d d|	didd	i}|r|drt |d 
 |
d< W n	 ty   Y nw dt |	d|	dt|	d|	d|
ddS )z_DB-only: returns the exact `stock_analysis_snapshots` doc referenced by the user's paper trade.r-   r	  r?   r@   zsnapshot_id is requiredrB   )rU   r  r
  r   i  zPaper trade snapshot not foundzInvalid snapshot_idstock_analysis_snapshotszSnapshot not foundanalysismarket_datafeaturesrT   stocksr  r   rR   r   )r  r  rR   r   rX  )r^   snapshot)r   rm   r   rn   r   rH  r   r9   r   r   ro   r   )r  r   r   rU   r	  snap_idr   ptoidsnaprX  rT   stockr;   r;   r=   get_paper_trade_snapshot  sV   
  rb  z/learning/paper-accountz'Get user's paper trading account (game)c                    s   zYt |d}t|d}|stdddddlm} || ||d}d	|d
p1| d| |d|d|d|dt|dtrN|dni t|dddW S  tyb     t	yz } zt
d tdt |dd }~ww )Nr-   r	  r@   r7  rB   r   )r8  r:  r   paper_account_id:r=  rB  rC  rD  settingsrd   rc  r=  rB  rC  rD  re  rd   r^   rG  zFailed to fetch paper accountr   )r   rm   r   r   r4  r8  r   r   r   r9   r   r   )r   r   rU   r	  r8  rM  r   r;   r;   r=   get_paper_account   s2   
rh  z.Update paper trading account (balance + rules)c                     s2  zt |d}t|d}|stdddddlm}m}m}m} ||||d}	|| }
| d	}| d
}t	| dt
rG| dnd }d| i}i }|d urh d}i }| D ]\}}||vrgq^|dkrz t|}||kr|tdtdfvrtdtdt|||< W n	 ty   Y q^w q^|dkrt	|trdd |D }dd |D }|r|||< q^|dkrt	|trdd |D }dd |D }dd |D }|r|||< q^|||< q^t
|	dpi }|| ||d< dd }||	d	pd}||	dpd}|d ur&||}|d u s|dk r tdddt||d
< |d urh||}|d u s9|dk r?tdddtt|t|}t||d	< ttd|| |d < | d!t|t|t|d"}t|d#kr}|s}d$d%|	d%id&W S d'|i}|rd(|i|d)< |
||d| |d urt|d	p|}||||| t|t|| d*d+ |
||dpi }d$|d%p| d,| |d
|d	|d|d t	|dt
r|dni t|dd-d&W S  ty     ty } ztd. td/t |dd }~ww )0Nr-   r	  r@   r7  rB   r   )PAPER_ACCOUNTS_COLLECTIONr8  _upsert_daily_balance_now_utcr:  rB  r=  re  rd   >
   rW   sourceseod_exit	decisions	min_scoremax_loss_pctmax_quantitymax_profit_pctmax_trade_valuemin_trade_valuero  inf-infr         Y@rl  c                 S       g | ]}t |pd   qS r?   r   rn   ro   .0r   r;   r;   r=   
<listcomp>       z(update_paper_account.<locals>.<listcomp>c                 S      g | ]}|d v r|qS )>   LOSERGAINERMANUALEARLY_MOVERSr;   r{  r;   r;   r=   r}        rn  c                 S   rx  ry  rz  r{  r;   r;   r=   r}    r~  c                 S   s(   g | ]}|d kr
dn|dkrdn|qS )LONGr   SHORTr   r;   r{  r;   r;   r=   r}    s   ( c                 S   r  )>   r   r   r;   r{  r;   r;   r=   r}    r  c                 S   sF   zt | }||ks|t dt dfv rW d S |W S  ty"   Y d S w )Nru  rv  )r   r9   )r   fr;   r;   r=   	_to_float  s   z'update_paper_account.<locals>._to_floatrC  zstarting_balance must be >= 0zbalance must be >= 0rD  MANUAL_EDIT)r_   typebalance_beforebalance_afterreservedr   r   rc  rg  rj   eventsz$pushMANUAL_BALANCE_EDIT)rU   r	  dt_utcrB  deltar2  rd  rf  zFailed to update paper accountr   )r   rm   r   r   r4  ri  r8  rj  rk  r   r   r   r   r   r   r9   r   updater   rp   rH  r   r   r   ) r/  r   r   rU   r	  ri  r8  rj  rk  rM  rw   next_balancenext_startingnext_settingsupdatespushesallowed	sanitizedr   r  vvvalsmergedr  
bal_beforer  sbnbupd_docnb2acc2r   r;   r;   r=   update_paper_accountA  s   






	





r  z/learning/paper-game/summaryz"Paper trading gamification summaryzHistory window for totalsc                    s(  zt |d}t|d}|stdddddlm}m}m} ||||d}t	 t
| d	 }	||d
|	id}
t|d |
}t|d i |
ddi}i |
ddi}t|d |ddd}t|}d}d}|| }d}|D ]?}|d}z|d urt|nd}W n ty   d}Y nw ||7 }|dkr|d7 }|d}t|tr|||kr||7 }qx|dkrt|t| d nd}d|d|d|d|dd|||t|t|t|t|t| ddW S  ty     ty } ztd tdt |dd }~ww ) Nr-   r	  r@   r7  rB   r   )r8  _paper_day_keyrk  r:  rE   r   r>  r
  r^   r?  CLOSEDr   )r   r  r   r   r  rw  r   rB  rC  rD  r=  rE  )total_tradesrA  closed_tradespnl_sumwinswin_pct	today_pnlr*   )r^   rG  metricsz$Failed to compute paper game summaryr   )r   rm   r   r   r4  r8  r  rk  r   r5   r   r   r   r   r   r   r   r9   r   r   r   )r*   r   r   rU   r	  r8  r  rk  rM  r   qbaser  rA  closed_qclosed_docsclosed_countr  r  	today_keyr  r   rT  pfcar  r   r;   r;   r=   get_paper_game_summary  sr   


 
r  z/learning/chat/{symbol}z:Learning chat about a trade/symbol (no fresh Zerodha data)rT   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.
    Nmessager?   r-   conversation_idF)r   r   rT   r  rU   r  include_fresh_datar   )r^   responsez Learning chat failed for symbol r   rB   )r   rm   r   r9   r   r   r   )rT   r/  r   r   resultr   r;   r;   r=   learning_chat_with_symbol)  s"   
	r  )A__doc__fastapir   r   r   r   r   r   r   typingr	   r
   r   r   loggingr   r   zoneinfor   bsonr   r   r   pymongor   app.dbr   app.v1.dependencies.authr   app.v1.services.teGPTr   r   teGPT_helpersr   r   r   r   r   r   r   r   r   r    r!   router	getLogger__name__r   rm   get_mongo_dbr   r   r   r   postr  r.  r6  rV  rb  rh  putr  r  r  r;   r;   r;   r=   <module>   s    $4


  
 2

b
.
Z: 
 "E
