Gamestudio Links
Zorro Links
Newest Posts
ZorroGPT
by TipmyPip. 06/06/26 12:36
Zorro 3.01 recoded MMI function issue
by TipmyPip. 06/04/26 05:44
SGT_FW
by Aku_Aku. 05/31/26 11:05
Issues resuming trades on Demo account
by Martin_HH. 05/22/26 13:31
XTB
by pr0logic. 05/18/26 12:27
Purchase A8 full licence version
by NeoDumont. 05/13/26 20:17
Black Book, 4th edition
by TipmyPip. 05/11/26 08:40
AUM Magazine
Latest Screens
Dorifto samurai
Shadow 2
Rocker`s Revenge
Stug 3 Stormartillery
Who's Online Now
1 registered members (Quad), 5,751 guests, and 2 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Seraphinang, Koti, curry, DeepxKalsi, Samed
19219 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 24 of 24 1 2 22 23 24
Re: ARIMA Package for Zorro [Re: qin] #489439
05/27/26 19:54
05/27/26 19:54
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
Dear Qin, I have found for you a nice video that examples for quant development, It is very interesting, and you don't need to try all the ideas at once, but you can start with small steps.

https://youtu.be/G57FAI-dkXs?si=0YhmlMeB0me3CGK8

Last edited by TipmyPip; 05/27/26 20:10.
ARIMA Package for Zorro (64bit) [Re: TipmyPip] #489440
05/27/26 22:41
05/27/26 22:41
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
64bit version of AutoArima Package for Zorro

AutoArima 64bit

1. Memory and Pointer Management Functions (13)
aa_alloc_vars
aa_clear_arima_work
aa_copy_vars
aa_free_vars
aa_prepare_arima_work
aa_shift_vars
aa_zero_vars
copy_arima_model
free_arima_model
free_arima_work
init_arima_model
init_arima_work
reset_arima_model

2. Basic Math and Array Utilities (13)
aa_argmax
aa_argmin
aa_correlation
aa_covariance
aa_demean
aa_max
aa_mean
aa_min
aa_normalize_minmax
aa_standardize
aa_stddev
aa_sum
aa_variance

3. Input Validation and Data Cleaning (11)
aa_clip_outliers
aa_count_invalid_values
aa_fill_missing_forward
aa_fill_missing_mean
aa_has_invalid_values
aa_limit_returns
aa_remove_invalid_values
aa_replace_zero_prices
aa_validate_price_series
aa_validate_series
aa_winsorize_series

4. Transformations and Differencing (15)
aa_boxcox_lambda
aa_boxcox_transform
aa_difference_once
aa_difference_series
aa_difference_twice
aa_inverse_boxcox_transform
aa_inverse_difference
aa_inverse_difference_path
aa_inverse_log_transform
aa_inverse_return_forecast
aa_inverse_seasonal_difference
aa_log_transform
aa_return_transform
aa_seasonal_difference_once
aa_seasonal_difference_series

5. Stationarity and Differencing Selection (16)
aa_adf_pvalue_approx
aa_adf_statistic
aa_adf_test
aa_calculate_d
aa_calculate_D
aa_is_stationary
aa_kpss_pvalue_approx
aa_kpss_statistic
aa_kpss_test
aa_ndiffs
aa_ndiffs_heuristic
aa_nsdiffs
aa_nsdiffs_heuristic
aa_pp_pvalue_approx
aa_pp_statistic
aa_pp_test

6. Autocorrelation and Partial Autocorrelation (10)
aa_acf
aa_acf_cutoff_lag
aa_autocorrelation
aa_autocovariance
aa_initial_ar_from_pacf
aa_initial_ma_from_acf
aa_levinson_durbin
aa_pacf
aa_pacf_cutoff_lag
aa_yule_walker

7. AR / MA Validity and Stability (9)
aa_ar_root_modulus
aa_clamp_coefficients
aa_coefficients_are_valid
aa_enforce_invertibility
aa_enforce_stationarity
aa_is_invertible_ma
aa_is_stationary_ar
aa_ma_root_modulus
aa_min_root_modulus

8. ARMA / ARIMA / SARIMA Fitting Functions (7)
aa_arima_fit
aa_arma_fit
aa_css_fit
aa_exact_mle_fit
aa_kalman_loglikelihood
aa_mle_fit
aa_sarima_fit

9. Optimizer Functions (14)
aa_adam_fit
aa_bfgs_fit
aa_check_convergence
aa_compute_gradient
aa_compute_hessian
aa_gradient_descent_fit
aa_gradient_norm
aa_lbfgs_fit
aa_nelder_mead_fit
aa_optimizer_report
aa_set_optimizer_defaults
aa_set_optimizer_learning_rate
aa_set_optimizer_max_iter
aa_set_optimizer_tolerance

10. Likelihood and Model Scoring (10)
aa_aic_score
aa_aicc_score
aa_aicc_score_general
aa_bic_score
aa_compare_ic
aa_conditional_loglikelihood
aa_exact_loglikelihood
aa_hqic_score
aa_loglikelihood
aa_model_score

11. AutoARIMA Search Functions (11)
aa_auto_arima_search
aa_candidate_exists
aa_expand_candidate_models
aa_fallback_model
aa_grid_search_arima
aa_init_candidate
aa_select_best_model
aa_set_candidate
aa_stepwise_auto_arima
aa_try_neighbor_models
aa_validate_candidate_model

12. Seasonal ARIMA / SARIMA Functions (7)
aa_auto_sarima_search
aa_detect_seasonal_period
aa_sarima_forecast_multi_step
aa_sarima_forecast_one_step
aa_seasonal_acf_score
aa_seasonal_strength
aa_stepwise_auto_sarima

13. ARIMAX / SARIMAX Functions (8)
aa_arimax_fit
aa_arimax_forecast
aa_prepare_exogenous_matrix
aa_regression_fit
aa_regression_predict
aa_sarimax_fit
aa_sarimax_forecast
aa_validate_exogenous_data

14. Forecasting Functions (9)
aa_backtransform_forecast
aa_bias_adjusted_backtransform
aa_forecast_bands
aa_forecast_confidence_interval
aa_forecast_multi_step
aa_forecast_one_step
aa_forecast_standard_error
aa_forecast_variance
aa_integrate_forecast

15. Residual Diagnostics (21)
aa_arch_lm_pvalue
aa_arch_lm_stat
aa_arch_lm_test
aa_box_pierce_pvalue
aa_box_pierce_stat
aa_box_pierce_test
aa_compute_residuals
aa_diagnostic_report
aa_durbin_watson_test
aa_jarque_bera_pvalue
aa_jarque_bera_stat
aa_jarque_bera_test
aa_ljung_box_pvalue
aa_ljung_box_stat
aa_ljung_box_test
aa_residual_acf
aa_residual_mean
aa_residual_normality_check
aa_residual_stddev
aa_residual_variance
aa_residual_white_noise_check

16. Model Reporting and File I/O (8)
aa_load_model_from_file
aa_print_coefficients
aa_print_forecast_report
aa_print_model_summary
aa_print_residual_diagnostics
aa_save_diagnostics_to_file
aa_save_forecast_to_file
aa_save_model_to_file

17. Model Caching and Reuse (7)
aa_cache_best_model
aa_clear_model_cache
aa_init_model_cache
aa_load_cached_model
aa_refit_best_model
aa_reuse_previous_model
aa_should_refit_model

18. Walk-Forward and Forecast Evaluation (8)
aa_directional_accuracy
aa_forecast_error_mae
aa_forecast_error_mape
aa_forecast_error_mse
aa_forecast_error_rmse
aa_rolling_forecast_test
aa_train_test_split
aa_walk_forward_arima

19. Trading Signal Functions (9)
aa_backtest_forecast_signal
aa_forecast_edge
aa_forecast_return
aa_forecast_zscore
aa_position_size_from_confidence
aa_position_size_from_forecast
aa_signal_from_confidence_band
aa_signal_from_directional_accuracy
aa_signal_from_forecast

20. Zorro Integration Functions (6)
aa_zorro_forecast_current_asset
aa_zorro_get_close_series
aa_zorro_plot_forecast
aa_zorro_plot_forecast_bands
aa_zorro_print_model
aa_zorro_trade_from_forecast

21. Current AutoARIMA Compatibility Functions (7)
aa_prepare_auto_arima_work
auto_arima_forecast
auto_arima_forecast_with_work
free_auto_arima_result
free_auto_arima_work
init_auto_arima_result
init_auto_arima_work

Last edited by TipmyPip; 05/27/26 22:42.
EUR/USD SMA + ARIMA forecast [Re: TipmyPip] #489441
05/28/26 01:43
05/28/26 01:43
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
This Zorro lite-C script plots a EUR/USD daily chart that combines a traditional SMA indicator with an external ARIMA forecast. It imports selected functions from AutoAri32.dll and defines a minimal AUTO_ARIMA_RESULT structure so the DLL can return the selected ARIMA order, convergence state, forecast value, and AICc score. During each run, the script loads EUR/USD closing prices, calculates a 20-period simple moving average, and skips execution until the LookBack period is complete. The ARIMA model uses the previous 120 completed closing prices to generate a one-step forecast. Before forecasting, the price series is validated, and the result is checked for convergence, invalid values, and a realistic EUR/USD range. If ARIMA fails, the script safely falls back to the previous close. It then plots price, SMA20, ARIMA forecast, and forecast error in pips, while printing diagnostic model statistics to the log.

Code
// Arima01.c
// EUR/USD SMA + ARIMA forecast
// Requires AutoAri32.dll in the same folder as this script.

// Minimal copy of AUTO_ARIMA_RESULT from aa_arima_types.h.
// Field names can be local; order and types must match the DLL.
typedef struct
{
    int p;
    int d;
    int q;
    int converged;

    var sse;
    var aicc;
    var forecast;

    var* ar;
    var* ma;

    int arCap;
    int maCap;

} AUTO_ARIMA_RESULT;

#define PRAGMA_API init_auto_arima_result;AutoAri32!init_auto_arima_result
#define PRAGMA_API free_auto_arima_result;AutoAri32!free_auto_arima_result
#define PRAGMA_API auto_arima_forecast;AutoAri32!auto_arima_forecast
#define PRAGMA_API aa_validate_price_series;AutoAri32!aa_validate_price_series

void init_auto_arima_result(AUTO_ARIMA_RESULT* R);
void free_auto_arima_result(AUTO_ARIMA_RESULT* R);
int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result);
int aa_validate_price_series(vars Close,int N);

#define ARIMA_WINDOW 120

function run()
{
    set(PLOTNOW,LOGFILE);

    BarPeriod = 1440;
    LookBack = ARIMA_WINDOW + 50;
    MaxBars = 800;

    PlotWidth = 1200;
    PlotHeight1 = 600;
    PlotBars = 300;

    asset("EUR/USD");

    vars Price = series(priceClose());

    var SMA20 = SMA(Price,20);

    if(is(LOOKBACK))
        return;

    var Forecast = Price[1]; // safe fallback
    int Status = 0;

    AUTO_ARIMA_RESULT R;
    init_auto_arima_result(&R);

    // The library documents price-series validation before model use.
    // It checks positive prices, invalid values, and enough samples.
    if(aa_validate_price_series(Price+1,ARIMA_WINDOW))
    {
        Status = auto_arima_forecast(Price+1,ARIMA_WINDOW,PIP,3,3,&R);

        if(Status and R.converged and !invalid(R.forecast))
        {
            if(R.forecast > 0.5 and R.forecast < 2.0)
                Forecast = R.forecast;
        }
    }

    var ErrorPips = (Price[0] - Forecast) / PIP;

    plot("Close",Price[0],MAIN|LINE,BLUE);
    plot("SMA20",SMA20,MAIN|LINE,RED);
    plot("ARIMA",Forecast,MAIN|LINE,GREEN);
    plot("ErrPips",ErrorPips,NEW|LINE,BLACK);

    printf(
        "\nBar %i Close %.5f SMA20 %.5f ARIMA %.5f Err %.2f pips Status %i p=%i d=%i q=%i AICc %.4f",
        Bar,
        Price[0],
        SMA20,
        Forecast,
        ErrorPips,
        Status,
        R.p,
        R.d,
        R.q,
        R.aicc
    );

    free_auto_arima_result(&R);
}

Arima Indicator Matrix (v1) [Re: TipmyPip] #489452
Yesterday at 12:00
Yesterday at 12:00
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
The strategy is a multi-module trading system that transforms traditional technical analysis into a forecast-driven decision process. Instead of reacting only to present indicator conditions, each module converts its indicator state into a time series and uses the ARIMA model to estimate the next expected state of that indicator. Bollinger position, RSI behavior, stochastic movement, Keltner distance, Ichimoku pressure, EMA separation, ADX strength, Donchian range position, MACD histogram pressure, squeeze expansion, Grey-model deviation, and flag-continuation pressure are treated as dynamic variables with measurable direction and persistence. The strategy then compares the current indicator state with its forecasted state to determine whether momentum, reversion, expansion, or contraction is more likely. This changes the logic from static threshold recognition to probabilistic state projection. A trade is opened only when the predicted indicator movement supports the module’s market context, such as recovery from an oversold state, rejection from an overextended band, strengthening trend pressure, or predicted breakout continuation. Risk management remains based on volatility, using ATR-derived stop distance, take-profit distance, trailing behavior, and adaptive scaling. The system also applies session filters, asset filters, trend-quality gates, regime direction checks, and portfolio exposure limits, so signals are not evaluated in isolation. In mathematical terms, the strategy treats every indicator as an evolving process, estimates its future path from recent observations, and trades only when the forecasted movement aligns with the structural meaning of that indicator. This makes the strategy less recognizable as a standard Bollinger, RSI, MACD, Donchian, or Ichimoku system, because the final decision is no longer based on the raw indicator signal itself, but on the predicted transformation of the indicator state.

Code
// ArimaIndicatorMatrix_v01.c
// 12-module strategy rewritten around ARIMA-predicted indicator states.
//
// The old strategy modules used direct indicator conditions such as:
//   - current RSI overbought / oversold
//   - current Bollinger / Keltner touch
//   - current MACD / EMA / Donchian / Ichimoku states
//
// This version changes the decision context:
//   indicator current value
//      -> indicator series
//      -> auto_arima_forecast(indicator series)
//      -> forecast delta / pressure
//      -> trade decision
//
// The ARIMA package functions are used with their exact declared signatures:
//   init_auto_arima_result(AUTO_ARIMA_RESULT* R)
//   free_auto_arima_result(AUTO_ARIMA_RESULT* R)
//   auto_arima_forecast(vars Data,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result)
//   aa_validate_price_series(vars Data,int N)
//
// Important: ARIMA is never called on a single var. Every forecast receives
// a vars time series generated from an indicator value with series(...).
//
// Source package: https://github.com/KoplaNum/ARIMA
//
// Setup:
//   Zorro.exe    -> AutoAri32.dll
//   Zorro64.exe  -> AutoAri64.dll

#define NUM_MODULES 12
#define TF_M30 1
#define TF_H1  2
#define TF_H2  4
#define TF_H4  8
#define TF_D1  48

// -----------------------------------------------------------------------------
// ARIMA package interface
// -----------------------------------------------------------------------------
// UseARIMAFilter is the old close-price confirmation filter.
// The main strategy below does not rely on that old filter. It creates ARIMA
// forecasts of the module indicator series themselves.
// -----------------------------------------------------------------------------

#define PRAGMA_API init_auto_arima_result;AutoAri32!init_auto_arima_result
#define PRAGMA_API free_auto_arima_result;AutoAri32!free_auto_arima_result
#define PRAGMA_API auto_arima_forecast;AutoAri32!auto_arima_forecast
#define PRAGMA_API aa_validate_price_series;AutoAri32!aa_validate_price_series

int UseARIMAFilter = 0; // old close-price gate; indicator ARIMA is the main logic
int ARIMA_N = 160;          // number of close prices used for the forecast
int ARIMA_MaxP = 3;         // maximum AR order searched by auto_arima_forecast
int ARIMA_MaxQ = 3;         // maximum MA order searched by auto_arima_forecast
var ARIMA_MinPips = 2.0;    // minimum forecast edge in pips
int ARIMA_PlotForecast = 0; // plots old price forecast only if UseARIMAFilter is enabled

int UseARIMAIndicatorPrediction = 1;
var ARIMA_MinOscDelta = 0.75;    // RSI/Stoch/Band position forecast delta
var ARIMA_MinTrendDelta = 0.60;  // trend/pressure forecast delta
var ARIMA_MinWidthDelta = 0.00001;

typedef struct AUTO_ARIMA_RESULT
{
	int p;
	int d;
	int q;
	int converged;
	var sse;
	var aicc;
	var forecast;
	var* ar;
	var* ma;
	int arCap;
	int maCap;
} AUTO_ARIMA_RESULT;

AUTO_ARIMA_RESULT GArimaResult;
int GArimaInitialized = 0;

// ARIMA DLL imports.
// The README signature for auto_arima_forecast is:
// int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result)
int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result);
int aa_validate_price_series(vars Close,int N);
void init_auto_arima_result(AUTO_ARIMA_RESULT* R);
void free_auto_arima_result(AUTO_ARIMA_RESULT* R);

void InitARIMAOnce()
{
	if(GArimaInitialized)
		return;

	init_auto_arima_result(&GArimaResult);
	GArimaInitialized = 1;
}

void ResetARIMAResult()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	init_auto_arima_result(&GArimaResult);
}

int ARIMAAllowsDirection(int dir,vars C)
{
	if(!UseARIMAFilter)
		return 1;

	if(ARIMA_N < 30)
		return 1;

	if(Bar < LookBack)
		return 0;

	InitARIMAOnce();

	// Avoid accumulating result-owned coefficient arrays between calls.
	ResetARIMAResult();

	if(!aa_validate_price_series(C,ARIMA_N))
		return 0;

	int ok = auto_arima_forecast(C,ARIMA_N,PIP,ARIMA_MaxP,ARIMA_MaxQ,&GArimaResult);

	if(!ok)
	{
		printf("\nARIMA forecast failed: Asset=%s Algo=%s Bar=%i",Asset,Algo,Bar);
		return 0;
	}

	var Threshold = ARIMA_MinPips*PIP;
	var Edge = GArimaResult.forecast - C[0];
	int Signal = 0;
	if(Edge > Threshold)
		Signal = 1;
	else if(Edge < -Threshold)
		Signal = -1;

	if(ARIMA_PlotForecast)
		plot("ARIMA Forecast",GArimaResult.forecast,LINE,BLUE);

	if(dir > 0 && Signal > 0)
		return 1;

	if(dir < 0 && Signal < 0)
		return 1;

	return 0;
}

var ARIMAForecastSeries(vars Data,int N,var TickSize,int MaxP,int MaxQ,int* OK)
{
	*OK = 0;

	if(!UseARIMAIndicatorPrediction)
	{
		*OK = 1;
		return Data[0];
	}

	if(N < 30)
		return Data[0];

	if(Bar < LookBack)
		return Data[0];

	InitARIMAOnce();
	ResetARIMAResult();

	if(!aa_validate_price_series(Data,N))
		return Data[0];

	int Status = auto_arima_forecast(
		Data,
		N,
		TickSize,
		MaxP,
		MaxQ,
		&GArimaResult
	);

	if(!Status)
		return Data[0];

	if(!GArimaResult.converged)
		return Data[0];

	if(invalid(GArimaResult.forecast))
		return Data[0];

	*OK = 1;
	return GArimaResult.forecast;
}

int ARIMAForecastUp(var Forecast,var CurrentValue,var MinDelta)
{
	if(Forecast - CurrentValue > MinDelta)
		return 1;
	return 0;
}

int ARIMAForecastDown(var Forecast,var CurrentValue,var MinDelta)
{
	if(CurrentValue - Forecast > MinDelta)
		return 1;
	return 0;
}

void FreeARIMA()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	GArimaInitialized = 0;
}


// -----------------------------------------------------------------------------
// Global inputs
// -----------------------------------------------------------------------------

var RiskPercent = 2.0;
int ATR_Period = 14;

int UseSessionFilter = 1;
int SessionStartHour = 7;
int SessionEndHour = 20;

int UseFixedRiskBase = 1;
var FixedRiskBalance = 10000;
var MaxLotCap = 0; // not used directly; Zorro sizes through Risk/Margin/Lots.

int UseTrailing = 1;
int UseBreakeven = 1;

int UseRegimeDirection = 1;
int Regime_MA = 200;
int Regime_UseSlope = 1;
int Regime_NeutralAllowBoth = 1;
int AllowLongs = 1;
int AllowShorts = 0;

int UseTrendQualityGate = 1;
int TQ_ADX_Period = 14;
var TQ_ADX_Min = 18.0;

int UseRiskCap = 1;
var MaxPortfolioRiskPct = 15.0;
int MaxOpenPositions = 12;

int UseAdaptiveMults = 1;
int Adapt_FastATR = 14;
int Adapt_SlowATR = 100;
var Adapt_Min = 0.75;
var Adapt_Max = 1.50;

// Module master switches
int Use_BB_Stoch       = 1; // M1
int Use_BB_RSI         = 1; // M2
int Use_Keltner_Stoch  = 1; // M3
int Use_Ichimoku_Stoch = 1; // M4
int Use_Supertrend_RSI = 1; // M5
int Use_EMA_ADX        = 1; // M6
int Use_Donchian       = 1; // M7
int Use_MACD_EMA       = 1; // M8
int Use_RSI_MR         = 1; // M9
int Use_BB_Squeeze     = 1; // M10
int Use_Grey           = 1; // M11
int Use_Flag           = 1; // M12

// M1
int M1_BB_Period = 20; var M1_BB_Dev = 2.0;
int M1_Stoch_K = 14; int M1_Stoch_D = 3; int M1_Stoch_Slowing = 3;
var M1_Stoch_OS = 20.0; var M1_Stoch_OB = 80.0;
int M1_UseRangeFilter = 1; int M1_ADX_Period = 14; var M1_ADX_RangeMax = 25.0;
int M1_UseReversionConfirm = 1;
var M1_TrailMult = 1.0; var M1_TrailStart = 1.0;
var M1_BE_Mult = 1.0; var M1_SL_Mult = 1.5; var M1_TP_Mult = 1.5;

// M2
int M2_BB_Period = 20; var M2_BB_Dev = 2.0;
int M2_RSI_Period = 14; var M2_RSI_OS = 30.0; var M2_RSI_OB = 70.0;
int M2_UseRangeFilter = 1; int M2_ADX_Period = 14; var M2_ADX_RangeMax = 25.0;
int M2_UseReversionConfirm = 1;
int M2_TP_AtMid = 1;
int M2_StructuralSL = 1;
var M2_SL_Buffer = 0.5;
var M2_TrailMult = 1.0; var M2_TrailStart = 0.8;
var M2_BE_Mult = 1.0; var M2_SL_Mult = 1.5; var M2_TP_Mult = 2.0;

// M3
int M3_EMA_Period = 20; int M3_ATR_Period = 10; var M3_ATR_Mult = 2.0;
int M3_Stoch_K = 14; int M3_Stoch_D = 3; int M3_Stoch_Slowing = 3;
var M3_Stoch_OS = 20.0; var M3_Stoch_OB = 80.0;
int M3_UseRangeFilter = 0; int M3_ADX_Period = 14; var M3_ADX_RangeMax = 25.0;
var M3_TrailMult = 1.5; var M3_TrailStart = 1.0;
var M3_BE_Mult = 1.0; var M3_SL_Mult = 1.5; var M3_TP_Mult = 2.5;

// M4
int M4_Tenkan = 9; int M4_Kijun = 26; int M4_Senkou = 52;
int M4_Stoch_K = 14; int M4_Stoch_D = 3; int M4_Stoch_Slowing = 3;
var M4_Stoch_OS = 40.0; var M4_Stoch_OB = 60.0;
int M4_UseADXFilter = 0; int M4_ADX_Period = 14; var M4_ADX_Min = 20.0;
var M4_TrailMult = 2.0; var M4_TrailStart = 1.5;
var M4_BE_Mult = 1.0; var M4_SL_Mult = 1.5; var M4_TP_Mult = 3.0;

// M5
int M5_ATR_Period = 10; var M5_ATR_Mult = 3.0;
int M5_RSI_Period = 14; var M5_RSI_OS = 35.0; var M5_RSI_OB = 65.0;
var M5_RSI_BuyLo = 40.0; var M5_RSI_SellHi = 60.0;
int M5_UseADXFilter = 1; int M5_ADX_Period = 14; var M5_ADX_Min = 25.0;
int M5_UseTrendAlign = 1; int M5_TrendEMA = 100;
int M5_MomConfirm = 1;
var M5_TrailMult = 2.5; var M5_TrailStart = 1.5;
var M5_BE_Mult = 1.0; var M5_SL_Mult = 1.5; var M5_TP_Mult = 3.0;

// M6
int M6_EMA_Fast = 9; int M6_EMA_Slow = 21; int M6_EMA_Trend = 50;
int M6_ADX_Period = 14; var M6_ADX_Min = 25.0; var M6_DI_Sep = 3.0;
int M6_RequirePullback = 0; int M6_UseSlopeFilter = 1;
var M6_TrailMult = 2.0; var M6_TrailStart = 1.5;
var M6_BE_Mult = 1.0; var M6_SL_Mult = 1.5; var M6_TP_Mult = 3.0;

// M7
int M7_Donch_Period = 20;
int M7_UseADXFilter = 1; int M7_ADX_Period = 14; var M7_ADX_Min = 30.0;
int M7_UseTrendAlign = 1; int M7_TrendEMA = 100;
int M7_UseSlopeFilter = 1;
var M7_MaxExtATR = 1.0;
var M7_TrailMult = 2.5; var M7_TrailStart = 1.5;
var M7_BE_Mult = 1.0; var M7_SL_Mult = 1.5; var M7_TP_Mult = 3.5;

// M8
int M8_MACD_Fast = 12; int M8_MACD_Slow = 26; int M8_MACD_Signal = 9;
int M8_TrendEMA = 100;
int M8_RequireZeroSide = 1;
int M8_UseSlopeFilter = 0;
int M8_UseADXFilter = 1; int M8_ADX_Period = 14; var M8_ADX_Min = 20.0;
var M8_TrailMult = 2.0; var M8_TrailStart = 1.5;
var M8_BE_Mult = 1.0; var M8_SL_Mult = 1.5; var M8_TP_Mult = 3.0;

// M9
int M9_RSI_Period = 14; var M9_RSI_OS = 35.0; var M9_RSI_OB = 65.0;
int M9_UseRangeFilter = 1; int M9_ADX_Period = 14; var M9_ADX_RangeMax = 25.0;
int M9_RequireSustain = 1;
var M9_TrailMult = 1.0; var M9_TrailStart = 0.8;
var M9_BE_Mult = 1.0; var M9_SL_Mult = 1.5; var M9_TP_Mult = 1.8;

// M10
int M10_BB_Period = 20; var M10_BB_Dev = 2.0; var M10_SqueezeRatio = 0.8;
int M10_UseADXFilter = 1; int M10_ADX_Period = 14; var M10_ADX_Min = 30.0;
int M10_UseTrendAlign = 1; int M10_TrendEMA = 100;
var M10_TrailMult = 2.5; var M10_TrailStart = 1.5;
var M10_BE_Mult = 1.0; var M10_SL_Mult = 1.5; var M10_TP_Mult = 3.5;

// M11
int M11_Period = 24;
int M11_Filter = 250;
int M11_UseTrendFilter = 1; int M11_TrendEMA = 100;
int M11_RequirePersist = 1;
var M11_TrailMult = 2.0; var M11_TrailStart = 1.5;
var M11_BE_Mult = 1.0; var M11_SL_Mult = 1.5; var M11_TP_Mult = 3.0;

// M12
int M12_PoleBars = 5;
var M12_PoleATRMult = 1.8;
int M12_FlagBars = 5;
var M12_FlagMaxATR = 1.6;
int M12_UseTrendFilter = 1; int M12_MA_Period = 200;
var M12_SL_PoleMult = 1.0;
var M12_TP_PoleMult = 1.5;
var M12_TrailMult = 2.5; var M12_TrailStart = 1.5;
var M12_BE_Mult = 1.0;

// Zorro asset names. Adjust to your Assets*.csv / broker mapping.
// lite-C can be picky with global string-array initializers, so use a function
// instead of: string Symbols[3] = { "EUR/USD", "GBP/USD", "XAU/USD" };
#define NUM_SYMBOLS 3

int Use_EURUSD = 1;
int Use_GBPUSD = 0; // enable after importing GBPUSD history files
int Use_XAUUSD = 0; // enable after importing XAUUSD history files

string SymbolName(int Index)
{
	if(Index == 0) return "EUR/USD";
	if(Index == 1) return "GBP/USD";
	if(Index == 2) return "XAU/USD";
	return "";
}

int SymbolEnabled(int Index)
{
	if(Index == 0) return Use_EURUSD;
	if(Index == 1) return Use_GBPUSD;
	if(Index == 2) return Use_XAUUSD;
	return 0;
}

// -----------------------------------------------------------------------------
// Utility
// -----------------------------------------------------------------------------

int contains(string s,string token)
{
	if(strstr(s,token) != 0) return 1;
	return 0;
}

int isForexAsset()
{
	if(contains(Asset,"EUR")) return 1;
	if(contains(Asset,"GBP")) return 1;
	if(contains(Asset,"USD") && !contains(Asset,"XAU")) return 1;
	return 0;
}

int isMetalAsset()
{
	if(contains(Asset,"XAU")) return 1;
	if(contains(Asset,"XAG")) return 1;
	if(contains(Asset,"GOLD")) return 1;
	if(contains(Asset,"SILVER")) return 1;
	return 0;
}

int ModuleRuns(int idx)
{
	if(idx == 0 && !Use_BB_Stoch) return 0;
	if(idx == 1 && !Use_BB_RSI) return 0;
	if(idx == 2 && !Use_Keltner_Stoch) return 0;
	if(idx == 3 && !Use_Ichimoku_Stoch) return 0;
	if(idx == 4 && !Use_Supertrend_RSI) return 0;
	if(idx == 5 && !Use_EMA_ADX) return 0;
	if(idx == 6 && !Use_Donchian) return 0;
	if(idx == 7 && !Use_MACD_EMA) return 0;
	if(idx == 8 && !Use_RSI_MR) return 0;
	if(idx == 9 && !Use_BB_Squeeze) return 0;
	if(idx == 10 && !Use_Grey) return 0;
	if(idx == 11 && !Use_Flag) return 0;

	// v8.11 logic from the uploaded EA:
	// FOREX = M3 + M9 only.
	if(isForexAsset())
	{
		if(idx == 2) return 1;
		if(idx == 8) return 1;
		return 0;
	}

	// METALS = M3,M5,M6,M7,M8,M9,M10,M12.
	if(isMetalAsset())
	{
		if(idx == 2) return 1;
		if(idx == 4) return 1;
		if(idx == 5) return 1;
		if(idx == 6) return 1;
		if(idx == 7) return 1;
		if(idx == 8) return 1;
		if(idx == 9) return 1;
		if(idx == 11) return 1;
		return 0;
	}

	return 1;
}

int IsModuleBar(int tf)
{
	if(tf <= 1) return 1;
	if(Bar % tf == 0) return 1;
	return 0;
}

int SessionOK(int tf)
{
	if(!UseSessionFilter) return 1;
	if(tf >= TF_D1) return 1;
	if(hour(0) >= SessionStartHour && hour(0) < SessionEndHour) return 1;
	return 0;
}

int CountTotalOpen()
{
	int n = 0;
	for(open_trades)
		n++;
	return n;
}

int CurrentAlgoHasOpen()
{
	int n = 0;
	for(current_trades)
		n++;
	if(n > 0) return 1;
	return 0;
}

var clampv(var x,var lo,var hi)
{
	if(x < lo) return lo;
	if(x > hi) return hi;
	return x;
}

var highestS(vars Data,int offset,int period)
{
	var h = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] > h) h = Data[i];
	return h;
}

var lowestS(vars Data,int offset,int period)
{
	var l = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] < l) l = Data[i];
	return l;
}

var smaAt(vars Data,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += Data[i];
	return sum/period;
}

var stdAt(vars Data,int offset,int period)
{
	var m = smaAt(Data,offset,period);
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += (Data[i]-m)*(Data[i]-m);
	return sqrt(sum/period);
}

var emaAt(vars Data,int offset,int period)
{
	int start = offset + period*3;
	var a = 2.0/(period+1.0);
	var e = Data[start];
	int i;
	for(i=start-1;i>=offset;i--)
		e = a*Data[i] + (1.0-a)*e;
	return e;
}

void bbAt(vars C,int period,var dev,int offset,var* mid,var* upper,var* lower)
{
	*mid = smaAt(C,offset,period);
	var sd = stdAt(C,offset,period);
	*upper = *mid + dev*sd;
	*lower = *mid - dev*sd;
}

var atrAt(vars H,vars L,vars C,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var a = H[i]-L[i];
		var b = abs(H[i]-C[i+1]);
		var c = abs(L[i]-C[i+1]);
		var tr = max(a,max(b,c));
		sum += tr;
	}
	return sum/period;
}

var rsiAt(vars C,int offset,int period)
{
	var up = 0;
	var dn = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var d = C[i]-C[i+1];
		if(d > 0) up += d;
		else dn -= d;
	}
	if(dn <= 0) return 100;
	var rs = up/dn;
	return 100.0 - 100.0/(1.0+rs);
}

void stochAt(vars H,vars L,vars C,int kPeriod,int dPeriod,int offset,var* kOut,var* dOut)
{
	var hh = highestS(H,offset,kPeriod);
	var ll = lowestS(L,offset,kPeriod);
	if(hh == ll)
		*kOut = 50;
	else
		*kOut = 100.0*(C[offset]-ll)/(hh-ll);

	var sum = 0;
	int j;
	for(j=0;j<dPeriod;j++)
	{
		var h2 = highestS(H,offset+j,kPeriod);
		var l2 = lowestS(L,offset+j,kPeriod);
		var k2 = 50;
		if(h2 != l2) k2 = 100.0*(C[offset+j]-l2)/(h2-l2);
		sum += k2;
	}
	*dOut = sum/dPeriod;
}

var adxApprox(vars H,vars L,vars C,int offset,int period,var* diPlus,var* diMinus)
{
	var trsum = 0;
	var pdm = 0;
	var mdm = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var upMove = H[i]-H[i+1];
		var dnMove = L[i+1]-L[i];
		if(upMove > dnMove && upMove > 0) pdm += upMove;
		if(dnMove > upMove && dnMove > 0) mdm += dnMove;

		var tr = max(H[i]-L[i],max(abs(H[i]-C[i+1]),abs(L[i]-C[i+1])));
		trsum += tr;
	}
	if(trsum <= 0)
	{
		*diPlus = 0;
		*diMinus = 0;
		return 0;
	}
	*diPlus = 100.0*pdm/trsum;
	*diMinus = 100.0*mdm/trsum;

	var den = *diPlus + *diMinus;
	if(den <= 0) return 0;
	return 100.0*abs(*diPlus-*diMinus)/den;
}

var macdLineAt(vars C,int offset,int fast,int slow)
{
	return emaAt(C,offset,fast)-emaAt(C,offset,slow);
}

var macdSignalAt(vars C,int offset,int fast,int slow,int sig)
{
	var tmp[100];
	int i;
	int n = sig*3;
	if(n > 90) n = 90;
	for(i=0;i<n;i++)
		tmp[i] = macdLineAt(C,offset+i,fast,slow);
	var a = 2.0/(sig+1.0);
	var e = tmp[n-1];
	for(i=n-2;i>=0;i--)
		e = a*tmp[i] + (1.0-a)*e;
	return e;
}

int trendQualityOK(vars H,vars L,vars C,int regime)
{
	if(!UseTrendQualityGate) return 1;
	if(regime != -1) return 1;

	var p,m;
	var adx = adxApprox(H,L,C,0,TQ_ADX_Period,&p,&m);
	if(adx >= TQ_ADX_Min) return 1;
	return 0;
}

var adaptFactor(vars H,vars L,vars C)
{
	if(!UseAdaptiveMults) return 1.0;
	var fast = atrAt(H,L,C,0,Adapt_FastATR);
	var slow = atrAt(H,L,C,0,Adapt_SlowATR);
	if(slow <= 0) return 1.0;
	return clampv(fast/slow,Adapt_Min,Adapt_Max);
}

int directionBlocked(int dir,vars C)
{
	int isBuy = 0;
	if(dir > 0) isBuy = 1;

	if(UseRegimeDirection)
	{
		// Uses current module's timeframe as a practical approximation.
		// For a strict D1 regime filter, move this calculation into a dedicated D1 TimeFrame block.
		var ma0 = smaAt(C,0,Regime_MA);
		var ma1 = smaAt(C,1,Regime_MA);
		int slopeUp = 0;
		int slopeDn = 0;
		if(ma0 > ma1) slopeUp = 1;
		if(ma0 < ma1) slopeDn = 1;

		if(C[0] > ma0 && (!Regime_UseSlope || slopeUp))
		{
			if(!isBuy) return 1;
			return 0;
		}
		if(C[0] < ma0 && (!Regime_UseSlope || slopeDn))
		{
			if(isBuy) return 1;
			return 0;
		}
		if(Regime_NeutralAllowBoth) return 0;
		return 1;
	}

	if(isBuy && !AllowLongs) return 1;
	if(!isBuy && !AllowShorts) return 1;
	return 0;
}

void openTradeDir(int dir,string name,var slDist,var tpDist,var trailMult,var trailStart,var beMult,vars C)
{
	if(slDist <= 0 || tpDist <= 0) return;
	if(directionBlocked(dir,C)) return;
	if(!ARIMAAllowsDirection(dir,C)) return;
	if(UseRiskCap && MaxOpenPositions > 0 && CountTotalOpen() >= MaxOpenPositions) return;

	algo(name);
	if(CurrentAlgoHasOpen()) return;

	Stop = slDist;
	TakeProfit = tpDist;

	// Zorro has no global BreakEven variable.
	// Breakeven-style behavior is approximated through TrailLock.
	// TrailLock = 1 moves the stop to about entry/breakeven once the Trail trigger is reached.
	// IMPORTANT: reset all trail-related globals before every new trade so values do not leak
	// from one module/component into the next.
	Trail = 0;
	TrailSlope = 100;
	TrailLock = 0;
	TrailStep = 0;

	if(UseTrailing)
		Trail = trailMult*slDist;

	if(UseBreakeven && Trail > 0)
		TrailLock = 1;

	var base = FixedRiskBalance;
	if(!UseFixedRiskBase) base = Balance;
	Risk = base*RiskPercent/100.0;

	if(dir > 0)
		enterLong();
	else
		enterShort();
}

// -----------------------------------------------------------------------------
// M11 Grey estimator
// -----------------------------------------------------------------------------

var greyMA(vars O,int offset,int period)
{
	if(period < 3) period = 3;

	var grey[80];
	var rez[1600];
	int j,k,cnt;
	if(period > 40) period = 40;

	for(j=0;j<period;j++)
		grey[j] = O[offset+j];

	for(j=period-2;j>=0;j--)
		grey[j] = grey[j] + grey[j+1];

	cnt = 0;
	for(j=period-2;j>=0;j--)
	{
		for(k=j+1;k<period;k++)
		{
			rez[cnt] = (grey[j]-grey[k])/(k-j);
			cnt++;
		}
	}

	// simple ascending sort
	int a,b;
	for(a=0;a<cnt-1;a++)
	{
		for(b=a+1;b<cnt;b++)
		{
			if(rez[b] < rez[a])
			{
				var t = rez[a];
				rez[a] = rez[b];
				rez[b] = t;
			}
		}
	}

	int i1 = cnt/2;
	int i2 = i1;
	if(cnt%2 == 0) i2 = i1 + 1;
	if(i2 >= cnt) i2 = cnt-1;

	return (rez[i1]+rez[i2])/2.0;
}

// -----------------------------------------------------------------------------
// Modules
// -----------------------------------------------------------------------------

void Module1_BB_Stoch()
{
	if(!ModuleRuns(0)) return;

	TimeFrame = TF_M30;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_N);
	vars StochKS = series(0,ARIMA_N);
	vars WidthS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_M30)) return;
	if(!SessionOK(TF_M30)) return;

	if(!trendQualityOK(H,L,C,1)) return;

	var dip,dim;
	if(M1_UseRangeFilter)
		if(adxApprox(H,L,C,0,M1_ADX_Period,&dip,&dim) >= M1_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M1_BB_Period,M1_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M1_BB_Period,M1_BB_Dev,1,&m2,&u2,&l2);

	var k1,d1;
	stochAt(H,L,C,M1_Stoch_K,M1_Stoch_D,0,&k1,&d1);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	var widthNow = (u1-l1)/fix0(m1);
	if(widthNow <= 0) widthNow = 0.0001;

	BandPosS[0] = bandPos;
	StochKS[0] = clampv(k1,1.,99.);
	WidthS[0] = widthNow;

	int BOk = 0;
	int SOk = 0;
	int WOk = 0;
	var bandF = ARIMAForecastSeries(BandPosS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&BOk);
	var stochF = ARIMAForecastSeries(StochKS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&SOk);
	var widthF = ARIMAForecastSeries(WidthS,ARIMA_N,0.0001,ARIMA_MaxP,ARIMA_MaxQ,&WOk);

	int buy = 0;
	int sell = 0;

	if(BOk && SOk && WOk)
	{
		if(bandPos < 40. and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			buy = 1;

		if(bandPos > 60. and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
}


void Module2_BB_RSI()
{
	if(!ModuleRuns(1)) return;

	TimeFrame = TF_H2;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_N);
	vars RSIS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H2)) return;
	if(!SessionOK(TF_H2)) return;

	var dip,dim;
	if(M2_UseRangeFilter)
		if(adxApprox(H,L,C,0,M2_ADX_Period,&dip,&dim) >= M2_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M2_BB_Period,M2_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M2_BB_Period,M2_BB_Dev,1,&m2,&u2,&l2);

	var r0 = rsiAt(C,0,M2_RSI_Period);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	BandPosS[0] = bandPos;
	RSIS[0] = clampv(r0,1.,99.);

	int BOk = 0;
	int ROk = 0;
	var bandF = ARIMAForecastSeries(BandPosS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&BOk);
	var rF = ARIMAForecastSeries(RSIS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&ROk);

	int buy = 0;
	int sell = 0;

	if(BOk && ROk)
	{
		if(bandPos < 42. and r0 < M2_RSI_OS+10.
			and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(bandPos > 58. and r0 > M2_RSI_OB-10.
			and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	var slDist = M2_SL_Mult*af*atr;
	var tpDist = M2_TP_Mult*af*atr;

	if(M2_TP_AtMid)
	{
		if(buy)
		{
			tpDist = max(m1-priceClose(0),0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max(priceClose(0)-(min(L[0],L[1])-M2_SL_Buffer*af*atr),0.5*af*atr);
			openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
		if(sell)
		{
			tpDist = max(priceClose(0)-m1,0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max((max(H[0],H[1])+M2_SL_Buffer*af*atr)-priceClose(0),0.5*af*atr);
			openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
	}
	else
	{
		if(buy) openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		if(sell) openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
	}
}


void Module3_Keltner_Stoch()
{
	if(!ModuleRuns(2)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars KPosS = series(0,ARIMA_N);
	vars StochS = series(0,ARIMA_N);

	var dip,dim;
	if(M3_UseRangeFilter)
		if(adxApprox(H,L,C,0,M3_ADX_Period,&dip,&dim) >= M3_ADX_RangeMax) return;

	var ema0 = emaAt(C,0,M3_EMA_Period);
	var atrK0 = atrAt(H,L,C,0,M3_ATR_Period);
	if(atrK0 <= 0) return;

	var k0,d0;
	stochAt(H,L,C,M3_Stoch_K,M3_Stoch_D,0,&k0,&d0);

	var kPos = 50.0 + 50.0*(C[0]-ema0)/fix0(M3_ATR_Mult*atrK0);
	kPos = clampv(kPos,1.,99.);

	KPosS[0] = kPos;
	StochS[0] = clampv(k0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int KOk = 0;
	int SOk = 0;
	var kPosF = ARIMAForecastSeries(KPosS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&KOk);
	var stF = ARIMAForecastSeries(StochS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&SOk);

	int buy = 0;
	int sell = 0;

	if(KOk && SOk)
	{
		if(kPos < 45. and ARIMAForecastUp(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stF,k0,ARIMA_MinOscDelta))
			buy = 1;

		if(kPos > 55. and ARIMAForecastDown(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stF,k0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
}


void Module4_Ichimoku_Stoch()
{
	if(!ModuleRuns(3)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars SpreadS = series(0,ARIMA_N);
	vars CloudS = series(0,ARIMA_N);
	vars StochS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M4_UseADXFilter)
		if(adxApprox(H,L,C,0,M4_ADX_Period,&dip,&dim) < M4_ADX_Min) return;

	var tenkan0 = (highestS(H,0,M4_Tenkan)+lowestS(L,0,M4_Tenkan))/2.0;
	var kijun0  = (highestS(H,0,M4_Kijun)+lowestS(L,0,M4_Kijun))/2.0;
	var senkouA = (tenkan0+kijun0)/2.0;
	var senkouB = (highestS(H,0,M4_Senkou)+lowestS(L,0,M4_Senkou))/2.0;
	var top = max(senkouA,senkouB);
	var bot = min(senkouA,senkouB);
	var cloudMid = (top+bot)/2.0;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;
	if(top-bot < atr*0.3) return;

	var k,d;
	stochAt(H,L,C,M4_Stoch_K,M4_Stoch_D,0,&k,&d);

	var spreadScore = 50.0 + 20.0*(tenkan0-kijun0)/atr;
	var cloudScore = 50.0 + 20.0*(C[0]-cloudMid)/atr;
	spreadScore = clampv(spreadScore,1.,99.);
	cloudScore = clampv(cloudScore,1.,99.);

	SpreadS[0] = spreadScore;
	CloudS[0] = cloudScore;
	StochS[0] = clampv(k,1.,99.);

	int SpOk = 0;
	int ClOk = 0;
	int StOk = 0;
	var spF = ARIMAForecastSeries(SpreadS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&SpOk);
	var clF = ARIMAForecastSeries(CloudS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&ClOk);
	var stF = ARIMAForecastSeries(StochS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&StOk);

	int buy = 0;
	int sell = 0;

	if(SpOk && ClOk && StOk)
	{
		if(spF > 52. and clF > 52.
			and ARIMAForecastUp(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF > k)
			buy = 1;

		if(spF < 48. and clF < 48.
			and ARIMAForecastDown(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF < k)
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
}


int superDir(vars H,vars L,vars C,int atrPeriod,var mult,int offset)
{
	var atr = atrAt(H,L,C,offset,atrPeriod);
	var mid = (H[offset]+L[offset])/2.0;
	if(C[offset] > mid + mult*atr*0.25) return 1;
	if(C[offset] < mid - mult*atr*0.25) return -1;
	return 0;
}

void Module5_Supertrend_RSI()
{
	if(!ModuleRuns(4)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PressureS = series(0,ARIMA_N);
	vars RSIS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M5_UseADXFilter)
		if(adxApprox(H,L,C,0,M5_ADX_Period,&dip,&dim) < M5_ADX_Min) return;

	var atrST = atrAt(H,L,C,0,M5_ATR_Period);
	if(atrST <= 0) return;

	var mid = (H[0]+L[0])/2.0;
	var pressure = 50.0 + 20.0*(C[0]-mid)/fix0(M5_ATR_Mult*atrST);
	pressure = clampv(pressure,1.,99.);

	var r0 = rsiAt(C,0,M5_RSI_Period);
	var emaT = emaAt(C,0,M5_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-emaT)/fix0(atrST);
	trendScore = clampv(trendScore,1.,99.);

	PressureS[0] = pressure;
	RSIS[0] = clampv(r0,1.,99.);
	TrendS[0] = trendScore;

	int POk = 0;
	int ROk = 0;
	int TOk = 0;
	var pF = ARIMAForecastSeries(PressureS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&POk);
	var rF = ARIMAForecastSeries(RSIS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&ROk);
	var tF = ARIMAForecastSeries(TrendS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && ROk && TOk)
	{
		if(pF > 52. and tF > 52. and rF > M5_RSI_BuyLo
			and ARIMAForecastUp(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 48. and tF < 48. and rF < M5_RSI_SellHi
			and ARIMAForecastDown(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);

	if(buy)
		openTradeDir(1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);

	if(sell)
		openTradeDir(-1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);
}


void Module6_EMA_ADX()
{
	if(!ModuleRuns(5)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars EmaS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);
	vars DiS = series(0,ARIMA_N);
	vars AdxS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var eF0 = emaAt(C,0,M6_EMA_Fast);
	var eS0 = emaAt(C,0,M6_EMA_Slow);
	var eT0 = emaAt(C,0,M6_EMA_Trend);
	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var dp,dm;
	var adx0 = adxApprox(H,L,C,0,M6_ADX_Period,&dp,&dm);

	var emaScore = 50.0 + 20.0*(eF0-eS0)/atr;
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	var diScore = 50.0 + (dp-dm);
	emaScore = clampv(emaScore,1.,99.);
	trendScore = clampv(trendScore,1.,99.);
	diScore = clampv(diScore,1.,99.);

	EmaS[0] = emaScore;
	TrendS[0] = trendScore;
	DiS[0] = diScore;
	AdxS[0] = clampv(adx0,1.,99.);

	int EOk = 0;
	int TOk = 0;
	int DOk = 0;
	int AOk = 0;
	var eF = ARIMAForecastSeries(EmaS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&EOk);
	var tF = ARIMAForecastSeries(TrendS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&TOk);
	var dF = ARIMAForecastSeries(DiS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&DOk);
	var aF = ARIMAForecastSeries(AdxS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&AOk);

	int buy = 0;
	int sell = 0;

	if(EOk && TOk && DOk && AOk)
	{
		if(eF > 52. and tF > 52. and dF > 52. and aF > M6_ADX_Min
			and ARIMAForecastUp(eF,emaScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(eF < 48. and tF < 48. and dF < 48. and aF > M6_ADX_Min
			and ARIMAForecastDown(eF,emaScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
}


void Module7_Donchian()
{
	if(!ModuleRuns(6)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PosS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M7_UseADXFilter)
		if(adxApprox(H,L,C,0,M7_ADX_Period,&dp,&dm) < M7_ADX_Min) return;

	var dHi = highestS(H,1,M7_Donch_Period);
	var dLo = lowestS(L,1,M7_Donch_Period);
	var width = dHi-dLo;
	if(width <= 0) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var pos = 100.0*(C[0]-dLo)/width;
	pos = clampv(pos,1.,99.);

	var eT0 = emaAt(C,0,M7_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	PosS[0] = pos;
	TrendS[0] = trendScore;

	int POk = 0;
	int TOk = 0;
	var pF = ARIMAForecastSeries(PosS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&POk);
	var tF = ARIMAForecastSeries(TrendS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && TOk)
	{
		if(pF > 80. and tF > 52.
			and ARIMAForecastUp(pF,pos,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 20. and tF < 48.
			and ARIMAForecastDown(pF,pos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M7_MaxExtATR > 0 && atr > 0)
	{
		if(buy && (C[0]-dHi) > M7_MaxExtATR*atr) buy = 0;
		if(sell && (dLo-C[0]) > M7_MaxExtATR*atr) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
}


void Module8_MACD_EMA()
{
	if(!ModuleRuns(7)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars HistS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M8_UseADXFilter)
		if(adxApprox(H,L,C,0,M8_ADX_Period,&dp,&dm) < M8_ADX_Min) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var macd0 = macdLineAt(C,0,M8_MACD_Fast,M8_MACD_Slow);
	var sig0 = macdSignalAt(C,0,M8_MACD_Fast,M8_MACD_Slow,M8_MACD_Signal);
	var hist = macd0-sig0;
	var histScore = 50.0 + 50.0*hist/atr;
	histScore = clampv(histScore,1.,99.);

	var eT0 = emaAt(C,0,M8_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	HistS[0] = histScore;
	TrendS[0] = trendScore;

	int HOk = 0;
	int TOk = 0;
	var hF = ARIMAForecastSeries(HistS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&HOk);
	var tF = ARIMAForecastSeries(TrendS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&TOk);

	int buy = 0;
	int sell = 0;

	if(HOk && TOk)
	{
		if(hF > 52. and tF > 52.
			and ARIMAForecastUp(hF,histScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(hF < 48. and tF < 48.
			and ARIMAForecastDown(hF,histScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
}


void Module9_RSI_MR()
{
	if(!ModuleRuns(8)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars RSIS = series(0,ARIMA_N);

	var dp,dm;
	if(M9_UseRangeFilter)
		if(adxApprox(H,L,C,0,M9_ADX_Period,&dp,&dm) >= M9_ADX_RangeMax) return;

	var r0 = rsiAt(C,0,M9_RSI_Period);
	var r2 = rsiAt(C,2,M9_RSI_Period);

	RSIS[0] = clampv(r0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int ROk = 0;
	var rF = ARIMAForecastSeries(RSIS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&ROk);

	int buy = 0;
	int sell = 0;

	if(ROk)
	{
		if(r0 < 45. and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(r0 > 55. and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M9_RequireSustain)
	{
		if(buy && r2 > 50.) buy = 0;
		if(sell && r2 < 50.) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
}


void Module10_BB_Squeeze()
{
	if(!ModuleRuns(9)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars WidthS = series(0,ARIMA_N);
	vars PosS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M10_UseADXFilter)
		if(adxApprox(H,L,C,0,M10_ADX_Period,&dp,&dm) < M10_ADX_Min) return;

	var m0,u0,l0;
	bbAt(C,M10_BB_Period,M10_BB_Dev,0,&m0,&u0,&l0);
	var range = u0-l0;
	if(range <= 0) return;

	var avgW = 0;
	int i;
	for(i=1;i<21;i++)
	{
		var mi,ui,li;
		bbAt(C,M10_BB_Period,M10_BB_Dev,i,&mi,&ui,&li);
		avgW += (ui-li)/fix0(mi);
	}
	avgW /= 20.0;

	var widthNow = range/fix0(m0);
	if(widthNow <= 0) widthNow = 0.0001;

	var bandPos = 100.0*(C[0]-l0)/range;
	bandPos = clampv(bandPos,1.,99.);

	WidthS[0] = widthNow;
	PosS[0] = bandPos;

	int WOk = 0;
	int POk = 0;
	var wF = ARIMAForecastSeries(WidthS,ARIMA_N,0.0001,ARIMA_MaxP,ARIMA_MaxQ,&WOk);
	var pF = ARIMAForecastSeries(PosS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&POk);

	int buy = 0;
	int sell = 0;

	if(WOk && POk)
	{
		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF > 62. and ARIMAForecastUp(pF,bandPos,ARIMA_MinOscDelta))
			buy = 1;

		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF < 38. and ARIMAForecastDown(pF,bandPos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M10_UseTrendAlign)
	{
		var e = emaAt(C,0,M10_TrendEMA);
		if(C[0] <= e) buy = 0;
		if(C[0] >= e) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
}


void Module11_Grey()
{
	if(!ModuleRuns(10)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars O = series(priceOpen());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars GreyS = series(0,ARIMA_N);
	vars SlopeS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var g0 = greyMA(O,0,M11_Period);
	var g1 = greyMA(O,1,M11_Period);

	var greyScore = 50.0 + 20.0*(g0-O[0])/atr;
	var greySlope = 50.0 + 20.0*(g0-g1)/atr;
	greyScore = clampv(greyScore,1.,99.);
	greySlope = clampv(greySlope,1.,99.);

	GreyS[0] = greyScore;
	SlopeS[0] = greySlope;

	int GOk = 0;
	int SOk = 0;
	var gF = ARIMAForecastSeries(GreyS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&GOk);
	var sF = ARIMAForecastSeries(SlopeS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&SOk);

	int buy = 0;
	int sell = 0;

	if(GOk && SOk)
	{
		if(gF > 52. and sF > 52.
			and ARIMAForecastUp(gF,greyScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(gF < 48. and sF < 48.
			and ARIMAForecastDown(gF,greyScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M11_UseTrendFilter)
	{
		var e = emaAt(C,0,M11_TrendEMA);
		if(O[0] <= e) buy = 0;
		if(O[0] >= e) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
}


void Module12_Flag()
{
	if(!ModuleRuns(11)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PoleS = series(0,ARIMA_N);
	vars BreakS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	int fB = M12_FlagBars;
	int pB = M12_PoleBars;

	int pNew = fB+1;
	int pOld = fB+pB;
	var poleMove = C[pNew]-C[pOld];

	var poleHigh = H[pNew];
	var poleLow = L[pNew];
	int k;
	for(k=pNew;k<=pOld;k++)
	{
		if(H[k] > poleHigh) poleHigh = H[k];
		if(L[k] < poleLow) poleLow = L[k];
	}

	var poleHeight = poleHigh-poleLow;
	if(poleHeight <= 0) return;

	var flagHigh = H[1];
	var flagLow = L[1];
	for(k=1;k<=fB;k++)
	{
		if(H[k] > flagHigh) flagHigh = H[k];
		if(L[k] < flagLow) flagLow = L[k];
	}

	if((flagHigh-flagLow) > M12_FlagMaxATR*atr) return;

	var flagMid = (flagHigh+flagLow)/2.0;
	var poleScore = 50.0 + 10.0*poleMove/atr;
	var breakScore = 50.0 + 20.0*(C[0]-flagMid)/atr;
	poleScore = clampv(poleScore,1.,99.);
	breakScore = clampv(breakScore,1.,99.);

	PoleS[0] = poleScore;
	BreakS[0] = breakScore;

	int POk = 0;
	int BOk = 0;
	var pF = ARIMAForecastSeries(PoleS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&POk);
	var bF = ARIMAForecastSeries(BreakS,ARIMA_N,0.01,ARIMA_MaxP,ARIMA_MaxQ,&BOk);

	int buy = 0;
	int sell = 0;

	if(POk && BOk)
	{
		if(pF > 55. and bF > 55.
			and ARIMAForecastUp(bF,breakScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(pF < 45. and bF < 45.
			and ARIMAForecastDown(bF,breakScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M12_UseTrendFilter)
	{
		var ma = smaAt(C,0,M12_MA_Period);
		if(C[0] <= ma) buy = 0;
		if(C[0] >= ma) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	var slDist = poleHeight*M12_SL_PoleMult*af;
	var tpDist = poleHeight*M12_TP_PoleMult*af;

	if(buy) openTradeDir(1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
}


// -----------------------------------------------------------------------------
// End-of-test CSV style log
// -----------------------------------------------------------------------------

void logClosedTrades()
{
	if(!is(EXITRUN)) return;

	file_delete("Log\\MultiStrategy_Trades_Zorro.csv");
	file_append("Log\\MultiStrategy_Trades_Zorro.csv",
		"asset,algo,profit\n",0);

	for(closed_trades)
	{
		file_append("Log\\MultiStrategy_Trades_Zorro.csv",
			strf("%s,%s,%.2f\n",Asset,Algo,(var)TradeProfit),0);
	}
}

// -----------------------------------------------------------------------------
// Main strategy
// -----------------------------------------------------------------------------

function run()
{
	set(PARAMETERS|OFF);

	BarPeriod = 30;
	LookBack = 2000;
	Capital = FixedRiskBalance;
	Hedge = 2;        // allow independent long/short components in backtest
	Fill = 3;         // more realistic order filling; adjust to your broker/data
	Slippage = 0;
	Spread = Spread; // keep asset-list spread

	if(is(INITRUN))
	{
		printf("\nArimaIndicatorMatrix v01 started.");
		printf("\nIndicator states are forecast with AutoAri before module signals.");
	}

	int i;
	for(i=0;i<NUM_SYMBOLS;i++)
	{
		if(!SymbolEnabled(i))
			continue;

		if(!asset(SymbolName(i)))
			continue;

		// Run all converted modules. ModuleRuns() applies the v8.11 instrument gating.
		Module1_BB_Stoch();
		Module2_BB_RSI();
		Module3_Keltner_Stoch();
		Module4_Ichimoku_Stoch();
		Module5_Supertrend_RSI();
		Module6_EMA_ADX();
		Module7_Donchian();
		Module8_MACD_EMA();
		Module9_RSI_MR();
		Module10_BB_Squeeze();
		Module11_Grey();
		Module12_Flag();

		TimeFrame = 1;
	}

	if(is(EXITRUN))
		FreeARIMA();

	logClosedTrades();
}

Arima Indicator Matrix (v2) [Re: TipmyPip] #489453
Yesterday at 12:34
Yesterday at 12:34
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
The following strategy is a multi module trading strategy that changes traditional technical analysis into a forecast driven decision process. Instead of using indicators only as fixed entry triggers, it converts each indicator into a normalized state and asks whether that state is expected to improve or weaken. Bollinger position, stochastic movement, RSI behavior, Keltner pressure, Ichimoku cloud relation, Supertrend pressure, EMA drift, ADX strength, Donchian range position, MACD flow, squeeze energy, Grey model path, and flag continuation are all treated as individual forecast streams. Each stream is passed to the ARIMA package as a proper time series, so the model predicts the next likely indicator state rather than simply confirming price direction. The strategy then compares the forecast with the current indicator condition and opens trades only when the predicted direction agrees with the module logic, market regime, session filter, volatility context, and risk controls. IOPa07 also adds a meta prediction layer that studies whether earlier indicator forecasts were successful. This creates a second level of analysis where the system measures trust in each prediction stream. The trade logic therefore depends on both the expected movement of an indicator and the recent reliability of that indicator forecast. In mathematical terms, the strategy is a layered forecasting framework where indicator state, forecast direction, forecast error, volatility, and regime context are combined into adaptive trading decisions. Its main purpose is to make indicator signals forward looking rather than reactive.

Code
// ArimaIndicatorMatrix_v02_meta.c

#define NUM_MODULES 12
#define TF_M30 1
#define TF_H1  2
#define TF_H2  4
#define TF_H4  8
#define TF_D1  48

// -----------------------------------------------------------------------------
// ARIMA package interface
// -----------------------------------------------------------------------------
// UseARIMAFilter is the old close-price confirmation filter.
// The main strategy below does not rely on that old filter. It creates ARIMA
// forecasts of the module indicator series themselves.
// -----------------------------------------------------------------------------

#define PRAGMA_API init_auto_arima_result;AutoAri32!init_auto_arima_result
#define PRAGMA_API free_auto_arima_result;AutoAri32!free_auto_arima_result
#define PRAGMA_API auto_arima_forecast;AutoAri32!auto_arima_forecast
#define PRAGMA_API aa_validate_price_series;AutoAri32!aa_validate_price_series

int UseARIMAFilter = 0; // old close-price gate; indicator ARIMA is the main logic
int ARIMA_N = 160;          // number of close prices used for the forecast
int ARIMA_MaxP = 3;         // maximum AR order searched by auto_arima_forecast
int ARIMA_MaxQ = 3;         // maximum MA order searched by auto_arima_forecast
var ARIMA_MinPips = 2.0;    // minimum forecast edge in pips
int ARIMA_PlotForecast = 0; // plots old price forecast only if UseARIMAFilter is enabled

int UseARIMAIndicatorPrediction = 1;
var ARIMA_MinOscDelta = 0.75;    // RSI/Stoch/Band position forecast delta
var ARIMA_MinTrendDelta = 0.60;  // trend/pressure forecast delta
var ARIMA_MinWidthDelta = 0.00001;

// -----------------------------------------------------------------------------
// ARIMA meta-prediction layer
// -----------------------------------------------------------------------------
// This layer measures the previous success rate of every indicator forecast.
// It then applies auto_arima_forecast(...) to the hit/miss stream itself.
// The CSV output lets us later discover under which indicator conditions the
// ARIMA prediction stream was reliable.
//
// Hit stream scale:
//   80 = previous forecast direction was correct
//   20 = previous forecast direction was wrong
//   50 = previous forecast edge was too small / neutral

#define META_FIELD_SLOTS 28
#define META_SERIES_CAP 80
#define META_RATE_CAP 20

int UseARIMAMetaPrediction = 1;
int UseARIMAMetaLog = 1;
int ARIMA_MetaN = META_SERIES_CAP;
int ARIMA_MetaRateN = META_RATE_CAP;

var GMetaForecast[META_FIELD_SLOTS][META_SERIES_CAP];
var GMetaHit[META_FIELD_SLOTS][META_SERIES_CAP];
int GMetaInitialized[META_FIELD_SLOTS];
int GMetaLastBar[META_FIELD_SLOTS];

typedef struct AUTO_ARIMA_RESULT
{
	int p;
	int d;
	int q;
	int converged;
	var sse;
	var aicc;
	var forecast;
	var* ar;
	var* ma;
	int arCap;
	int maCap;
} AUTO_ARIMA_RESULT;

AUTO_ARIMA_RESULT GArimaResult;
int GArimaInitialized = 0;

// ARIMA DLL imports.
// The README signature for auto_arima_forecast is:
// int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result)
int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result);
int aa_validate_price_series(vars Close,int N);
void init_auto_arima_result(AUTO_ARIMA_RESULT* R);
void free_auto_arima_result(AUTO_ARIMA_RESULT* R);

void InitARIMAOnce()
{
	if(GArimaInitialized)
		return;

	init_auto_arima_result(&GArimaResult);
	GArimaInitialized = 1;
}

void ResetARIMAResult()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	init_auto_arima_result(&GArimaResult);
}

int ARIMAAllowsDirection(int dir,vars C)
{
	if(!UseARIMAFilter)
		return 1;

	if(ARIMA_N < 30)
		return 1;

	if(Bar < LookBack)
		return 0;

	InitARIMAOnce();

	// Avoid accumulating result-owned coefficient arrays between calls.
	ResetARIMAResult();

	if(!aa_validate_price_series(C,ARIMA_N))
		return 0;

	int ok = auto_arima_forecast(C,ARIMA_N,PIP,ARIMA_MaxP,ARIMA_MaxQ,&GArimaResult);

	if(!ok)
	{
		printf("\nARIMA forecast failed: Asset=%s Algo=%s Bar=%i",Asset,Algo,Bar);
		return 0;
	}

	var Threshold = ARIMA_MinPips*PIP;
	var Edge = GArimaResult.forecast - C[0];
	int Signal = 0;
	if(Edge > Threshold)
		Signal = 1;
	else if(Edge < -Threshold)
		Signal = -1;

	if(ARIMA_PlotForecast)
		plot("ARIMA Forecast",GArimaResult.forecast,LINE,BLUE);

	if(dir > 0 && Signal > 0)
		return 1;

	if(dir < 0 && Signal < 0)
		return 1;

	return 0;
}

var ARIMAForecastSeries(vars Data,int N,var TickSize,int MaxP,int MaxQ,int* OK)
{
	*OK = 0;

	if(!UseARIMAIndicatorPrediction)
	{
		*OK = 1;
		return Data[0];
	}

	if(N < 30)
		return Data[0];

	if(Bar < LookBack)
		return Data[0];

	InitARIMAOnce();
	ResetARIMAResult();

	if(!aa_validate_price_series(Data,N))
		return Data[0];

	int Status = auto_arima_forecast(
		Data,
		N,
		TickSize,
		MaxP,
		MaxQ,
		&GArimaResult
	);

	if(!Status)
		return Data[0];

	if(!GArimaResult.converged)
		return Data[0];

	if(invalid(GArimaResult.forecast))
		return Data[0];

	*OK = 1;
	return GArimaResult.forecast;
}

int ARIMAForecastUp(var Forecast,var CurrentValue,var MinDelta)
{
	if(Forecast - CurrentValue > MinDelta)
		return 1;
	return 0;
}

int ARIMAForecastDown(var Forecast,var CurrentValue,var MinDelta)
{
	if(CurrentValue - Forecast > MinDelta)
		return 1;
	return 0;
}

var ARIMAMetaRate(vars HitS,int N)
{
	if(N < 1)
		return 0.50;

	var Sum = 0;
	int i;
	for(i=0;i<N;i++)
		Sum += HitS[i];

	return clamp((Sum/N)/100.0,0.,1.);
}

int MetaFieldSlot(string ModuleName,string FieldName)
{
	if(strstr(ModuleName,"AP1_BandOsc")) {
		if(strstr(FieldName,"band")) return 0;
		if(strstr(FieldName,"stoch")) return 1;
		if(strstr(FieldName,"width")) return 2;
	}
	if(strstr(ModuleName,"AP2_RSIState")) {
		if(strstr(FieldName,"band")) return 3;
		if(strstr(FieldName,"rsi")) return 4;
	}
	if(strstr(ModuleName,"AP3_ChannelOsc")) {
		if(strstr(FieldName,"kpos")) return 5;
		if(strstr(FieldName,"stoch")) return 6;
	}
	if(strstr(ModuleName,"AP4_CloudFlow")) {
		if(strstr(FieldName,"spread")) return 7;
		if(strstr(FieldName,"cloud")) return 8;
		if(strstr(FieldName,"stoch")) return 9;
	}
	if(strstr(ModuleName,"AP5_Pressure")) {
		if(strstr(FieldName,"pressure")) return 10;
		if(strstr(FieldName,"rsi")) return 11;
		if(strstr(FieldName,"trend")) return 12;
	}
	if(strstr(ModuleName,"AP6_DriftADX")) {
		if(strstr(FieldName,"ema")) return 13;
		if(strstr(FieldName,"trend")) return 14;
		if(strstr(FieldName,"di")) return 15;
		if(strstr(FieldName,"adx")) return 16;
	}
	if(strstr(ModuleName,"AP7_RangeFlow")) {
		if(strstr(FieldName,"pos")) return 17;
		if(strstr(FieldName,"trend")) return 18;
	}
	if(strstr(ModuleName,"AP8_MacdFlow")) {
		if(strstr(FieldName,"hist")) return 19;
		if(strstr(FieldName,"trend")) return 20;
	}
	if(strstr(ModuleName,"AP9_RSIPath")) return 21;
	if(strstr(ModuleName,"AP10_BandEnergy")) {
		if(strstr(FieldName,"width")) return 22;
		if(strstr(FieldName,"pos")) return 23;
	}
	if(strstr(ModuleName,"AP11_GreyPath")) {
		if(strstr(FieldName,"grey")) return 24;
		if(strstr(FieldName,"slope")) return 25;
	}
	if(strstr(ModuleName,"AP12_ShapePath")) {
		if(strstr(FieldName,"pole")) return 26;
		if(strstr(FieldName,"break")) return 27;
	}
	return -1;
}

void MetaShift(var* Data,int Count)
{
	int i;
	for(i=Count-1;i>0;i--)
		Data[i] = Data[i-1];
}

void EnsureMetaSlot(int Slot,var ForecastValue)
{
	int i;
	if(Slot < 0 || Slot >= META_FIELD_SLOTS)
		return;

	if(!GMetaInitialized[Slot])
	{
		for(i=0;i<META_SERIES_CAP;i++)
		{
			GMetaForecast[Slot][i] = ForecastValue;
			GMetaHit[Slot][i] = 50.;
		}
		GMetaInitialized[Slot] = 1;
		GMetaLastBar[Slot] = Bar;
		return;
	}

	if(GMetaLastBar[Slot] != Bar)
	{
		MetaShift(&GMetaForecast[Slot][0],META_SERIES_CAP);
		MetaShift(&GMetaHit[Slot][0],META_SERIES_CAP);
		GMetaLastBar[Slot] = Bar;
	}
}

var ARIMAMetaRel(vars ValueS,vars ForecastS,vars HitS,var MinDelta,int* OK)
{
	*OK = 0;

	if(!UseARIMAMetaPrediction)
	{
		*OK = 1;
		return 1.0;
	}

	var PrevEdge = ForecastS[1] - ValueS[1];
	var ActualMove = ValueS[0] - ValueS[1];
	var Hit = 50.0;

	if(abs(PrevEdge) > MinDelta)
	{
		if(PrevEdge * ActualMove > 0)
			Hit = 80.0;
		else
			Hit = 20.0;
	}

	HitS[0] = Hit;

	int HOk = 0;
	var HF = ARIMAForecastSeries(HitS,ARIMA_MetaN,0.01,ARIMA_MaxP,ARIMA_MaxQ,&HOk);

	if(!HOk)
		return ARIMAMetaRate(HitS,ARIMA_MetaRateN);

	*OK = 1;
	return clamp(HF/100.0,0.,1.);
}

var ARIMAForecastMeta(string ModuleName,string FieldName,vars Data,int N,var TickSize,var MinDelta,int* OK)
{
	int RawOK = 0;
	var F = ARIMAForecastSeries(Data,N,TickSize,ARIMA_MaxP,ARIMA_MaxQ,&RawOK);
	int Slot = MetaFieldSlot(ModuleName,FieldName);
	int MetaOK = 0;
	var Rel = 1.0;
	var Rate = 0.50;

	if(Slot >= 0)
	{
		EnsureMetaSlot(Slot,F);
		GMetaForecast[Slot][0] = F;
		Rel = ARIMAMetaRel(Data,&GMetaForecast[Slot][0],&GMetaHit[Slot][0],MinDelta,&MetaOK);
		Rate = ARIMAMetaRate(&GMetaHit[Slot][0],ARIMA_MetaRateN);
	}

	if(UseARIMAMetaLog)
	{
		file_append("Log\\ArimaIndicatorMeta.csv",
			strf("%s,%i,%s,%s,%.6f,%.6f,%.6f,%.4f,%.4f,%i,%i\n",
				Asset,Bar,ModuleName,FieldName,Data[0],F,F-Data[0],Rate,Rel,RawOK,MetaOK),0);
	}

	*OK = RawOK;
	return F;
}

void FreeARIMA()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	GArimaInitialized = 0;
}


// -----------------------------------------------------------------------------
// Global inputs
// -----------------------------------------------------------------------------

var RiskPercent = 2.0;
int ATR_Period = 14;

int UseSessionFilter = 1;
int SessionStartHour = 7;
int SessionEndHour = 20;

int UseFixedRiskBase = 1;
var FixedRiskBalance = 10000;
var MaxLotCap = 0; // not used directly; Zorro sizes through Risk/Margin/Lots.

int UseTrailing = 1;
int UseBreakeven = 1;

int UseRegimeDirection = 1;
int Regime_MA = 200;
int Regime_UseSlope = 1;
int Regime_NeutralAllowBoth = 1;
int AllowLongs = 1;
int AllowShorts = 0;

int UseTrendQualityGate = 1;
int TQ_ADX_Period = 14;
var TQ_ADX_Min = 18.0;

int UseRiskCap = 1;
var MaxPortfolioRiskPct = 15.0;
int MaxOpenPositions = 12;

int UseAdaptiveMults = 1;
int Adapt_FastATR = 14;
int Adapt_SlowATR = 100;
var Adapt_Min = 0.75;
var Adapt_Max = 1.50;

// Module master switches
int Use_BB_Stoch       = 1; // M1
int Use_BB_RSI         = 1; // M2
int Use_Keltner_Stoch  = 1; // M3
int Use_Ichimoku_Stoch = 1; // M4
int Use_Supertrend_RSI = 1; // M5
int Use_EMA_ADX        = 1; // M6
int Use_Donchian       = 1; // M7
int Use_MACD_EMA       = 1; // M8
int Use_RSI_MR         = 1; // M9
int Use_BB_Squeeze     = 1; // M10
int Use_Grey           = 1; // M11
int Use_Flag           = 1; // M12

// M1
int M1_BB_Period = 20; var M1_BB_Dev = 2.0;
int M1_Stoch_K = 14; int M1_Stoch_D = 3; int M1_Stoch_Slowing = 3;
var M1_Stoch_OS = 20.0; var M1_Stoch_OB = 80.0;
int M1_UseRangeFilter = 1; int M1_ADX_Period = 14; var M1_ADX_RangeMax = 25.0;
int M1_UseReversionConfirm = 1;
var M1_TrailMult = 1.0; var M1_TrailStart = 1.0;
var M1_BE_Mult = 1.0; var M1_SL_Mult = 1.5; var M1_TP_Mult = 1.5;

// M2
int M2_BB_Period = 20; var M2_BB_Dev = 2.0;
int M2_RSI_Period = 14; var M2_RSI_OS = 30.0; var M2_RSI_OB = 70.0;
int M2_UseRangeFilter = 1; int M2_ADX_Period = 14; var M2_ADX_RangeMax = 25.0;
int M2_UseReversionConfirm = 1;
int M2_TP_AtMid = 1;
int M2_StructuralSL = 1;
var M2_SL_Buffer = 0.5;
var M2_TrailMult = 1.0; var M2_TrailStart = 0.8;
var M2_BE_Mult = 1.0; var M2_SL_Mult = 1.5; var M2_TP_Mult = 2.0;

// M3
int M3_EMA_Period = 20; int M3_ATR_Period = 10; var M3_ATR_Mult = 2.0;
int M3_Stoch_K = 14; int M3_Stoch_D = 3; int M3_Stoch_Slowing = 3;
var M3_Stoch_OS = 20.0; var M3_Stoch_OB = 80.0;
int M3_UseRangeFilter = 0; int M3_ADX_Period = 14; var M3_ADX_RangeMax = 25.0;
var M3_TrailMult = 1.5; var M3_TrailStart = 1.0;
var M3_BE_Mult = 1.0; var M3_SL_Mult = 1.5; var M3_TP_Mult = 2.5;

// M4
int M4_Tenkan = 9; int M4_Kijun = 26; int M4_Senkou = 52;
int M4_Stoch_K = 14; int M4_Stoch_D = 3; int M4_Stoch_Slowing = 3;
var M4_Stoch_OS = 40.0; var M4_Stoch_OB = 60.0;
int M4_UseADXFilter = 0; int M4_ADX_Period = 14; var M4_ADX_Min = 20.0;
var M4_TrailMult = 2.0; var M4_TrailStart = 1.5;
var M4_BE_Mult = 1.0; var M4_SL_Mult = 1.5; var M4_TP_Mult = 3.0;

// M5
int M5_ATR_Period = 10; var M5_ATR_Mult = 3.0;
int M5_RSI_Period = 14; var M5_RSI_OS = 35.0; var M5_RSI_OB = 65.0;
var M5_RSI_BuyLo = 40.0; var M5_RSI_SellHi = 60.0;
int M5_UseADXFilter = 1; int M5_ADX_Period = 14; var M5_ADX_Min = 25.0;
int M5_UseTrendAlign = 1; int M5_TrendEMA = 100;
int M5_MomConfirm = 1;
var M5_TrailMult = 2.5; var M5_TrailStart = 1.5;
var M5_BE_Mult = 1.0; var M5_SL_Mult = 1.5; var M5_TP_Mult = 3.0;

// M6
int M6_EMA_Fast = 9; int M6_EMA_Slow = 21; int M6_EMA_Trend = 50;
int M6_ADX_Period = 14; var M6_ADX_Min = 25.0; var M6_DI_Sep = 3.0;
int M6_RequirePullback = 0; int M6_UseSlopeFilter = 1;
var M6_TrailMult = 2.0; var M6_TrailStart = 1.5;
var M6_BE_Mult = 1.0; var M6_SL_Mult = 1.5; var M6_TP_Mult = 3.0;

// M7
int M7_Donch_Period = 20;
int M7_UseADXFilter = 1; int M7_ADX_Period = 14; var M7_ADX_Min = 30.0;
int M7_UseTrendAlign = 1; int M7_TrendEMA = 100;
int M7_UseSlopeFilter = 1;
var M7_MaxExtATR = 1.0;
var M7_TrailMult = 2.5; var M7_TrailStart = 1.5;
var M7_BE_Mult = 1.0; var M7_SL_Mult = 1.5; var M7_TP_Mult = 3.5;

// M8
int M8_MACD_Fast = 12; int M8_MACD_Slow = 26; int M8_MACD_Signal = 9;
int M8_TrendEMA = 100;
int M8_RequireZeroSide = 1;
int M8_UseSlopeFilter = 0;
int M8_UseADXFilter = 1; int M8_ADX_Period = 14; var M8_ADX_Min = 20.0;
var M8_TrailMult = 2.0; var M8_TrailStart = 1.5;
var M8_BE_Mult = 1.0; var M8_SL_Mult = 1.5; var M8_TP_Mult = 3.0;

// M9
int M9_RSI_Period = 14; var M9_RSI_OS = 35.0; var M9_RSI_OB = 65.0;
int M9_UseRangeFilter = 1; int M9_ADX_Period = 14; var M9_ADX_RangeMax = 25.0;
int M9_RequireSustain = 1;
var M9_TrailMult = 1.0; var M9_TrailStart = 0.8;
var M9_BE_Mult = 1.0; var M9_SL_Mult = 1.5; var M9_TP_Mult = 1.8;

// M10
int M10_BB_Period = 20; var M10_BB_Dev = 2.0; var M10_SqueezeRatio = 0.8;
int M10_UseADXFilter = 1; int M10_ADX_Period = 14; var M10_ADX_Min = 30.0;
int M10_UseTrendAlign = 1; int M10_TrendEMA = 100;
var M10_TrailMult = 2.5; var M10_TrailStart = 1.5;
var M10_BE_Mult = 1.0; var M10_SL_Mult = 1.5; var M10_TP_Mult = 3.5;

// M11
int M11_Period = 24;
int M11_Filter = 250;
int M11_UseTrendFilter = 1; int M11_TrendEMA = 100;
int M11_RequirePersist = 1;
var M11_TrailMult = 2.0; var M11_TrailStart = 1.5;
var M11_BE_Mult = 1.0; var M11_SL_Mult = 1.5; var M11_TP_Mult = 3.0;

// M12
int M12_PoleBars = 5;
var M12_PoleATRMult = 1.8;
int M12_FlagBars = 5;
var M12_FlagMaxATR = 1.6;
int M12_UseTrendFilter = 1; int M12_MA_Period = 200;
var M12_SL_PoleMult = 1.0;
var M12_TP_PoleMult = 1.5;
var M12_TrailMult = 2.5; var M12_TrailStart = 1.5;
var M12_BE_Mult = 1.0;

// Zorro asset names. Adjust to your Assets*.csv / broker mapping.
// lite-C can be picky with global string-array initializers, so use a function
// instead of: string Symbols[3] = { "EUR/USD", "GBP/USD", "XAU/USD" };
#define NUM_SYMBOLS 3

int Use_EURUSD = 1;
int Use_GBPUSD = 0; // enable after importing GBPUSD history files
int Use_XAUUSD = 0; // enable after importing XAUUSD history files

string SymbolName(int Index)
{
	if(Index == 0) return "EUR/USD";
	if(Index == 1) return "GBP/USD";
	if(Index == 2) return "XAU/USD";
	return "";
}

int SymbolEnabled(int Index)
{
	if(Index == 0) return Use_EURUSD;
	if(Index == 1) return Use_GBPUSD;
	if(Index == 2) return Use_XAUUSD;
	return 0;
}

// -----------------------------------------------------------------------------
// Utility
// -----------------------------------------------------------------------------

int contains(string s,string token)
{
	if(strstr(s,token) != 0) return 1;
	return 0;
}

int isForexAsset()
{
	if(contains(Asset,"EUR")) return 1;
	if(contains(Asset,"GBP")) return 1;
	if(contains(Asset,"USD") && !contains(Asset,"XAU")) return 1;
	return 0;
}

int isMetalAsset()
{
	if(contains(Asset,"XAU")) return 1;
	if(contains(Asset,"XAG")) return 1;
	if(contains(Asset,"GOLD")) return 1;
	if(contains(Asset,"SILVER")) return 1;
	return 0;
}

int ModuleRuns(int idx)
{
	if(idx == 0 && !Use_BB_Stoch) return 0;
	if(idx == 1 && !Use_BB_RSI) return 0;
	if(idx == 2 && !Use_Keltner_Stoch) return 0;
	if(idx == 3 && !Use_Ichimoku_Stoch) return 0;
	if(idx == 4 && !Use_Supertrend_RSI) return 0;
	if(idx == 5 && !Use_EMA_ADX) return 0;
	if(idx == 6 && !Use_Donchian) return 0;
	if(idx == 7 && !Use_MACD_EMA) return 0;
	if(idx == 8 && !Use_RSI_MR) return 0;
	if(idx == 9 && !Use_BB_Squeeze) return 0;
	if(idx == 10 && !Use_Grey) return 0;
	if(idx == 11 && !Use_Flag) return 0;

	// v8.11 logic from the uploaded EA:
	// FOREX = M3 + M9 only.
	if(isForexAsset())
	{
		if(idx == 2) return 1;
		if(idx == 8) return 1;
		return 0;
	}

	// METALS = M3,M5,M6,M7,M8,M9,M10,M12.
	if(isMetalAsset())
	{
		if(idx == 2) return 1;
		if(idx == 4) return 1;
		if(idx == 5) return 1;
		if(idx == 6) return 1;
		if(idx == 7) return 1;
		if(idx == 8) return 1;
		if(idx == 9) return 1;
		if(idx == 11) return 1;
		return 0;
	}

	return 1;
}

int IsModuleBar(int tf)
{
	if(tf <= 1) return 1;
	if(Bar % tf == 0) return 1;
	return 0;
}

int SessionOK(int tf)
{
	if(!UseSessionFilter) return 1;
	if(tf >= TF_D1) return 1;
	if(hour(0) >= SessionStartHour && hour(0) < SessionEndHour) return 1;
	return 0;
}

int CountTotalOpen()
{
	int n = 0;
	for(open_trades)
		n++;
	return n;
}

int CurrentAlgoHasOpen()
{
	int n = 0;
	for(current_trades)
		n++;
	if(n > 0) return 1;
	return 0;
}

var clampv(var x,var lo,var hi)
{
	if(x < lo) return lo;
	if(x > hi) return hi;
	return x;
}

var highestS(vars Data,int offset,int period)
{
	var h = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] > h) h = Data[i];
	return h;
}

var lowestS(vars Data,int offset,int period)
{
	var l = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] < l) l = Data[i];
	return l;
}

var smaAt(vars Data,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += Data[i];
	return sum/period;
}

var stdAt(vars Data,int offset,int period)
{
	var m = smaAt(Data,offset,period);
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += (Data[i]-m)*(Data[i]-m);
	return sqrt(sum/period);
}

var emaAt(vars Data,int offset,int period)
{
	int start = offset + period*3;
	var a = 2.0/(period+1.0);
	var e = Data[start];
	int i;
	for(i=start-1;i>=offset;i--)
		e = a*Data[i] + (1.0-a)*e;
	return e;
}

void bbAt(vars C,int period,var dev,int offset,var* mid,var* upper,var* lower)
{
	*mid = smaAt(C,offset,period);
	var sd = stdAt(C,offset,period);
	*upper = *mid + dev*sd;
	*lower = *mid - dev*sd;
}

var atrAt(vars H,vars L,vars C,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var a = H[i]-L[i];
		var b = abs(H[i]-C[i+1]);
		var c = abs(L[i]-C[i+1]);
		var tr = max(a,max(b,c));
		sum += tr;
	}
	return sum/period;
}

var rsiAt(vars C,int offset,int period)
{
	var up = 0;
	var dn = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var d = C[i]-C[i+1];
		if(d > 0) up += d;
		else dn -= d;
	}
	if(dn <= 0) return 100;
	var rs = up/dn;
	return 100.0 - 100.0/(1.0+rs);
}

void stochAt(vars H,vars L,vars C,int kPeriod,int dPeriod,int offset,var* kOut,var* dOut)
{
	var hh = highestS(H,offset,kPeriod);
	var ll = lowestS(L,offset,kPeriod);
	if(hh == ll)
		*kOut = 50;
	else
		*kOut = 100.0*(C[offset]-ll)/(hh-ll);

	var sum = 0;
	int j;
	for(j=0;j<dPeriod;j++)
	{
		var h2 = highestS(H,offset+j,kPeriod);
		var l2 = lowestS(L,offset+j,kPeriod);
		var k2 = 50;
		if(h2 != l2) k2 = 100.0*(C[offset+j]-l2)/(h2-l2);
		sum += k2;
	}
	*dOut = sum/dPeriod;
}

var adxApprox(vars H,vars L,vars C,int offset,int period,var* diPlus,var* diMinus)
{
	var trsum = 0;
	var pdm = 0;
	var mdm = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var upMove = H[i]-H[i+1];
		var dnMove = L[i+1]-L[i];
		if(upMove > dnMove && upMove > 0) pdm += upMove;
		if(dnMove > upMove && dnMove > 0) mdm += dnMove;

		var tr = max(H[i]-L[i],max(abs(H[i]-C[i+1]),abs(L[i]-C[i+1])));
		trsum += tr;
	}
	if(trsum <= 0)
	{
		*diPlus = 0;
		*diMinus = 0;
		return 0;
	}
	*diPlus = 100.0*pdm/trsum;
	*diMinus = 100.0*mdm/trsum;

	var den = *diPlus + *diMinus;
	if(den <= 0) return 0;
	return 100.0*abs(*diPlus-*diMinus)/den;
}

var macdLineAt(vars C,int offset,int fast,int slow)
{
	return emaAt(C,offset,fast)-emaAt(C,offset,slow);
}

var macdSignalAt(vars C,int offset,int fast,int slow,int sig)
{
	var tmp[100];
	int i;
	int n = sig*3;
	if(n > 90) n = 90;
	for(i=0;i<n;i++)
		tmp[i] = macdLineAt(C,offset+i,fast,slow);
	var a = 2.0/(sig+1.0);
	var e = tmp[n-1];
	for(i=n-2;i>=0;i--)
		e = a*tmp[i] + (1.0-a)*e;
	return e;
}

int trendQualityOK(vars H,vars L,vars C,int regime)
{
	if(!UseTrendQualityGate) return 1;
	if(regime != -1) return 1;

	var p,m;
	var adx = adxApprox(H,L,C,0,TQ_ADX_Period,&p,&m);
	if(adx >= TQ_ADX_Min) return 1;
	return 0;
}

var adaptFactor(vars H,vars L,vars C)
{
	if(!UseAdaptiveMults) return 1.0;
	var fast = atrAt(H,L,C,0,Adapt_FastATR);
	var slow = atrAt(H,L,C,0,Adapt_SlowATR);
	if(slow <= 0) return 1.0;
	return clampv(fast/slow,Adapt_Min,Adapt_Max);
}

int directionBlocked(int dir,vars C)
{
	int isBuy = 0;
	if(dir > 0) isBuy = 1;

	if(UseRegimeDirection)
	{
		// Uses current module's timeframe as a practical approximation.
		// For a strict D1 regime filter, move this calculation into a dedicated D1 TimeFrame block.
		var ma0 = smaAt(C,0,Regime_MA);
		var ma1 = smaAt(C,1,Regime_MA);
		int slopeUp = 0;
		int slopeDn = 0;
		if(ma0 > ma1) slopeUp = 1;
		if(ma0 < ma1) slopeDn = 1;

		if(C[0] > ma0 && (!Regime_UseSlope || slopeUp))
		{
			if(!isBuy) return 1;
			return 0;
		}
		if(C[0] < ma0 && (!Regime_UseSlope || slopeDn))
		{
			if(isBuy) return 1;
			return 0;
		}
		if(Regime_NeutralAllowBoth) return 0;
		return 1;
	}

	if(isBuy && !AllowLongs) return 1;
	if(!isBuy && !AllowShorts) return 1;
	return 0;
}

void openTradeDir(int dir,string name,var slDist,var tpDist,var trailMult,var trailStart,var beMult,vars C)
{
	if(slDist <= 0 || tpDist <= 0) return;
	if(directionBlocked(dir,C)) return;
	if(!ARIMAAllowsDirection(dir,C)) return;
	if(UseRiskCap && MaxOpenPositions > 0 && CountTotalOpen() >= MaxOpenPositions) return;

	algo(name);
	if(CurrentAlgoHasOpen()) return;

	Stop = slDist;
	TakeProfit = tpDist;

	// Zorro has no global BreakEven variable.
	// Breakeven-style behavior is approximated through TrailLock.
	// TrailLock = 1 moves the stop to about entry/breakeven once the Trail trigger is reached.
	// IMPORTANT: reset all trail-related globals before every new trade so values do not leak
	// from one module/component into the next.
	Trail = 0;
	TrailSlope = 100;
	TrailLock = 0;
	TrailStep = 0;

	if(UseTrailing)
		Trail = trailMult*slDist;

	if(UseBreakeven && Trail > 0)
		TrailLock = 1;

	var base = FixedRiskBalance;
	if(!UseFixedRiskBase) base = Balance;
	Risk = base*RiskPercent/100.0;

	if(dir > 0)
		enterLong();
	else
		enterShort();
}

// -----------------------------------------------------------------------------
// M11 Grey estimator
// -----------------------------------------------------------------------------

var greyMA(vars O,int offset,int period)
{
	if(period < 3) period = 3;

	var grey[80];
	var rez[1600];
	int j,k,cnt;
	if(period > 40) period = 40;

	for(j=0;j<period;j++)
		grey[j] = O[offset+j];

	for(j=period-2;j>=0;j--)
		grey[j] = grey[j] + grey[j+1];

	cnt = 0;
	for(j=period-2;j>=0;j--)
	{
		for(k=j+1;k<period;k++)
		{
			rez[cnt] = (grey[j]-grey[k])/(k-j);
			cnt++;
		}
	}

	// simple ascending sort
	int a,b;
	for(a=0;a<cnt-1;a++)
	{
		for(b=a+1;b<cnt;b++)
		{
			if(rez[b] < rez[a])
			{
				var t = rez[a];
				rez[a] = rez[b];
				rez[b] = t;
			}
		}
	}

	int i1 = cnt/2;
	int i2 = i1;
	if(cnt%2 == 0) i2 = i1 + 1;
	if(i2 >= cnt) i2 = cnt-1;

	return (rez[i1]+rez[i2])/2.0;
}

// -----------------------------------------------------------------------------
// Modules
// -----------------------------------------------------------------------------

void Module1_BB_Stoch()
{
	if(!ModuleRuns(0)) return;

	TimeFrame = TF_M30;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_N);
	vars StochKS = series(0,ARIMA_N);
	vars WidthS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_M30)) return;
	if(!SessionOK(TF_M30)) return;

	if(!trendQualityOK(H,L,C,1)) return;

	var dip,dim;
	if(M1_UseRangeFilter)
		if(adxApprox(H,L,C,0,M1_ADX_Period,&dip,&dim) >= M1_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M1_BB_Period,M1_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M1_BB_Period,M1_BB_Dev,1,&m2,&u2,&l2);

	var k1,d1;
	stochAt(H,L,C,M1_Stoch_K,M1_Stoch_D,0,&k1,&d1);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	var widthNow = (u1-l1)/fix0(m1);
	if(widthNow <= 0) widthNow = 0.0001;

	BandPosS[0] = bandPos;
	StochKS[0] = clampv(k1,1.,99.);
	WidthS[0] = widthNow;

	int BOk = 0;
	int SOk = 0;
	int WOk = 0;
	var bandF = ARIMAForecastMeta("AP1_BandOsc","band",BandPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&BOk);
	var stochF = ARIMAForecastMeta("AP1_BandOsc","stoch",StochKS,ARIMA_N,0.01,ARIMA_MinOscDelta,&SOk);
	var widthF = ARIMAForecastMeta("AP1_BandOsc","width",WidthS,ARIMA_N,0.0001,ARIMA_MinWidthDelta,&WOk);

	int buy = 0;
	int sell = 0;

	if(BOk && SOk && WOk)
	{
		if(bandPos < 40. and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			buy = 1;

		if(bandPos > 60. and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
}


void Module2_BB_RSI()
{
	if(!ModuleRuns(1)) return;

	TimeFrame = TF_H2;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_N);
	vars RSIS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H2)) return;
	if(!SessionOK(TF_H2)) return;

	var dip,dim;
	if(M2_UseRangeFilter)
		if(adxApprox(H,L,C,0,M2_ADX_Period,&dip,&dim) >= M2_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M2_BB_Period,M2_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M2_BB_Period,M2_BB_Dev,1,&m2,&u2,&l2);

	var r0 = rsiAt(C,0,M2_RSI_Period);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	BandPosS[0] = bandPos;
	RSIS[0] = clampv(r0,1.,99.);

	int BOk = 0;
	int ROk = 0;
	var bandF = ARIMAForecastMeta("AP2_RSIState","band",BandPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&BOk);
	var rF = ARIMAForecastMeta("AP2_RSIState","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);

	int buy = 0;
	int sell = 0;

	if(BOk && ROk)
	{
		if(bandPos < 42. and r0 < M2_RSI_OS+10.
			and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(bandPos > 58. and r0 > M2_RSI_OB-10.
			and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	var slDist = M2_SL_Mult*af*atr;
	var tpDist = M2_TP_Mult*af*atr;

	if(M2_TP_AtMid)
	{
		if(buy)
		{
			tpDist = max(m1-priceClose(0),0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max(priceClose(0)-(min(L[0],L[1])-M2_SL_Buffer*af*atr),0.5*af*atr);
			openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
		if(sell)
		{
			tpDist = max(priceClose(0)-m1,0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max((max(H[0],H[1])+M2_SL_Buffer*af*atr)-priceClose(0),0.5*af*atr);
			openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
	}
	else
	{
		if(buy) openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		if(sell) openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
	}
}


void Module3_Keltner_Stoch()
{
	if(!ModuleRuns(2)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars KPosS = series(0,ARIMA_N);
	vars StochS = series(0,ARIMA_N);

	var dip,dim;
	if(M3_UseRangeFilter)
		if(adxApprox(H,L,C,0,M3_ADX_Period,&dip,&dim) >= M3_ADX_RangeMax) return;

	var ema0 = emaAt(C,0,M3_EMA_Period);
	var atrK0 = atrAt(H,L,C,0,M3_ATR_Period);
	if(atrK0 <= 0) return;

	var k0,d0;
	stochAt(H,L,C,M3_Stoch_K,M3_Stoch_D,0,&k0,&d0);

	var kPos = 50.0 + 50.0*(C[0]-ema0)/fix0(M3_ATR_Mult*atrK0);
	kPos = clampv(kPos,1.,99.);

	KPosS[0] = kPos;
	StochS[0] = clampv(k0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int KOk = 0;
	int SOk = 0;
	var kPosF = ARIMAForecastMeta("AP3_ChannelOsc","kpos",KPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&KOk);
	var stF = ARIMAForecastMeta("AP3_ChannelOsc","stoch",StochS,ARIMA_N,0.01,ARIMA_MinOscDelta,&SOk);

	int buy = 0;
	int sell = 0;

	if(KOk && SOk)
	{
		if(kPos < 45. and ARIMAForecastUp(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stF,k0,ARIMA_MinOscDelta))
			buy = 1;

		if(kPos > 55. and ARIMAForecastDown(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stF,k0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
}


void Module4_Ichimoku_Stoch()
{
	if(!ModuleRuns(3)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars SpreadS = series(0,ARIMA_N);
	vars CloudS = series(0,ARIMA_N);
	vars StochS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M4_UseADXFilter)
		if(adxApprox(H,L,C,0,M4_ADX_Period,&dip,&dim) < M4_ADX_Min) return;

	var tenkan0 = (highestS(H,0,M4_Tenkan)+lowestS(L,0,M4_Tenkan))/2.0;
	var kijun0  = (highestS(H,0,M4_Kijun)+lowestS(L,0,M4_Kijun))/2.0;
	var senkouA = (tenkan0+kijun0)/2.0;
	var senkouB = (highestS(H,0,M4_Senkou)+lowestS(L,0,M4_Senkou))/2.0;
	var top = max(senkouA,senkouB);
	var bot = min(senkouA,senkouB);
	var cloudMid = (top+bot)/2.0;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;
	if(top-bot < atr*0.3) return;

	var k,d;
	stochAt(H,L,C,M4_Stoch_K,M4_Stoch_D,0,&k,&d);

	var spreadScore = 50.0 + 20.0*(tenkan0-kijun0)/atr;
	var cloudScore = 50.0 + 20.0*(C[0]-cloudMid)/atr;
	spreadScore = clampv(spreadScore,1.,99.);
	cloudScore = clampv(cloudScore,1.,99.);

	SpreadS[0] = spreadScore;
	CloudS[0] = cloudScore;
	StochS[0] = clampv(k,1.,99.);

	int SpOk = 0;
	int ClOk = 0;
	int StOk = 0;
	var spF = ARIMAForecastMeta("AP4_CloudFlow","spread",SpreadS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&SpOk);
	var clF = ARIMAForecastMeta("AP4_CloudFlow","cloud",CloudS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&ClOk);
	var stF = ARIMAForecastMeta("AP4_CloudFlow","stoch",StochS,ARIMA_N,0.01,ARIMA_MinOscDelta,&StOk);

	int buy = 0;
	int sell = 0;

	if(SpOk && ClOk && StOk)
	{
		if(spF > 52. and clF > 52.
			and ARIMAForecastUp(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF > k)
			buy = 1;

		if(spF < 48. and clF < 48.
			and ARIMAForecastDown(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF < k)
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
}


int superDir(vars H,vars L,vars C,int atrPeriod,var mult,int offset)
{
	var atr = atrAt(H,L,C,offset,atrPeriod);
	var mid = (H[offset]+L[offset])/2.0;
	if(C[offset] > mid + mult*atr*0.25) return 1;
	if(C[offset] < mid - mult*atr*0.25) return -1;
	return 0;
}

void Module5_Supertrend_RSI()
{
	if(!ModuleRuns(4)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PressureS = series(0,ARIMA_N);
	vars RSIS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M5_UseADXFilter)
		if(adxApprox(H,L,C,0,M5_ADX_Period,&dip,&dim) < M5_ADX_Min) return;

	var atrST = atrAt(H,L,C,0,M5_ATR_Period);
	if(atrST <= 0) return;

	var mid = (H[0]+L[0])/2.0;
	var pressure = 50.0 + 20.0*(C[0]-mid)/fix0(M5_ATR_Mult*atrST);
	pressure = clampv(pressure,1.,99.);

	var r0 = rsiAt(C,0,M5_RSI_Period);
	var emaT = emaAt(C,0,M5_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-emaT)/fix0(atrST);
	trendScore = clampv(trendScore,1.,99.);

	PressureS[0] = pressure;
	RSIS[0] = clampv(r0,1.,99.);
	TrendS[0] = trendScore;

	int POk = 0;
	int ROk = 0;
	int TOk = 0;
	var pF = ARIMAForecastMeta("AP5_Pressure","pressure",PressureS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&POk);
	var rF = ARIMAForecastMeta("AP5_Pressure","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);
	var tF = ARIMAForecastMeta("AP5_Pressure","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && ROk && TOk)
	{
		if(pF > 52. and tF > 52. and rF > M5_RSI_BuyLo
			and ARIMAForecastUp(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 48. and tF < 48. and rF < M5_RSI_SellHi
			and ARIMAForecastDown(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);

	if(buy)
		openTradeDir(1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);

	if(sell)
		openTradeDir(-1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);
}


void Module6_EMA_ADX()
{
	if(!ModuleRuns(5)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars EmaS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);
	vars DiS = series(0,ARIMA_N);
	vars AdxS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var eF0 = emaAt(C,0,M6_EMA_Fast);
	var eS0 = emaAt(C,0,M6_EMA_Slow);
	var eT0 = emaAt(C,0,M6_EMA_Trend);
	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var dp,dm;
	var adx0 = adxApprox(H,L,C,0,M6_ADX_Period,&dp,&dm);

	var emaScore = 50.0 + 20.0*(eF0-eS0)/atr;
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	var diScore = 50.0 + (dp-dm);
	emaScore = clampv(emaScore,1.,99.);
	trendScore = clampv(trendScore,1.,99.);
	diScore = clampv(diScore,1.,99.);

	EmaS[0] = emaScore;
	TrendS[0] = trendScore;
	DiS[0] = diScore;
	AdxS[0] = clampv(adx0,1.,99.);

	int EOk = 0;
	int TOk = 0;
	int DOk = 0;
	int AOk = 0;
	var eF = ARIMAForecastMeta("AP6_DriftADX","ema",EmaS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&EOk);
	var tF = ARIMAForecastMeta("AP6_DriftADX","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);
	var dF = ARIMAForecastMeta("AP6_DriftADX","di",DiS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&DOk);
	var aF = ARIMAForecastMeta("AP6_DriftADX","adx",AdxS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&AOk);

	int buy = 0;
	int sell = 0;

	if(EOk && TOk && DOk && AOk)
	{
		if(eF > 52. and tF > 52. and dF > 52. and aF > M6_ADX_Min
			and ARIMAForecastUp(eF,emaScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(eF < 48. and tF < 48. and dF < 48. and aF > M6_ADX_Min
			and ARIMAForecastDown(eF,emaScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
}


void Module7_Donchian()
{
	if(!ModuleRuns(6)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PosS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M7_UseADXFilter)
		if(adxApprox(H,L,C,0,M7_ADX_Period,&dp,&dm) < M7_ADX_Min) return;

	var dHi = highestS(H,1,M7_Donch_Period);
	var dLo = lowestS(L,1,M7_Donch_Period);
	var width = dHi-dLo;
	if(width <= 0) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var pos = 100.0*(C[0]-dLo)/width;
	pos = clampv(pos,1.,99.);

	var eT0 = emaAt(C,0,M7_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	PosS[0] = pos;
	TrendS[0] = trendScore;

	int POk = 0;
	int TOk = 0;
	var pF = ARIMAForecastMeta("AP7_RangeFlow","pos",PosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&POk);
	var tF = ARIMAForecastMeta("AP7_RangeFlow","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && TOk)
	{
		if(pF > 80. and tF > 52.
			and ARIMAForecastUp(pF,pos,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 20. and tF < 48.
			and ARIMAForecastDown(pF,pos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M7_MaxExtATR > 0 && atr > 0)
	{
		if(buy && (C[0]-dHi) > M7_MaxExtATR*atr) buy = 0;
		if(sell && (dLo-C[0]) > M7_MaxExtATR*atr) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
}


void Module8_MACD_EMA()
{
	if(!ModuleRuns(7)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars HistS = series(0,ARIMA_N);
	vars TrendS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M8_UseADXFilter)
		if(adxApprox(H,L,C,0,M8_ADX_Period,&dp,&dm) < M8_ADX_Min) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var macd0 = macdLineAt(C,0,M8_MACD_Fast,M8_MACD_Slow);
	var sig0 = macdSignalAt(C,0,M8_MACD_Fast,M8_MACD_Slow,M8_MACD_Signal);
	var hist = macd0-sig0;
	var histScore = 50.0 + 50.0*hist/atr;
	histScore = clampv(histScore,1.,99.);

	var eT0 = emaAt(C,0,M8_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	HistS[0] = histScore;
	TrendS[0] = trendScore;

	int HOk = 0;
	int TOk = 0;
	var hF = ARIMAForecastMeta("AP8_MacdFlow","hist",HistS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&HOk);
	var tF = ARIMAForecastMeta("AP8_MacdFlow","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(HOk && TOk)
	{
		if(hF > 52. and tF > 52.
			and ARIMAForecastUp(hF,histScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(hF < 48. and tF < 48.
			and ARIMAForecastDown(hF,histScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
}


void Module9_RSI_MR()
{
	if(!ModuleRuns(8)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars RSIS = series(0,ARIMA_N);

	var dp,dm;
	if(M9_UseRangeFilter)
		if(adxApprox(H,L,C,0,M9_ADX_Period,&dp,&dm) >= M9_ADX_RangeMax) return;

	var r0 = rsiAt(C,0,M9_RSI_Period);
	var r2 = rsiAt(C,2,M9_RSI_Period);

	RSIS[0] = clampv(r0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int ROk = 0;
	var rF = ARIMAForecastMeta("AP9_RSIPath","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);

	int buy = 0;
	int sell = 0;

	if(ROk)
	{
		if(r0 < 45. and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(r0 > 55. and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M9_RequireSustain)
	{
		if(buy && r2 > 50.) buy = 0;
		if(sell && r2 < 50.) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
}


void Module10_BB_Squeeze()
{
	if(!ModuleRuns(9)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars WidthS = series(0,ARIMA_N);
	vars PosS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M10_UseADXFilter)
		if(adxApprox(H,L,C,0,M10_ADX_Period,&dp,&dm) < M10_ADX_Min) return;

	var m0,u0,l0;
	bbAt(C,M10_BB_Period,M10_BB_Dev,0,&m0,&u0,&l0);
	var range = u0-l0;
	if(range <= 0) return;

	var avgW = 0;
	int i;
	for(i=1;i<21;i++)
	{
		var mi,ui,li;
		bbAt(C,M10_BB_Period,M10_BB_Dev,i,&mi,&ui,&li);
		avgW += (ui-li)/fix0(mi);
	}
	avgW /= 20.0;

	var widthNow = range/fix0(m0);
	if(widthNow <= 0) widthNow = 0.0001;

	var bandPos = 100.0*(C[0]-l0)/range;
	bandPos = clampv(bandPos,1.,99.);

	WidthS[0] = widthNow;
	PosS[0] = bandPos;

	int WOk = 0;
	int POk = 0;
	var wF = ARIMAForecastMeta("AP10_BandEnergy","width",WidthS,ARIMA_N,0.0001,ARIMA_MinWidthDelta,&WOk);
	var pF = ARIMAForecastMeta("AP10_BandEnergy","pos",PosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&POk);

	int buy = 0;
	int sell = 0;

	if(WOk && POk)
	{
		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF > 62. and ARIMAForecastUp(pF,bandPos,ARIMA_MinOscDelta))
			buy = 1;

		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF < 38. and ARIMAForecastDown(pF,bandPos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M10_UseTrendAlign)
	{
		var e = emaAt(C,0,M10_TrendEMA);
		if(C[0] <= e) buy = 0;
		if(C[0] >= e) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
}


void Module11_Grey()
{
	if(!ModuleRuns(10)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars O = series(priceOpen());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars GreyS = series(0,ARIMA_N);
	vars SlopeS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var g0 = greyMA(O,0,M11_Period);
	var g1 = greyMA(O,1,M11_Period);

	var greyScore = 50.0 + 20.0*(g0-O[0])/atr;
	var greySlope = 50.0 + 20.0*(g0-g1)/atr;
	greyScore = clampv(greyScore,1.,99.);
	greySlope = clampv(greySlope,1.,99.);

	GreyS[0] = greyScore;
	SlopeS[0] = greySlope;

	int GOk = 0;
	int SOk = 0;
	var gF = ARIMAForecastMeta("AP11_GreyPath","grey",GreyS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&GOk);
	var sF = ARIMAForecastMeta("AP11_GreyPath","slope",SlopeS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&SOk);

	int buy = 0;
	int sell = 0;

	if(GOk && SOk)
	{
		if(gF > 52. and sF > 52.
			and ARIMAForecastUp(gF,greyScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(gF < 48. and sF < 48.
			and ARIMAForecastDown(gF,greyScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M11_UseTrendFilter)
	{
		var e = emaAt(C,0,M11_TrendEMA);
		if(O[0] <= e) buy = 0;
		if(O[0] >= e) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
}


void Module12_Flag()
{
	if(!ModuleRuns(11)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PoleS = series(0,ARIMA_N);
	vars BreakS = series(0,ARIMA_N);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	int fB = M12_FlagBars;
	int pB = M12_PoleBars;

	int pNew = fB+1;
	int pOld = fB+pB;
	var poleMove = C[pNew]-C[pOld];

	var poleHigh = H[pNew];
	var poleLow = L[pNew];
	int k;
	for(k=pNew;k<=pOld;k++)
	{
		if(H[k] > poleHigh) poleHigh = H[k];
		if(L[k] < poleLow) poleLow = L[k];
	}

	var poleHeight = poleHigh-poleLow;
	if(poleHeight <= 0) return;

	var flagHigh = H[1];
	var flagLow = L[1];
	for(k=1;k<=fB;k++)
	{
		if(H[k] > flagHigh) flagHigh = H[k];
		if(L[k] < flagLow) flagLow = L[k];
	}

	if((flagHigh-flagLow) > M12_FlagMaxATR*atr) return;

	var flagMid = (flagHigh+flagLow)/2.0;
	var poleScore = 50.0 + 10.0*poleMove/atr;
	var breakScore = 50.0 + 20.0*(C[0]-flagMid)/atr;
	poleScore = clampv(poleScore,1.,99.);
	breakScore = clampv(breakScore,1.,99.);

	PoleS[0] = poleScore;
	BreakS[0] = breakScore;

	int POk = 0;
	int BOk = 0;
	var pF = ARIMAForecastMeta("AP12_ShapePath","pole",PoleS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&POk);
	var bF = ARIMAForecastMeta("AP12_ShapePath","break",BreakS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&BOk);

	int buy = 0;
	int sell = 0;

	if(POk && BOk)
	{
		if(pF > 55. and bF > 55.
			and ARIMAForecastUp(bF,breakScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(pF < 45. and bF < 45.
			and ARIMAForecastDown(bF,breakScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M12_UseTrendFilter)
	{
		var ma = smaAt(C,0,M12_MA_Period);
		if(C[0] <= ma) buy = 0;
		if(C[0] >= ma) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	var slDist = poleHeight*M12_SL_PoleMult*af;
	var tpDist = poleHeight*M12_TP_PoleMult*af;

	if(buy) openTradeDir(1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
}


// -----------------------------------------------------------------------------
// End-of-test CSV style log
// -----------------------------------------------------------------------------

void logClosedTrades()
{
	if(!is(EXITRUN)) return;

	file_delete("Log\\MultiStrategy_Trades_Zorro.csv");
	file_append("Log\\MultiStrategy_Trades_Zorro.csv",
		"asset,algo,profit\n",0);

	for(closed_trades)
	{
		file_append("Log\\MultiStrategy_Trades_Zorro.csv",
			strf("%s,%s,%.2f\n",Asset,Algo,(var)TradeProfit),0);
	}
}

// -----------------------------------------------------------------------------
// Main strategy
// -----------------------------------------------------------------------------

function run()
{
	set(PARAMETERS|OFF);

	BarPeriod = 30;
	LookBack = 2000;
	Capital = FixedRiskBalance;
	Hedge = 2;        // allow independent long/short components in backtest
	Fill = 3;         // more realistic order filling; adjust to your broker/data
	Slippage = 0;
	Spread = Spread; // keep asset-list spread

	if(is(INITRUN))
	{
		printf("\nArimaIndicatorMatrix v02 meta started.");
		printf("\nIndicator states and their prediction-success streams are forecast with AutoAri.");

		if(UseARIMAMetaLog)
		{
			file_delete("Log\\ArimaIndicatorMeta.csv");
			file_append("Log\\ArimaIndicatorMeta.csv",
				"asset,bar,module,field,value,forecast,delta,rate20,meta_rel,raw_ok,meta_ok\n",0);
		}
	}

	int i;
	for(i=0;i<NUM_SYMBOLS;i++)
	{
		if(!SymbolEnabled(i))
			continue;

		if(!asset(SymbolName(i)))
			continue;

		// Run all converted modules. ModuleRuns() applies the v8.11 instrument gating.
		Module1_BB_Stoch();
		Module2_BB_RSI();
		Module3_Keltner_Stoch();
		Module4_Ichimoku_Stoch();
		Module5_Supertrend_RSI();
		Module6_EMA_ADX();
		Module7_Donchian();
		Module8_MACD_EMA();
		Module9_RSI_MR();
		Module10_BB_Squeeze();
		Module11_Grey();
		Module12_Flag();

		TimeFrame = 1;
	}

	if(is(EXITRUN))
		FreeARIMA();

	logClosedTrades();
}

Last edited by TipmyPip; Yesterday at 12:38.
Arima Indicator Matrix (v3) [Re: TipmyPip] #489454
Yesterday at 12:36
Yesterday at 12:36
Joined: Sep 2017
Posts: 307
TipmyPip Offline OP
Senior Member
TipmyPip  Offline OP
Senior Member

Joined: Sep 2017
Posts: 307
The strategy treats every market indicator as a time series whose future state can be estimated rather than merely observed. Instead of asking whether an indicator is currently overbought, oversold, trending, compressed, or breaking out, the strategy first converts each indicator into a normalized state value and then applies an ARIMA forecast to estimate where that state is likely to move next. A second feedback layer evaluates whether previous forecasts were directionally correct and under what market conditions they succeeded or failed. That prediction history is itself modeled, so the system can adjust the next ARIMA configuration before making a new forecast. In this way, the model does not only predict indicators; it learns which prediction settings have recently been reliable for each indicator stream. Trade decisions are then based on predicted indicator movement, forecast reliability, volatility context, regime filters, and adaptive risk settings. The result is a layered forecasting framework where price action, indicator state, prediction error, and previous forecast quality all influence the next decision. This makes the strategy mathematically adaptive: it continually updates how much it trusts each indicator forecast and changes the forecasting parameters accordingly, aiming to improve signal quality before entries are taken rather than only judging performance after trades close.

Code
// ArimaIndicatorMatrix_v03_feedback.c

#define NUM_MODULES 12
#define TF_M30 1
#define TF_H1  2
#define TF_H2  4
#define TF_H4  8
#define TF_D1  48

// -----------------------------------------------------------------------------
// ARIMA package interface
// -----------------------------------------------------------------------------
// UseARIMAFilter is the old close-price confirmation filter.
// The main strategy below does not rely on that old filter. It creates ARIMA
// forecasts of the module indicator series themselves.
// -----------------------------------------------------------------------------

#define PRAGMA_API init_auto_arima_result;AutoAri32!init_auto_arima_result
#define PRAGMA_API free_auto_arima_result;AutoAri32!free_auto_arima_result
#define PRAGMA_API auto_arima_forecast;AutoAri32!auto_arima_forecast
#define PRAGMA_API aa_validate_price_series;AutoAri32!aa_validate_price_series

int UseARIMAFilter = 0; // old close-price gate; indicator ARIMA is the main logic
int ARIMA_N = 160;          // number of close prices used for the forecast
int ARIMA_MaxP = 3;         // maximum AR order searched by auto_arima_forecast
int ARIMA_MaxQ = 3;         // maximum MA order searched by auto_arima_forecast
var ARIMA_MinPips = 2.0;    // minimum forecast edge in pips
int ARIMA_PlotForecast = 0; // plots old price forecast only if UseARIMAFilter is enabled

int UseARIMAIndicatorPrediction = 1;
var ARIMA_MinOscDelta = 0.75;    // RSI/Stoch/Band position forecast delta
var ARIMA_MinTrendDelta = 0.60;  // trend/pressure forecast delta
var ARIMA_MinWidthDelta = 0.00001;

// -----------------------------------------------------------------------------
// ARIMA meta-prediction layer
// -----------------------------------------------------------------------------
// This layer measures the previous success rate of every indicator forecast.
// It then applies auto_arima_forecast(...) to the hit/miss stream itself.
// The CSV output lets us later discover under which indicator conditions the
// ARIMA prediction stream was reliable.
//
// Hit stream scale:
//   80 = previous forecast direction was correct
//   20 = previous forecast direction was wrong
//   50 = previous forecast edge was too small / neutral

#define META_FIELD_SLOTS 28
#define META_SERIES_CAP 80
#define META_RATE_CAP 20

int UseARIMAMetaPrediction = 1;
int UseARIMAMetaLog = 1;
int ARIMA_MetaN = META_SERIES_CAP;
int ARIMA_MetaRateN = META_RATE_CAP;

var GMetaForecast[META_FIELD_SLOTS][META_SERIES_CAP];
var GMetaHit[META_FIELD_SLOTS][META_SERIES_CAP];
int GMetaInitialized[META_FIELD_SLOTS];
int GMetaLastBar[META_FIELD_SLOTS];

// v03 feedback-controller state.
// These parameters are changed from previous prediction quality before the
// next indicator ARIMA forecast is calculated.
int UseARIMAParameterFeedback = 1;
int ARIMA_MinAdaptiveN = 80;
int ARIMA_MaxAdaptiveN = 240;
int ARIMA_MaxAdaptiveOrder = 5;

var ARIMA_ReliabilityLow = 0.46;
var ARIMA_ReliabilityHigh = 0.62;
var ARIMA_ErrorHigh = 1.40;

int GMetaUseN[META_FIELD_SLOTS];
int GMetaUseP[META_FIELD_SLOTS];
int GMetaUseQ[META_FIELD_SLOTS];
var GMetaDeltaMult[META_FIELD_SLOTS];
var GMetaLastRate[META_FIELD_SLOTS];
var GMetaLastRel[META_FIELD_SLOTS];
var GMetaLastErr[META_FIELD_SLOTS];
var GMetaParamQuality[META_FIELD_SLOTS];

typedef struct AUTO_ARIMA_RESULT
{
	int p;
	int d;
	int q;
	int converged;
	var sse;
	var aicc;
	var forecast;
	var* ar;
	var* ma;
	int arCap;
	int maCap;
} AUTO_ARIMA_RESULT;

AUTO_ARIMA_RESULT GArimaResult;
int GArimaInitialized = 0;

// ARIMA DLL imports.
// The README signature for auto_arima_forecast is:
// int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result)
int auto_arima_forecast(vars Close,int N,var TickSize,int MaxP,int MaxQ,AUTO_ARIMA_RESULT* Result);
int aa_validate_price_series(vars Close,int N);
void init_auto_arima_result(AUTO_ARIMA_RESULT* R);
void free_auto_arima_result(AUTO_ARIMA_RESULT* R);

void InitARIMAOnce()
{
	if(GArimaInitialized)
		return;

	init_auto_arima_result(&GArimaResult);
	GArimaInitialized = 1;
}

void ResetARIMAResult()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	init_auto_arima_result(&GArimaResult);
}

int ARIMAAllowsDirection(int dir,vars C)
{
	if(!UseARIMAFilter)
		return 1;

	if(ARIMA_N < 30)
		return 1;

	if(Bar < LookBack)
		return 0;

	InitARIMAOnce();

	// Avoid accumulating result-owned coefficient arrays between calls.
	ResetARIMAResult();

	if(!aa_validate_price_series(C,ARIMA_N))
		return 0;

	int ok = auto_arima_forecast(C,ARIMA_N,PIP,ARIMA_MaxP,ARIMA_MaxQ,&GArimaResult);

	if(!ok)
	{
		printf("\nARIMA forecast failed: Asset=%s Algo=%s Bar=%i",Asset,Algo,Bar);
		return 0;
	}

	var Threshold = ARIMA_MinPips*PIP;
	var Edge = GArimaResult.forecast - C[0];
	int Signal = 0;
	if(Edge > Threshold)
		Signal = 1;
	else if(Edge < -Threshold)
		Signal = -1;

	if(ARIMA_PlotForecast)
		plot("ARIMA Forecast",GArimaResult.forecast,LINE,BLUE);

	if(dir > 0 && Signal > 0)
		return 1;

	if(dir < 0 && Signal < 0)
		return 1;

	return 0;
}

var ARIMAForecastSeries(vars Data,int N,var TickSize,int MaxP,int MaxQ,int* OK)
{
	*OK = 0;

	if(!UseARIMAIndicatorPrediction)
	{
		*OK = 1;
		return Data[0];
	}

	if(N < 30)
		return Data[0];

	if(Bar < LookBack)
		return Data[0];

	InitARIMAOnce();
	ResetARIMAResult();

	if(!aa_validate_price_series(Data,N))
		return Data[0];

	int Status = auto_arima_forecast(
		Data,
		N,
		TickSize,
		MaxP,
		MaxQ,
		&GArimaResult
	);

	if(!Status)
		return Data[0];

	if(!GArimaResult.converged)
		return Data[0];

	if(invalid(GArimaResult.forecast))
		return Data[0];

	*OK = 1;
	return GArimaResult.forecast;
}

int ARIMAForecastUp(var Forecast,var CurrentValue,var MinDelta)
{
	if(Forecast - CurrentValue > MinDelta)
		return 1;
	return 0;
}

int ARIMAForecastDown(var Forecast,var CurrentValue,var MinDelta)
{
	if(CurrentValue - Forecast > MinDelta)
		return 1;
	return 0;
}

var ARIMAMetaRate(vars HitS,int N)
{
	if(N < 1)
		return 0.50;

	var Sum = 0;
	int i;
	for(i=0;i<N;i++)
		Sum += HitS[i];

	return clamp((Sum/N)/100.0,0.,1.);
}

void InitMetaParams(int Slot)
{
	if(Slot < 0 || Slot >= META_FIELD_SLOTS)
		return;

	GMetaUseN[Slot] = ARIMA_N;
	GMetaUseP[Slot] = ARIMA_MaxP;
	GMetaUseQ[Slot] = ARIMA_MaxQ;
	GMetaDeltaMult[Slot] = 1.0;
	GMetaLastRate[Slot] = 0.50;
	GMetaLastRel[Slot] = 0.50;
	GMetaLastErr[Slot] = 1.0;
	GMetaParamQuality[Slot] = 0.50;
}

void ResetMetaState()
{
	int i;
	for(i=0;i<META_FIELD_SLOTS;i++)
	{
		GMetaInitialized[i] = 0;
		GMetaLastBar[i] = -1;
		InitMetaParams(i);
	}
}

void AdaptMetaParams(int Slot,var Rate,var Rel,var ErrNorm,var DriftNorm)
{
	if(Slot < 0 || Slot >= META_FIELD_SLOTS)
		return;

	if(!UseARIMAParameterFeedback)
	{
		InitMetaParams(Slot);
		return;
	}

	var Quality = 0.50*Rate + 0.50*Rel;
	int NewN = ARIMA_N;
	int NewP = ARIMA_MaxP;
	int NewQ = ARIMA_MaxQ;
	var NewDeltaMult = 1.0;

	// Good recent prediction stream: shorter memory, lower order, more responsive.
	if(Quality >= ARIMA_ReliabilityHigh and ErrNorm < ARIMA_ErrorHigh)
	{
		NewN = ARIMA_N - 40;
		NewP = ARIMA_MaxP - 1;
		NewQ = ARIMA_MaxQ - 1;
		NewDeltaMult = 0.85;
	}

	// Weak prediction stream: longer memory, more flexible model, stricter delta.
	if(Quality <= ARIMA_ReliabilityLow)
	{
		NewN = ARIMA_N + 60;
		NewP = ARIMA_MaxP + 1;
		NewQ = ARIMA_MaxQ + 1;
		NewDeltaMult = 1.25;
	}

	// High realized forecast error: make the next forecast more conservative.
	if(ErrNorm > ARIMA_ErrorHigh)
	{
		NewN = NewN + 40;
		NewP = NewP + 1;
		NewQ = NewQ + 1;
		NewDeltaMult += 0.20;
	}

	// Large recent forecast edge but poor quality: demand a bigger future edge.
	if(abs(DriftNorm) > 2.0 and Quality < 0.55)
		NewDeltaMult += 0.15;

	if(NewN < ARIMA_MinAdaptiveN)
		NewN = ARIMA_MinAdaptiveN;

	if(NewN > ARIMA_MaxAdaptiveN)
		NewN = ARIMA_MaxAdaptiveN;

	if(NewP < 1)
		NewP = 1;

	if(NewQ < 1)
		NewQ = 1;

	if(NewP > ARIMA_MaxAdaptiveOrder)
		NewP = ARIMA_MaxAdaptiveOrder;

	if(NewQ > ARIMA_MaxAdaptiveOrder)
		NewQ = ARIMA_MaxAdaptiveOrder;

	GMetaUseN[Slot] = NewN;
	GMetaUseP[Slot] = NewP;
	GMetaUseQ[Slot] = NewQ;
	GMetaDeltaMult[Slot] = clamp(NewDeltaMult,0.70,1.70);
	GMetaLastRate[Slot] = Rate;
	GMetaLastRel[Slot] = Rel;
	GMetaLastErr[Slot] = ErrNorm;
	GMetaParamQuality[Slot] = Quality;
}

int MetaFieldSlot(string ModuleName,string FieldName)
{
	if(strstr(ModuleName,"AP1_BandOsc")) {
		if(strstr(FieldName,"band")) return 0;
		if(strstr(FieldName,"stoch")) return 1;
		if(strstr(FieldName,"width")) return 2;
	}
	if(strstr(ModuleName,"AP2_RSIState")) {
		if(strstr(FieldName,"band")) return 3;
		if(strstr(FieldName,"rsi")) return 4;
	}
	if(strstr(ModuleName,"AP3_ChannelOsc")) {
		if(strstr(FieldName,"kpos")) return 5;
		if(strstr(FieldName,"stoch")) return 6;
	}
	if(strstr(ModuleName,"AP4_CloudFlow")) {
		if(strstr(FieldName,"spread")) return 7;
		if(strstr(FieldName,"cloud")) return 8;
		if(strstr(FieldName,"stoch")) return 9;
	}
	if(strstr(ModuleName,"AP5_Pressure")) {
		if(strstr(FieldName,"pressure")) return 10;
		if(strstr(FieldName,"rsi")) return 11;
		if(strstr(FieldName,"trend")) return 12;
	}
	if(strstr(ModuleName,"AP6_DriftADX")) {
		if(strstr(FieldName,"ema")) return 13;
		if(strstr(FieldName,"trend")) return 14;
		if(strstr(FieldName,"di")) return 15;
		if(strstr(FieldName,"adx")) return 16;
	}
	if(strstr(ModuleName,"AP7_RangeFlow")) {
		if(strstr(FieldName,"pos")) return 17;
		if(strstr(FieldName,"trend")) return 18;
	}
	if(strstr(ModuleName,"AP8_MacdFlow")) {
		if(strstr(FieldName,"hist")) return 19;
		if(strstr(FieldName,"trend")) return 20;
	}
	if(strstr(ModuleName,"AP9_RSIPath")) return 21;
	if(strstr(ModuleName,"AP10_BandEnergy")) {
		if(strstr(FieldName,"width")) return 22;
		if(strstr(FieldName,"pos")) return 23;
	}
	if(strstr(ModuleName,"AP11_GreyPath")) {
		if(strstr(FieldName,"grey")) return 24;
		if(strstr(FieldName,"slope")) return 25;
	}
	if(strstr(ModuleName,"AP12_ShapePath")) {
		if(strstr(FieldName,"pole")) return 26;
		if(strstr(FieldName,"break")) return 27;
	}
	return -1;
}

void MetaShift(var* Data,int Count)
{
	int i;
	for(i=Count-1;i>0;i--)
		Data[i] = Data[i-1];
}

void EnsureMetaSlot(int Slot,var ForecastValue)
{
	int i;
	if(Slot < 0 || Slot >= META_FIELD_SLOTS)
		return;

	if(!GMetaInitialized[Slot])
	{
		for(i=0;i<META_SERIES_CAP;i++)
		{
			GMetaForecast[Slot][i] = ForecastValue;
			GMetaHit[Slot][i] = 50.;
		}
		GMetaInitialized[Slot] = 1;
		GMetaLastBar[Slot] = Bar;
		InitMetaParams(Slot);
		return;
	}

	if(GMetaLastBar[Slot] != Bar)
	{
		MetaShift(&GMetaForecast[Slot][0],META_SERIES_CAP);
		MetaShift(&GMetaHit[Slot][0],META_SERIES_CAP);
		GMetaLastBar[Slot] = Bar;
	}
}

var ARIMAMetaRel(vars ValueS,vars ForecastS,vars HitS,var MinDelta,int* OK)
{
	*OK = 0;

	if(!UseARIMAMetaPrediction)
	{
		*OK = 1;
		return 1.0;
	}

	var PrevEdge = ForecastS[1] - ValueS[1];
	var ActualMove = ValueS[0] - ValueS[1];
	var Hit = 50.0;

	if(abs(PrevEdge) > MinDelta)
	{
		if(PrevEdge * ActualMove > 0)
			Hit = 80.0;
		else
			Hit = 20.0;
	}

	HitS[0] = Hit;

	int HOk = 0;
	var HF = ARIMAForecastSeries(HitS,ARIMA_MetaN,0.01,ARIMA_MaxP,ARIMA_MaxQ,&HOk);

	if(!HOk)
		return ARIMAMetaRate(HitS,ARIMA_MetaRateN);

	*OK = 1;
	return clamp(HF/100.0,0.,1.);
}

var ARIMAForecastMeta(string ModuleName,string FieldName,vars Data,int N,var TickSize,var MinDelta,int* OK)
{
	int RawOK = 0;
	int Slot = MetaFieldSlot(ModuleName,FieldName);
	int MetaOK = 0;

	int UseN = N;
	int UseP = ARIMA_MaxP;
	int UseQ = ARIMA_MaxQ;
	var UseDelta = MinDelta;

	var Rel = 1.0;
	var Rate = 0.50;
	var ErrNorm = 0.;
	var DriftNorm = 0.;
	var Quality = 0.50;
	var DeltaMultLog = 1.0;

	if(Slot >= 0)
	{
		EnsureMetaSlot(Slot,Data[0]);

		// Step 1: evaluate the previous indicator forecast now that the actual
		// current indicator value is known. This is causal: only previous
		// forecast quality can influence the current forecast parameters.
		var PrevForecast = GMetaForecast[Slot][1];
		var PrevEdge = PrevForecast - Data[1];
		var PrevError = abs(PrevForecast - Data[0]);

		ErrNorm = PrevError / fix0(MinDelta*4.0);
		DriftNorm = PrevEdge / fix0(MinDelta);

		Rel = ARIMAMetaRel(Data,&GMetaForecast[Slot][0],&GMetaHit[Slot][0],MinDelta,&MetaOK);
		Rate = ARIMAMetaRate(&GMetaHit[Slot][0],ARIMA_MetaRateN);

		// Step 2: adapt the parameters for the next indicator ARIMA call.
		AdaptMetaParams(Slot,Rate,Rel,ErrNorm,DriftNorm);

		UseN = GMetaUseN[Slot];
		UseP = GMetaUseP[Slot];
		UseQ = GMetaUseQ[Slot];
		UseDelta = MinDelta * GMetaDeltaMult[Slot];
		Quality = GMetaParamQuality[Slot];
		DeltaMultLog = GMetaDeltaMult[Slot];
	}

	// Step 3: current indicator forecast uses parameters already modified by
	// the previous forecast-success model.
	var F = ARIMAForecastSeries(Data,UseN,TickSize,UseP,UseQ,&RawOK);

	if(Slot >= 0)
		GMetaForecast[Slot][0] = F;

	if(UseARIMAMetaLog)
	{
		file_append("Log\\ArimaIndicatorMeta.csv",
			strf("%s,%i,%s,%s,%.6f,%.6f,%.6f,%.4f,%.4f,%i,%i,%i,%i,%i,%.4f,%.4f,%.4f\n",
				Asset,Bar,ModuleName,FieldName,Data[0],F,F-Data[0],
				Rate,Rel,RawOK,MetaOK,UseN,UseP,UseQ,DeltaMultLog,ErrNorm,Quality),0);
	}

	*OK = RawOK;

	// Return the forecast. The caller still uses ARIMAForecastUp/Down, but now
	// its MinDelta should be interpreted through the Slot's current delta
	// multiplier. To keep module code stable, the forecast itself is adjusted
	// toward Data[0] when the adaptive threshold is high.
	if(Slot >= 0 and UseDelta > MinDelta)
	{
		var Shrink = clamp((UseDelta/MinDelta - 1.0)*0.50,0.,0.35);
		F = Data[0] + (F-Data[0])*(1.0-Shrink);
	}

	return F;
}

void FreeARIMA()
{
	if(!GArimaInitialized)
		return;

	free_auto_arima_result(&GArimaResult);
	GArimaInitialized = 0;
}


// -----------------------------------------------------------------------------
// Global inputs
// -----------------------------------------------------------------------------

var RiskPercent = 2.0;
int ATR_Period = 14;

int UseSessionFilter = 1;
int SessionStartHour = 7;
int SessionEndHour = 20;

int UseFixedRiskBase = 1;
var FixedRiskBalance = 10000;
var MaxLotCap = 0; // not used directly; Zorro sizes through Risk/Margin/Lots.

int UseTrailing = 1;
int UseBreakeven = 1;

int UseRegimeDirection = 1;
int Regime_MA = 200;
int Regime_UseSlope = 1;
int Regime_NeutralAllowBoth = 1;
int AllowLongs = 1;
int AllowShorts = 0;

int UseTrendQualityGate = 1;
int TQ_ADX_Period = 14;
var TQ_ADX_Min = 18.0;

int UseRiskCap = 1;
var MaxPortfolioRiskPct = 15.0;
int MaxOpenPositions = 12;

int UseAdaptiveMults = 1;
int Adapt_FastATR = 14;
int Adapt_SlowATR = 100;
var Adapt_Min = 0.75;
var Adapt_Max = 1.50;

// Module master switches
int Use_BB_Stoch       = 1; // M1
int Use_BB_RSI         = 1; // M2
int Use_Keltner_Stoch  = 1; // M3
int Use_Ichimoku_Stoch = 1; // M4
int Use_Supertrend_RSI = 1; // M5
int Use_EMA_ADX        = 1; // M6
int Use_Donchian       = 1; // M7
int Use_MACD_EMA       = 1; // M8
int Use_RSI_MR         = 1; // M9
int Use_BB_Squeeze     = 1; // M10
int Use_Grey           = 1; // M11
int Use_Flag           = 1; // M12

// M1
int M1_BB_Period = 20; var M1_BB_Dev = 2.0;
int M1_Stoch_K = 14; int M1_Stoch_D = 3; int M1_Stoch_Slowing = 3;
var M1_Stoch_OS = 20.0; var M1_Stoch_OB = 80.0;
int M1_UseRangeFilter = 1; int M1_ADX_Period = 14; var M1_ADX_RangeMax = 25.0;
int M1_UseReversionConfirm = 1;
var M1_TrailMult = 1.0; var M1_TrailStart = 1.0;
var M1_BE_Mult = 1.0; var M1_SL_Mult = 1.5; var M1_TP_Mult = 1.5;

// M2
int M2_BB_Period = 20; var M2_BB_Dev = 2.0;
int M2_RSI_Period = 14; var M2_RSI_OS = 30.0; var M2_RSI_OB = 70.0;
int M2_UseRangeFilter = 1; int M2_ADX_Period = 14; var M2_ADX_RangeMax = 25.0;
int M2_UseReversionConfirm = 1;
int M2_TP_AtMid = 1;
int M2_StructuralSL = 1;
var M2_SL_Buffer = 0.5;
var M2_TrailMult = 1.0; var M2_TrailStart = 0.8;
var M2_BE_Mult = 1.0; var M2_SL_Mult = 1.5; var M2_TP_Mult = 2.0;

// M3
int M3_EMA_Period = 20; int M3_ATR_Period = 10; var M3_ATR_Mult = 2.0;
int M3_Stoch_K = 14; int M3_Stoch_D = 3; int M3_Stoch_Slowing = 3;
var M3_Stoch_OS = 20.0; var M3_Stoch_OB = 80.0;
int M3_UseRangeFilter = 0; int M3_ADX_Period = 14; var M3_ADX_RangeMax = 25.0;
var M3_TrailMult = 1.5; var M3_TrailStart = 1.0;
var M3_BE_Mult = 1.0; var M3_SL_Mult = 1.5; var M3_TP_Mult = 2.5;

// M4
int M4_Tenkan = 9; int M4_Kijun = 26; int M4_Senkou = 52;
int M4_Stoch_K = 14; int M4_Stoch_D = 3; int M4_Stoch_Slowing = 3;
var M4_Stoch_OS = 40.0; var M4_Stoch_OB = 60.0;
int M4_UseADXFilter = 0; int M4_ADX_Period = 14; var M4_ADX_Min = 20.0;
var M4_TrailMult = 2.0; var M4_TrailStart = 1.5;
var M4_BE_Mult = 1.0; var M4_SL_Mult = 1.5; var M4_TP_Mult = 3.0;

// M5
int M5_ATR_Period = 10; var M5_ATR_Mult = 3.0;
int M5_RSI_Period = 14; var M5_RSI_OS = 35.0; var M5_RSI_OB = 65.0;
var M5_RSI_BuyLo = 40.0; var M5_RSI_SellHi = 60.0;
int M5_UseADXFilter = 1; int M5_ADX_Period = 14; var M5_ADX_Min = 25.0;
int M5_UseTrendAlign = 1; int M5_TrendEMA = 100;
int M5_MomConfirm = 1;
var M5_TrailMult = 2.5; var M5_TrailStart = 1.5;
var M5_BE_Mult = 1.0; var M5_SL_Mult = 1.5; var M5_TP_Mult = 3.0;

// M6
int M6_EMA_Fast = 9; int M6_EMA_Slow = 21; int M6_EMA_Trend = 50;
int M6_ADX_Period = 14; var M6_ADX_Min = 25.0; var M6_DI_Sep = 3.0;
int M6_RequirePullback = 0; int M6_UseSlopeFilter = 1;
var M6_TrailMult = 2.0; var M6_TrailStart = 1.5;
var M6_BE_Mult = 1.0; var M6_SL_Mult = 1.5; var M6_TP_Mult = 3.0;

// M7
int M7_Donch_Period = 20;
int M7_UseADXFilter = 1; int M7_ADX_Period = 14; var M7_ADX_Min = 30.0;
int M7_UseTrendAlign = 1; int M7_TrendEMA = 100;
int M7_UseSlopeFilter = 1;
var M7_MaxExtATR = 1.0;
var M7_TrailMult = 2.5; var M7_TrailStart = 1.5;
var M7_BE_Mult = 1.0; var M7_SL_Mult = 1.5; var M7_TP_Mult = 3.5;

// M8
int M8_MACD_Fast = 12; int M8_MACD_Slow = 26; int M8_MACD_Signal = 9;
int M8_TrendEMA = 100;
int M8_RequireZeroSide = 1;
int M8_UseSlopeFilter = 0;
int M8_UseADXFilter = 1; int M8_ADX_Period = 14; var M8_ADX_Min = 20.0;
var M8_TrailMult = 2.0; var M8_TrailStart = 1.5;
var M8_BE_Mult = 1.0; var M8_SL_Mult = 1.5; var M8_TP_Mult = 3.0;

// M9
int M9_RSI_Period = 14; var M9_RSI_OS = 35.0; var M9_RSI_OB = 65.0;
int M9_UseRangeFilter = 1; int M9_ADX_Period = 14; var M9_ADX_RangeMax = 25.0;
int M9_RequireSustain = 1;
var M9_TrailMult = 1.0; var M9_TrailStart = 0.8;
var M9_BE_Mult = 1.0; var M9_SL_Mult = 1.5; var M9_TP_Mult = 1.8;

// M10
int M10_BB_Period = 20; var M10_BB_Dev = 2.0; var M10_SqueezeRatio = 0.8;
int M10_UseADXFilter = 1; int M10_ADX_Period = 14; var M10_ADX_Min = 30.0;
int M10_UseTrendAlign = 1; int M10_TrendEMA = 100;
var M10_TrailMult = 2.5; var M10_TrailStart = 1.5;
var M10_BE_Mult = 1.0; var M10_SL_Mult = 1.5; var M10_TP_Mult = 3.5;

// M11
int M11_Period = 24;
int M11_Filter = 250;
int M11_UseTrendFilter = 1; int M11_TrendEMA = 100;
int M11_RequirePersist = 1;
var M11_TrailMult = 2.0; var M11_TrailStart = 1.5;
var M11_BE_Mult = 1.0; var M11_SL_Mult = 1.5; var M11_TP_Mult = 3.0;

// M12
int M12_PoleBars = 5;
var M12_PoleATRMult = 1.8;
int M12_FlagBars = 5;
var M12_FlagMaxATR = 1.6;
int M12_UseTrendFilter = 1; int M12_MA_Period = 200;
var M12_SL_PoleMult = 1.0;
var M12_TP_PoleMult = 1.5;
var M12_TrailMult = 2.5; var M12_TrailStart = 1.5;
var M12_BE_Mult = 1.0;

// Zorro asset names. Adjust to your Assets*.csv / broker mapping.
// lite-C can be picky with global string-array initializers, so use a function
// instead of: string Symbols[3] = { "EUR/USD", "GBP/USD", "XAU/USD" };
#define NUM_SYMBOLS 3

int Use_EURUSD = 1;
int Use_GBPUSD = 0; // enable after importing GBPUSD history files
int Use_XAUUSD = 0; // enable after importing XAUUSD history files

string SymbolName(int Index)
{
	if(Index == 0) return "EUR/USD";
	if(Index == 1) return "GBP/USD";
	if(Index == 2) return "XAU/USD";
	return "";
}

int SymbolEnabled(int Index)
{
	if(Index == 0) return Use_EURUSD;
	if(Index == 1) return Use_GBPUSD;
	if(Index == 2) return Use_XAUUSD;
	return 0;
}

// -----------------------------------------------------------------------------
// Utility
// -----------------------------------------------------------------------------

int contains(string s,string token)
{
	if(strstr(s,token) != 0) return 1;
	return 0;
}

int isForexAsset()
{
	if(contains(Asset,"EUR")) return 1;
	if(contains(Asset,"GBP")) return 1;
	if(contains(Asset,"USD") && !contains(Asset,"XAU")) return 1;
	return 0;
}

int isMetalAsset()
{
	if(contains(Asset,"XAU")) return 1;
	if(contains(Asset,"XAG")) return 1;
	if(contains(Asset,"GOLD")) return 1;
	if(contains(Asset,"SILVER")) return 1;
	return 0;
}

int ModuleRuns(int idx)
{
	if(idx == 0 && !Use_BB_Stoch) return 0;
	if(idx == 1 && !Use_BB_RSI) return 0;
	if(idx == 2 && !Use_Keltner_Stoch) return 0;
	if(idx == 3 && !Use_Ichimoku_Stoch) return 0;
	if(idx == 4 && !Use_Supertrend_RSI) return 0;
	if(idx == 5 && !Use_EMA_ADX) return 0;
	if(idx == 6 && !Use_Donchian) return 0;
	if(idx == 7 && !Use_MACD_EMA) return 0;
	if(idx == 8 && !Use_RSI_MR) return 0;
	if(idx == 9 && !Use_BB_Squeeze) return 0;
	if(idx == 10 && !Use_Grey) return 0;
	if(idx == 11 && !Use_Flag) return 0;

	// v8.11 logic from the uploaded EA:
	// FOREX = M3 + M9 only.
	if(isForexAsset())
	{
		if(idx == 2) return 1;
		if(idx == 8) return 1;
		return 0;
	}

	// METALS = M3,M5,M6,M7,M8,M9,M10,M12.
	if(isMetalAsset())
	{
		if(idx == 2) return 1;
		if(idx == 4) return 1;
		if(idx == 5) return 1;
		if(idx == 6) return 1;
		if(idx == 7) return 1;
		if(idx == 8) return 1;
		if(idx == 9) return 1;
		if(idx == 11) return 1;
		return 0;
	}

	return 1;
}

int IsModuleBar(int tf)
{
	if(tf <= 1) return 1;
	if(Bar % tf == 0) return 1;
	return 0;
}

int SessionOK(int tf)
{
	if(!UseSessionFilter) return 1;
	if(tf >= TF_D1) return 1;
	if(hour(0) >= SessionStartHour && hour(0) < SessionEndHour) return 1;
	return 0;
}

int CountTotalOpen()
{
	int n = 0;
	for(open_trades)
		n++;
	return n;
}

int CurrentAlgoHasOpen()
{
	int n = 0;
	for(current_trades)
		n++;
	if(n > 0) return 1;
	return 0;
}

var clampv(var x,var lo,var hi)
{
	if(x < lo) return lo;
	if(x > hi) return hi;
	return x;
}

var highestS(vars Data,int offset,int period)
{
	var h = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] > h) h = Data[i];
	return h;
}

var lowestS(vars Data,int offset,int period)
{
	var l = Data[offset];
	int i;
	for(i=offset+1;i<offset+period;i++)
		if(Data[i] < l) l = Data[i];
	return l;
}

var smaAt(vars Data,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += Data[i];
	return sum/period;
}

var stdAt(vars Data,int offset,int period)
{
	var m = smaAt(Data,offset,period);
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
		sum += (Data[i]-m)*(Data[i]-m);
	return sqrt(sum/period);
}

var emaAt(vars Data,int offset,int period)
{
	int start = offset + period*3;
	var a = 2.0/(period+1.0);
	var e = Data[start];
	int i;
	for(i=start-1;i>=offset;i--)
		e = a*Data[i] + (1.0-a)*e;
	return e;
}

void bbAt(vars C,int period,var dev,int offset,var* mid,var* upper,var* lower)
{
	*mid = smaAt(C,offset,period);
	var sd = stdAt(C,offset,period);
	*upper = *mid + dev*sd;
	*lower = *mid - dev*sd;
}

var atrAt(vars H,vars L,vars C,int offset,int period)
{
	var sum = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var a = H[i]-L[i];
		var b = abs(H[i]-C[i+1]);
		var c = abs(L[i]-C[i+1]);
		var tr = max(a,max(b,c));
		sum += tr;
	}
	return sum/period;
}

var rsiAt(vars C,int offset,int period)
{
	var up = 0;
	var dn = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var d = C[i]-C[i+1];
		if(d > 0) up += d;
		else dn -= d;
	}
	if(dn <= 0) return 100;
	var rs = up/dn;
	return 100.0 - 100.0/(1.0+rs);
}

void stochAt(vars H,vars L,vars C,int kPeriod,int dPeriod,int offset,var* kOut,var* dOut)
{
	var hh = highestS(H,offset,kPeriod);
	var ll = lowestS(L,offset,kPeriod);
	if(hh == ll)
		*kOut = 50;
	else
		*kOut = 100.0*(C[offset]-ll)/(hh-ll);

	var sum = 0;
	int j;
	for(j=0;j<dPeriod;j++)
	{
		var h2 = highestS(H,offset+j,kPeriod);
		var l2 = lowestS(L,offset+j,kPeriod);
		var k2 = 50;
		if(h2 != l2) k2 = 100.0*(C[offset+j]-l2)/(h2-l2);
		sum += k2;
	}
	*dOut = sum/dPeriod;
}

var adxApprox(vars H,vars L,vars C,int offset,int period,var* diPlus,var* diMinus)
{
	var trsum = 0;
	var pdm = 0;
	var mdm = 0;
	int i;
	for(i=offset;i<offset+period;i++)
	{
		var upMove = H[i]-H[i+1];
		var dnMove = L[i+1]-L[i];
		if(upMove > dnMove && upMove > 0) pdm += upMove;
		if(dnMove > upMove && dnMove > 0) mdm += dnMove;

		var tr = max(H[i]-L[i],max(abs(H[i]-C[i+1]),abs(L[i]-C[i+1])));
		trsum += tr;
	}
	if(trsum <= 0)
	{
		*diPlus = 0;
		*diMinus = 0;
		return 0;
	}
	*diPlus = 100.0*pdm/trsum;
	*diMinus = 100.0*mdm/trsum;

	var den = *diPlus + *diMinus;
	if(den <= 0) return 0;
	return 100.0*abs(*diPlus-*diMinus)/den;
}

var macdLineAt(vars C,int offset,int fast,int slow)
{
	return emaAt(C,offset,fast)-emaAt(C,offset,slow);
}

var macdSignalAt(vars C,int offset,int fast,int slow,int sig)
{
	var tmp[100];
	int i;
	int n = sig*3;
	if(n > 90) n = 90;
	for(i=0;i<n;i++)
		tmp[i] = macdLineAt(C,offset+i,fast,slow);
	var a = 2.0/(sig+1.0);
	var e = tmp[n-1];
	for(i=n-2;i>=0;i--)
		e = a*tmp[i] + (1.0-a)*e;
	return e;
}

int trendQualityOK(vars H,vars L,vars C,int regime)
{
	if(!UseTrendQualityGate) return 1;
	if(regime != -1) return 1;

	var p,m;
	var adx = adxApprox(H,L,C,0,TQ_ADX_Period,&p,&m);
	if(adx >= TQ_ADX_Min) return 1;
	return 0;
}

var adaptFactor(vars H,vars L,vars C)
{
	if(!UseAdaptiveMults) return 1.0;
	var fast = atrAt(H,L,C,0,Adapt_FastATR);
	var slow = atrAt(H,L,C,0,Adapt_SlowATR);
	if(slow <= 0) return 1.0;
	return clampv(fast/slow,Adapt_Min,Adapt_Max);
}

int directionBlocked(int dir,vars C)
{
	int isBuy = 0;
	if(dir > 0) isBuy = 1;

	if(UseRegimeDirection)
	{
		// Uses current module's timeframe as a practical approximation.
		// For a strict D1 regime filter, move this calculation into a dedicated D1 TimeFrame block.
		var ma0 = smaAt(C,0,Regime_MA);
		var ma1 = smaAt(C,1,Regime_MA);
		int slopeUp = 0;
		int slopeDn = 0;
		if(ma0 > ma1) slopeUp = 1;
		if(ma0 < ma1) slopeDn = 1;

		if(C[0] > ma0 && (!Regime_UseSlope || slopeUp))
		{
			if(!isBuy) return 1;
			return 0;
		}
		if(C[0] < ma0 && (!Regime_UseSlope || slopeDn))
		{
			if(isBuy) return 1;
			return 0;
		}
		if(Regime_NeutralAllowBoth) return 0;
		return 1;
	}

	if(isBuy && !AllowLongs) return 1;
	if(!isBuy && !AllowShorts) return 1;
	return 0;
}

void openTradeDir(int dir,string name,var slDist,var tpDist,var trailMult,var trailStart,var beMult,vars C)
{
	if(slDist <= 0 || tpDist <= 0) return;
	if(directionBlocked(dir,C)) return;
	if(!ARIMAAllowsDirection(dir,C)) return;
	if(UseRiskCap && MaxOpenPositions > 0 && CountTotalOpen() >= MaxOpenPositions) return;

	algo(name);
	if(CurrentAlgoHasOpen()) return;

	Stop = slDist;
	TakeProfit = tpDist;

	// Zorro has no global BreakEven variable.
	// Breakeven-style behavior is approximated through TrailLock.
	// TrailLock = 1 moves the stop to about entry/breakeven once the Trail trigger is reached.
	// IMPORTANT: reset all trail-related globals before every new trade so values do not leak
	// from one module/component into the next.
	Trail = 0;
	TrailSlope = 100;
	TrailLock = 0;
	TrailStep = 0;

	if(UseTrailing)
		Trail = trailMult*slDist;

	if(UseBreakeven && Trail > 0)
		TrailLock = 1;

	var base = FixedRiskBalance;
	if(!UseFixedRiskBase) base = Balance;
	Risk = base*RiskPercent/100.0;

	if(dir > 0)
		enterLong();
	else
		enterShort();
}

// -----------------------------------------------------------------------------
// M11 Grey estimator
// -----------------------------------------------------------------------------

var greyMA(vars O,int offset,int period)
{
	if(period < 3) period = 3;

	var grey[80];
	var rez[1600];
	int j,k,cnt;
	if(period > 40) period = 40;

	for(j=0;j<period;j++)
		grey[j] = O[offset+j];

	for(j=period-2;j>=0;j--)
		grey[j] = grey[j] + grey[j+1];

	cnt = 0;
	for(j=period-2;j>=0;j--)
	{
		for(k=j+1;k<period;k++)
		{
			rez[cnt] = (grey[j]-grey[k])/(k-j);
			cnt++;
		}
	}

	// simple ascending sort
	int a,b;
	for(a=0;a<cnt-1;a++)
	{
		for(b=a+1;b<cnt;b++)
		{
			if(rez[b] < rez[a])
			{
				var t = rez[a];
				rez[a] = rez[b];
				rez[b] = t;
			}
		}
	}

	int i1 = cnt/2;
	int i2 = i1;
	if(cnt%2 == 0) i2 = i1 + 1;
	if(i2 >= cnt) i2 = cnt-1;

	return (rez[i1]+rez[i2])/2.0;
}

// -----------------------------------------------------------------------------
// Modules
// -----------------------------------------------------------------------------

void Module1_BB_Stoch()
{
	if(!ModuleRuns(0)) return;

	TimeFrame = TF_M30;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_MaxAdaptiveN);
	vars StochKS = series(0,ARIMA_MaxAdaptiveN);
	vars WidthS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_M30)) return;
	if(!SessionOK(TF_M30)) return;

	if(!trendQualityOK(H,L,C,1)) return;

	var dip,dim;
	if(M1_UseRangeFilter)
		if(adxApprox(H,L,C,0,M1_ADX_Period,&dip,&dim) >= M1_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M1_BB_Period,M1_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M1_BB_Period,M1_BB_Dev,1,&m2,&u2,&l2);

	var k1,d1;
	stochAt(H,L,C,M1_Stoch_K,M1_Stoch_D,0,&k1,&d1);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	var widthNow = (u1-l1)/fix0(m1);
	if(widthNow <= 0) widthNow = 0.0001;

	BandPosS[0] = bandPos;
	StochKS[0] = clampv(k1,1.,99.);
	WidthS[0] = widthNow;

	int BOk = 0;
	int SOk = 0;
	int WOk = 0;
	var bandF = ARIMAForecastMeta("AP1_BandOsc","band",BandPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&BOk);
	var stochF = ARIMAForecastMeta("AP1_BandOsc","stoch",StochKS,ARIMA_N,0.01,ARIMA_MinOscDelta,&SOk);
	var widthF = ARIMAForecastMeta("AP1_BandOsc","width",WidthS,ARIMA_N,0.0001,ARIMA_MinWidthDelta,&WOk);

	int buy = 0;
	int sell = 0;

	if(BOk && SOk && WOk)
	{
		if(bandPos < 40. and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			buy = 1;

		if(bandPos > 60. and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stochF,k1,ARIMA_MinOscDelta)
			and widthF <= widthNow*1.08)
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP1_BandOsc",M1_SL_Mult*af*atr,M1_TP_Mult*af*atr,M1_TrailMult,M1_TrailStart,M1_BE_Mult,C);
}


void Module2_BB_RSI()
{
	if(!ModuleRuns(1)) return;

	TimeFrame = TF_H2;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars BandPosS = series(0,ARIMA_MaxAdaptiveN);
	vars RSIS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H2)) return;
	if(!SessionOK(TF_H2)) return;

	var dip,dim;
	if(M2_UseRangeFilter)
		if(adxApprox(H,L,C,0,M2_ADX_Period,&dip,&dim) >= M2_ADX_RangeMax) return;

	var m1,u1,l1,m2,u2,l2;
	bbAt(C,M2_BB_Period,M2_BB_Dev,0,&m1,&u1,&l1);
	bbAt(C,M2_BB_Period,M2_BB_Dev,1,&m2,&u2,&l2);

	var r0 = rsiAt(C,0,M2_RSI_Period);

	var bandRange = u1-l1;
	if(bandRange <= 0) return;

	var bandPos = 100.0*(C[0]-l1)/bandRange;
	bandPos = clampv(bandPos,1.,99.);

	BandPosS[0] = bandPos;
	RSIS[0] = clampv(r0,1.,99.);

	int BOk = 0;
	int ROk = 0;
	var bandF = ARIMAForecastMeta("AP2_RSIState","band",BandPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&BOk);
	var rF = ARIMAForecastMeta("AP2_RSIState","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);

	int buy = 0;
	int sell = 0;

	if(BOk && ROk)
	{
		if(bandPos < 42. and r0 < M2_RSI_OS+10.
			and ARIMAForecastUp(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(bandPos > 58. and r0 > M2_RSI_OB-10.
			and ARIMAForecastDown(bandF,bandPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	var slDist = M2_SL_Mult*af*atr;
	var tpDist = M2_TP_Mult*af*atr;

	if(M2_TP_AtMid)
	{
		if(buy)
		{
			tpDist = max(m1-priceClose(0),0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max(priceClose(0)-(min(L[0],L[1])-M2_SL_Buffer*af*atr),0.5*af*atr);
			openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
		if(sell)
		{
			tpDist = max(priceClose(0)-m1,0.8*af*atr);
			if(M2_StructuralSL)
				slDist = max((max(H[0],H[1])+M2_SL_Buffer*af*atr)-priceClose(0),0.5*af*atr);
			openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		}
	}
	else
	{
		if(buy) openTradeDir(1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
		if(sell) openTradeDir(-1,"AP2_RSIState",slDist,tpDist,M2_TrailMult,M2_TrailStart,M2_BE_Mult,C);
	}
}


void Module3_Keltner_Stoch()
{
	if(!ModuleRuns(2)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars KPosS = series(0,ARIMA_MaxAdaptiveN);
	vars StochS = series(0,ARIMA_MaxAdaptiveN);

	var dip,dim;
	if(M3_UseRangeFilter)
		if(adxApprox(H,L,C,0,M3_ADX_Period,&dip,&dim) >= M3_ADX_RangeMax) return;

	var ema0 = emaAt(C,0,M3_EMA_Period);
	var atrK0 = atrAt(H,L,C,0,M3_ATR_Period);
	if(atrK0 <= 0) return;

	var k0,d0;
	stochAt(H,L,C,M3_Stoch_K,M3_Stoch_D,0,&k0,&d0);

	var kPos = 50.0 + 50.0*(C[0]-ema0)/fix0(M3_ATR_Mult*atrK0);
	kPos = clampv(kPos,1.,99.);

	KPosS[0] = kPos;
	StochS[0] = clampv(k0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int KOk = 0;
	int SOk = 0;
	var kPosF = ARIMAForecastMeta("AP3_ChannelOsc","kpos",KPosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&KOk);
	var stF = ARIMAForecastMeta("AP3_ChannelOsc","stoch",StochS,ARIMA_N,0.01,ARIMA_MinOscDelta,&SOk);

	int buy = 0;
	int sell = 0;

	if(KOk && SOk)
	{
		if(kPos < 45. and ARIMAForecastUp(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastUp(stF,k0,ARIMA_MinOscDelta))
			buy = 1;

		if(kPos > 55. and ARIMAForecastDown(kPosF,kPos,ARIMA_MinOscDelta)
			and ARIMAForecastDown(stF,k0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP3_ChannelOsc",M3_SL_Mult*af*atr,M3_TP_Mult*af*atr,M3_TrailMult,M3_TrailStart,M3_BE_Mult,C);
}


void Module4_Ichimoku_Stoch()
{
	if(!ModuleRuns(3)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars SpreadS = series(0,ARIMA_MaxAdaptiveN);
	vars CloudS = series(0,ARIMA_MaxAdaptiveN);
	vars StochS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M4_UseADXFilter)
		if(adxApprox(H,L,C,0,M4_ADX_Period,&dip,&dim) < M4_ADX_Min) return;

	var tenkan0 = (highestS(H,0,M4_Tenkan)+lowestS(L,0,M4_Tenkan))/2.0;
	var kijun0  = (highestS(H,0,M4_Kijun)+lowestS(L,0,M4_Kijun))/2.0;
	var senkouA = (tenkan0+kijun0)/2.0;
	var senkouB = (highestS(H,0,M4_Senkou)+lowestS(L,0,M4_Senkou))/2.0;
	var top = max(senkouA,senkouB);
	var bot = min(senkouA,senkouB);
	var cloudMid = (top+bot)/2.0;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;
	if(top-bot < atr*0.3) return;

	var k,d;
	stochAt(H,L,C,M4_Stoch_K,M4_Stoch_D,0,&k,&d);

	var spreadScore = 50.0 + 20.0*(tenkan0-kijun0)/atr;
	var cloudScore = 50.0 + 20.0*(C[0]-cloudMid)/atr;
	spreadScore = clampv(spreadScore,1.,99.);
	cloudScore = clampv(cloudScore,1.,99.);

	SpreadS[0] = spreadScore;
	CloudS[0] = cloudScore;
	StochS[0] = clampv(k,1.,99.);

	int SpOk = 0;
	int ClOk = 0;
	int StOk = 0;
	var spF = ARIMAForecastMeta("AP4_CloudFlow","spread",SpreadS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&SpOk);
	var clF = ARIMAForecastMeta("AP4_CloudFlow","cloud",CloudS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&ClOk);
	var stF = ARIMAForecastMeta("AP4_CloudFlow","stoch",StochS,ARIMA_N,0.01,ARIMA_MinOscDelta,&StOk);

	int buy = 0;
	int sell = 0;

	if(SpOk && ClOk && StOk)
	{
		if(spF > 52. and clF > 52.
			and ARIMAForecastUp(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF > k)
			buy = 1;

		if(spF < 48. and clF < 48.
			and ARIMAForecastDown(spF,spreadScore,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(clF,cloudScore,ARIMA_MinTrendDelta)
			and stF < k)
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP4_CloudFlow",M4_SL_Mult*af*atr,M4_TP_Mult*af*atr,M4_TrailMult,M4_TrailStart,M4_BE_Mult,C);
}


int superDir(vars H,vars L,vars C,int atrPeriod,var mult,int offset)
{
	var atr = atrAt(H,L,C,offset,atrPeriod);
	var mid = (H[offset]+L[offset])/2.0;
	if(C[offset] > mid + mult*atr*0.25) return 1;
	if(C[offset] < mid - mult*atr*0.25) return -1;
	return 0;
}

void Module5_Supertrend_RSI()
{
	if(!ModuleRuns(4)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PressureS = series(0,ARIMA_MaxAdaptiveN);
	vars RSIS = series(0,ARIMA_MaxAdaptiveN);
	vars TrendS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dip,dim;
	if(M5_UseADXFilter)
		if(adxApprox(H,L,C,0,M5_ADX_Period,&dip,&dim) < M5_ADX_Min) return;

	var atrST = atrAt(H,L,C,0,M5_ATR_Period);
	if(atrST <= 0) return;

	var mid = (H[0]+L[0])/2.0;
	var pressure = 50.0 + 20.0*(C[0]-mid)/fix0(M5_ATR_Mult*atrST);
	pressure = clampv(pressure,1.,99.);

	var r0 = rsiAt(C,0,M5_RSI_Period);
	var emaT = emaAt(C,0,M5_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-emaT)/fix0(atrST);
	trendScore = clampv(trendScore,1.,99.);

	PressureS[0] = pressure;
	RSIS[0] = clampv(r0,1.,99.);
	TrendS[0] = trendScore;

	int POk = 0;
	int ROk = 0;
	int TOk = 0;
	var pF = ARIMAForecastMeta("AP5_Pressure","pressure",PressureS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&POk);
	var rF = ARIMAForecastMeta("AP5_Pressure","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);
	var tF = ARIMAForecastMeta("AP5_Pressure","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && ROk && TOk)
	{
		if(pF > 52. and tF > 52. and rF > M5_RSI_BuyLo
			and ARIMAForecastUp(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 48. and tF < 48. and rF < M5_RSI_SellHi
			and ARIMAForecastDown(pF,pressure,ARIMA_MinTrendDelta)
			and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);

	if(buy)
		openTradeDir(1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);

	if(sell)
		openTradeDir(-1,"AP5_Pressure",M5_SL_Mult*af*atr,M5_TP_Mult*af*atr,M5_TrailMult,M5_TrailStart,M5_BE_Mult,C);
}


void Module6_EMA_ADX()
{
	if(!ModuleRuns(5)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars EmaS = series(0,ARIMA_MaxAdaptiveN);
	vars TrendS = series(0,ARIMA_MaxAdaptiveN);
	vars DiS = series(0,ARIMA_MaxAdaptiveN);
	vars AdxS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var eF0 = emaAt(C,0,M6_EMA_Fast);
	var eS0 = emaAt(C,0,M6_EMA_Slow);
	var eT0 = emaAt(C,0,M6_EMA_Trend);
	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var dp,dm;
	var adx0 = adxApprox(H,L,C,0,M6_ADX_Period,&dp,&dm);

	var emaScore = 50.0 + 20.0*(eF0-eS0)/atr;
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	var diScore = 50.0 + (dp-dm);
	emaScore = clampv(emaScore,1.,99.);
	trendScore = clampv(trendScore,1.,99.);
	diScore = clampv(diScore,1.,99.);

	EmaS[0] = emaScore;
	TrendS[0] = trendScore;
	DiS[0] = diScore;
	AdxS[0] = clampv(adx0,1.,99.);

	int EOk = 0;
	int TOk = 0;
	int DOk = 0;
	int AOk = 0;
	var eF = ARIMAForecastMeta("AP6_DriftADX","ema",EmaS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&EOk);
	var tF = ARIMAForecastMeta("AP6_DriftADX","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);
	var dF = ARIMAForecastMeta("AP6_DriftADX","di",DiS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&DOk);
	var aF = ARIMAForecastMeta("AP6_DriftADX","adx",AdxS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&AOk);

	int buy = 0;
	int sell = 0;

	if(EOk && TOk && DOk && AOk)
	{
		if(eF > 52. and tF > 52. and dF > 52. and aF > M6_ADX_Min
			and ARIMAForecastUp(eF,emaScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(eF < 48. and tF < 48. and dF < 48. and aF > M6_ADX_Min
			and ARIMAForecastDown(eF,emaScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP6_DriftADX",M6_SL_Mult*af*atr,M6_TP_Mult*af*atr,M6_TrailMult,M6_TrailStart,M6_BE_Mult,C);
}


void Module7_Donchian()
{
	if(!ModuleRuns(6)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PosS = series(0,ARIMA_MaxAdaptiveN);
	vars TrendS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M7_UseADXFilter)
		if(adxApprox(H,L,C,0,M7_ADX_Period,&dp,&dm) < M7_ADX_Min) return;

	var dHi = highestS(H,1,M7_Donch_Period);
	var dLo = lowestS(L,1,M7_Donch_Period);
	var width = dHi-dLo;
	if(width <= 0) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var pos = 100.0*(C[0]-dLo)/width;
	pos = clampv(pos,1.,99.);

	var eT0 = emaAt(C,0,M7_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	PosS[0] = pos;
	TrendS[0] = trendScore;

	int POk = 0;
	int TOk = 0;
	var pF = ARIMAForecastMeta("AP7_RangeFlow","pos",PosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&POk);
	var tF = ARIMAForecastMeta("AP7_RangeFlow","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(POk && TOk)
	{
		if(pF > 80. and tF > 52.
			and ARIMAForecastUp(pF,pos,ARIMA_MinOscDelta))
			buy = 1;

		if(pF < 20. and tF < 48.
			and ARIMAForecastDown(pF,pos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M7_MaxExtATR > 0 && atr > 0)
	{
		if(buy && (C[0]-dHi) > M7_MaxExtATR*atr) buy = 0;
		if(sell && (dLo-C[0]) > M7_MaxExtATR*atr) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP7_RangeFlow",M7_SL_Mult*af*atr,M7_TP_Mult*af*atr,M7_TrailMult,M7_TrailStart,M7_BE_Mult,C);
}


void Module8_MACD_EMA()
{
	if(!ModuleRuns(7)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars HistS = series(0,ARIMA_MaxAdaptiveN);
	vars TrendS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M8_UseADXFilter)
		if(adxApprox(H,L,C,0,M8_ADX_Period,&dp,&dm) < M8_ADX_Min) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var macd0 = macdLineAt(C,0,M8_MACD_Fast,M8_MACD_Slow);
	var sig0 = macdSignalAt(C,0,M8_MACD_Fast,M8_MACD_Slow,M8_MACD_Signal);
	var hist = macd0-sig0;
	var histScore = 50.0 + 50.0*hist/atr;
	histScore = clampv(histScore,1.,99.);

	var eT0 = emaAt(C,0,M8_TrendEMA);
	var trendScore = 50.0 + 20.0*(C[0]-eT0)/atr;
	trendScore = clampv(trendScore,1.,99.);

	HistS[0] = histScore;
	TrendS[0] = trendScore;

	int HOk = 0;
	int TOk = 0;
	var hF = ARIMAForecastMeta("AP8_MacdFlow","hist",HistS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&HOk);
	var tF = ARIMAForecastMeta("AP8_MacdFlow","trend",TrendS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&TOk);

	int buy = 0;
	int sell = 0;

	if(HOk && TOk)
	{
		if(hF > 52. and tF > 52.
			and ARIMAForecastUp(hF,histScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(hF < 48. and tF < 48.
			and ARIMAForecastDown(hF,histScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP8_MacdFlow",M8_SL_Mult*af*atr,M8_TP_Mult*af*atr,M8_TrailMult,M8_TrailStart,M8_BE_Mult,C);
}


void Module9_RSI_MR()
{
	if(!ModuleRuns(8)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars RSIS = series(0,ARIMA_MaxAdaptiveN);

	var dp,dm;
	if(M9_UseRangeFilter)
		if(adxApprox(H,L,C,0,M9_ADX_Period,&dp,&dm) >= M9_ADX_RangeMax) return;

	var r0 = rsiAt(C,0,M9_RSI_Period);
	var r2 = rsiAt(C,2,M9_RSI_Period);

	RSIS[0] = clampv(r0,1.,99.);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	int ROk = 0;
	var rF = ARIMAForecastMeta("AP9_RSIPath","rsi",RSIS,ARIMA_N,0.01,ARIMA_MinOscDelta,&ROk);

	int buy = 0;
	int sell = 0;

	if(ROk)
	{
		if(r0 < 45. and ARIMAForecastUp(rF,r0,ARIMA_MinOscDelta))
			buy = 1;

		if(r0 > 55. and ARIMAForecastDown(rF,r0,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M9_RequireSustain)
	{
		if(buy && r2 > 50.) buy = 0;
		if(sell && r2 < 50.) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP9_RSIPath",M9_SL_Mult*af*atr,M9_TP_Mult*af*atr,M9_TrailMult,M9_TrailStart,M9_BE_Mult,C);
}


void Module10_BB_Squeeze()
{
	if(!ModuleRuns(9)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars WidthS = series(0,ARIMA_MaxAdaptiveN);
	vars PosS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var dp,dm;
	if(M10_UseADXFilter)
		if(adxApprox(H,L,C,0,M10_ADX_Period,&dp,&dm) < M10_ADX_Min) return;

	var m0,u0,l0;
	bbAt(C,M10_BB_Period,M10_BB_Dev,0,&m0,&u0,&l0);
	var range = u0-l0;
	if(range <= 0) return;

	var avgW = 0;
	int i;
	for(i=1;i<21;i++)
	{
		var mi,ui,li;
		bbAt(C,M10_BB_Period,M10_BB_Dev,i,&mi,&ui,&li);
		avgW += (ui-li)/fix0(mi);
	}
	avgW /= 20.0;

	var widthNow = range/fix0(m0);
	if(widthNow <= 0) widthNow = 0.0001;

	var bandPos = 100.0*(C[0]-l0)/range;
	bandPos = clampv(bandPos,1.,99.);

	WidthS[0] = widthNow;
	PosS[0] = bandPos;

	int WOk = 0;
	int POk = 0;
	var wF = ARIMAForecastMeta("AP10_BandEnergy","width",WidthS,ARIMA_N,0.0001,ARIMA_MinWidthDelta,&WOk);
	var pF = ARIMAForecastMeta("AP10_BandEnergy","pos",PosS,ARIMA_N,0.01,ARIMA_MinOscDelta,&POk);

	int buy = 0;
	int sell = 0;

	if(WOk && POk)
	{
		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF > 62. and ARIMAForecastUp(pF,bandPos,ARIMA_MinOscDelta))
			buy = 1;

		if(widthNow < avgW*1.05 and wF > widthNow + ARIMA_MinWidthDelta
			and pF < 38. and ARIMAForecastDown(pF,bandPos,ARIMA_MinOscDelta))
			sell = 1;
	}

	if(M10_UseTrendAlign)
	{
		var e = emaAt(C,0,M10_TrendEMA);
		if(C[0] <= e) buy = 0;
		if(C[0] >= e) sell = 0;
	}

	var atr = atrAt(H,L,C,0,ATR_Period);
	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP10_BandEnergy",M10_SL_Mult*af*atr,M10_TP_Mult*af*atr,M10_TrailMult,M10_TrailStart,M10_BE_Mult,C);
}


void Module11_Grey()
{
	if(!ModuleRuns(10)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars O = series(priceOpen());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars GreyS = series(0,ARIMA_MaxAdaptiveN);
	vars SlopeS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	var g0 = greyMA(O,0,M11_Period);
	var g1 = greyMA(O,1,M11_Period);

	var greyScore = 50.0 + 20.0*(g0-O[0])/atr;
	var greySlope = 50.0 + 20.0*(g0-g1)/atr;
	greyScore = clampv(greyScore,1.,99.);
	greySlope = clampv(greySlope,1.,99.);

	GreyS[0] = greyScore;
	SlopeS[0] = greySlope;

	int GOk = 0;
	int SOk = 0;
	var gF = ARIMAForecastMeta("AP11_GreyPath","grey",GreyS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&GOk);
	var sF = ARIMAForecastMeta("AP11_GreyPath","slope",SlopeS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&SOk);

	int buy = 0;
	int sell = 0;

	if(GOk && SOk)
	{
		if(gF > 52. and sF > 52.
			and ARIMAForecastUp(gF,greyScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(gF < 48. and sF < 48.
			and ARIMAForecastDown(gF,greyScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M11_UseTrendFilter)
	{
		var e = emaAt(C,0,M11_TrendEMA);
		if(O[0] <= e) buy = 0;
		if(O[0] >= e) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	if(buy) openTradeDir(1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP11_GreyPath",M11_SL_Mult*af*atr,M11_TP_Mult*af*atr,M11_TrailMult,M11_TrailStart,M11_BE_Mult,C);
}


void Module12_Flag()
{
	if(!ModuleRuns(11)) return;

	TimeFrame = TF_H4;
	vars C = series(priceClose());
	vars H = series(priceHigh());
	vars L = series(priceLow());
	vars PoleS = series(0,ARIMA_MaxAdaptiveN);
	vars BreakS = series(0,ARIMA_MaxAdaptiveN);

	if(!IsModuleBar(TF_H4)) return;
	if(!SessionOK(TF_H4)) return;

	if(!trendQualityOK(H,L,C,-1)) return;

	var atr = atrAt(H,L,C,0,ATR_Period);
	if(atr <= 0) return;

	int fB = M12_FlagBars;
	int pB = M12_PoleBars;

	int pNew = fB+1;
	int pOld = fB+pB;
	var poleMove = C[pNew]-C[pOld];

	var poleHigh = H[pNew];
	var poleLow = L[pNew];
	int k;
	for(k=pNew;k<=pOld;k++)
	{
		if(H[k] > poleHigh) poleHigh = H[k];
		if(L[k] < poleLow) poleLow = L[k];
	}

	var poleHeight = poleHigh-poleLow;
	if(poleHeight <= 0) return;

	var flagHigh = H[1];
	var flagLow = L[1];
	for(k=1;k<=fB;k++)
	{
		if(H[k] > flagHigh) flagHigh = H[k];
		if(L[k] < flagLow) flagLow = L[k];
	}

	if((flagHigh-flagLow) > M12_FlagMaxATR*atr) return;

	var flagMid = (flagHigh+flagLow)/2.0;
	var poleScore = 50.0 + 10.0*poleMove/atr;
	var breakScore = 50.0 + 20.0*(C[0]-flagMid)/atr;
	poleScore = clampv(poleScore,1.,99.);
	breakScore = clampv(breakScore,1.,99.);

	PoleS[0] = poleScore;
	BreakS[0] = breakScore;

	int POk = 0;
	int BOk = 0;
	var pF = ARIMAForecastMeta("AP12_ShapePath","pole",PoleS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&POk);
	var bF = ARIMAForecastMeta("AP12_ShapePath","break",BreakS,ARIMA_N,0.01,ARIMA_MinTrendDelta,&BOk);

	int buy = 0;
	int sell = 0;

	if(POk && BOk)
	{
		if(pF > 55. and bF > 55.
			and ARIMAForecastUp(bF,breakScore,ARIMA_MinTrendDelta))
			buy = 1;

		if(pF < 45. and bF < 45.
			and ARIMAForecastDown(bF,breakScore,ARIMA_MinTrendDelta))
			sell = 1;
	}

	if(M12_UseTrendFilter)
	{
		var ma = smaAt(C,0,M12_MA_Period);
		if(C[0] <= ma) buy = 0;
		if(C[0] >= ma) sell = 0;
	}

	var af = adaptFactor(H,L,C);
	var slDist = poleHeight*M12_SL_PoleMult*af;
	var tpDist = poleHeight*M12_TP_PoleMult*af;

	if(buy) openTradeDir(1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
	if(sell) openTradeDir(-1,"AP12_ShapePath",slDist,tpDist,M12_TrailMult,M12_TrailStart,M12_BE_Mult,C);
}


// -----------------------------------------------------------------------------
// End-of-test CSV style log
// -----------------------------------------------------------------------------

void logClosedTrades()
{
	if(!is(EXITRUN)) return;

	file_delete("Log\\MultiStrategy_Trades_Zorro.csv");
	file_append("Log\\MultiStrategy_Trades_Zorro.csv",
		"asset,algo,profit\n",0);

	for(closed_trades)
	{
		file_append("Log\\MultiStrategy_Trades_Zorro.csv",
			strf("%s,%s,%.2f\n",Asset,Algo,(var)TradeProfit),0);
	}
}

// -----------------------------------------------------------------------------
// Main strategy
// -----------------------------------------------------------------------------

function run()
{
	set(PARAMETERS|OFF);

	BarPeriod = 30;
	LookBack = 2000;
	Capital = FixedRiskBalance;
	Hedge = 2;        // allow independent long/short components in backtest
	Fill = 3;         // more realistic order filling; adjust to your broker/data
	Slippage = 0;
	Spread = Spread; // keep asset-list spread

	if(is(INITRUN))
	{
		printf("\nArimaIndicatorMatrix v03 feedback started.");
		printf("\nIndicator forecasts use feedback-adaptive AutoAri parameters from prior prediction success.");

		ResetMetaState();

		if(UseARIMAMetaLog)
		{
			file_delete("Log\\ArimaIndicatorMeta.csv");
			file_append("Log\\ArimaIndicatorMeta.csv",
				"asset,bar,module,field,value,forecast,delta,rate20,meta_rel,raw_ok,meta_ok,use_n,use_p,use_q,delta_mult,err_norm,param_quality\n",0);
		}
	}

	int i;
	for(i=0;i<NUM_SYMBOLS;i++)
	{
		if(!SymbolEnabled(i))
			continue;

		if(!asset(SymbolName(i)))
			continue;

		// Run all converted modules. ModuleRuns() applies the v8.11 instrument gating.
		Module1_BB_Stoch();
		Module2_BB_RSI();
		Module3_Keltner_Stoch();
		Module4_Ichimoku_Stoch();
		Module5_Supertrend_RSI();
		Module6_EMA_ADX();
		Module7_Donchian();
		Module8_MACD_EMA();
		Module9_RSI_MR();
		Module10_BB_Squeeze();
		Module11_Grey();
		Module12_Flag();

		TimeFrame = 1;
	}

	if(is(EXITRUN))
		FreeARIMA();

	logClosedTrades();
}

Page 24 of 24 1 2 22 23 24

Moderated by  Petra 

Powered by UBB.threads™ PHP Forum Software 7.7.1