
    /jG              	         U d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZ ddlmZ ddlZe
j$                  j'                  d e ee      j-                         j.                  j.                               ddlmZmZmZmZ ddlmZ ddlm Z m!Z!m"Z" dd	l#m$Z$ dd
l%m&Z& ddl'm(Z( ddl)m*Z*m+Z+ d6dZ, G d d      Z- G d d      Z. G d d      Z/ G d d      Z0 G d d      Z1 G d de      Z2d7dZ3ddl4m4Z5m6Z7  e5dddddde7jp                         Z9d!e:d"<   dd#e!jv                  d$d8d%Z<d& Z=d' Z>d( Z?d) Z@d* ZAd+ ZBd, ZCd- ZDd. ZEd/ ZFd0 ZGd1 ZHd2 ZId3 ZJd9d4Z%eKd5k(  r e
j                   e%              yy):a  
Phase C1 tests: SIGTERM, DryRunBroker, broker connect retry, account balance.

14 tests:
  SIGTERM (3):
    1. signal handler sets stop_event -> graceful exit
    2. stop during iteration finishes the tick + saves
    3. KeyboardInterrupt path returns 130

  DryRunBroker (5):
    4. delegates get_account_balance to wrapped
    5. delegates positions_get to wrapped
    6. intercepts place_market_bracket (no-op + synthetic IDs)
    7. intercepts close_position (no-op success)
    8. intercepts modify_stop (no-op success)

  Connect retry (2):
    9. succeeds on 2nd attempt
    10. fails after max_attempts

  Account balance (3):
    11. PAPER uses dry_run_balance (no broker)
    12. LIVE uses broker.get_account_balance
    13. LIVE broker failure falls back to dry_run_balance

  Logging (1):
    14. dry-run write events written to brain_log

Run:
    cd ~/apex_v16
    python -m tests.test_orchestrator_phase_c1
    )annotationsN)Path)Optional)
BrokerBaseCancelResultOrderResultPosition)DryRunBroker)RuntimeConfigRunModeAccountKind)EntryDecision)_connect_with_retry)Orchestrator)SessionState
StateStorec                     t        d|         y )Nz  ok  )print)labels    7/home/work/apex_v16/tests/test_orchestrator_phase_c1.py_okr   7   s    	F5'
    c                      e Zd ZddZddZy)FakeAINc                *   K   ddl m}  |d d      S wNr   )
AIResponseunknown)text
error_kindbrain.ai_clientr   )selfprompttemperature
max_tokensr   s        r   askz
FakeAI.ask@        .t	::   c                *   K   ddl m}  |d d      S wr   r!   )r#   r$   r&   wherer   s        r   ask_for_decisionzFakeAI.ask_for_decisionC   r(   r)   )g?N)iX  N)__name__
__module____qualname__r'   r,    r   r   r   r   ?   s    ;;r   r   c                      e Zd Zd Zd Zy)	JsonlSinkc                    g | _         y N)eventsr#   s    r   __init__zJsonlSink.__init__I   s	    r   c                B    | j                   j                  d|i|       y )Nevent)r5   appendr#   r9   fieldss      r   writezJsonlSink.writeK   s    GU5f56r   N)r-   r.   r/   r7   r=   r0   r   r   r2   r2   H   s    7r   r2   c                  *    e Zd Zd Zd Zd Zd Zd Zy)
FakeLoggerc                    dd l }t               | _        t               | _        t               | _        |j                  d      | _        y )Nr   ztest.c1)loggingr2   	brain_logsession_log	error_log	getLoggersystem)r#   rA   s     r   r7   zFakeLogger.__init__P   s3    "$;"''	2r   c                >     | j                   j                  |fi | y r4   )rC   r=   r;   s      r   log_session_eventzFakeLogger.log_session_eventV   s    u//r   c                B     | j                   j                  d||d| y )N)r+   error)rJ   )rD   r=   )r#   r+   rJ   extras       r   	log_errorzFakeLogger.log_errorX   s     HEH%Hr   c                <     | j                   j                  di | y )N)trade_openedrB   r=   r#   r<   s     r   log_trade_openedzFakeLogger.log_trade_openedZ       6v6r   c                <     | j                   j                  di | y )N)trade_closedrO   rP   s     r   log_trade_closedzFakeLogger.log_trade_closed\   rR   r   N)r-   r.   r/   r7   rH   rL   rQ   rU   r0   r   r   r?   r?   O   s    30I77r   r?   c                      e Zd Zd Zy)FakeProviderc                :   K   t        j                  g d      S w)Nopenhighlowclosevolumecolumns)pd	DataFramer#   symbol	timeframens       r   get_barszFakeProvider.get_barsa   s     ||$NOOs   N)r-   r.   r/   rg   r0   r   r   rW   rW   `   s    Pr   rW   c                      e Zd Zd Zd Zy)_MemoryStorec                    d| _         y Nr   savesr6   s    r   r7   z_MemoryStore.__init__f   s	    
r   c                .    | xj                   dz  c_         y )N   rl   )r#   states     r   savez_MemoryStore.saveh   s    

