This script is designed to transform standard price action into a Renko chart, which focuses on price movement rather than the passage of time. In a typical chart, every candle represents a specific minute or hour; in this Renko system, a new "brick" (or box) only appears when the price moves by a specific, predetermined amount.
Core Functionality
The script works by monitoring live market data and creating a synthetic history of price movement. Instead of displaying every fluctuation, it filters the noise to show only significant price changes based on the user-defined "Box Size."
How the Logic Works:
1. Initialization and Compatibility When first launched, the script performs several behind-the-scenes checks:
- Broker Adjustment: It automatically detects if your broker uses different decimal precisions (like 5 or 6 digits) and adjusts the box size accordingly to ensure accuracy.
- Validation: It verifies that the connection is active and that the user has granted the necessary permissions for the script to run its background tasks.
2. Historical Data Processing Before showing you live prices, the script looks at the existing history of the asset:
- It scans through past price data and "reconstructs" what the Renko bricks would have looked like.
- It calculates whether the price moved up or down enough to form a brick based on your chosen box size.
- It creates an offline file (a
.hstfile) to store this reconstructed history so that the chart looks continuous from the past to the present.
3. Live Price Tracking Once the history is processed, the script enters "Live Mode," where it monitors every tick of the market:
- Price Movement: It watches the current "Bid" price. If the price moves high enough to exceed the previous brick's top boundary, it creates a new "Up" brick. Conversely, if it drops far enough below the bottom boundary, it creates a "Down" brick.
- Wick Handling: Depending on your settings, the script can track "wicks"—these are the small lines that show how far the price pushed into a direction before retreating, even if it didn't move far enough to create a full new brick.
- Continuous Updates: The script constantly updates a hidden file with the latest coordinates (Open, High, Low, Close) of these bricks.
4. Visual Integration To ensure you can actually see this data on your platform, the script includes a mechanism to communicate with the chart window. It sends commands to refresh the display so that as new bricks are formed in the background, they appear seamlessly on your screen.
Summary for the User
In plain terms, this script acts as a "translator." It takes the messy, jagged movements of standard price charts and translates them into clean, uniform blocks. It ignores minor price fluctuations and only updates your view when the market moves a significant, consistent distance in either direction.
//+---------------------------------------------------------------------------+
//| EA VERSION
//| RenkoLiveChart_v3.0.mq4
//| Inspired from Renko script by "e4" (renko_live_scr.mq4)
//| Copyleft 2009 LastViking
//|
//| Sep 2009 - 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
//+---------------------------------------------------------------------------+
#property copyright ""
//+------------------------------------------------------------------+
#include <WinUser32.mqh>
#include <stdlib.mqh>
//+------------------------------------------------------------------+
extern int RenkoBoxSize = 10;
extern int BoxOffset = 0;
extern int RenkoTimeFrame = 2; // What time frame to use for the offline renko chart
extern bool StrangeSymbolName = false;
extern bool ShowWicks = true;
int BoxSize;
//+------------------------------------------------------------------+
int HstHandle = -1;
string SymbolName;
//+------------------------------------------------------------------+
void UpdateChartWindow() {
static int hwnd = 0;
if(hwnd == 0) {
hwnd = WindowHandle(SymbolName, RenkoTimeFrame);
if(hwnd != 0) Print("Chart window detected");
}
if(hwnd != 0) if(PostMessageA(hwnd, WM_COMMAND, 0x822c, 0) == 0) hwnd = 0;
}
int init() {
BoxSize = RenkoBoxSize;
if (Digits == 5)
{BoxSize = BoxSize*10;}
if (Digits == 6)
{BoxSize = BoxSize*100;}
HstHandle = -1;
return(0);
}
//+------------------------------------------------------------------+
int start() {
static int LastFPos = 0;
static double BoxPoints, PrevLow, PrevHigh, PrevOpen, PrevClose, CurVolume, CurHigh, CurLow;
static double CurOpen, CurClose;
static datetime PrevTime;
static double UpWick = 0;
static double DnWick = EMPTY_VALUE;
if(HstHandle < 0) {
// Init
// Error checking
if(!IsConnected()) {
Print("Waiting for connection...");
return(0);
}
if(!IsDllsAllowed()) {
Print("Error: Dll calls must be allowed!");
return(-1);
}
if(MathAbs(BoxOffset) >= BoxSize) {
Print("Error: |BoxOffset| should be less then BoxSize!");
return(-1);
}
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)!");
return(-1);
}
//
if(StrangeSymbolName) SymbolName = StringSubstr(Symbol(), 0, 6);
else SymbolName = Symbol();
BoxPoints = NormalizeDouble(BoxSize*Point, Digits);
PrevLow = NormalizeDouble(BoxOffset*Point + MathFloor(Close[Bars-1]/BoxPoints)*BoxPoints, Digits);
PrevHigh = PrevLow + BoxPoints;
PrevOpen = PrevLow;
PrevClose = PrevHigh;
CurVolume = 1;
PrevTime = Time[Bars-1];
// create / open hst file
HstHandle = FileOpenHistory(SymbolName + RenkoTimeFrame + ".hst", FILE_BIN|FILE_WRITE);
if(HstHandle < 0) return(-1);
//
// write hst file header
int HstUnused[13];
FileWriteInteger(HstHandle, 400, LONG_VALUE); // Version
FileWriteString(HstHandle, "", 64); // Copyright
FileWriteString(HstHandle, SymbolName, 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;
//---------------------------------------------------------------------------
while(i >= 0) {
CurVolume += Volume[i];
UpWick = MathMax(UpWick,High[i]);
DnWick = MathMin(DnWick,Low[i]);
bool UpTrend = High[i]+Low[i] > PrevHigh+PrevLow;
// update low before high or the revers depending on is closest to prev. renko bar
while(UpTrend && (Low[i] < PrevLow-BoxPoints || CompareDoubles(Low[i],PrevLow-BoxPoints))) {
PrevHigh = PrevHigh - BoxPoints;
PrevLow = PrevLow - BoxPoints;
PrevOpen = PrevHigh;
PrevClose = PrevLow;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE);
FileWriteDouble(HstHandle, PrevOpen, DOUBLE_VALUE);
FileWriteDouble(HstHandle, PrevLow, DOUBLE_VALUE);
if (ShowWicks && UpWick > PrevHigh)
{FileWriteDouble(HstHandle, UpWick, DOUBLE_VALUE);}
else
{FileWriteDouble(HstHandle, PrevHigh, DOUBLE_VALUE);}
UpWick = 0;
DnWick = EMPTY_VALUE;
FileWriteDouble(HstHandle, PrevClose, DOUBLE_VALUE);
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE);
CurVolume = 0;
if(PrevTime < Time[i]) PrevTime = Time[i];
else PrevTime++;
}
while(UpTrend && (High[i] > PrevHigh+BoxPoints || CompareDoubles(High[i],PrevHigh+BoxPoints))) {
PrevHigh = PrevHigh + BoxPoints;
PrevLow = PrevLow + BoxPoints;
PrevOpen = PrevLow;
PrevClose = PrevHigh;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE);
FileWriteDouble(HstHandle, PrevOpen, DOUBLE_VALUE);
if (ShowWicks && DnWick < PrevLow)
{FileWriteDouble(HstHandle, DnWick, DOUBLE_VALUE);}
else
{FileWriteDouble(HstHandle, PrevLow, DOUBLE_VALUE);}
UpWick = 0;
DnWick = EMPTY_VALUE;
FileWriteDouble(HstHandle, PrevHigh, DOUBLE_VALUE);
FileWriteDouble(HstHandle, PrevClose, DOUBLE_VALUE);
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE);
CurVolume = 0;
if(PrevTime < Time[i]) PrevTime = Time[i];
else PrevTime++;
}
while(!UpTrend && (Low[i] < PrevLow-BoxPoints || CompareDoubles(Low[i],PrevLow-BoxPoints))) {
PrevHigh = PrevHigh - BoxPoints;
PrevLow = PrevLow - BoxPoints;
PrevOpen = PrevHigh;
PrevClose = PrevLow;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE);
FileWriteDouble(HstHandle, PrevOpen, DOUBLE_VALUE);
FileWriteDouble(HstHandle, PrevLow, DOUBLE_VALUE);
if (ShowWicks && UpWick > PrevHigh)
{FileWriteDouble(HstHandle, UpWick, DOUBLE_VALUE);}
else
{FileWriteDouble(HstHandle, PrevHigh, DOUBLE_VALUE);}
UpWick = 0;
DnWick = EMPTY_VALUE;
FileWriteDouble(HstHandle, PrevClose, DOUBLE_VALUE);
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE);
CurVolume = 0;
if(PrevTime < Time[i]) PrevTime = Time[i];
else PrevTime++;
}
i--;
}
FileFlush(HstHandle);
LastFPos = FileTell(HstHandle); // Remember Last pos in file
//
Comment("RenkoLiveChart(" + BoxSize + "): Open Offline ", SymbolName, ",M", RenkoTimeFrame, " to view chart");
CurOpen = PrevClose;
if (UpWick > PrevHigh)
{CurHigh = UpWick;}
else
{CurHigh = PrevHigh;}
if (DnWick < PrevLow)
{CurLow = DnWick;}
else
{CurLow = PrevLow;}
CurClose = Close[0];
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE); // Time
FileWriteDouble(HstHandle, CurOpen, DOUBLE_VALUE); // Open
FileWriteDouble(HstHandle, CurLow, DOUBLE_VALUE); // Low
FileWriteDouble(HstHandle, CurHigh, DOUBLE_VALUE); // High
FileWriteDouble(HstHandle, CurClose, DOUBLE_VALUE); // Close
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE); // Volume
FileFlush(HstHandle);
UpdateChartWindow();
return(0);
// End historical data / Init
}
//----------------------------------------------------------------------------
// HstHandle not < 0 so we always enter here after history done
// Begin live data feed
//
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;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE);
FileWriteDouble(HstHandle, PrevOpen, DOUBLE_VALUE);
if (ShowWicks && DnWick < PrevLow)
{FileWriteDouble(HstHandle, DnWick, DOUBLE_VALUE);}
else
{FileWriteDouble(HstHandle, PrevLow, DOUBLE_VALUE);}
UpWick = 0;
DnWick = EMPTY_VALUE;
FileWriteDouble(HstHandle, PrevHigh, DOUBLE_VALUE);
FileWriteDouble(HstHandle, PrevClose, DOUBLE_VALUE);
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE);
FileFlush(HstHandle);
LastFPos = FileTell(HstHandle); // Remeber Last pos in file
if(PrevTime < TimeCurrent()) PrevTime = TimeCurrent();
else PrevTime++;
CurVolume = 0;
CurOpen = PrevClose;
CurHigh = PrevHigh;
CurLow = PrevHigh;
UpdateChartWindow();
}
// down box
//-------------------------------------------------------------------------
else if(Bid < PrevLow-BoxPoints || CompareDoubles(Bid,PrevLow-BoxPoints)) {
PrevHigh = PrevHigh - BoxPoints;
PrevLow = PrevLow - BoxPoints;
PrevOpen = PrevHigh;
PrevClose = PrevLow;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE);
FileWriteDouble(HstHandle, PrevOpen, DOUBLE_VALUE);
FileWriteDouble(HstHandle, PrevLow, DOUBLE_VALUE);
if (ShowWicks && UpWick > PrevHigh)
{FileWriteDouble(HstHandle, UpWick, DOUBLE_VALUE);}
else
{FileWriteDouble(HstHandle, PrevHigh, DOUBLE_VALUE);}
UpWick = 0;
DnWick = EMPTY_VALUE;
FileWriteDouble(HstHandle, PrevClose, DOUBLE_VALUE);
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE);
FileFlush(HstHandle);
LastFPos = FileTell(HstHandle); // Remeber Last pos in file
if(PrevTime < TimeCurrent()) PrevTime = TimeCurrent();
else PrevTime++;
CurVolume = 0;
CurOpen = PrevClose;
CurHigh = PrevLow;
CurLow = PrevLow;
UpdateChartWindow();
}
else {
// no box - high/low not hit
//-------------------------------------------------------------------------
if(Bid > CurHigh) CurHigh = Bid;
if(Bid < CurLow) CurLow = Bid;
CurClose = Bid;
FileWriteInteger(HstHandle, PrevTime, LONG_VALUE); // Time
FileWriteDouble(HstHandle, CurOpen, DOUBLE_VALUE); // Open
FileWriteDouble(HstHandle, CurLow, DOUBLE_VALUE); // Low
FileWriteDouble(HstHandle, CurHigh, DOUBLE_VALUE); // High
FileWriteDouble(HstHandle, CurClose, DOUBLE_VALUE); // Close
FileWriteDouble(HstHandle, CurVolume, DOUBLE_VALUE); // Volume
FileFlush(HstHandle);
UpdateChartWindow();
}
return(0);
}
//+------------------------------------------------------------------+
int deinit() {
if(HstHandle >= 0) {
FileClose(HstHandle);
HstHandle = -1;
}
Comment("");
return(0);
}
//+------------------------------------------------------------------+
Comments