
    9j2!                        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ZddlmZ ddlmZmZmZmZmZ ej,                  j/                  ej,                  j1                  e      dddd      ZdZdZ ej:                  d	
      d        ZddZd Z ddddddZ!d Z" G d d      Z# G d d      Z$ G d d      Z% G d d      Z&y)u  
TDD tests for strategy_mlp_scores.generate_signals.

Core guarantee under test (linear degeneracy): an MLP constructed to be an
(arbitrarily good) linear approximation of the existing perceptron score must
reproduce the existing strategy's behaviour — near-perfect score correlation
and identical entry/exit bars when thresholds are scaled by the same factor.
This pins the new module's crossunder/trailing/position logic to the old one.
    N)FEATURE_COLSFEATURE_WEIGHT_PARAMS_score_to_signalsgenerate_signalssave_mlp_artifactz..datamlpzCOINBASE_BTCUSD, 360.csvgMbP?module)scopec                     t        j                  t              } | j                  j                  j                         j                  j                         | _        t        j                  | d   d      j                  j                  d       | d<   | j                  dd      | d<   | j                  dd      | d<   | j                  d	      j                  d
      S )NtimeT)utcqqq_spy_roc_sign        	sopr_normfear_greed_normcvd_normi  )drop)pdread_csvDATA_CSVcolumnsstrlowerstripto_datetimedttz_localizegettailreset_index)dfs    A/Users/jameslopez/projects/TradingBot25/tests/test_mlp_signals.pydf_realr$       s    	X	B%%'++113BJ6
588DDTJBvJ ff/5B{OVV-s3BzN774=$$$$//    c                 |   ddl }t        |j                        }t        j                  j                  |       }|j                  dd|      }d|t        j                  |      dk  <   t        t        |j                  |            }t        j                  t        D cg c]  }||v r||    c}      }||fS c c}w )uU  Random nonzero weight per feature for the 49 features shared with the perceptron.

    Uses only the params that the perceptron strategy actually reads (config.WEIGHT_COLS).
    bb_pct_b_norm (col 49) is MLP-only and excluded so both strategies normalise by
    the same denominator — keeping the linear-degeneracy equivalence intact.
    r   Nid   )sizeg      @)configlenWEIGHT_COLSnprandomdefault_rnguniformabsdictziparrayr   )seedr)   nrngww_paramsparam
artifact_ws           r#   _perceptron_weightsr;   .   s     FA
))


%CD#A&AAbffQi#oC**A./H**EH 	* J
 xs   B9c                    ddl }t        t              D cg c]%  \  }}|t        |j                        v r	t
        |   ' }}}t        |      }t        |      }||k(  }|sHt        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	t        j                  d	t        |       d
|       dz   d|	iz  }
t        t        j                  |
            dx}}|t!        j"                  t!        j$                  |            z  }t!        j&                  d|f      }t(        |z  |dddf<   t!        j&                  d      }t!        j*                  t,        t(        z  dgg      }t!        j&                  d      }t/        | dz        }t1        |||f||fgdd|       |S c c}}w )u  [N, 2, 1] MLP that linearises to DELTA * perceptron score.

    Uses the same N features as the perceptron (config.WEIGHT_COLS) so normalisation
    denominators match.  bb_pct_b_norm (col 49) is excluded — the artifact saves
    its own feature_cols list so generate_signals uses the right subset.

    Hidden unit 0 = tanh(EPS * x.w_hat) ~ EPS * s  (w_hat = w / sum|w|, s in [-1,1])
    Output       = tanh((DELTA/EPS) * h0) ~ DELTA * s
    => mlp_score ~ DELTA * 1000 * s = DELTA * perceptron_score
    r   N==)z0%(py0)s == %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}r5   r*   r7   )py0py2py3py5zweight vector length z != feature subset length z
