
    5Yj                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZmZ ddlmZ ej                   j#                  d e ee      j)                         j*                  j*                               ddlmZmZ ddlmZ ddlmZ dd	lmZmZm Z  dd
l!m"Z"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/ d Z0 G d d      Z1 G d d      Z2 G d d      Z3dJdZ4dKdZ5dLdZ6dMdNdZ7dde*jp                  jr                  dddf	 	 	 	 	 	 	 	 	 dOdZ:dPdZ;d Z<d Z=d  Z>d! Z?d" Z@d# ZAd$ ZBd% ZCd& ZDd' ZEd( ZFd) ZGd* ZH G d+ d,      ZId- ZJd. ZKd/ ZLd0 ZMd1 ZNd2 ZOd3 ZPd4 ZQd5 ZRdQd6ZSd7 ZTd8 ZU	 	 	 dR	 	 	 	 	 	 	 dSd9ZVd: ZWd; ZXd< ZYd= ZZd> Z[d? Z\d@ Z]dA Z^dB Z_dC Z`dD ZadE ZbdF ZcdTdGZddTdHZeefdIk(  r ej                   ee              yy)Uz
Smoke tests for brain/brain_tf.py.

Uses FakeAIClient to avoid hitting Anthropic; canned AIResponse drives
each post-validation and entry/exit branch deterministically.

Run:
    cd ~/apex_v16
    python -m tests.test_brain_tf
    )annotationsN)datetimetimezone)Path)extract_pa_signalsscore_pa)TechSnapshot)
AIResponse)BrainTFTF_ASSET_PROFILESGENERIC_PROFILE)RuntimeConfigRunModeAccountKind)
BrainContextBrainDecision	DirectionEntryDecisionMarketStructureRegimeTradeAction
TradeEntryTradeRuntimeutc_nowc           
        K   d|vr@ddl m}  ||j                  |j                  t	        |dd      t	        |dd      d	      |d<    | j
                  ||g|i | d {   }|j                  S 7 w)
N	bias_datar   )BiasDatah1_compatibility      ?	h1_reasontestF)biasallowed_directionr   r    	ambiguous)analysis.biasr   r"   r#   getattrevaluate_entrydecision)brainsymbolsnapargskwargsr   results          */home/work/apex_v16/tests/test_brain_tf.py_evalr0   .   s      & *&"44$T+=sCdK8
{ (5''FtFvFFF?? Gs   AA4!A2"A4c                  0    e Zd ZdZdddZ	 d	 	 	 	 	 ddZy)	FakeAIClientz}
    Mimics AIClient.ask_for_decision: returns a pre-set AIResponse.
    Tracks call count + last prompt for assertions.
    Nc                >    |xs t        d d      | _        g | _        y )Nunknown)text
error_kind)r
   cannedcalls)selfr7   s     r/   __init__zFakeAIClient.__init__H   s    K
 K-/
    c                j   K   | j                   j                  d|d d ||df       | j                  S w)Nask_for_decisionP   )prompt_preview
max_tokenswhere)r8   appendr7   )r9   promptr@   rA   s       r/   r=   zFakeAIClient.ask_for_decisionL   sB      	

-$Sbk$0
  	
 {{s   13N)r7   zAIResponse | NonereturnNone)iX  N)rC   strr@   intrE   r
   )__name__
__module____qualname____doc__r:   r=    r;   r/   r2   r2   C   s.    0
 9='*	r;   r2   c                       e Zd ZdZddZddZy)FakeJsonlLoggerz?In-memory JSONL sink for asserting structured rejection events.c                    g | _         y rD   )events)r9   s    r/   r:   zFakeJsonlLogger.__init__Y   s	    "$r;   c                B    | j                   j                  d|i|       y )Nevent)rQ   rB   )r9   rS   fieldss      r/   writezFakeJsonlLogger.write\   s    GU5f56r;   NrE   rF   )rS   rG   rE   rF   )rI   rJ   rK   rL   r:   rU   rM   r;   r/   rO   rO   W   s    I%7r;   rO   c                      e Zd ZdZddZy)FakeLoggerBundlezBJust enough of LoggerBundle for BrainTF._reject to find brain_log.c                V    t               | _        dd l}|j                  d      | _        y )Nr   ztest.brain_tf.fake)rO   	brain_loglogging	getLoggersystem)r9   _loggings     r/   r:   zFakeLoggerBundle.__init__b   s"    (*"(()=>r;   NrV   rI   rJ   rK   rL   r:   rM   r;   r/   rX   rX   `   s
    L?r;   rX   c                B    t        t        j                  |       d      S )z3Wrap a dict as a successful AIResponse (JSON text).   )r5   attempts)r
   jsondumps)payloads    r/   make_ai_responserf   i   s    4::g.;;r;   c                d
   t        d>i d| d   dt        | j                  dd            dt        | j                  d| j                  dd                  dt        | j                  dd      xs d      dt	        | j                  dd            d	t        | j                  d	d
            dt        | j                  dd            dt        | j                  d| j                  dd                  dt        | j                  dd            dt        | j                  dd            dt        | j                  dd            dt        | j                  dd            d| j                  dd      dt	        | j                  dd            d| j                  dd      dt	        | j                  dd            dt	        | j                  dd            dt        | j                  dd            d| j                  dd      d| j                  dd      dt        | j                  dg             d t        | j                  d d            d!| j                  d!d"      d#t	        | j                  d#d            d$t        | j                  d$d            d%t        | j                  d%d            d&t	        | j                  d&d            d't	        | j                  d'd            d(t	        | j                  d(d            d)t	        | j                  d)d            d*t	        | j                  d*d            d+| j                  d+      d,t	        | j                  d,d            d-t	        | j                  d-d            d.t	        | j                  d.d            d/t	        | j                  d/d            d0t	        | j                  d0d            d1t	        | j                  d1d            d2t	        | j                  d2d            d3t        | j                  d3| j                  dd                  d4t        | j                  d4d            d5| j                  d5d6      d7| j                  d7d"      d8t        | j                  d8d            d9| j                  d9d      d:t        | j                  d:i             d;t        | j                  d;d            d<t        | j                  d<d            d=t        | j                  d=d            S )?z
    Build a TechSnapshot from a legacy test-dict so existing test
    factories can stay dict-mutable. Defaults fill any missing field
    so per-test fixtures only specify what's relevant.
    r*   price        opencandle_timer   is_candle_closedTcandle_age_seconds      $@rsi      I@rsi_prevrsi_h1rsi_h4atr_m5_points	atr_ratior   
vol_regimeNORMAL	vol_spikeFmarket_structureRANGINGh1_struct_bullh1_struct_beartrend_maturityregimeregime_reason regime_near_trendingdeviation_pct
divergenceNONEmacd_deceleratingmacd_hist_lastcandle_strengthhammershooting_starbull_engulfingbear_engulfingdoji	doji_typepiercing
dark_cloudmorning_starevening_starvolume_weakbuy_absorptionsell_absorptionvwapvwap_deviation_pctr"   NEUTROr#   r   r    
swing_dataconsecutive_sl_count	tick_size
tick_valuerM   )r	   floatgetrH   boollistdict)ds    r/   _to_snapr   n   s(     2{2AEE'3'(2 155w!4562 mQ/415	2
 aee$6=>2 !';T!BC2 !%%t$%2 quuZud);<=2 QUU8T*+2 QUU8T*+2 AEE/3782 k3/02 55x02 quu[%012 19=2  AEE"2E:;!2" AEE"2E:;#2$ 155!1156%2& uuXy)'2( eeOR0)2* "!%%(>"CD+2, AEE/378-2. 55v./20 quu%8%@A122 QUU#3S9:324 aee$5s;<526 AEE(E*+728 155%8992: AEE"2E:;;2< AEE"2E:;=2> !%%&'?2@ %%$A2B aeeJ./C2D lE23E2F !%%67G2H !%%67I2J }e45K2L AEE"2E:;M2N QUU#4e<=O2P 155w!456Q2R !';S!ABS2T UU68$U2V %% 3V<W2X quu%7=>Y2Z %%R([2\ lB/0]2^ !'=q!AB_2` k3/0a2b |S12c2 2r;   c                 T    t        t        j                  t        j                        S )N)modeaccount)r   r   PAPERr   
INELIGIBLErM   r;   r/   make_configr      s    gmm[5K5KLLr;   MESc                    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t         j                  j                  dt        j                  j                  dddddddd dd!d"d#id$S )%z5Tech dict with valid TF BUY entry conditions for MES.r*   rh        @rj   g     @ro        F@rq   g     E@rr         J@rs        K@ru   皙?rt          @r   r   r   r   gQry   r~   rv   rw   r}      rk   g   ABULLISHBUYtrendswing_foundF)r"   r#   r   r    r   )r   BULLISH_EXPANSIONvaluer   TRENDING)r*   s    r/   make_tech_buy_validr      s   67 	7 	4	
 	4 	4 	4 	4 	3 	3 	6 	e 	O==CC 	6??00 	8  	1!" 	<#$ %"")51- r;   r   r   r   K   c                    t        d$i d|ddd| ddd|j                  d      rd	nd
d| dk(  rdndd| dk(  rdnddt        dddddt        j                        ddddd|ddd |d!t
        j                  j                  d"|d#|S )%Nr*   
brain_nameTF	direction	contractsra   entry_priceMr   \(\?sl_pricer        @g     @tp_priceg     @g     @	opened_ati           r   )tzinforsi_m5_at_entryr   rsi_h1_at_entryr   rsi_h4_at_entryatr_ratio_at_entryr   market_structure_at_entryregime_at_entryh1_compat_at_entryconfidence_at_entryrM   )r   
startswithr   r   utcr   r   r   )r   r*   	structurers   	h1_compat
confidences         r/   
make_entryr      s    
    	
 %//4F& %-6 %-6 4BAhllC      #, -- %  '! r;   c                     t        d|         y )Nz  ok  )print)labels    r/   _okr      s    	F5'
r;   c                   K   t               } t               }t        | |      }t               }d|d<   t	        |dt        |             d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}}|j                  }t        |      }	d}
|	|
k(  }|s t        j                  d|fd|	|
f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      t        j                  |
      dz  }t        j                   d      dz   d|iz  }t        t        j                  |            dx}x}	x}}
