
    +i]                       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
m
Z
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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# dd	l$m%Z%m&Z&m'Z'm(Z( dd
l)m*Z*m+Z+ d>dZ,ddddddddddd
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d?dZ-d@dZ.dAdBdZ/dddddd	 	 	 	 	 	 	 	 	 	 	 dCdZ0dDdZ1dEd Z2d! Z3d" Z4d# Z5d$ Z6d% Z7d& Z8d' Z9d( Z:d) Z;d* Z<d+ Z=d, Z>d- Z?d. Z@d/ ZAd0 ZBd1 ZCd2 ZDd3 ZEd4 ZFd5 ZGd6 ZHd7 ZId8 ZJd9 ZKd: ZLd; ZMdFd<ZNeOd=k(  r e	j                   eN              yy)Ga[  
Smoke tests for trading/risk_manager.py.

Covers all 13 RiskRule rejection codes + lifecycle hooks (halt, daily P&L
update, register_sl_hit, register_tp_hit). Calendar boundary tests for
FORCE_FLAT (21:08 vs 21:07) and LAST_FRIDAY (15:00 vs 14:59), plus 4-Friday
and 5-Friday months.

Run:
    cd ~/apex_v16
    python -m tests.test_risk_manager
    )annotationsN)datetime	timedeltatimezone)Path)RuntimeConfigRunModeAccountKind)EntryDecisionRiskRuleutc_now)ActiveTrade	BiasCacheBrainCountersCooldownStateDailyCountersSessionState)CORRELATION_GROUPS	RiskAuditRiskCheckResultRiskManagerSizingAuditSizingDecisionc                     t        d|         y )Nz  ok  )print)labels    ./home/work/apex_v16/tests/test_risk_manager.py_okr   "   s    	F5'
    F     p     @     r@
      Q?         )
enable_correlationdaily_loss_hard_stopdaily_loss_soft_stopdaily_profit_targetmax_daily_tradesmax_open_trades_totalmax_risk_vs_daily_budgetforce_flat_utc_hourforce_flat_utc_minute$last_friday_of_month_cutoff_utc_hourc        
            t        t        j                  t        j                        }
| |
_        ||
_        ||
_        ||
_        ||
_	        ||
_
        ||
_        ||
_        ||
_        |	|
_        |
S )N)modeaccount)r   r	   PAPERr
   
INELIGIBLEr*   r+   r,   r-   r.   r/   r0   r1   r2   r3   )r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   cfgs              r   make_configr:   *   so     W]]K4J4J
KC/C3C3C1C+C 5C#;C 1C 5C/SC,Jr    c                     t               S )N)r    r    r   
make_stater=   E   s
    >r    c           	     B    t        | d| dk(  rdnd| dk(  rdndddd	
      S )N     @BUY    @g    @     @g     @g      ?K   test)	directionentry_pricesl_pricetp_pricerr_multiplier
