Double Tap 3D [Neblok]
Похожие материалы по тегам
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «doubletap3d.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Индикатор MetaTrader 5 для обнаружения паттернов «двойная вершина» и «двойная впадина» на ценовом графике. Выполняет расчёт качества каждого найденного паттерна, отображает зоны с эффектом 3D-выпуклости, отслеживает состояние паттернов от формирования до завершения и показывает уровни TP/SL. Включает информационную панель с статистикой по сделкам и поддержку уведомлений (всплывающее окно, push, e-mail).
Настройки программы
| Настройка | Описание |
|---|---|
| Detect Double Tops (InpShowTops) | Обнаружение двойных вершин — Включает или отключает поиск паттернов двойной вершины |
| Detect Double Bottoms (InpShowBots) | Обнаружение двойных впадин — Включает или отключает поиск паттернов двойной впадины |
| Pivot Left Bars (InpPivLeft) | Бары слева пивота — Количество баров слева от точки для подтверждения пивота |
| Pivot Right Bars (confirmation; no repaint) (InpPivRight) | Бары справа пивота — Количество баров справа от точки для подтверждения пивота (без перерисовки) |
| Peak Match Tolerance (x ATR) (InpTolAtr) | Допуск совпадения пиков — Допустимое отклонение высоты пиков в кратных ATR |
| Min Bars Between Peaks (InpMinSpan) | Минимум баров между пиками — Минимальное расстояние в барах между двумя пиками паттерна |
| Max Bars Between Peaks (InpMaxSpan) | Максимум баров между пиками — Максимальное расстояние в барах между двумя пиками паттерна |
| Min Pattern Height (x ATR) (InpMinHeightAtr) | Минимальная высота паттерна — Минимальная высота паттерна в кратных ATR |
| Bars Allowed to Break Neckline (InpExpiryBars) | Бары до разрыва линии шеи — Максимальное количество баров, в течение которых допускается разрыв линии шеи |
| Prior Trend Lookback (InpPriorLook) | Откат для предшествующего движения — Глубина отката назад для определения движения перед первым пиком |
| ATR Length (InpAtrLen) | Длина ATR — Период расчёта среднеквадратичного диапазона |
| Max history bars to scan (performance) (InpMaxBars) | Максимум баров для сканирования — Ограничение глубины истории для сканирования (производительность) |
| Min Quality Score for Signals (0-100) (InpMinScore) | Минимальный балл качества — Минимальный балл от 0 до 100 для формирования сигналов |
| Draw Patterns Below Min Score (InpShowLowQ) | Отображение слабых паттернов — Рисовать паттерны с баллом ниже минимального порога |
| RSI Length (Divergence) (InpRsiLen) | Длина RSI — Период расчёта RSI для определения дивергенции |
| Trend Filter: Signal Only With EMA (InpUseTrend) | Фильтр тренда по EMA — Разрешать сигналы только при условии цены относительно EMA |
| Trend EMA Length (InpEmaLen) | Длина EMA фильтра — Период экспоненциальной скользящей средней для фильтра тренда |
| Require Volume Surge on Break (InpUseVolBrk) | Требовать всплеск объёма — Требовать увеличение объёма при пробое линии шеи |
| Break Volume >= x 20-Bar Avg (InpVolMult) | Множитель объёма — Пробной объём должен быть не менее этого множителя от среднего за 20 баров |
| Stop Buffer Beyond Peaks (x ATR) (InpSlBufAtr) | Буфер стопа за пиками — Отступ стопа за линию пиков в кратных ATR |
| TP1 (x Pattern Height) (InpTp1Mult) | Множитель TP1 — Множитель высоты паттерна для первого уровня прибыли |
| TP2 (x Pattern Height) (InpTp2Mult) | Множитель TP2 — Множитель высоты паттерна для второго уровня прибыли |
| Show TP / SL Lines (InpShowTargets) | Отображение TP/SL — Показывать линии уровней Take Profit и Stop Loss |
| LONG Signals (Double Bottoms) (InpSigLong) | Сигналы LONG — Генерировать сигналы на покупку при двойных впадинах |
| SHORT Signals (Double Tops) (InpSigShort) | Сигналы SHORT — Генерировать сигналы на продажу при двойных вершинах |
| Track Stop at Breakeven After TP1 (InpMoveBE) | Безубыток после TP1 — Перемещать стоп в точку входа после достижения TP1 |
| Double Top (InpColTop) | Цвет двойной вершины — Цвет линий и зон для паттернов двойной вершины |
| Double Bottom (InpColBot) | Цвет двойной впадины — Цвет линий и зон для паттернов двойной впадины |
| Success (InpColWin) | Цвет успешного исхода — Цвет индикации успешного завершения паттерна |
| Failed / SL (InpColLoss) | Цвет неудачного исхода — Цвет индикации неудачного завершения или срабатывания стопа |
Поиск по коду файла
#property version "1.00"
#property description "Double Top / Double Bottom detection with quality scoring,"
#property description "measured-move targets, signals, outcome tracking, stats dashboard, 3D zones."
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_label1 "Trend EMA"
#property indicator_type1 DRAW_LINE
#property indicator_color1 C'188,19,254'
#property indicator_width1 2
enum ENUM_SZ { SZ_NORMAL = 0, // Normal
SZ_LARGE = 1, // Large
SZ_HUGE = 2 // Huge
};
enum ENUM_DPOS { DP_TR = 0, // Top Right
DP_TL = 1, // Top Left
DP_BR = 2, // Bottom Right
DP_BL = 3 // Bottom Left
};
input group "① Detection"
input bool InpShowTops = true; // Detect Double Tops
input bool InpShowBots = true; // Detect Double Bottoms
input int InpPivLeft = 8; // Pivot Left Bars
input int InpPivRight = 5; // Pivot Right Bars (confirmation; no repaint)
input double InpTolAtr = 0.75; // Peak Match Tolerance (x ATR)
input int InpMinSpan = 10; // Min Bars Between Peaks
input int InpMaxSpan = 150; // Max Bars Between Peaks
input double InpMinHeightAtr = 1.5; // Min Pattern Height (x ATR)
input int InpExpiryBars = 60; // Bars Allowed to Break Neckline
input int InpPriorLook = 60; // Prior Trend Lookback
input int InpAtrLen = 14; // ATR Length
input int InpMaxBars = 2000; // Max history bars to scan (performance)
input group "② Quality & Filters"
input int InpMinScore = 50; // Min Quality Score for Signals (0-100)
input bool InpShowLowQ = true; // Draw Patterns Below Min Score
input int InpRsiLen = 14; // RSI Length (Divergence)
input bool InpUseTrend = false; // Trend Filter: Signal Only With EMA
input int InpEmaLen = 200; // Trend EMA Length
input bool InpUseVolBrk = false; // Require Volume Surge on Break
input double InpVolMult = 1.5; // Break Volume >= x 20-Bar Avg
input group "③ Targets & Risk"
input double InpSlBufAtr = 0.25; // Stop Buffer Beyond Peaks (x ATR)
input double InpTp1Mult = 1.0; // TP1 (x Pattern Height)
input double InpTp2Mult = 1.618; // TP2 (x Pattern Height)
input bool InpShowTargets = true; // Show TP / SL Lines
input group "④ Signals"
input bool InpSigLong = true; // LONG Signals (Double Bottoms)
input bool InpSigShort = true; // SHORT Signals (Double Tops)
input bool InpMoveBE = true; // Track Stop at Breakeven After TP1
input group "⑤ Visuals"
input color InpColTop = C'255,32,121'; // Double Top
input color InpColBot = C'0,240,255'; // Double Bottom
input color InpColWin = C'57,255,20'; // Success
input color InpColLoss = C'255,95,31'; // Failed / SL
input color InpColTP = C'255,240,31'; // Targets
input color InpColNeck = C'188,19,254'; // Neckline
input bool InpUse3D = true; // 3D Extruded Zones & Shadowed Legs
input int InpDepthBars = 4; // 3D Depth (Bars)
input double InpDepthAtr = 0.6; // 3D Depth (x ATR)
input ENUM_SZ InpLblSize = SZ_LARGE; // Label Size
input int InpLineW = 3; // Pattern Line Width
input int InpMaxHist = 5; // Completed Patterns to Keep
input bool InpKeepTags = false; // Keep TP / SL Tags on Finished Patterns
input group "⑥ Dashboard"
input bool InpShowDash = true; // Show Dashboard
input ENUM_DPOS InpDashPos = DP_BL; // Position
input ENUM_SZ InpDashSize = SZ_LARGE; // Text Size
input group "⑦ Continuation & Flip Zones (RBS / SBR)"
input bool InpShowCont = true; // Show Bullish / Bearish Continuation tags
input bool InpShowFlip = true; // Show RBS / SBR zones
input int InpContMaxGap = 150; // Continuation: max bars between the two patterns
input int InpFlipMaxGap = 200; // RBS/SBR: max bars from flip to new pattern break
input double InpFlipTolAtr = 1.0; // RBS/SBR: new peaks within (x ATR) of old zone
input color InpColCont = C'0,200,120'; // Continuation tag color
input color InpColFlip = C'255,165,0'; // RBS / SBR zone color
input group "⑧ Alerts"
input bool InpAlertPopup = true; // Popup alert
input bool InpAlertPush = false; // Push notification
input bool InpAlertMail = false; // E-mail
#define PFX "DT3D_"
#define PIVOT_MEMORY 6
struct Pivot
{
int x;
double p;
double r;
double v;
};
struct Pattern
{
int id;
int dir; // -1 double top, +1 double bottom
int x0; double p0;
int x1; double p1;
int xn; double neck;
int x2; double p2;
double height, stop, tp1, tp2, atrV;
int score;
string grade;
string notes;
int state; // 0 forming, 1 active, 2 success, 3 failed, 5 timed out
int xb; double pb;
int xEnd;
bool tp1Hit, tp2Hit, signal, beMoved;
string brkTxt;
double brkPrice;
bool drawn;
string contTag; // "BULLISH CONT." / "BEARISH CONT." / ""
string flipTag; // "RBS" / "SBR" / ""
int zX; // flip zone start bar
double zT, zB; // flip zone top / bottom
};
struct HRec
{
int dir;
int x1, x2, xb;
double top, bot; // peak band of the pattern
double neck, stop, atrV;
bool success; // broke the neckline and reached at least TP1
bool failed; // stop hit / invalidated
int xFail;
bool flipped; // close beyond stop level within FLIP_WINDOW bars of failing
int xFlip;
};
#define FLIP_WINDOW 10
Pivot pHighs[], pLows[];
Pattern live[], done[];
HRec hist[];
int stats[12];
int g_total = 0;
int g_last = -1;
int g_nextId = 0;
string g_alertMsg = "";
string g_tf = "";
datetime g_time[];
double g_high[], g_low[], g_close[], g_vol[];
double g_tr[], g_atr[], g_gain[], g_loss[], g_ag[], g_al[], g_rsi[], g_ema[], g_volAvg[];
double EmaBuf[];
template<typename T>
void RemoveAt(T &arr[], const int idx)
{
int n = ArraySize(arr);
if(idx < 0 || idx >= n) return;
for(int k = idx; k < n - 1; k++) arr[k] = arr[k + 1];
ArrayResize(arr, n - 1);
}
color Mix(const color c, const color bg, const int transp)
{
int r1 = c & 0xFF, g1 = (c >> 8) & 0xFF, b1 = (c >> 16) & 0xFF;
int r2 = bg & 0xFF, g2 = (bg >> 8) & 0xFF, b2 = (bg >> 16) & 0xFF;
int r = (r1 * (100 - transp) + r2 * transp) / 100;
int g = (g1 * (100 - transp) + g2 * transp) / 100;
int b = (b1 * (100 - transp) + b2 * transp) / 100;
return (color)(r | (g << 8) | (b << 16));
}
int FontSz(const ENUM_SZ s)
{
if(s == SZ_NORMAL) return 9;
if(s == SZ_HUGE) return 15;
return 11;
}
datetime TimeAt(const int idx)
{
if(idx < g_total) return g_time[MathMax(idx, 0)];
return g_time[g_total - 1] + (datetime)((idx - g_total + 1) * PeriodSeconds());
}
string Px(const double v) { return DoubleToString(v, _Digits); }
void Bump(const int dir, const int m) { stats[(dir == -1 ? 0 : 6) + m]++; }
int Stat(const int dir, const int m) { return stats[(dir == -1 ? 0 : 6) + m]; }
void Prep(const string n, const bool back)
{
ObjectSetInteger(0, n, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, n, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, n, OBJPROP_BACK, back);
}
void Trend(const string n, const int xa, const double ya, const int xb, const double yb,
const color c, const int w, const ENUM_LINE_STYLE st)
{
ObjectCreate(0, n, OBJ_TREND, 0, TimeAt(xa), ya, TimeAt(xb), yb);
ObjectSetInteger(0, n, OBJPROP_COLOR, c);
ObjectSetInteger(0, n, OBJPROP_WIDTH, st == STYLE_SOLID ? w : 1); // MT5 only draws styles at width 1
ObjectSetInteger(0, n, OBJPROP_STYLE, st);
ObjectSetInteger(0, n, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, n, OBJPROP_RAY_LEFT, false);
Prep(n, false);
}
void Rect(const string n, const int xa, const double ya, const int xb, const double yb,
const color c, const bool fill, const int w)
{
ObjectCreate(0, n, OBJ_RECTANGLE, 0, TimeAt(xa), ya, TimeAt(xb), yb);
ObjectSetInteger(0, n, OBJPROP_COLOR, c);
ObjectSetInteger(0, n, OBJPROP_FILL, fill);
ObjectSetInteger(0, n, OBJPROP_WIDTH, w);
Prep(n, fill);
}
void Tri(const string n, const int x1, const double y1, const int x2, const double y2,
const int x3, const double y3, const color c)
{
ObjectCreate(0, n, OBJ_TRIANGLE, 0, TimeAt(x1), y1, TimeAt(x2), y2, TimeAt(x3), y3);
ObjectSetInteger(0, n, OBJPROP_COLOR, c);
ObjectSetInteger(0, n, OBJPROP_FILL, true);
Prep(n, true);
}
void Txt(const string n, const int x, const double y, const string t, const color c,
const int fs, const ENUM_ANCHOR_POINT a, const string tip = "")
{
ObjectCreate(0, n, OBJ_TEXT, 0, TimeAt(x), y);
ObjectSetString(0, n, OBJPROP_TEXT, t);
ObjectSetString(0, n, OBJPROP_FONT, "Arial Bold");
ObjectSetInteger(0, n, OBJPROP_FONTSIZE, fs);
ObjectSetInteger(0, n, OBJPROP_COLOR, c);
ObjectSetInteger(0, n, OBJPROP_ANCHOR, a);
if(tip != "") ObjectSetString(0, n, OBJPROP_TOOLTIP, tip);
Prep(n, false);
}
void Compute(const int from, const int n)
{
for(int i = from; i < n; i++)
{
double tr = (i == 0) ? g_high[0] - g_low[0]
: MathMax(g_high[i] - g_low[i],
MathMax(MathAbs(g_high[i] - g_close[i - 1]),
MathAbs(g_low[i] - g_close[i - 1])));
g_tr[i] = tr;
if(i < InpAtrLen - 1) g_atr[i] = 0.0;
else if(i == InpAtrLen - 1)
{
double s = 0; for(int k = 0; k <= i; k++) s += g_tr[k];
g_atr[i] = s / InpAtrLen;
}
else g_atr[i] = (g_atr[i - 1] * (InpAtrLen - 1) + tr) / InpAtrLen;
if(i == 0) { g_gain[0] = 0; g_loss[0] = 0; }
else
{
double ch = g_close[i] - g_close[i - 1];
g_gain[i] = MathMax(ch, 0.0);
g_loss[i] = MathMax(-ch, 0.0);
}
if(i < InpRsiLen) { g_ag[i] = 0; g_al[i] = 0; g_rsi[i] = 50.0; }
else
{
if(i == InpRsiLen)
{
double sg = 0, sl = 0;
for(int k = 1; k <= InpRsiLen; k++) { sg += g_gain[k]; sl += g_loss[k]; }
g_ag[i] = sg / InpRsiLen; g_al[i] = sl / InpRsiLen;
}
else
{
g_ag[i] = (g_ag[i - 1] * (InpRsiLen - 1) + g_gain[i]) / InpRsiLen;
g_al[i] = (g_al[i - 1] * (InpRsiLen - 1) + g_loss[i]) / InpRsiLen;
}
if(g_al[i] == 0) g_rsi[i] = 100.0;
else if(g_ag[i] == 0) g_rsi[i] = 0.0;
else g_rsi[i] = 100.0 - 100.0 / (1.0 + g_ag[i] / g_al[i]);
}
if(i < InpEmaLen - 1) g_ema[i] = 0.0;
else if(i == InpEmaLen - 1)
{
double s = 0; for(int k = 0; k <= i; k++) s += g_close[k];
g_ema[i] = s / InpEmaLen;
}
else
{
double a = 2.0 / (InpEmaLen + 1.0);
g_ema[i] = g_ema[i - 1] + a * (g_close[i] - g_ema[i - 1]);
}
if(i < 19) g_volAvg[i] = 0.0;
else { double s = 0; for(int k = i - 19; k <= i; k++) s += g_vol[k]; g_volAvg[i] = s / 20.0; }
}
}
bool PivHigh(const int cur, double &val)
{
int p = cur - InpPivRight;
if(p - InpPivLeft < 0) return false;
double v = g_high[p];
for(int k = 1; k <= InpPivLeft; k++) if(g_high[p - k] > v) return false;
for(int k = 1; k <= InpPivRight; k++) if(g_high[p + k] >= v) return false;
val = v; return true;
}
bool PivLow(const int cur, double &val)
{
int p = cur - InpPivRight;
if(p - InpPivLeft < 0) return false;
double v = g_low[p];
for(int k = 1; k <= InpPivLeft; k++) if(g_low[p - k] < v) return false;
for(int k = 1; k <= InpPivRight; k++) if(g_low[p + k] <= v) return false;
val = v; return true;
}
int Score(const int dir, Pivot &a, Pivot &b, const int xn, const double h,
const double priorMove, const double atrV, string ¬es)
{
double matchPct = MathMax(0.0, 1.0 - MathAbs(b.p - a.p) / (InpTolAtr * atrV));
bool rsiDiv = (dir == -1) ? (b.r < a.r) : (b.r > a.r);
bool volKnown = (a.v > 0 && b.v > 0);
bool volDiv = volKnown && (b.v < a.v);
double l1 = xn - a.x;
double l2 = b.x - xn;
double sym = MathMin(l1, l2) / MathMax(MathMax(l1, l2), 1.0);
double trendRatio = MathMin(1.0, priorMove / MathMax(h, _Point));
double s1 = 25.0 * matchPct;
double s2 = rsiDiv ? 20.0 : 0.0;
double s3 = volKnown ? (volDiv ? 15.0 : 0.0) : 7.5;
double s4 = 15.0 * MathMin(1.0, h / (3.0 * atrV));
double s5 = 10.0 * sym;
double s6 = 15.0 * trendRatio;
int score = (int)MathRound(s1 + s2 + s3 + s4 + s5 + s6);
notes = "Peak match: " + DoubleToString(matchPct * 100, 0) + "%";
notes += "\nRSI divergence: " + (rsiDiv ? "YES" : "no");
notes += "\nVolume divergence: " + (volKnown ? (volDiv ? "YES" : "no") : "n/a");
notes += "\nHeight: " + DoubleToString(h / atrV, 1) + " x ATR";
notes += "\nSymmetry: " + DoubleToString(sym * 100, 0) + "%";
notes += "\nPrior trend: " + DoubleToString(trendRatio * 100, 0) + "% of height";
return score;
}
bool Detect(const int dir, Pivot &b, Pivot &piv[], const int cur, Pattern &res)
{
int n = ArraySize(piv);
double atr = g_atr[cur];
if(n <= 0 || atr <= 0) return false;
for(int k = n - 1; k >= 0; k--)
{
Pivot a = piv[k];
int span = b.x - a.x;
if(span > InpMaxSpan) break;
if(span >= InpMinSpan && MathAbs(b.p - a.p) <= InpTolAtr * atr)
{
double neck = 0, rim = 0;
bool haveNeck = false, haveRim = false;
int xn = a.x + 1;
for(int x = b.x - 1; x >= a.x + 1; x--)
{
if(dir == -1)
{
if(!haveNeck || g_low[x] < neck) { neck = g_low[x]; xn = x; haveNeck = true; }
rim = haveRim ? MathMax(rim, g_high[x]) : g_high[x];
}
else
{
if(!haveNeck || g_high[x] > neck) { neck = g_high[x]; xn = x; haveNeck = true; }
rim = haveRim ? MathMin(rim, g_low[x]) : g_low[x];
}
haveRim = true;
}
if(!haveNeck) continue;
double ext = (dir == -1) ? MathMax(a.p, b.p) : MathMin(a.p, b.p);
bool clean = (dir == -1) ? (rim <= ext) : (rim >= ext);
if(!clean) break; // a higher high / lower low sits between: older pivots can't qualify
double h = MathAbs(ext - neck);
if(h >= InpMinHeightAtr * atr)
{
double pr = 0; bool havePr = false; int xp = a.x;
int endX = MathMax(a.x - InpPriorLook, 0);
for(int x = a.x - 1; x >= endX; x--)
{
if(dir == -1) { if(!havePr || g_low[x] < pr) { pr = g_low[x]; xp = x; havePr = true; } }
else { if(!havePr || g_high[x] > pr) { pr = g_high[x]; xp = x; havePr = true; } }
}
double p0 = havePr ? pr : a.p;
double priorMove = (dir == -1) ? MathMax(0.0, a.p - p0) : MathMax(0.0, p0 - a.p);
string notes;
int sc = Score(dir, a, b, xn, h, priorMove, atr, notes);
res.id = 0; res.dir = dir;
res.x0 = xp; res.p0 = p0;
res.x1 = a.x; res.p1 = a.p;
res.xn = xn; res.neck = neck;
res.x2 = b.x; res.p2 = b.p;
res.height = h;
res.stop = (dir == -1) ? ext + InpSlBufAtr * atr : ext - InpSlBufAtr * atr;
res.tp1 = (dir == -1) ? neck - h * InpTp1Mult : neck + h * InpTp1Mult;
res.tp2 = (dir == -1) ? neck - h * InpTp2Mult : neck + h * InpTp2Mult;
res.atrV = atr;
res.score = sc;
res.grade = sc >= 75 ? "A" : sc >= 55 ? "B" : "C";
res.notes = notes;
res.state = 0;
res.xb = 0; res.pb = 0;
res.xEnd = cur;
res.tp1Hit = false; res.tp2Hit = false; res.signal = false; res.beMoved = false;
res.brkTxt = ""; res.brkPrice = 0;
res.drawn = false;
res.contTag = ""; res.flipTag = "";
res.zX = 0; res.zT = 0; res.zB = 0;
return true;
}
}
}
return false;
}
color ColorOf(const Pattern &pt)
{
if(pt.state == 2) return InpColWin;
if(pt.state == 3) return InpColLoss;
return pt.dir == -1 ? InpColTop : InpColBot;
}
void Zone(const Pattern &pt, double &top, double &bot)
{
top = MathMax(pt.p1, pt.p2);
bot = MathMin(pt.p1, pt.p2);
double minT = 0.2 * pt.atrV;
if(top - bot < minT)
{
if(pt.dir == -1) bot = top - minT;
else top = bot + minT;
}
}
string StatusText(const Pattern &pt)
{
string name = pt.dir == -1 ? "DOUBLE TOP" : "DOUBLE BOTTOM";
string st;
switch(pt.state)
{
case 0: st = "FORMING"; break;
case 1: st = pt.tp1Hit ? "TP1 HIT" : "ACTIVE"; break;
case 2: st = pt.tp2Hit ? "TP2 HIT" : "SUCCESS"; break;
case 3: st = "FAILED"; break;
default: st = "TIMED OUT";
}
return name + " | " + st + " | Grade " + pt.grade + " " + IntegerToString(pt.score) + "/100";
}
void DrawLeg(const string pre, const string key, const int xa, const double ya, const int xb,
const double yb, const color c, const color bg, const double atrV)
{
if(InpUse3D)
{
double sh = 0.18 * atrV;
Trend(pre + "S" + key, xa + 1, ya - sh, xb + 1, yb - sh, Mix(c, bg, 72), InpLineW, STYLE_SOLID);
}
Trend(pre + "L" + key, xa, ya, xb, yb, c, InpLineW, STYLE_SOLID);
}
void DeleteObjs(const int id)
{
ObjectsDeleteAll(0, PFX + IntegerToString(id) + "_");
}
void DrawPattern(Pattern &pt)
{
string pre = PFX + IntegerToString(pt.id) + "_";
ObjectsDeleteAll(0, pre);
color bg = (color)ChartGetInteger(0, CHART_COLOR_BACKGROUND);
color c = ColorOf(pt);
int fs = FontSz(InpLblSize);
double top, bot; Zone(pt, top, bot);
DrawLeg(pre, "1", pt.x0, pt.p0, pt.x1, pt.p1, c, bg, pt.atrV);
DrawLeg(pre, "2", pt.x1, pt.p1, pt.xn, pt.neck, c, bg, pt.atrV);
DrawLeg(pre, "3", pt.xn, pt.neck, pt.x2, pt.p2, c, bg, pt.atrV);
if(pt.state >= 1) DrawLeg(pre, "4", pt.x2, pt.p2, pt.xb, pt.pb, c, bg, pt.atrV);
TrПоказано первые 50% кода (символов: 25665)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.