t#        d       y7 w)z1RSI outside [42,58] -> reject without calling AI.     @P@ro   r   Nisz%(py0)s is %(py3)sr.   py0py3assert %(py5)spy5r   ==zK%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.calls
})
} == %(py8)slenair   py1r   r   py8z*AI should NOT be called when pre-val fails
>assert %(py10)spy10z+pre-val: RSI outside TF zone -> None, no AI)r   r2   r   r   r0   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr8   r   _format_assertmsgr   cfgr   r)   techr.   @py_assert2@py_assert1@py_format4@py_format6@py_assert4@py_assert7@py_assert6@py_format9@py_format11s                 r/   test_pre_val_rsi_outside_zoner     sX    
-C	BCE DDKuhtn55F6T>6T66TxxK3x=KAK=AKKK=AKKKKKK3KKK3KKKKKKrKKKrKKKxKKK=KKKAKKKKKKKKKKK56 6s   A	II
G?Ic                 r  K   t               } t               }t        | |      }t               }d|d<   t	        |dt        |             d {   }d }||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}}|j                  }t        |      }	d
}
|	|
k(  }|s
t        j                  d|fd|	|
f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}x}	x}}
t!        d       y 7 w)N      ?ru   r   r   r   r.   r   r   r   r   r   r   r   r   r   assert %(py10)sr   z'pre-val: ATR ratio < 0.8 -> None, no AIr   r2   r   r   r0   r   r   r   r   r   r   r   r   r   r8   r   r   r   s                 r/   test_pre_val_atr_below_floorr     sM    
-C	BCE DDuhtn55F6T>6T66Txx3x=A=A=A33rrx=A12 6s   A	H7H4G)H7c                   K   t               } t               }t        | |      }t               }d|d<   d|d<   d|d<   t	        |dt        |             d {   }d }||u }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}|j                  }t        |      }	d}
|	|
k(  }|s
t        j                  d|fd|	|
f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}x}	x}}
t!        d       y 7 w)Ng       @r   r   rh   r   rj   r   r   r   r.   r   r   r   r   r   r   r   r   r   r	  r   z7pre-val: capitulation candle against BUY -> None, no AIr
  r   s                 r/    test_pre_val_capitulation_candler    s`    
-C	BCE D!D	DMDLuhtn55F6T>6T66Txx3x=A=A=A33rrx=AAB 6s   AIH>G)Ic                 <  K   t               } t               }t               }t        | ||      }t	               }d|d<   d|d<   t        |dt        |             d{   }d}||u }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}}|j                  }t!        |      }
d}|
|k(  }|s t        j                  d|fd|
|f      dt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      t        j                  |      dz  }t        j"                  d      dz   d|iz  }t        t        j                  |            dx}x}
x}}|j$                  j&                  D cg c]  }|d   dk(  s| }}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d   }d}||u }|slt        j                  d|fd ||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d!   }d"}| }||k(  }|slt        j                  d|fd#||f      t        j                  |      t        j                  |      dz  }	d$d%|	iz  }t        t        j                  |            dx}x}x}}t)        d&       y7 c c}w w)'z=BUY + macd_decel=False + hist<0 -> MACD_ACCELERATING_AGAINST.loggerFr   g(\r   r   Nr   r   r.   r   r   r   r   r   r   r   r   r   z'AI must NOT be called when gate rejectsr   r   rS   entry_rejectedruleMACD_ACCELERATING_AGAINSTz%(py1)s == %(py4)sr   py4assert %(py6)spy6
macd_decelz%(py1)s is %(py4)s	macd_histg(\@)z%(py1)s == -%(py4)sassert %(py7)spy7zHpre-val TF: BUY + MACD bearish accelerating -> MACD_ACCELERATING_AGAINST)r   r2   rX   r   r   r0   r   r   r   r   r   r   r   r   r   r8   r   r   rZ   rQ   r   )r   r   logr)   r   r.   r   r   r   r   r  r  r  r  r  erQ   @py_assert0@py_assert3@py_format5@py_format7@py_assert5@py_format8s                          r/   -test_pre_val_macd_accelerating_against_buy_tfr&    s    
-C	B

CCC(E D %D	"D	x~66F6T>6T66TxxH3x=HAH=AHHH=AHHHHHH3HHH3HHHHHHrHHHrHHHxHHH=HHHAHHHHHHHHHHH--PA7?O1OaPFP!9V; ;; ;;;;; ;;;;;;; ;;;;;;;;!9\"+e+"e++++"e+++"+++e+++++++!9[!*d*dU*!U****!U***!***d*******RS 7 Qs,   APPH
P'P5P9FPPc                 d  K   t               } t               }t               }t        | ||      }t	               }d|d<   d|d<   t
        j                  j                  |d<   d|d<   d	|d
<   d|d<   d|d<   t        |dt        |             d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }	t!        t        j"                  |	            dx}}|j$                  }t'        |      }
d}|
|k(  }|s
t        j                  d|fd|
|f      dt        j                         v st        j                  t&              rt        j                  t&              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}
x}}|j(                  j*                  D cg c]  }|d   d k(  s| }}|d   d!   }d"}||k(  }|slt        j                  d|fd#||f      t        j                  |      t        j                  |      d$z  }d%d&|iz  }t!        t        j"                  |            dx}x}}|d   d'   }d}||k(  }|slt        j                  d|fd#||f      t        j                  |      t        j                  |      d$z  }d%d&|iz  }t!        t        j"                  |            dx}x}}t-        d(       y7 c c}w w))z>SELL + macd_decel=False + hist>0 -> MACD_ACCELERATING_AGAINST.r  BEARISHr"   SELLr#   ry   r   rh   g     @rj   Fr   g?r   r   Nr   r   r.   r   r   r   r   r   r   r   r   r   r	  r   rS   r  r  r  r  r  r  r  r  zIpre-val TF: SELL + MACD bullish accelerating -> MACD_ACCELERATING_AGAINST)r   r2   rX   r   r   r   BEARISH_EXPANSIONr   r0   r   r   r   r   r   r   r   r   r   r8   r   rZ   rQ   r   )r   r   r  r)   r   r.   r   r   r   r   r  r  r  r  r  r  rQ   r   r!  r"  r#  s                        r/   .test_pre_val_macd_accelerating_against_sell_tfr+  ,  s    
-C	B

CCC(E DDL &D	.@@FFD	DMDL %D	!D	x~66F6T>6T66Txx3x=A=A=A33rrx=A--PA7?O1OaPFP!9V; ;; ;;;;; ;;;;;;; ;;;;;;;;!9[!)T)!T))))!T)))!)))T)))))))ST 7 Qs,   BN0N(G4N0N+N+DN0+N0c                 t  K   t               } t               }t               }t        | ||      }t	               }d|d<   d|d<   t        |dt        |             d{    |j                  j                  D cg c]   }|d   d	k(  r|j                  d
      dk(  r|" }}| }|s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t!        t        j"                  |            d}t%        d       y7 c c}w w)zGBUY + macd_decel=False + hist>0 -> gate passes (MACD favors direction).r  Fr   333333?r   r   NrS   r  r  r  z-gate should pass when MACD favors direction: 
>assert not %(py0)sr   rejectedz:pre-val TF: BUY + MACD bullish accelerating -> gate passesr   r2   rX   r   r   r0   r   rZ   rQ   r   r   r   r   r   r   r   r   r   r   	r   r   r  r)   r   r  r/  r   @py_format2s	            r/   1test_pre_val_macd_accelerating_in_favor_passes_tfr3  E  s    
-C	B

CCC(E D %D	!D	
uhtn
---==''W:))EE&M88 	
H 
 <S<SSH
SSSSSSSxSSSxSSSSSSDE .s%   AD8D1D89%D3BD83D8c                 n  K   t               } t               }t               }t        | ||      }t	               }d|d<   d|d<   t        |dt        |             d{    |j                  j                  D cg c]   }|d   d	k(  r|j                  d
      dk(  r|" }}| }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t!        t        j"                  |            d}t%        d       y7 c c}w w)z=BUY + macd_decel=True -> gate passes regardless of hist sign.r  Tr   g333333r   r   NrS   r  r  r  z/decelerating momentum must not trigger the gater.  r   r/  z5pre-val TF: macd_decel=True -> gate passes (any sign)r0  r1  s	            r/   (test_pre_val_macd_decelerating_passes_tfr5  Y  s     
-C	B

CCC(E D $D	"D	
uhtn
---==''W:))EE&M88 	
H 
 <J<JJJJJJJJJxJJJxJJJJJJ?@ .s%   AD5D.D59%D0BD50D5c                 *  K   t               } t        t        dddddddddd	d	d
            }t        | |      }t	        |dt        t                            d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d       y7 w)z?AI approves with confidence 65% -> watchdog rejects (floor 70).BUONO
FAVOREVOLETA   r   r   (\?r  okstep_1_qualita_scontostep_2_timing_pullbackstep_3_contesto_macroapprovedr   r   risk_multipliersl_atr_multiplierrr_multiplierkey_riskreasonr7   r   Nr   r   r.   r   r   r   z,post-val: confidence 65% < 70% floor -> None)r   r2   rf   r   r0   r   r   r   r   r   r   r   r   r   r   r   )r   r   r)   r.   r   r   r   r   s           r/   $test_post_val_confidence_below_floorrG  q  s     
-C	-!(")!-!/  
B CEuh/B/D&EFFF6T>6T66T67 Gs   ADDB6Dc                 8  K   t               } t        t        dddddddddd	d
d            }t        | |      }t	               }d|d<   t        |dt        |             d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d       y7 w)z=confidence 95% but H4 RSI 35 against BUY -> watchdog rejects.OTTIMOr8  T_   r   333333?r:  gq=
ףp?zh4 weakzdeep discountr<  rF  g     A@rs   r   Nr   r   r.   r   r   r   z)post-val: C95% + H4 RSI 35 vs BUY -> None)r   r2   rf   r   r   r0   r   r   r   r   r   r   r   r   r   r   )	r   r   r)   r   r.   r   r   r   r   s	            r/   test_post_val_c95_h4_weakrL    s     
-C	-!)"*!-!!/  
B CE DDNuhtn55F6T>6T66T34 6s   A D"D#B6Dc                   K   t               } t        t        dddddddddd	d	d
            }t               }t	        | ||      }t        |dt        t                            d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                   j"                  D 	cg c]  }	|	d   dk(  s|	 }
}	t%        |
      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|
d   d    }d!}||k(  }|slt        j                  d|fd"||f      t        j                  |      t        j                  |      d#z  }d$d%|iz  }t        t        j                  |            dx}x}}t'        d&       y7 uc c}	w w)'u  
    TP variante γ: AI emits rr_multiplier outside advisory prompt-range
    [0.17, 0.67] -> POST_VAL_RR_RANGE rejection (calibration signal).
    Hard clamp [0.10, 0.80] in tp_resolver is defense-in-depth and not
    triggered for this rejection — the brain rejects first.
    r7  r8  TN   r   r   r:  g      ?r;  r<  rF  r  r   Nr   r   r.   r   r   r   rS   r  ra   r   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   rQ   r   r   r   r  assert %(py8)sr   r   r  POST_VAL_RR_RANGEr  r  r  r  zFpost-val: rr_multiplier 0.75 outside [0.17, 0.67] -> POST_VAL_RR_RANGEr   r2   rf   rX   r   r0   r   r   r   r   r   r   r   r   r   r   rZ   rQ   r   r   r   r   r  r)   r.   r   r   r   r   r  rQ   r$  r  r#  r  r   r!  r"  s                     r/   test_post_val_rr_out_of_rangerU    s     -C	-!(")!-!/  
B FCF+Ex0C0E'FGGF6T>6T66T))00SAAgJBR4RaSFSv;!;!;!33vv;!!9V3 33 33333 3333333 33333333PQ HS,   A%K$'K(CK$)K7K;F"K$K$c                   K   t               } t        t        ddddddddddd	
      
      }t               }t	        | ||      }t        |dt        t                            d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                   j"                  D 	cg c]  }	|	d   dk(  s|	 }
}	t%        |
      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|
d   d   }d }||k(  }|slt        j                  d|fd!||f      t        j                  |      t        j                  |      d"z  }d#d$|iz  }t        t        j                  |            dx}x}}t'        d%       y7 uc c}	w w)&z9rr_multiplier <= 0 (missing/zero) -> POST_VAL_RR_MISSING.r7  r8  TrN  r   r   r:  r;  )
r=  r>  r?  r@  r   r   rA  rB  rD  rE  rF  r  r   Nr   r   r.   r   r   r   rS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  POST_VAL_RR_MISSINGr  r  r  r  z6post-val: rr_multiplier missing -> POST_VAL_RR_MISSINGrS  rT  s                     r/   test_post_val_rr_missingrY    s    
-C	-!(")!-!/  
B FCF+Ex0C0E'FGGF6T>6T66T))00SAAgJBR4RaSFSv;!;!;!33vv;!!9V5 55 55555 5555555 55555555@A HSs,   A$K#&K'CK#(K6K:F"K#K#c                   K   t               } t        t        dddddddddd	d	d
            }t               }t	        | ||      }t        |dt        t                            d{   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                   j"                  D 	cg c]  }	|	d   dk(  s|	 }
}	t%        |
      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|
d   d    }d!}||k(  }|slt        j                  d|fd"||f      t        j                  |      t        j                  |      d#z  }d$d%|iz  }t        t        j                  |            dx}x}}t'        d&       y7 uc c}	w w)'zy
    BUG 9 fix: AI returns sl_atr_multiplier outside profile.sl_range.
    Post-fix: rejected via POST_VAL_SL_RANGE.
    r7  r8  TrN  r   r   g?r  r;  r<  rF  r  r   Nr   r   r.   r   r   r   rS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  POST_VAL_SL_RANGEr  r  r  r  zFpost-val: sl_atr 0.20 < profile sl_range min 0.36 -> POST_VAL_SL_RANGErS  rT  s                     r/   %test_post_val_sl_out_of_profile_ranger\    s    
 -C	-!(")!-!/  
B FCF+Ex0C0E'FGGF6T>6T66T))00SAAgJBR4RaSFSv;!;!;!33vv;!!9V3 33 33333 3333333 33333333PQ HSrV  c                 
  K   t               } t        t        dddddddddd	d
d            }t        | |      }t	               }d|d<   t        |dt        |             d{   }t        |t              }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|j                   }d}||k(  }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j$                  }d}||k(  }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j&                  }d}||k(  }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j(                  }|j&                  }||k  }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d z  }d!d"|iz  }t        t        j                  |            dx}x}}|j*                  }d#}||k(  }|st        j"                  d|fd$||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j,                  }d}||k(  }|st        j"                  d|fd%||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j.                  d&   }d'}||k(  }|slt        j"                  d|fd(||f      t        j                  |      t        j                  |      d)z  }d*d+|iz  }t        t        j                  |            dx}x}}|j.                  d,   }d}||k(  }|slt        j"                  d|fd(||f      t        j                  |      t        j                  |      d)z  }d*d+|iz  }t        t        j                  |            dx}x}}d-}|j.                  d.   }||k  }d/}||k  }|r|st        j"                  d0||fd1|||f      t        j                  |      t        j                  |      t        j                  |      d2z  }
t        j0                  d3|j.                  d.    d4      d5z   d6|
iz  }t        t        j                  |            dx}x}x}x}}|j.                  d7   }d8}||k(  }|slt        j"                  d|fd(||f      t        j                  |      t        j                  |      d)z  }d*d+|iz  }t        t        j                  |            dx}x}}t3        d9       y7 w):u   
    Valid setup -> EntryDecision with computed SL prices.
    TP variante γ: brain emits tp_price=0.0 sentinel + rr_multiplier;
    orchestrator finalizes tp_price post-sizing via tp_resolver.
    r7  r8  TrN  r   r   r:  r  ztrend stalezdeep discount confluencer<  rF        >@rt   r   Nz5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer.   r   )r   r   py2r  r   )z1%(py2)s
{%(py2)s = %(py0)s.direction
} == %(py5)s)r   r`  r   r  r  )z2%(py2)s
{%(py2)s = %(py0)s.confidence
} == %(py5)sr   )z3%(py2)s
{%(py2)s = %(py0)s.entry_price
} == %(py5)s)<)zP%(py2)s
{%(py2)s = %(py0)s.sl_price
} < %(py6)s
{%(py6)s = %(py4)s.entry_price
})r   r`  r  r  rQ  r   ri   )z0%(py2)s
{%(py2)s = %(py0)s.tp_price
} == %(py5)s)z5%(py2)s
{%(py2)s = %(py0)s.rr_multiplier
} == %(py5)sr)   r   r  r  r  r  rr_multiplier_ai   sl_ticks_used(   )<=rf  )z%(py1)s <= %(py5)sz%(py5)s <= %(py7)s)r   r   r  zMES sl_ticks z out of [8,40]z
>assert %(py9)spy9profile_originUS500zMhappy: EntryDecision with SL prices + rr_multiplier (TP resolved post-sizing))r   r2   rf   r   r   r0   r   r_  r   r   r   r   r   r   r   r   r   r   r   r   r   r   rC  metadatar   r   )r   r   r)   r   r.   r!  r"  r   r  r   r%  r$  r#  r  r   r   r  @py_format10s                     r/   test_entry_happy_pathrl    s     -C	-!(")!-!!,/  
B CE D Duhtn55Ffm,,,,,,,,:,,,:,,,,,,f,,,f,,,,,,m,,,m,,,,,,,,,,$u$u$$$$u$$$$$$6$$$6$$$$$$u$$$$$$$""""""""""""6"""6"""""""""""""((((((((((((6(((6(((((((((((((??/V///?/////?///////6///6///?//////V///V///////////??!c!?c!!!!?c!!!!!!6!!!6!!!?!!!c!!!!!!!'4'4''''4''''''6'''6''''''4'''''''??7#+t+#t++++#t+++#+++t+++++++??-.6$6.$6666.$666.666$6666666 I0 I106 IB I0B6 I I7H7HI10B I I?Hy  I I?Hy 1 I I?Hy 57 I I7H7H-89HI I I5H5HI I I??+,77,7777,777,7777777777WX 6s   A d"d #bdc                      e Zd ZdZddZy)_SLTechz9Minimal tech stub for _compute_sl_only direct unit tests.c                     || _         || _        y rD   rh   rt   )r9   rh   rt   s      r/   r:   z_SLTech.__init__%  s    
*r;   N)rh   r   rt   r   rE   rF   r_   rM   r;   r/   rn  rn  #  s
    C+r;   rn  c                    t        j                  ddt        dd      d      } | d   }d	}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}d}||z
  }||k(  }|st        j                  d
|fd||f      t        j
                  |      t        j
                  |      t        j
                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}x}x}}t        d       y)uH   MYM BUY: AI's sl_atr produces sl_ticks_pre=5 < MIN_SL=10 → floor a 10.MYMr        |@r^  rp  {Gz?r*   r   r   sl_atrsl_ticks_pre_clamp   r   r  r  r  r  Nsl_ticks_post_clamp
   
sl_flooredTr   r  sl_min_ticksr   rn   )z%(py1)s == (%(py4)s - %(py6)s))r   r  r  zassert %(py9)srg  u9   sl_floored: MYM AI proposes 5 ticks → floored to MIN 10	r   _compute_sl_onlyrn  r   r   r   r   r   r   )
pcr   r!  r   r"  r#  r$  r  r%  rk  s
             r/    test_sl_floored_mym_min_sl_ticksr  *  s    
	!	!7$7
B
 "#(q(#q((((#q(((#(((q(((((((#$**$****$***$**********l#t#t####t######t#######n###################j>+W+t+Wt^+>^++++>^+++>+++W+++t+++++++CDr;   c                 `   t        j                  ddt        dd      d      } | d   }d	}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d	}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| d   }d}||k(  }|slt        j                  d