confidence	rationale)r   )rE   s    r   
make_entryrL   I   s6    %.G%.G r    ok      Y@   )skipreason	contractsreal_risk_usdsl_ticksc                R    t        ddddddddd	d
dd      }t        || ||||      S )NMES      ?g       @g      @g      ?g      ?g     B@rN   g     ~@r(   F)symbolrisk_multipliertarget_floatsl_distance_points	tick_size
tick_valuesl_usd_per_contractrisk_usd_targetdaily_budget_cap_usdmax_contracts_usedclamp_activeinverted_quote)rR   rP   rQ   rT   rS   auditr   )rP   rQ   rR   rS   rT   rd   s         r   make_sizingre   U   sS      "E # r    c            	     B    t        ddddddt        j                        S )z2A safe Wednesday at 14:00 UTC (no weekly cutoffs).           r   tzinfo)r   r   utcr<   r    r   wednesday_14_utcrn   u   s    D!RQ(,,??r    c                     ddl m} m}  | d"i ddddddd	d
dddddddt               dddddddddddddddd }t	        | |       !      S )#z9Tiny ActiveTrade fixture for occupancy/correlation tests.r   )
TradeEntryTradeRuntimerX   rV   
brain_nameTFrE   r@   rR      rF   r?   rG   rA   rH   rB   	opened_atrsi_m5_at_entryg     K@rsi_h1_at_entryg      M@rsi_h4_at_entryg      N@atr_ratio_at_entryrW   market_structure_at_entryBULLISH_EXPANSIONregime_at_entryTRENDINGh1_compat_at_entryconfidence_at_entryrC   )entryruntimer<   )core.contractsrp   rq   r   r   )rp   rq   r   s      r   make_active_trader   z   s    7 !%16BC%+6< ) 	 /3	 EI	
 
 ;N # 8; E ULN;;r    c                    t               } t               }t        | |      }|j                  t	               t               di t                     }|j                  }d}||u }|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                   }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(                  }|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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}	}t-        d       y )NrV   r   sizingrX   active_tradesnow_utcTisz0%(py2)s
{%(py2)s = %(py0)s.approved
} is %(py5)srespy0py2py5assert %(py7)spy7==)z_%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.OK
}.value
}r   r   r   py4py6py8assert %(py10)spy10g        )zL%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.audit
}.daily_pnl
} == %(py7)sr   r   r   r   assert %(py9)spy9z0check_entry: all clear -> approved=True, rule=OK)r:   r=   r   check_entryrL   re   rn   approved
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationruler   OKvaluerd   	daily_pnlr   )r9   statermr   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_assert5@py_assert7@py_format9@py_format11@py_assert6@py_format10s                  r   #test_check_entry_all_clear_approvedr      s   
-CLE	S%	 B
..l;=B0@0B  C <<4<4<433<488(x{{({(((8(((((8(((((((3(((3(((8((((((x(((x((({(((((((((((99%9%#%#%%%%#%%%%%%3%%%3%%%9%%%%%%#%%%%%%%:;r    c                 X   t        t               t                     } t        dd      }| j	                  t               |di t                     }|j                  }d}||u }|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                   }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 )NTsize_too_small)rP   rQ   rV   r   Fr   r   r   r   r   r   r   )zh%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.SIZING_SKIP
}.value
}r   r   r   r   inz.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.reason
}py1py3r   z4check_entry: SizingDecision.skip=True -> SIZING_SKIP)r   r:   r=   re   r   rL   rn   r   r   r   r   r   r   r   r   r   r   r   SIZING_SKIPr   rQ   r   )r   r   r   r   r   r   r   r   r   r   r   r   @py_assert0@py_assert2s                 r   test_sizing_skip_propagatesr      s   	[]JL	1Bd+;<F
..l6B0@0B  C << 5 <5    <5      3   3   <   5       881x++1+11181111181111111311131118111111x111x111+11111111111)szz)z))))z)))))))))s)))s)))z)))))))>?r    c                    t               } d| _        d| _        t        t	               |       }|j                  t               t               di t                     }|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 )NTzmanual halt for testrV   r   r   )zc%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.HALTED
}.value
}r   r   r   r   r   zmanual haltr   r   r   r   r   z#check_entry: state.halted -> HALTED)r=   haltedhalt_reasonr   r:   r   rL   re   rn   r   r   HALTEDr   r   r   r   r   r   r   r   r   rQ   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                 r   test_halted_blocksr      sn   LEEL.E	[]E	*B
..l;=B0@0B  C 88,x,,,,8,,,,,8,,,,,,,3,,,3,,,8,,,,,,x,,,x,,,,,,,,,,,,,,&CJJ&=J&&&&=J&&&=&&&&&&C&&&C&&&J&&&&&&&-.r    c                    t        d      } t               }d|j                  _        t	        | |      }|j                  t               t               di t                     }|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}
||
u }|st        j                  d|fd||
f      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |
      dz  }t        j,                  d      dz   d|iz  }t'        t        j(                  |            d x}x}}
|j                  }|j.                  }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$                  |      dz  }t        j,                  d      dz   d|iz  }t'        t        j(                  |            d x}x}x}}t1        d       y )Nr!   )r+   rV   r   r   )zu%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.DAILY_LOSS_HARD_STOP_HIT
}.value
}r   r   r   r   r   Tr   z.%(py2)s
{%(py2)s = %(py0)s.halted
} is %(py5)sr   r   zhard stop must auto-halt
>assert %(py7)sr   )z[%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.daily
}.daily_loss_hard_stop_hit
} is %(py7)sr   zexplicit V16 flag must set
>assert %(py9)sr   zQDAILY_LOSS_HARD_STOP_HIT -> auto-halt + state.daily.daily_loss_hard_stop_hit=True)r:   r=   dailyr   r   r   rL   re   rn   r   r   DAILY_LOSS_HARD_STOP_HITr   r   r   r   r   r   r   r   r   r   _format_assertmsgdaily_loss_hard_stop_hitr   r9   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                  r   ,test_daily_loss_hard_stop_triggers_auto_haltr      s   
7
3CLE#EKK	S%	 B
..l;=B0@0B  C 88>x88>8>>>8>>>>>8>>>>>>>3>>>3>>>8>>>>>>x>>>x>>>8>>>>>>>>>>><<;4;<4;;;<4;;;;;;5;;;5;;;<;;;4;;;!;;;;;;;;;;U;//U4U/47UUU/4UUUUUU5UUU5UUU;UUU/UUU4UUU9UUUUUUUU[\r    c                    t        d      } t               }d|j                  _        t	        | |      }|j                  t               t               di t                     }|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}
||
u }|st        j                  d|fd||
f      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |
      dz  }t        j,                  d      dz   d|iz  }t'        t        j(                  |            d x}x}}
