o
    §�¿jX ã                "   @   sŽ
  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZ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Zd dlmZ d dlmZ d dlmZ d dlmZ d dlZd d	lm Z!m"Z"m#Z# d
Z$e j%dkrvdZ&ndZ&e d¡Z'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2dZ3dZ4dZ5dZ6dZ7dZ8d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/d0d1d2d œd3d4d5d6d œd7d8ddd œd9d:d;d<d œd=d>d?dd œd@dAdBdd œdCdDdEd2d œdFdGdHdId œdJdKdLdMd œdNdOdPdQd œdRdSdTdMd œdUdVdWdXd œdYdZd[d+d œd\d]d^d_d œd`dadbdcd œdddedfd+d œdgdhdfdid œdjdkdldmd œdndodldMd œdpdqdldmd œgZ9dddrdd œd!d"dsd$d œd%d&dtdd œd(d)dud+d œd,d-dvd+d œd/d0dwd2d œd3d4dxd6d œd7d8dydd œd9d:d5d<d œd=d>dzdd œd@dAd{dd œdCdDd|d2d œdFdGd;dId œdJdKd?dMd œdNdOdHdQd œdRdSdLdMd œdUdVd}dXd œdYdZd~d+d œd\d]dTd_d œd`dadWdcd œddded[d+d œdgdhd^did œdjdkdbdmd œdd€dbdMd œdpdqdbdmd œd�d‚dWdId œdƒd„dfdd œd…d†dld2d œd‡dˆdld+d œd‰dŠd‹dŒd œgZ:h d�£Z;dŽd�d�d‘d’d“d”œZ<e=e< >¡ ƒZ?d•d–hZ@eƒ ZAeAjBed—gd˜d—gd—gd™� ee jC Ddš¡d›dœ�ZEi ZFd�dž„ ZGdŸd „ ZHd¡d¢„ ZI�d]d£d¤„ZJd¥d¦„ ZKd§d¨„ ZLd©eMdªeNfd«d¬„ZO�d^d©eMd®ePd¯e=fd°d±„ZQeLƒ  g d²¢ZRg d³¢ZSd´eMd¯eTfdµd¶„ZUd©eMd·eMd¯eTfd¸d¹„ZVe(fdºePd¯eWfd»d¼„ZXd¯eTfd½d¾„ZY�d_d©eMd¯eNfd¿dÀ„ZZ�d`dÁdÂ„Z[dÃdÄ„ Z\�d_dÅeMd¯eNfdÆdÇ„Z]�d^d©eMdÈePd¯e=fdÉdÊ„Z^�dad©eMdÌePd¯e=fdÍdÎ„Z_dÏdÐdÑœZ`g dÒ¢dÓdÔgg dÕ¢g dÖ¢g d×¢dØdÙgd”œZadÚeMd¯eMfdÛdÜ„Zb�dbd©eMdÞePd¯eMfdßdà„Zc�dcd©eMdâeWd¯eNfdãdä„Zdi Zedåe=d¯eNfdædç„ZfdèeNd¯eNfdédê„Zgd¯e=fdëdì„Zhdídî„ Zieiƒ  dïdð„ Zjdñdò„ Zkdódô„ Zldõdö„ Zmd÷dø„ Zndùdú„ Zodûdü„ Zp�dddþdÿ„Zq�de�d �d„Zr�df�d�d„Zs�d�d„ ZteA D�d¡�d�d„ ƒZueA D�d	¡d©eMf�d
�d„ƒZveA D�d¡�d^d©eMd®ePf�d�d„ƒZweA D�d¡d©eMf�d�d„ƒZxeA D�d¡dÅeMf�d�d„ƒZyeA D�d¡�d�d„ ƒZzeA D�d¡�d�d„ ƒZ{eA D�d¡�d�d„ ƒZ|eA D�d¡�df�deT�d eTf�d!�d"„ƒZ}eA D�d#¡�d$�d%„ ƒZ~eA D�d&¡�dg�d'ePf�d(�d)„ƒZeA D�d*¡�d+�d,„ ƒZ€eA D�d-¡�df�deT�d eTf�d.�d/„ƒZ�eA D�d0¡�d1�d2„ ƒZ‚eA D�d3¡�d4�d5„ ƒZƒee'�d6�Z„e„j…ete�d7�d8d e'�d9��d:�d;d˜�d<� e„j…ete�d7�d=�d>e'�d9��d?�d@d˜�d<� e„j…ete�d7�dA�d>e'�d9��dB�dCd˜�d<� e†�d8�dDƒD ]_Z‡�dED ]XZˆe‡�d8k�r”eˆ�d>k �r”�q„e‡�dAk�r¢eˆ�d>k�r¢�q„z/e„j…ese�d7e‡eˆde'�dF��dGe‡�dH›eˆ�dH›��dIe‡�dH›�dJeˆ�dH›�d˜�dK�dL� W �q„ e‰�yÜ   Y �q„w �qe„j…ese�d7�dD�d>de'�dF��dM�dNd˜�dO�dL� e„ Š¡  e‹�dPe$› �ƒ e‹�dQƒ e‹�dRƒ e‹�dSƒ e‹�dTƒ e‹�dUƒ �dV�dW„ ZŒej�eŒd˜�dX� Š¡  eŽ�dYk�rEd dl�Z�e�j�eA�dZ�d[�d\� dS dS (h  é    N)ÚdatetimeÚ	timedeltaÚtimezone)ÚFastAPI)ÚCORSMiddleware)ÚOpenAI)ÚYouTubeTranscriptApi)ÚBackgroundScheduler)ÚCronTrigger)Úget_unique_stocksÚ	MIN_PRICEÚ	MAX_PRICEzv1.0.0ÚntÚpythonz%/home/dinkstrade/pdmp/venv/bin/pythonzAsia/Kolkataé   iô  é   gš™™™™™©?ç      @g      Ð?ç      à?g333333ë?gÍÌÌÌÌÌì?é   éH   zsentiment_history.dbzzones_15m.dbúHDFCBANK.NSz	HDFC Bankgffffff"@ÚBanks)ÚsymbolÚnameÚweightÚsectorúRELIANCE.NSÚRelianceg333333 @ÚEnergyúICICIBANK.NSz
ICICI Bankgš™™™™™@zINFY.NSÚInfosysg333333@ÚITzTCS.NSÚTCSgÍÌÌÌÌÌ@zITC.NSÚITCgffffff@ÚFMCGzLT.NSzL&Tg      @ÚInfrazSBIN.NSÚSBIzBHARTIARTL.NSzBharti Airtelg333333@ÚTelecomzAXISBANK.NSz	Axis Bankgš™™™™™@zKOTAKBANK.NSzKotak MahindragÍÌÌÌÌÌ@zHINDUNILVR.NSÚHULg      @zBAJFINANCE.NSzBajaj Financeg333333@ÚNBFCz	MARUTI.NSzMaruti Suzukigš™™™™™@ÚAutozASIANPAINT.NSzAsian Paintsg       @ÚPaintszM&M.NSzM&MgÍÌÌÌÌÌü?zSUNPHARMA.NSz
Sun Pharmag333333û?ÚPharmaz
HCLTECH.NSzHCL Techgš™™™™™ù?zTITAN.NSÚTitanç      ø?ÚConsumerzULTRACEMCO.NSzUltraTech Cementgffffffö?ÚCementzWIPRO.NSÚWiprogÍÌÌÌÌÌô?zADANIENT.NSzAdani EnterprisesÚConglomeratezNTPC.NSÚNTPCg333333ó?ÚPowerzBAJAJ-AUTO.NSz
Bajaj AutozPOWERGRID.NSz
Power Gridg      +@g      (@g      "@gÍÌÌÌÌÌ@gÍÌÌÌÌÌ@g333333@g      @gš™™™™™@gffffff
@gš™™™™™	@gÍÌÌÌÌÌ@gÍÌÌÌÌÌ @gffffffþ?zHEROMOTOCO.NSzHero MotoCorpzBAJAJFINSV.NSzBajaj FinservzINDUSINDBK.NSzIndusInd BankzNESTLEIND.NSzNestle IndiazTECHM.NSzTech MahindrazTATASTEEL.NSz
Tata Steelgš™™™™™ñ?ÚMetals>   r   r   r   z"Nifty 50" stock market Indiaz4"Sensex" OR "BSE Sensex" -defence -bankex -auto -PSUz!"gold rate" OR "gold price" Indiaz%"silver rate" OR "silver price" Indiaz3"Crude Oil" OR "Crude price" OR "Brent crude" Indiaz"Bitcoin price" cryptocurrency)ÚNIFTYÚSENSEXÚGOLDÚSILVERÚCRUDEOILÚBITCOINr6   r7   Ú*T)Úallow_originsÚallow_credentialsÚallow_methodsÚallow_headersÚGROQ_API_KEYzhttps://api.groq.com/openai/v1)Úapi_keyÚbase_urlc                  C   sV   t  t¡} |  ¡ dkrdS | jddddd�}| jddddd�}||   ko(|kS   S )Né   Fé	   é   r   )ÚhourÚminuteÚsecondÚmicrosecondé   )r   ÚnowÚISTÚweekdayÚreplace)rL   Úmarket_openÚmarket_close© rR   ú/home/dinkstrade/pdmp/main.pyÚis_market_hours_now·   s   
rT   c                 C   s�   t ƒ }|  d¡r|rdS dS |  d¡r|rdS dS | dkr#|r!dS dS | dkr-|r+d	S dS |  d
¡r8|r6d	S dS | dkrB|r@dS dS |rFdS dS )NÚoption_chain_é´   i  Úconstituents_ÚrangeéX  i  Úfii_dii_scorei„  Ú
sentiment_Úlatest_scani,  )rT   Ú
startswith)ÚkeyrP   rR   rR   rS   Ú_auto_ttl_for_key¿   s   


