Last active
November 4, 2021 18:08
-
-
Save oderayi/4556a63f1c8e0c555daf3a1b299a56a3 to your computer and use it in GitHub Desktop.
Renko Chart Generator with ATR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| 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