o
    >œ j¬P  ã                   @   sº  d Z ddlmZmZ ddlmZ dZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdZdZdZdZdZi dd“dd“dd“dd“dd “d!d"“d#d$“d%d$“d&d'“d(d)“d*d+“d,d-“d.d/“d0d1“d2d“d3i eg d4¢“ed5dg“e
d6g“ed5g“e	dg“ed6g“ed7g“eg “eg “eg “eg “ed8g“eg “ed7g“ed7d6g“ed6g“ed6d5g“ed6d5ged5d6gi¥“ZeG d9d:„ d:ƒƒZd;ed<ed=efd>d?„Z	@	@dFd;edAedBedCed=ef
dDdE„Z d@S )Ga+  
regime_engine.py

[SIMULATION-ONLY 2026-09-05] LIVE, continuously-re-evaluated regime
classifier -- combines trend_engine.TrendReading + structure_engine.
StructureReading + stream_features.StreamFeatures into one label
describing what's happening RIGHT NOW, and which entry setups (per the
future setup_engine.py) are allowed in that regime. Not consumed
anywhere in the live bot yet -- see config.json's regime_engine._note.

NOT THE SAME MODULE AS regime_detector.py (built earlier this session)
-- deliberately kept separate, answering a different question:

    regime_detector.py   "What KIND OF SESSION did/is this symbol
                          have(ing), overall?" -- computed once (or on a
                          fixed window) for offline strategy simulation
                          against a full day's data
                          (simulate_regime_strategies.py). Its regimes:
                          NORMAL_MOMENTUM, GAP_MOMENTUM,
                          CATALYST_GAP_HIGH_VOLATILITY, RANGE_CHOP,
                          FAILED_BREAKOUT, RECOVERY_RECLAIM,
                          INTRADAY_SPIKE_NO_GAP_WHIPSAW.

    regime_engine.py (this file)   "What's happening in this symbol's
                          price action RIGHT NOW, this instant?" --
                          re-evaluated every cycle from live trend/
                          structure/feature readings, feeding the live
                          entry decision. Its regimes are the original
                          design brief's list: STRONG_UPTREND,
                          WEAK_UPTREND, BREAKOUT, PULLBACK, VWAP_RECLAIM,
                          OPENING_VOLATILITY, RANGE, CHOP, DISTRIBUTION,
                          DOWNTREND, FAILED_BREAKOUT, RECOVERY.

Same names appearing in both (FAILED_BREAKOUT) describe genuinely
related but differently-scoped ideas -- one retrospective/whole-session,
one instantaneous/live -- exactly like structure_engine.py's swing-pivot
detection vs indicators.is_higher_highs_higher_lows()'s windowed-bar
check: neither is a duplicate of the other.
é    )Ú	dataclassÚfield)Ú
get_configÚOPENING_VOLATILITYÚFAILED_BREAKOUTÚRECOVERYÚVWAP_RECLAIMÚBREAKOUTÚPULLBACKÚDISTRIBUTIONÚSTRONG_UPTRENDÚWEAK_UPTRENDÚ	DOWNTRENDÚRANGEÚCHOPÚSTRUCTURE_BREAKDOWNÚACCUMULATIONÚPRESSURE_BUILDINGÚBREAKOUT_ATTEMPTÚBREAKOUT_CONFIRMEDÚ	EXPANSIONÚCONTINUATIONÚ!opening_volatility_window_minutesé   Úopening_volatility_min_atr_pctç      ð?Úpullback_trend_slope_thresholdg      à¿Ú$distribution_min_volume_accelerationgÍÌÌÌÌÌô?Údistribution_max_trend_slopegš™™™™™É¿Úvwap_reclaim_min_time_below_pctg      >@Úchop_min_atr_pctgš™™™™™é?Úrange_max_atr_pctÚstructure_breakdown_hard_blockTÚ"accumulation_min_compression_scoreé7   Ú-pressure_building_min_breakout_pressure_scoreéF   Úbreakout_confirm_barsé   Úexpansion_min_barsé   Úcontinuation_min_barsé   Úbreakout_volume_confirm_ratioÚallowed_setups)ÚPULLBACK_CONTINUATIONÚBREAKOUT_RETESTr   r/   r0   ÚCOMPRESSION_EXPANSIONÚHIGHER_LOW_REVERSALc                   @   sp   e Zd ZU eed< eZeed< dZeed< e	e
d�Ze
ed< e	e
d�Ze
ed< dZeed	< e	e
d�Ze
ed
< dS )ÚRegimeReadingÚsymbolÚregimeg        Úscore)Údefault_factoryr.   ÚreasonsFÚinsufficient_dataÚmissingN)Ú__name__Ú
__module__Ú__qualname__ÚstrÚ__annotations__r   r5   r6   Úfloatr   Úlistr.   r8   r9   Úboolr:   © rC   rC   úI/var/www/screener/trade/premarket_backup_2026-09-08_2010/regime_engine.pyr3   Œ   s   
 r3   r4   r:   Úreturnc                 C   s   t | d|d�S )NT)r4   r9   r:   )r3   )r4   r:   rC   rC   rD   Ú_insufficient—   s   rF   NÚsession_elapsed_minutesÚstateÚcfgc              	   C   sò  i t ¥|ptƒ  di ¡¥}|d }g }	t|ddƒr|	 d¡ t|ddƒr)|	 d¡ t|ddƒr4|	 d¡ |	r;t| |	ƒS g }
