Ë
    ¨I¦j¥T  ã                  ód  — d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
mZmZ ddlZddlZddlZdZg d	¢Zg d
¢Zg d¢Zd$d„Zd%d„Zd&d„Zd'd„Zd(d)d„Zd*d„Zd+d„Z	 d(ddddœ	 	 	 	 	 	 	 	 	 	 	 d,d„Zd-d„Zd.d/d„Zd0d„Z 	 d(dddœ	 	 	 	 	 	 	 	 	 d1d„Z!d2d„Z" ed¬ «       G d!„ d"«      «       Z#d3d4d#„Z$y)5a¯  Point-in-time research context for industry, themes, and catalysts.

The module intentionally has no dependency on the M1 pipeline.  An
orchestrator can pass the ``[research_context]`` portion of a TOML file as a
plain mapping and decide where, or whether, to persist the returned tables.
All date filters are applied before rolling calculations so a historical run
cannot accidentally use observations that arrived in the future.
é    )Úannotations)Ú	dataclass)Údate)ÚPath)ÚAnyÚMappingÚSequenceNz0.1.0)Úcontext_keyr   Úhotspot_scoreÚsmoothed_scoreÚscore_changeÚpeak_to_dateÚdrawdown_from_peakÚhotspot_stage)Úsource_codeÚindustry_codeÚtheme_idÚ
theme_nameÚweightÚrole)Úcatalyst_idr   r   Úcatalyst_dateÚavailable_dateÚstatusÚimpactÚprobabilityÚcatalyst_scoreÚdays_to_catalystÚcatalyst_proximityÚtitlec                ó@   — t        j                  t        | «      ¬«      S )N©Úcolumns)ÚpdÚ	DataFrameÚlistr"   s    ú?C:\FundamentalWorkbench\src\fundamental_mvp\research_context.pyÚ_emptyr(   #   s   € Ü�<‰<¤ W£Ô.Ð.ó    c                óü   — | j                  «       }d|vrd|v r|j                  ddi¬«      }d|v rK|d   j                  t        «      j                  j	                  «       j                  j                  «       |d<   |S )Nr   Ú
stock_coder"   )ÚcopyÚrenameÚastypeÚstrÚstripÚlower)ÚframeÚresults     r'   Ú_normalise_stock_coder4   '   sv   € Ø�Z‰Z‹\€FØ˜FÑ" |°vÑ'=Ø—‘¨°mÐ'D�ÓEˆØ˜ÑØ & }Ñ 5× <Ñ <¼SÓ A× EÑ E× KÑ KÓ M× QÑ Q× WÑ WÓ Yˆˆ}ÑØ€Mr)   c                ó`   — t        j                  | d¬«      j                  j                  «       S )NÚcoerce©Úerrors)r$   Úto_datetimeÚdtÚ	normalize©Úvaluess    r'   Ú_normalise_dater>   0   s"   € Ü�>‰>˜&¨Ô2×5Ñ5×?Ñ?ÓAÐAr)   c                óV   — || v r| |   S t        j                  || j                  ¬«      S )z=Return a Series even when an optional input column is absent.©Úindex)r$   ÚSeriesrA   )r2   ÚcolumnÚdefaults      r'   Ú_column_or_defaultrE   4   s&   € à" e™Oˆ5�‰=ÐV´·±¸7È%Ï+É+Ô1VÐVr)   c                ó¢  — | �t        | t        «      r| dk(  rt        j                  «       S t        | t        j                  «      r| j	                  «       S t        | t
        t        f«      rt        j                  | «      S t        | t        «      rb| }|r%t        |j                  |«      t
        «      r||   }n$t        |j                  d«      t
        «      r|d   }t        j                  |«      S t        t        | «      «      }|j                  «       r|n||z  }|j                  «       st        j                  «       S |j                  j                  «       dk(  rt        j                  |«      S |j                  j                  «       dk(  r2t!        j"                  |j%                  d¬«      «      }t'        |||«      S t)        d|› �«      ‚)zKRead CSV/JSON input without treating an omitted optional input as an error.Ú Úrecordsz.csvú.jsonúutf-8©Úencodingz)research context only supports CSV/JSON: )Ú
isinstancer/   r$   r%   r,   r&   ÚtupleÚjson_normalizer   Úgetr   Úis_absoluteÚexistsÚsuffixr1   Úread_csvÚjsonÚloadsÚ	read_textÚ_read_tableÚ
ValueError)ÚvalueÚbase_dirÚpreferred_json_keyÚrawÚpaths        r'   rX   rX   9   sf  € à€}œ E¬3Ô/°E¸R²KÜ�|‰|‹~ÐÜ�%œŸ™Ô&Ø�z‰z‹|ÐÜ�%œ$¤˜Ô'Ü× Ñ  Ó'Ð'Ü�%œÔ!ØˆÙ¤*¨S¯W©WÐ5GÓ-HÌ$Ô"OØÐ(Ñ)‰CÜ˜Ÿ™ 	Ó*¬DÔ1Ø�i‘.ˆCÜ× Ñ  Ó%Ð%Ü”�E“
Ó€DØ×#Ñ#Ô%‰4¨8°d©?€DØ�;‰;Œ=Ü�|‰|‹~ÐØ‡{�{×ÑÓ˜fÒ$Ü�{‰{˜4Ó Ð Ø‡{�{×ÑÓ˜gÒ%Ü�j‰j˜Ÿ™°˜Ó9Ó:ˆÜ˜3 Ð*<Ó=Ð=Ü
Ð@ÀÀÐGÓ
HÐHr)   c                óÈ   — dD ]8  }|| v sŒ| |   j                  t        «      j                  j                  «       c S  t        j                  d| j
                  t        ¬«      S )N)r   r   r
   r   Úindustry_namerG   ©rA   Údtype)r.   r/   r0   r$   rB   rA   )r2   rC   s     r'   Ú_context_keyrc   T   sQ   € Û]ˆØ�UŠ?Ø˜‘=×'Ñ'¬Ó,×0Ñ0×6Ñ6Ó8Ò8ð ^ô �9‰9�R˜uŸ{™{´#Ô6Ð6r)   c                óþ  — dD ]2  }|| v sŒt        j                  | |   d¬«      j                  dd«      c S  dD �cg c]	  }|| v sŒ|‘Œ }}|s4t        j                  t        j
                  | j                  t        ¬«      S |D �cg c]A  }t        j                  | |   d¬«      j                  | |   «      j                  d¬	«      dz  ‘ŒC }}t        j                  |d
¬«      j                  d
¬«      S c c}w c c}w )N)r   Úsignal_scoreÚscorer6   r7   r   éd   )Ú	return_5dÚ
return_20dÚactivityÚ	attentionÚbreadthra   T)Úpcté   ©Úaxis)r$   Ú
to_numericÚcliprB   ÚnpÚnanrA   ÚfloatÚgroupbyÚrankÚconcatÚmean)r2   Údate_columnrC   Ú
componentsÚrankss        r'   Ú_infer_scorer}   [   sý   € Û<ˆØ�UŠ?Ü—=‘=  v¡°xÔ@×EÑEÀaÈÓMÒMð =ñ (gÓzÑ'f˜VÐjpÐtyÒjy’&Ð'f€JÐzÙÜ�y‰yœŸ™ u§{¡{¼%Ô@Ð@ñ {Eó  Fñ  {EÐpvŒR�]‰]˜5 ™=°Ô:×BÑBÀ5ÈÑCUÓV×[Ñ[Ð`dÐ[ÓeÐhkÓkð  {E€Eð  FÜ�9‰9�U Ô#×(Ñ(¨aÐ(Ó0Ð0ùò	 {ùò Fs   ¼	C5ÁC5ÂAC:é   r   ©Úshort_windowÚgroup_columnrz   c          
     óV  ‡— | �| j                   rt        t        «      S | j                  «       }||vrt        t        «      S t	        ||   «      |d<   |j
                  |d   j                  «          j                  «       }|�#t        j                  |«      j                  «       nd}|�‡|j
                  |d   j                  |«         j                  «       }dD ]S  }||v sŒt	        ||   «      }|j
                  |j                  «       |j                  |«      z     j                  «       } n |j                   rt        t        «      S |r8||v r4||   j                  t        «      j                  j                  «       |d<   nt        |«      |d<   |j
                  |d   j!                  d«         j                  «       }|j                   rt        t        «      S t#        |d«      |d<   |j%                  ddg«      j'                  ddgd¬«      }|j)                  dd	¬