t/        d       y )Nr"   r,   rV   r   r   )zu%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.DAILY_LOSS_SOFT_STOP_HIT
}.value
}r   r   r   r   r   Fr   r   r   r   zsoft stop must NOT haltr   r   zBDAILY_LOSS_SOFT_STOP_HIT -> block, halted stays False (V15 parity))r:   r=   r   r   r   r   rL   re   rn   r   r   DAILY_LOSS_SOFT_STOP_HITr   r   r   r   r   r   r   r   r   r   r   r   )r9   r   r   r   r   r   r   r   r   r   r   r   r   s                r   (test_daily_loss_soft_stop_blocks_no_haltr      s   
7
3CLE#EKK	S%	 B
..l;=B0@0B  C 88>x88>8>>>8>>>>>8>>>>>>>3>>>3>>>8>>>>>>x>>>x>>>8>>>>>>>>>>><<;5;<5 ;;;<5;;;;;;5;;;5;;;<;;;5;;;";;;;;;;;LMr    c                 j   t        d      } t               }d|j                  _        t	        | |      }|j                  t               t               di t                     }|j                  }d}||u }|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}}t%        d       y)z5One penny above soft -> ok again (recovery scenario).r"   r   gR?rV   r   Tr   r   r   r   r   r   Nz>daily_pnl=-999.99 (one cent above soft) -> approved (recovery))r:   r=   r   r   r   r   rL   re   rn   r   r   r   r   r   r   r   r   r   r   )	r9   r   r   r   r   r   r   r   r   s	            r   )test_daily_loss_soft_stop_recovers_passesr      s    
7
3CLE#EKK	S%	 B
..l;=B0@0B  C <<4<4<433<4HIr    c                    t        d      } t               }d|j                  _        t	        | |      }|j                  t               t               di t                     }|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}
||
u }|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,                  }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$                  |      dz  }dd|iz  }t'        t        j(                  |            d x}x}x}}t/        d       y )Nr#   )r-   rV   r   r   )zx%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.DAILY_PROFIT_TARGET_REACHED
}.value
}r   r   r   r   r   Fr   r   r   r   r   r   T)zT%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.daily
}.profit_target_hit
} is %(py7)sr   r   r   z7DAILY_PROFIT_TARGET_REACHED -> block, NO halt, flag set)r:   r=   r   r   r   r   rL   re   rn   r   r   DAILY_PROFIT_TARGET_REACHEDr   r   r   r   r   r   r   r   r   r   profit_target_hitr   r   s                  r   'test_daily_profit_target_blocks_no_haltr      s   
%
0CLE!EKK	S%	 B
..l;=B0@0B  C 88Ax;;A;AAA8AAAAA8AAAAAAA3AAA3AAA8AAAAAAxAAAxAAA;AAAAAAAAAAA<< 5 <5    <5      5   5   <   5       ;;0;((0D0(D0000(D00000050005000;000(000D0000000ABr    c                    t        d      } t        | t                     }t               t               d}|j	                  t               t               d|t                     }|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 )Nr%   )r/   )6EGCrV   r   r   )zt%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.MAX_OPEN_TRADES_REACHED
}.value
}r   r   r   r   r   z2/2r   r   r   r   r   z3MAX_OPEN_TRADES_REACHED: 2 active vs cap=2 -> block)r:   r   r=   r   r   rL   re   rn   r   r   MAX_OPEN_TRADES_REACHEDr   r   r   r   r   r   r   r   r   rQ   r   )r9   r   activesr   r   r   r   r   r   r   r   r   r   r   r   s                  r   test_max_open_trades_reachedr     sw   
A
.C	S*,	'B&(0A0CDG
..l;=G5E5G  C 88=x77=7===8=====8=======3===3===8======x===x===7===========CJJ5J5J5CCJ=>r    c                 \   t               } d| j                  _        t        t	        d      |       }|j                  t               t               di t                     }|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}}t+        d       y )Nr$   )r.   rV   r   r   )zu%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.MAX_DAILY_TRADES_REACHED
}.value
}r   r   r   r   r   z7MAX_DAILY_TRADES_REACHED: executed_count=10/10 -> block)r=   r   executed_countr   r:   r   rL   re   rn   r   r   MAX_DAILY_TRADES_REACHEDr   r   r   r   r   r   r   r   r   r   )	r   r   r   r   r   r   r   r   r   s	            r   test_max_daily_trades_reachedr     s   LE!#EKK	["5u	=B
..l;=B0@0B  C 88>x88>8>>>8>>>>>8>>>>>>>3>>>3>>>8>>>>>>x>>>x>>>8>>>>>>>>>>>ABr    c            	     b   t        t               t                     } t        ddddddt        j
                        }| j                  t               t               di |	      }|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}}t+        d       y )Nrg   rh   ri   r'   r(   r   rk   rV   r   r   )zt%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.FORCE_FLAT_TIME_REACHED
}.value
}r   r   r   r   r   z*FORCE_FLAT boundary: 21:08:00 UTC -> block)r   r:   r=   r   r   rm   r   rL   re   r   r   FORCE_FLAT_TIME_REACHEDr   r   r   r   r   r   r   r   r   r   	r   nowr   r   r   r   r   r   r   s	            r   test_force_flat_at_2108_blocksr   )  s   	[]JL	1B
4BAq
>C
..l;=B  C 88=x77=7===8=====8=======3===3===8======x===x===7===========45r    c            	     l   t        t               t                     } t        ddddddt        j
                        }| j                  t               t               di |	      }|j                  }d
}||u }|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}}t%        d       y )Nrg   rh   ri   r'      ;   rk   rV   r   Tr   r   r   r   r   r   z-FORCE_FLAT boundary: 21:07:59 UTC -> approvedr   r:   r=   r   r   rm   r   rL   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s           r   test_force_flat_at_2107_passesr   5  s    	[]JL	1B
4BAr(,,
?C
..l;=B  C <<4<4<433<478r    c            	     b   t        t               t                     } t        ddddddt        j
                        }| j                  t               t               di |      }|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}}t+        d       y )Nrg   rh      r)   r   rk   rV   r   r   zo%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.LAST_FRIDAY_CUTOFF
}.value
}r   r   r   r   r   z"LAST_FRIDAY: 24-Apr 15:00 -> block)r   r:   r=   r   r   rm   r   rL   re   r   r   LAST_FRIDAY_CUTOFFr   r   r   r   r   r   r   r   r   r   r   s	            r   test_last_friday_15_00_blocksr   D  s   	[]JL	1B
4BAq
>C
..l;=B  C 888x228288888888888888888388838888888888x888x888288888888888,-r    c            	     l   t        t               t                     } t        ddddddt        j
                        }| j                  t               t               di |      }|j                  }d	}||u }|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}}t%        d       y )Nrg   rh   r   rj   r   rk   rV   r   Tr   r   r   r   r   r   z3LAST_FRIDAY: 24-Apr 14:59:59 -> approved (boundary)r   r   s           r   test_last_friday_14_59_passesr   P  s    	[]JL	1B
