
    ;j                         d 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  e
j                  d      Zd Zd Zd Zd Zd	 Zy)
u  
RED→GREEN acceptance test for the trailing-stop time-gating parity fix.

Pine gates BOTH `strategy.close` calls (score-exit and trailing-stop) on
`timeCondition = time >= startDate and time <= endDate`. So a position that is
open when the window ends is held open to the chart end — Pine cannot close it
after `endDate`.

Python's `_apply_trailing_stop` previously fired the trailing stop regardless of
the time window, so a trade open across `endDate` would trail-out in OOS while
TV held it open (the 4H "TV#106 open trade" parity break).

Given/When/Then:
  Given a trade entered just before `endDate` whose price drops below the trail
        stop only on bars AFTER `endDate`,
  When  the signals are generated with a Pine time gate (`_pine_time_end`),
  Then  no exit (trail or score) fires after `endDate` — the position is held
        open, matching Pine.

A second case (no time gate) asserts the trailing stop still fires normally, so
the fix does not disable the trail inside the trading window.
    N)_score_to_signalsz
2026-02-28c                     t        j                  ddd      } t        j                  g dt              }t        j                  g dt              }t        j                  g dt              }t        j
                  | |||d      S )	Nz
2026-02-24   D)periodsfreq)
      (   r   r   r   r   r   dtype)2   r   <   r   d   F   r   r   )timeactivation_scoreclosehigh)pd
date_rangenparrayfloat	DataFrame)timesscorer   r   s       I/Users/jameslopez/projects/TradingBot25/tests/test_mlp_trail_time_gate.py_fixture_dfr   "   sj     MM,<EHH=UKE HH=UKE88<EJD<<E"'7 8 8    c            	          dddddddddS )	Ng      Y@g      I@g     g      ?Fg      4@   )!i_long_entry_activation_threshold i_long_exit_activation_threshold-i_long_exit_activation_confirmation_thresholdi_use_long_exit_confirmationi_use_long_entry_confirmationi_trailing_stop_thresholdi_exit_score_windowi_entry_score_window r+   r    r   _base_paramsr,   1   s&     .3,09A(+).%)  !	 	r    c           	         t               }t        j                  t        |      t        j                        }t        || ||d   j                  t        j                        |d   j                  t        j                              }|S )Nr   r   r   )r   r   zeroslenfloat64r   to_numpy)paramsdf
stoch_peakouts       r   _runr6   @   sk    	B#b'4J

FJ
72::.
6
"**-C
 Jr    c                     t               } t        j                  d      | d<   t        | d<   t	        |       }|d   j
                  d   }|sNt        j                  d      dz   dt        j                  |      iz  }t        t        j                  |            d	}|d
   t        kD  }|j                  |df   }|j                  } |       }| }|svt        j                  d      dz   t        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d	x}x}x}}|d   j
                  d   }d}	||	k(  }|st        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            d	x}x}}	y	)z?Given a Pine time gate, the trailing stop must NOT fire in OOS.z
2017-12-01_pine_time_start_pine_time_endexecute_entry   expected entry at idx2
>assert %(py1)spy1Nr   execute_exitu}   trailing stop fired after endDate — Python should hold the position open to match Pine's timeCondition-gated strategy.closezD
>assert not %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.any
}()
})r>   py3py5positionr"   ==z%(py1)s == %(py4)sr>   py4z(position should remain open past endDate
>assert %(py6)spy6)r,   r   	TimestampENDr6   iloc
@pytest_ar_format_assertmsg	_safereprAssertionError_format_explanationlocany_call_reprcompare)r2   r5   @py_assert0@py_format2	after_end@py_assert2@py_assert4@py_assert6@py_format7@py_assert3@py_format5s              r   6test_trail_does_not_fire_after_endDate_when_time_gatedr_   K   s   ^F!#l!;F"F
v,C $$Q'A'AA)AAAA'AAAAA Fc!Iwwy.01 155 57 77 7  	B   2    6    8      
 z?#TqT#q(TTT#qTTT#TTTqTTT*TTTTTTTTr    c                     t               } t        |       }|d   j                  d   }|sNt        j                  d      dz   dt        j
                  |      iz  }t        t        j                  |            d}|d   j                  d   }|sNt        j                  d	      dz   dt        j
                  |      iz  }t        t        j                  |            d}|d
   j                  d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}}y)zFSanity: without a time gate, the trailing stop fires normally at idx5.r:   r;   r<   r=   r>   Nr?      z5trailing stop should fire at idx5 without a time gaterB   rC   r   rD   rF   rG   z/position should be closed after the trail firesrI   rJ   )	r,   r6   rM   rN   rO   rP   rQ   rR   rU   )r2   r5   rV   rW   r]   rY   r^   r\   s           r   *test_trail_still_fires_when_not_time_gatedrb   _   s    ^F
v,C$$Q'A'AA)AAAA'AAAAA~##A&_&__(____&_____z?#[q[#q([[[#q[[[#[[[q[[[*[[[[[[[[r    )__doc__builtins@py_builtins_pytest.assertion.rewrite	assertionrewriterN   numpyr   pandasr   pyteststrategies.strategy_mlp_scoresr   rK   rL   r   r,   r6   r_   rb   r+   r    r   <module>rm      sJ   .      < bll< 8U(\r    