«      d   }	|	j+                  ˆfd„«      |d<   |j)                  dd	¬
«      d   j-                  ‰«      |d<   |j)                  dd	¬
«      d   j/                  «       |d<   |d   |d   z
  |d<   |d   }
|d   j1                  d«      }|d   j1                  d«      }|
j3                  |d   dz
  «      }t5        j6                  |
j9                  d«      |j3                  d«      |j                  d«      z  |
j3                  d«      |j;                  d«      |z  z  |
j3                  d«      |j;                  d«      z  |
j3                  d«      |j3                  d«      z  gg d¢d¬«      |d<   |j=                  d¬«      S )u‘  Classify each dated industry/theme observation using only data available then.

    Stages are ``è�ŒèŠ½``, ``å�‡æ¸©``, ``é«˜æ½®``, ``é€€æ½®`` and ``å†·å�´``.  ``as_of`` first
    removes future rows (and rows whose ``available_date`` is not yet known),
    then all smoothing, peaks, and changes are calculated in chronological
    order.  Thus the output is safe to use in a historical backtest.
    Nr   ©r   Úavailable_onÚpublished_dater
   rG   r   Úlast©ÚkeepF)Úsortc                óF   •— | j                  ‰d¬«      j                  «       S )Nrn   )Úmin_periods)Úrollingry   )Úitemr€   s    €r'   Ú<lambda>z,classify_hotspot_lifecycle.<locals>.<lambda>‘   s   ø€ ¸T¿\¹\È,Ðde¸\Ó=f×=kÑ=kÔ=mr)   r   r   r   r   ç        é   é   é   r   éP   é<   é(   )õ   å†·å�´u   é€€æ½®u   é«˜æ½®u   å�‡æ¸©u   è�ŒèŠ½r–   ©rD   r   T©Údrop)Úemptyr(   Ú_EMPTY_LIFECYCLE_COLUMNSr,   r>   ÚlocÚnotnar$   Ú	Timestampr;   ÚleÚisnar.   r/   r0   rc   Úner}   Úsort_valuesÚdrop_duplicatesrv   Ú	transformÚdiffÚcummaxÚfillnaÚgers   ÚselectÚltÚgtÚreset_index)Úindustry_dataÚas_ofr€   r�   rz   r2   ÚcutoffÚavailability_columnÚ	availableÚgroupedrf   ÚchangeÚdrawdownÚ	near_peaks     `           r'   Úclassify_hotspot_lifecycler¶   g   so  ø€ ð Ð × 3Ò 3ÜÔ.Ó/Ð/Ø×ÑÓ €EØ˜%ÑÜÔ.Ó/Ð/Ü# E¨+Ñ$6Ó7€Eˆ&�MØ�I‰I�e˜F‘m×)Ñ)Ó+Ñ,×1Ñ1Ó3€EØ05Ð0AŒR�\‰\˜%Ó ×*Ñ*Ô,Àt€FØÐØ—	‘	˜% ™-×*Ñ*¨6Ó2Ñ3×8Ñ8Ó:ˆÛ#WÐØ" eÒ+Ü+¨EÐ2EÑ,FÓG�	ØŸ	™	 )§.¡.Ó"2°Y·\±\À&Ó5IÑ"IÑJ×OÑOÓQ�Ùð	 $Xð
 ‡{‚{ÜÔ.Ó/Ð/Ù˜¨Ñ-Ø$ \Ñ2×9Ñ9¼#Ó>×BÑB×HÑHÓJˆˆmÒä+¨EÓ2ˆˆmÑØ�I‰I�e˜MÑ*×-Ñ-¨bÓ1Ñ2×7Ñ7Ó9€EØ‡{‚{ÜÔ.Ó/Ð/Ü)¨%°Ó8€Eˆ/ÑØ×Ñ˜}¨fÐ5Ó6×FÑFÈÐW]ÐG^ÐekÐFÓl€EØ�m‰m˜M°ˆmÓ6°ÑG€GØ%×/Ñ/Ó0mÓn€EÐ
ÑØ!ŸM™M¨-¸e˜MÓDÐEUÑV×[Ñ[Ð\hÓi€Eˆ.ÑØ!ŸM™M¨-¸e˜MÓDÐEUÑV×]Ñ]Ó_€Eˆ.ÑØ"'¨Ñ"7¸%Ð@PÑ:QÑ"Q€EÐ
ÑàÐ"Ñ#€EØ�>Ñ"×)Ñ)¨#Ó.€FØÐ)Ñ*×1Ñ1°#Ó6€HØ—‘˜˜~Ñ.°Ñ2Ó3€IÜŸY™Yà�H‰H�R‹LØ�K‰K˜‹O˜fŸi™i¨›lÑ*Ø�H‰H�R‹L˜FŸI™I a›L¨9Ñ4Ñ5Ø�H‰H�R‹L˜6Ÿ9™9 Q›<Ñ'Ø�H‰H�R‹L˜6Ÿ9™9 Q›<Ñ'ð	
ò 	;Øô
€Eˆ/Ñð ×Ñ $ÐÓ'Ð'r)   c                óB  — t        | t        «      rt        | j                  d«      t        «      st	        j
                  «       S g }| d   D ]¹  }t        |t        «      sŒdD �ci c]  }||j                  |«      “Œ }}dD ]‚  \  }}|j                  |g «      }t        |t        «      sŒ)|D ]U  }t        |«      }	t        |t        «      r"|	j                  |«       ||	vrd|	v r|	d   |	|<   n||	|<   |j                  |	«       ŒW Œ„ Œ» t	        j
                  |«      S c c}w )zEExpand convenient JSON theme definitions into normal membership rows.Úthemes)r   r   r   r   ))Ústocksr   )Úmembersr   )Úindustry_codesr   r+   )	rM   r   rP   r&   r$   r%   ÚdictÚupdateÚappend)
