renkolivechart_v600_indi

Author: Copyright 2016, MetaQuotes Software Corp.
renkolivechart_v600_indi
Miscellaneous
It writes information to fileIt writes information to fileIt writes information to file
0 Views
0 Downloads
0 Favorites
renkolivechart_v600_indi
//+------------------------------------------------------------------+
//|                                      RenkoLiveChart_v600.4.2.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

//+---------------------------------------------------------------------------+
//|   EA VERSION
//|   RenkoLiveChart_v3.2.mq4
//|   Inspired from Renko script by "e4" (renko_live_scr.mq4)
//|   Copyleft 2009 LastViking
//|   
//|   Aug 12 2009 (LV): 
//|            - Wanted volume in my Renko chart so I wrote my own script
//|     
//|   Aug 20-21 2009 (LV) (v1.1 - v1.3):
//|            - First attempt at live Renko brick formation (bugs O bugs...)
//|            - Fixed problem with strange symbol names at some 5 digit 
//|               brokers (credit to Tigertron)
//|     
//|   Aug 24 2009 (LV) (v1.4):
//|            - Handle High / Low in history in a reasonable way (prev. 
//|               used Close)
//|   
//|   Aug 26 2009 (Lou G) (v1.5/v1.6):
//|            - Finaly fixing the "late appearance" (live Renko brick 
//|               formation) bug
//| 
//|   Aug 31 2009 (LV) (v2.0):
//|            - Not a script anylonger, but run as indicator 
//|            - Naroved down the MT4 bug that used to cause the "late appearance bug" 
//|               a little closer (has to do with High / Low gaps)
//|            - Removed the while ... sleep() loop. Renko chart is now tick 
//|               driven: -MUCH nicer to system resources this way
//| 
//|   Sep 03 2009 (LV) (v2.1):
//|            - Fixed so that Time[] holds the open time of the renko 
//|               bricks (prev. used time of close)
//|     
//|   Sep 16 2009 (Lou G) (v3.0): 
//|            - Optional wicks added
//|            - Conversion back to EA 
//|            - Auto adjust for 5 and 6 dec brokers added
//|               enter RenkoBoxSize as "actual" size e.g. "10" for 10 pips
//|            - Compensation for "zero compare" problem added
//|
//|   Okt 05 2009 (LV) (v3.1): 
//|            - Fixed a bug related to BoxOffset
//|            - Auto adjust for 3 and 4 dec JPY pairs
//|            - Removed init() function
//|            - Changed back to old style Renko brick formation
//| 
//|   Okt 13 2009 (LV) (v3.2): 
//|            - Added "EmulateOnLineChart" option (credit to Skipperxit/Mimmo)
//| 
//|   Feb 07 2014 (KZ) (v600.1): 
//|            - Build 600 forced upgrade for new history file format
//|            - Build 600 has some "funny" quirks
//|            - "So that is why everyone is laughing"?
//|            -   1) The share/lock access rights
//|            -   2) It appears to me static variables do not act right
//|            -      Seems like they might not be reset when the code is re-loaded
//|            -      Not sure, so just moved them all to common
//|            - Many thanks to LastViking, Lou G, Kiads, Mihailo, and many others
//|            - that have contributed to making Renko a success
//|            - My apologies to each of you if I have abused your code
//|            - Many thanks to Mary-Jane for helping me get up to date on passing strings to DLLs
//|            - "surprise, surprise, surprise"
//|            - Many thanks to MetaQuirks for forcing me to bring my programming skills up to date
//|
//|   Apr 03 2015 (SK) (v600.3)
//|            - Fixed missing wicks on the same side of bar as current direction
//|            - Fixed missing wicks on extremums
//|            - Made a start timer to build the chart once even if no ticks coming (i.e. during weekend)
//|   Nov 25 2015 (SK - https://www.mql5.com/en/users/marketeer) (v600.4)
//|            - Classical 'look and feel' of renko wicks applied as a patch
//|
//|   Jan 19 2106 (File45 - https://www.mql5.com/en/users/file45/publications) (v600.5 & v600.6)
//|            - Transcribed to Post MT4 Build 600 New Code
//|            - Change Renko BoxSize from int to double
//|            - Corrected ShowWicks=false failure to remove wicks 
//|   Mar 24 2106 (File45 - https://www.mql5.com/en/users/file45/publications) (v600.6)   
//|            - Convert EA to Indicator
//|
//| From the MQL4 Reference
//| MqlRates
//|
//| This structure stores information about the prices, volumes and spread.
//|
//| struct MqlRates
//| {
//|   datetime time;         // Period start time
//|   double   open;         // Open price
//|   double   high;         // The highest price of the period
//|   double   low;          // The lowest price of the period
//|   double   close;        // Close price
//|   long     tick_volume;  // Tick volume
//|   int      spread;       // Spread
//|   long     real_volume;  // Trade volume
//| };
//+---------------------------------------------------------------------------+