r_   c                 C   s4   | t v rt |  \}}}t ¡ | |k r|S t | = d S ©N)ÚCACHEÚtime)r^   ÚvalueÚ	timestampÚttlrR   rR   rS   Ú	cache_getÏ   s   rf   c                 C   s&   |d u rt | ƒ}|t ¡ |ft| < d S r`   )r_   rb   ra   )r^   rc   Úttl_secondsrR   rR   rS   Ú	cache_setØ   s   rh   c                 C   s   | t v r
t |  d S d S )Nr   )ra   ©r^   rR   rR   rS   Ú
cache_peekÝ   s   rj   c                  C   sT   t  t¡} |  ¡ }| d¡ z| d¡ W n
 t jy   Y nw |  ¡  |  ¡  d S )Nac  
        CREATE TABLE IF NOT EXISTS daily_sentiment (
            date TEXT NOT NULL,
            symbol TEXT NOT NULL,
            score REAL NOT NULL,
            news_score REAL,
            twitter_score REAL,
            youtube_score REAL,
            fii_dii_score REAL,
            label TEXT,
            PRIMARY KEY (date, symbol)
        )
    z9ALTER TABLE daily_sentiment ADD COLUMN fii_dii_score REAL)Úsqlite3ÚconnectÚSENTIMENT_DB_PATHÚcursorÚexecuteÚOperationalErrorÚcommitÚclose)Úconnrn   rR   rR   rS   Úinit_sentiment_dbå   s   

ÿrt   r   Úresultc                 C   sÀ   t  t¡ d¡}z:t t¡}| ¡ }| d|| | 	dd¡| 	dd¡| 	dd¡| 	dd¡| 	dd¡| 	d	d
¡f¡ | 
¡  | ¡  W d S  ty_ } ztd| › d|› �ƒ W Y d }~d S d }~ww )Nz%Y-%m-%dzÊ
            INSERT OR REPLACE INTO daily_sentiment
            (date, symbol, score, news_score, twitter_score, youtube_score, fii_dii_score, label)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        Úscorer   Ú
news_scoreÚtwitter_scoreÚyoutube_scorerZ   ÚlabelÚNEUTRALzSentiment DB save error for ú: )r   rL   rM   Ústrftimerk   rl   rm   rn   ro   Úgetrq   rr   Ú	ExceptionÚprint)r   ru   Útodayrs   rn   ÚerR   rR   rS   Úsave_to_historyü   s(   






ùü"€ÿrƒ   é   ÚdaysÚreturnc              
   C   s„   z#t  t¡}| ¡ }| d| |f¡ | ¡ }| ¡  dd„ t|ƒD ƒW S  tyA } zt	d| › d|› �ƒ g W  Y d }~S d }~ww )Nz”
            SELECT date, score, label FROM daily_sentiment
            WHERE symbol = ?
            ORDER BY date DESC
            LIMIT ?
        c                 S   s$   g | ]}|d  |d |d dœ‘qS )r   é   r   )Údaterv   rz   rR   ©Ú.0ÚrrR   rR   rS   Ú
<listcomp>  s   $ zget_history.<locals>.<listcomp>zSentiment DB read error for r|   )
rk   rl   rm   rn   ro   Úfetchallrr   Úreversedr   r€   )r   r…   rs   rn   Úrowsr‚   rR   rR   rS   Úget_history  s   
û€þr�   )ÚfallÚfallsÚcrashÚcrashesÚplungeÚplungesÚdropÚdropsÚdeclineÚdeclinesÚslumpÚslumpsÚweakÚlossÚlossesÚdownÚbearishzsell-offÚselloffÚtumbleÚtumblesÚslide)ÚriseÚrisesÚsurgeÚsurgesÚgainÚgainsÚjumpÚjumpsÚrallyÚralliesÚhighÚrecordÚstrongÚupÚbullishÚsoarÚsoarsÚclimbÚclimbsÚrecoverÚrecoversÚtextc                    sn   |   ¡ ‰ t‡ fdd„tD ƒƒ}t‡ fdd„tD ƒƒ}|| }|dkr$dS || | d }ttdtd|ƒƒdƒS )	Nc                 3   ó   � | ]}ˆ   |¡V  qd S r`   ©Úcount©rŠ   Úw©Ú
text_lowerrR   rS   Ú	<genexpr>2  ó   € z keyword_score.<locals>.<genexpr>c                 3   r¼   r`   r½   r¿   rÁ   rR   rS   rÃ   3  rÄ   r   ç        é
   iöÿÿÿr‡   )ÚlowerÚsumÚBULLISH_WORDSÚBEARISH_WORDSÚroundÚmaxÚmin)r»   ÚbullÚbearÚtotalrv   rR   rÁ   rS   Úkeyword_score0  s   rÑ   Ú
text_blockc              
   C   s
  t j d¡r
| ¡ st|ƒS d| › d|d d… › d�}zHtjjjdddd	œd
dd	œddd	œd
dd	œd|d	œgddddid�}|j	d j
j ¡ }t d|¡}|r_ttdtdt| ¡ ƒƒƒdƒW S t|ƒW S  ty„ } ztd| › d|› d�ƒ t|ƒW  Y d }~S d }~ww )NrA   z2Analyze the sentiment of the following text about zW.
Rate from -10 (very bearish) to +10 (very bullish). Reply with only a number.

Text:
i¸  z

Sentiment score:zopenai/gpt-oss-120bÚuserz6Analyze: 'Nifty hits all-time high on strong earnings')ÚroleÚcontentÚ	assistantÚ7z-Analyze: 'Market crashes on weak global cues'z-6ç333333Ó?é2   Úreasoning_effortÚlow)ÚmodelÚmessagesÚtemperatureÚ
max_tokensÚ
extra_bodyr   z-?\d+\.?\d*ç      $Àç      $@r‡   ú[z] AI error: z. Using keyword fallback.)ÚosÚenvironr~   ÚstriprÑ   ÚclientÚchatÚcompletionsÚcreateÚchoicesÚmessagerÕ   ÚreÚsearchrË   rÌ   rÍ   ÚfloatÚgroupr   r€   )r   rÒ   ÚpromptÚresponseÚrawÚmatchr‚   rR   rR   rS   Úai_sentiment=  s8   
üûõ 
€þrõ   Úmax_age_hoursc                 C   sd   t | dd ƒ}|s
dS zt|d d… dtjiŽ}W n
 ty"   Y dS w t tj¡t|d� }||kS )NÚpublished_parsedTé   Útzinfo©Úhours)Úgetattrr   r   Úutcr   rL   r   )Úentryrö   Ú	publishedÚpublished_dtÚcutoffrR   rR   rS   Úis_freshd  s   ÿr  c               
   C   sÐ  d} t | ƒ}|d ur|S z¼ddddœ}tjd|dd�}|jd	kr0td
|j› �ƒ t| dƒ W dS | ¡ }t|tƒr?t	|ƒdkrGt| dƒ W dS d }d }|D ]=}t
| dd¡ƒ ¡ }t
| dd¡ƒ dd¡ ¡ }	zt|	ƒ}
W n tyx   d}
Y nw d|v s�d|v r„|
}qMd|v rŠ|
}qM|d u s“|d u r›t| dƒ W dS || }tdtd|t ƒƒ}t|dƒ}td|d›d|d›d|d›d|› �ƒ t| |ƒ |W S  tyç } ztd|› �ƒ t| dƒ W Y d }~dS d }~ww )NrZ   zoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36zapplication/jsonzhttps://www.nseindia.com/)z
User-AgentÚAcceptÚRefererz-https://www.nseindia.com/api/fiidiiTradeReactrÆ   )ÚheadersÚtimeoutéÈ   u#   âš ï¸� FII/DII NSE returned status rÅ   r   ÚcategoryÚ ÚnetValueÚ0ú,ÚFIIÚFPIÚDIIrá   râ   r‡   z[FII/DII] FII net: ú+.2fz cr | DII net: z cr | Combined: z cr | Score: u   âš ï¸� FII/DII fetch error: )rf   Úrequestsr~   Ústatus_coder€   rh   ÚjsonÚ
isinstanceÚlistÚlenÚstrÚupperrO   ræ   rï   Ú
ValueErrorrÌ   rÍ   ÚFII_DII_SCALErË   r   )Ú	cache_keyÚcachedr  r‹   ÚdataÚfii_netÚdii_netÚrowr  Únet_strÚnetÚcombined_netrv   r‚   rR   rR   rS   Úfetch_fii_dii_scorer  sp   üý


ÿ€

ÿÿ

€ýr$  c                 C   s   d| › �}t |ƒ}|d ur|S z}tj tj tj t¡¡d¡}tjt	|| gdddd�}|j
dkrV|j ¡ p6d}td|d d	… › �ƒ t|d
|d d	… iƒ d
|d d	… iW S t |j ¡ ¡}t||ƒ td| › d| d¡› d| di ¡ d¡› d| di ¡ d¡› d| d¡› �
ƒ |W S  tjy¨   td| › �ƒ t|d
diƒ d
di Y S  tyÏ } ztd|› �ƒ t|d
t|ƒiƒ d
t|ƒiW  Y d }~S d }~ww )NrU   zoption_chain_helper.pyTrK   )Úcapture_outputr»   r  r   zunknown erroru#   âš ï¸� Option chain helper failed: r  Úerrorz[Option Chain] z spot=Úspotz R=Ú
resistanceÚlevelz S=Úsupportz PCR=Úpcru)   âš ï¸� Option chain helper timed out for r  u   âš ï¸� Option chain error: )rf   rä   ÚpathÚjoinÚdirnameÚabspathÚ__file__Ú
subprocessÚrunÚVENV_PYTHONÚ
returncodeÚstderrræ   r€   rh   Újson_libÚloadsÚstdoutr~   ÚTimeoutExpiredr   r  )r   r  r  Úhelper_pathru   Úerrr  r‚   rR   rR   rS   Úfetch_option_chain_levels°  sL   
þþ

ÿþý€ýr<  c              	   C   sV   z| d u rW d S t | ƒ}t |¡st |¡rW d S t||ƒW S  ttfy*   Y d S w r`   )rï   ÚmathÚisnanÚisinfrË   r  Ú	TypeError)ÚvalÚdecimalsÚfrR   rR   rS   Ú_safe_floatÙ  s   ÿrD  c              	   C   sT   z| d u rW d S t | ƒ}t |¡st |¡rW d S t|ƒW S  ttfy)   Y d S w r`   )rï   r=  r>  r?  Úintr  r@  )rA  rC  rR   rR   rS   Ú	_safe_intä  s   
ÿrF  Úindexc                 C   sh  d| › �}t |ƒ}|d ur|S �zó| dkrtnt}dd„ |D ƒ}tjd |¡dddd	dd
d�}g }|D �]«}|d }�zrt|ƒdkrE|}	n||j d¡v rQ|| nd }	|	d u sZ|	j	ru| 
||d |d |d d d d d d d d d ddœ¡ W q3|	d  ¡ }
d|	v r…|	d  ¡ nd }d|	v r‘|	d  ¡ nd }t|
ƒdk r¿| 
||d |d |d t|
ƒr°t|
jd ƒnd d d d d d d d ddœ¡ W q3t|
jd ƒ}t|
jd ƒ}t|| | d dƒ}d }d }d }|d u�rR|d u�rRt|ƒdk�rRt|ƒdk�rRg }tddƒD ]*}zt|j| ƒ}t|j| ƒ}|| }|dk�r| 
|¡ W qý t�y'   Y qýw |�rRtt|ƒt|ƒ dƒ}|dk�rRt|| d dƒ}|dk�rRtt|ƒ| dƒ}|d u�rb|j	�sbt|jd ƒnd }|d u�rt|j	�stt|jd ƒnd }d|	v �rŠ|	d j	�sŠt|	d jd ƒnd }| 
||d |d |d t|dƒ|t|dƒ||||||d dœ¡ W q3 t�yß } z%| 
||d |d |d d d d d d d d d t|ƒd d … dœ¡ W Y d }~q3d }~ww | t t¡ d!¡|t|ƒd"œ}t||ƒ td#| › d$t|ƒ› d%�ƒ |W S  t�y3 } z#td&| › d'|› �ƒ | t|ƒd d(… g d)œ}t||ƒ |W  Y d }~S d }~ww )*NrW   r6   c                 S   s   g | ]}|d  ‘qS ©r   rR   )rŠ   ÚcrR   rR   rS   rŒ   ú  ó    z&fetch_constituents.<locals>.<listcomp>ú Ú7dÚ1dFÚtickerT)ÚtickersÚperiodÚintervalÚprogressÚgroup_byÚauto_adjustÚthreadsr   r‡   r   r   r   r   Úno_data)r   r   r   r   ÚpriceÚ
change_pctÚatrÚatr_pctÚmove_vs_atrÚvolumeÚday_highÚday_lowr&  ÚCloseÚHighÚLowr   éÿÿÿÿÚinsufficient_historyéþÿÿÿéd   rD   éûÿÿÿÚVolume)r   r   r   r   rW  rX  Ú
prev_closerY  rZ  r[  r]  r^  r\  r&  éP   ú%d %b %Y, %I:%M %p IST)rG  ÚupdatedÚconstituentsr¾   z[Constituents] z
: fetched ú stocksu$   âš ï¸� Constituents fetch error for r|   r  )rG  r&  rl  )rf   ÚNIFTY50_CONSTITUENTSÚSENSEX30_CONSTITUENTSÚyfÚdownloadr-  r  ÚcolumnsÚget_level_valuesÚemptyÚappendÚdropnarD  Úilocrï   rË   rX   r   rÈ   ÚabsrF  r  r   rL   rM   r}   rh   r€   )rG  r  r  rl  Úsymbolsr  ÚresultsrI  r   Úticker_dataÚclosesÚhighsÚlowsrh  Úcurrent_pricerX  rY  rZ  r[  Útrue_rangesÚiÚhÚlÚtrr]  r^  r\  Úexru   r‚   r;  rR   rR   rS   Úfetch_constituentsò  sÚ   
ù


ûù	0

€ÿ

$$,ø

û€ÿ
ü

€ür†  Úmax_headlinesc                 C   sP   t j t | | ¡¡}d|› d�}t |¡}dd„ |jD ƒ}dd„ |d |… D ƒS )Nú%https://news.google.com/rss/search?q=ú&hl=en-IN&gl=IN&ceid=IN:enc                 S   ó   g | ]}t |ƒr|‘qS rR   ©r  ©rŠ   r‚   rR   rR   rS   rŒ   p  ó    z(fetch_news_headlines.<locals>.<listcomp>c                 S   ó   g | ]}|j ‘qS rR   ©Útitle©rŠ   rþ   rR   rR   rS   rŒ   q  ó    )ÚurllibÚparseÚquoteÚSEARCH_QUERIESr~   Ú
feedparserÚentries)r   r‡  ÚqueryÚurlÚfeedÚfreshrR   rR   rS   Úfetch_news_headlinesl  s
   
r�  rD   Ú	max_postsc                 C   sZ   t  | | ¡}tj |› d�¡}d|› d�}t |¡}dd„ |jD ƒ}dd„ |d |… D ƒS )Nz site:x.com OR site:twitter.comrˆ  r‰  c                 S   rŠ  rR   r‹  rŒ  rR   rR   rS   rŒ   x  r�  z'fetch_twitter_posts.<locals>.<listcomp>c                 S   rŽ  rR   r�  r‘  rR   rR   rS   rŒ   y  r’  )r–  r~   r“  r”  r•  r—  r˜  )r   rž  Úkeywordr™  rš  r›  rœ  rR   rR   rS   Úfetch_twitter_postss  s   
r   Úcnbctv18ÚETNOW)z	CNBC-TV18zET Now)ÚniftyÚnifty50znifty 50Úsensexz
bse sensex)Úgoldz
gold pricez	gold ratezmcx gold)Úsilverzsilver pricezsilver rate)Úcrudez	crude oilÚbrentÚwtiÚbitcoinÚbtcrš  c                 C   s   t  d| ¡}|r| d¡S dS )Nz5(?:v=|youtu\.be/|/embed/|/shorts/)([A-Za-z0-9_-]{11})r‡   r	  )rí   rî   rð   )rš  rô   rR   rR   rS   Úextract_video_idˆ  s   r­  éÄ	  Ú	max_charsc                    sî  t  | |  ¡ g¡}t tj¡ttd� }zt	ƒ }W n t
y6 } ztd| › d|› �ƒ W Y d }~dS d }~ww t ¡ D ]±\}}zŽd|› �}t |¡}	|	jD ]~}
t|
dd ƒ}|sXqMt|d d… dtjiŽ}||k riqM|
j ¡ ‰ t‡ fd	d
„|D ƒƒszqMt|
jƒ}|s‚qMz@|j|g d¢d�}g }|D ]}t|dd ƒ}|rŸ| |¡ q�d |¡}td| › d|
jd d… › d|› �ƒ |d |… W   W   S  t
yË   Y qMw W q; t
yì } ztd| › d|› d|› �ƒ W Y d }~q;d }~ww td| › d�ƒ dS )Nrú   rã   z] YouTube init error: r	  z.https://www.youtube.com/feeds/videos.xml?user=r÷   rø   rù   c                 3   s   � | ]}|ˆ v V  qd S r`   rR   )rŠ   Úkw©Útitle_lowerrR   rS   rÃ   ¤  s   € z+fetch_youtube_transcript.<locals>.<genexpr>)Úenzen-INÚhi)Ú	languagesr»   rK  z] YouTube OK 'é<   z' from z
] Channel z error: z%] YouTube: no usable transcript found)ÚSYMBOL_KEYWORDSr~   rÇ   r   rL   r   rý   r   ÚNEWS_MAX_AGE_HOURSr   r   r€   ÚFINANCE_CHANNELSÚitemsr—  r”  r˜  rü   r�  Úanyr­  ÚlinkÚfetchru  r-  )r   r¯  Úkeywordsr  Úapir‚   Úchannel_nameÚusernameÚfeed_urlr›  rþ   rÿ   r   Úvideo_idÚ
transcriptÚpartsÚchunkr»   Ú	full_textrR   r±  rS   Úfetch_youtube_transcriptŒ  s`   
€þ





€
$ÿæ€þrÈ  FÚbypass_cachec                 C   s®  d| › �}|st |ƒ}|r|S t| ƒ}t| ƒ}t| ƒ}| tv r"tƒ nd}|r.t| d |¡ƒnd}|r:t| d |¡ƒnd}	|rCt| |ƒnd}
g g }}|rV| d¡ | |¡ |rb| d¡ | |
¡ |rn| d¡ | |	¡ | tv r|| d¡ | |¡ |s—| ddddddg g d	d
œ
}t	||ƒ t
| |ƒ |S t|ƒ}ttdd„ t||ƒD ƒƒ| dƒ}|dkr³d}n	|dkrºd}nd}| ||||	|
|||t|ƒd
œ
}t	||ƒ t
| |ƒ |S )Nr[   rÅ   Ú
r   gš™™™™™É?gš™™™™™¹?rØ   r{   F)
r   rv   rz   rw   rx   ry   rZ   Ú	headlinesÚtweetsÚhas_youtubec                 s   s   � | ]	\}}|| V  qd S r`   rR   )rŠ   ÚsrÀ   rR   rR   rS   rÃ   ä  s   € z&get_sentiment_score.<locals>.<genexpr>r‡   rb  ÚBEARISHÚBULLISH)rf   r�  r   rÈ  ÚFII_DII_SYMBOLSr$  rõ   r-  ru  rh   rƒ   rÈ   rË   ÚzipÚbool)r   rÉ  r  r  ÚnewsrÌ  Úyoutube_textrZ   rw   rx   ry   ÚweightsÚscoresru   Útotal_weightÚfinal_scorerz   rR   rR   rS   Úget_sentiment_scoreÁ  sT   