r]   ÚrowsÚthemeÚkeyÚcommonÚ
member_keyÚ
output_keyr=   rZ   Úrows
             r'   Ú_expand_theme_jsonrÆ   ¨   s  € ä�cœ7Ô#¬:°c·g±g¸hÓ6GÌÔ+NÜ�|‰|‹~ÐØ$&€DØ�X”ˆÜ˜%¤Ô)ØÙ1]Ó^Ñ1]¨#�#�u—y‘y “~Ñ%Ð1]ˆÐ^ó 'CÑ"ˆJ˜
Ø—Y‘Y˜z¨2Ó.ˆFÜ˜f¤dÔ+ØÛ�Ü˜6“l�Ü˜e¤WÔ-Ø—J‘J˜uÔ%Ø!¨Ñ,°ÀÑ1DØ*-¨lÑ*;˜˜Jšà&+�C˜
‘OØ—‘˜CÕ ñ  ñ	 'Cð	 ô" �<‰<˜ÓÐùò _s   Á#Dc                ó  — d}t        | t        «      r| }n§| �¥t        | t        j                  «      s‹| dk7  r†t	        t        | «      «      }|j                  «       r|nt	        |«      |z  }|j                  j                  «       dk(  r5|j                  «       r%t        j                  |j                  d¬«      «      }t        |«      }t        | t	        |«      d«      }|j                  st        j                   ||gdd¬	«      n|}|j                  rt#        t$        «      S t'        |«      }d
|vrG|j)                  dt        j*                  d|j,                  ¬«      «      j/                  t
        «      |d