|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}t        d       y)u@   6E sl_ticks_pre=15 ≥ MIN_SL=10 → no floor, sl_floored=False.6Er   r   ga2U0*#?rp  g      @ru  rw     r   r  r  r  r  Nry  r{  Fr   r  r|  rz  u?   sl_floored: 6E sl=15 ≥ MIN 10 → unchanged, sl_floored=Falser}  )r  r   r!  r   r"  r#  s         r/   $test_sl_floored_false_when_above_minr  <  s{    
	!	!u69
B
 "#)r)#r))))#r)))#)))r)))))))#$**$****$***$**********l$u$u$$$$u$$$$$$u$$$$$$$n###################IJr;   c                   ddl m} t        |j                        }|j	                  dd       | j                  |d|       t        j                  ddt        dd      d	
      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}t        d       y)uK   Symbol non listato in MIN_SL_TICKS → sl_floored=False (no floor applied).r   Nrr  MIN_SL_TICKSr   rs  r^  rp  rt  ru  rw  rx  r   r  r  r  r  ry  r{  Fr   r  r|  uA   sl_floored: no MIN_SL_TICKS config → no floor, sl_floored=False)core.config_futuresconfig_futuresr   r  popsetattrr   r~  rn  r   r   r   r   r   r   )	monkeypatchcfg_futpatchedr  r   r!  r   r"  r#  s	            r/   3test_sl_floored_false_when_symbol_has_no_min_configr  L  s    *7''(GKKt9		!	!7$7