4BB8<<
@C
..l;=B  C <<4<4<433<4=>r    c            
        t        t               t                     } dD ]*  }t        dd|dddt        j
                        }| j                  t               t               di |      }|j                  }d	}||u }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                   d| d      dz   d|iz  }t#        t        j$                  |            dx}x}}- t        ddddddt        j
                        }	| j                  t               t               di |	      }
|
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}}t/        d       y)zu
    Feb 2026 has 4 Fridays: 6, 13, 20, 27.
    Only 27/02 is the last; the others must NOT trigger LAST_FRIDAY.
    )         rg   r%      r   rk   rV   r   Tr   r   r   r   Friday z/02 must NOT triggerr   r   N   r   r   res_lastr   r   r   r   zA4-Friday month (Feb 2026): only 27/02 triggers LAST_FRIDAY_CUTOFFr   r:   r=   r   r   rm   r   rL   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   dayr   r   r   r   r   r   r   lastr  r   r   r   r   s                  r   &test_4_friday_month_only_last_triggersr  _  s   
 
[]JL	1B ItQRAhllCnn,{}C  
 ||HtH|t#HHH|tHHHHHHsHHHsHHH|HHHtHHHwse3G%HHHHHHHHI D!RQ(,,?D~~l;=B  H ===H77=7=================8===8==========H===H===7===========KLr    c            
        t        t               t                     } dD ]*  }t        dd|dddt        j
                        }| j                  t               t               di |      }|j                  }d	}||u }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                   d| d      dz   d|iz  }t#        t        j$                  |            dx}x}}- t        ddddddt        j
                        }	| j                  t               t               di |	      }