<   d|vr|d
   |d<   dD ]M  }||vrd||<   ||   j1                  d«      j/                  t
        «      j
                  j3                  «       ||<   ŒO t        j4                  t7        |dd«      d¬«      j1                  d«      j9                  d¬«      |d<   |j:                  |d
   j=                  d«      |d   j=                  d«      |d   j=                  d«      z  z     }|t$           j?                  «       jA                  d¬«      S )z@Load custom stock/industry-to-theme membership from CSV or JSON.NrG   rI   rJ   rK   rº   TF©Úignore_indexr‰   r   r   r@   )r   r   r   r   r   r   ç      ð?r6   r7   r   ©r1   r   r   r˜   )!rM   r   r$   r%   r   r/   rQ   rS   r1   rR   rU   rV   rW   rÆ   rX   rš   rx   r(   Ú_EMPTY_MAPPING_COLUMNSr4   rP   rB   rA   r.   r§   r0   rq   rE   rr   rœ   r¡   r£   r¬   )rZ   r[   Úraw_jsonr^   ÚexpandedÚtabler2   rC   s           r'   Úload_theme_mappingrÐ   Á   s/  € à"€HÜ�%œÔ!Ø‰Ø	Ð	¤:¨e´R·\±\Ô#BÀuÐPRÂ{Ü”C˜“JÓˆØ×'Ñ'Ô)‰t¬t°H«~ÀÑ/DˆØ�;‰;×ÑÓ 'Ò)¨d¯k©k¬mÜ—z‘z $§.¡.¸' .Ó"BÓCˆHÜ! (Ó+€HÜ˜œt H›~¨yÓ9€EØOWÏ~Ê~ŒB�I‰I�u˜hÐ'°dÀÕGÐch€EØ‡{‚{ÜÔ,Ó-Ð-Ü! %Ó(€EØ˜ÑØ!ŸI™I l´B·I±I¸bÈÏÉÔ4TÓU×\Ñ\Ô]`ÓaˆˆjÑØ˜5Ñ Ø# JÑ/ˆˆlÑÛTˆØ˜ÑØˆE�&‰MØ˜f™×,Ñ,¨RÓ0×7Ñ7¼Ó<×@Ñ@×FÑFÓHˆˆfŠð Uô —m‘mÔ$6°u¸hÈÓ$LÐU]Ô^×eÑeÐfiÓj×oÑoÐvwÐoÓx€Eˆ(�OØ�I‰I�e˜JÑ'×*Ñ*¨2Ó.°%¸Ñ2F×2IÑ2IÈ"Ó2MÐPUÐVeÑPf×PiÑPiÐjlÓPmÑ2mÑnÑo€EØÔ'Ñ(×8Ñ8Ó:×FÑFÈDÐFÓQÐQr)   c                ó²  — t        | t        j                  «      rt        | «      }n+t        j                  dt	        | «      i«      }t        |«      }d|vrt        d«      ‚|j                  d«      }|�|j                  rt        t        «      S t        |«      }|dg   j                  |j                  |d   j                  d«         dd¬«      }t        t        «      }d|v rj|d   j                  d«      j                  «       rH|ddg   j                  |j                  |d   j                  d«         j                  d¬«      dd¬«      }t        j                   ||gdd	¬
«      }|j                  rt        t        «      S t        j"                  |d   d¬«      j%                  d«      |d<   |t           j                  ddg«      j'                  d¬«      S )z?Map stock codes (and optional industry codes) to custom themes.r   ú/stocks needs a source_code or stock_code columnrG   Úinner©ÚonÚhowr   r"   TFrÈ   r   r6   r7   rÊ   r   r˜   )rM   r$   r%   r4   r&   rY   r£   rš   r(   rÌ   rÐ   Úmergerœ   r¡   Úanyr™   rx   rq   r§   r¬   )r¹   Útheme_mappingÚuniverseÚmappingÚdirectÚby_industryr3   s          r'   Úmap_stock_themesrÞ   Þ   s·  € ä�&œ"Ÿ,™,Ô'Ü(¨Ó0‰ä—<‘< ´°V³Ð =Ó>ˆÜ(¨Ó2ˆØ˜HÑ$ÜÐJÓKÐKØ×'Ñ'¨Ó6€HØÐ × 3Ò 3ÜÔ,Ó-Ð-Ü  Ó/€GØ�}�oÑ&×,Ñ,¨W¯[©[¸ÀÑ9O×9RÑ9RÐSUÓ9VÑ-WÐ\iÐovÐ,Ów€FÜÔ/Ó0€KØ˜(Ñ" w¨Ñ'?×'BÑ'BÀ2Ó'F×'JÑ'JÔ'LØ ¨Ð?Ñ@×FÑFØ�K‰K˜ Ñ0×3Ñ3°BÓ7Ñ8×=Ñ=ÀmÐ=ÓTÐYhÐnuð Gó 
ˆô �Y‰Y˜ Ð,¸4ÀeÔL€FØ‡|‚|ÜÔ,Ó-Ð-Ü—}‘} V¨HÑ%5¸hÔG×NÑNÈsÓS€Fˆ8ÑØÔ(Ñ)×9Ñ9¸=È*Ð:UÓV×bÑbÐhlÐbÓmÐmr)   é-   é   ©Úhorizon_daysÚ
grace_daysc               óœ	  ‡— | �| j                   rt        t        «      S t        | «      Šd‰vr!dD ]  }|‰v sŒ‰j	                  |di¬«      Š n d‰vrt        t        «      S t        ‰d   «      ‰d<   |�#t        j                  |«      j                  «       n+t        j                  j                  «       j                  «       }t        ˆfd„dD «       d«      }|rUt        ‰|   «      ‰d<   ‰j                  ‰d   j                  «       ‰d   j                  |«      z     j                  «       Šnt        j                  ‰d<   ‰j                   rt        t        «      S t!        ‰dt!        ‰d	t#        t%        ‰«      «      «      «      j'                  t(        «      ‰d<   t!        ‰d
t!        ‰dd«      «      j+                  d«      j'                  t(        «      ‰d
<   t!        ‰dd«      j+                  d«      j'                  t(        «      j(                  j-                  «       ‰d<   d‰vrd‰d<   t!        ‰dd«      j+                  d«      j'                  t(        «      j(                  j-                  «       j(                  j/                  «       ‰d<   t        j0                  t!        ‰dd«      d¬«      j+                  d«      ‰d<   t        j0                  t!        ‰dd«      d¬«      j+                  d«      ‰d<   t3        j4                  ‰d   j7                  d«      ‰d   dz  ‰d   «      j9                  dd«      ‰d<   t3        j4                  ‰d   j7                  d«      ‰d   dz  ‰d   «      j9                  dd«      ‰d<   ‰d   |z
  j:                  j<                  ‰d<   ‰d   }t3        j>                  |jA                  d|«      |jA                  | d«      gd|j9                  d¬«      tC        |d«      z  z
  dgd¬«      ‰d<   ‰d   jE                  h d £«      }‰d   jE                  h d!£«      }	t3        j4                  |	dt3        j4                  ‰d   jE                  d"d#h«      d$d%«      «      }
d&‰d   z  ‰d   z  ‰d   z  |
z  j5                  | d«      ‰d'<   ‰t        D �cg c]	  }|‰v sŒ|‘Œ c}   jG                  d(¬)«      S c c}w )*zHReturn catalysts known at ``as_of`` with status and timing-aware scores.Nr   )Úexpected_dateÚ
event_dater   r"   c              3  ó,   •K  — | ]  }|‰v sŒ|–— Œ y ­w©N© )Ú.0r�   r2   s     €r'   Ú	<genexpr>z%evaluate_catalysts.<locals>.<genexpr>  s   øè ø€ ÐtÑ.b dÐfjÐnsÒfsœTÑ.bùs   ƒ	�rƒ   r   r   Úidr    ÚnamerG   r   r   r   u   è®¡åˆ’r   rÊ   r6   r7   r   rn   g      Y@r   r   éÿÿÿÿrË   g      Ð?r�   r—   r   >   õ   å�–æ¶ˆõ   å¤±æ•ˆÚexpiredÚcanceledÚ	cancelled>   õ   ç¡®è®¤õ	   å·²ç¡®è®¤Ú	confirmedu   ä¼ é—»Úrumorg333333ã?gš™™™™™é?rg   r   Tr˜   )$rš   r(   Ú_EMPTY_CATALYST_COLUMNSr4   r-   r>   r$   rž   r;   ÚtodayÚnextrœ   r    rŸ   r,   ÚNaTrE   ÚrangeÚlenr.   r/   r§   r0   r1   rq   rs   Úwherer«   rr   r:   Údaysr©   ÚbetweenÚmaxÚisinr¬   )Ú	catalystsr®   râ   rã   Úalternativer¯   Úavailable_columnrÿ   ró   rö   Ú
confidencerC   r2   s               @r'   Úevaluate_catalystsr  ø   sœ  ø€ ð Ð˜IŸOšOÜÔ-Ó.Ð.Ü! )Ó,€EØ˜eÑ#ÛBˆKØ˜eÒ#ØŸ™¨k¸?Ð-K˜ÓL�Ùð Cð ˜eÑ#ÜÔ-Ó.Ð.Ü,¨U°?Ñ-CÓD€Eˆ/ÑØ05Ð0AŒR�\‰\˜%Ó ×*Ñ*Ô,ÄrÇ|Á|×GYÑGYÓG[×GeÑGeÓGg€FÜÓtÑ.bÓtÐvzÓ{ÐÙÜ"1°%Ð8HÑ2IÓ"JˆÐÑØ—	‘	˜%Ð 0Ñ1×6Ñ6Ó8¸5ÐAQÑ;R×;UÑ;UÐV\Ó;]Ñ]Ñ^×cÑcÓe‰ä"$§&¡&ˆÐÑØ‡{‚{ÜÔ-Ó.Ð.Ü-¨e°]ÔDVÐW\Ð^bÔdiÔjmÐnsÓjtÓduÓDvÓw×~Ñ~ô  @Có  D€Eˆ-ÑÜ'¨¨wÔ8JÈ5ÐRXÐZ\Ó8]Ó^×eÑeÐfhÓi×pÑpÔqtÓu€Eˆ'�NÜ*¨5°*¸bÓA×HÑHÈÓL×SÑSÔTWÓX×\Ñ\×bÑbÓd€Eˆ*ÑØ˜EÑ!Ø!ˆˆmÑÜ(¨°¸(ÓC×JÑJÈ8ÓT×[Ñ[Ô\_Ó`×dÑd×jÑjÓl×pÑp×vÑvÓx€Eˆ(�OÜ—m‘mÔ$6°u¸hÈÓ$LÐU]Ô^×eÑeÐfiÓj€Eˆ(�OÜŸ=™=Ô);¸EÀ=ÐRUÓ)VÐ_gÔh×oÑoÐpsÓt€Eˆ-ÑÜ—h‘h˜u X™×1Ñ1°!Ó4°e¸H±oÈÑ6MÈuÐU]ÉÓ_×dÑdÐefÐhiÓj€Eˆ(�OÜŸ8™8 E¨-Ñ$8×$;Ñ$;¸AÓ$>ÀÀmÑ@TÐW\Ñ@\Ð^cÐdqÑ^rÓs×xÑxÐyzÐ|}Ó~€Eˆ-ÑØ!& Ñ!7¸&Ñ!@× DÑ D× IÑ I€EÐ
ÑØÐ#Ñ$€DÜ"$§)¡)Ø	�‰�a˜Ó	&¨¯©°j°[À"Ó(EÐFØ	
ˆT�Y‰Y˜QˆYÓ¤# l°AÓ"6Ñ6Ñ	6¸Ð=Øô#€EÐ
Ñð
 �h‘×$Ñ$Ò%]Ó^€IØ�h‘×$Ñ$Ò%IÓJ€IÜ—‘˜) S¬"¯(©(°5¸±?×3GÑ3GÈÐSZÐH[Ó3\Ð^aÐcfÓ*gÓh€JØ" U¨8¡_Ñ4°u¸]Ñ7KÑKÈeÐThÑNiÑiÐlvÑv×}Ñ}ð  @Ið  Ið  KNó  O€EÐ