ü

"
ü

rÚ  rl  c                 C   sÞ   i }| D ]H}|  d¡d u rq|d }||vrdddg dœ||< || d  d7  < || d  |d 7  < || d	  |d
 7  < || d  |d ¡ q|D ]}|| d dkrlt|| d || d  dƒ|| d< qO|S )NrX  r   r   rÅ   )r¾   Ú
avg_changerØ  Ústocksr¾   r‡   rÛ  rØ  r   rÜ  r   r   )r~   ru  rË   )rl  Úsector_datarI  rÎ  rR   rR   rS   Ú_build_sector_summaryü  s    &€rÞ  Ústockc                 C   s  |   d¡}|   d¡}|   dd¡}|tv }|d u rd d dœS t|ƒ}|r5|tkr,dddœS |tkr5dd	dœS |d u s=|d
kr]|dkrFdddœS |dkrOdddœS |dkrXdddœS d d dœS || }|tkrjdddœS |tkrsdddœS |tkr|dddœS d d dœS )NrX  rZ  r   r	  )r)  Úsuggested_actionÚMAJORuI   Extreme move for a heavyweight â€” momentum may exhaust soon, use cautionÚ	IMPORTANTuA   Significant heavyweight move â€” chart may show entry opportunityr   g      @u   Extreme move â€” use cautionr   u+   Significant move â€” watch for continuationr.   ÚSIGNALu2   Early mover â€” open chart, watch for continuationu7   Extreme move â€” momentum may exhaust soon, use cautionu5   Significant move â€” chart may show entry opportunity)r~   ÚTIER1_SYMBOLSrx  ÚTIER1_MAJOR_FLOORÚTIER1_IMPORTANT_FLOORÚATR_MAJOR_MULTÚATR_IMPORTANT_MULTÚATR_SIGNAL_MULT)rß  ÚpctrZ  r   Úis_tier1Úabs_pctr[  rR   rR   rS   Ú_classify_move  s2   









rí  c            &      C   sl  g } d }d }d }d }d }d}t dƒ}z5t d¡}|jdd�}	|	jsFt|	d jd ƒ}t|	ƒdkrFt|	d jd	 ƒ}
|
rFt||
 |
 d
 dƒ}W n t	y` } zt
d|› �ƒ W Y d }~nd }~ww tdƒ dg ¡}|d ur¢t|ƒtkr¢|dkr�|  ddddd|d›d|d›d�ddœ¡ n|  ddddd|d›d|d›d�ddœ¡ |D ]”}| d¡}|d u r°q¤| d d¡}tt|ƒ| d
 d!ƒ}| d"¡}|dkrÌd#nd$}t|ƒ}| d%¡}| d&¡}|dkråd'\}}n|dkrîd(\}}n
|d)kr÷d*\}}nq¤|d u�rd+t|d
 ƒ› d,�nd-}d.|d/›d0�}|› d1|d2 › d3|d4›d5|› d6|› |› |› �}|  ||| ¡ › d7�|||dœ¡ q¤t|ƒ}| ¡ D ]A\}}|d8 d!k�r�t|d9 ƒd:k�r�|d9 dk �r^d;nd<}|  d=d>d?d|› d@|› dA|d9 d4›dB|d8 › dC�dD|› dE�dœ¡ �qAdF|v �rÖt| dF¡tƒ�rÖ|dF  d%¡}t dG¡}|d u�rÖ|d u�rÖ|| }t|ƒtk�rÖ|dk�r¹dHndI}|  d=dJdKddL|› dMt|ƒdN›dOt|ƒdN›�dPdœ¡ dQ|v �r)t| dQ¡tƒ�r)|dQ  d%¡}t dR¡} |d u�r)| d u�r)||  }t|ƒtk�r)|dk�rdHndI}|  d=dJdSddT|› dMt| ƒdN›dOt|ƒdN›�dUdœ¡ | dV¡}t dW¡}!|d u�rl|!d u�rl||! }t|ƒtk�rl|dk�rOdXndY}"|  dZd[d\d)d]|!d›dO|d›d^|"› d_�d`|"› �dœ¡ tdaƒ}#|#�r”|# db¡d u�r”|#db dck�r”|  dddedfd)dg|#db › dh�didœ¡ tdjƒ}$|$�r¼|$ db¡d u�r¼|$db d!k�r¼|  dddkdld)dm|$db › dn�dodœ¡ | dp¡}t dq¡}%|d u�ró|%d u�ró||% }t|ƒdrk�ró|  dsdtdud)dvt|%ƒdN›dOt|ƒdN›�dwdœ¡ |d u�rü|tdG< |d u�r|tdR< |d u�r|tdW< |d u�r|tdq< | jdxdy„ dz� | d t… } | �s4|  d{d|d}d~dd dœ¡ | S )€NrÅ   r6   ú	^INDIAVIXÚ5d©rP  r_  rb  r   rd  re  z[Action] VIX error: rl  r   r‡   u   âš ï¸�Ú	vix_surgerá  zVIX surged +ú.1fz% to z.2fu    â€” premium expansion warningu3   Options getting expensive â€” avoid chasing premium)ÚpriorityÚiconÚtyper)  rì   rà  u   âœ…Úvix_droprâ  zVIX dropped u    â€” premium contractionu2   Calmer market â€” options cheaper, potential entryrX  r   é   r[  r³   r    r)  rà  )u   ðŸš¨r‡   )u   ðŸ””r   rã  )u   ðŸ”�r÷  u    â€¢ z% of 5-day ATRr	  u    â€¢ contributing ~z.3fz