|
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}}t/        d       y)zO
    Jan 2026 has 5 Fridays: 2, 9, 16, 23, 30.
    Only 30/01 is the last.
    )r%   	   r      rg   rt   r   r   rk   rV   r   Tr   r   r   r   r   z/01 must NOT triggerr   r   NrO   r   r   r  r   r   r   r   zA5-Friday month (Jan 2026): only 30/01 triggers LAST_FRIDAY_CUTOFFr  r  s                  r   &test_5_friday_month_only_last_triggersr  y  s   
 
[]JL	1B ItQRAhllCnn,{}C  
 ||HtH|t#HHH|tHHHHHHsHHHsHHH|HHHtHHHwse3G%HHHHHHHHI D!RQ(,,?D~~l;=B  H ===H77=7=================8===8==========H===H===7===========KLr    c                    t               } t               }|t        d      z   j                         | j                  j
                  d<   t        t               |       }|j                  t               t               di |      }|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}}t/        d       y )NrO   minutesrV   r   r   )zl%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.COOLDOWN_ACTIVE
}.value
}r   r   r   r   r   z2COOLDOWN_ACTIVE: cooldown_until in future -> block)r=   rn   r   	isoformatcooldowncooldown_untilr   r:   r   rL   re   r   r   COOLDOWN_ACTIVEr   r   r   r   r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   s
             r   test_cooldown_active_blocksr    s!   LE

C,/)B2G,G+R+R+TENN!!%(	[]E	*B
..l;=B  C 885x//5/55585555585555555355535558555555x555x555/55555555555<=r    c                    t               } t               }|t        d      z
  j                         | j                  j
                  d<   t        t               |       }|j                  t               t               di |      }|j                  }d}||u }|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}}d}	| j                  }|j
                  }
|	|
v}|st        j                  d|fd|	|
f      t        j"                  |	      dt        j                         v st        j                   |       rt        j"                  |       ndt        j"                  |      t        j"                  |
      dz  }t        j(                  d      dz   d|iz  }t%        t        j&                  |            d x}	x}x}}
t+        d       y )Nrt   )secondsrV   r   Tr   r   r   r   r   r   )not in)zX%(py1)s not in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.cooldown
}.cooldown_until
}r   r   r   r   r   zexpired entry should be clearedr   r   z,COOLDOWN expired -> approved + entry cleared)r=   rn   r   r  r  r  r   r:   r   rL   re   r   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_cooldown_expired_passes_and_clearsr    ss   LE

C,/)A2F,F+Q+Q+SENN!!%(	[]E	*B
..l;=B  C <<4<4<433<4XX55X555XXX55XXX5XXXXXXXXXXXXXXX5XXX7XXXXXXXX67r    c                 "   t        t        d      t                     } dt               i}| j	                  t               t               d|t                     }|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(                  }|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"                  |      t        j"                  |	      dz  }
dd|
iz  }t%        t        j&                  |            d x}x}x}}	t-        d       y )NTr*   rV   MNQr   r   zp%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.CORRELATION_BLOCKED
}.value
}r   r   r   r   r   zV%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.audit
}.correlation_blocker
} == %(py7)sr   r   r   z9CORRELATION: MES open + try MNQ (EQUITY_INDICES) -> blockr   r:   r=   r   r   rL   re   rn   r   r   CORRELATION_BLOCKEDr   r   r   r   r   r   r   r   r   rd   correlation_blockerr   r   r   r   r   r   r   r   r   r   r   r   r   s               r   'test_correlation_blocked_equity_indicesr"    s   	[D9:<	HB')*G
..l;=G5E5G  C 889x339399989999989999999399939998999999x999x9993999999999999919((1E1(E1111(E111111311131119111(111E1111111CDr    c                 X   t        t        d      t                     } dt               i}| j	                  t               t               d|t                     }|j                  }d}||u }|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}}t#        d       y )NFr  rV   r  r   Tr   r   r   r   r   r   z%CORRELATION disabled: MES+MNQ both ok)r   r:   r=   r   r   rL   re   rn   r   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   r   r   s           r    test_correlation_disabled_passesr$    s    	[E:JL	IB')*G
..l;=G5E5G  C <<4<4<433<4/0r    c                 "   t        t        d      t                     } dt               i}| j	                  t               t               d|t                     }|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(                  }|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"                  |      t        j"                  |	      dz  }
dd|
iz  }t%        t        j&                  |            dx}x}x}}	t-        d       y)z
    V15 bundles 6E/6B/6A/6J/6C into FX_MAJORS. Opening 6E and 6J together
    must be blocked when correlation is enabled (dollar-index correlation).
    Tr  r   6Jr   r   r  r   r   r   r   r   Nr  r   r   r   z6CORRELATION: V15 FX_MAJORS bundle -> 6E open blocks 6Jr  r!  s               r   !test_correlation_fx_majors_bundler'    s   
 