#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "6.00"
#property strict
#property indicator_chart_window

#include <WinUser32.mqh>
#include <stdlib.mqh>

//+------------------------------------------------------------------+
#import "user32.dll"
int RegisterWindowMessageW(string lpString);
#import
//+------------------------------------------------------------------+

input double RenkoBoxSize = 3.0;
input int RenkoBoxOffset = 0;
input int RenkoTimeFrame = 7; // Offline Timeframe
input bool ShowWicks = false;
input bool EmulateOnLineChart = true;
input bool StrangeSymbolName = false;

//+------------------------------------------------------------------+
int HstHandle = -1, LastFPos = 0, MT4InternalMsg = 0;
string sSymbolName;
datetime dtSendTime;
double dSendOpen;
double dSendHigh;
double dSendLow;
double dSendClose;
double dSendVol;
bool bStopAll = false;
int iRcdCnt = 0;
int hwnd = 0;
double BoxPoints, UpWick, DnWick;
double PrevLow, PrevHigh, PrevOpen, PrevClose, CurVolume, CurLow, CurHigh, CurOpen, CurClose;
datetime PrevTime;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
    if(HstHandle > 0)
    {
      FileClose(HstHandle);
    }
    HstHandle = -1;
    EventSetTimer(1);
  
   return(INIT_SUCCEEDED);
  }
  
void OnDeinit(const int reason)
  {
   if(HstHandle >= 0)
  {
    FileClose(HstHandle);
    HstHandle = -1;
  }
  Comment("");
  return;
   
  }  
  
