
    /jD                    h   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mZmZmZ ddl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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, d*dZ- G d d      Z. G d d      Z/ G d d      Z0 G d de      Z1dde$jd                  jf                  df	 d+dZ4dde$jd                  jf                  f	 d,dZ5d Z6d Z7d Z8d Z9d Z:d Z;d Z<d  Z=d! Z>d" Z?d# Z@d$ ZAd% ZBd& ZCeDd'k(  rl eEd(        e7         e8         e9         e:         e;         e<         e=         e>         e?         e@         eA         eB         eC         eEd)       yy)-u-  
Phase C2a unit tests: Reconciler 5-case matrix + watchdog.

12 tests against an in-memory FakeBroker and synthetic state. No
orchestrator, no main — just the Reconciler API.

  case (i):     1 test
  case (ii):    4 tests (no-history, win, loss, no-risk-manager)
  case (iii):   1 test
  case (iv):    1 test
  case (v):     2 tests (naked logged, with-SL not naked)
  watchdog:     2 tests (no positions early-exit, raises non-fatal)
  report:       1 test (mixed cases counted correctly)

Run:
    cd ~/apex_v16
    python tests/test_reconciliation.py
    )annotationsN)datetime	timedeltatimezone)Path)Optional)
BrokerBaseCancelResultClosedTradeOrderOrderResultPosition)NakedPositionsReportReconciliationReport
Reconciler)	BrainName	DirectionMarketStructureRegime
TradeEntryTradeRuntime)ActiveTradeSessionStatec                     t        d|         y )Nz  ok  )print)labels    0/home/work/apex_v16/tests/test_reconciliation.py_okr   *   s    	F5'
    c                      e Zd Zd Zd Zy)	JsonlSinkc                    g | _         y N)eventsselfs    r   __init__zJsonlSink.__init__3   s	    "$r   c                B    | j                   j                  d|i|       y )Nevent)r$   append)r&   r)   fieldss      r   writezJsonlSink.write5   s    GU5f56r   N)__name__