[D9:<	HB&()G
..l;=74D4F  C 889x339399989999989999999399939998999999x999x9993999999999999909((0D0(D0000(D000000300030009000(000D0000000@Ar    c                 :   t        t               t                     } t        d      }| j	                  t               |di t                     }|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}}t'        d       y)zJSizing produced more contracts than the per-symbol cap (regression guard).c   )rR   rV   r   r   )zs%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.MAX_CONTRACTS_EXCEEDED
}.value
}r   r   r   r   r   Nz=MAX_CONTRACTS_EXCEEDED: contracts=99 > MES cap (sanity guard))r   r:   r=   re   r   rL   rn   r   r   MAX_CONTRACTS_EXCEEDEDr   r   r   r   r   r   r   r   r   r   )	r   r   r   r   r   r   r   r   r   s	            r   test_max_contracts_exceededr+    s    	[]JL	1B2&F
..l6B0@0B  C 88<x66<6<<<8<<<<<8<<<<<<<3<<<3<<<8<<<<<<x<<<x<<<6<<<<<<<<<<<GHr    c                 l   t        ddd      } t               }d|j                  _        t	        | |      }t        d      }|j                  t               |di t                     }|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}}t+        d       y)zx
    daily_pnl=-1400, hard=-1500 -> remaining=$100. Cap=33% -> $33 allowed.
    sizing.real_risk_usd=50 -> exceeds.
    r!   r&   )r+   r,   r0   g           I@rS   rV   r   r   )z~%(py2)s
{%(py2)s = %(py0)s.rule
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.MAX_RISK_VS_DAILY_BUDGET_EXCEEDED
}.value
}r   r   r   r   r   Nz?MAX_RISK_VS_DAILY_BUDGET_EXCEEDED: $50 risk on $33 cap -> block)r:   r=   r   r   r   re   r   rL   rn   r   r   !MAX_RISK_VS_DAILY_BUDGET_EXCEEDEDr   r   r   r   r   r   r   r   r   r   )r9   r   r   r   r   r   r   r   r   r   r   s              r    test_max_risk_vs_budget_exceededr0    s    $$!%C
 LE#EKK	S%	 Bt,F
..l6B0@0B  C 88GxAAGAGGG8GGGGG8GGGGGGG3GGG3GGG8GGGGGGxGGGxGGGAGGGGGGGGGGGIJr    c                 D   t               } d| j                  _        d| j                  _        t	               t        d      z   j                         | j                  j                  d<   t        t               |       }t        d      }|j                  t               |di t	                     }|j                  }|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}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}x}}|j0                  }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}x}}|j2                  }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}}|j4                  }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}}|j6                  }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}}|j8                  }d}d}||z  }||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(                  |      dz  }
dd|
iz  }t+        t        j,                  |            d x}x}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 }||u}|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>                  }d#} ||      }|sd$dt#        j$                         v st        j&                  |      rt        j(                  |      ndt        j(                  |      t        j(                  |      t        j(                  |      t        j(                  |      d%z  }
t+        t        j,                  |
            d x}x}x}}|jA                         }g }|d&   }d	}| }||k(  }|}|r|d'   }d}||k(  }|}|st        j                   d