>assert %(py7)spy7   r      zmlp_weights_DEGEN_6H.jsonTEST6H)asset	timeframefeature_cols)r)   	enumerater   setr+   r   r*   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationr,   sumr0   zerosEPSr3   DELTAr   r   )tmp_pathr7   r)   ip	feat_colsr5   @py_assert4@py_assert1@py_format6@py_format8w_hatW1b1W2b2paths                    r#   _degenerate_artifactrh   C   s    -67L-M 2-MTQV//00 a-MI 2IAAU1;UUU1UUUUUU1UUU1UUUUUUUUUUUUUUUAUUUAUUUUUU/Ax7QRSQTUUUUUUUrvvay!!E	1a&	BU{Bq!tH	!B	ECK%&	'B	!Bx556Ddb"XBx0$#,.K2s   *I3      Y@g     a@g      >@      ?F)!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_confirmationc                  X    t        t              } dD ]  }t        |   t        z  | |<    | S )N)rk   rl   rm   )r1   
THRESHOLDSrY   )outks     r#   _scaled_thresholdsrt   h   s3    
z
C? A&A? Jr%   c                       e Zd Zd Zd Zy)TestLinearDegeneracyc                    t               \  }}t        ||      }t        j                  |j	                         fi i |t
        }t        |j	                         fd|it               }t        j                  |d   |d         d   }d}	||	kD  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dz  }d	d
|iz  }t        t        j                   |            d x}
}	t        j"                  j%                  |d   j&                  |d   j&                         t        j"                  j%                  |d   j&                  |d   j&                         t        j"                  j%                  |d   j&                  |d   j&                         y )Nmlp_weights_fileactivation_score)r   rE   g!?)>)z%(py0)s > %(py3)scorr)r?   rA   zassert %(py5)srB   execute_entryexecute_exitposition)r;   rh   
perceptronr   copyrq   rt   r,   corrcoefrM   rN   rO   rP   rQ   rR   rT   rU   testingassert_array_equalvalues)selfrZ   r$   r7   r8   artifactoldnewr{   @py_assert2r_   @py_format4r`   s                r#   +test_score_correlation_and_identical_tradesz@TestLinearDegeneracy.test_score_correlation_and_identical_tradesr   s[   )+8'!4))',,.W<Vx<V:<VWw||~aaL^L`a{{312C8J4KLTRththtth


%% ''_)=)D)D	F


%%&&N(;(B(B	D


%%c*o&<&<c*o>T>TUr%   c                 J   t        d      \  }}t        ||      }ddi}t        j                  |j	                         fi i |t
        |}t        |j	                         fd|ii t               |}t        j                  j                  |d   j                  |d   j                         t        j                  j                  |d   j                  |d   j                         t        j                  j                  |d   j                  |d   j                         y )	N   )r4   i_trailing_stop_thresholdg      $@rx   r~   r|   r}   )r;   rh   r   r   r   rq   rt   r,   r   r   r   )	r   rZ   r$   r7   r8   r   trailr   r   s	            r#   #test_trailing_stop_path_equivalencez8TestLinearDegeneracy.test_trailing_stop_path_equivalence   s
   )r28'!4,d3))',,.`<_x<_:<_Y^<_`w||~ D D!B$6$8!BE!BD 	

%%c*o&<&<c*o>T>TU


%% ''_)=)D)D	F


%%&&N(;(B(B	Dr%   N)__name__
__module____qualname__r   r    r%   r#   rv   rv   q   s    V Dr%   rv   c                       e Zd Zd Zd Zy)TestParamValidationc                     t        j                  t        d      5  t        |j	                         fi t
         d d d        y # 1 sw Y   y xY w)Nrx   match)pytestraises
ValueErrorr   r   rq   )r   r$   s     r#    test_missing_weights_file_raisesz4TestParamValidation.test_missing_weights_file_raises   s1    ]]:-?@W\\^:z: A@@s   AAc                    t        |dz        }t        j                  d      t        j                  d      ft        j                  d      t        j                  d      fg}t        ||g d       t	        j
                  t        d	      5  t        |j                         fd
|it         d d d        y # 1 sw Y   y xY w)Nzmlp_weights_BAD_6H.json)rD      rD   )rE   rD   rE   )abc)rJ   rJ   r   rx   )
r   r,   rW   r   r   r   r   r   r   rq   )r   rZ   r$   rg   layerss        r#   #test_mismatched_feature_cols_raisesz7TestParamValidation.test_mismatched_feature_cols_raises   s    877888F#RXXa[1BHHV4Dbhhqk3RS$_E]]:^<W\\^QdQjQ =<<s   !B88CN)r   r   r   r   r   r   r%   r#   r   r      s    ;Rr%   r   c                       e Zd Zd Zy)TestPineTimeGatec           	      v   t        j                  t        j                  g d      g dg dg dd      }ddddd	d
d}t        |j	                         |t        j                  t        |            |d   j                  t
        j                        |d   j                  t
        j                              }|d   }|j                  } |       }g 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                  } |       }g 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}}y )N)z2017-11-30 16:00z2017-12-01 00:002017-12-01 08:00z2017-12-01 16:00)      i@      I@r   r   )ri   g     @Y@g     Y@g     Y@)r   ry   closehighri   g      @g      rj   Fr   )rk   rl   rm   rn   ro   _pine_time_startr   r   r|   )FFFTr=   )zE%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.tolist
}()
} == %(py8)s)py1rA   rB   py8zassert %(py10)spy10r~   )r   r   r   rE   )r   	DataFramer   r   r   r,   rW   r*   to_numpyfloat64tolistrM   rN   rR   rT   rU   )r   r"   paramssignals@py_assert0r   r^   @py_assert7@py_assert6@py_format9@py_format11s              r#   0test_pre_start_crossunder_does_not_open_positionzATestPineTimeGate.test_pre_start_crossunder_does_not_open_position   s   \\NN $  !;10

 
 2705=C,/-2 2
 $GGIHHSWwK  ,vJ