ÑØÕ'>ÓRÑ'>˜VÀ&ÈEÂ/’&Ð'>ÑRÑS×_Ñ_ÐeiÐ_ÓjÐjùÒRs   Ò&	S	Ò0S	c                ó  ‡— | j                   t        j                  | ‰   d¬«      j                  «          j	                  «       }|j
                  rt        j                  d‰g¬«      S t        j                  |j                  dd«      d¬«      j                  d«      j                  d¬«      |d	<   t        j                  |‰   d¬«      |d
<   |j                  dd¬«      j                  ˆfd„«      j                  d¬«      S )Nr6   r7   r   r"   r   rÊ   r   rË   Ú_weightÚ_valueF©Úas_indexc                óh   •— t        j                  ‰t        j                  | d   | d   ¬«      i«      S )Nr
  r	  )Úweights)r$   rB   rs   Úaverage)ÚgrouprZ   s    €r'   rŽ   z#_weighted_average.<locals>.<lambda>3  s(   ø€ ”b—i‘i ¬¯
©
°5¸±?ÈEÐR[ÑL\Ô(]Ð ^Ô_r)   Tr˜   )rœ   r$   rq   r�   r,   rš   r%   rP   r§   rr   rv   Úapplyr¬   )r2   rZ   Úvalids    ` r'   Ú_weighted_averager  ,  sÏ   ø€ Ø�I‰I”b—m‘m E¨%¡L¸ÔB×HÑHÓJÑK×PÑPÓR€EØ‡{‚{Ü�|‰| ]°EÐ$:Ô;Ð;Ü—}‘} U§Y¡Y¨x¸Ó%=ÀhÔO×VÑVÐWZÓ[×`Ñ`ÐghÐ`Ói€Eˆ)ÑÜ—m‘m E¨%¡L¸ÔB€Eˆ(�OØ�=‰=˜°ˆ=Ó7×=Ñ=Û_óç�k�t€kÓðr)   T)Úfrozenc                  óX   — e Zd ZU dZded<   ded<   ded<   ded<   ded<   d	ed
<   ddd„Zy)ÚResearchContextzFLoaded point-in-time research inputs and a stock-level scoring facade.zpd.Timestamp | Noner®   úpd.DataFramer­   Ú	lifecyclerÙ   r  zMapping[str, float]r  Nc           
     óz  — t        |t        j                  «      rt        |«      }n)t        t        j                  dt	        |«      i«      «      }d|vrt        d«      ‚|j                  d«      j                  «       }t        || j                  «      }| j                  j                  «       }|�#t        j                  |«      j                  «       n| j                  }|�-|j                  s!|j                  |d   j!                  |«         }|j                  s"|j#                  d«      j                  dd¬«      nt%        t&        «      }|j                  s|j)                  |g d¢   ddd	¬