B "#(q(#q((((#q(((#(((q(((((((#$))$))))$)))$))))))))))l$u$u$$$$u$$$$$$u$$$$$$$n"""""""""""""""""""KLr;   c                 f  K   t               } t               }t               }t        | ||      }t	               }d|d<   t        |dt        |             d{    |j                  j                  D cg c]  }|d   dk(  s| }}t        |      }d}||k(  }	|	st        j                  d	|	fd
||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t!        t        j"                  |            dx}x}	}|d   }|d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}|d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}|d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}|d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}|d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}t%        d       y7 c c}w w)zCPre-val rejection emits structured event with rsi/rsi_low/rsi_high.r  r   ro   r   NrS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  PULLBACK_ZONEr  r  r  r  rsi_m5rsi_lowg      E@rsi_high      M@r)   r   z,logging: PULLBACK_ZONE event with rsi fields)r   r2   rX   r   r   r0   r   rZ   rQ   r   r   r   r   r   r   r   r   r   r   )r   r   
log_bundler)   r   r  rQ   r   r$  r  r#  r  evr   r!  r"  s                   r/   $test_rejection_logging_pullback_zoner  a  s    
-C	B!#JCJ/E DDK
eXd^
,,,#--44WA'
FV8VaWFWv;!;!;!33vv;!	Bf:((:((((:(((:((((((((((h<4<4<4<4i= D =D    =D   =   D       j>!T!>T!!!!>T!!!>!!!T!!!!!!!g;$;$;$;$67 -Ws+   AP1P)P14P,P,N$P1,P1c                   K   t               } t               }t               }t        | ||      }t	               }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{    |j                  j                  D cg c]  }|d   dk(  s| }}|d   }|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d!   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d"   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d#   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d$   }d
}	||	u }
|
slt        j                  d%|
fd&||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d'   }d(}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d   }d
}	||	u }
|
slt        j                  d%|
fd&||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d)   }d*}	||	u }
|
slt        j                  d%|
fd&||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d+   }d*}	||	u }
|
slt        j                  d%|
fd&||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	|d,   }d
}	||	u }
|
slt        j                  d%|
fd&||	f      t        j                  |      t        j                  |	      dz  }dd |iz  }t        t        j                  |            dx}x}
}	t        d-       y7 =c c}w w).zV18 dashboard radar: entry_rejected carries rsi_m5/rsi_h4/h1_compat/
    macd_*/pattern/atr_ratio/bias/h1_struct_*/volume_weak/divergence/bouncing_rsi.r  r   ro   r  rs   r-  r   gJ4q?r   Tr   r   rK  ru   r   r"   r{   r   g      N@rq   r   NrS   r  r   r  r  r   r  r  r  r  r  r   r  r  r   r  patternHAMMERr|   Fr   bouncing_rsiz<logging: entry_rejected carries full RADAR tech fields (V18))r   r2   rX   r   r   r0   r   rZ   rQ   r   r   r   r   r   r   )r   r   r  r)   r   r  rQ   r  r   r!  r   r"  r#  s                r/   %test_rejection_logs_radar_tech_fieldsr  u  s[     -C	B!#JCJ/E DDKDN#D	#D	 $D	DNDDL!D	"DD
