forked from rosh/MQL5Book
202 lines
6.7 KiB
MQL5
202 lines
6.7 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| LibHoughChannel.mq5 |
| |||
//| Copyright (c) 2015-2022, Marketeer |
| |||
//| https://www.mql5.com/en/users/marketeer |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright (c) 2015-2022, Marketeer"
| |||
#property link "https://www.mql5.com/en/users/marketeer"
| |||
#property version "1.0"
| |||
#property description "Create 2+ trend lines on highs and lows using Hough transform."
| |||
| |||
#property indicator_chart_window
| |||
#property indicator_buffers 0
| |||
#property indicator_plots 0
| |||
| |||
//#define LIB_HOUGH_IMPL_DEBUG
| |||
#include "..\..\Include\LibHoughTransform.mqh"
| |||
#include "..\..\Include\AutoPtr.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| I N P U T S |
| |||
//+------------------------------------------------------------------+
| |||
input int BarOffset = 0;
| |||
input int BarCount = 21;
| |||
input int MaxLines = 3;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom implementation of HoughImage based on quotes |
| |||
//+------------------------------------------------------------------+
| |||
class HoughQuotes: public HoughImage<int>
| |||
{
| |||
public:
| |||
enum PRICE_LINE
| |||
{
| |||
HighLow = 0, // Bar Range |High..Low|
| |||
OpenClose = 1, // Bar Body |Open..Close|
| |||
LowLow = 2, // Bar Lows
| |||
HighHigh = 3, // Bar Highs
| |||
};
| |||
| |||
protected:
| |||
int size;
| |||
int offset;
| |||
int step;
| |||
double base;
| |||
PRICE_LINE type;
| |||
| |||
public:
| |||
HoughQuotes(int startbar, int barcount, PRICE_LINE price)
| |||
{
| |||
offset = startbar;
| |||
size = barcount;
| |||
type = price;
| |||
int hh = iHighest(NULL, 0, MODE_HIGH, size, startbar);
| |||
int ll = iLowest(NULL, 0, MODE_LOW, size, startbar);
| |||
int pp = (int)((iHigh(NULL, 0, hh) - iLow(NULL, 0, ll)) / _Point);
| |||
step = pp / size;
| |||
base = iLow(NULL, 0, ll);
| |||
}
| |||
| |||
virtual int getWidth() const override
| |||
{
| |||
return size;
| |||
}
| |||
| |||
virtual int getHeight() const override
| |||
{
| |||
return size;
| |||
}
| |||
| |||
virtual int get(int x, int y) const override
| |||
{
| |||
if(offset + x >= iBars(NULL, 0)) return 0;
| |||
| |||
const double price = convert(y);
| |||
if(type == HighLow)
| |||
{
| |||
if(price >= iLow(NULL, 0, offset + x) && price <= iHigh(NULL, 0, offset + x))
| |||
{
| |||
return 1;
| |||
}
| |||
}
| |||
else if(type == OpenClose)
| |||
{
| |||
if(price >= fmin(iOpen(NULL, 0, offset + x), iClose(NULL, 0, offset + x))
| |||
&& price <= fmax(iOpen(NULL, 0, offset + x), iClose(NULL, 0, offset + x)))
| |||
{
| |||
return 1;
| |||
}
| |||
}
| |||
else if(type == LowLow)
| |||
{
| |||
if(iLow(NULL, 0, offset + x) >= price - step * _Point / 2
| |||
&& iLow(NULL, 0, offset + x) <= price + step * _Point / 2)
| |||
{
| |||
return 1;
| |||
}
| |||
}
| |||
else if(type == HighHigh)
| |||
{
| |||
if(iHigh(NULL, 0, offset + x) >= price - step * _Point / 2
| |||
&& iHigh(NULL, 0, offset + x) <= price + step * _Point / 2)
| |||
{
| |||
return 1;
| |||
}
| |||
}
| |||
return 0;
| |||
}
| |||
| |||
// index by Y (quantized) -> continuous value (such as price)
| |||
double convert(const double y) const
| |||
{
| |||
return base + y * step * _Point;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| G L O B A L S |
| |||
//+------------------------------------------------------------------+
| |||
const string Prefix = "HoughChannel-";
| |||
HoughTransform *ht;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom indicator initialization function |
| |||
//+------------------------------------------------------------------+
| |||
int OnInit()
| |||
{
| |||
ht = createHoughTransform(BarCount);
| |||
HoughInfo info = getHoughInfo();
| |||
Print(info.dimension, " per ", info.about);
| |||
return CheckPointer(ht) != POINTER_INVALID ? INIT_SUCCEEDED : INIT_FAILED;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom indicator iteration function |
| |||
//+------------------------------------------------------------------+
| |||
int OnCalculate(const int rates_total,
| |||
const int prev_calculated,
| |||
const int begin,
| |||
const double &price[])
| |||
{
| |||
static datetime now = 0;
| |||
if(now != iTime(NULL, 0, 0))
| |||
{
| |||
HoughQuotes highs(BarOffset, BarCount, HoughQuotes::HighHigh);
| |||
HoughQuotes lows(BarOffset, BarCount, HoughQuotes::LowLow);
| |||
static double result[];
| |||
int n;
| |||
n = ht.transform(highs, result, fmin(MaxLines, 5));
| |||
if(n)
| |||
{
| |||
for(int i = 0; i < n; ++i)
| |||
{
| |||
DrawLine(highs, Prefix + "Highs-" + (string)i, result[i * 2 + 0], result[i * 2 + 1], clrBlue, 5 - i);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
Print("No solution for Highs");
| |||
}
| |||
n = ht.transform(lows, result, fmin(MaxLines, 5));
| |||
if(n)
| |||
{
| |||
for(int i = 0; i < n; ++i)
| |||
{
| |||
DrawLine(lows, Prefix + "Lows-" + (string)i, result[i * 2 + 0], result[i * 2 + 1], clrRed, 5 - i);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
Print("No solution for Lows");
| |||
}
| |||
now = iTime(NULL, 0, 0);
| |||
}
| |||
return rates_total;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Single line visual presenter |
| |||
//+------------------------------------------------------------------+
| |||
void DrawLine(HoughQuotes "es, const string name, const double a, const double b,
| |||
const color clr, const int width)
| |||
{
| |||
ObjectCreate(0, name, OBJ_TREND, 0, 0, 0);
| |||
ObjectSetInteger(0, name, OBJPROP_TIME, 0, iTime(NULL, 0, BarOffset + BarCount - 1));
| |||
ObjectSetDouble(0, name, OBJPROP_PRICE, 0, quotes.convert(a * (BarCount - 1) + b));
| |||
| |||
ObjectSetInteger(0, name, OBJPROP_TIME, 1, iTime(NULL, 0, BarOffset));
| |||
ObjectSetDouble(0, name, OBJPROP_PRICE, 1, quotes.convert(a * 0 + b));
| |||
| |||
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
| |||
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Finalization handler |
| |||
//+------------------------------------------------------------------+
| |||
void OnDeinit(const int)
| |||
{
| |||
AutoPtr<HoughTransform> destructor(ht);
| |||
ObjectsDeleteAll(0, Prefix);
| |||
}
| |||
//+------------------------------------------------------------------+
|