__module____qualname__r'   r,    r   r   r!   r!   2   s    %7r   r!   c                      e Zd Zd Zy)
FakeLoggerc                "    t               | _        y r#   )r!   	brain_logr%   s    r   r'   zFakeLogger.__init__:   s    "r   N)r-   r.   r/   r'   r0   r   r   r2   r2   9   s    %r   r2   c                  *    e Zd Zd Zd Zd ZdddZy)FakeRiskManagerc                .    g | _         g | _        g | _        y r#   )	pnl_callstp_hitssl_hitsr%   s    r   r'   zFakeRiskManager.__init__?   s    8:"$"$r   c               @    | j                   j                  |||f       y r#   )r8   r*   )r&   	delta_usdis_winbrains       r   update_daily_pnlz FakeRiskManager.update_daily_pnlD   s    y&%89r   c                :    | j                   j                  |       y r#   )r9   r*   r&   symbols     r   register_tp_hitzFakeRiskManager.register_tp_hitG       F#r   N)now_utcc               :    | j                   j                  |       y r#   )r:   r*   )r&   rB   rE   s      r   register_sl_hitzFakeRiskManager.register_sl_hitJ   rD   r   )r-   r.   r/   r'   r?   rC   rG   r0   r   r   r6   r6   >   s    %
:$ 26 $r   r6   c                      e Zd ZdZd Zd Zd Zd Zd Zd Z	ddZ
dd	Zdd
Zd Zd Zd Zd Zd ZddZd Zd Zd Zd Zy)
FakeBrokerzHIn-memory BrokerBase. Tests configure `positions`, `pendings`, `trades`.c                <    g | _         g | _        g | _        d| _        y )NF)	positionspendingstradesrecent_trades_raisedr%   s    r   r'   zFakeBroker.__init__R   s    )+%')+*/!r   c                   K   ywNTr0   r%   s    r   connectzFakeBroker.connectX   s     D   c                   K   y wr#   r0   r%   s    r   
disconnectzFakeBroker.disconnectY   s     trR   c                   K   ywrP   r0   r%   s    r   is_connectedzFakeBroker.is_connectedZ   s     rR   c                   K   yw)N     @r0   rA   s     r   get_last_pricezFakeBroker.get_last_price[   s     6rR   Nc                l   K   | j                   D cg c]  }||j                  |k(  s| c}S c c}w wr#   )rK   rB   )r&   rB   ps      r   positions_getzFakeBroker.positions_get\   s-     >>TafnF@RTTTs   4//4c                   K   |t        | j                        S | j                  D cg c]  }|j                  |k(  s| c}S c c}w wr#   )listrL   rB   )r&   rB   os      r   pending_orderszFakeBroker.pending_orders^   s=     >&&==?aAHH,>???s   &A	AAA	c                   K   | j                   rt        d      t        | j                        }|-|D cg c]"  }|j                  |k(  s||j                  v s!|$ }}|d | S c c}w w)Nzhistory fetch failed)rN   RuntimeErrorr^   rM   rB   )r&   rB   sincelimitrowsts         r   recent_tradeszFakeBroker.recent_tradesb   sj     $$566DKK #P!qxx6'9Vqxx=OAPDPFU| Qs   3A("A#A#A(c                "   K   t        d      S wNT)successr   )r&   kws     r   place_market_bracketzFakeBroker.place_market_bracketi   s     {47P0P   c                (   K   t        d|dd      S w)NTzS-FAKE)rj   sl_pricestop_identry_idrk   )r&   rB   side	contracts
stop_prices        r   place_stop_orderzFakeBroker.place_stop_orderj   s     4*h$,. 	.   c                (   K   t        d|dd      S w)NTzT-FAKE)rj   tp_price	target_idrr   rk   )r&   rB   rs   rt   limit_prices        r   place_limit_orderzFakeBroker.place_limit_orderm   s     4+$,. 	.rw   c                "   K   t        d      S wri   )r
   )r&   rB   order_ids      r   cancel_orderzFakeBroker.cancel_orderp   s     <PT;U4Urn   c                   K   yw)Nr   r0   rA   s     r   cancel_all_for_symbolz FakeBroker.cancel_all_for_symbolq   s     !rR   c                "   K   t        d      S wri   rk   )r&   rB   rt   s      r   close_positionzFakeBroker.close_positionr   s     ;W[C\<\rn   c	                ,   K   t        dddd||      S w)NTzC-FAKEzS2-FAKEzT2-FAKE)rj   rr   rq   rz   rp   ry   rk   )	r&   rB   	directioncontracts_to_closeresidual_contractsnew_sl_pricenew_tp_priceold_stop_order_idold_target_order_ids	            r    partial_close_via_opposite_orderz+FakeBroker.partial_close_via_opposite_orders   s#      8Y)!L
 	
   c                $   K   t        d|      S w)NT)rj   rp   rk   )r&   rB   r~   r   s       r   modify_stopzFakeBroker.modify_stop{   s     4,??s   c                   K   yw)Ng     j@r0   r%   s    r   get_account_balancezFakeBroker.get_account_balance}   s     rR   c                :   K   dd l }|j                  g d      S w)Nr   )openhighlowclosevolume)columns)pandas	DataFrame)r&   rB   	timeframenpds        r   
fetch_barszFakeBroker.fetch_bars~   s     ||$N|OOs   r#   )NN2   )r-   r.   r/   __doc__namer'   rQ   rT   rV   rY   r\   r`   rg   rm   rv   r|   r   r   r   r   r   r   r   r0   r   r   rI   rI   N   s^    RD0 )+-9U@ Q.. V;\
@7Pr   rI   MES   
   c           	     r   t        d i d| d|dt        j                  j                  d|ddddd	d
dt	        j
                  t        j                        t        |      z
  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S )!NrB   
brain_namer   rt   entry_pricerX   rp        @ry        @	opened_at)minutesrsi_m5_at_entryg     K@rsi_h1_at_entryg      J@rsi_h4_at_entryg      I@atr_ratio_at_entryg      ?market_structure_at_entryregime_at_entryh1_compat_at_entryconfidence_at_entryF   entry_order_idE1stop_order_idS1target_order_idT1r0   )r   r   BUYvaluer   nowr   utcr   r   BULLISH_EXPANSIONr   TRENDING)rB   rt   r>   opened_minutes_agos       r   
make_entryr      s    "'3<==3F3F  &, 7= ,,x||,yAS/TT	
 
 /3
 EI  #2"C"C"I"I --  57  ,0 BF r   c                ~    t               }t        | ||      }t               }t        ||      |j                  | <   |S )N)rB   rt   r>   entryruntime)r   r   r   r   active_trades)rB   rt   r>   stater   r   s         r   make_state_with_trader      s:    NEf	GEnG"-E7"KELr   c                ,    t        j                  |       S r#   )asynciorun)coros    r   r   r      s    ;;tr   c                 ,   t        dd      } t               }t        dddd      g|_        t	        || t               t                     }t        |j                               }|j                  }dg}||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}}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  }t        j&                  d      dz   d|iz  }t!        t        j"                  |            dx}	x}
}t)        d       y)zJstate OPEN + broker OPEN + matching contracts -> case (i) OK, no mutation.r   r   rt   r   rX   rB   r   rt   	avg_price==z1%(py2)s
{%(py2)s = %(py0)s.case_i_ok
} == %(py5)sreportpy0py2py5assert %(py7)spy7Nin)z5%(py1)s in %(py5)s
{%(py5)s = %(py3)s.active_trades
}r   py1py3r   z%state must NOT be mutated in case (i)
>assert %(py7)szHcase (i): state OPEN + broker OPEN + size match -> log-only, no mutation)r   rI   r   rK   r   r6   r2   r   reconcile_startup	case_i_ok
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr   _format_assertmsgr   r   brokerrecr   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_assert0@py_assert2s              r   (test_case_i_state_open_broker_open_matchr      sO   !%15E\F !W]^_F
VUO$5z|
DC&&()F&w&w&&&&w&&&&&&6&&&6&&&&&&w&&&&&&&PE''P5''PPP5'PPP5PPPPPPEPPPEPPP'PPP)PPPPPPPPRSr   c                 
   t        d      } t               }t               }t        || |t	                     }t        |j                               }|j                  }dg}||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                   }g }||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}}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  }t        j$                  d      dz   d|iz  }	t        t        j                  |	            dx}
x}}g }|j&                  }g }||k(  }|}
|r,|j(                  }g }||k(  }|}
|r|j*                  }g }||k(  }|}
|
s#t        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  }|j-                  |       |rBt        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  }|j-                  |       |rt        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  }|j-                  |       t        j.                  |d      i z  }dd|iz  }t        t        j                  |            dx}
x}x}x}x}x}x}x}x}x}}t1        d        y)!zCstate OPEN + broker FLAT + no recent_trades -> drop, no risk hooks.r   r   zF%(py2)s
{%(py2)s = %(py0)s.case_ii_state_open_broker_flat
} == %(py5)sr   r   r   r   NzE%(py2)s
{%(py2)s = %(py0)s.case_ii_recovered_via_history
} == %(py5)snot inz9%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.active_trades
}r   r   z$case (ii) MUST drop the orphan trader   )z1%(py4)s
{%(py4)s = %(py2)s.pnl_calls
} == %(py7)srisk)r   py4r   %(py9)spy9)z3%(py13)s
{%(py13)s = %(py11)s.tp_hits
} == %(py16)s)py11py13py16%(py18)spy18)z3%(py22)s
{%(py22)s = %(py20)s.sl_hits
} == %(py25)s)py20py22py25z%(py27)spy27r   zassert %(py30)spy30z3case (ii): no history -> drop trade, no risk update)r   rI   r6   r   r2   r   r   case_ii_state_open_broker_flatr   r   r   r   r   r   r   r   case_ii_recovered_via_historyr   r   r8   r9   r:   r*   _format_boolopr   )r   r   r   r   r   r   r   r   r   r   r   r   @py_assert6@py_assert5@py_assert12@py_assert15@py_assert14@py_assert21@py_assert24@py_assert23@py_format10@py_format17@py_format19@py_format26@py_format28@py_format29@py_format31s                              r   7test_case_ii_no_history_drops_trade_without_risk_updater     s   !%(E\FD
VUD*,
7C&&()F00;UG;0G;;;;0G;;;;;;6;;;6;;;0;;;G;;;;;;;//525/25555/255555565556555/55525555555S++S5++SSS5+SSS5SSSSSSSSSSSS+SSS-SSSSSSSSM4>>MRM>RMDLLMBMLB$6M4<<M2M<2;MMMMM>RMMMMMM4MMM4MMM>MMMRMMMMMMMLBMMMMMMDMMMDMMMLMMMBMMMMMMM<2MMMMMM4MMM4MMM<MMM2MMMMMMMMMMMMMMM=>r   c            	     ~
   t        dt        j                  j                        } t	               }t        ddddddd	      g|_        t               }t        || |t                     }t        |j                               }|j                  }dg}||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g}||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g}||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}}|j0                  }g }||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}}d}
| j2                  }|
|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}}t5        d       y)zRstate OPEN + broker FLAT + recent_trades has WIN -> register_tp_hit + pnl applied.r   r>   T9r   SELL     @      ^@2026-04-28T12:00:00+00:00trade_idrB   rt   rs   
exit_pricepnl_usd	closed_atr   r   r   r   r   r   N)z9%(py2)s
{%(py2)s = %(py0)s.pnl_recovered_usd
} == %(py5)s)r$  TTFz1%(py2)s
{%(py2)s = %(py0)s.pnl_calls
} == %(py5)sr   z/%(py2)s
{%(py2)s = %(py0)s.tp_hits
} == %(py5)sz/%(py2)s
{%(py2)s = %(py0)s.sl_hits
} == %(py5)sr   r   r   r   zDcase (ii) recovered WIN: pnl applied, register_tp_hit, trade dropped)r   r   r+  r   rI   r   rM   r6   r   r2   r   r   r  r   r   r   r   r   r   r   r   pnl_recovered_usdr8   r9   r:   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s               r   &test_case_ii_recovered_via_history_winr1     s!   !%y||/A/ABE\F eqv54O FM D
VUD*,
7C&&()F//:E7:/7::::/7::::::6:::6:::/:::7:::::::##,u,#u,,,,#u,,,,,,6,,,6,,,#,,,u,,,,,,,>>2122>22222>222222242224222>22222222222<<"E7"<7""""<7""""""4"""4"""<"""7"""""""<<2<2<244<2++++5+++++5++++5++++++++++++++++++++NOr   c            	     h   t        dt        j                  j                        } t	               }t        ddddddd	      g|_        t               }t        || |t                     }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g}||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g}||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.                  }g }||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}}t1        d       y)zEstate OPEN + broker FLAT + recent_trades has LOSS -> register_sl_hit.r   r   r!  r   r"  r        Vr%  r&  g     V@r   )z:%(py2)s
{%(py2)s = %(py0)s.pnl_recovered_usd
} == -%(py5)sr   r   zassert %(py8)spy8N)r3  FMRr,  r   r   r   r.  r-  z6case (ii) recovered LOSS: pnl applied, register_sl_hit)r   r   r5  r   rI   r   rM   r6   r   r2   r   r   r/  r   r   r   r   r   r   r   r   r8   r:   r9   r   )r   r   r   r   r   r   r   r  r   @py_format7@py_format9r   r   s                r   'test_case_ii_recovered_via_history_lossr8     sB   !%y||/A/ABE\F eqv54O FM D
VUD*,
7C&&()F##,,u,#u,,,,#u,,,,,,6,,,6,,,#,,,,,,,,,,>>3233>33333>333333343334333>33333333333<<"E7"<7""""<7""""""4"""4"""<"""7"""""""<<2<2<244<2@Ar   c                 0   t        d      } t               }d|_        t               }t	        || |t                     }t        |j                               }|j                  }dg}||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"                  }g }||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}}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  }t        j&                  d      dz   d|iz  }	t        t        j                   |	            d	x}
x}}|j(                  }g }||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}}t+        d       y	)zCrecent_trades raising -> degraded mode: drop trade, no risk update.r   Tr   r   r   r   r   r   Nr   r   r   r   r   zfallback still drops the trader   r,  r   zDcase (ii) recent_trades raises: degraded, drop trade, no risk update)r   rI   rN   r6   r   r2   r   r   r  r   r   r   r   r   r   r   r   r  r   r   r8   r   r0  s               r   ,test_case_ii_recent_trades_raises_falls_backr:     s"   !%(E\F"&FD
VUD*,
7C&&()F00;UG;0G;;;;0G;;;;;;6;;;6;;;0;;;G;;;;;;;//525/25555/255555565556555/55525555555M++M5++MMM5+MMM5MMMMMMMMMMMM+MMM-MMMMMMMM>>R>R>R44>RNOr   c            	     J   t        d      } t               }t        ddddddd      g|_        t	        || d	t               
      }t        |j                               }|j                  }g }||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  }t        j                  d      dz   d|iz  }t!        t        j"                  |            d	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  }t        j                  d      dz   d|iz  }t!        t        j"                  |            d	x}	x}
}t'        d       y	)zKrisk_manager=None -> case (ii) drops trade but never attempts P&L recovery.r   r!  r   r"  r#  r$  r%  r&  N)risk_managerloggerr   r   r   r   z(no risk_manager -> no recovery attemptedr   r   r   r   r   r   ztrade still droppedz0case (ii) no risk_manager: drop without recovery)r   rI   r   rM   r   r2   r   r   r  r   r   r   r   r   r   r   r   r   r   r   r   s              r   3test_case_ii_no_risk_manager_drops_without_recoveryr>     s   !%(E\F eqv54O FM VUjl
KC&&()F// 32 3/25 3!2!23/2 3 3,2F3 322  3 3)2  3 3)2 0 3 3)2 46 3 3!2!223 3 3223 3B++B5++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:;r   c                    t               } t               }t        dddd      g|_        t	               }t        || t               |      }t        |j                               }|j                  }dg}||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}}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  }t        j&                  d      dz   d|iz  }	t!        t        j"                  |	            dx}
x}}d |j(                  j*                  D        }t-        |      }|sddt        j                         v st        j                  t,              rt        j                  t,              ndt        j                  |      t        j                  |      dz  }t!        t        j"                  |            dx}}t/        d       y)zAstate FLAT + broker OPEN -> case (iii), LOG-ONLY (no auto-adopt).r   r      rX   r   r   zG%(py2)s
{%(py2)s = %(py0)s.case_iii_state_flat_broker_open
} == %(py5)sr   r   r   r   Nr   r   r   r   zcase (iii) MUST NOT auto-adoptr   c              3  ,   K   | ]  }|d    dk(    yw)r)   %recon_case_iii_state_flat_broker_openNr0   .0es     r   	<genexpr>z@test_case_iii_state_flat_broker_open_log_only.<locals>.<genexpr>  s"      1 zDD 1r   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   r   r   z?case (iii): state FLAT + broker OPEN -> log-only, no auto-adopt)r   rI   r   rK   r2   r   r6   r   r   case_iii_state_flat_broker_openr   r   r   r   r   r   r   r   r   r   r4   r$   rI  r   )r   r   r=  r   r   r   r   r   r   r   r   r   @py_format5s                r   -test_case_iii_state_flat_broker_open_log_onlyrM    s   NE\F f F \F
VUO$5v
>C&&()F11<eW<1W<<<<1W<<<<<<6<<<6<<<1<<<W<<<<<<<M++M5++MMM5+MMM5MMMMMMMMMMMM+MMM-MMMMMMMM1((//1 13 1 1 1 1 1*0&1 100  1 1'0y  1 1'0y1 1 1'0y1 1 1 1001 1IJr   c                    t        dd      } t               }t        dddd      g|_        t	               }t        || t               |      }t        |j                               }|j                  }dg}||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   }
|
j&                  }|j(                  }d}||k(  }|st        j                  d|fd||f      t        j                  |
      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}
