Point & Figure
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «point and figure.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Point & Figure — индикатор для MetaTrader 5, реализующий классический метод технического анализа Point & Figure. Он строит графическую модель цены в виде квадратов X (рост) и O (падение) в отдельном окне индикатора и отображает подробную информационную панель на основном графике. Работает на любом символе и таймфрейме.
Индикатор автоматически рассчитывает столбцы P&F на основе заданного размера коробки — фиксированного в пунктах или адаптивного на основе ATR. Генерируются сигналы входа BUY (+1) и SELL (-1) при пробое уровней предыдущих столбцов. Доступны фильтры: по структуре цен (более высокий минимум / более низкий максимум), по тренду (EMA), по силе тренда (ADX) и по торговой сессии.
Информационная панель показывает план сделки (вход, стоп-лосс, тейк-профит, соотношение риск/прибыль, размер лота), текущие условия входа, состояние фильтров, структуру P&F и уровни поддержки/сопротивления. Поддерживаются оповещения: всплывающие окна, звуковые сигналы, push-уведомления и e-mail.
Индикатор также определяет классические паттерны P&F (двойной/тройной верх и низ, катапульта, треугольник) и отображает их названия в окне. Линии поддержки и сопротивления R1/R2/S1/S2 рисуются на основном графике с настраиваемым цветом и стилем.
Настройки программы
| Настройка | Описание |
|---|---|
| InpBoxMode | Режим определения размера коробки: фиксированный (в пунктах) или адаптивный (на основе ATR). |
| InpBoxPoints | Фиксированный размер коробки в пунктах. Используется при выборе фиксированного режима. |
| InpATRPeriod | Период расчёта индикатора ATR для автоматического определения размера коробки. |
| InpATRTf | Таймфрейм для расчёта ATR при использовании адаптивного режима размера коробки. |
| InpATRMult | Множитель ATR: размер коробки в адаптивном режиме рассчитывается как кратное значение ATR. |
| InpReversal | Количество коробок, необходимое для разворота направления столбца P&F. |
| InpSource | Источник цены для построения P&F: цена закрытия или диапазон высокий/низкий. |
| InpHistoryBars | Максимальное количество баров истории, используемых для расчёта P&F. |
| InpClosedOnly | Использование только закрытых баров для расчёта P&F, что обеспечивает стабильность сигналов. |
| InpColorX | Цвет квадратов X, обозначающих рост цены в P&F. |
| InpColorO | Цвет квадратов O, обозначающих падение цены в P&F. |
| InpMaxColumns | Максимальное количество отображаемых столбцов P&F в окне индикатора. |
| InpColWidth | Ширина столбца P&F в барах основного графика. |
| InpLeftShift | Количество баров сдвига от последнего бара для отображения P&F в отдельном окне. |
| InpGapPct | Процент зазора между квадратами P&F относительно размера коробки. |
| InpShowBorder | Отображение границы вокруг квадратов P&F. |
| InpBorderColor | Цвет границы вокруг квадратов P&F (при включённом отображении границ). |
| InpBorderWidth | Ширина границы квадратов в пикселях. Автоматически уменьшается в маленьких окнах. |
| InpMaxObjects | Максимальное количество графических объектов (квадраты и границы) на графике. |
| InpWindowHeight | Высота окна Point & Figure в пикселях. 0 — высота остаётся по умолчанию. |
| InpShowPrice | Отображение линии текущей цены в отдельном окне P&F. |
| InpShowPanel | Отображение информационной панели на основном графике. |
| InpPanelPos | Расположение информационной панели на графике: верхний/нижний левый или правый угол. |
| InpPanelMode | Начальный режим отображения панели: полный (Full), компактный (Compact) или минимальный (Minimal). |
| InpPanelX | Горизонтальное расстояние панели от края графика в пикселях. |
| InpPanelY | Вертикальное расстояние панели от края графика в пикселях. |
| InpPanelBg | Цвет фона информационной панели на основном графике. |
| InpSectionColor | Цвет заголовков секций на информационной панели. |
| InpPanelRefreshMs | Интервал обновления данных панели в миллисекундах. |
| InpPanelScale | Масштаб размера панели: 1.0 — нормальный, 1.5 — увеличен на 50%, 2.0 — удвоен. |
| InpTextScale | Масштаб размера текста на панели: 1.0 — нормальный, 1.3 — +30%, 1.6 — +60%. |
| InpRequireHL | Фильтрация сигналов по структуре: BUY требует более высокого минимума, SELL — более низкого максимума. |
| InpOnlyFlips | Генерация сигнала только при смене направления по сравнению с предыдущим сигналом. |
| InpRR | Соотношение риска к прибыли (Risk/Reward) для расчёта уровня тейк-профита. |
| InpSLBuffer | Дополнительный буфер стоп-лосса в пунктах. 0 — автоматический (20% от размера коробки). |
| InpShowPatterns | Отображение названий паттернов P&F в окне индикатора. |
| InpPatternColor | Цвет текста названий паттернов P&F в окне индикатора. |
| InpRiskPct | Процент баланса, используемый как допустимый риск для расчёта размера лота. |
| InpMaxRiskPips | Предупреждение, если стоп-лосс превышает указанное количество пипсов. 0 — автоматический расчёт (6 коробок). |
| InpMaxChasePips | Предупреждение, если цена сместилась дальше пробоя на указанное количество пипсов. 0 — автоматический расчёт (1 коробка). |
| InpMaxSpreadPips | Предупреждение, если спред превышает указанное количество пипсов. 0 — автоматический расчёт (0.3 коробки). |
| InpUseTrendMA | Включение фильтра тренда EMA: BUY только выше EMA, SELL только ниже EMA. |
| InpMAPeriod | Период экспоненциальной скользящей средней (EMA) для фильтрации тренда. |
| InpUseADX | Включение фильтра ADX: сигналы игнорируются при боковом рынке (ADX ниже минимального значения). |
| InpADXPeriod | Период расчёта индекса ADX (сила тренда) для фильтрации сигналов. |
| InpADXMin | Минимальное значение ADX: сигналы игнорируются, если индекс силы тренда ниже этого порога. Используется для фильтрации бокового рынка. |
| InpUseSession | Включение фильтрации сигналов по времени торговой сессии (серверное время). |
| InpStartHour | Час начала торговой сессии по серверному времени для фильтрации сигналов. |
| InpEndHour | Час окончания торговой сессии по серверному времени для фильтрации сигналов. |
| InpSRLookback | Количество столбцов P&F, анализируемых для определения уровней поддержки и сопротивления. |
| InpShowSRLines | Отрисовка линий R1/R2/S1/S2 и их подписей на основном графике. |
| InpResistColor | Цвет линий сопротивления R1/R2 на основном графике. |
| InpSupportColor | Цвет линий поддержки S1/S2 на основном графике. |
| InpResistLabelBg | Цвет фона подписей уровней сопротивления на основном графике. |
| InpSupportLabelBg | Цвет фона подписей уровней поддержки на основном графике. |
| InpSRLabelText | Цвет текста подписей уровней поддержки и сопротивления. |
| InpSRLineWidth | Толщина линий поддержки и сопротивления на основном графике (от 1 до 5). |
| InpSRLabelSize | Размер шрифта подписей уровней поддержки и сопротивления. |
| InpSRLabelRight | Расстояние подписей уровней поддержки/сопротивления от правого края графика в пикселях. |
| InpAlertSignals | Отправка оповещения при появлении сигнала BUY или SELL. |
| InpAlertPatterns | Отправка оповещения при обнаружении паттерна P&F (двойной/тройной верх или низ, катапульта, треугольник). |
| InpAlertColumn | Отправка оповещения при формировании нового столбца X/O на графике P&F. |
| InpAlertPopup | Отображение всплывающего окна при срабатывании оповещений. |
| InpAlertSound | Воспроизведение звукового сигнала при срабатывании оповещений. |
| InpSoundFile | Путь к звуковому файлу, воспроизводимому при оповещениях. |
| InpAlertPush | Отправка push-уведомления на мобильное устройство при оповещениях. |
| InpAlertEmail | Отправка оповещения по электронной почте при появлении сигналов, паттернов или столбцов. |
Поиск по коду файла
#property version "4.10"
#property description "Point & Figure: lime squares = X (rising), red squares = O (falling), navy border."
#property description "Navy panel in the main window: signal, trade plan, entry conditions, P&F structure."
#property description "Works on any symbol / timeframe. Signal buffer: +1 BUY, -1 SELL, 0 none."
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_type1 DRAW_NONE
#property indicator_label1 "PF Signal"
enum ENUM_BOX_MODE
{
BOX_FIXED_POINTS = 0, // Fixed (points)
BOX_ATR = 1 // ATR based (adapts to symbol / timeframe)
};
enum ENUM_PF_SOURCE
{
PF_CLOSE = 0, // Close price
PF_HIGHLOW = 1 // High / Low
};
enum ENUM_PF_PATTERN
{
PAT_NONE = 0,
PAT_DTB, // Double top breakout
PAT_DBB, // Double bottom breakdown
PAT_TTB, // Triple top breakout
PAT_TBB, // Triple bottom breakdown
PAT_BULL_CAT, // Bullish catapult
PAT_BEAR_CAT, // Bearish catapult
PAT_TRIANGLE // Triangle (consolidation)
};
enum ENUM_PANEL_POS
{
PNL_LEFT_TOP = 0, // Top left
PNL_RIGHT_TOP = 1, // Top right
PNL_LEFT_BOTTOM = 2, // Bottom left
PNL_RIGHT_BOTTOM = 3 // Bottom right
};
enum ENUM_PANEL_MODE
{
PMODE_FULL = 0, // Full
PMODE_COMPACT = 1, // Compact
PMODE_MIN = 2 // Minimal
};
enum ENUM_SECTION_CLR
{
SC_SKY = 0, // Sky blue
SC_GOLD = 1, // Gold
SC_ORANGE = 2, // Orange
SC_LIME = 3, // Lime green
SC_AQUA = 4, // Aqua
SC_PINK = 5, // Pink
SC_MAGENTA = 6, // Magenta
SC_VIOLET = 7, // Violet
SC_SILVER = 8, // Silver
SC_WHITE = 9 // White
};
input group "=== Point & Figure ==="
input ENUM_BOX_MODE InpBoxMode = BOX_ATR; // Box size mode
input int InpBoxPoints = 50; // Box size (points) - fixed mode
input int InpATRPeriod = 14; // ATR period - ATR mode
input ENUM_TIMEFRAMES InpATRTf = PERIOD_CURRENT; // ATR timeframe - ATR mode
input double InpATRMult = 1.0; // ATR multiplier - ATR mode
input int InpReversal = 3; // Reversal (number of boxes)
input ENUM_PF_SOURCE InpSource = PF_CLOSE; // Price source
input int InpHistoryBars = 3000; // Max. history bars used
input bool InpClosedOnly = true; // Closed bars only (stable signals)
input group "=== Display (P&F window) ==="
input color InpColorX = clrLime; // X squares color (rising)
input color InpColorO = clrRed; // O squares color (falling)
input int InpMaxColumns = 40; // Max. columns displayed
input int InpColWidth = 3; // Column width (chart bars)
input int InpLeftShift = 8; // Shift to the left (bars) from the last bar
input double InpGapPct = 20.0; // Gap between squares (% of box)
input bool InpShowBorder = true; // Border around squares
input color InpBorderColor = clrNavy; // Border color
input int InpBorderWidth = 2; // Border width (pixels, reduced automatically in small windows)
input int InpMaxObjects = 5000; // Object limit (squares + borders)
input int InpWindowHeight = 0; // P&F window height (pixels), 0 = leave as is
input bool InpShowPrice = true; // Current price line
input group "=== Info panel (main window) ==="
input bool InpShowPanel = true; // Show panel
input ENUM_PANEL_POS InpPanelPos = PNL_LEFT_TOP; // Panel position
input ENUM_PANEL_MODE InpPanelMode = PMODE_FULL; // Initial mode (panel button: Full/Compact/Minimal)
input int InpPanelX = 12; // Horizontal margin (px)
input int InpPanelY = 28; // Vertical margin (px)
input color InpPanelBg = clrNavy; // Panel background color
input ENUM_SECTION_CLR InpSectionColor = SC_SKY; // Section title color
input int InpPanelRefreshMs = 250; // Panel refresh (ms)
input double InpPanelScale = 1.0; // Panel size (1.0 = normal, 1.5 = +50%, 2.0 = double)
input double InpTextScale = 1.0; // Text size (1.0 = normal, 1.3 = +30%, 1.6 = +60%)
input group "=== Entry signals ==="
input bool InpRequireHL = true; // Filter: higher low (BUY) / lower high (SELL)
input bool InpOnlyFlips = true; // Signal only when direction changes
input double InpRR = 1.5; // Risk/Reward ratio for TP
input int InpSLBuffer = 0; // SL buffer (points), 0 = auto (20% of box)
input bool InpShowPatterns = true; // Show P&F pattern names (P&F window)
input color InpPatternColor = clrWhite; // Pattern text color
input group "=== Risk management (panel + alerts) ==="
input double InpRiskPct = 1.0; // Risk per trade (% of balance) for lot size
input double InpMaxRiskPips = 0.0; // Warn: SL larger than (pips), 0 = auto (6 boxes)
input double InpMaxChasePips = 0.0; // Warn: price ran past breakout by (pips), 0 = auto (1 box)
input double InpMaxSpreadPips = 0.0; // Warn: spread larger than (pips), 0 = auto (0.3 box)
input group "=== Filters for cleaner signals ==="
input bool InpUseTrendMA = true; // Trend filter: BUY only above EMA, SELL only below EMA
input int InpMAPeriod = 200; // EMA period (on current timeframe)
input bool InpUseADX = true; // ADX filter: ignore sideways market
input int InpADXPeriod = 14; // ADX period
input double InpADXMin = 20.0; // Minimum ADX for a signal
input bool InpUseSession = true; // Session filter (server time)
input int InpStartHour = 9; // Start hour (server time)
input int InpEndHour = 21; // End hour (server time)
input group "=== Support / Resistance ==="
input int InpSRLookback = 40; // Number of columns analysed
input bool InpShowSRLines = true; // Draw R1/R2/S1/S2 lines + labels on the MAIN chart
input color InpResistColor = clrRed; // Resistance line color
input color InpSupportColor = C'0,150,60'; // Support line color
input color InpResistLabelBg = C'200,30,30'; // Resistance label background (red)
input color InpSupportLabelBg = C'0,150,60'; // Support label background (green)
input color InpSRLabelText = clrWhite; // Label text color
input int InpSRLineWidth = 3; // Line width (1-5)
input int InpSRLabelSize = 10; // Label font size
input int InpSRLabelRight = 8; // Label distance from the right edge (px)
input group "=== Alerts ==="
input bool InpAlertSignals = true; // Alert on BUY/SELL signal
input bool InpAlertPatterns = false; // Alert on pattern
input bool InpAlertColumn = false; // Alert on new column (X/O)
input bool InpAlertPopup = true; // Popup window
input bool InpAlertSound = false; // Sound
input string InpSoundFile = "alert.wav"; // Sound file
input bool InpAlertPush = false; // Push notification (mobile)
input bool InpAlertEmail = false; // E-mail
color SectionColor()
{
switch(InpSectionColor)
{
case SC_SKY: return C'80,210,255';
case SC_GOLD: return C'255,210,64';
case SC_ORANGE: return C'255,150,50';
case SC_LIME: return C'120,235,90';
case SC_AQUA: return C'0,230,230';
case SC_PINK: return C'255,140,190';
case SC_MAGENTA: return C'255,80,255';
case SC_VIOLET: return C'185,140,255';
case SC_SILVER: return C'200,200,210';
case SC_WHITE: return clrWhite;
}
return C'80,210,255';
}
#define PREFIX "PFB_" // objects in the P&F window
#define PNL "PFP_" // panel objects (main window)
#define SRL "PFSR_" // support/resistance lines + labels (main chart)
#define BLK_HL 1
#define BLK_EMA 2
#define BLK_ADX 4
#define BLK_SES 8
#define BLK_FLIP 16
#define P_W 470
#define P_H_FULL 420
#define P_H_COMP 234
#define P_H_MIN 82
#define P_X1 12
#define P_X2 242
#define P_CW 216
enum PV_SLOT
{
PV_HDR = 0, PV_BANNER, PV_STATUS, PV_VERDICT, PV_SUB,
PV_ENTRY, PV_SL, PV_TP, PV_RR, PV_LOT,
PV_EMA, PV_ADX, PV_SES, PV_SPR, PV_ATR,
PV_BOX, PV_COL, PV_EXT, PV_REV, PV_BOB, PV_BOS, PV_STR,
PV_R2, PV_R1, PV_S1, PV_S2,
PV_H0, PV_H1, PV_H2, PV_HR0, PV_HR1, PV_HR2,
PV_FL, PV_FR,
PV_COUNT
};
struct PFCol
{
int dir; // +1 = X, -1 = O
int top; // top box level
int bot; // bottom box level
int sig; // raw breakout: +1 buy, -1 sell, 0 none
int eff; // effective ENTRY signal (after filters)
int pat; // pattern (ENUM_PF_PATTERN)
int blk; // filters that blocked the breakout (BLK_*)
int trig; // index of the bar where the breakout happened (-1 = none)
int b0; // index of the bar where the column started
datetime t0; // time of the bar where the column started
datetime tTrig; // time of the breakout bar
double pTrig; // price level of the breakout
};
PFCol g_cols[];
int g_n = 0;
int g_boxPts = 50;
int g_boxAuto = 0; // last ATR-derived box (hysteresis)
double g_pip = 0.0001;
int g_hATR = INVALID_HANDLE; // ATR for the box (ATR mode)
int g_hATRc = INVALID_HANDLE; // ATR on the current timeframe (informative)
int g_hMA = INVALID_HANDLE;
int g_hADX = INVALID_HANDLE;
double g_sigBuf[];
double g_maBuf[];
double g_adxBuf[];
int g_fOff = 0; // index (non-series) of the first element of g_maBuf / g_adxBuf
double g_emaV = 0.0; // informative values for the panel
double g_adxV = 0.0;
double g_atrV = 0.0;
int g_rev = 3;
int g_W = 3;
int g_shift = 8;
int g_maxCols = 40;
int g_maxObj = 5000;
int g_hist = 3000;
double g_gap = 20.0;
int g_maP = 200;
int g_adxP = 14;
int g_srLook = 40;
int g_win = -1; // separate window of the indicator
string g_lastSig = "";
bool g_needRecalc = true;
int g_lastTotal = 0;
datetime g_lastBarT = 0;
int g_drawn = 0; // drawn columns
int g_subH = 0; // height (px) of the P&F window at the last redraw
bool g_hSet = false; // window height already applied
double g_lastPrice = 0.0;
double g_scLo = 0.0; // fixed vertical scale of the P&F window
double g_scHi = 0.0;
double g_res[];
double g_sup[];
int g_nr = 0;
int g_ns = 0;
bool g_firstRun = true;
string g_alSig = "";
string g_alPat = "";
string g_alCol = "";
string g_srKey = ""; // last drawn S/R state (avoids useless object updates)
bool g_panelBuilt = false;
bool g_chartDirty = false;
int g_pmode = 0;
double g_scale = 1.0;
int g_pcount = 0;
string g_pn[];
string g_pt[];
color g_pc[];
int g_pl[];
int g_pk[];
int g_px[];
int g_py[];
int g_pw[];
int g_ph[];
int g_v[PV_COUNT];
int g_bg = -1;
int g_btn = -1;
int g_cw = 0;
int g_chh = 0;
uint g_lastUiMs = 0;
string g_fT = "Arial Bold";
string g_fB = "Arial Bold";
string g_up, g_dn, g_dot, g_dia, g_mid;
int OnInit()
{
// код доступен только после оплаты
}
void OnDeinit(const int reason)
{
if(g_hATR != INVALID_HANDLE)
IndicatorRelease(g_hATR);
if(g_hATRc != INVALID_HANDLE)
IndicatorRelease(g_hATRc);
if(g_hMA != INVALID_HANDLE)
IndicatorRelease(g_hMA);
if(g_hADX != INVALID_HANDLE)
IndicatorRelease(g_hADX);
ObjectsDeleteAll(0, PREFIX);
ObjectsDeleteAll(0, PNL);
ObjectsDeleteAll(0, SRL);
ChartRedraw();
}
int Sc(const int v)
{
return (int)MathRound(v * g_scale);
}
int Fs(const int size)
{
return (int)MathMax(6, MathRound(size * MathMax(0.5, MathMin(3.0, InpTextScale))));
}
color Mix(const color a, const color b, const double t)
{
int ra = (int)a & 0xFF, ga = ((int)a >> 8) & 0xFF, ba = ((int)a >> 16) & 0xFF;
int rb = (int)b & 0xFF, gb = ((int)b >> 8) & 0xFF, bb = ((int)b >> 16) & 0xFF;
int r = (int)MathRound(ra + (rb - ra) * t);
int g = (int)MathRound(ga + (gb - ga) * t);
int bl = (int)MathRound(ba + (bb - ba) * t);
return (color)(r | (g << 8) | (bl << 16));
}
string Px(const double p)
{
return DoubleToString(p, _Digits);
}
string SP(const double pips)
{
double v = MathRound(pips * 10.0) / 10.0;
string s = (v >= 0.0) ? "+" : "-";
return s + DoubleToString(MathAbs(v), 1) + "p";
}
string TStr(const datetime t)
{
MqlDateTime d;
TimeToStruct(t, d);
return StringFormat("%02d.%02d %02d:%02d", d.day, d.mon, d.hour, d.min);
}
string TfName()
{
string s = EnumToString((ENUM_TIMEFRAMES)_Period);
return StringSubstr(s, 7); // strips "PERIOD_"
}
bool SessionApplies()
{
return (InpUseSession && PeriodSeconds() <= 14400);
}
bool InSession(const int hour)
{
if(InpStartHour == InpEndHour)
return true;
if(InpStartHour < InpEndHour)
return (hour >= InpStartHour && hour < InpEndHour);
return (hour >= InpStartHour || hour < InpEndHour);
}
int LotDigits()
{
double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
int d = 0;
if(st <= 0.0)
return 2;
while(d < 8 && MathAbs(st - MathRound(st)) > 1e-8)
{
st *= 10.0;
d++;
}
return d;
}
string AgeText(const int bars)
{
if(bars <= 0)
return "on current bar";
long sec = (long)bars * (long)PeriodSeconds();
string d;
if(sec < 7200)
d = IntegerToString(sec / 60) + " min";
else
if(sec < 172800)
d = DoubleToString((double)sec / 3600.0, 1) + " h";
else
d = DoubleToString((double)sec / 86400.0, 1) + " d";
return IntegerToString(bars) + (bars == 1 ? " bar" : " bars") + " ago (" + d + ")";
}
double BoxPips()
{
return g_boxPts * _Point / g_pip;
}
double MaxRiskP()
{
return (InpMaxRiskPips > 0.0) ? InpMaxRiskPips : 6.0 * BoxPips();
}
double MaxChaseP()
{
return (InpMaxChasePips > 0.0) ? InpMaxChasePips : 1.0 * BoxPips();
}
double MaxSpreadP()
{
return (InpMaxSpreadPips > 0.0) ? InpMaxSpreadPips : 0.3 * BoxPips();
}
double SLBufferPrice()
{
int pts = (InpSLBuffer > 0) ? InpSLBuffer : (int)MathMax(1, MathRound(0.2 * g_boxPts));
return pts * _Point;
}
int Level(const double price)
{
long pts = (long)MathRound(price / _Point);
return (int)MathFloor((double)pts / (double)g_boxPts);
}
int NiceBoxPts(const double rawPts)
{
double pipPts = g_pip / _Point;
double pips = rawPts / pipPts;
if(pips <= 0.0)
return 1;
double m[10] = {1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0};
double base = MathPow(10.0, MathFloor(MathLog10(pips)));
double mant = pips / base;
int best = 0;
double bd = DBL_MAX;
for(int i = 0; i < 10; i++)
{
double d = MathAbs(MathLog(mant / m[i]));
if(d < bd)
{
bd = d;
best = i;
}
}
return (int)MathMax(1, MathRound(m[best] * base * pipPts));
}
void AddCol(const int dir, const int bot, const int top, const int bar, const datetime t)
{
ArrayResize(g_cols, g_n + 1, 2048);
g_cols[g_n].dir = dir;
g_cols[g_n].bot = bot;
g_cols[g_n].top = top;
g_cols[g_n].sig = 0;
g_cols[g_n].eff = 0;
g_cols[g_n].pat = PAT_NONE;
g_cols[g_n].blk = 0;
g_cols[g_n].trig = -1;
g_cols[g_n].b0 = bar;
g_cols[g_n].t0 = t;
g_cols[g_n].tTrig = 0;
g_cols[g_n].pTrig = 0.0;
g_n++;
}
void BuildPF(const datetime &time[], const double &high[], const double &low[],
const double &close[], const int total, const int startRaw)
{
g_n = 0;
ArrayResize(g_cols, 0, 2048);
int lastBar = InpClosedOnly ? total - 2 : total - 1;
int start = startRaw;
if(start > 0)
{
int lim = MathMin(lastBar - 40, start + 1500);
for(int s = start; s <= lim; s++)
if((long)time[s] / 86400 != (long)time[s - 1] / 86400)
{
start = s;
break;
}
}
if(lastBar <= start)
return;
int rev = g_rev;
int base = Level(close[start]);
for(int i = start + 1; i <= lastBar; i++)
{
double h = (InpSource == PF_HIGHLOW) ? high[i] : close[i];
double l = (InpSource == PF_HIGHLOW) ? low[i] : close[i];
int hL = Level(h);
int lL = Level(l);
if(g_n == 0)
{
if(hL > base)
AddCol(1, base, hL, i, time[i]);
else
if(lL < base)
AddCol(-1, lL, base, i, time[i]);
continue;
}
int j = g_n - 1;
if(g_cols[j].dir == 1)
{
if(hL > g_cols[j].top)
g_cols[j].top = hL; // X extension
else
if(lL <= g_cols[j].top - rev)
AddCol(-1, lL, g_cols[j].top - 1, i, time[i]); // reversal -> O
}
else
{
if(lL < g_cols[j].bot)
g_cols[j].bot = lL; // O extension
else
if(hL >= g_cols[j].bot + rev)
AddCol(1, g_cols[j].bot + 1, hL, i, time[i]); // reversal -> X
}
j = g_n - 1;
if(j >= 2 && g_cols[j].trig < 0)
{
double bp = g_boxPts * _Point;
if(g_cols[j].dir == 1 && g_cols[j].top > g_cols[j - 2].top)
{
g_cols[j].trig = i;
g_cols[j].tTrig = time[i];
g_cols[j].pTrig = (g_cols[j - 2].top + 1) * bp;
}
else
if(g_cols[j].dir == -1 && g_cols[j].bot < g_cols[j - 2].bot)
{
g_cols[j].trig = i;
g_cols[j].tTrig = time[i];
g_cols[j].pTrig = g_cols[j - 2].bot * bp;
}
}
}
}
int FilterMask(const int dir, const int bar, const datetime &time[], const double &close[], const int total)
{
if(bar < 0 || bar >= total)
return (BLK_HL | BLK_EMA | BLK_ADX | BLK_SES);
int m = 0;
int ix = bar - g_fOff;
if(InpUseTrendMA && g_hMA != INVALID_HANDLE)
{
if(ix < 0 || ix >= ArraySize(g_maBuf))
m |= BLK_EMA;
else
{
if(dir > 0 && !(close[bar] > g_maBuf[ix]))
m |= BLK_EMA;
if(dir < 0 && !(close[bar] < g_maBuf[ix]))
m |= BLK_EMA;
}
}
if(InpUseADX && g_hADX != INVALID_HANDLE)
{
if(ix < 0 || ix >= ArraySize(g_adxBuf))
m |= BLK_ADX;
else
if(g_adxBuf[ix] < InpADXMin)
m |= BLK_ADX;
}
if(SessionApplies())
{
MqlDateTime dt;
TimeToStruct(time[bar], dt);
if(!InSession(dt.hour))
m |= BLK_SES;
}
return m;
}
void Analyze(const datetime &time[], const double &close[], const int total)
{
int lastSig = 0;
for(int j = 0; j < g_n; j++)
{
g_cols[j].sig = 0;
g_cols[j].eff = 0;
g_cols[j].pat = PAT_NONE;
g_cols[j].blk = 0;
if(j >= 2)
{
if(g_cols[j].dir == 1 && g_cols[j].top > g_cols[j - 2].top)
{
g_cols[j].sig = 1;
g_cols[j].pat = PAT_DTB;
if(j >= 4 && g_cols[j - 2].top == g_cols[j - 4].top)
g_cols[j].pat = PAT_TTB;
if(g_cols[j - 2].pat == PAT_TTB && g_cols[j - 1].bot >= g_cols[j - 4].top)
g_cols[j].pat = PAT_BULL_CAT;
}
else
if(g_cols[j].dir == -1 && g_cols[j].bot < g_cols[j - 2].bot)
{
g_cols[j].sig = -1;
g_cols[j].pat = PAT_DBB;
if(j >= 4 && g_cols[j - 2].bot == g_cols[j - 4].bot)
g_cols[j].pat = PAT_TBB;
if(g_cols[j - 2].pat == PAT_TBB && g_cols[j - 1].top <= g_cols[j - 4].bot)
g_cols[j].pat = PAT_BEAR_CAT;
}
}
if(g_cols[j].pat == PAT_NONE && j >= 4)
{
bool tri = true;
int lt = INT_MAX, lb = INT_MIN;
for(int k = j - 4; k <= j; k++)
{
if(g_cols[k].dir == 1)
{
if(g_cols[k].top >= lt) { tri = false; break; }
lt = g_cols[k].top;
}
else
{
if(g_cols[k].bot <= lb) { tri = false; break; }
lb = g_cols[k].bot;
}
}
if(tri)
g_cols[j].pat = PAT_TRIANGLE;
}
if(g_cols[j].sig != 0)
{
int sg = g_cols[j].sig;
int blk = 0;
if(InpRequireHL)
{
bool okHL;
if(j < 3)
okHL = false;
else
if(sg == 1)
okHL = (g_cols[j - 1].bot > g_cols[j - 3].bot); // pullback with a higher low
else
okHL = (g_cols[j - 1].top < g_cols[j - 3].top); // pullback with a lower high
if(!okHL)
blk |= BLK_HL;
}
blk |= FilterMask(sg, g_cols[j].trig, time, close, total);
if(blk == 0)
{
if(InpOnlyFlips && sg == lastSig)
blk = BLK_FLIP;
else
g_cols[j].eff = sg;
lastSig = sg;
}
g_cols[j].blk = blk;
}
}
}
string PatShort(const int p)
{
switch(p)
{
case PAT_DTB: return "Double top breakout";
case PAT_DBB: return "Double bottom breakdown";
case PAT_TTB: return "Triple top breakout";
case PAT_TBB: return "Triple bottom breakdown";
case PAT_BULL_CAT: return "Bullish catapult";
case PAT_BEAR_CAT: return "Bearish catapult";
case PAT_TRIANGLE: return "Triangle";
}
return "";
}
string PatName(const int p)
{
switch(p)
{
case PAT_DTB:
case PAT_TTB:
case PAT_BULL_CAT: return PatShort(p) + " (BUY)";
case PAT_DBB:
case PAT_TBB:
case PAT_BEAR_CAT: return PatShort(p) + " (SELL)";
case PAT_TRIANGLE: return PatShort(p) + " (neutral)";
}
return "";
}
void JoinAdd(string &r, const string s)
{
if(r != "")
r += ", ";
r += s;
}
string BlkText(const int m)
{
string r = "";
if((m & BLK_HL) != 0) JoinAdd(r, "structure (higher low / lower high)");
if((m & BLK_EMA) != 0) JoinAdd(r, "EMA");
if((m & BLK_ADX) != 0) JoinAdd(r, "ADX");
if((m & BLK_SES) != 0) JoinAdd(r, "session");
if((m & BLK_FLIP) != 0) JoinAdd(r, "same direction as previous signal");
if(r == "")
r = "-";
return r;
}
datetime SlotTime(const datetime &time[], const int total, const int idx)
{
long ps = (long)PeriodSeconds();
int last = total - 1;
if(idx < 0)
return (datetime)((long)time[0] + (long)idx * ps);
if(idx <= last)
return time[idx];
return (datetime)((long)time[last] + (long)(idx - last) * ps);
}
datetime SlotTimeF(const datetime &time[], const int total, const double idx)
{
double fl = MathFloor(idx);
int i0 = (int)fl;
double fr = idx - fl;
long t = (long)SlotTime(time, total, i0);
if(fr > 0.0)
{
t += (long)MathRound(fr * (double)PeriodSeconds());
if(i0 >= 0 && i0 < total - 1)
{
long tn = (long)time[i0 + 1];
if(t >= tn)
t = tn - 1; // never cross into the next bar (e.g. short months on MN1)
}
}
return (datetime)t;
}
double CalcLot(const double riskDist, double &riskMoney)
{
riskMoney = 0.0;
double bal = AccountInfoDouble(ACCOUNT_BALANCE);
if(bal <= 0.0 || InpRiskPct <= 0.0 || riskDist <= 0.0)
return 0.0;
riskMoney = bal * InpRiskPct / 100.0;
double tv = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_LOSS);
if(tv <= 0.0)
tv = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double ts = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(tv <= 0.0 || ts <= 0.0)
return 0.0;
double lossPerLot = riskDist / ts * tv;
if(lossPerLot <= 0.0)
return 0.0;
double lot = riskMoney / lossPerLot;
double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double mx = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
if(st > 0.0)
lot = MathFloor(lot / st + 1e-9) * st;
if(lot < mn)
return 0.0;
if(mx > 0.0 && lot > mx)
lot = mx;
return NormalizeDouble(lot, LotDigits());
}
bool Plan(const int j, const double bid, const double ask,
double &entry, double &sl, double &tp, double &riskP, double &lot, double &riskMoney)
{
if(j < 1 || j >= g_n || g_cols[j].eff == 0)
return false;
bool buy = (g_cols[j].eff > 0);
double bp = g_boxPts * _Point;
double buf = SLBufferPrice();
entry = buy ? ask : bid;
sl = buy ? g_cols[j - 1].bot * bp - buf
: (g_cols[j - 1].top + 1) * bp + buf;
double risk = MathAbs(entry - sl);
if(risk <= 0.0)
return false;
tp = buy ? entry + risk * InpRR : entry - risk * InpRR;
sl = NormalizeDouble(sl, _Digits);
tp = NormalizeDouble(tp, _Digits);
riskP = risk / g_pip;
lot = CalcLot(risk, riskMoney);
return true;
}
void AddUnique(double &arr[], int &n, const double v, const double tol)
{
for(int i = 0; i < n; i++)
if(MathAbs(arr[i] - v) < tol * 0.5)
return;
ArrayResize(arr, n + 1);
arr[n] = v;
n++;
}
void CalcSR(const double cur)
{
g_nr = 0;
g_ns = 0;
if(g_n < 1)
return;
double bp = g_boxPts * _Point;
double r[];
double s[];
int nr = 0, ns = 0;
ArrayResize(r, 0);
ArrayResize(s, 0);
int from = MathMax(0, g_n - g_srLook);
for(int j = from; j < g_n; j++)
{
if(g_cols[j].dir == 1)
{
double p = (g_cols[j].top + 1) * bp; // upper edge of the highest X
if(p > cur)
AddUnique(r, nr, p, bp);
}
else
{
double p = g_cols[j].bot * bp; // lower edge of the lowest O
if(p < cur)
AddUnique(s, ns, p, bp);
}
}
if(nr > 1) ArraySort(r);
if(ns > 1) ArraySort(s);
g_nr = MathMin(2, nr);
g_ns = MathMin(2, ns);
ArrayResize(g_res, g_nr);
ArrayResize(g_sup, g_ns);
for(int q = 0; q < g_nr; q++)
g_res[q] = r[q]; // nearest resistance first
for(int q2 = 0; q2 < g_ns; q2++)
g_sup[q2] = s[ns - 1 - q2]; // nearest support first
}
void DrawRect(const string name, datetime t1, double p1, datetime t2, double p2,
color clr, bool fill = true, int width = 1)
{
if(!ObjectCreate(0, name, OBJ_RECTANGLE, g_win, t1, p1, t2, p2))
return;
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FILL, fill);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
void DrawText(const string name, datetime t, double p, const string txt, color clr,
ENUM_ANCHOR_POINT anchor, int size = 8)
{
if(!ObjectCreate(0, name, OBJ_TEXT, g_win, t, p))
return;
ObjectSetString(0, name, OBJPROP_TEXT, txt);
ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold");
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, anchor);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
void DrawPriceLine(const string name, datetime t1, datetime t2, double p, color clr, const string txt)
{
if(ObjectCreate(0, name, OBJ_TREND, g_win, t1, p, t2, p))
{
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
DrawText(name + "_t", t1, p, txt, clr, ANCHOR_LEFT_LOWER, 8);
}
void UpdatePriceLine(const double p)
{
if(!InpShowPrice || g_win < 0)
return;
if(MathAbs(p - g_lastPrice) < _Point * 0.5)
return;
if(ObjectFind(0, PREFIX + "PRICE") < 0)
return;
double bp = g_boxPts * _Point;
if(g_scHi > g_scLo && (p < g_scLo + bp || p > g_scHi - bp))
{
g_lastSig = "";
g_needRecalc = true;
return;
}
ObjectSetDouble(0, PREFIX + "PRICE", OBJPROP_PRICE, 0, p);
ObjectSetDouble(0, PREFIX + "PRICE", OBJPROP_PRICE, 1, p);
ObjectSetDouble(0, PREFIX + "PRICE_t", OBJPROP_PRICE, p);
ObjectSetString(0, PREFIX + "PRICE_t", OBJPROP_TEXT, Px(p));
g_lastPrice = p;
g_chartDirty = true;
}
void SetSRObject(const string nm, const double price, const color clr, const string txt, const datetime t)
{
int w = (int)MathMax(1, MathMin(5, InpSRLineWidth));
if(ObjectFind(0, nm) < 0)
{
if(!ObjectCreate(0, nm, OBJ_HLINE, 0, 0, price))
return;
ObjectSetInteger(0, nm, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, nm, OBJPROP_BACK, true); // behind the candles
ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, nm, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, nm, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
}
ObjectSetInteger(0, nm, OBJPROP_COLOR, clr);
ObjectSetInteger(0, nm, OBJPROP_WIDTH, w);
ObjectSetDouble(0, nm, OBJPROP_PRICE, 0, price);
string tn = nm + "_t";
bool isRes = (StringFind(nm, "_R") >= 0);
if(ObjectFind(0, tn) < 0)
{
if(!ObjectCreate(0, tn, OBJ_EDIT, 0, 0, 0))
return;
ObjectSetString(0, tn, OBJPROP_FONT, "Arial Bold");
ObjectSetInteger(0, tn, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, tn, OBJPROP_ALIGN, ALIGN_CENTER);
ObjectSetInteger(0, tn, OBJPROP_READONLY, true);
ObjectSetInteger(0, tn, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, tn, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, tn, OBJPROP_BACK, false);
ObjectSetInteger(0, tn, OBJPROP_ZORDER, 10);
ObjectSetInteger(0, tn, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
}
color bg = isRes ? InpResistLabelBg : InpSupportLabelBg;
ObjectSetInteger(0, tn, OBJPROP_FONTSIZE, (int)MathMax(6, InpSRLabelSize));
ObjectSetInteger(0, tn, OBJPROP_COLOR, InpSRLabelText);
ObjectSetInteger(0, tn, OBJPROP_BGCOLOR, bg);
ObjectSetInteger(0, tn, OBJPROP_BORDER_COLOR, bg);
ObjectSetString(0, tn, OBJPROP_TEXT, txt);
}
void PlaceSRLabels()
{
if(!InpShowSRLines)
return;
double pmax = ChartGetDouble(0, CHART_PRICE_MAX, 0);
double pmin = ChartGetDouble(0, CHART_PRICE_MIN, 0);
int cw = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
int ch = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
if(pmax <= pmin || cw <= 0 || ch <= 0)
return;
double dp = (double)TerminalInfoInteger(TERMINAL_SCREEN_DPI);
dp = (dp >= 96.0) ? MathMin(3.0, dp / 96.0) : 1.0; // DPI only (not the panel scale input)
int fs = (int)MathMax(6, InpSRLabelSize);
int boxH = (int)MathRound((fs * 2 + 6) * dp);
int right = cw - (int)MathRound(MathMax(0, InpSRLabelRight) * dp);
if(ChartGetInteger(0, CHART_SHOW_PRICE_SCALE) != 0)
right -= (iПоказано первые 50% кода (символов: 47985)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.