a
r   N)r-   r.   r/   r7   rq   r0   r   r   ri   ri   e   s    r   ri   c                      e Zd ZdZdZdd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)_FullFakeBrokerz6Concrete BrokerBase with all abstract methods stubbed.
FakeBrokerc                <    g | _         || _        d| _        d| _        y )NF)calls_balancefail_balance	connected)r#   balances     r   r7   z_FullFakeBroker.__init__o   s    -/
!r   c                T   K   | j                   j                  di f       d| _        yw)NconnectTrv   r:   ry   r6   s    r   r|   z_FullFakeBroker.connectu   s&     

9b/*   &(c                T   K   | j                   j                  di f       d| _        y w)N
disconnectFr}   r6   s    r   r   z_FullFakeBroker.disconnecty   s$     

<,-r~   c                "   K   | j                   S wr4   )ry   r6   s    r   is_connectedz_FullFakeBroker.is_connected|   s     ~~s   c                J   K   | j                   j                  dd|if       yw)Nget_last_pricerd        @rv   r:   r#   rd   s     r   r   z_FullFakeBroker.get_last_price~   s&     

+h-?@A   !#Nc                L   K   | j                   j                  dd|if       g S w)Npositions_getrd   r   r   s     r   r   z_FullFakeBroker.positions_get   s'     

?Xv,>?@	   "$c                L   K   | j                   j                  dd|if       g S w)Npending_ordersrd   r   r   s     r   r   z_FullFakeBroker.pending_orders   s(     

+h-?@A	r   c                P   K   | j                   j                  d|||df       g S w)Nrecent_trades)rd   sincelimitr   )r#   rd   r   r   s       r   r   z_FullFakeBroker.recent_trades   s2     

?uu-
  	 	s   $&c           	     t   K   | j                   j                  d|||||df       t        dd||ddd      S w)	Nplace_market_bracketrd   	direction	contractssl_pricetp_priceTr   zREAL-E1zREAL-S1zREAL-T1)successentry_pricer   r   entry_idstop_id	target_idrv   r:   r   )r#   rd   r   r   r   r   kws          r   r   z$_FullFakeBroker.place_market_bracket   sR     

199 h4
  	 4V$,x$-yIW 	Ws   68c                l   K   | j                   j                  d||||df       t        d|dd      S w)Nplace_stop_order)rd   sider   
stop_priceTREAL-S2)r   r   r   r   r   )r#   rd   r   r   r   s        r   r   z _FullFakeBroker.place_stop_order   sI     

-d$0
  	 4*#,yB 	B   24c                l   K   | j                   j                  d||||df       t        d|dd      S w)Nplace_limit_order)rd   r   r   limit_priceTREAL-T2)r   r   r   r   r   )r#   rd   r   r   r   s        r   r   z!_FullFakeBroker.place_limit_order   sI     

.d&1
  	 4+%.D 	Dr   c                v   K   | j                   j                  d||df       t        dt        |            S w)Ncancel_order)rd   order_idT)r   r   )rv   r:   r   str)r#   rd   r   s      r   r   z_FullFakeBroker.cancel_order   s3     

>f(+STUD3x=AAs   79c                J   K   | j                   j                  dd|if       yw)Ncancel_all_for_symbolrd   r   r   r   s     r   r   z%_FullFakeBroker.cancel_all_for_symbol   s&     

2Xv4FGHr   c                b   K   | j                   j                  d||df       t        d      S w)Nclose_position)rd   r   T)r   r   )r#   rd   r   s      r   r   z_FullFakeBroker.close_position   s.     

+Y-WXY4((s   -/c	                x   K   | j                   j                  d||||||||df       t        dddd||      S w)N partial_close_via_opposite_order)rd   r   contracts_to_closeresidual_contractsnew_sl_pricenew_tp_priceold_stop
old_targetTz
REAL-CLOSEr   r   )r   r   r   r   r   r   r   )	r#   rd   r   r   r   r   r   old_stop_order_idold_target_order_ids	            r   r   z0_FullFakeBroker.partial_close_via_opposite_order   s[      	

=9"4"4(,)9L@
  	 <i!L
 	
s   8:c                f   K   | j                   j                  d|||df       t        d|      S w)Nmodify_stop)rd   r   r   T)r   r   r   )r#   rd   r   r   s       r   r   z_FullFakeBroker.modify_stop   s:     

=(L+
  	 4,??s   /1c                   K   | j                   j                  di f       | j                  rt        d      | j                  S w)Nget_account_balancezbalance fetch failed)rv   r:   rx   RuntimeErrorrw   r6   s    r   r   z#_FullFakeBroker.get_account_balance   s=     

0"56566}}s   AAc                |   K   | j                   j                  d|||df       t        j                  g d      S w)N
fetch_bars)rd   re   rf   rY   r_   )rv   r:   ra   rb   rc   s       r   r   z_FullFakeBroker.fetch_bars   s=     

<91*
  	 ||$NOOs   :<)g     j@)rz   floatr4   )NN2   )r-   r.   r/   __doc__namer7   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r0   r   r   rs   rs   l   sj    @D
WBDB)
@

Pr   rs   c                     t        t        j                  t        j                        }dg|_        d|_        d|_        d|_        d|_	        | j                         D ]  \  }}t        |||        |S )N)modeaccountMESr   g        )r   r   PAPERr   
INELIGIBLEasset_filterloop_sleep_secondsscan_loop_phase_offset_secondsmanage_loop_interval_seconds!maintenance_loop_interval_secondsitemssetattr)overcfgkvs       r   make_configr      sl    
W]]K4J4J
KCwCC),C&'(C$,-C)

 1QJr   )datetimetimezonei           )tzinfo_dtFIXED_DAY_UTCro   )brokermax_iterationsr   c                    t               }||_        t               }t               }t	        |t               t               |t               |i | d |
      }||fS )Nc                     t         S r4   )r   r0   r   r   <lambda>zmake_orch.<locals>.<lambda>   s     r   )
config	ai_clientmarket_data_providerrp   storeloggerbrain_dispatchr   now_utc_providerr   )r   r   r   r?   r   r   rW   ri   )r   r   r   r   rp   r   orchs          r   	make_orchr      sT    
-CCHNE\Ffh)^<>&&.%D <r   c                 ~   t               \  } }| j                  }|j                  } |       }| }|sddt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}x}}| j                          | j                  }|j                  } |       }|sddt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}t        d       y)z@orchestrator.stop() sets the internal _stop_event used by run().zfassert not %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s._stop_event
}.is_set
}()
}r   )py0py2py4py6Nzbassert %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s._stop_event
}.is_set
}()
}z?stop(): _stop_event set, run() will exit at next sleep boundary)r   _stop_eventis_set@py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationstopr   )r   _@py_assert1@py_assert3@py_assert5@py_assert7@py_format8@py_format7s           r   #test_signal_handler_sets_stop_eventr     s   kGD!(&&(&(((((((((((t(((t((((((&((((((((((IIK$""$"$$$$$$$$4$$$4$$$$$$"$$$$$$$$$$IJr   c                    d } 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  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
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  }t        j                  d      dz   d|iz  }	t        t        j                  |	            d
x}x}x}}t        d       y
)zBrun() finishes the current tick + persists state before returning.c                    K   t        d      \  } fd}t        j                  j                          |              d {    S 7 w)Nd   r   c                 l   K   t        j                  d       d {     j                          y 7 w)Ng?)asynciosleepr   )r   s   r   stopperzTtest_stop_during_iteration_finishes_tick_then_saves.<locals>.runner.<locals>.stopper  s'     --%%%IIK &s   424)r   r  gatherrun)r   r  r   s     @r   runnerzCtest_stop_during_iteration_finishes_tick_then_saves.<locals>.runner   sB     3/a	 nnTXXZ333 	4s   AAAAro   )>=)z2%(py2)s
{%(py2)s = %(py0)s._iteration
} >= %(py5)sr   r   r   py5z$must complete at least one iterationz
>assert %(py7)spy7N)zH%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.store
}.saves
} >= %(py7)sr   r   r   r  zmust save at least oncez
>assert %(py9)spy9z1stop(): tick finishes + save executes before exit)r  r  
_iterationr   _call_reprcomparer   r   r   r   _format_assertmsgr   r   r   rm   r   )
r  r   r   @py_assert4r   @py_format6r  @py_assert6r  @py_format10s
             r   3test_stop_during_iteration_finishes_tick_then_savesr     s-    ;;vx D??GaG?aGGG?aGGGGGG4GGG4GGG?GGGaGGG!GGGGGGGG::;:;q;q ;;;q;;;;;;4;;;4;;;:;;;;;;q;;;";;;;;;;;;<r   c                    d } t        j                   |              }d}||k(  }|st        j                  d|fd||f      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}}t        d       y
)z7Synthetic KeyboardInterrupt in a loop -> exit code 130.c                 t   K   t        d      \  } }d }|| _        | j                          d {   }|S 7 w)Nr  r	  c                    K   t         wr4   )KeyboardInterruptr0   r   r   _ki_loopzJtest_keyboard_interrupt_path_returns_130.<locals>.runner.<locals>._ki_loop  s     ##s   	)r   
_scan_loopr  )r   r   r#  rcs       r   r  z8test_keyboard_interrupt_path_returns_130.<locals>.runner  s8     3/a	$"88:	 s   -868   ==z%(py0)s == %(py3)sr%  r   py3z,KeyboardInterrupt path must return 130, got z
>assert %(py5)sr  Nz5KeyboardInterrupt: orchestrator returns exit code 130)r  r  r   r  r   r   r   r   r  r   r   r   )r  r%  @py_assert2r   @py_format4r  s         r   (test_keyboard_interrupt_path_returns_130r.    s     
VX	BI29III2IIIIII2III2IIIIIIDRDIIIIIII?@r   c                 x   t        d      } 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                  |      dz  }dd|iz  }t        t        j                  |            d x}}d	 | j                  D        }t        |      }|st        j                  d
      dz   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 )Ng    @rz   r'  r)  balr*  assert %(py5)sr  c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr0   .0cs     r   	<genexpr>zDtest_dry_run_broker_delegates_get_account_balance.<locals>.<genexpr>&  s     Aqt,,A   zmust reach the wrapped brokerz.
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   r   r   z=DryRunBroker.get_account_balance: delegates to wrapped broker)rs   r
   r  r  r   r   r  r   r   r   r   r   r   rv   r9  r  r   )	realdryr1  r,  r   r-  r  r   @py_format5s	            r   1test_dry_run_broker_delegates_get_account_balancer>  !  s>   8,D
t
C
++c--/
0C3(?3(33(AdjjA (3AA (A ('''( (!'( (''  ( ('i  ( ('i B ( ('i B ( ( (''( (GHr   c                    t               } t        |       }t        j                  |j	                  d             d | 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 )Nr   c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr0   r4  s     r   r7  z>test_dry_run_broker_delegates_positions_get.<locals>.<genexpr>/  s     ;1qt&;r8  ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r9  r:  z7DryRunBroker.positions_get: delegates to wrapped broker)rs   r
   r  r  r   rv   r9  r   r   r   r   r   r   r   r   )r;  r<  r   r   r=  s        r   +test_dry_run_broker_delegates_positions_getrB  +  s    D
t
CKK!!%();

;;3;;;;;;;;;3;;;3;;;;;;;;;;;;;;ABr   c            	        t               } t               }t        | |      }t        j                  |j                  ddddd            }|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}}g }|j                  }|}	|r$|j                  }
|
j                   }d} ||      }|}	|	stddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }|j#                  |       |rddt        j                         v st        j                  |      rt        j                  |      ndt        j                  
      t        j                        t        j                        t        j                        dz  }|j#                  |       t        j$                  |d      i z  }t        j&                  |j                        dz   d|iz  }t        t        j                  |            dx}	x}x}x}
x}x}}d | j(                  D        }t+        |      }| }|st        j&                  d      dz   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}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) zLplace_market_bracket on dry returns synthetic IDs and DOES NOT call wrapped.r   r   BUY        @     @r   Tisz/%(py2)s
{%(py2)s = %(py0)s.success
} is %(py5)sresr  assert %(py7)sr  NzDRY-place-E-z%%(py4)s
{%(py4)s = %(py2)s.entry_id
})r   r   zh%(py14)s
{%(py14)s = %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s.entry_id
}.startswith
}(%(py12)s)
})r   py8py10py12py14r   z
>assert %(py17)spy17c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr0   r4  s     r   r7  zFtest_dry_run_broker_intercepts_place_market_bracket.<locals>.<genexpr>>  s     Fa1Q411Fr8  z/wrapped broker must NOT be called for write opsz2
>assert not %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r9  r:  c              3  ,   K   | ]  }|d    dk(    yw)r9   dry_place_market_bracketNr0   )r5  es     r   r7  zFtest_dry_run_broker_intercepts_place_market_bracket.<locals>.<genexpr>A  s     YAqz77Yr8  rA  zODryRunBroker.place_market_bracket: intercepted, synthetic DRY- IDs, log emitted)rs   r?   r
   r  r  r   r   r   r  r   r   r   r   r   r   r   
startswithr:   _format_boolopr  rv   r9  rB   r5   r   )r;  r   r<  rL  r   r  r   r  r  @py_assert0r  @py_assert9@py_assert11@py_assert13r=  @py_format15@py_format16@py_format18r  s                      r   3test_dry_run_broker_intercepts_place_market_bracketr`  3  s   D\F
tF
+C
++c..& /  C ;;$;$;$33;$Q3<<Q<Q<CLLQL33QNQ3NCQCQQQQQQ3QQQ3QQQ<QQQQ<QQQQQCQQQCQQQLQQQ3QQQNQQQCQQQQQQQQQS\\QQQQQQQQF4::F :sFF :FF :F :(9(99: :396: :!9!9  : :09	  : :09	 G : :09	 G : : :&9&9: : ZAQAQAXAXYY3YYYYYYYYY3YYY3YYYYYYYYYYYYYYYZr   c                    t               } t        |       }t        j                  |j	                  d            }|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                  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}x}}t!        d       y )Nr   TrI  rK  rL  r  rM  r  c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr0   r4  s     r   r7  z@test_dry_run_broker_intercepts_close_position.<locals>.<genexpr>J  s     @1Q4++@r8  0assert not %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r9  r:  z=DryRunBroker.close_position: intercepted (wrapped NOT called))rs   r
   r  r  r   r   r   r  r   r   r   r   r   r   rv   r9  r   	r;  r<  rL  r   r  r   r  r  r  s	            r   -test_dry_run_broker_intercepts_close_positionre  E  s   D
t
C
++c((/
0C;;$;$;$33;$@TZZ@@s@@@@@@@@@@@@s@@@s@@@@@@@@@@@@@@GHr   c                 ,   t               } t        |       }t        j                  |j	                  ddd            }|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                  }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}}d | 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}x}}t#        d       y )Nr   S1     @)r   TrI  rK  rL  r  rM  r  r'  )z0%(py2)s
{%(py2)s = %(py0)s.sl_price
} == %(py5)sc              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr0   r4  s     r   r7  z=test_dry_run_broker_intercepts_modify_stop.<locals>.<genexpr>T  s     =Q1Q4=(=r8  rc  r9  r:  z@DryRunBroker.modify_stop: intercepted, returns synthetic success)rs   r
   r  r  r   r   r   r  r   r   r   r   r   r   r   rv   r9  r   rd  s	            r   *test_dry_run_broker_intercepts_modify_stoprj  N  s   D
t
C
++cooeToG
HC;;$;$;$33;$<<!6!<6!!!!<6!!!!!!3!!!3!!!<!!!6!!!!!!!=$**==s============s===s==============JKr   c                 n    G d d      }  |        }t               }t        j                  t        ||dd            }d}||u }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }dd|iz  }t        t	        j                  |            dx}}|j                  }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}	}t        d       y)z9First attempt returns False, second True -> overall True.c                      e Zd Zd Zd Zy)?test_connect_with_retry_succeeds_on_2nd_attempt.<locals>._Flakyc                    d| _         y rk   attemptsr6   s    r   r7   zHtest_connect_with_retry_succeeds_on_2nd_attempt.<locals>._Flaky.__init___  	    DMr   c                R   K   | xj                   dz  c_         | j                   dk\  S w)Nro   rF  ro  r6   s    r   r|   zGtest_connect_with_retry_succeeds_on_2nd_attempt.<locals>._Flaky.connecta  s#     MMQM==A%%s   %'Nr-   r.   r/   r7   r|   r0   r   r   _Flakyrm  ^  s    		&r   rt     r   r   r   r   max_attemptsdelays_secondsTrI  z%(py0)s is %(py3)sokr*  r2  r  NrF  r'  z0%(py2)s
{%(py2)s = %(py0)s.attempts
} == %(py5)sr   r  rM  r  z,_connect_with_retry: succeeds on 2nd attemptr?   r  r  r   r   r  r   r   r   r   r   r   rp  r   )rt  r   r   r{  r,  r   r-  r  r  r   r  s              r   /test_connect_with_retry_succeeds_on_2nd_attemptr~  \  s   & & XF\F	(vAi 
B 2:222??a?a?a66?a67r   c                 n    G d d      }  |        }t               }t        j                  t        ||dd            }d}||u }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }dd|iz  }t        t	        j                  |            d x}}|j                  }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}	}t        d       y )Nc                      e Zd Zd Zd Zy)Atest_connect_with_retry_fails_after_max_attempts.<locals>._Alwaysc                    d| _         y rk   ro  r6   s    r   r7   zJtest_connect_with_retry_fails_after_max_attempts.<locals>._Always.__init__p  rq  r   c                J   K   | xj                   dz  c_         t        d      w)Nro   znetwork down)rp  r   r6   s    r   r|   zItest_connect_with_retry_fails_after_max_attempts.<locals>._Always.connectr  s     MMQM~..r   Nrs  r0   r   r   _Alwaysr  o  s    		/r   r  ru  rv  rw  FrI  rz  r{  r*  r2  r  r'  r|  r   r  rM  r  z:_connect_with_retry: fails after 3 attempts, returns Falser}  )r  r   r   r{  r,  r   r-  r  r  r   r  s              r   0test_connect_with_retry_fails_after_max_attemptsr  n  s   / / YF\F	(vAi 
B 2;222??a?a?a66?aDEr   c                    t        d      } t               }t        | t               t	               |t               t               i d d	      }t        j                  |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 )Ng    O@dry_run_balancero   	r   r   r   rp   r   r   r   r   r   r'  zW%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s._resolve_account_balance
}()
} == %(py7)sr   r  assert %(py9)sr  zJPAPER (no broker): _resolve_account_balance returns config.dry_run_balance)r   r   r   r   rW   ri   r?   r  r  _refresh_account_balance_resolve_account_balancer   r  r   r   r   r   r   r   r   )	r   rp   r   r   r   r  r  r  r  s	            r   7test_resolve_account_balance_paper_uses_dry_run_balancer    s    
h
/CNEfh)^<>*,$D KK--/0((6(*6h6*h6666*h66666646664666(666*666h6666666TUr   c                     t        d      } t        j                  | _        t	               }t        d      }t        | t               t               |t               t               i |d	      }t        j                  |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 )N     j@r  g    `f@r0  ro   r  r'  r  r   r  r  r  zFLIVE: _refresh -> broker.get_account_balance, _resolve uses real value)r   r   LIVEr   r   rs   r   r   rW   ri   r?   r  r  r  r  r   r  r   r   r   r   r   r   r   
r   rp   r   r   r   r   r  r  r  r  s
             r   -test_resolve_account_balance_live_uses_brokerr    s    
i
0C||CHNEX.Ffh)^<>*,&D KK--/0((6(*6h6*h6666*h66666646664666(666*666h6666666PQr   c                 
   t        d      } t        j                  | _        t	               }t               }d|_        t        | t               t               |t               t               i |d	      }t        j                  |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}}t1        d       y )Nr  r  Tro   r  r'  r  r   r  r  r  z?LIVE: broker balance fetch fails -> fallback to dry_run_balance)r   r   r  r   r   rs   rx   r   r   rW   ri   r?   r  r  r  r  r   r  r   r   r   r   r   r   r   r  s
             r   4test_resolve_account_balance_live_failure_falls_backr    s    
i
0C||CHNEFFfh)^<>*,&D KK--/0((7(*7i7*i7777*i77777747774777(777*777i7777777IJr   c            	     r   t               } t               }t        | |      }t        j                  |j                  ddddd             t        j                  |j                  ddd             t        j                  |j                  d             |j                  j                  D cg c]  }|d	   	 }}d
D ]  }||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                   d|       dz   d|iz  }t#        t        j$                  |            d } t'        d       y c c}w )NrD  r   rE  ro   rG  rH  rg  rh  r9   )rU  dry_modify_stopdry_close_position)in)z%(py0)s in %(py2)sexpectedr5   )r   r   zmissing event: z
>assert %(py4)sr   z@DryRunBroker: 3 write methods log structured events to brain_log)rs   r?   r
   r  r  r   r   r   rB   r5   r   r  r   r   r   r   r  r   r   r   )	r;  r   r<  rV  r5   r  r   @py_format3r=  s	            r   %test_dry_run_logs_events_to_brain_logr    s.   D\F
tF
+CKK((q&&IJKKtV45KK""5)*"("2"2"9"9:Qaj:F: @
 6!???x6??????x???x??????6???6????_XJ#???????@ JK ;s   ,F4c                 H   t        d       t                t                t                t	                t                t                t                t                t                t                t                t                t                t                t        d       y)Nztest_orchestrator_phase_c1.pyzALL 14 TESTS PASSEDr   )r   r  r  r.  r>  rB  r`  re  rj  r~  r  r  r  r  r  r0   r   r   mainr    sk    	
)*')79,.57/17913.03546;=138:)+	
 r   __main__)r   r   returnNone)r  r   )r  tuple)r  int)Mr   
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r  systempfilepathlibr   typingr   pandasra   pathinsertr   __file__resolveparentbroker.broker_baser   r   r   r	   broker.dry_run_brokerr
   core.configr   r   r   core.contractsr   r  r   orchestratorr   persistence.state_storer   r   r   r   r2   r?   rW   ri   rs   r   r   r   r   _tzutcr   __annotations__r   r   r  r  r.  r>  rB  r`  re  rj  r~  r  r  r  r  r  r-   exitr0   r   r   <module>r     sl  B #    
     3tH~--/66==> ? N N . ; ; ( $ % <; ;7 77 7"P P
 ]Pj ]PH	 6q"b!Qsww?s ? QW]] (K= A(IC[$IL8$F*VR"K.L*( zCHHTV r   