«      nt        j                  «       }|j                  st+        |d«      nt        j                  ddg¬«      }	|j                  s'|j#                  dd¬«      j                  d«      ddg   nt        j                  ddg¬«      }
t        j                  ddg¬«      }d|v rP|j                  sDd| j,                  v r6|ddg   j)                  |ddg   ddd	¬
«      ddg   j/                  ddi¬«      }| j0                  j                  «       }|�t3        ||«      }|j                  s&|j                  |d   j5                  d«         ddg   nt        j                  «       }|j                  sD|j                  s8|j)                  |j                  |d   j5                  d«         ddg   dd¬«      nt        j                  «       }|j                  st+        |d«      nt        j                  ddg¬«      }|j                  r|j                  st        j6                  ||gd¬«      nt        j                  ddg¬«      }|j                  s$|j9                  dd¬«      d   j;                  «       n|}|j)                  |dd	¬«      j)                  |	dd	¬«      j)                  |
dd	¬«      j)                  |dd	¬«      }|j                  sD|j9                  d«      d   j=                  d„ «      j?                  |d   «      jA                  «       nd|d<   |j                  sD|j9                  d«      d   j=                  d„ «      j?                  |d   «      jA                  «       nd|d<   g d¢}d D �ci c](  }|tC        | jD                  jG                  |d!«      «      “Œ* }}tI        |jK                  «       «      xs d"}|d   jM                  d#«      |d$   z  |d   jM                  d#«      |d%   z  z   |d   jM                  d#«      |d&   z  z   |z  |d'<   ||   jO                  «       jQ                  d(¬)«      |d*<   tR        |d+<   |S c c}w ),zMScore a stock universe; absent optional data contributes no artificial score.r   rÒ   r   r
   r†   r‡   )r
   r   r   r   Úleft)Úleft_onÚright_onrÖ   r   r"   r   F)Ú	ascendingr   Úindustry_scorer   rG   r   rÓ   rÔ   T)rÉ   r  c                óJ   — dj                  t        j                  | «      «      S )NÚ;©Újoinr¼   Úfromkeysr<   s    r'   rŽ   z.ResearchContext.score_stocks.<locals>.<lambda>g  s   € Ð_b×_gÑ_gÔhl×huÑhuÐv|Óh}Ô_~r)   Ú	theme_idsr   c                óJ   — dj                  t        j                  | «      «      S )Nu   ï¼›r!  r<   s    r'   rŽ   z.ResearchContext.score_stocks.<locals>.<lambda>h  s)   € Ðch×cmÑcmÔnr×n{Ñn{ð  }Có  oDô  dEr)   Útheme_names)r  r   r   ©ÚindustryÚhotspotÚcatalystr�   rÊ   r   r(  r)  r*  Úresearch_context_scorern   ro   Úresearch_context_coverageÚmodel_version)*rM   r$   r%   r4   r&   rY   r£   r,   rÞ   rÙ   r  rž   r;   r®   rš   rœ   rŸ   r¢   r(   r›   r×   r  r­   r-   r  r  r¡   rx   rv   r  ÚaggÚreindexÚto_numpyru   r  rP   Úsumr=   r§   r�   ry   ÚRESEARCH_CONTEXT_MODEL_VERSION)Úselfr¹   r®   rÚ   Ú