|fd(||f      t        j(                  |      t        j(                  |      d)z  }d*d+|iz  }|jC                  |       |r_t        j                   d
fd,f      t        j(                  |      t        j(                  |      d-z  }d.d/|iz  }|jC                  |       t        jD                  |d      i z  }d0d1|iz  }t+        t        j,                  |            d x}x}x}x}x}x}x}x}}tG        d2       y )3Ng      rh   rO   r  rV   g      ^@r.  r   g      @r   )z2%(py2)s
{%(py2)s = %(py0)s.daily_pnl
} == -%(py5)sar   zassert %(py8)sr   g     p@)z=%(py2)s
{%(py2)s = %(py0)s.daily_loss_hard_stop
} == -%(py5)sg     @@)z=%(py2)s
{%(py2)s = %(py0)s.daily_loss_soft_stop
} == -%(py5)sr#   )z;%(py2)s
{%(py2)s = %(py0)s.daily_profit_target
} == %(py5)sr   r   g     @)z>%(py2)s
{%(py2)s = %(py0)s.daily_remaining_budget
} == %(py5)s)z8%(py2)s
{%(py2)s = %(py0)s.pending_risk_usd
} == %(py5)s)zF%(py2)s
{%(py2)s = %(py0)s.risk_vs_budget_pct
} == (%(py5)s / %(py7)s))r   r   r   r   r   r   r   )z9%(py2)s
{%(py2)s = %(py0)s.open_trades_count
} == %(py5)s)is not)z:%(py2)s
{%(py2)s = %(py0)s.cooldown_until
} is not %(py5)sz2026-04-29T14:00ziassert %(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.now_utc
}.startswith
}(%(py6)s)
}r   r   pending_risk_usd)z%(py3)s == -%(py6)s)r   r   z%(py9)sr   )z%(py12)s == %(py15)s)py12py15z%(py17)spy17zassert %(py20)spy20z2RiskAudit fully populated; audit_dict() serializes)$r=   r   r   r   rn   r   r  r  r  r   r:   re   r   rL   rd   r   r   r   r   r   r   r   r   r+   r,   r-   daily_remaining_budgetr4  risk_vs_budget_pctopen_trades_countr   
startswith
audit_dictappend_format_boolopr   )r   r   r   r   r2  r   r   r   r   @py_format7r   r   r   @py_assert8r   r   r   dr   r   @py_assert11@py_assert14@py_assert13r   @py_format16@py_format18@py_format19@py_format21s                               r   !test_audit_populated_on_rejectionrJ    s   LE"EKK!"EKKYr22ik 
NN!!%( 
[]E	*Bu-F
..l6B0@0B  C 99A;; 5 5& ;&    ;&      1   1   ;   5       !!,f,fW,!W,,,,!W,,,,,,1,,,1,,,!,,,f,,,,,,,!!,f,fW,!W,,,,!W,,,,,,1,,,1,,,!,,,f,,,,,,,  )E) E)))) E))))))1)))1))) )))E)))))))##,u,#u,,,,#u,,,,,,1,,,1,,,#,,,u,,,,,,,&&&&&&&&&&&&1&&&1&&&&&&&&&&&&&0505055=0=0000=00000010001000000500050000000#!#!####!######1###1######!#######'4'4''''4''''''1'''1''''''4'''''''99393 23 233333333133313339333333 23333333333AF1[>FeFeVF>V#F*<(=FF(=(FFFF>VFFF>FFFeFFFFFFF(=FFF(=FFFFFFFFFFFFFFFFFF<=r    c                    t               } t        t               |       }t               }|j	                  d|       | j
                  j                  d   }t        j                  |      }d}t        |      }||z   }||k(  }|s7t        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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   }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 )NrV   r   rO   r  r   )zD%(py0)s == (%(py2)s + %(py7)s
{%(py7)s = %(py3)s(minutes=%(py5)s)
})expiryr   r   r   r   r   r   r   r   r   consecutive_sl_countrt   z%(py1)s == %(py4)sr   r   assert %(py6)sr   z:register_sl_hit: first SL -> 30min cooldown, consecutive=1)r=   r   r:   rn   register_sl_hitr  r  r   fromisoformatr   r   r   r   r   r   r   r   r   metadatar   r   r   r   curM  r   r   rA  r   r   r   r   r   r   @py_format5r@  s                   r   )test_register_sl_hit_first_30min_cooldownrY  0  su   LE	[]E	*B

Cuc*		&	&u	-B##B'F-/09R00S0006000006000000060006000000S000S00000090009000R00000000000>>01%8=A=8A====8A===8===A=======DEr    c                    t               } d| j                  j                  di       d<   t        t	               |       }t               }|j                  d|       | j                  j                  d   }t        j                  |      }d}t        |      }||z   }||k(  }|s7t        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	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   }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 )Nr%   rO  rV   rL  )hoursr   )zB%(py0)s == (%(py2)s + %(py7)s
{%(py7)s = %(py3)s(hours=%(py5)s)
})rM  r   r   rN  r   r      rP  rQ  rR  r   zEregister_sl_hit: prior consecutive=2 -> 2h cooldown (circuit breaker))r=   rU  
setdefaultr   r:   rn   rS  r  r  r   rT  r   r   r   r   r   r   r   r   r   r   rV  s                   r   ,test_register_sl_hit_consecutive_2h_cooldownr^  <  s   LECDENN4b9%@	[]E	*B