% to NIFTYr|   r   rK  r  z% (u   % weight) â€” Ú_mover¾   rÛ  r.   r�   r²   é   u   ðŸ“ŠÚsector_alertz sector z: avg z	% across rm  zCoordinated u    move â€” check sector rotationr*  Únifty_supportÚUPÚDOWNu   ðŸ“�Úsupport_shiftzNIFTY Support shifted z from r  z to z'Adjust stops and targets to new supportr(  Únifty_resistanceÚresistance_shiftzNIFTY Resistance shifted z*Adjust stops and targets to new resistancer+  Ú	nifty_pcrr´   r¡   rD   u   ðŸ”„Ú	pcr_shiftzPCR moved from u    â€” z shiftzPositioning is now Úsentiment_CRUDEOILrv   éýÿÿÿrø   u   ðŸ›¢ï¸�Úcrude_warningzCrudeoil bearish (score u   ) â€” Reliance may followz#Watch Reliance for sympathetic moveÚsentiment_GOLDu   ðŸ¥‡Úgold_strengthzGold bullish (score u   ) â€” defensive rotationz#Watch for risk-off trade developingÚmax_painÚnifty_maxpainrÙ   r„   u   ðŸŽ¯Úmaxpain_shiftzMax Pain shifted from zExpiry target has movedc                 S   s   | d S )Nró  rR   )ÚxrR   rR   rS   Ú<lambda>¤  s    z(generate_action_events.<locals>.<lambda>ri   éc   u   âšªÚneutralÚINFOu2   No significant events detected â€” market is quiet)r<  rp  ÚTickerÚhistoryrt  rï   rw  r  rË   r   r€   r†  r~   rx  ÚVIX_SURGE_MIN_PCTru  rí  rE  rÇ   rÞ  rº  r  ÚdictÚPREVIOUS_SNAPSHOTÚSUPPORT_RESISTANCE_SHIFT_MINÚPCR_SHIFT_MINrj   ÚsortÚACTION_DASHBOARD_MAX_EVENTS)&ÚeventsÚcurr_supÚcurr_resÚcurr_pcrÚcurr_maxpainÚcurrent_vixÚvix_change_pctÚnifty_ocÚ
vix_tickerÚvix_dataÚprev_vixr‚   Únifty_constrß  rê  r   Úimpactr[  Ú	directionÚclassificationr)  rà  rô  ró  Úatr_noteÚimpact_noterì   Úsector_summaryr   ÚsdataÚprev_supÚdiffÚprev_resÚprev_pcrÚtoneÚ
crude_sentÚ	gold_sentÚprev_maxpainrR   rR   rS   Úgenerate_action_events-  sö   
€€ÿ
þþ




