//+------------------------------------------------------------------+
//|                                     09_OnChart_Oscillator.mq5 |
//|                                  Copyright 2026, FXおもしろラボ |
//|                                      https://fx-omoshiro-lab.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FXおもしろラボ"
#property link      "https://fx-omoshiro-lab.com"
#property version   "1.00"
#property description "Displays an oscillator (RSI/Stochastic) on the main chart within MA +/- ATR bands."

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   4

//--- Plot Center Line (MA)
#property indicator_label1  "CenterLine"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrOrange
#property indicator_style1  STYLE_DASHDOT

//--- Plot Upper Band
#property indicator_label2  "UpperBand"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDarkOrange
#property indicator_style2  STYLE_SOLID

//--- Plot Lower Band
#property indicator_label3  "LowerBand"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrDarkOrange
#property indicator_style3  STYLE_SOLID

//--- Plot Oscillator
#property indicator_label4  "Oscillator"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrYellow
#property indicator_style4  STYLE_SOLID
#property indicator_width4  2

//--- Enums
enum ENUM_OSC_TYPE
  {
   OSC_RSI=0,        // RSI
   OSC_STOCH=1       // Stochastic
  };

//--- Input parameters
input string               inpSettingsGeneral      = "--- General Settings ---"; // 
input ENUM_OSC_TYPE        inpOscType              = OSC_RSI;          // Oscillator Type
input string               inpSettingsMA           = "--- MA Settings ---";      // 
input int                  inpMAPeriod             = 20;               // MA Period
input ENUM_MA_METHOD       inpMAMethod             = MODE_SMA;         // MA Method
input ENUM_APPLIED_PRICE   inpMAPrice              = PRICE_CLOSE;      // MA Applied Price
input string               inpSettingsATR          = "--- ATR Band Settings ---"; // 
input ENUM_TIMEFRAMES      inpATRTimeframe         = PERIOD_D1;        // ATR Timeframe (e.g., Daily)
input int                  inpATRPeriod            = 14;               // ATR Period
input double               inpBandMultiplier       = 1.0;              // Band Multiplier (ATR * X)
input string               inpSettingsOsc          = "--- Oscillator Settings ---"; // 
// RSI Settings
input int                  inpRSIPeriod            = 14;               // RSI Period
input ENUM_APPLIED_PRICE   inpRSIPrice             = PRICE_CLOSE;      // RSI Applied Price
// Stochastic Settings
input int                  inpStochKPeriod         = 5;                // Stochastic %K Period
input int                  inpStochDPeriod         = 3;                // Stochastic %D Period
input int                  inpStochSlowing         = 3;                // Stochastic Slowing
input ENUM_MA_METHOD       inpStochMethod          = MODE_SMA;         // Stochastic MA Method
input ENUM_STO_PRICE       inpStochPrice           = STO_LOWHIGH;      // Stochastic Price Field

//--- Indicator buffers
double         BufferCenter[];
double         BufferUpper[];
double         BufferLower[];
double         BufferOsc[];

//--- Handles
int            handle_ma;
int            handle_atr;
int            handle_osc;

//--- Helper arrays
double         atr_val[];
double         osc_val[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferCenter,INDICATOR_DATA);
   SetIndexBuffer(1,BufferUpper,INDICATOR_DATA);
   SetIndexBuffer(2,BufferLower,INDICATOR_DATA);
   SetIndexBuffer(3,BufferOsc,INDICATOR_DATA);

//--- Set empty values
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,EMPTY_VALUE);

//--- Create handles
   handle_ma = iMA(_Symbol,_Period,inpMAPeriod,0,inpMAMethod,inpMAPrice);
   if(handle_ma == INVALID_HANDLE)
     {
      PrintFormat("Failed to create MA handle. Error: %d",GetLastError());
      return(INIT_FAILED);
     }

   handle_atr = iATR(_Symbol,inpATRTimeframe,inpATRPeriod);
   if(handle_atr == INVALID_HANDLE)
     {
      PrintFormat("Failed to create ATR handle. Error: %d",GetLastError());
      return(INIT_FAILED);
     }

   if(inpOscType == OSC_RSI)
     {
      handle_osc = iRSI(_Symbol,_Period,inpRSIPeriod,inpRSIPrice);
     }
   else if(inpOscType == OSC_STOCH)
     {
      handle_osc = iStochastic(_Symbol,_Period,inpStochKPeriod,inpStochDPeriod,inpStochSlowing,inpStochMethod,inpStochPrice);
     }
     
   if(handle_osc == INVALID_HANDLE)
     {
      PrintFormat("Failed to create Oscillator handle. Error: %d",GetLastError());
      return(INIT_FAILED);
     }
     
   IndicatorSetString(INDICATOR_SHORTNAME,"OnChartOsc(" + EnumToString(inpOscType) + ")");

   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| Get ATR from higher timeframe                                    |
//+------------------------------------------------------------------+
double GetATRForTime(datetime time, int handle)
  {
   double res[1];
   if(CopyBuffer(handle, 0, time, 1, res) > 0)
     {
      return res[0];
     }
   return 0;
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int start = 0;
   if(prev_calculated > 0)
      start = prev_calculated - 1;

//--- Ensure we have enough data
   if(rates_total < inpMAPeriod || rates_total < 2)
      return(0);

   int count = rates_total - start;

//--- Copy data to temp dynamic arrays
   double ma_val[];
   if(CopyBuffer(handle_ma, 0, 0, count, ma_val) <= 0) return(0);
   
   if(CopyBuffer(handle_osc, 0, 0, count, osc_val) <= 0) return(0);

   for(int i = start; i < rates_total; i++)
     {
      int pos = i - start;
      // 1. Get Center
      double center = ma_val[pos];
      BufferCenter[i] = center;
      
      // 2. Get ATR
      double atr = GetATRForTime(time[i], handle_atr);
      
      if(atr > 0 && center != EMPTY_VALUE && center != 0)
        {
         // 3. Calc Bands
         double band_half_width = atr * inpBandMultiplier;
         BufferUpper[i] = center + band_half_width;
         BufferLower[i] = center - band_half_width;
         
         // 4. Map Oscillator
         double oscRaw = osc_val[pos];
         double scaledVal = EMPTY_VALUE;
         
         if (oscRaw != EMPTY_VALUE) 
           {
            // Simple mapping from 0-100 range to Lower-Upper band
            double normalized_osc = MathMax(0.0, MathMin(100.0, oscRaw)) / 100.0;
            scaledVal = BufferLower[i] + (normalized_osc * (BufferUpper[i] - BufferLower[i]));
           }
         BufferOsc[i] = scaledVal;
        }
      else
        {
         BufferUpper[i] = EMPTY_VALUE;
         BufferLower[i] = EMPTY_VALUE;
         BufferOsc[i]   = EMPTY_VALUE;
        }
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