uhtn
---#--44WA'
FV8VaWFW	Bf:((:((((:(((:((((((((((h<4<4<4<4h<4<4<4<4k?"d"?d""""?d"""?"""d"""""""k?$f$?f$$$$?f$$$?$$$f$$$$$$$l#t#t####t######t#######i=$H$=H$$$$=H$$$=$$$H$$$$$$$k?"d"?d""""?d"""?"""d"""""""f:"":"""":""":""""""""""'4'4''''4''''''4'''''''(5(5((((5((((((5(((((((m%%%%%%%%%%%%%%%%%%%l(y(y((((y((((((y(((((((n%%%%%%%%%%%%%%%%%%%FG# .Ws+   B_	_
_&_	4_	8\_	_c                   K   t               } t        t        dddddddddd	d	d
            }t               }t	        | ||      }t        |dt        t                            d{    |j                  j                  D cg c]  }|d   dk(  s| }}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }	dd|	iz  }
t#        t        j$                  |
            dx}x}}|d   }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|d    }d}||k(  }|slt        j                  d|fd||f      t        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|d!   }d}||k(  }|slt        j                  d|fd||f      t        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|d"   }d}||k(  }|slt        j                  d|fd||f      t        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}t'        d#       y7 Rc c}w w)$zIPost-val rejection includes ai_confidence + ai_sl_atr + ai_rr_multiplier.r7  r8  Tr9  r   r   r:  r  r;  r<  rF  r  r   NrS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  POST_VAL_CONFr  r  r  r  ai_confidence	ai_sl_atrai_rr_multiplierz2logging: POST_VAL_CONF event with ai_* diagnosticsr   r2   rf   rX   r   r0   r   r   rZ   rQ   r   r   r   r   r   r   r   r   r   r   )r   r   r  r)   r  rQ   r   r$  r  r#  r  r  r   r!  r"  s                  r/   test_rejection_logging_post_valr    s    
-C	-!(")!-!/  
B "#JCJ/E
eX&9&;<
===#--44WA'
FV8VaWFWv;!;!;!33vv;!	Bf:((:((((:(((:((((((((((o$"$"$$$$"$$$$$$"$$$$$$$k?"d"?d""""?d"""?"""d""""""" !)T)!T))))!T)))!)))T)))))))<= >Ws+   A%O'N9(ON<N<L$O<Oc                   K   t               } t        t        ddddddddd	d
ddddd            }t               }t	        | ||      }t        |dt        t                            d{    |j                  j                  D cg c]  }|d   dk(  s| }}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }	dd|	iz  }
t#        t        j$                  |
            dx}x}}|d   }|d   }d }||k(  }|slt        j                  d|fd!||f      t        j                   |      t        j                   |      d"z  }d#d$|iz  }	t#        t        j$                  |	            dx}x}}|d%   }d}||k(  }|slt        j                  d|fd!||f      t        j                   |      t        j                   |      d"z  }d#d$|iz  }	t#        t        j$                  |	            dx}x}}|d&   }|j&                  }d'} ||      }|std(t        j                   |      t        j                   |      t        j                   |      t        j                   |      d)z  }t#        t        j$                  |            dx}x}x}}t)        d*       y7 c c}w w)+zuAI returns approved=false + rejection_details -> entry_rejected
    event carries ai_rule_failed/ai_rejection_detail.DEBOLE	PREMATUROr   F<   r   r  r:  333333?z
weak setupzdiscount too shallowSTEP1_DEBOLEz'RSI 45 ai margini, sconto poco profondo)rule_faileddetail)r=  r>  r?  r@  r   r   rA  rB  rC  rD  rE  rejection_detailsrF  r  r   NrS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  AI_REJECTEDr  r  r  r  ai_rule_failedai_rejection_detailzRSI 45 ai marginizLassert %(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.startswith
}(%(py5)s)
})r   r   r   r  zGlogging: AI_REJECTED event carries ai_rule_failed + ai_rejection_detail)r   r2   rf   rX   r   r0   r   r   rZ   rQ   r   r   r   r   r   r   r   r   r   r   r   )r   r   r  r)   r  rQ   r   r$  r  r#  r  r  r   r!  r"  r  r%  s                    r/   %test_ai_rejection_with_details_loggedr    sc     -C	-!)"-!)! ()?
/  
B" "#JCJ/E
uh':'<=
>>>#--44WA'
FV8VaWFWv;!;!;!33vv;!	Bf:&&:&&&&:&&&:&&&&&&&&&&1>1>1111>111111>1111111#$D$//D0CD/0CDDDDD$DDD/DDD0CDDDDDDDDDDQR ?Ws+   A)M+M,MMMJ=MMc                   K   t               } t        t        ddddddddd	d
dd            }t               }t	        | ||      }t        |dt        t                            d{    |j                  j                  D cg c]  }|d   dk(  s| }}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }	dd|	iz  }
t#        t        j$                  |
            dx}x}}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                   |      t        j                   |      dz  }d d!|iz  }	t#        t        j$                  |	            dx}x}}t'        d"       y7 c c}w w)#z[AI returns approved=false WITHOUT rejection_details -> fallback
    UNSPECIFIED (no crash).r  r  r   Fr  r   r  r:  r  zn/anor<  rF  r  r   NrS   r  ra   r   rO  r   rQ   rP  rQ  r   r   r  UNSPECIFIEDr  r  r  r  zGlogging: AI rejection without rejection_details -> UNSPECIFIED fallbackr  )r   r   r  r)   r  rQ   r   r$  r  r#  r  r   r!  r"  s                 r/   &test_ai_rejection_missing_details_safer    s     -C	-!)"-!)!/  
B "#JCJ/E
uh':'<=
>>>#--44WA'
FV8VaWFWv;!;!;!33vv;!!9%&7-7&-7777&-777&777-7777777QR	 ?Ws+   A%H?'H7(H?H:H:F"H?:H?c                   K   t               } t        t        dddddddt        d   d   d	z   d
ddd            }t	        | |      }d}|t
        v}|st        j                  d|fd|t
        f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t
              rt        j                  t
              nddz  }dd|iz  }t        t        j                  |            d}t        |      }d|d<   d|d<   d|d<   |j                  }||v}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d d!|iz  }	t        t        j                  |	            dx}}t!        ||t#        |             d{   }
|j                  }||v }|st        j                  d"|fd#||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d d!|iz  }	t        t        j                  |	            dx}}t!        ||t#        |             d{   }
t%        d$| d%       y7 #7 w)&a  
    Symbol senza profile dedicato -> usa GENERIC_PROFILE + emette warning
    una sola volta. Dopo Fix A V16, tutti gli asset attivi hanno profile
    dedicato; usiamo un symbol fittizio (non in TF_ASSET_PROFILES) per
    esercitare il path GENERIC fallback.
    r7  r8  Tr   r   r   sl_ranger   g?r  r;  r<  rF  ZZZ_TEST_NO_PROFILEnot in)z%(py0)s not in %(py2)sfake_symbolr   )r   r`  zassert %(py4)sr  Ng?rh   g	^)?rj   gMbP?rt   )zC%(py0)s not in %(py4)s
{%(py4)s = %(py2)s._warned_generic_profile
}r)   )r   r`  r  r  r  in)z?%(py0)s in %(py4)s
{%(py4)s = %(py2)s._warned_generic_profile
}zgeneric profile: z# (no profile) tracked + warned once)r   r2   rf   r   r   r   r   r   r   r   r   r   r   r   r   _warned_generic_profiler0   r   r   )r   r   r)   r  r   @py_format3r"  r   r!  r#  _s              r/   test_generic_profile_warningr    sG     -C	-!(")!-,Z8;cA/  
B CE'K/////;///////;///;//////////////////{+D DMDL"D#;;;;;;;;;;;;;;;;;;;;;;;;;;;;e;;;e;;;;;;;;;;;E;77A777;77777;7777777;777;777777%777%77777777777E;77A
K=(KLM	 	8 	8s%   IM2
M-DM2M0M20M2c                0   t               }| |d<   t        |      }t        |      }t        |d      }t        d   }t        j                  dd|j                  |j                  |j                  |j                  |j                  |j                  ||||      S )z8Build a TF entry prompt with given consecutive_sl_count.r   r   r   )r*   r   r"   r~   ro   rq   ru   r   r   signalsscoreprofile)r   r   r   r   r   r   _build_entry_promptr"   r~   ro   rq   ru   r   )	consec_slr   r   r  r  r  s         r/   _render_tf_promptr  !  s    A )AA;D &GWe$E&G&&DIIdkkHHt}},,7%	 r;   c                    t        d      } d}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d
}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}t        d       y )N   r  z2 SL recentir  z%(py1)s in %(py3)srC   r   r   r   r       la struttura ti ha già stoppatozRSI in zona ottimale (42-46zSL consecutivi sessione: 2u   re-entry post-SL: SÌzFprompt: consec_sl=2 -> inline anti-revenge warning + RSI ottimale rule
r  r   r   r   r   r   r   r   r   r   rC   r   r   r   r   s        r/   "test_prompt_consecutive_sl_warningr  1  s   +F #>V####>V###>######V###V#######-7-7777-777-7777777777777777(2(F2222(F222(222222F222F2222222'1'61111'6111'111111611161111111","f,,,,"f,,,",,,,,,f,,,f,,,,,,,PQr;   c                    t        d      } d}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d
}|| v }|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}d}|| v}|st        j                  d|fd|| f      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       nddz  }dd	|iz  }t        t        j                  |            d x}}t        d       y )Nr   r  zSL consecutivi sessione: 0r  r  rC   r  r   r   zre-entry post-SL: NOr  r  )z%(py1)s not in %(py3)sz5prompt: consec_sl=0 -> no inline anti-revenge warningr  r  s        r/   test_prompt_no_sl_no_warningr  =  s+   +F (1'61111'6111'111111611161111111!+!V++++!V+++!++++++V+++V+++++++-;-V;;;;-V;;;-;;;;;;V;;;V;;;;;;;?@r;   c                    t        | xs
 t               |xs t        ddd      t        ||            S t	                           S )Nrn         4@ri   minutes_opennet_profit_usdlast_exit_eval_time)entryruntimetech_now)r   r   r   r   r   r  r  r   s      r/   make_ctxr  K  sV    
 #z| A<T$<?A$"2$N	  9L8MN	 r;   c                 B  K   t               } t               }t        | |      }t        t	        ddd            }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }|s
t        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      t        j                  |      dz  }	dd|	iz  }
t!        t        j"                  |
            dx}x}x}}d}|j$                  }||v }|st        j                  d|fd||f      t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}}|j&                  }t)        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t(              rt        j                  t(              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t!        t        j"                  |
            dx}x}x}}t+        d       y7 Mw)z6P&L<=0 + minutes >= threshold -> EXIT without AI call.g     r@g      ri   r  )r  Nr   zc%(py2)s
{%(py2)s = %(py0)s.action
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.EXIT
}.value
}r(   r   r   r`  r  r  r   r	  r   zTime Stop TFr  z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.reason
}r   r   r   r  r  r   r   r   r   r   z+exit: time stop hit (P&L<=0) -> EXIT, no AI)r   r2   r   r  r   manage_exitactionr   EXITr   r   r   r   r   r   r   r   r   rE  r8   r   r   )r   r   r)   ctxr(   r   r$  r  r!  r  r  r   r  r   r   r%  r  s                    r/    test_exit_time_stop_negative_pnlr  X  s    
-C	BCE
%146C &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444,X__,>_,,,,>_,,,>,,,,,,X,,,X,,,_,,,,,,,xx3x=A=A=A33rrx=A56	 ,s   ANNMNc                 b  K   t               } t               }t        | |      }t               }d|d<   t	        t        ddd      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd	||f      d
t        j                         v st        j                  |      rt        j                   |      nd
t        j                   |      dt        j                         v st        j                  t              rt        j                   t              ndt        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}	x}}d}|j&                  }||v }|st        j                  d|fd||f      t        j                   |      d
t        j                         v st        j                  |      rt        j                   |      nd
t        j                   |      dz  }dd|iz  }t#        t        j$                  |            dx}x}}|j(                  }t+        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t*              rt        j                   t*              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}x}}t-        d       y7 Mw)zCtech.candle_time <= runtime.last_exit_eval_time -> HOLD without AI.g     @@rk   rn   r  r  r  r   Nr   zc%(py2)s
{%(py2)s = %(py0)s.action
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.HOLD
}.value
}r(   r   r  r	  r   zstessa candelar  r  r  r  r  r   r   r   r   r   z&exit: same-candle dedup -> HOLD, no AI)r   r2   r   r   r  r   r  r  r   HOLDr   r   r   r   r   r   r   r   r   rE  r8   r   r   )r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r  r   r   r%  r  s                     r/   test_exit_same_candle_dedupr  h  s.    
-C	BCE D D
$t179C
 &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444.x..............x...x..........xx3x=A=A=A33rrx=A01	 ,s   AN/N, MN/c            	       K   t               } t        t        ddd            }t        | |      }t	        t
        j                  j                        }t               }t
        j                  j                  |d<   d|d<   t        |t        d	d
d      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }	||	k(  }
|
s
t!        j"                  d|
fd||	f      dt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      dt%        j&                         v st!        j(                  t              rt!        j*                  t              ndt!        j*                  |      t!        j*                  |	      dz  }dd|iz  }t-        t!        j.                  |            dx}x}
x}}	|j0                  }|j2                  }
d} |
|      }	d}|	|u }|st!        j"                  d|fd|	|f      dt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      t!        j*                  |
      t!        j*                  |      t!        j*                  |	      t!        j*                  |      dz  }dd|iz  }t-        t!        j.                  |            dx}x}
x}x}	x}}|j0                  }|j2                  }
d} |
|      }	d}|	|k(  }|st!        j"                  d|fd|	|f      dt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      t!        j*                  |
      t!        j*                  |      t!        j*                  |	      t!        j*                  |      dz  }dd|iz  }t-        t!        j.                  |            dx}x}
x}x}	x}}t5        d       y7 w)z?LONG with new BEARISH struct (after grace) -> flag in metadata.Tzstruct flipexit_nowrE  rF  )r   ry   g     @@rk         .@rn   g     p@r  r  Nr   r  r(   r   r  r	  r   struct_flippedr   )zh%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.metadata
}.get
}(%(py6)s)
} is %(py11)s)r   r`  r  r  r   py11zassert %(py13)spy13evaluated_candle_time)zh%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.metadata
}.get
}(%(py6)s)
} == %(py11)sz:exit: struct flip detected -> metadata flag set, AI called)r   r2   rf   r   r   r   r   r   r   r*  r  r   r  r  r   r  r   r   r   r   r   r   r   r   rj  r   r   )r   r   r)   r  r   r  r(   r   r$  r  r!  r  r  @py_assert10@py_assert9@py_format12@py_format14s                    r/   test_exit_struct_flip_detectedr  {  s    
-C	-4=.YZ	[BCE!B!B!H!HIE D.@@FFD	 D
$t179	C &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444:  :!1: !12:d:2d::::2d::::::8:::8:::::: :::!1:::2:::d::::::::C  C!8C !89CVC9VCCCC9VCCCCCC8CCC8CCCCCC CCC!8CCC9CCCVCCCCCCCCDE	 ,s   B-Q/Q0NQc                 ,  K   t               } t        t        ddd            }t        | |      }t	               }d|d<   t        t        ddd	
      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}	x}}d}|j(                  }||v }|st        j                  d|fd||f      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dz  }dd|iz  }t%        t        j&                  |            dx}x}}|j*                  d   }d}	||	k(  }|slt        j                  d|fd||	f      t        j"                  |      t        j"                  |	      dz  }dd|iz  }t%        t        j&                  |            dx}x}}	t-        d       y7 w)z"AI returns exit_now=false -> HOLD.Fzno inversionr  rF  g     p@rk   r  r  ri   r  r  Nr   r  r(   r   r  r	  r   r  r  r  r  r  r  r  r  r  r  z4exit: AI says HOLD -> HOLD with metadata candle_time)r   r2   rf   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rE  rj  r   )r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r  r   r   r%  r"  r#  s                      r/   test_exit_ai_says_holdr    s    
-C	-5N.[\	]BCE D D
$t146C
 &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444,X__,>_,,,,>_,,,>,,,,,,X,,,X,,,_,,,,,,,45??5????5???5??????????>?	 ,s   A+L-L.J$Lc                   K   t               } t        t        ddd            }t        | |      }t	               }d|d<   t        t        ddd	
      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}	x}}d}|j(                  }||v }|st        j                  d|fd||f      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dz  }dd|iz  }t%        t        j&                  |            dx}x}}t+        d       y7 w)z!AI returns exit_now=true -> EXIT.Tzengulfing+H4 crollor  rF  g     @@rk   r^  r   ri   r  r  Nr   r  r(   r   r  r	  r   	engulfingr  r  r  r  r  zexit: AI says EXIT -> EXIT)r   r2   rf   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rE  r   r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r  r   r   r%  s                    r/   test_exit_ai_says_exitr    s    
-C	-'/  
B CE D D
$s146C
 &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444)(//);/))));/)));))))))()))()))/)))))))$% ,   A+J
-J.HJ
c                   K   t               } t        t        ddd            }t        | |      }t	               }d|d<   t        t        dd	d
      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}	x}}d}|j(                  }||v }|st        j                  d|fd||f      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dz  }dd|iz  }t%        t        j&                  |            dx}x}}t+        d       y7 w)z4AI returns None text -> HOLD default (conservative).Noverloadr   )r5   r6   rb   rF  g     @rk   r  g      @ri   r  r  r   r  r(   r   r  r	  r   zAI errorr  r  r  r  r  zexit: AI error -> HOLD default)r   r2   r
   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rE  r   r  s                    r/   test_exit_ai_error_holdsr    s    
-C	ZTjSTU	VBCE D D
$s146C
 &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444((:((((:(((:(((((((((((((((((((() ,r   c            
     
  K   t               } t               }t        | |      }t               }t	               }d|d<   t        |t        ddddd      |	      }|j                  |       d
{   }|j                  }t        j                  }|j                  }	||	k(  }
|
s
t        j                  d|
fd||	f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |	      dz  }dd|iz  }t%        t        j&                  |            d
x}x}
x}}	|j(                  d   }d}
||
k(  }|slt        j                  d|fd||
f      t        j"                  |      t        j"                  |
      dz  }dd|iz  }t%        t        j&                  |            d
x}x}}
|j(                  d   }d}
||
u }|slt        j                  d|fd||
f      t        j"                  |      t        j"                  |
      dz  }dd|iz  }t%        t        j&                  |            d
x}x}}
|j(                  d   }|j*                  }||k(  }|st        j                  d|fd||f      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dz  }d d!|iz  }t%        t        j&                  |            d
x}x}}|j(                  d"   }d}
||
k(  }|slt        j                  d|fd||
f      t        j"                  |      t        j"                  |
      dz  }dd|iz  }t%        t        j&                  |            d
x}x}}
|j,                  }t/        |      }d#}	||	k(  }|s
t        j                  d|fd$||	f      d%t        j                         v st        j                   t.              rt        j"                  t.              nd%d&t        j                         v st        j                   |      rt        j"                  |      nd&t        j"                  |      t        j"                  |      t        j"                  |	      d'z  }dd|iz  }t%        t        j&                  |            d
x}x}x}}	t1        d(       y
7 w))zEprogress >= 50% + !partial_done -> PARTIAL_50 + set_be_after_partial.      ?r   rn   r  r   Fri   r  r  progress_pctpartial_doner  r  Nr   zi%(py2)s
{%(py2)s = %(py0)s.action
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.PARTIAL_50
}.value
}r(   r   r  r	  r   triggerauto_partial_50r  r  r  r  set_be_after_partialTr   r  be_price)z3%(py1)s == %(py5)s
{%(py5)s = %(py3)s.entry_price
}r  r  r  r  r  r   r   r   r   r   z6exit: progress 55% -> PARTIAL_50 + set_be (no AI call))r   r2   r   r   r   r  r   r  r  r   
PARTIAL_50r   r   r   r   r   r   r   r   r   rj  r   r8   r   r   )r   r   r)   r  r   r  r(   r   r$  r  r!  r  r  r   r   r"  r#  r  r   r%  r  s                        r/   +test_exit_auto_partial_50_fires_with_set_ber    s]    
-C	BCELE DD
$t*.*/146 C &&s++H??:k44:4:::?:::::?:::::::8:::8:::?::::::k:::k:::4:::::::::::Y'<+<<'+<<<<<'+<<<<'<<<+<<<<<<<<34<<4<<<<4<<<4<<<<<<<<<<Z(=E,=,==(,=====(,====(======E===E===,========^,44,4444,444,4444444444xx3x=A=A=A33rrx=A@A ,s   A*U',U$-S8U'c            	       K   t               } t               }t        | |      }t               }d|d<   t	        t        ddddd      |	      }|j                  |       d
{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      dt        j                         v st        j                  t              rt        j                   t              ndt        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            d
x}x}	x}}|j&                  d   }d}	||	k(  }|slt        j                  d|fd||	f      t        j                   |      t        j                   |	      dz  }dd|iz  }t#        t        j$                  |            d
x}x}}	t)        d       y
7 ݭw)z9progress == 50.0 (boundary) -> trigger fires (>=, not >).r  r   r   rn   rp   Fri   r  r  Nr   r	  r(   r   r  r	  r   r
  r  r  r  r  r  z,exit: progress 50.0 (boundary) -> PARTIAL_50)r   r2   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rj  r   )r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r   r"  r#  s                   r/   )test_exit_auto_partial_50_threshold_exactr    s    
-C	BCE DD
#d*.*/146 C &&s++H??:k44:4:::?:::::?:::::::8:::8:::?::::::k:::k:::4:::::::::::Y'<+<<'+<<<<<'+<<<<'<<<+<<<<<<<<67 ,s   AI!H>"GIc            	     *  K   t               } t        t        ddd            }t        | |      }t	               }d|d<   d|d<   t        t        d	d
ddd      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}	x}}|j(                  }t+        |      }d}||k(  }|s t        j                  d|fd||f      dt        j                         v st        j                   t*              rt        j"                  t*              nddt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      t        j"                  |      t        j"                  |      dz  }
t        j,                  d      dz   d|
iz  }t%        t        j&                  |            dx}x}x}}t/        d       y7 w) zMOne-shot guard: partial_done=True -> trigger NOT fired (falls through to AI).Fzhold partial doner  rF  r  r   g     @rk   r  g      9@g     R@Tri   r  r  Nr   r  r(   r   r  r	  r   ra   r   r   r   r   z3AI should be consulted because partial path skippedr   z8exit: partial_done=True -> no re-partial (falls through))r   r2   rf   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   r8   r   r   r   r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r  r  s                  r/   1test_exit_auto_partial_50_skipped_if_partial_doner    s    
-C	-&9: 
B CE DD D
$t*.*.146 C &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444xxT3x=TAT=ATTT=ATTTTTT3TTT3TTTTTTrTTTrTTTxTTT=TTTATTTTTTTTTTTBC ,s   A2L4L5JLc            	       K   t               } t        t        ddd            }t        | |      }t	               }d|d<   d|d<   t        t        d	d
ddd      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      dt        j                         v st        j                   t              rt        j"                  t              ndt        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}	x}}|j(                  }t+        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                   t*              rt        j"                  t*              nddt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      t        j"                  |      t        j"                  |      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}x}}t-        d       y7 w)zBprogress < 50% -> trigger NOT fired (falls through to AI / dedup).Fzlow progress holdr  rF  r  r   g     @rk   r   g      @g33333H@ri   r  r  Nr   r  r(   r   r  r	  r   ra   r   r   r   r   z5exit: progress 49.9% -> below threshold, AI consulted)r   r2   rf   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   r8   r   r   r  s                  r/   1test_exit_auto_partial_50_below_threshold_no_firer    s    
-C	-&9: 
B CE DD D
#c*.*/146 C &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444xx3x=A=A=A33rrx=A?@ ,s   A2K=4K:5JK=c            	       K   t               } t               }t        | |      }t               }d|d<   d|d<   t	        t        ddddd	      |
      }|j                  |       d{   }|j                  }t        j                  }|j                  }||k(  }	|	s
t        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      dt        j                         v st        j                  t              rt        j                   t              ndt        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}	x}}|j&                  d   }d}	||	k(  }|slt        j                  d|fd||	f      t        j                   |      t        j                   |	      dz  }dd|iz  }t#        t        j$                  |            dx}x}}	|j(                  }t+        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t*              rt        j                   t*              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}x}}t-        d       y7 w)zISame-candle dedup must NOT block the auto-partial (deterministic action).r  r   g     X@rk         (@g      2@g      O@Fr  r  Nr   r	  r(   r   r  r	  r   r
  r  r  r  r  r  r   r   r   r   r   z<exit: partial trigger fires even on already-evaluated candle)r   r2   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rj  r8   r   r   )r   r   r)   r   r  r(   r   r$  r  r!  r  r  r   r   r"  r#  r  r  s                     r/   ,test_exit_auto_partial_50_fires_before_dedupr  (  s,    
-C	BCE DD D
$t*.*/179 C &&s++H??:k44:4:::?:::::?:::::::8:::8:::?::::::k:::k:::4:::::::::::Y'<+<<'+<<<<<'+<<<<'<<<+<<<<<<<<xx3x=A=A=A33rrx=AFG	 ,s   A$M9&M6'LM9c            
     :  K   t               } t               }t        | |      }t               }t	        d*i d|j
                  d|j                  d|j                  d|j                  ddd|j                  d|j                  d	|j                  d
|j                  d|j                  d|j                  d|j                  d|j                   d|j"                  d|j$                  d|j&                  }t)               }d|d<   t+        |t-        ddddd      |      }|j/                  |       d{   }|j0                  }t2        j4                  }|j6                  }	||	k(  }
|
s
t9        j:                  d|
fd||	f      dt=        j>                         v st9        j@                  |      rt9        jB                  |      ndt9        jB                  |      dt=        j>                         v st9        j@                  t2              rt9        jB                  t2              ndt9        jB                  |      t9        jB                  |	      d z  }d!d"|iz  }tE        t9        jF                  |            dx}x}
x}}	|jH                  d#   }d$}
||
k(  }|slt9        j:                  d|fd%||
f      t9        jB                  |      t9        jB                  |
      d&z  }d'd(|iz  }tE        t9        jF                  |            dx}x}}
tK        d)       y7 ݭw)+zRbe_price aligned to instrument tick grid (defensive against off-grid entry_price).r*   r   r   r   r   g{G!@r   r   r   r   r   r   r   r   r   r   r   r  r   rn   r  g     I@Fri   r  r  Nr   r	  r(   r   r  r	  r   r  g    @@r  r  r  r  z(exit: be_price tick-aligned to 0.25 gridrM   )&r   r2   r   r   r   r*   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   r   rj  r   r   r   r)   r  r   r  r(   r   r$  r  r!  r  r  r   r   r"  r#  s                    r/   /test_exit_auto_partial_50_be_price_tick_alignedr  >  sz    
-C	BCELE ||(-(8(8//-2__  	 +0..	
 // -- -- -- !33 #("A"A -- !33 "55E  DD
$t*.*/146 C &&s++H??:k44:4:::?:::::?:::::::8:::8:::?::::::k:::k:::4:::::::::::Z(3G3(G3333(G333(333G333333323	 ,s   D9L;L<GLc                 "  K   t               } t        t        ddd            }t        | |      }t	        dt
        j                  j                        }t               }t
        j                  j                  |d<   d|d	<   t        |t        d
dd      |      }|j                  |       d{   }|j                  }t        j                  }|j                  }	||	k(  }
|
s
t!        j"                  d|
fd||	f      dt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      dt%        j&                         v st!        j(                  t              rt!        j*                  t              ndt!        j*                  |      t!        j*                  |	      dz  }dd|iz  }t-        t!        j.                  |            dx}x}
x}}	|j0                  d   }d}
||
u }|slt!        j"                  d|fd||
f      t!        j*                  |      t!        j*                  |
      dz  }dd|iz  }t-        t!        j.                  |            dx}x}}
t3        d       y7 ܭw)z5SHORT trade with new BULLISH struct -> flip detected.Tflipr  rF  r)  )r   r   ry   g     p@rk   r  r   ri   r  r  Nr   r  r(   r   r  r	  r   r  r   r  r  r  r  u2   exit: SHORT symmetry — new BULLISH flip detected)r   r2   rf   r   r   r   r*  r   r   r   r  r   r  r  r   r  r   r   r   r   r   r   r   r   rj  r   r  s                    r/   test_exit_short_symmetryr  e  s    
-C	-46.RS	TBCE?3T3T3Z3Z[E D.@@FFD	 D
$s146	C &&s++H??4k..4.444?44444?444444484448444?444444k444k444.44444444444-.6$6.$6666.$666.666$6666666<= ,s   B.J0J1GJc                   K   t        d       t                d {    t                d {    t                d {    t	                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t                d {    t!                d {    t#                d {    t%                d {    t'                d {    t)                t+                t-                t/                t1                d {    t3                d {    t5                d {    t7                d {    t9                d {    t;                d {    t=                d {    t?                d {    tA                d {    tC                d {    tE                d {    tG                d {    tI                d {    t        d       y7 g7 X7 I7 :7 +7 7 7 7 7 7 7 7 7 7 7 7 w7 h7 Y7 "7 7 7 7 7 7 7 7 7 7 7 t7 dw)Nztest_brain_tf.pyzALL TESTS PASSEDr   )%r   r  r  r  r&  r+  r3  r5  rG  rL  rU  rY  r\  rl  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rM   r;   r/   
main_asyncr!  ~  s9    	

'
)))
&
(((
*
,,,
7
999
8
:::
;
===
2
444
.
000
#
%%%
'
)))
"
$$$
/
111

!!!
.
000
/
111
)
+++
/
111
0
222
&
(((&( " %&(*
*
,,,
%
'''
(
***
 
"""
 
"""
"
$$$
"
$$$
5
777
3
555
;
===
;
===
6
888
9
;;;	
_ *(,9:=40%)$1!01+12( -'*""$$75==8;s:  KJKJKJ KJK#J$K5J6KJKJK+J,K=J>KJ K!J#"K3J&4KJ)KJ,K)J/*K;J2<KJ5KJ8 9KJ;K+J>,K=K>KKK!K"K3K4KK
KKK)K*K;K<KKKK K1K2KKKKKKKKKK K#K&K)K,K/K2K5K8K;K>KKKKK
KKKKKKKc                 <    t        j                  t                     S rD   )asynciorunr!  rM   r;   r/   mainr%    s    ;;z|$$r;   __main__)re   r   rE   r
   )r   r   rE   r	   )rE   r   )r   )r*   rG   rE   r   )r   rG   r*   rG   r   rG   rs   r   r   r   r   rH   rE   r   )r   rG   rE   rF   )r  rH   rE   rG   )NNN)r  zTradeEntry | Noner  zTradeRuntime | Noner   zdict | NonerE   r   )rE   rH   )hrL   
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r#  rc   sysr   r   pathlibr   pathinsertrG   __file__resolveparentanalysis.price_actionr   r   analysis.tech_snapshotr	   brain.ai_clientr
   brain.brain_tfr   r   r   core.configr   r   r   core.contractsr   r   r   r   r   r   r   r   r   r   r0   r2   rO   rX   rf   r   r   r   r   r   r   r   r  r  r  r&  r+  r3  r5  rG  rL  rU  rY  r\  rl  rn  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r%  rI   exitrM   r;   r/   <module>r:     sJ  	 #     
 '  3tH~--/66==> ? > / & F F ; ;  &* (7 7? ?<
8vM8 !&U / A A G G#"%!#	   	 )3	27
3C&T(U2F(A08,50R>B4RD&YR+ +E$K M*8($HN>:SBS6%NX 	RA  $#'

 
 
 	
7 2&F,@&&**$B48(D0A.H,$4N>22j% zCHHTV r;   