+
 'O'..O.0O4OO04OOOOO04OOOO'OOO.OOO0OOO4OOOOOOOOz";"));)+;|;+|;;;;+|;;;";;;);;;+;;;|;;;;;;;;r%   N)r   r   r   r   r   r%   r#   r   r      s    <r%   r   c                       e Zd Zd Zd Zy)TestFeatureWeightParamsc           	         t        t              }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}t        t              }d	}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndd
t	        j
                         v st        j                  t              rt        j                  t              nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}d t        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        t              }t        |      }d}	||	k(  }
|
s[t        j                  d|
fd||	f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            d x}x}x}
}	y )N2   r=   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr*   r   )r?   r   rA   py6zassert %(py8)sr   7   r   c              3   >   K   | ]  }|j                  d         yw)i_w_N)
startswith).0r\   s     r#   	<genexpr>zETestFeatureWeightParams.test_one_param_per_feature.<locals>.<genexpr>   s     G1FA1<<'1Fs   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}all)r?   r@   py4)zN%(py6)s
{%(py6)s = %(py0)s(%(py4)s
{%(py4)s = %(py1)s(%(py2)s)
})
} == %(py9)srL   )r?   r   r@   r   r   py9zassert %(py11)spy11)r*   r   rM   rN   rO   rP   rQ   rR   rT   rU   r   r   rL   )r   r   @py_assert5r^   @py_format7r   r_   @py_assert3@py_format5@py_assert8r   @py_format10@py_format12s                r#   test_one_param_per_featurez2TestFeatureWeightParams.test_one_param_per_feature   sP   
 ()/R/)R////)R//////s///s//////(///(///)///R///////< &B& B&&&& B&&&&&&s&&&s&&&&&&<&&&<&&& &&&B&&&&&&&G1FGGsGGGGGGGGGsGGGsGGGGGGGGGGGGGG,-4s-.4"4."4444."444444s444s44444434443444444,444,444-444.444"4444444r%   c                    dd l }|j                  }t        |      }|j                  }t        t              } ||      }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nd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}x}x}}y )Nr   zassert %(py13)s
{%(py13)s = %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.WEIGHT_COLS
})
}.issubset
}(%(py11)s
{%(py11)s = %(py8)s(%(py9)s)
})
}rL   r)   r   )	r?   r   rA   rB   rC   r   r   r   py13)r)   r+   rL   issubsetr   rO   rP   rM   rQ   rR   rT   rU   )r   r)   r   r^   r   @py_assert10@py_assert12@py_format14s           r#   !test_config_weight_cols_is_subsetz9TestFeatureWeightParams.test_config_weight_cols_is_subset   s    	%%Ks%&K&//K4I0JK/0JKKKKKKKKsKKKsKKKKKK6KKK6KKK%KKK&KKK/KKKKKKKKKKKKKKK4IKKK4IKKK0JKKKKKKKKKKKr%   N)r   r   r   r   r   r   r%   r#   r   r      s    5Lr%   r   )   )'__doc__builtinsrO   _pytest.assertion.rewrite	assertionrewriterM   osnumpyr,   pandasr   r   %strategies.strategy_activation_scoresstrategy_activation_scoresr   strategies.strategy_mlp_scoresr   r   r   r   r   rg   joindirname__file__r   rX   rY   fixturer$   r;   rh   rq   rt   rv   r   r   r   r   r%   r#   <module>r      s     	    :  77<<14Hbc  h
0  
0 *: */(-59$'%*
D DB
R 
R< <DL Lr%   