x}x}x}}d |j*                  j,                  D        }t/        |      }|sddt        j                         v st        j                  t.              rt        j                  t.              ndt        j                  |      t        j                  |      dz  }t!        t        j"                  |            dx}}t1        d       y)zIstate OPEN(2) + broker OPEN(1) -> case (iv), LOG-ONLY (V16 conservative).r   r   r   r   r@  rX   r   r   z=%(py2)s
{%(py2)s = %(py0)s.case_iv_size_mismatch
} == %(py5)sr   r   r   r   N)zL%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.entry
}.contracts
} == %(py8)s)r   r   r   r4  assert %(py10)spy10c              3  ,   K   | ]  }|d    dk(    yw)r)   recon_case_iv_size_mismatchNr0   rD  s     r   rG  z6test_case_iv_size_mismatch_log_only.<locals>.<genexpr>%  s"      1 z:: 1r   rH  rI  rJ  z5case (iv): size mismatch -> log-only, state untouched)r   rI   r   rK   r2   r   r6   r   r   case_iv_size_mismatchr   r   r   r   r   r   r   r   r   r   rt   r4   r$   rI  r   )r   r   r=  r   r   r   r   r   r   r   r   r   @py_assert7r  r7  @py_format11rL  s                    r   #test_case_iv_size_mismatch_log_onlyrW    s   !%15E\F f F \F
VUO$5v
>C&&()F''2E72'72222'722222262226222'22272222222u%:%++:+55::5::::5:::%:::+:::5::::::::::1((//1 13 1 1 1 1 1*0&1 100  1 1'0y  1 1'0y1 1 1'0y1 1 1 1001 1?@r   c                    t        d      } t               }t        dddd      g|_        t	        dddd	d
      g|_        t        || t               t                     }t        |j                               }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)z<Position with no STOP order in pending -> case (v) reported.r   r   r   rX   r   zO-TPCON.F.US.ES.M26LIMITr   r~   rB   kindpricert   r   )z;%(py1)s in %(py5)s
{%(py5)s = %(py3)s.case_v_naked_orders
}r   r   r   r   Nz;case (v): position without STOP in pending -> flagged nakedr   rI   r   rK   r   rL   r   r6   r2   r   r   case_v_naked_ordersr   r   r   r   r   r   r   r   r   	r   r   r   r   r   r   r   r   r   s	            r   !test_case_v_naked_position_loggedra  *  s    !%(E\F f F  1 FO VUO$5z|
DC&&()F.F...5.....5....5......F...F...........EFr   c                    t        d      } t               }t        dddd      g|_        t	        dddd	d
      g|_        t        || t               t                     }t        |j                               }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)z&Position with STOP order -> NOT naked.r   r   r   rX   r   zO-SLrY  STOPr   r[  r   z?%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.case_v_naked_orders
}r   r   r   r   Nz1case (v): position with STOP -> not flagged nakedr^  r`  s	            r   (test_case_v_position_with_stop_not_nakedre  <  s    !%(E\F f F  1 FO VUO$5z|
DC&&()F222252222252222522222222222222222222;<r   c                    t               } t               }t        || t               t	                     }t        |j                               }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                   }g }||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}}t%        d       y)zBwatchdog_naked_positions with no broker positions -> empty report.z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer   r   )r   r   r   r   Nr   z5%(py2)s
{%(py2)s = %(py0)s.naked_symbols
} == %(py5)sr   r   r   z4watchdog: no positions -> empty NakedPositionsReport)r   rI   r   r6   r2   r   watchdog_naked_positionsrg  r   r   r   r   r   r   r   r   naked_symbolsr   r   )
r   r   r   r   r   rL  r   r   r   r   s
             r   (test_watchdog_no_positions_returns_emptyrk  M  s>   NE\F
VUO$5z|
DC--/0Ff233333333:333:333333f333f333333233323333333333%2%2%%%%2%%%%%%6%%%6%%%%%%2%%%%%%%>?r   c                 z   t               } t               }t        dddd      g|_        g |_        t        || t               t                     }t        |j                               }|j                  }dg}||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}}t'        d       y)zJwatchdog_naked_positions: position present, no STOP in pending -> flagged.MNQr"  r@  g     @r   r   rh  r   r   r   r   Nz=watchdog: position without any pending order -> flagged naked)r   rI   r   rK   rL   r   r6   r2   r   ri  rj  r   r   r   r   r   r   r   r   r   )	r   r   r   r   r   r   r   r   r   s	            r   ,test_watchdog_flags_naked_after_pending_droprn  X  s    NE\F !w F FO
VUO$5z|
DC--/0F*E7*7****7******6***6******7*******GHr   c                    t               } t        dd      }t        |t                     | j                  d<   t        dd      }t        |t                     | j                  d<   t        dd      }t        |t                     | j                  d<   t               }t        dddd	
      t        dddd
      t        dddd
      g|_        t        ddddd      g|_	        t        || t               t                     }t        |j                               }|j                  }dg}||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}	}|j0                  }dg}||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}	}|j2                  }dg}||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g}||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                  }t9        |      }ddh}||k\  }|s
t!        j"                  d|fd ||f      d!t%        j&                         v st!        j(                  t8              rt!        j*                  t8              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}}d}|j6                  }||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  }
t!        j:                  d(      d)z   d|
iz  }t-        t!        j.                  |            dx}x}}g }d}| j                  }||v }|}|r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  }|j=                  |       |rt!        j"                  d*fd0f      t!        j*                  |      d,t%        j&                         v st!        j(                  |       rt!        j*                  |       nd,t!        j*                  |      d1z  }d2d3|iz  }|j=                  |       t!        j>                  |d4      i z  }d5d6|iz  }t-        t!        j.                  |            dx}x}x}x}x}x}x}}d}| j                  }||v}|st!        j"                  d%|fd7||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}}tA        d8       y)9zDAll 5 cases coexist in a single reconcile_startup() -> all reported.r   r   )rB   rt   r   rm  r@  6Er   rX   r      g?6Br"  gRQ?zOS-MESrY  rc  r   r[  r   r   r   r   r   r   Nr   rA  rO  )>=)zY%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.case_v_naked_orders
})
} >= %(py8)sset)r   r   r   r   r4  rP  rQ  r   rd  r   zMES has its STOP -> not nakedr   r   )z5%(py3)s in %(py7)s
{%(py7)s = %(py5)s.active_trades
}r   )r   r   r   r   r  )z9%(py12)s in %(py16)s
{%(py16)s = %(py14)s.active_trades
})py12py14r  r  r  r   zassert %(py21)spy21r   z7mixed: all 5 cases counted; mutation only for case (ii))!r   r   r   r   r   rI   r   rK   r   rL   r   r6   r2   r   r   r   r   r   r   r   r   r   r   r   r  rK  rT  r_  rt  r   r*   r  r   )r   e_mese_mnqe_6er   r   r   r   r   r   r   r   r   rU  r  r7  rV  r   @py_assert11r  @py_assert13r  r  r  @py_format20@py_format22s                             r   test_report_counts_mixed_casesr  f  sh   NEeq1E!,5,.!QEeq1E!,5,.!QETQ/D +$ OE\F!vNdK!tL	F 	x(9a	)FO VUO$5z|
DC&&()F&w&w&&&&w&&&&&&6&&&6&&&&&&w&&&&&&&00;UG;0G;;;;0G;;;;;;6;;;6;;;0;;;G;;;;;;;11;dV;1V;;;;1V;;;;;;6;;;6;;;1;;;V;;;;;;;''1D61'61111'611111161116111'11161111111)):3)*:tTl:*l::::*l::::::3:::3::::::v:::v:::):::*:::l:::::::S22S522SSS52SSS5SSSSSSSSSSSS2SSS4SSSSSSSSG5GE''G5''GDGE4G4GGD4G,GGGGG5'GGG5GGGGGGEGGGEGGG'GGGGGGGD4GGGGDGGGGGGEGGGEGGG4GGGGGGGGGGGGGGG++++5+++++5++++5++++++++++++++++++++ABr   __main__ztest_reconciliation.pyzALL 13 TESTS PASSED)r   strreturnNone)r  r   )r  r   )Fr   
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r   sysr   r   r   pathlibr   typingr   pathinsertr  __file__resolveparentbroker.broker_baser	   r
   r   r   r   r   broker.reconciliationr   r   r   core.contractsr   r   r   r   r   r   persistence.state_storer   r   r   r!   r2   r6   rI   r+  r   r   r   r   r   r  r1  r8  r:  r>  rM  rW  ra  re  rk  rn  r  r-   r   r0   r   r   <module>r     s  & #    
 2 2   3tH~--/66==> ?    >7 7% %
$ $ 2P 2Pr q	0B0B"$)3  "'! ) 2 27C	T?P(B$P< K"A$G$="@I&CZ z	
"#,.;=*,+-027913')%',.,.02"$	
  r   