".
ÿ $
þ€
 þ
 þ

þ$þ$þ

þþr4  c                  C   s^   t  t¡} |  ¡ }| d¡ | d¡ z| d¡ W n
 t jy$   Y nw |  ¡  |  ¡  d S )Na†  
        CREATE TABLE IF NOT EXISTS zones (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            symbol TEXT NOT NULL,
            name TEXT,
            sector TEXT,
            zone_type TEXT NOT NULL,
            zone_top REAL NOT NULL,
            zone_bottom REAL NOT NULL,
            created_at TEXT NOT NULL,
            created_price REAL,
            age_bars INTEGER DEFAULT 0,
            entry_count INTEGER DEFAULT 0,
            first_entry_at TEXT,
            last_entry_at TEXT,
            last_entry_price REAL,
            is_active INTEGER DEFAULT 1,
            UNIQUE(symbol, zone_type, created_at)
        )
    a«  
        CREATE TABLE IF NOT EXISTS zone_events (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            symbol TEXT NOT NULL,
            name TEXT,
            sector TEXT,
            event_type TEXT NOT NULL,
            zone_type TEXT,
            zone_top REAL,
            zone_bottom REAL,
            price REAL,
            event_at TEXT NOT NULL,
            tier TEXT,
            message TEXT
        )
    z.ALTER TABLE zone_events ADD COLUMN sector TEXT)rk   rl   ÚZONES_DB_PATHrn   ro   rp   rq   rr   )rs   rI  rR   rR   rS   Úinit_zones_db±  s   


