﻿//+------------------------------------------------------------------+
//|                                                ChartLauncher.mqh |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                          https://www.mql5.com/en/users/lynnchris |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"

#ifndef _CHART_LAUNCHER_MQH
#define _CHART_LAUNCHER_MQH

#include <Indicators\Indicators.mqh>

//+------------------------------------------------------------------+
//| Determines the target window: 0 = main chart, >0 = sub-window    |
//+------------------------------------------------------------------+
int GetTargetWindow(const ENUM_INDICATOR type)
  {
//--- Overlay indicators are drawn directly on the price chart
   switch(type)
     {
      case IND_MA:
      case IND_DEMA:
      case IND_TEMA:
      case IND_AMA:
      case IND_VIDYA:
      case IND_BANDS:
      case IND_ENVELOPES:
      case IND_ICHIMOKU:
      case IND_SAR:
      case IND_ALLIGATOR:
      case IND_FRACTALS:
         return(0);   
     }
//--- All other indicators go to a new sub‑window
   return((int)ChartGetInteger(0, CHART_WINDOWS_TOTAL));
  }

//+------------------------------------------------------------------+
//| Creates an indicator handle with sensible default parameters     |
//+------------------------------------------------------------------+
int CreateIndicator(const ENUM_INDICATOR type)
  {
   MqlParam params[];   
   int paramCount = 0;

//--- Build parameter arrays according to each indicator's signature
   switch(type)
     {
      //--- Oscillators (typically placed in sub‑windows)
      case IND_RSI:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;          
         params[1].type = TYPE_INT;
         params[1].integer_value = PRICE_CLOSE; 
         paramCount = 2;
         break;

      case IND_MACD:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 12;          
         params[1].type = TYPE_INT;
         params[1].integer_value = 26;          
         params[2].type = TYPE_INT;
         params[2].integer_value = 9;           
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         paramCount = 4;
         break;

      case IND_STOCHASTIC:
         ArrayResize(params, 5);
         params[0].type = TYPE_INT;
         params[0].integer_value = 5;           
         params[1].type = TYPE_INT;
         params[1].integer_value = 3;           
         params[2].type = TYPE_INT;
         params[2].integer_value = 3;           
         params[3].type = TYPE_INT;
         params[3].integer_value = MODE_SMA;    
         params[4].type = TYPE_INT;
         params[4].integer_value = PRICE_CLOSE;
         paramCount = 5;
         break;

      case IND_MFI:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         params[1].type = TYPE_INT;
         params[1].integer_value = VOLUME_TICK;
         paramCount = 2;
         break;

      case IND_CCI:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         params[1].type = TYPE_INT;
         params[1].integer_value = PRICE_CLOSE;
         paramCount = 2;
         break;

      //--- Indicators with zero parameters (just draw on price or volume)
      case IND_AO:
      case IND_AC:
      case IND_AD:
      case IND_OBV:
      case IND_BWMFI:
      case IND_GATOR:
      case IND_VOLUMES:
         paramCount = 0;
         break;

      case IND_WPR:
         ArrayResize(params, 1);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         paramCount = 1;
         break;

      //--- Overlay indicators (main chart)
      case IND_MA:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 10;          
         params[1].type = TYPE_INT;
         params[1].integer_value = 0;           
         params[2].type = TYPE_INT;
         params[2].integer_value = MODE_SMA;    
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         paramCount = 4;
         break;

      case IND_DEMA:
      case IND_TEMA:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         params[1].type = TYPE_INT;
         params[1].integer_value = 0;
         params[2].type = TYPE_INT;
         params[2].integer_value = MODE_SMA;
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         paramCount = 4;
         break;

      case IND_VIDYA:
         ArrayResize(params, 3);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         params[1].type = TYPE_DOUBLE;
         params[1].double_value = 0.2;      
         params[2].type = TYPE_INT;
         params[2].integer_value = PRICE_CLOSE;
         paramCount = 3;
         break;

      case IND_AMA:
         ArrayResize(params, 5);
         params[0].type = TYPE_INT;
         params[0].integer_value = 9;           
         params[1].type = TYPE_INT;
         params[1].integer_value = 30;          
         params[2].type = TYPE_INT;
         params[2].integer_value = 2;           
         params[3].type = TYPE_INT;
         params[3].integer_value = 30;          
         params[4].type = TYPE_INT;
         params[4].integer_value = PRICE_CLOSE;
         paramCount = 5;
         break;

      case IND_BANDS:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 20;
         params[1].type = TYPE_DOUBLE;
         params[1].double_value = 2.0;      
         params[2].type = TYPE_INT;
         params[2].integer_value = 0;
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         paramCount = 4;
         break;

      case IND_ENVELOPES:
         ArrayResize(params, 5);
         params[0].type = TYPE_INT;
         params[0].integer_value = 10;
         params[1].type = TYPE_INT;
         params[1].integer_value = 0;
         params[2].type = TYPE_INT;
         params[2].integer_value = MODE_SMA;
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         params[4].type = TYPE_DOUBLE;
         params[4].double_value = 0.1;      
         paramCount = 5;
         break;

      case IND_ICHIMOKU:
         ArrayResize(params, 5);
         params[0].type = TYPE_INT;
         params[0].integer_value = 9;           
         params[1].type = TYPE_INT;
         params[1].integer_value = 26;          
         params[2].type = TYPE_INT;
         params[2].integer_value = 52;          
         params[3].type = TYPE_INT;
         params[3].integer_value = 26;          
         params[4].type = TYPE_INT;
         params[4].integer_value = 26;          
         paramCount = 5;
         break;

      case IND_SAR:
         ArrayResize(params, 2);
         params[0].type = TYPE_DOUBLE;
         params[0].double_value = 0.02;      
         params[1].type = TYPE_DOUBLE;
         params[1].double_value = 0.2;       
         paramCount = 2;
         break;

      case IND_ALLIGATOR:
         ArrayResize(params, 6);
         params[0].type = TYPE_INT;
         params[0].integer_value = 13;          
         params[1].type = TYPE_INT;
         params[1].integer_value = 8;           
         params[2].type = TYPE_INT;
         params[2].integer_value = 5;           
         params[3].type = TYPE_INT;
         params[3].integer_value = 8;           
         params[4].type = TYPE_INT;
         params[4].integer_value = 5;           
         params[5].type = TYPE_INT;
         params[5].integer_value = 3;           
         paramCount = 6;
         break;

      case IND_FRACTALS:
         paramCount = 0;   
         break;

      //--- Other sub‑window indicators with parameters
      case IND_ADX:
      case IND_ADXW:
         ArrayResize(params, 1);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         paramCount = 1;
         break;

      case IND_ATR:
         ArrayResize(params, 1);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         paramCount = 1;
         break;

      case IND_TRIX:
      case IND_MOMENTUM:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         params[1].type = TYPE_INT;
         params[1].integer_value = PRICE_CLOSE;
         paramCount = 2;
         break;

      case IND_STDDEV:
         ArrayResize(params, 3);
         params[0].type = TYPE_INT;
         params[0].integer_value = 10;
         params[1].type = TYPE_INT;
         params[1].integer_value = 0;
         params[2].type = TYPE_INT;
         params[2].integer_value = PRICE_CLOSE;
         paramCount = 3;
         break;

      case IND_FORCE:
         ArrayResize(params, 3);
         params[0].type = TYPE_INT;
         params[0].integer_value = 13;
         params[1].type = TYPE_INT;
         params[1].integer_value = MODE_SMA;
         params[2].type = TYPE_INT;
         params[2].integer_value = VOLUME_TICK;
         paramCount = 3;
         break;

      case IND_RVI:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 10;
         params[1].type = TYPE_INT;
         params[1].integer_value = MODE_SMA;
         paramCount = 2;
         break;

      case IND_OSMA:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 12;
         params[1].type = TYPE_INT;
         params[1].integer_value = 26;
         params[2].type = TYPE_INT;
         params[2].integer_value = 9;
         params[3].type = TYPE_INT;
         params[3].integer_value = PRICE_CLOSE;
         paramCount = 4;
         break;

      case IND_CHAIKIN:
         ArrayResize(params, 4);
         params[0].type = TYPE_INT;
         params[0].integer_value = 3;
         params[1].type = TYPE_INT;
         params[1].integer_value = 10;
         params[2].type = TYPE_INT;
         params[2].integer_value = MODE_SMA;
         params[3].type = TYPE_DOUBLE;
         params[3].double_value = 0.0;
         paramCount = 4;
         break;

      case IND_DEMARKER:
         ArrayResize(params, 1);
         params[0].type = TYPE_INT;
         params[0].integer_value = 14;
         paramCount = 1;
         break;

      case IND_BEARS:
      case IND_BULLS:
         ArrayResize(params, 2);
         params[0].type = TYPE_INT;
         params[0].integer_value = 13;
         params[1].type = TYPE_INT;
         params[1].integer_value = VOLUME_TICK;
         paramCount = 2;
         break;

      default:
         Print("Unsupported indicator type: ", EnumToString(type));
         return(INVALID_HANDLE);
     }

//--- Create the indicator using the built‑in MT5 function
   int handle = IndicatorCreate(Symbol(), PERIOD_CURRENT, type, paramCount, params);
   if(handle == INVALID_HANDLE)
      Print("Failed to create ", EnumToString(type), ", error: ", GetLastError());
   return(handle);
  }

//+------------------------------------------------------------------+
//| Attaches an indicator to the correct window (main or sub)        |
//+------------------------------------------------------------------+
bool AttachIndicator(const ENUM_INDICATOR type)
  {
   int handle = CreateIndicator(type);
   if(handle == INVALID_HANDLE)
      return(false);

//--- Choose the right window: 0 for main chart, or a new sub‑window
   int window = GetTargetWindow(type);
   if(!ChartIndicatorAdd(0, window, handle))
     {
      Print("Failed to add indicator to window ", window, ", error: ", GetLastError());
      IndicatorRelease(handle);
      return(false);
     }

   ChartRedraw();   
   string windowDesc = (window == 0) ? "main chart" : "sub‑window " + IntegerToString(window);
   Print("Indicator ", EnumToString(type), " attached to ", windowDesc);
   return(true);
  }

#endif // _CHART_LAUNCHER_MQH
//+------------------------------------------------------------------+