//+------------------------------------------------------------------+
//| 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[])
  {
 
   if(bStopAll) return(0);

  //+------------------------------------------------------------------+
  // This is only executed once, then the first tick arives.
  if(HstHandle < 0)
  {
    // Init
    // Error checking	
    if(!IsConnected())
    {
      Print("Waiting for connection...");
      return(0);
    }
    if(!IsDllsAllowed())
    {
      Print("Error: Dll calls must be allowed!");
      bStopAll = true;
      return(0);
    }
    if(MathAbs(RenkoBoxOffset) >= RenkoBoxSize)
    {
      Print("Error: |RenkoBoxOffset| should be less then RenkoBoxSize!");
      bStopAll = true;
      return(0);
    }
    switch(RenkoTimeFrame)
    {
      case 1:
      case 5:
      case 15:
      case 30:
      case 60:
      case 240:
      case 1440:
      case 10080:
      case 43200:
      case 0:
        Print("Error: Invald time frame used for offline renko chart (RenkoTimeFrame)!");
        bStopAll = true;
        return(0);
    }

    double BoxSize = RenkoBoxSize;
    int BoxOffset = RenkoBoxOffset;
    if(Digits == 5 || (Digits == 3 && StringFind(Symbol(), "JPY") != -1))
    {
      BoxSize = BoxSize * 10;
      BoxOffset = BoxOffset * 10;
    }
    if(Digits == 6 || (Digits == 4 && StringFind(Symbol(), "JPY") != -1))
    {
      BoxSize = BoxSize * 100;
      BoxOffset = BoxOffset * 100;
    }

    if(StrangeSymbolName) sSymbolName = StringSubstr(Symbol(), 0, 6);
    else sSymbolName = Symbol();
    BoxPoints = NormalizeDouble(BoxSize * Point, Digits);
    PrevLow = NormalizeDouble(BoxOffset * Point + MathFloor(Close[Bars - 1] / BoxPoints) * BoxPoints, Digits);
    DnWick = PrevLow;
    PrevHigh = PrevLow + BoxPoints;
    UpWick = PrevHigh;
    PrevOpen = PrevLow;
    PrevClose = PrevHigh;
    CurVolume = 1;
    PrevTime = Time[Bars - 1];

    // create / open hst file		
    HstHandle = FileOpenHistory(sSymbolName + IntegerToString(RenkoTimeFrame) + ".hst", FILE_BIN | FILE_WRITE | FILE_ANSI);//W1
    if(HstHandle < 0)
    {
      Print("Error: can\'t create / open history file: " + ErrorDescription(GetLastError()) + ": " + sSymbolName + IntegerToString(RenkoTimeFrame) + ".hst");
      bStopAll = true;
      return(0);
    }
    else
    {
      Print("History file opened for write, handle: " + IntegerToString(HstHandle));
      FileSeek(HstHandle, 0, SEEK_SET);
      // Hist file opened as write zero length to create
    }
    // the file is created empty, now re-open it read write shared
    DoOpenHistoryReadWrite();
    FileSeek(HstHandle, 0, SEEK_SET);
    //Hist file opened as read write for adding to


    // write hst file header  -  does anyone have a structure for this heading?
    int HstUnused[13];
    FileWriteInteger(HstHandle, 401, LONG_VALUE); // Version  // was 400
    FileWriteString(HstHandle, "", 64); // Copyright
    FileWriteString(HstHandle, sSymbolName, 12); // Symbol
    FileWriteInteger(HstHandle, RenkoTimeFrame, LONG_VALUE); // Period
    FileWriteInteger(HstHandle, Digits, LONG_VALUE); // Digits
    FileWriteInteger(HstHandle, 0, LONG_VALUE); // Time Sign
    FileWriteInteger(HstHandle, 0, LONG_VALUE); // Last Sync
    FileWriteArray(HstHandle, HstUnused, 0, 13); // Unused

    // process historical data
    int i = Bars - 2;
    //Print(Symbol() + " " + High[i] + " " + Low[i] + " " + Open[i] + " " + Close[i]);
    //---------------------------------------------------------------------------
    while(i >= 0)
    {
      CurVolume = CurVolume + Volume[i];

      UpWick = MathMax(UpWick, High[i]);
      DnWick = MathMin(DnWick, Low[i]);

      // update low before high or the revers depending on is closest to prev. bar
      bool UpTrend = High[i] + Low[i] > High[i + 1] + Low[i + 1];
      bool WipeUpWick = false, WipeDownWick = false;

      // go down in up phase
      while(UpTrend && (Low[i] < PrevLow - BoxPoints || CompareDoubles(Low[i], PrevLow - BoxPoints)))
      {
        PrevHigh = PrevHigh - BoxPoints;
        PrevLow = PrevLow - BoxPoints;
        PrevOpen = PrevHigh;
        PrevClose = PrevLow;

        dtSendTime = PrevTime;
        dSendOpen = PrevOpen;
        if(ShowWicks==true && DnWick < PrevLow && Low[i] >= PrevLow - BoxPoints)
        {
          dSendLow = DnWick;
          WipeDownWick = true;
        }
        else
        {
          //dSendLow = PrevLow;// When ShowWicks = false this code will show wicks (file45)
          dSendLow = PrevHigh;
         
        }
        
        if(ShowWicks==true && UpWick > PrevHigh && UpWick <= PrevHigh + 2 * BoxPoints)
        {
          dSendHigh = UpWick;
          WipeUpWick = true;
        }
        else
        {
          dSendHigh = PrevHigh;
          
        }
        
        dSendClose = PrevClose;
        dSendVol = CurVolume;
        DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);

        if(WipeUpWick) UpWick = 0;
        if(WipeDownWick) DnWick = EMPTY_VALUE;
        CurVolume = 0;
        CurHigh = PrevLow;
        CurLow = PrevLow;

        if(PrevTime < Time[i]) PrevTime = Time[i];
        else PrevTime++;
      }

      // go up
      while(High[i] > PrevHigh + BoxPoints || CompareDoubles(High[i], PrevHigh + BoxPoints))
      {
        PrevHigh = PrevHigh + BoxPoints;
        PrevLow = PrevLow + BoxPoints;
        PrevOpen = PrevLow;
        PrevClose = PrevHigh;

        dtSendTime = PrevTime;
        dSendOpen = PrevOpen;
        
        if(ShowWicks==true && DnWick < PrevLow && DnWick >= PrevLow - 2 * BoxPoints )
        {
          dSendLow = DnWick;
          WipeDownWick = true;
        }
        else
        {
          dSendLow = PrevLow;
        }
        
         
        if(ShowWicks==true && UpWick > PrevHigh && High[i] <= PrevHigh + BoxPoints)
        {
          dSendHigh = UpWick;
          WipeUpWick = true;
        }
        else
        {
          //dSendHigh = PrevHigh; // When ShowWicks = false this code will show wicks (file45)
          dSendHigh = PrevLow;
        }
       
        dSendClose = PrevClose;
        dSendVol = CurVolume;
        DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);

        if(WipeUpWick) UpWick = 0;
        if(WipeDownWick) DnWick = EMPTY_VALUE;
        CurVolume = 0;
        CurHigh = PrevHigh;
        CurLow = PrevHigh;

        if(PrevTime < Time[i]) PrevTime = Time[i];
        else PrevTime++;
      
         RefreshRates();
      }

      // go down in down phase
      while(!UpTrend && (Low[i] < PrevLow - BoxPoints || CompareDoubles(Low[i], PrevLow - BoxPoints)))
      {
        PrevHigh = PrevHigh - BoxPoints;
        PrevLow = PrevLow - BoxPoints;
        PrevOpen = PrevHigh;
        PrevClose = PrevLow;

        dtSendTime = PrevTime;
        dSendOpen = PrevOpen;
        
        if(ShowWicks==true && DnWick < PrevLow && Low[i] >= PrevLow - BoxPoints)
        {
          dSendLow = DnWick;
          WipeDownWick = true;
        }
        else
        {
          //dSendLow = PrevLow; // When ShowWicks = false this code will show wicks (file45)
          dSendLow = PrevHigh;
        }
        
        
        if(ShowWicks==true && UpWick > PrevHigh)
        {
          dSendHigh = UpWick;
          WipeUpWick = true;
        }
        else
        {
          dSendHigh = PrevHigh;
        }
       
        dSendClose = PrevClose;
        dSendVol = CurVolume;
        DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);

        if(WipeUpWick) UpWick = 0;
        if(WipeDownWick) DnWick = EMPTY_VALUE;
        CurVolume = 0;
        CurHigh = PrevLow;
        CurLow = PrevLow;

        if(PrevTime < Time[i]) PrevTime = Time[i];
        else PrevTime++;
      
        RefreshRates();
      }
      i--;
    }
    LastFPos = (int)FileTell(HstHandle); // Remember Last pos in file

    if(Close[0] > MathMax(PrevClose, PrevOpen)) CurOpen = MathMax(PrevClose, PrevOpen);
    else if(Close[0] < MathMin(PrevClose, PrevOpen)) CurOpen = MathMin(PrevClose, PrevOpen);
    else CurOpen = Close[0];

    CurClose = Close[0];

    if(ShowWicks==true)
    {
      if(UpWick > PrevHigh) CurHigh = UpWick;
      if(DnWick < PrevLow) CurLow = DnWick;
    }

    dtSendTime = PrevTime;
    dSendOpen = CurOpen;
    dSendLow = CurLow;
    dSendHigh = CurHigh;
    dSendClose = CurClose;
    dSendVol = CurVolume;
    DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);
    FileFlush(HstHandle);

    if(bStopAll) return(0);
    Comment("RenkoLiveChart (" + DoubleToString(RenkoBoxSize) + "): Open Offline ", sSymbolName, ",M", RenkoTimeFrame, " To View Chart");//3
    UpdateChartWindow();
    return(0);
    // End historical data / Init		
  }
  //----------------------------------------------------------------------------
  // HstHandle not < 0 so we always enter here after history done
  // Begin live data feed
  if(bStopAll) return(0);
  UpWick = MathMax(UpWick, Bid);
  DnWick = MathMin(DnWick, Bid);

  CurVolume++;
  FileSeek(HstHandle, LastFPos, SEEK_SET);

  //-------------------------------------------------------------------------	   				
  // up box	   				
  if(Bid > PrevHigh + BoxPoints || CompareDoubles(Bid, PrevHigh + BoxPoints))
  {
    PrevHigh = PrevHigh + BoxPoints;
    PrevLow = PrevLow + BoxPoints;
    PrevOpen = PrevLow;
    PrevClose = PrevHigh;

    dtSendTime = PrevTime;
    dSendOpen = PrevOpen;
    if(ShowWicks==true && DnWick < PrevLow)
    {
      dSendLow = DnWick;
    }
    else
    {
      dSendLow = PrevLow;
    }
    if(ShowWicks==true && UpWick > PrevHigh)
    {
      dSendHigh = UpWick;
    }
    else
    {
      dSendHigh = PrevHigh;
    }
    dSendClose = PrevClose;
    dSendVol = CurVolume;
    DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);
    FileFlush(HstHandle);
    LastFPos = (int) FileTell(HstHandle); // Remeber Last pos in file				  							

    if(PrevTime < TimeCurrent()) PrevTime = TimeCurrent();
    else PrevTime++;

    CurVolume = 0;
    CurHigh = PrevHigh;
    CurLow = PrevHigh;

    UpWick = 0;
    DnWick = EMPTY_VALUE;

    UpdateChartWindow();
  }
  //-------------------------------------------------------------------------	   				
  // down box
  else if(Bid < PrevLow - BoxPoints || CompareDoubles(Bid, PrevLow - BoxPoints))
  {
    PrevHigh = PrevHigh - BoxPoints;
    PrevLow = PrevLow - BoxPoints;
    PrevOpen = PrevHigh;
    PrevClose = PrevLow;

    dtSendTime = PrevTime;
    dSendOpen = PrevOpen;
   
    if(ShowWicks==true && DnWick < PrevLow)
    {
      dSendLow = DnWick;
    }
    else
    {
      dSendLow = PrevLow;
      
    }
    
    if(ShowWicks==true && UpWick > PrevHigh)
    {
      dSendHigh = UpWick;
    }
    else
    {
      dSendHigh = PrevHigh;
    }
    dSendClose = PrevClose;
    dSendVol = CurVolume;
    DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol);
    FileFlush(HstHandle);
    LastFPos = (int)FileTell(HstHandle); // Remeber Last pos in file				  							

    if(PrevTime < TimeCurrent()) PrevTime = TimeCurrent();
    else PrevTime++;

    CurVolume = 0;
    CurHigh = PrevLow;
    CurLow = PrevLow;

    UpWick = 0;
    DnWick = EMPTY_VALUE;

    UpdateChartWindow();
  }
  //-------------------------------------------------------------------------	   				
  // no box - high/low not hit				
  else
  {
    if(Bid > CurHigh) CurHigh = Bid;
    if(Bid < CurLow) CurLow = Bid;

    if(PrevHigh <= Bid) CurOpen = PrevHigh;
    else if(PrevLow >= Bid) CurOpen = PrevLow;
    else CurOpen = Bid;

    CurClose = Bid;

    dtSendTime = PrevTime;
    dSendOpen = CurOpen;
    dSendLow = CurLow;
    dSendHigh = CurHigh;
    dSendClose = CurClose;
    dSendVol = CurVolume;
    DoWriteStruct(dtSendTime, dSendOpen, dSendHigh, dSendLow, dSendClose, dSendVol, false);
    FileFlush(HstHandle);

    UpdateChartWindow();
  }
   return(rates_total);
  }
 
 void UpdateChartWindow()
{
  if(hwnd == 0)
  {
    hwnd = WindowHandle(sSymbolName, RenkoTimeFrame);
    if(hwnd != 0) Print("Chart window detected");
  }
  if(EmulateOnLineChart && MT4InternalMsg == 0) MT4InternalMsg = RegisterWindowMessageW("MetaTrader4_Internal_Message");
  if(hwnd != 0) if(PostMessageW(hwnd, WM_COMMAND, 0x822c, 0) == 0) hwnd = 0;
  if(hwnd != 0 && MT4InternalMsg != 0) PostMessageW(hwnd, MT4InternalMsg, 2, 1);
  return;
}