ÿr6  c                 C   s<   t  t¡}| ¡ }| d| ||f¡ | ¡ }| ¡  |d uS )NzDSELECT id FROM zones WHERE symbol=? AND zone_type=? AND created_at=?)rk   rl   r5  rn   ro   Úfetchonerr   )r   Ú	zone_typeÚ
created_atrs   rI  r   rR   rR   rS   Úzone_existsá  s   
ÿr:  c                 C   sž   t  t¡}| ¡ }z&| d| d | d |  dd¡| d | d | d | d	 | d
 f¡ | ¡  W n tyH } ztd|› �ƒ W Y d }~nd }~ww | 	¡  d S )Nzå
            INSERT OR IGNORE INTO zones
            (symbol, name, sector, zone_type, zone_top, zone_bottom,
             created_at, created_price, age_bars, is_active)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, 1)
        r   r   r   r	  r8  Úzone_topÚzone_bottomr9  Úcreated_pricezInsert zone error: ©
rk   rl   r5  rn   ro   r~   rq   r   r€   rr   )Úzoners   rI  r‚   rR   rR   rS   Úinsert_zoneê  s   
ýû
€ÿr@  c                 C   s¾   t  t¡}| ¡ }z6| d| d |  d¡|  dd¡| d |  d¡|  d¡|  d	¡|  d
¡| d |  d¡|  d¡f¡ | ¡  W n tyX } ztd|› �ƒ W Y d }~nd }~ww | 	¡  d S )Nzà
            INSERT INTO zone_events
            (symbol, name, sector, event_type, zone_type, zone_top, zone_bottom,
             price, event_at, tier, message)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        r   r   r   r	  Ú
event_typer8  r;  r<  rW  Úevent_atÚtierrì   zInsert zone event error: r>  )Úeventrs   rI  r‚   rR   rR   rS   Úinsert_zone_eventý  s    
üû€ÿrE  c                  C   sV   t  t¡ttd�  ¡ } t t¡}| 	¡ }| 
d| f¡ | ¡ }| ¡  dd„ |D ƒS )Nrú   a  
        SELECT id, symbol, name, sector, zone_type, zone_top, zone_bottom,
               created_at, created_price, age_bars, entry_count,
               first_entry_at, last_entry_at, last_entry_price
        FROM zones
        WHERE is_active = 1 AND created_at >= ?
    c                 S   sf   g | ]/}|d  |d |d |d |d |d |d |d |d |d	 |d
 |d |d |d dœ‘qS )r   r‡   r   r÷  rù  rD   rø   r„   é   rE   rÆ   é   é   é   )Úidr   r   r   r8  r;  r<  r9  r=  Úage_barsÚentry_countÚfirst_entry_atÚlast_entry_atÚlast_entry_pricerR   r‰   rR   rR   rS   rŒ     s    û
ûz$get_active_zones.<locals>.<listcomp>)r   rL   rM   r   ÚZONE_MAX_AGE_HOURSÚ	isoformatrk   rl   r5  rn   ro   r�   rr   )r  rs   rI  r�   rR   rR   rS   Úget_active_zones  s   
úúrR  c                 C   s:   t  t¡}| ¡ }| d|||| f¡ | ¡  | ¡  d S )NzÔ
        UPDATE zones
        SET entry_count = entry_count + 1,
            first_entry_at = COALESCE(first_entry_at, ?),
            last_entry_at = ?,
            last_entry_price = ?
        WHERE id = ?
    )rk   rl   r5  rn   ro   rq   rr   )Úzone_idrW  Úat_timers   rI  rR   rR   rS   Úupdate_zone_entry&  s   

ùrU  c                  C   sL   t  t¡ttd�  ¡ } t t¡}| 	¡ }| 
d| f¡ | ¡  | ¡  d S )Nrú   z3UPDATE zones SET is_active = 0 WHERE created_at < ?)r   rL   rM   r   rP  rQ  rk   rl   r5  rn   ro   rq   rr   )r  rs   rI  rR   rR   rS   Údeactivate_old_zones4  s   
rV  c              
   C   sÜ  g }t | ƒ}|tt d k r|S tt|t ƒD ]Ô}| | }d}t|t |ƒD ]}| | d |d kr6d} nq&|rUt|d |t d ƒD ]}| | d |d krTd} nqD|r„t|d |d ƒ}t|d |ƒ}t|d |ƒ}	| |dt|dƒt|	dƒ|d |d	 d
œ¡ d}
t|t |ƒD ]}| | d |d kr�d}
 nq�|
r¼t|d |t d ƒD ]}| | d |d kr»d}
 nq«|
rët|d |d ƒ}t|d |ƒ}t|d |ƒ}	| |dt|dƒt|	dƒ|d |d	 d
œ¡ q|S )Nr‡   TrÛ   FÚopenrr   rÎ   r   rb   )rG  rõ  ÚtopÚbottomrW  rb   r°   rÏ   )r  Ú
PIVOT_LEFTÚPIVOT_RIGHTrX   rÍ   rÌ   ru  rË   )ÚbarsÚpivotsÚnr�  ÚbarÚis_pivot_lowÚjÚbody_lowÚbox_topÚ
box_bottomÚis_pivot_highÚ	body_highrR   rR   rS   Úfind_pivots?  s`   þþþþþþ€rg  r÷  c                 C   sú   z^t  | ¡}|j|› d�ddd�}|jrg W S g }| ¡ D ]>\}}z/| | ¡ t|d ƒt|d ƒt|d ƒt|d ƒt 	t|d	 ƒ¡sJt
|d	 ƒnd
dœ¡ W q ttfy[   Y qw |W S  ty| } ztd| › d|› �ƒ g W  Y d }~S d }~ww )NÚdÚ15mF)rP  rQ  ÚprepostÚOpenr`  ra  r_  rg  r   )rb   rW  r°   rÛ   rr   r\  rã   z] 15m fetch error: )rp  r  r  rt  Úiterrowsru  rQ  rï   r=  r>  rE  r  r@  r   r€   )r   r…   rN  Údfr\  Úidxr   r‚   rR   rR   rS   Úfetch_15m_barss  s2   




 úÿ€þro  c           
   	   C   sø   |   d| d ¡}|  d¡}|dkrdnd}|dkr6|rdnd	}d