Cuc*		&	&u	-B##B'F+,-91--S---6-----6-------6---6------S---S------9---9---1----------->>01%8=A=8A====8A===8===A=======OPr    c                    t               } d| j                  j                  di       d<   t        t	               |       }|j                  d       | j                  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}| j                  }|j                  }||v }|st        j                  d
|fd||f      t        j                  |      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}x}}t!        d       y )Nr\  rO  rV   r   r   rP  rQ  rR  r   r   )zY%(py1)s in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.cooldown
}.last_trade_close_at
}r   r  r   r   z*register_tp_hit: consecutive_sl reset to 0)r=   rU  r]  r   r:   register_tp_hitr   r   r   r   r   r  last_trade_close_atr   r   r   r   )r   r   r   r   r   rX  r@  r   r   r   r   s              r   *test_register_tp_hit_resets_consecutive_slrb  M  s,   LECDENN4b9%@	[]E	*Bu>>01%8=A=8A====8A===8===A=======6ENN6N666566666566665666666E666E666N6666666666645r    c                    t               } t        t               |       }|j                  ddd       |j                  ddd       | j                  }|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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}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}}g }| j                  }|j                   }d}
||
k(  }|}|r!| j                  }|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                  |      t        j                  |
      dz  }dd|iz  }|j%                  |       |rt        j                  d	fdf      dt        j                         v st        j                  |       rt        j                  |       ndt        j                        t        j                  |      t        j                  |      dz  }dd|iz  }|j%                  |       t        j&                  |d      i z  }dd|iz  }t        t        j                  |            d x}x}x}x}x}x}
x}x}x}}t)        d       y ) Nr-  Trs   )is_winbraing      >FMRg      4@r   )zL%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.daily
}.daily_pnl
} == %(py7)sr   r   r   r   )z3%(py2)s
{%(py2)s = %(py0)s.session_pnl
} == %(py5)sr   r   r   rt   )zJ%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s.brain
}.tf_wins
} == %(py9)s)r   r   r   r   z%(py11)spy11)zR%(py17)s
{%(py17)s = %(py15)s
{%(py15)s = %(py13)s.brain
}.mr_losses
} == %(py20)s)py13r6  r7  r8  z%(py22)spy22r   zassert %(py25)spy25z@update_daily_pnl: routes win/loss to brain.{tf,mr}_{wins,losses})r=   r   r:   update_daily_pnlr   r   r   r   r   r   r   r   r   r   session_pnlre  tf_wins	mr_lossesr>  r?  r   )r   r   r   r   r   r   r   r   r   r   rA  r   r   rD  @py_assert16@py_assert19@py_assert18@py_format12rI  @py_format23@py_format24@py_format26s                         r   .test_update_daily_pnl_routes_to_brain_countersrv  W  sd   LE	[]E	*BT6e48;;(;  (D( D(((( D((((((5(((5(((;((( (((D((((((($$$$$$$$$$$$5$$$5$$$$$$$$$$$$$B5;;B;B!B!#BB(=(=BB(=(BBBBB!BBBBBB5BBB5BBB;BBBBBB!BBBBBBB(=BBBBBBBBBBBBBBB(=BBBBBBBBBBBBBBBBBBJKr    c                 L   t        d       t                t                t                t	                t                t                t                t                t                t                t                t                t                t                t                t!                t#                t%                t'                t)                t+                t-                t/                t1                t3                t5                t7                t        d       y)Nztest_risk_manager.pyzALL 27 TESTS PASSEDr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r"  r$  r'  r+  r0  rJ  rY  r^  rb  rv  r<   r    r   mainrx  f  s    	
 !')!02,.-/+- "!#"$"$!#!#*,*,!+-+-$&%'!$&%'-/02.024	
 r    __main__)r   strreturnNone)r*   boolr+   floatr,   r~  r-   r~  r.   intr/   r  r0   r~  r1   r  r2   r  r3   r  r{  r   )r{  r   )r@   )rE   rz  r{  r   )rP   r}  rQ   rz  rR   r  rS   r~  rT   r  r{  r   )r{  r   )r{  r   )r{  r  )Q__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   sysr   r   r   pathlibr   pathinsertrz  __file__resolveparentcore.configr   r	   r
   r   r   r   r   persistence.state_storer   r   r   r   r   r   trading.risk_managerr   r   r   r   trading.sizingr   r   r   r:   r=   rL   re   rn   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r"  r$  r'  r+  r0  rJ  rY  r^  rb  rv  rx  __name__exitr<   r    r   <module>r     s,   #   
 2 2  3tH~--/66==> ? ; ; ; ;   7  %")")!&!"&*!!"02    	
    $   +. 6	  
  	
   @@
<&<$
@"/$]&NJ$C&
?"	C 	69	.?M4M4
>8$	E1B(
I"K8>D	F
Q"6LB zCHHTV r    