2026-08-21 10:01:21 +07:00
//+------------------------------------------------------------------+
//| AlgoForge_Engine2_UnitTest.mq5 |
//| Project : Algo Forge (refactor total) |
//| Sumber inspirasi: SniperGold SMC Pro+ (c) Waseem Shahrukh |
//| https://www.mql5.com/en/code/75466 |
//+------------------------------------------------------------------+
//| Unit test minimal Engine 2 (4 agen sinyal independen + agregator)|
//| Jalankan di Strategy Tester (XAUUSD, model "every tick"). |
//| Semua hasil dicetak di journal dengan prefix "AFTEST2". |
//| |
//| CEK YANG DIJALANKAN: |
//| T1 - validitas output tiap agen (buy/sell/bias/conf/dir) |
//| T2 - independensi: mengubah input agen X TIDAK mengubah output |
//| agen lain; determinisme (input sama -> output sama) |
//| T3 - closed-bar lock: semua bar yang dipakai sudah tertutup |
//| T4 - non-repaint: dalam bar yang sama, output identik |
//| T5 - validitas output agregator (dir/bias/score/levels) |
//| T6 - agregator dengan input sintetis (netral/buy/sell/campur) |
//+------------------------------------------------------------------+
# property copyright " Algo Forge - refactor SniperGold SMC Pro+ (Waseem Shahrukh, https://www.mql5.com/en/code/75466) "
# property version " 1.00 "
# property strict
# property description " Unit test Engine 2: 4 agen sinyal independen (N/C/E/P) + agregator. Jalankan di Strategy Tester; hasil di journal (prefix AFTEST2). "
# include <AlgoForge\AF_Engine2_Aggregator.mqh>
2026-08-22 23:31:22 +07:00
# include <AlgoForge\AF_Engine2_Setup.mqh>
2026-08-21 10:01:21 +07:00
input group " ===== ENGINE 2 UNIT TEST ===== "
2026-08-21 15:39:52 +07:00
// TF agen HARDCODED (AF_E2_TF_S1..S4 = H4/M30/M15/M5) - tanpa input manual
input ENUM_TIMEFRAMES InpTamper1 = PERIOD_H1 ; // Slot tamper N (uji independensi; beda dari base H4)
input ENUM_TIMEFRAMES InpTamper2 = PERIOD_M20 ; // Slot tamper C (beda dari base M30)
input ENUM_TIMEFRAMES InpTamper3 = PERIOD_M12 ; // Slot tamper E (beda dari base M15)
2026-08-21 15:44:49 +07:00
input ENUM_TIMEFRAMES InpTamper4 = PERIOD_M6 ; // Slot tamper P (beda dari base M3)
2026-08-21 10:01:21 +07:00
input int InpMaxBars = 600 ; // Kapasitas cache per TF
input bool InpVerbose = false ; // Log detail
AFEngine1MTF g_e1 ;
AFEngine2Signals g_eng2 ;
AFAgentNarrative g_agN ;
AFAgentContext g_agC ;
AFAgentEntry g_agE ;
AFAgentPriceAction g_agP ;
AFAggregator g_agg ;
int g_s [ 4 ] ; // slot N,C,E,P
int g_t [ 4 ] ; // slot tamper
long g_lastBar [ 4 ] ;
AFSignalOut g_out [ 4 ] ;
AFAggOut g_aggOut ;
int g_pass = 0 , g_fail = 0 ;
bool g_verbose = false ;
bool g_indepDone = false ;
bool g_repaintPending = false ;
//+------------------------------------------------------------------+
string AgentName ( int i )
{
switch ( i )
{
case 0 : return " Narrative " ;
case 1 : return " Context " ;
case 2 : return " Entry " ;
case 3 : return " PriceAction " ;
}
return " ? " ;
}
void Pass ( const string what ) { g_pass + + ; if ( g_verbose ) Print ( " AFTEST2 PASS: " + what ) ; }
void Fail ( const string what ) { g_fail + + ; Print ( " AFTEST2 FAIL: " + what ) ; }
bool SameSignal ( const AFSignalOut & a , const AFSignalOut & b )
{
if ( MathAbs ( a . buy - b . buy ) > 1e-12 ) return false ;
if ( MathAbs ( a . sell - b . sell ) > 1e-12 ) return false ;
if ( a . dir ! = b . dir ) return false ;
if ( a . reason ! = b . reason ) return false ;
return true ;
}
//+------------------------------------------------------------------+
//| T1 - validitas output agen |
//+------------------------------------------------------------------+
void CheckAgentOut ( int i )
{
AFSignalOut o = g_out [ i ] ;
bool ok = true ;
if ( o . buy < 0.0 | | o . buy > 1.0 | | o . sell < 0.0 | | o . sell > 1.0 ) ok = false ;
if ( o . bias < -1.0 -1e-9 | | o . bias > 1.0 + 1e-9 ) ok = false ;
if ( o . confidence < 0.0 | | o . confidence > 1.0 ) ok = false ;
if ( o . dir = = 1 & & o . bias < = AF_E2_DIR_TOL ) ok = false ;
if ( o . dir = = -1 & & o . bias > = - AF_E2_DIR_TOL ) ok = false ;
if ( o . dir = = 0 & & MathAbs ( o . bias ) > AF_E2_DIR_TOL ) ok = false ;
if ( o . name ! = AgentName ( i ) ) ok = false ;
if ( ok )
Pass ( " T1 " + AgentName ( i ) + " output valid (dir= " + IntegerToString ( o . dir )
+ " bias= " + DoubleToString ( o . bias , 2 ) + " conf= " + DoubleToString ( o . confidence , 2 ) + " ) " ) ;
else
Fail ( " T1 " + AgentName ( i ) + " output INVALID (buy= " + DoubleToString ( o . buy , 3 )
+ " sell= " + DoubleToString ( o . sell , 3 ) + " bias= " + DoubleToString ( o . bias , 3 )
+ " dir= " + IntegerToString ( o . dir ) + " ) " ) ;
}
//+------------------------------------------------------------------+
//| T5 - validitas output agregator |
//+------------------------------------------------------------------+
void CheckAggOut ( )
{
AFAggOut o = g_aggOut ;
bool ok = true ;
if ( o . buy < 0.0 | | o . buy > 1.0 | | o . sell < 0.0 | | o . sell > 1.0 ) ok = false ;
if ( MathAbs ( o . bias - ( o . buy - o . sell ) ) > 1e-9 ) ok = false ;
if ( MathAbs ( o . score - MathAbs ( o . bias ) ) > 1e-9 ) ok = false ;
if ( o . confidence < 0.0 | | o . confidence > 1.0 ) ok = false ;
if ( o . dir = = 1 & & ( o . bias < AF_AGG_BUY_TH | | o . buy < AF_AGG_MIN_SUP ) ) ok = false ;
if ( o . dir = = -1 & & ( o . bias > - AF_AGG_BUY_TH | | o . sell < AF_AGG_MIN_SUP ) ) ok = false ;
if ( o . dir ! = 0 )
{
if ( ! o . hasLevels | | o . entry < = 0.0 ) ok = false ;
if ( o . dir = = 1 & & ( o . sl > = o . entry | | o . tp < = o . entry ) ) ok = false ;
if ( o . dir = = -1 & & ( o . sl < = o . entry | | o . tp > = o . entry ) ) ok = false ;
}
if ( o . reason = = " " ) ok = false ;
if ( ok )
Pass ( " T5 agregator valid (dir= " + IntegerToString ( o . dir )
+ " bias= " + DoubleToString ( o . bias , 2 ) + " score= " + DoubleToString ( o . score , 2 )
+ " conf= " + DoubleToString ( o . confidence , 2 ) + " ) " ) ;
else
Fail ( " T5 agregator INVALID (dir= " + IntegerToString ( o . dir )
+ " buy= " + DoubleToString ( o . buy , 3 ) + " sell= " + DoubleToString ( o . sell , 3 ) + " ) " ) ;
}
//+------------------------------------------------------------------+
//| T2 - independensi & determinisme |
//+------------------------------------------------------------------+
bool CheckIndependence ( )
{
AFSignalOut base [ 4 ] ;
g_agN . Compute ( g_e1 , g_s [ 0 ] , base [ 0 ] ) ;
g_agC . Compute ( g_e1 , g_s [ 1 ] , base [ 1 ] ) ;
g_agE . Compute ( g_e1 , g_s [ 2 ] , base [ 2 ] ) ;
g_agP . Compute ( g_e1 , g_s [ 3 ] , base [ 3 ] ) ;
bool tamperReady = true ;
for ( int i = 0 ; i < 4 ; i + + )
if ( g_t [ i ] < 0 | | ! g_e1 . IsReady ( g_t [ i ] ) ) tamperReady = false ;
if ( ! tamperReady )
{
Print ( " AFTEST2 T2 SKIP: slot tamper belum siap (akan dicoba di bar berikutnya) " ) ;
return false ;
}
bool indepOK = true ;
for ( int t = 0 ; t < 4 ; t + + )
{
AFSignalOut alt [ 4 ] ;
g_agN . Compute ( g_e1 , ( t = = 0 ) ? g_t [ 0 ] : g_s [ 0 ] , alt [ 0 ] ) ;
g_agC . Compute ( g_e1 , ( t = = 1 ) ? g_t [ 1 ] : g_s [ 1 ] , alt [ 1 ] ) ;
g_agE . Compute ( g_e1 , ( t = = 2 ) ? g_t [ 2 ] : g_s [ 2 ] , alt [ 2 ] ) ;
g_agP . Compute ( g_e1 , ( t = = 3 ) ? g_t [ 3 ] : g_s [ 3 ] , alt [ 3 ] ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
if ( i = = t ) continue ; // agen yang diubah BOLEH berbeda
if ( ! SameSignal ( base [ i ] , alt [ i ] ) )
{
Fail ( " T2 independensi rusak: ganti input " + AgentName ( t ) + " mengubah " + AgentName ( i ) ) ;
indepOK = false ;
}
}
}
AFSignalOut chk [ 4 ] ;
g_agN . Compute ( g_e1 , g_s [ 0 ] , chk [ 0 ] ) ;
g_agC . Compute ( g_e1 , g_s [ 1 ] , chk [ 1 ] ) ;
g_agE . Compute ( g_e1 , g_s [ 2 ] , chk [ 2 ] ) ;
g_agP . Compute ( g_e1 , g_s [ 3 ] , chk [ 3 ] ) ;
bool det = true ;
for ( int i = 0 ; i < 4 ; i + + ) if ( ! SameSignal ( base [ i ] , chk [ i ] ) ) det = false ;
if ( det & & indepOK ) Pass ( " T2 independensi & determinisme OK " ) ;
if ( ! det ) Fail ( " T2 determinisme rusak (input sama -> output beda) " ) ; return true ;
}
//+------------------------------------------------------------------+
//| T4 - non-repaint (output identik dalam bar yang sama) |
//+------------------------------------------------------------------+
void CheckNonRepaint ( )
{
AFSignalOut chk [ 4 ] ;
g_agN . Compute ( g_e1 , g_s [ 0 ] , chk [ 0 ] ) ;
g_agC . Compute ( g_e1 , g_s [ 1 ] , chk [ 1 ] ) ;
g_agE . Compute ( g_e1 , g_s [ 2 ] , chk [ 2 ] ) ;
g_agP . Compute ( g_e1 , g_s [ 3 ] , chk [ 3 ] ) ;
bool ok = true ;
for ( int i = 0 ; i < 4 ; i + + ) if ( ! SameSignal ( g_out [ i ] , chk [ i ] ) ) ok = false ;
if ( ok ) Pass ( " T4 non-repaint: output identik dalam bar yang sama " ) ;
else Fail ( " T4 non-repaint dilanggar " ) ;
}
//+------------------------------------------------------------------+
//| T6 - agregator dengan input sintetis (logika murni) |
//+------------------------------------------------------------------+
void SyntheticAggTests ( )
{
AFSignalOut z , b , s ;
AF_SignalInit ( z , " Z " , " ? " ) ;
AF_SignalInit ( b , " B " , " ? " ) ;
b . buy = 0.9 ; b . sell = 0.1 ; b . bias = 0.8 ; b . confidence = 0.9 ; b . dir = 1 ;
AF_SignalInit ( s , " S " , " ? " ) ;
s . buy = 0.1 ; s . sell = 0.9 ; s . bias = -0.8 ; s . confidence = 0.9 ; s . dir = -1 ;
AFAggOut o ;
g_agg . Compute ( g_e1 , 0 , z , z , z , z , o ) ;
if ( o . dir = = 0 ) Pass ( " T6 agregator: semua netral -> WAIT " ) ;
else Fail ( " T6 agregator: semua netral harus WAIT " ) ;
g_agg . Compute ( g_e1 , 0 , b , b , b , b , o ) ;
if ( o . dir = = 1 & & o . buy > 0.5 ) Pass ( " T6 agregator: semua buy kuat -> BUY " ) ;
else Fail ( " T6 agregator: semua buy kuat harus BUY " ) ;
g_agg . Compute ( g_e1 , 0 , s , s , s , s , o ) ;
if ( o . dir = = -1 & & o . sell > 0.5 ) Pass ( " T6 agregator: semua sell kuat -> SELL " ) ;
else Fail ( " T6 agregator: semua sell kuat harus SELL " ) ;
g_agg . Compute ( g_e1 , 0 , b , z , z , z , o ) ;
if ( o . dir = = 1 ) Pass ( " T6 agregator: N buy kuat saja -> BUY (bobot N) " ) ;
else Fail ( " T6 agregator: N buy kuat harus BUY " ) ;
g_agg . Compute ( g_e1 , 0 , b , s , z , z , o ) ;
if ( o . dir = = 0 ) Pass ( " T6 agregator: N buy vs C sell seimbang -> WAIT " ) ;
else Fail ( " T6 agregator: N buy vs C sell seimbang harus WAIT " ) ;
}
2026-08-22 23:31:22 +07:00
//+------------------------------------------------------------------+
//| T7 - F3 Candidate Setup layer (sintetis, semantic inputs) |
//| Port test dari spec_tests_candidate_setup_runtime.py oracle: |
//| T7a : rantai lengkap -> CANDIDATE_SETUP (F3-T01) |
//| T7b : H4 conflict -> BLOCKED (F3-T08) |
//| T7c : M3 contrary -> setup valid, M3_CONFIRMED=false (F3-T11) |
//| T7d : entry konsumsi -> CONSUMED, satu entry (F3-T18) |
//| T7e : score rendah tetap ada setup (F3-T25) |
//+------------------------------------------------------------------+
void SyntheticSetupTests ( )
{
AFSetupEngine eng ;
AFSetupInputs inp ;
AFSetupOutcome out ;
// T7a: rantai lengkap bullish (mirror F3-T01)
eng . Reset ( ) ;
inp . h4 = 1 ; inp . m30 = 1 ;
inp . sweep . onset = 2 ; inp . sweep . dir = 1 ;
inp . choch . onset = 5 ; inp . choch . dir = 1 ;
inp . zone . type = AF_SETUP_ZONE_OB ; inp . zone . formation = 4 ;
inp . zone . dir = 1 ; inp . zone . mit = AF_ZONE_UNMITIGATED ; inp . zone . invalidated = false ;
inp . m15 = 1 ; inp . m3 = 0 ; inp . entry = false ; inp . score = 0.5 ;
// bar 6: sweep fresh (age 4), choch fresh (age 1), chain completes
eng . Step ( 6 , inp , out ) ;
if ( out . setup_exists & & out . setup_id = = 1 & & out . state = = AF_SETUP_CANDIDATE & & out . dir = = 1 )
Pass ( " T7a setup layer: rantai lengkap -> CANDIDATE_SETUP id=1 " ) ;
else
Fail ( " T7a setup layer: rantai lengkap gagal (state= " + EnumToString ( out . state ) + " ) " ) ;
// T7b: H4 conflict -> BLOCKED (mirror F3-T08)
eng . Reset ( ) ;
inp . h4 = -1 ; inp . m30 = 1 ;
inp . sweep . onset = 2 ; inp . sweep . dir = 1 ;
inp . choch . onset = 3 ; inp . choch . dir = 1 ;
inp . zone . type = AF_SETUP_ZONE_OB ; inp . zone . formation = 3 ;
inp . zone . dir = 1 ; inp . zone . mit = AF_ZONE_UNMITIGATED ; inp . zone . invalidated = false ;
inp . m15 = 1 ; inp . m3 = 0 ; inp . entry = false ; inp . score = 0.5 ;
eng . Step ( 6 , inp , out ) ;
if ( out . blocked & & ! out . setup_exists )
Pass ( " T7b setup layer: H4/M30 conflict -> BLOCKED " ) ;
else
Fail ( " T7b setup layer: H4/M30 conflict harus BLOCKED " ) ;
// T7c: M3 contrary -> setup valid, M3_CONFIRMED=false (mirror F3-T11)
eng . Reset ( ) ;
inp . h4 = 1 ; inp . m30 = 1 ;
inp . sweep . onset = 2 ; inp . sweep . dir = 1 ;
inp . choch . onset = 5 ; inp . choch . dir = 1 ;
inp . zone . type = AF_SETUP_ZONE_OB ; inp . zone . formation = 4 ;
inp . zone . dir = 1 ; inp . zone . mit = AF_ZONE_UNMITIGATED ; inp . zone . invalidated = false ;
inp . m15 = 1 ; inp . m3 = -1 ; inp . entry = false ; inp . score = 0.5 ;
eng . Step ( 6 , inp , out ) ;
eng . Step ( 7 , inp , out ) ;
if ( out . setup_exists & & out . setup_id = = 1 & & ! out . m3_confirmed & &
out . state = = AF_SETUP_CANDIDATE )
Pass ( " T7c setup layer: M3 contrary -> setup valid, M3_CONFIRMED=false " ) ;
else
Fail ( " T7c setup layer: M3 contrary harus tetap valid tanpa konfirmasi " ) ;
// T7d: entry konsumsi -> CONSUMED, satu entry per setup (mirror F3-T18)
eng . Reset ( ) ;
inp . h4 = 1 ; inp . m30 = 1 ;
inp . sweep . onset = 2 ; inp . sweep . dir = 1 ;
inp . choch . onset = 5 ; inp . choch . dir = 1 ;
inp . zone . type = AF_SETUP_ZONE_OB ; inp . zone . formation = 4 ;
inp . zone . dir = 1 ; inp . zone . mit = AF_ZONE_UNMITIGATED ; inp . zone . invalidated = false ;
inp . m15 = 1 ; inp . m3 = 0 ; inp . score = 0.5 ;
inp . entry = false ;
eng . Step ( 5 , inp , out ) ; // forming
inp . entry = true ;
eng . Step ( 6 , inp , out ) ; // entry pada bar yang sama -> CONSUMED
inp . entry = false ;
eng . Step ( 7 , inp , out ) ; // setup sudah terminal -> slot bebas
if ( eng . EntryBindings ( ) = = 1 & & out . state = = AF_SETUP_NONE )
Pass ( " T7d setup layer: satu entry per setup (CONSUMED) " ) ;
else
Fail ( " T7d setup layer: aturan satu-entry gagal (bindings= "
+ IntegerToString ( eng . EntryBindings ( ) ) + " ) " ) ;
// T7e: score rendah tetap ada setup (mirror F3-T25)
eng . Reset ( ) ;
inp . h4 = 1 ; inp . m30 = 1 ;
inp . sweep . onset = 2 ; inp . sweep . dir = 1 ;
inp . choch . onset = 5 ; inp . choch . dir = 1 ;
inp . zone . type = AF_SETUP_ZONE_OB ; inp . zone . formation = 4 ;
inp . zone . dir = 1 ; inp . zone . mit = AF_ZONE_UNMITIGATED ; inp . zone . invalidated = false ;
inp . m15 = 1 ; inp . m3 = 0 ; inp . entry = false ; inp . score = 0.05 ;
eng . Step ( 6 , inp , out ) ;
if ( out . setup_exists & & out . setup_id = = 1 & & out . score = = 0.05 )
Pass ( " T7e setup layer: setup ada walau score rendah (score != setup) " ) ;
else
Fail ( " T7e setup layer: score rendah harus tetap punya setup " ) ;
}
2026-08-21 10:01:21 +07:00
//+------------------------------------------------------------------+
//| Log verbose |
//+------------------------------------------------------------------+
void PrintAllVerbose ( )
{
for ( int i = 0 ; i < 4 ; i + + )
PrintFormat ( " AFTEST2 [%s] TF=%s dir=%d buy=%.3f sell=%.3f conf=%.3f | %s " ,
g_out [ i ] . name , g_out [ i ] . tfName , g_out [ i ] . dir , g_out [ i ] . buy ,
g_out [ i ] . sell , g_out [ i ] . confidence , g_out [ i ] . reason ) ;
PrintFormat ( " AFTEST2 [AGG] %s " , g_aggOut . reason ) ;
if ( g_aggOut . hasLevels )
PrintFormat ( " AFTEST2 [AGG] entry=%.2f sl=%.2f tp=%.2f " ,
g_aggOut . entry , g_aggOut . sl , g_aggOut . tp ) ;
}
//+------------------------------------------------------------------+
//| Semua cek pada bar tertutup baru (atau saat semua slot siap) |
//+------------------------------------------------------------------+
bool RunAllChecks ( )
{
for ( int i = 0 ; i < 4 ; i + + )
{
if ( g_s [ i ] < 0 | | ! g_e1 . IsReady ( g_s [ i ] ) )
{
PrintFormat ( " AFTEST2 SKIP: slot %s belum siap " , AgentName ( i ) ) ;
return false ;
}
if ( g_e1 . Count ( g_s [ i ] ) < AF_E2_MIN_BARS )
{
PrintFormat ( " AFTEST2 SKIP: data %s kurang (%d bar < %d) " ,
AgentName ( i ) , g_e1 . Count ( g_s [ i ] ) , AF_E2_MIN_BARS ) ;
return false ;
}
}
// T3 - closed-bar lock: bar terbaru tiap slot sudah tertutup
datetime now = TimeCurrent ( ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
datetime t0 = g_e1 . Time ( g_s [ i ] , 0 ) ;
if ( ! g_e1 . IsBarClosed ( t0 , g_e1 . TfOf ( g_s [ i ] ) , now ) )
Fail ( " T3 " + AgentName ( i ) + " : bar terbaru belum tertutup ( " + TimeToString ( t0 ) + " ) " ) ;
}
// compute semua agen + agregator (via facade)
g_eng2 . Compute ( g_e1 , g_s [ 0 ] , g_s [ 1 ] , g_s [ 2 ] , g_s [ 3 ] ,
g_out [ 0 ] , g_out [ 1 ] , g_out [ 2 ] , g_out [ 3 ] , g_aggOut ) ;
for ( int i = 0 ; i < 4 ; i + + ) CheckAgentOut ( i ) ;
CheckAggOut ( ) ;
if ( ! g_indepDone )
{
g_indepDone = CheckIndependence ( ) ;
2026-08-21 10:28:46 +07:00
2026-08-21 10:01:21 +07:00
}
if ( g_verbose ) PrintAllVerbose ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Init |
//+------------------------------------------------------------------+
int OnInit ( )
{
Print ( " AFTEST2 ============================================================ " ) ;
Print ( " AFTEST2 Algo Forge Engine2 UnitTest v " + AF_PROJECT_VERSION ) ;
Print ( " AFTEST2 Atribusi: " + AF_SOURCE_TITLE + " (c) " + AF_SOURCE_AUTHOR + " - " + AF_SOURCE_URL ) ;
g_verbose = InpVerbose ;
ENUM_TIMEFRAMES tfs [ 4 ] ;
2026-08-21 15:39:52 +07:00
tfs [ 0 ] = AF_E2_TF_S1 ; // H4 (N)
tfs [ 1 ] = AF_E2_TF_S2 ; // M30 (C)
tfs [ 2 ] = AF_E2_TF_S3 ; // M15 (E)
2026-08-21 15:44:49 +07:00
tfs [ 3 ] = AF_E2_TF_S4 ; // M3 (P)
2026-08-21 10:01:21 +07:00
ENUM_TIMEFRAMES tft [ 4 ] ;
tft [ 0 ] = InpTamper1 ;
tft [ 1 ] = InpTamper2 ;
tft [ 2 ] = InpTamper3 ;
tft [ 3 ] = InpTamper4 ;
for ( int i = 0 ; i < 4 ; i + + )
{
g_s [ i ] = g_e1 . Register ( tfs [ i ] , InpMaxBars ) ;
g_t [ i ] = g_e1 . Register ( tft [ i ] , InpMaxBars ) ;
g_lastBar [ i ] = -1 ;
if ( g_s [ i ] < 0 ) Fail ( " Register slot " + AgentName ( i ) + " gagal " ) ;
}
g_e1 . Refresh ( ) ;
SyntheticAggTests ( ) ; // T6 - murni logika, jalan tanpa data
2026-08-22 23:31:22 +07:00
SyntheticSetupTests ( ) ; // T7 - F3 setup layer, input semantik sintetis
2026-08-21 10:01:21 +07:00
PrintFormat ( " AFTEST2 slot: N=%d C=%d E=%d P=%d | tamper N=%d C=%d E=%d P=%d " ,
g_s [ 0 ] , g_s [ 1 ] , g_s [ 2 ] , g_s [ 3 ] , g_t [ 0 ] , g_t [ 1 ] , g_t [ 2 ] , g_t [ 3 ] ) ;
return ( INIT_SUCCEEDED ) ;
}
//+------------------------------------------------------------------+
//| Tick |
//+------------------------------------------------------------------+
void OnTick ( )
{
g_e1 . Refresh ( ) ;
bool barsChanged = false ;
for ( int i = 0 ; i < 4 ; i + + )
{
if ( g_s [ i ] < 0 ) continue ;
if ( ! g_e1 . IsReady ( g_s [ i ] ) ) continue ;
long lb = g_e1 . LastBars ( g_s [ i ] ) ;
if ( lb ! = g_lastBar [ i ] )
{
barsChanged = true ;
g_lastBar [ i ] = lb ;
}
}
if ( barsChanged )
{
if ( RunAllChecks ( ) ) g_repaintPending = true ;
else g_repaintPending = false ;
}
else if ( g_repaintPending )
{
CheckNonRepaint ( ) ; // bar sama -> output harus identik
g_repaintPending = false ;
}
}
//+------------------------------------------------------------------+
//| Tester summary |
//+------------------------------------------------------------------+
double OnTester ( )
{
Print ( " AFTEST2 ============================================================ " ) ;
PrintFormat ( " AFTEST2 RESULT: PASS=%d FAIL=%d " , g_pass , g_fail ) ;
Print ( " AFTEST2 RESULT: " + ( g_fail = = 0 ? " SEMUA CEK LULUS " : " ADA CEK GAGAL " ) ) ;
for ( int i = 0 ; i < 4 ; i + + )
if ( g_s [ i ] > = 0 & & g_e1 . IsReady ( g_s [ i ] ) )
PrintFormat ( " AFTEST2 final [%s]: TF=%s count=%d historyCalls=%d " ,
AgentName ( i ) , AF_E2_TfName ( g_e1 . TfOf ( g_s [ i ] ) ) ,
g_e1 . Count ( g_s [ i ] ) , g_e1 . HistoryCalls ( g_s [ i ] ) ) ;
return ( g_fail = = 0 ) ? 1000.0 : 0.0 ;
}