|› d|› d|d › d|d › d�	}||fS |dkrq|  dd¡}	|	dkr]d}d|› d|› d|d › d|d › d�	}||fS d	}d|› d|› d|	d › d�}||fS d	}|› d�}||fS )Nr   r   r8  rÎ   u   ðŸŸ¢ Bullishu   ðŸ”´ BearishÚzone_createdrâ  rã  z
NEW ZONE: z created a z reversal zone (r<  ú-r;  ú)Úzone_enteredrL  r   zFIRST ENTRY: z	 entered z
RE-ENTRY: z re-entered z zone (entry #r‡   z zone event)r~   )
rß  r?  rA  r  r   r8  Ú
zone_labelrC  ÚmsgrL  rR   rR   rS   Úclassify_zone_eventŽ  s&   
&ô&úý
rv  c                    sà  t  t¡}| d ur| nt}|d ur|nt}td| d¡› d|› d|› d�ƒ tƒ }tdt|ƒ› d�ƒ t	ƒ  g }i }t
ƒ D ]}| |d g ¡ |¡ q=d	}	d	}
d	}|D �]5}|d }�zt|d
d�‰ tˆ ƒdk rjW qSˆ d d }||k sx||krzW qS|	d7 }	tˆ ƒ}|s†W qS‡ fdd„|D ƒ}|D ]Y}|d }t||d |ƒr q‘|
d7 }
||d | dd¡|d |d |d ||d dœ}t|ƒ t||ddd�\}}| ||d | dd¡d|d |d |d || ¡ ||dœ¡ q‘| |g ¡}|D ]w}|d }|d  }ˆ d!d … D ]f}|d" |k�r|d" |k�p-|d# |k�o|d# |k�p-|d" |k�o-|d# |k}|�rht|d$ |d |d ƒ t||d%ƒ\}}| ||d | dd¡d%|d& |||d |d ||dœ¡ |d7 } n�qqóW qS t�y‰ } ztd'|› d(|› �ƒ W Y d }~qSd }~ww |D ]}t|ƒ �qŒt  t¡|  ¡ }td)|	› d*t|ƒ› d+�ƒ td,|
› d-|› �ƒ td.|d/›d0�ƒ t| ¡ | d1¡|	td2d„ |D ƒƒtd3d„ |D ƒƒd4d„ |D ƒd5d„ |D ƒtt
ƒ ƒd6œ	}td7|ƒ |S )8Nú
[ú%Y-%m-%d %H:%M:%S ISTu&   ] Zone scan started (price filter: â‚¹u   -â‚¹z)...z  Universe: z F&O stocksr   r   r÷  )r…   rÆ   rb  rr   r‡   c                    s(   g | ]}|d  t ˆ ƒt d kr|‘qS )rG  r÷  )r  r[  )rŠ   Úp©r\  rR   rS   rŒ   Ì  s   ( z!run_zone_scan.<locals>.<listcomp>rb   rõ  r   r   r	  rX  rY  rW  )r   r   r   r8  r;  r<  r9  r=  rp  Tr‹  ©r   r   r   rA  r8  r;  r<  rW  rB  rC  rì   r;  r<  r  rÛ   r°   rJ  rs  r8  rã   z] scan error: z  Scanned: ú/rm  z  New zones: z | Entries: z  Completed in rò  rÎ  z%d %b %Y, %I:%M:%S %p ISTc                 S   ó   g | ]
}|d  dkr|‘qS ©rA  rp  rR   rŒ  rR   rR   rS   rŒ     ó    c                 S   r}  ©rA  rs  rR   rŒ  rR   rR   rS   rŒ     r  c                 S   r}  r~  rR   rŒ  rR   rR   rS   rŒ     r  c                 S   r}  r€  rR   rŒ  rR   rR   rS   rŒ     r  )	ÚversionÚ
scanned_atÚscanned_at_humanÚstocks_scannedÚnew_zones_countÚentries_countÚ	new_zonesÚrecent_entriesÚactive_zones_totalr\   )r   rL   rM   r   r   r€   r}   Úget_fno_stocksr  rV  rR  Ú
setdefaultru  ro  rg  r:  r~   r@  rv  rQ  rU  r   rE  Útotal_secondsÚVERSIONrh   )Ú	min_priceÚ	max_priceÚstartedÚ_minÚ_maxrÜ  Ú
new_eventsÚactive_zones_by_symbolÚzÚscanned_countÚpivots_foundÚentries_foundrß  r   r  r]  Úfresh_pivotsry  r9  r?  rC  ru  Úsymbol_zonesÚztÚzbr_  Útouchedr‚   ÚevtÚelapsedru   rR   rz  rS   Úrun_zone_scan§  sÊ   
ÿ
ÿ


û

ú	ÿý
úô€ø€þ÷
r   c                  C   sž   t dt t¡ d¡› d�ƒ tD ]8} zt| dd�}t d| › d|d › d	|d
 › d�ƒ W q tyH } zt d| › d|› �ƒ W Y d }~qd }~ww t dƒ d S )Nrw  rx  z ] Scheduled sentiment refresh...T)rÉ  z   [z	] Score: rv   z (rz   rr  z	] error: zSentiment refresh complete.
)r€   r   rL   rM   r}   ÚSYMBOLSrÚ  r   )Úsymru   r‚   rR   rR   rS   Úscheduled_sentiment_refresh  s   ( €ÿr£  z/api/sentimentc                   C   s   dd„ t D ƒS )Nc                 S   s   g | ]}t |ƒ‘qS rR   )rÚ  )rŠ   r¢  rR   rR   rS   rŒ   '  rJ  z&get_all_sentiments.<locals>.<listcomp>)r¡  rR   rR   rR   rS   Úget_all_sentiments%  s   r¤  z/api/sentiment/{symbol}c                 C   ó   t |  ¡ ƒS r`   )rÚ  r  rH  rR   rR   rS   Úget_single_sentiment)  ó   r¦  z/api/history/{symbol}c                 C   s   |   ¡ t|   ¡ |ƒdœS )N)r   r  )r  r�   )r   r…   rR   rR   rS   Úget_symbol_history-  s   r¨  z/api/option-chain/{symbol}c                 C   r¥  r`   )r<  r  rH  rR   rR   rS   Úget_option_chain1  r§  r©  z/api/constituents/{index}c                 C   s    |   ¡ }|dvrddiS t|ƒS )N)r6   r7   r&  zIndex must be NIFTY or SENSEX)r  r†  )rG  Úindex_upperrR   rR   rS   Úget_constituents5  s   r«  z/api/action-dashboardc               
   C   s€   zt ƒ } t t¡ d¡t| ƒt| dœW S  ty? } z td|› �ƒ t t¡ d¡dg t	|ƒd d… dœW  Y d }~S d }~ww )Nrj  )rk  r¾   Ú
max_eventsr  u   âš ï¸� Action dashboard error: r   r  )rk  r¾   r  r&  )
r4  r   rL   rM   r}   r  r  r   r€   r  )r  r‚   rR   rR   rS   Úget_action_dashboard<  s   üÿ€þr­  z
/api/rangec               
   C   s  t dƒ} | r| S zet d¡}t d¡}|jdd�}|jdd�}|js%|jr*ddiW S |d jd	 }|d jd	 }|d
kr@|d n|}||t d¡  }t|dƒt|dƒt|| dƒt|| dƒt|dƒdœ}	t	d|	ƒ |	W S  t
y… }
 zdt|
ƒiW  Y d }
~
S d }
~
ww )NrX   z^NSEIrî  rM  rð  r&  zCould not fetch market data.r_  rb  g      ð?re  éü   r   )Ú
last_closeÚvixrÛ   r°   Úmid)rf   rp  r  r  rt  rw  r=  ÚsqrtrË   rh   r   r  )r  r£  r°  Ú
nifty_datar"  r¯  r  Úvix_decimalÚ
daily_moveru   r‚   rR   rR   rS   Úget_expected_rangeK  s2   


