
#property copyright "Copyright © 2008, MQL Service"
#property link      "http://www.mqlservice.net"
#property show_inputs

#include <WinUser32.mqh>
#include <stdlib.mqh>

#import "user32.dll"
   int RegisterWindowMessageA(string a0);
#import

extern int BarsRange = 25;
extern int TimeFrame = 2;
extern int MaxBars = 10000;
extern bool ShowGaps = FALSE;
extern bool RescaleFor5DigitsBroker = TRUE;
int gi_96 = -1;
string gs_100;

double volume(int ai_0) {
   return (iVolume(Symbol(), PERIOD_M1, ai_0));
}

double open(int ai_0) {
   return (iOpen(Symbol(), PERIOD_M1, ai_0));
}

double close(int ai_0) {
   return (iClose(Symbol(), PERIOD_M1, ai_0));
}

double high(int ai_0) {
   return (iHigh(Symbol(), PERIOD_M1, ai_0));
}

double low(int ai_0) {
   return (iLow(Symbol(), PERIOD_M1, ai_0));
}

int time(int ai_0) {
   return (ai_0);
}

int start() {
   int li_8;
   int li_20;
   double ld_72;
   int lia_104[13];
   double ld_116;
   int li_124;
   if (_invalid(BarsRange, 0, "BarsRange")) return (0);
   if (_invalid(TimeFrame, 1, "TimeFrame")) return (0);
   if (!IsDllsAllowed()) {
      Alert(WindowExpertName(), ": Please Allow DLL imports to run this script");
      Comment(WindowExpertName(), " aborted due to disabled DLL calls");
      return (-1);
   }
   int li_0 = RegisterWindowMessageA("MetaTrader4_Internal_Message");
   gs_100 = Symbol();
   int li_80 = 0;
   int li_84 = 0;
   int li_88 = 400;
   int li_100 = Digits;
   for (int li_4 = StringFind(gs_100, ".", 0); li_4 > 0; li_4 = StringFind(gs_100, ".", 0)) gs_100 = StringSubstr(gs_100, 0, li_4) + StringSubstr(gs_100, li_4 + 1);
   gi_96 = FileOpenHistory(gs_100 + TimeFrame + ".hst", FILE_BIN|FILE_WRITE);
   if (gi_96 < 0) {
      Alert(WindowExpertName(), ": Cannot create ", gs_100 + TimeFrame + ".hst");
      Comment(WindowExpertName(), " aborted: Cannot create ", gs_100 + TimeFrame + ".hst");
      return (-1);
   }
   Print("$Id: //mqlservice/mt4files/experts/scripts/s-Constant Range Bars.mq4#14 $");
   string ls_92 = "(C)opyright 2008, MQL Service";
   FileWriteInteger(gi_96, li_88, LONG_VALUE);
   FileWriteString(gi_96, ls_92, 64);
   FileWriteString(gi_96, gs_100, 12);
   FileWriteInteger(gi_96, TimeFrame, LONG_VALUE);
   FileWriteInteger(gi_96, li_100, LONG_VALUE);
   FileWriteInteger(gi_96, 0, LONG_VALUE);
   FileWriteInteger(gi_96, 0, LONG_VALUE);
   FileWriteArray(gi_96, lia_104, 0, 13);
   FileFlush(gi_96);
   int li_24 = FileTell(gi_96);
   int li_28 = 60 * TimeFrame;
   int li_12 = MathMin(MaxBars, iBars(Symbol(), PERIOD_M1) - 1);
   if (li_12 <= 0)
      if (MessageBox("No 1M bars available, there will be no history bars!\n\nContinue?", WindowExpertName(), MB_YESNO|MB_ICONQUESTION) == IDNO) return (0);
   if (Period() != PERIOD_M1)
      if (MessageBox("It should be run on 1M chart!\n\nContinue?", WindowExpertName(), MB_YESNO|MB_ICONQUESTION) == IDNO) return (0);
   int li_108 = 1;
   if (Digits == 3 || Digits > 4) {
      if (RescaleFor5DigitsBroker) {
         BarsRange = 10 * BarsRange;
         li_108 = 10;
      }
   }
   int li_16 = time(iTime(Symbol(), PERIOD_M1, li_12));
   Print("Starting from ", TimeToStr(li_16, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
   double ld_40 = close(li_12);
   double ld_48 = ld_40;
   double ld_64 = 1.0;
   double ld_56 = ld_40;
   double ld_32 = ld_40;
   int li_112 = 1;
   for (li_4 = li_12 - 1; li_4 >= 0; li_4--) {
      li_20 = time(iTime(Symbol(), PERIOD_M1, li_4));
      if (Volume[li_4] > 0.0) li_112 = MathMax(li_108, MathCeil((high(li_4) - low(li_4)) / Point / Volume[li_4]));
      else li_112 = li_108;
      li_112 = MathRound(li_112 / li_108) * li_108;
      if (open(li_4) > close(li_4)) {
         li_8 = MathRound(high(li_4) / Point / li_108) * li_108;
         while (li_8 >= MathRound(low(li_4) / Point / li_108) * li_108) {
            ld_116 = NormalizeDouble(li_8 * Point, Digits);
            ld_40 = MathMin(ld_40, ld_116);
            ld_48 = MathMax(ld_48, ld_116);
            ld_64++;
            if (MathRound((ld_48 - ld_40) / Point) >= BarsRange + li_108) {
               li_24 = FileTell(gi_96);
               if (CompareDoubles(ld_40, ld_116)) {
                  if (ShowGaps) ld_40 = NormalizeDouble(ld_48 - BarsRange * Point, Digits);
                  else ld_40 = NormalizeDouble(ld_40 + li_108 * Point, Digits);
                  ld_56 = ld_40;
               }
               if (CompareDoubles(ld_48, ld_116)) {
                  if (ShowGaps) ld_48 = NormalizeDouble(ld_40 + BarsRange * Point, Digits);
                  else ld_48 = NormalizeDouble(ld_48 - li_108 * Point, Digits);
                  ld_56 = ld_48;
               }
               FileWriteInteger(gi_96, li_16, LONG_VALUE);
               FileWriteDouble(gi_96, ld_32, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_40, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_48, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_56, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_64, DOUBLE_VALUE);
               FileFlush(gi_96);
               li_84++;
               li_16++;
               li_16 = MathMax(li_20, li_16);
               ld_32 = ld_116;
               ld_40 = ld_116;
               ld_48 = ld_116;
               ld_56 = ld_116;
               ld_64 = 1.0;
            } else ld_56 = ld_116;
            li_8 -= li_112;
         }
      } else {
         li_8 = MathRound(low(li_4) / Point / li_108) * li_108;
         while (li_8 <= MathRound(high(li_4) / Point / li_108) * li_108) {
            ld_116 = NormalizeDouble(li_8 * Point, Digits);
            ld_40 = MathMin(ld_40, ld_116);
            ld_48 = MathMax(ld_48, ld_116);
            ld_64++;
            if (MathRound((ld_48 - ld_40) / Point) >= BarsRange + li_108) {
               li_24 = FileTell(gi_96);
               if (CompareDoubles(ld_40, ld_116)) {
                  if (ShowGaps) ld_40 = NormalizeDouble(ld_48 - BarsRange * Point, Digits);
                  else ld_40 = NormalizeDouble(ld_40 + li_108 * Point, Digits);
                  ld_56 = ld_40;
               }
               if (CompareDoubles(ld_48, ld_116)) {
                  if (ShowGaps) ld_48 = NormalizeDouble(ld_40 + BarsRange * Point, Digits);
                  else ld_48 = NormalizeDouble(ld_48 - li_108 * Point, Digits);
                  ld_56 = ld_48;
               }
               FileWriteInteger(gi_96, li_16, LONG_VALUE);
               FileWriteDouble(gi_96, ld_32, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_40, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_48, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_56, DOUBLE_VALUE);
               FileWriteDouble(gi_96, ld_64, DOUBLE_VALUE);
               FileFlush(gi_96);
               li_84++;
               li_16++;
               li_16 = MathMax(li_20, li_16);
               ld_32 = ld_116;
               ld_40 = ld_116;
               ld_48 = ld_116;
               ld_56 = ld_116;
               ld_64 = 1.0;
            } else ld_56 = ld_116;
            li_8 += li_112;
         }
      }
   }
   li_24 = FileTell(gi_96);
   FileWriteInteger(gi_96, li_16, LONG_VALUE);
   FileWriteDouble(gi_96, ld_32, DOUBLE_VALUE);
   FileWriteDouble(gi_96, ld_40, DOUBLE_VALUE);
   FileWriteDouble(gi_96, ld_48, DOUBLE_VALUE);
   FileWriteDouble(gi_96, ld_56, DOUBLE_VALUE);
   FileWriteDouble(gi_96, ld_64, DOUBLE_VALUE);
   FileFlush(gi_96);
   Print(li_84, " record(s) written");
   if (li_80 == 0) {
      li_80 = WindowHandle(gs_100, TimeFrame);
      if (li_80 != 0) Print("Chart window detected");
   }
   _postMessage(li_80, li_0);
   li_16 = TimeCurrent();
   Comment(WindowExpertName(), " started");
   while (IsStopped() == FALSE) {
      li_124 = TimeLocal();
      if (RefreshRates()) {
         FileSeek(gi_96, li_24, SEEK_SET);
         ld_40 = MathMin(ld_40, Close[0]);
         ld_48 = MathMax(ld_48, Close[0]);
         ld_64++;
         if (MathRound((ld_48 - ld_40) / Point / li_108) <= MathRound(BarsRange / li_108)) {
            ld_72 = volume(0);
            ld_56 = close(0);
         } else {
            if (CompareDoubles(ld_40, Close[0])) {
               if (ShowGaps) ld_40 = NormalizeDouble(ld_48 - BarsRange * Point, Digits);
               else ld_40 = NormalizeDouble(ld_40 + li_108 * Point, Digits);
               ld_56 = ld_40;
            }
            if (CompareDoubles(ld_48, Close[0])) {
               if (ShowGaps) ld_48 = NormalizeDouble(ld_40 + BarsRange * Point, Digits);
               else ld_48 = NormalizeDouble(ld_48 - li_108 * Point, Digits);
               ld_56 = ld_48;
            }
            FileWriteInteger(gi_96, li_16, LONG_VALUE);
            FileWriteDouble(gi_96, NormalizeDouble(MathMin(MathMax(ld_32, ld_40), ld_48), Digits), DOUBLE_VALUE);
            FileWriteDouble(gi_96, NormalizeDouble(MathMin(ld_40, ld_48), Digits), DOUBLE_VALUE);
            FileWriteDouble(gi_96, NormalizeDouble(MathMax(ld_48, ld_40), Digits), DOUBLE_VALUE);
            FileWriteDouble(gi_96, NormalizeDouble(MathMin(MathMax(ld_56, ld_40), ld_48), Digits), DOUBLE_VALUE);
            FileWriteDouble(gi_96, NormalizeDouble(ld_64, 0), DOUBLE_VALUE);
            li_24 = FileTell(gi_96);
            li_16++;
            li_16 = MathMax(li_16, TimeCurrent());
            ld_64 = 1;
            ld_32 = Close[0];
            ld_40 = Close[0];
            ld_48 = Close[0];
            ld_56 = Close[0];
            ld_64 = 1.0;
            ld_72 = ld_64;
         }
         FileWriteInteger(gi_96, li_16, LONG_VALUE);
         FileWriteDouble(gi_96, NormalizeDouble(MathMin(MathMax(ld_32, ld_40), ld_48), Digits), DOUBLE_VALUE);
         FileWriteDouble(gi_96, NormalizeDouble(MathMin(ld_40, ld_48), Digits), DOUBLE_VALUE);
         FileWriteDouble(gi_96, NormalizeDouble(MathMax(ld_48, ld_40), Digits), DOUBLE_VALUE);
         FileWriteDouble(gi_96, NormalizeDouble(MathMin(MathMax(ld_56, ld_40), ld_48), Digits), DOUBLE_VALUE);
         FileWriteDouble(gi_96, NormalizeDouble(ld_64, 0), DOUBLE_VALUE);
         FileFlush(gi_96);
         if (li_80 == 0) {
            li_80 = WindowHandle(gs_100, TimeFrame);
            if (li_80 != 0) Print("Chart window detected");
         }
         li_80 = WindowHandle(gs_100, TimeFrame);
         _postMessage(li_80, li_0);
      } else Sleep(100);
   }
   Comment(WindowExpertName(), " stopped");
   return (0);
}

void _postMessage(int ai_0, int ai_4) {
   if (ai_0 != 0) {
      PostMessageA(ai_0, WM_COMMAND, 33324, 1);
      PostMessageA(ai_0, ai_4, 2, 1);
   }
}

void deinit() {
   if (gi_96 >= 0) {
      FileClose(gi_96);
      Print(gs_100, TimeFrame, ".hst closed");
      gi_96 = -1;
   }
   Print("Inputs were: ", "BarsRange=", BarsRange, "; ", "TimeFrame=", TimeFrame, "; ", "MaxBars=", MaxBars, "; ", "ShowGaps=", ShowGaps, ";");
}

bool _invalid(int ai_0, int ai_4, string as_8) {
   if (ai_0 <= ai_4) {
      Alert(WindowExpertName() + " " + Symbol() + Period() + " invalid parameter ", as_8, ": ", ai_0, ". Must be grater than ", ai_4);
      return (TRUE);
   }
   return (FALSE);
}