|jduoP|j d	d
¡|jkoP|jdk}|durc|r_| dd
¡d nd
|d< |pfi  d|rldnd
¡}|d rŒ|j	 d¡rŒ|
 d¡ t
| td|j |t |
d�S |dur½||d kr½|j dd
¡|d kr½|
 d|d›d|j d¡› d�¡ t
| td|t |
d�S |j	 d¡rÔ|
 d¡ t
| t|j|t |
d�S dd„ |jD ƒ}t|ƒdk�r	|d  jd!k�r	|d" jd#k�r	|jd
k�r	|
 d$¡ t
| td%|t |
d�S |j d&d
¡}|j d'd
¡}|d
k�r>||d( k�r>|jd
k�r>|
 d)|d*›d+�¡ t
| td,|t |
d�S |�rº|j d-¡�pId.|d/ k}|d0 }||d1  }||d2  }||k �ryt}|
 d3|j d	¡› d4|j› d5|› �¡ n5||k �r’|�rƒtnt}|
 d6|› d7|› d�¡ n||k �r£t}|
 d8|› d9�¡ nt}|
 d:|› d;�¡ t
| ||j|| |
d�S |jd<v �rä|j|d= k�rä|jd>k�rä|
 d?|j› d�¡ t
| t|j|t |
d�S |j d-¡}|du�r||d@ k�r|j|dA k�r|jdBk�r|
 dC|› dD|j› dE�¡ t
| td%|t |
d�S |jd<v �rH|jdBk�rH|
 dF|j› dG�¡ |jdHk�r:t nt!}t
| ||j|| |
d�S |jdIv �rc|
 dF|j› �¡ t
| t"|j|t" |
d�S |j dd
¡}|jdJk�rÚ||dK k�rÚ|du�rÅt|ddƒ�sÅ|j#|dL k�r¤|
 dM|› dN|j#› dO�¡ t
| t$|j#|t$ |
d�S |j%|dP k�rÅ|
 dM|› dQ|j%› dR�¡ t
| t&|j%|t& |
d�S |
 dM|› d�¡ t
| t'|j|t' |
d�S |
 dS|j› dT|j› dU|› d�¡ t