û
€ÿr¶  z/api/scan/zones-15mc                  C   s   t dƒ} | r| S tƒ S )Nr\   )rf   r   )r  rR   rR   rS   Úget_zone_scani  s   r·  z/api/scan/rescanrŽ  r�  c                 C   s   t | |d�S )N©rŽ  r�  )r   r¸  rR   rR   rS   Úforce_zone_rescanp  r§  r¹  z/api/scan/active-zonesc                  C   s   t ƒ } t| ƒ| dœS )N)r¾   Úzones)rR  r  )rº  rR   rR   rS   Úget_active_zones_endpointt  s   r»  z/api/scan/recent-eventsrû   c                 C   s`   t  t¡t| d�  ¡ }t t¡}| ¡ }| 	d|f¡ | 
¡ }| ¡  t|ƒdd„ |D ƒdœS )Nrú   zì
        SELECT symbol, name, sector, event_type, zone_type, zone_top, zone_bottom,
               price, event_at, tier, message
        FROM zone_events
        WHERE event_at >= ?
        ORDER BY event_at DESC
        LIMIT 100
    c                 S   sT   g | ]&}|d  |d |d |d |d |d |d |d |d |d	 |d
 dœ‘qS )r   r‡   r   r÷  rù  rD   rø   r„   rF  rE   rÆ   r{  rR   r‰   rR   rR   rS   rŒ   Š  s    ý
ýz*get_recent_zone_events.<locals>.<listcomp>)r¾   r  )r   rL   rM   r   rQ  rk   rl   r5  rn   ro   r�   rr   r  )rû   r  rs   rI  r�   rR   rR   rS   Úget_recent_zone_eventsy  s   
ùüþr¼  z/api/statusc                  C   sf   t  t¡} |  ¡ dk }d| j  kodk n  p!| jdko!| jdk}|r(|r(dnd}||  d¡tdœS )	NrD   rE   rF   rK   úMarket OpenúMarket Closedrj  )Ústatusrk  r�  )r   rL   rM   rN   rG   rH   r}   r�  )rL   Ú
is_weekdayÚis_market_hoursr¿  rR   rR   rS   Úget_market_status”  s
   
.rÂ  z/api/scan/statusc                 C   s¼   t  t¡}| ¡ dk }d|j  kodk n  p!|jdko!|jdk}|r(|r(dnd}| d ur0| nt}|d ur8|nt}t|| 	d¡t
tƒ ƒt
tƒ ƒdt|ƒ› d	t|ƒ› �||d
tttdœdœ
S )NrD   rE   rF   rK   r½  r¾  rj  u   â‚¹u    - â‚¹ri  )ÚleftÚrightÚzone_length_bars)
r�  r¿  rk  Úuniverse_countÚactive_zonesÚprice_filterÚ	price_minÚ	price_maxÚ	timeframeÚpivot_config)r   rL   rM   rN   rG   rH   r   r   r�  r}   r  rŠ  rR  rE  rZ  r[  ÚZONE_LENGTH_BARS)rŽ  r�  rL   rÀ  rÁ  r¿  r‘  r’  rR   rR   rS   Úscan_statusœ  s"   
.
örÎ  z/api/versionc                   C   s   t dg d¢dœS )Nz
2026-10-02)zUNIFIED PLATFORM v1.0.0z--- Sentiment Scanner ---z4Multi-source AI sentiment (News + Twitter + YouTube)zFII/DII institutional flowsz.Option chain (Support/Resistance/Max Pain/PCR)zOI Buildup with net writer biasz(Nifty 50 Top 25 + Sensex 30 constituentsz(Weight-aware + ATR-based tiered alertingzLive Action Dashboardz--- Zone Scanner ---z15-minute reversal zone scannerz!Pine Script pivot detection logicz F&O stock universe (~190 stocks)zNew zone + zone entry detectionz"Tiered alerts (IMPORTANT / SIGNAL)z!Automatic 15-minute scan schedulez--- Shared ---z%Adaptive caching (market-hours-aware)zSQLite persistence (2 DBs)zScheduled snapshots)r�  rˆ   Úfeatures)r�  rR   rR   rR   rS   Úget_version±  s   ýrÐ  z/api/scheduler/statusc                  C   s4   t  ¡ } tttƒt t¡ d¡tƒ dd„ | D ƒdœS )Nrx  c                 S   s.   g | ]}|j |j|jr|j d ¡nddœ‘qS )z%Y-%m-%d %H:%M:%S %ZN)rJ  r   Únext_run)rJ  r   Únext_run_timer}   )rŠ   ra  rR   rR   rS   rŒ   Ö  s    þÿÿz$scheduler_status.<locals>.<listcomp>)r�  r   Úcurrent_timeÚmarket_hoursÚjobs)	Ú	schedulerÚget_jobsr�  r  rM   r   rL   r}   rT   )rÕ  rR   rR   rS   Úscheduler_statusÎ  s   ýûrØ  )r   zmon-frirE   )Úday_of_weekrG   rH   r   Úsentiment_9amzSentiment 9:00 AM)ÚtriggerrJ  r   Úreplace_existingrH  rK   Úsentiment_1230pmzSentiment 12:30 PMrF   Úsentiment_330pmzSentiment 3:30 PMé   )r   rF   rK   é-   )rÙ  rG   rH   rI   r   Úzone_Ú02dz
Zone scan ú:éx   )rÛ  rJ  r   rÜ  Úmisfire_grace_timeÚzone_1630_finalzFinal zone scan 16:30rY   u   
ðŸš€ PDMP Unified Platform z:   Sentiment: 3 daily snapshots (9:00 / 12:30 / 15:30 IST)z/   Zone Scanner: every 15 min + final 16:30 ISTz6   Universe: F&O (~190 stocks) + Sentiment (6 symbols)z   API: http://0.0.0.0:8000z*   Both scanners running from one process
c               
   C   s\   t  d¡ ztdƒ tƒ  tdƒ W d S  ty- }  ztd| › �ƒ W Y d } ~ d S d } ~ ww )Nr÷  z Running initial zone backfill...zZone backfill complete.
zZone backfill error: )rb   Úsleepr€   r   r   )r‚   rR   rR   rS   Údelayed_backfill  s   
€ÿrè  )ÚtargetÚdaemonÚ__main__z0.0.0.0i@  )ÚhostÚportr`   )r„   )r6   )r   )rD   )r®  )F)r÷  )T)NN)r   )‘rä   rí   rb   r=  rk   r  r1  Ú	threadingr  r6  r—  Úurllib.parser“  r   r   r   Úfastapir   Úfastapi.middleware.corsr   Úyfinancerp  Úopenair   Úyoutube_transcript_apir   Ú!apscheduler.schedulers.backgroundr	   Úapscheduler.triggers.cronr
   ÚpytzÚ
fno_stocksr   rŠ  r   r   r�  r   r3  rM   r¸  r  r  r  r  ré  rè  rç  ræ  rå  r  rZ  r[  rÍ  rP  rm   r5  rn  ro  rä  r–  r  Úkeysr¡  rÑ  ÚappÚadd_middlewarerå   r~   rç   ra   rT   r_   rf   rh   rj   rt   r  r  rƒ   rE  r�   rÊ   rÉ   rï   rÑ   rõ   rÓ  r  r$  r<  rD  rF  r†  r�  r   r¹  r·  r­  rÈ  rÚ  r  rÞ  rí  r4  r6  r:  r@  rE  rR  rU  rV  rg  ro  rv  r   r£  r¤  r¦  r¨  r©  r«  r­  r¶  r·  r¹  r»  r¼  rÂ  rÎ  rÐ  rØ  rÖ  Úadd_jobrX   rG   rH   r   Ústartr€   rè  ÚThreadÚ__name__Úuvicornr2  rR   rR   rR   rS   Ú<module>   sò  

çâ!úû
þ	'>)z
ú	59  .	4q








 



 


þ
þ
þ
üÿ÷ý




	þ