Ë
    xWj�  ã                  ó¢   — d Z ddlmZ ddlmZ ddlmZ e G d„ d«      «       Ze G d„ d«      «       Zdd	„Z	dd
„Z
	 	 	 	 dd„Zddd„Zdd„Zdd„Zy)zÛShared scoring primitives.

Strategies express each signal as a 0..1 "sub-score" and combine them with
weights. These helpers turn raw metrics into 0..1 signals in a readable way
so the strategy files stay declarative.
é    )Úannotations)Ú	dataclass)ÚOptionalc                  óD   — e Zd ZU ded<   ded<   ded<   ded<   dZded	<   y
)ÚSignalÚstrÚnameúOptional[float]ÚvalueÚscoreÚfloatÚweightÚ ÚnoteN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__r   © ó    ú./var/www/html/finance-tool/screener/scoring.pyr   r      s!   … à
ƒIØÓØÓØƒMØ€Dˆ#„Nr   r   c                  ó>   — e Zd ZU ded<   ded<   ded<   ded<   d
d„Zy	)ÚStrategyResultr   Ústrategyr   r   úlist[Signal]ÚsignalsÚverdictc                óŠ   — dt        | j                  d«      i}| j                  D ]  }|j                  ||j                  <   Œ |S )Nr   é   )Úroundr   r   r   r	   )ÚselfÚrowÚss      r   Úas_rowzStrategyResult.as_row   s@   € Øœ˜dŸj™j¨!Ó,Ð-ˆØ—‘ò 	"ˆAØŸ'™'ˆC�—‘ŠKð	"àˆ
r   N)ÚreturnÚdict)r   r   r   r   r$   r   r   r   r   r      s   … àƒMØƒLØÓØƒLôr   r   c                óL   — | €y||k(  r	| |k\  rdS dS t        | |z
  ||z
  z  «      S )u#  1.0 when value >= hi, 0.0 when <= lo, linear between.

    None -> None so the signal is *excluded* from the weighted average rather
    than scored a rewarding 0.5. (Damodaran/McKinsey: a missing or negative
    metric should not silently count as neutral â€” e.g. a loss-maker's P/E.)
    Nç      ð?ç        ©Ú_clamp©r   ÚloÚhis      r   Úhigher_betterr/   $   s<   € ð €}ØØ	ˆR‚xØ˜r’kˆsÐ* sÐ*Ü�5˜2‘: " r¡'Ñ*Ó+Ð+r   c                óR   — | €y||k(  r	| |k  rdS dS t        d| |z
  ||z
  z  z
  «      S )z>1.0 when value <= lo, 0.0 when >= hi. None -> None (excluded).Nr(   r)   r*   r,   s      r   Úlower_betterr1   2   s?   € à€}ØØ	ˆR‚xØ˜r’kˆsÐ* sÐ*Ü�#˜ ™¨¨R©Ñ0Ñ0Ó1Ð1r   c                ó€   — | €y| |k  r||k(  ryt        | |z
  ||z
  z  «      S ||k(  ryt        d| |z
  ||z
  z  z
  «      S )a  Inverted-U: rewards a moderate value, penalises extremes.

    Rises 0->1 as value goes rise_from->peak, then falls 1->0 as it goes
    peak->fade_to. Used for Shiller-style narrative virality, where a story
    *fuels* a move but an *extreme* reading marks the blow-off top.
    Nr(   r*   )r   Ú	rise_fromÚpeakÚfade_tos       r   Úhump_betterr6   ;   s_   € ð €}ØØ�‚}Ø�9ÒØÜ�u˜yÑ(¨T°IÑ-=Ñ>Ó?Ð?Ø�$‚ØÜ�#˜ ™¨'°D©.Ñ9Ñ9Ó:Ð:r   c                ó.   — t        |t        || «      «      S ©N)ÚmaxÚmin)Úxr-   r.   s      r   r+   r+   N   s   € Üˆr”3�r˜1“:ÓÐr   c                ó¨   — | D �cg c]  }|j                   €Œ|‘Œ }}t        d„ |D «       «      }|dk(  ryt        d„ |D «       «      }d|z  |z  S c c}w )uÖ   Weighted average of sub-scores, rescaled to 0..100.

    Signals with score None are skipped and their weight removed, so absent
    data neither rewards nor penalises â€” the score reflects only what we know.
    c              3  ó4   K  — | ]  }|j                   –— Œ y ­wr8   )r   ©Ú.0r#   s     r   ú	<genexpr>zcombine.<locals>.<genexpr>Y   s   è ø€ Ò+˜q�!—(•(Ñ+ùs   ‚r   r)   c              3  óN   K  — | ]  }|j                   |j                  z  –— Œ y ­wr8   )r   r   r>   s     r   r@   zcombine.<locals>.<genexpr>\   s   è ø€ Ò6¨!�1—7‘7˜QŸX™XÕ%Ñ6ùs   ‚#%g      Y@)r   Úsum)r   r#   ÚactiveÚtotal_wÚweighteds        r   ÚcombinerF   R   s_   € ð !Ö8�A A§G¡GÑ$7ŠaÐ8€FÐ8ÜÑ+ FÔ+Ó+€GØ�!‚|ØÜÑ6¨vÔ6Ó6€HØ�8Ñ˜gÑ%Ð%ùò 9s
   …A—Ac                ó(   — | dk\  ry| dk\  ry| dk\  ryy)NéK   z
Strong fité<   zGood fité-   ÚMixedzWeak fitr   )r   s    r   Úverdict_fromrL   `   s#   € Ø�‚{ØØ�‚{ØØ�‚{ØØr   N)r   r
   r-   r   r.   r   r%   r
   )
r   r
   r3   r   r4   r   r5   r   r%   r
   )r)   r(   )r;   r   r-   r   r.   r   r%   r   )r   r   r%   r   )r   r   r%   r   )Ú__doc__Ú
__future__r   Údataclassesr   Útypingr   r   r   r/   r1   r6   r+   rF   rL   r   r   r   ú<module>rQ      su   ðñõ #å !Ý ð ÷ð ó ðð ÷
ð 
ó ð
ó,ó2ð;Øð;Ø#2ó;ô&ó&ôr   