membershipr  r¯   ÚlatestÚthemedr)  Ústager(  r*  Ú
direct_catÚ	theme_catÚ	cat_partsÚ	cat_scorer3   Úcomponent_columnsrÁ   Ú
configuredÚtotal_weights                         r'   Úscore_stockszResearchContext.score_stocksB  sª  € ä�fœbŸl™lÔ+Ü,¨VÓ4‰Hä,¬R¯\©\¸=Ì$ÈvË,Ð:WÓ-XÓYˆHØ Ñ(ÜÐNÓOÐOØ×+Ñ+¨MÓ:×?Ñ?ÓAˆÜ% h°×0BÑ0BÓCˆ
Ø—N‘N×'Ñ'Ó)ˆ	Ø49Ð4E”—‘˜eÓ$×.Ñ.Ô0È4Ï:É:ˆØÐ i§o¢oØ!Ÿ™ i°Ñ&7×&:Ñ&:¸6Ó&BÑCˆIØbk×bqÒbq�×&Ñ& vÓ.×>Ñ>¸}ÐSYÐ>ÔZÔw}ô  Wó  xXˆð ]g÷  ]mò  ]m�×!Ñ! &Ò)ZÑ"[Ðeoð  {Hð  NTÐ!ô  Uô  su÷  sñ  só  sAˆØDJÇLÂLÔ# F¨OÔ<ÔVX×VbÑVbÐlyð  |Kð  lLô  WMˆàŸšð ×#Ñ# H¸Ð#Ó>×NÑNÈ}Ó]Ð_lÐn}Ð^~ÒÜ*,¯,©,ÀÈÐ?_Ô*`ð 	ô —<‘<¨Ð8HÐ(IÔJˆØ˜hÑ&¨v¯|ª|ÀÐSW×SeÑSeÑ@eØ °Ð @ÑA×GÑGØ˜ Ð7Ñ8À/Ð\iÐouð Hó à˜oÐ.ñ0ç06±ÀÐQaÐ?b°Ó0cð ð —>‘>×&Ñ&Ó(ˆØÐÜ)¨(°FÓ;ˆHØlt×lzÒlz�X—\‘\ (¨=Ñ"9×"<Ñ"<¸RÓ"@ÑAÀ=ÐRbÐBcÒdô  AC÷  AMñ  AMó  AOˆ
ð T^÷  Tdò  Tdð  mu÷  m{ò  m{�J×$Ñ$ X§\¡\°(¸:Ñ2F×2IÑ2IÈ"Ó2MÑ%NÐPZÐ\lÐOmÑ%nÐs}ð  DKÐ$ô  Lô  AC÷  AMñ  AMó  AOˆ	ØJSÏ/Ê/Ô% iÐ1AÔBÔ_a×_kÑ_kð  vCð  EUð  uVô  `Wˆ	ØQ[×QaÒQaÐir×ixÒix”B—I‘I˜z¨9Ð5ÀDÕIô  A÷  Kñ  Kð  Ubð  dtð  Tuô  vˆ	Ødm×dsÒds�I×%Ñ% m¸eÐ%ÓDÐEUÑV×ZÑZÔ\ð  zCˆ	à—‘ ¨]À�ÓG×MÑMÈgÐZgÐmsÐMÓt×zÑzð  |Að  FSð  Y_Ðzó  `÷  fñ  fð  gpð  uBð  HNð  fó  Oˆð r|÷  rBò  rB˜j×0Ñ0°Ó?À
ÑK×OÑOÑP~Ó÷  Hñ  Hð  IOð  P]ñ  I^ó  _÷  hñ  hô  jð  HJˆˆ{Ñð xB÷  xHò  xH 
× 2Ñ 2°=Ó AÀ,Ñ O× SÑ Sñ  UEó  !F÷  !Nñ  !Nð  OUð  Vcñ  Odó  !e÷  !nñ  !nô  !pð  NPˆˆ}ÑÚQÐÙHkÓlÑHkÀ�cœ5 §¡×!1Ñ!1°#°sÓ!;Ó<Ñ<ÐHkˆ
ÐlÜ˜:×,Ñ,Ó.Ó/Ò6°3ˆàÐ#Ñ$×+Ñ+¨AÓ.°¸JÑ1GÑGØ�_Ñ%×,Ñ,¨QÓ/°*¸YÑ2GÑGñHàÐ%Ñ&×-Ñ-¨aÓ0°:¸jÑ3IÑIñJð ñ	,ˆÐ'Ñ(ð
 /5Ð5FÑ.G×.MÑ.MÓ.O×.TÑ.TÐZ[Ð.TÓ.\ˆÐ*Ñ+Ü"@ˆˆÑØˆùò ms   Ó%-V8rè   )r¹   úpd.DataFrame | Sequence[str]r®   ú str | date | pd.Timestamp | NoneÚreturnr  )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r?  ré   r)   r'   r  r  7  s.   … áPàÓØÓØÓØÓØÓØ Ó õ1r)   r  c                ó  — t        | xs i «      }t        |j                  d«      t        «      rt        |d   «      }t	        |j                  dd«      «      }t        |j                  d|j                  d«      «      |d«      }t        |j                  d|j                  d«      «      |«      }t        |j                  d|j                  d	«      «      |d	«      }|�#t        j                  |«      j                  «       nd
}t        ||t        |j                  dd«      «      |j                  d«      t        |j                  dd«      «      ¬«      }t        ||t        |j                  dd«      «      t        |j                  dd«      «      ¬«      }	ddddœ}
|
j                  t        |j                  di «      «      j                  «       D ��ci c]  \  }}||
v sŒ|t!        |«      “Œ c}}«       t#        |||||	|
«      S c c}}w )a-  Load optional CSV/JSON research inputs specified by a plain TOML mapping.

    Accepted keys are ``industry_data_path``, ``theme_mapping_path`` and
    ``catalyst_path`` (the shorter ``industry_data``, ``theme_mapping`` and
    ``catalysts`` aliases also work), plus ``base_dir`` and ``weights``.
    Úresearch_contextr[   Ú.Úindustry_data_pathr­   Útheme_mapping_pathrÙ   Úcatalyst_pathr  Nr€   r~   r�   rz   r   r   Úcatalyst_horizon_daysrß   Úcatalyst_grace_daysrà   rá   gffffffÖ?g333333Ó?r'  r  )r¼   rM   rP   r   r   rX   rÐ   r$   rž   r;   r¶   Úintr/   r  r½   Úitemsru   r  )Úconfigr®   r]   r[   r(  rÛ   Úcatalyst_inputr¯   r  r  r  rÁ   rZ   s                r'   Úload_research_contextrT  v  sÄ  € ô ˆvŠ|˜Ó
€CÜ�#—'‘'Ð,Ó-¬wÔ7Ü�3Ð)Ñ*Ó+ˆÜ�C—G‘G˜J¨Ó,Ó-€HÜ˜3Ÿ7™7Ð#7¸¿¹ÀÓ9QÓRÐT\Ð^mÓn€HÜ  §¡Ð)=¸s¿w¹wÀÓ?WÓ!XÐZbÓc€GÜ  §¡¨¸#¿'¹'À+Ó:NÓ!OÐQYÐ[fÓg€NØ05Ð0AŒR�\‰\˜%Ó ×*Ñ*Ô,Àt€FÜ*Ø�&Ü˜Ÿ™ °Ó3Ó4Ø—W‘W˜^Ó,Ü˜Ÿ™ ¨vÓ6Ó7ô	€Iô #Ø˜Ü˜Ÿ™Ð!8¸"Ó=Ó>Ü�s—w‘wÐ4°aÓ8Ó9ô€Ið
  ¨D¸dÑC€GØ‡N�N¼¸S¿W¹WÀYÐPRÓ=SÓ8T×8ZÑ8ZÔ8\ÔoÑ8\©*¨#¨uÐ`cÐgnÒ`n�Cœ˜u›Ñ%Ð8\ÒoÔpÜ˜6 8¨Y¸ÀÈGÓTÐTùó ps   ÇH
ÇH
)r#   zSequence[str]rB  r  )r2   r  rB  r  )r=   ú	pd.SeriesrB  rU  )r2   r  rC   r/   rD   ÚobjectrB  rU  rè   )rZ   rV  r[   r   r\   ú
str | NonerB  r  )r2   r  rB  rU  )r2   r  rz   r/   rB  rU  )r­   r  r®   rA  r€   rP  r�   rW  rz   r/   rB  r  )r]   rV  rB  r  )NrJ  )rZ   rV  r[   z
Path | strrB  r  )r¹   r@  rÙ   r  rB  r  )
r  r  r®   rA  râ   rP  rã   rP  rB  r  )r2   r  rZ   r/   rB  r  )NN)rR  zMapping[str, Any] | Noner®   rA  rB  r  )%rF  Ú
__future__r   Údataclassesr   Údatetimer   Úpathlibr   Útypingr   r   r	   rU   Únumpyrs   Úpandasr$   r2  r›   rÌ   rø   r(   r4   r>   rE   rX   rc   r}   r¶   rÆ   rÐ   rÞ   r  r  r  rT  ré   r)   r'   Ú<module>r_     sI  ðñõ #å !Ý Ý ß )Ñ )Û ã Û ð ")Ð òÐ ò fÐ òÐ ó/óóBóWô
Ió67ó	1ð /3ð>(ð Ø#Øñ>(Øð>(à+ð>(ð ð	>(ð
 ð>(ð ð>(ð ó>(óBô2Ró:nð8 /3ð1kð Øñ1kØð1kà+ð1kð ð	1kð
 ð1kð ó1kóhñ �$Ô÷;ð ;ó ð;õ|Ur)   