| t(d|j |t( |
d�S )Va¤  
    features: stream_features.StreamFeatures
    trend: trend_engine.TrendReading
    structure: structure_engine.StructureReading
    session_elapsed_minutes: minutes since regular-session open, or None
        if unknown (in which case OPENING_VOLATILITY can never fire --
        fails safe to "don't know if we're in the opening window" rather
        than guessing).
    compression: [Phase 4, optional] compression_engine.CompressionReading.
        Omit entirely to reproduce this function's exact pre-Phase-4
        behavior for the RANGE branch (ACCUMULATION/PRESSURE_BUILDING can
        only ever fire when this is supplied).
    state: [Phase 4, optional] caller-held per-symbol dict, same ownership
        pattern as entry_score.py's confirmation_state -- this function
        mutates state["bars_since_breakout"] in place and also returns it
        via the reading isn't needed since the caller already holds the
        same dict object; a fresh {} (or None) starts the counter at 0,
        exactly like a cold start anywhere else in this pipeline. Drives
        the BREAKOUT_ATTEMPT -> BREAKOUT_CONFIRMED -> EXPANSION ->
        CONTINUATION progression below.
    Úregime_enginer.   r9   FÚstream_featuresÚtrendÚ	structureNÚlastr   ÚUPÚbars_since_breakouté   r"   Úsupport_failurez�structure_engine confirmed a support failure (broke below the last swing low) -- highest-priority risk state, overrides opening-window handlingg      Y@)r4   r5   r6   r.   r8   r   Úatr_pctr   zwithin opening window (z.1fz%m) with elevated volatility (atr_pct=ú)g     €V@Úfailed_breakoutzMstructure_engine confirmed a failed breakout (broke resistance, gave it back)c                 S   s$   g | ]}|j d kr|jdur|‘qS )ÚLOWN)ÚkindÚlabel)Ú.0ÚsrC   rC   rD   Ú
<listcomp>ö   s   $ z#classify_regime.<locals>.<listcomp>r(   éþÿÿÿÚLLéÿÿÿÿÚHLzKbottomed (LL) then printed a higher low (HL) with momentum turning positiveg      N@Úprice_vs_vwap_pctÚtime_below_pctr   z#price reclaimed VWAP (was below it z.0fz6% of the recent window) with momentum turning positiveg     @P@Úvolume_accelerationr   r-   r'   r)   r+   zprice (z) above last swing high (z), uptrend intact, attempt #zbreakout held for z$ consecutive reads (volume_confirms=zbreakout held z* reads past the initial break -- expansionzbreakout sustained z reads -- continuation)r   r   r   ÚBULLISH_STRUCTUREzRuptrend intact (structure=BULLISH) but short-term momentum weakening (trend_slope=r   r   ÚBEARISH_STRUCTUREzelevated volume (accel=z%x) with fading momentum (trend_slope=z ) ahead of a confirmed breakdownztrend_engine=z", structure does not contradict itr   )ÚWEAK_DOWNTRENDÚSTRONG_DOWNTRENDÚRANGE_STRUCTUREr!   r%   z*structure=RANGE, calm volatility (atr_pct=z), breakout_pressure_score=z* -- compression + bullish context buildingr#   z), compression_score=z -- qualifies as accumulationz%no clear directional edge (structure=z, trend=z
, atr_pct=))ÚDEFAULT_CONFIGr   ÚgetÚgetattrÚappendrF   Úlast_swing_highÚpriceÚ	directionÚflagsr3   r   r6   Ú
volatilityr   r   ÚswingsÚlenrX   Útrend_sloper   Úvwapr   Úvolumer   r   r   r   rH   rM   r
   r   r   r   r   Úbreakout_pressure_scorer   Úcompression_scorer   r   r   )r4   ÚfeaturesrL   rM   rG   ÚcompressionrH   rI   Úallowed_setups_mapr:   r8   Úis_breakout_conditionrP   Ú
low_swingsÚprice_vs_vwapÚ
time_belowÚvolume_confirmsÚ
confirm_atÚexpansion_atÚcontinuation_atr5   Ú	vol_accelrS   rC   rC   rD   Úclassify_regime›   s  




ÿýÿÿ	
ÿ

ÿÿ

ÿ.
ÿ$ÿ

ÿ
ÿ
ÿ

ÿ
ÿ
ÿ
ÿÿ
ÿ
ÿ	
ÿ
ÿ
ÿ
ÿ
ÿÿ
ÿÿr„   )NNNN)!Ú__doc__Údataclassesr   r   Úconfig_loaderr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   rh   r3   r>   rA   rF   r@   Údictr„   rC   rC   rC   rD   Ú<module>   sÔ    (	ÿþýüûúùøôðïèçæå ÿþýüûúùø	÷
öõôòñðïçåà@
þÿþþþ