void DoWriteStruct(datetime dtTime, double dOpen, double dHigh, double dLow, double dClose, double dVol, bool history = true)
{
  iRcdCnt++;
  static int iErr = 0;
  static int iBWritn = 0;
  MqlRates rate;
  rate.time = dtTime;
  rate.open = dOpen;
  static double prevHigh = 0, prevLow = DBL_MAX;
  if(history)
  {
    rate.high = (dOpen < dClose)?dClose:MathMax(dHigh, prevHigh);
    rate.low = (dOpen > dClose)?dClose:MathMin(dLow, prevLow);
    prevHigh = (dOpen < dClose)?dHigh:0;
    prevLow = (dOpen > dClose)?dLow:DBL_MAX;
  }
  else
  {
    rate.high = dHigh;
    rate.low = dLow;
  }
  rate.close = dClose;
  rate.tick_volume = (long) dVol;
  rate.spread = 0;
  rate.real_volume = (long) dVol;
  iBWritn = (int)FileWriteStruct(HstHandle, rate);
  if(iBWritn == 0)
  {
    iErr = GetLastError();
    Print("Error on write struct at cntr: " + IntegerToString(iRcdCnt) + ", errdesc: " + ErrorDescription(iErr));//W4
    bStopAll = true;
  }
  return;
}

void DoOpenHistoryReadWrite()
{
  if(HstHandle >= 0)
  {
    int iSz = (int)FileSize(HstHandle);
    Print("fl sz " + IntegerToString(iSz));
    FileClose(HstHandle);
    HstHandle = -1;
  }
  HstHandle = FileOpenHistory(
  sSymbolName + IntegerToString(RenkoTimeFrame) + ".hst", FILE_BIN | FILE_READ | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_ANSI);
  // this combination is critical to unlock the file and still allow read write and opening a chart on it
  if(HstHandle < 0)
  {
    Print("Error: cant open history file read write: " + ErrorDescription(GetLastError()) + ": " + sSymbolName + IntegerToString(RenkoTimeFrame) + ".hst");
    bStopAll = true;
  }
  else
  {
    Print("Hist file opened for read write, handle: " + IntegerToString(HstHandle));
  }
  return;
}

Comments