Skip to content

Instantly share code, notes, and snippets.

@oderayi
Last active November 4, 2021 18:08
Show Gist options
  • Save oderayi/4556a63f1c8e0c555daf3a1b299a56a3 to your computer and use it in GitHub Desktop.
Save oderayi/4556a63f1c8e0c555daf3a1b299a56a3 to your computer and use it in GitHub Desktop.
Renko Chart Generator with ATR
//+------------------------------------------------------------------+
//| IndRange.mq4 |
//| Copyright 2016, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "The indicator creates an Range chart"
#property strict
#property indicator_chart_window
//--- input parameter
input double SizeRenko=40;
input bool UseATRBoxSize=true;
input ENUM_TIMEFRAMES ATRTimeframe=PERIOD_CURRENT;
input int ATRPeriod=14;
input string ChartTemplate="RenkoTemplate.tpl";
input bool ClosePreviousOfflineChart=true;
//---
int ExtOffPeriod =7;
bool first_start =true; // true -> it's first start
bool crash =false; // false -> error in the code
int HandleHistory =-1; // handle for the opened "*.hst" file
datetime time0; //
ulong last_fpos =0; //
int periodseconds; //
int i_period; //
MqlRates rate; //
long ChartOffID =-1; // ID of the offline chart
long ChartOffIDPrev = -1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 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(crash)
return(rates_total);
if(prev_calculated==0 && first_start) // first start
{
if(CreateHeader(ExtOffPeriod))
first_start=false;
else
{
crash=true;
return(rates_total);
}
//---
FirstWriteHistory(ExtOffPeriod);
first_start=false;
//---
ResetLastError();
if (ClosePreviousOfflineChart) {
ChartOffIDPrev = GetPrevChartID();
if (ChartOffIDPrev != -1) ChartClose(ChartOffIDPrev);
}
ChartOffID=ChartOpen(Symbol(),PERIOD_M1*ExtOffPeriod);
if(ChartOffID==0)
{
Print("Error open chart: ",GetLastError());
first_start=false;
crash=true;
return(rates_total);
}
else
StoreChartID(ChartOffID);
Print(__FUNCTION__,"Opening offline chart id=",ChartOffID);
ChartApplyTemplate(ChartOffID, ChartTemplate);
}
//---
if(prev_calculated==0 && !first_start) // a deeper history downloaded or history blanks filled
{
Print("a deeper history downloaded or history blanks filled. first_start=",first_start);
if(CreateHeader(ExtOffPeriod))
first_start=false;
else
{
crash=true;
return(rates_total);
}
//---
FirstWriteHistory(ExtOffPeriod);
first_start=false;
}
//---
CollectTicks();
//--- return value of prev_calculated for next call
return(rates_total);
}
void StoreChartID(long chartID) {
long topID = chartID/1000000000;
long bottomID = chartID - topID*1000000000;
GlobalVariableSet("ChartOffIDPrevTop", (double)topID);
GlobalVariableSet("ChartOffIDPrevBottom", (double)bottomID);
}
long GetPrevChartID() {
long topID = (long)GlobalVariableGet("ChartOffIDPrevTop");
long bottomID = (long)GlobalVariableGet("ChartOffIDPrevBottom");
return (topID*1000000000)+bottomID;
}
//+------------------------------------------------------------------+
//| The function checks offline mode of the chart |
//+------------------------------------------------------------------+
bool IsOffline(const long chart_ID=0)
{
bool offline=ChartGetInteger(chart_ID,CHART_IS_OFFLINE);
return(offline);
}
//+------------------------------------------------------------------+
//| Create history header |
//+------------------------------------------------------------------+
bool CreateHeader(const int offline_period)
{
//---- History header
int file_version=401;
string c_copyright;
string c_symbol=Symbol();
i_period=PERIOD_M1*offline_period;//Period()*offline_period; //
int i_digits=Digits;
int i_unused[13];
//---
ResetLastError();
HandleHistory=FileOpenHistory(c_symbol+(string)i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
if(HandleHistory<0)
{
Print("Error open ",c_symbol+(string)i_period,".hst file ",GetLastError());
return(false);
}
c_copyright="(C)opyright 2003, MetaQuotes Software Corp.";
ArrayInitialize(i_unused,0);
//--- write history file header
FileWriteInteger(HandleHistory,file_version,LONG_VALUE);
FileWriteString(HandleHistory,c_copyright,64);
FileWriteString(HandleHistory,c_symbol,12);
FileWriteInteger(HandleHistory,i_period,LONG_VALUE);
FileWriteInteger(HandleHistory,i_digits,LONG_VALUE);
FileWriteInteger(HandleHistory,0,LONG_VALUE);
FileWriteInteger(HandleHistory,0,LONG_VALUE);
FileWriteArray(HandleHistory,i_unused,0,13);
return(true);
}
//+------------------------------------------------------------------+
//| First Write History |
//+------------------------------------------------------------------+
bool FirstWriteHistory(const int offline_period)
{
int i,start_pos;
int cnt=0;
double renkoSize = GetRenkoSize();
//--- write history file
periodseconds=offline_period*60;
start_pos=Bars-1;
rate.open=Open[start_pos];
rate.close=Close[start_pos];
rate.low=Low[start_pos];
rate.high=High[start_pos];
rate.tick_volume=(long)Volume[start_pos];
rate.spread=0;
rate.real_volume=0;
//--- normalize open time
rate.time=D'1980.07.19 12:30:27';
for(i=start_pos-1; i>=0; i--)
{
if(IsStopped())
break;
while((High[i]-rate.high)>renkoSize*Point())
{
rate.time+=1;
rate.open=rate.high;
rate.low=rate.open;
rate.close=NormalizeDouble(rate.low+renkoSize*Point(),Digits);
rate.high=rate.close;
last_fpos=FileTell(HandleHistory);
uint byteswritten=FileWriteStruct(HandleHistory,rate);
//--- check the number of bytes written
if(byteswritten==0)
PrintFormat("Error read data. Error code=%d",GetLastError());
else
cnt++;
}
while((Low[i]-rate.low)<-GetRenkoSize()*Point())
{
rate.time+=1;
rate.open=rate.low;
rate.high=rate.open;
rate.close=NormalizeDouble(rate.high-renkoSize*Point(),Digits);
rate.low=rate.close;
last_fpos=FileTell(HandleHistory);
uint byteswritten=FileWriteStruct(HandleHistory,rate);
//--- check the number of bytes written
if(byteswritten==0)
PrintFormat("Error read data. Error code=%d",GetLastError());
else
cnt++;
}
}
FileFlush(HandleHistory);
PrintFormat("%d record(s) written",cnt);
return(true);
}
//+------------------------------------------------------------------+
//| Collect Ticks |
//+------------------------------------------------------------------+
bool CollectTicks()
{
static datetime last_time;//=TimeLocal()-5;
long chart_id=0;
datetime cur_time=TimeLocal();
double renkoSize = GetRenkoSize();
//---
while((Close[0]-rate.high)>renkoSize*Point())
{
rate.time+=1;
rate.open=rate.high;
rate.low=rate.open;
rate.close=NormalizeDouble(rate.low+renkoSize*Point(),Digits);
rate.high=rate.close;
last_fpos=FileTell(HandleHistory);
uint byteswritten=FileWriteStruct(HandleHistory,rate);
//--- check the number of bytes written
if(byteswritten==0)
PrintFormat("Error read data. Error code=%d",GetLastError());
}
while((Close[0]-rate.low)<-renkoSize*Point())
{
rate.time+=1;
rate.open=rate.low;
rate.high=rate.open;
rate.close=NormalizeDouble(rate.high-renkoSize*Point(),Digits);
rate.low=rate.close;
last_fpos=FileTell(HandleHistory);
uint byteswritten=FileWriteStruct(HandleHistory,rate);
//--- check the number of bytes written
if(byteswritten==0)
PrintFormat("Error read data. Error code=%d",GetLastError());
}
//--- refresh window not frequently than 1 time in 2 seconds
if(cur_time-last_time>=3)
{
FileFlush(HandleHistory);
ChartSetSymbolPeriod(ChartOffID,Symbol(),i_period);
last_time=cur_time;
}
return(true);
}
double GetRenkoSize() {
if (!UseATRBoxSize) return SizeRenko;
else {
double atr = iATR(NULL, ATRTimeframe, ATRPeriod, 0);
double atr_in_points = (int)round(atr/_Point);
return atr_in_points;
}
}
//+------------------------------------------------------------------+
//| Deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(HandleHistory>=0)
{
FileClose(HandleHistory);
HandleHistory=-1;
}
}
//+------------------------------------------------------------------+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment