@@ -0,0 +1,204 @@
|
||||
% !TEX program = xelatex
|
||||
% UPS 自提 / 取件码 — 流程与系统设计示意(TikZ)
|
||||
% Overleaf: 使用 fontset=fandol(TeX Live 自带,无需 SimSun)
|
||||
% 本地 Windows 可改为: \usepackage[UTF8,scheme=plain]{ctex}\setCJKmainfont{SimSun}
|
||||
\documentclass[11pt,a4paper]{article}
|
||||
\usepackage[UTF8,scheme=plain,fontset=fandol]{ctex}
|
||||
\usepackage{geometry}
|
||||
\geometry{margin=2.2cm}
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{
|
||||
arrows.meta,
|
||||
positioning,
|
||||
shapes.geometric,
|
||||
shapes.symbols,
|
||||
fit,
|
||||
backgrounds,
|
||||
calc,
|
||||
shadows.blur
|
||||
}
|
||||
\definecolor{UPSbrown}{HTML}{351C15}
|
||||
\definecolor{UPSgold}{HTML}{FFB500}
|
||||
\definecolor{UPSlight}{HTML}{F5F0E8}
|
||||
\usepackage{hyperref}
|
||||
\hypersetup{colorlinks=true,linkcolor=UPSbrown,urlcolor=UPSgold}
|
||||
|
||||
\tikzset{
|
||||
font=\small,
|
||||
actor/.style={
|
||||
draw=UPSbrown,
|
||||
line width=0.8pt,
|
||||
rounded corners=3pt,
|
||||
minimum width=2.6cm,
|
||||
minimum height=1cm,
|
||||
align=center,
|
||||
fill=white,
|
||||
drop shadow={shadow xshift=1pt,shadow yshift=-1pt}
|
||||
},
|
||||
sys/.style={
|
||||
draw=UPSbrown,
|
||||
line width=0.6pt,
|
||||
rounded corners=2pt,
|
||||
minimum width=3cm,
|
||||
minimum height=0.85cm,
|
||||
align=center,
|
||||
fill=UPSlight
|
||||
},
|
||||
% 勿用名「step」:与 TikZ 内置 key /tikz/step 冲突(Overleaf 会报 pgfkeys Error)
|
||||
flowstep/.style={
|
||||
draw=UPSbrown,
|
||||
rounded corners=2pt,
|
||||
fill=white,
|
||||
minimum width=3cm,
|
||||
minimum height=0.7cm,
|
||||
align=center,
|
||||
font=\footnotesize
|
||||
},
|
||||
flow/.style={-{Stealth[length=2.2mm]}, thick, UPSbrown},
|
||||
lab/.style={font=\footnotesize, align=center},
|
||||
secret/.style={fill=UPSgold!25, draw=UPSgold!80!black, dashed}
|
||||
}
|
||||
|
||||
\title{\textcolor{UPSbrown}{UPS 风格自提点:取件码与系统设计}\\[0.3em]
|
||||
\large TikZ 图示(教学/示意,非官方)}
|
||||
\author{}
|
||||
\date{}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
\noindent
|
||||
本文档用 TikZ 示意「快递员投件 — 平台发码 — 收件人取件」的信息边界:
|
||||
投件方通常不掌握收件人取件码;取件码仅通过安全通道下发给收件人。
|
||||
\end{abstract}
|
||||
|
||||
% --------------------------------------------------------------------------
|
||||
\section{角色与信息可见性}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\begin{tikzpicture}[node distance=1.4cm and 2cm]
|
||||
\node[actor] (c) {快递员\\(存件/投件)};
|
||||
\node[actor, right=3.2cm of c] (s) {发件人\\(电商/个人)};
|
||||
\coordinate (midcs) at ($ (c)!0.5!(s) $);
|
||||
\node[actor, below=1.8cm of midcs] (r) {收件人};
|
||||
|
||||
\node[sys, right=3cm of r, minimum width=3.4cm] (plat) {物流平台\\\footnotesize 订单 / 轨迹 / 发码};
|
||||
\node[sys, below=of plat, minimum width=3.4cm] (lock) {自提柜控制器\\\footnotesize 格口 / 电子锁};
|
||||
|
||||
\draw[flow] (c) -- node[lab, left] {投件扫码\\工号/任务单} (plat);
|
||||
\draw[flow] (s) -- node[lab, above, sloped] {运单信息\\(无取件码)} (plat);
|
||||
\draw[flow, UPSgold!70!black] (plat) -- node[lab, right] {短信/App\\\textbf{取件码}} (r);
|
||||
\draw[flow] (plat) -- node[lab, right] {开格指令} (lock);
|
||||
\draw[flow] (c) -- node[lab, below, sloped] {物理投件} (lock);
|
||||
|
||||
\node[secret, rounded corners, fit=(r) (plat), inner sep=8pt, label={[font=\footnotesize]above:\textbf{取件码仅在收件人通道}}] {};
|
||||
\end{tikzpicture}
|
||||
\caption{示意:发件人与快递员一般不接收「收件取件码」;收件人通过平台下发获得取件码。}
|
||||
\label{fig:visibility}
|
||||
\end{figure}
|
||||
|
||||
% --------------------------------------------------------------------------
|
||||
\section{业务流程(泳道图)}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\begin{tikzpicture}[
|
||||
x=1cm, y=1cm,
|
||||
lane/.style={draw=UPSbrown!40, fill=UPSlight, minimum height=5.2cm, minimum width=3.6cm, anchor=north west}
|
||||
]
|
||||
|
||||
% lanes
|
||||
\node[lane] (L1) at (0,0) {};
|
||||
\node[anchor=north west, font=\bfseries\footnotesize, text=UPSbrown] at (0.15,-0.15) {快递员};
|
||||
\node[lane] (L2) at (4,0) {};
|
||||
\node[anchor=north west, font=\bfseries\footnotesize, text=UPSbrown] at (4.15,-0.15) {平台};
|
||||
\node[lane] (L3) at (8,0) {};
|
||||
\node[anchor=north west, font=\bfseries\footnotesize, text=UPSbrown] at (8.15,-0.15) {收件人};
|
||||
|
||||
% courier steps
|
||||
\node[flowstep] at (1.8,-1.1) (a1) {到站扫描};
|
||||
\node[flowstep, below=0.55 of a1] (a2) {分配格口};
|
||||
\node[flowstep, below=0.55 of a2] (a3) {投件关门};
|
||||
|
||||
% platform steps
|
||||
\node[flowstep] at (5.8,-1.1) (b1) {校验运单};
|
||||
\node[flowstep, below=0.55 of b1] (b2) {生成取件码};
|
||||
\node[flowstep, below=0.55 of b2] (b3) {短信/App 推送};
|
||||
\node[flowstep, below=0.55 of b3] (b4) {更新状态\\「待取件」};
|
||||
|
||||
% recipient
|
||||
\node[flowstep] at (9.8,-1.1) (c1) {收到通知};
|
||||
\node[flowstep, below=0.55 of c1] (c2) {到柜输入码};
|
||||
\node[flowstep, below=0.55 of c2] (c3) {取件完成};
|
||||
|
||||
\draw[flow] (a1) -- (b1);
|
||||
\draw[flow] (b2) -- (c1);
|
||||
\path (a3.south) ++(0,-0.2) coordinate (tmpa);
|
||||
\draw[flow] (tmpa) -- (tmpa -| b1.west) |- (b1);
|
||||
\path (c2.west) ++(-0.6,0) coordinate (tmpr);
|
||||
\draw[flow] (c2.west) -- (tmpr) |- (b4.east);
|
||||
|
||||
\end{tikzpicture}
|
||||
\caption{泳道示意:平台在投件确认后生成取件码并下发收件人;快递员侧流程与取件码解耦。}
|
||||
\label{fig:swimlane}
|
||||
\end{figure}
|
||||
|
||||
% --------------------------------------------------------------------------
|
||||
\section{系统分层架构}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\begin{tikzpicture}[node distance=0.75cm]
|
||||
\node[sys, minimum width=10cm, text width=9.6cm] (cli) {客户端层:快递员 App / 收件人 App / 柜机触摸屏};
|
||||
\node[sys, minimum width=10cm, text width=9.6cm, below=of cli] (gw) {网关层:API 网关、鉴权、限流、审计日志};
|
||||
\node[sys, minimum width=4.5cm, below left=1 and -0.2 of gw] (ord) {订单与运单服务};
|
||||
\node[sys, minimum width=4.5cm, below right=1 and -0.2 of gw] (code) {取件码服务\\\footnotesize 生成·绑定·失效};
|
||||
\node[sys, minimum width=4.5cm, below=of ord] (dev) {设备接入服务\\\footnotesize 开柜指令·状态回传};
|
||||
\node[sys, minimum width=4.5cm, below=of code] (msg) {消息服务\\\footnotesize 短信·推送·邮件};
|
||||
\node[sys, minimum width=10cm, text width=9.6cm, below=1.2 of dev.south west, anchor=west, xshift=0] (data) {数据层:运单库、取件码表(哈希)、设备影子、不可变审计};
|
||||
|
||||
\draw[flow] (cli) -- (gw);
|
||||
\draw[flow] (gw.south west) ++(1.2,0) -- ++(0,-0.35) -| (ord);
|
||||
\draw[flow] (gw.south east) ++(-1.2,0) -- ++(0,-0.35) -| (code);
|
||||
\draw[flow] (ord) -- (dev);
|
||||
\draw[flow] (code) -- (msg);
|
||||
\draw[flow] (dev) -- (data.north -| dev);
|
||||
\draw[flow] (msg) -- (data.north -| msg);
|
||||
\end{tikzpicture}
|
||||
\caption{逻辑分层:取件码由独立服务生成与校验,与投件流水解耦,便于最小权限与审计。}
|
||||
\label{fig:architecture}
|
||||
\end{figure}
|
||||
|
||||
% --------------------------------------------------------------------------
|
||||
\section{取件码生命周期(状态机)}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\begin{tikzpicture}[
|
||||
stnode/.style={circle, draw=UPSbrown, minimum size=1.15cm, align=center, font=\footnotesize, fill=white},
|
||||
acc/.style={-{Stealth}, thick, UPSbrown}
|
||||
]
|
||||
\node[stnode] (A) {未生成};
|
||||
\node[stnode, right=2.8cm of A] (B) {已生成\\未通知};
|
||||
\node[stnode, right=2.8cm of B] (C) {已下发};
|
||||
\coordinate (midBC) at ($ (B)!0.5!(C) $);
|
||||
\node[stnode, below=2cm of midBC] (D) {已核销};
|
||||
\node[stnode, left=2.8cm of D, fill=UPSlight] (E) {过期/作废};
|
||||
|
||||
\draw[acc] (A) -- node[above, font=\scriptsize] {投件确认} (B);
|
||||
\draw[acc] (B) -- node[above, font=\scriptsize] {推送} (C);
|
||||
\draw[acc] (C) -- node[right, font=\scriptsize] {正确输入} (D);
|
||||
\draw[acc] (C) -- node[below left, font=\scriptsize] {超时策略} (E);
|
||||
\draw[acc] (B) -- node[left, font=\scriptsize] {撤件} (E);
|
||||
\end{tikzpicture}
|
||||
\caption{取件码状态机示意:实际生产需加入重试、风控冻结、客服人工核销等分支。}
|
||||
\label{fig:statemachine}
|
||||
\end{figure}
|
||||
|
||||
\vfill
|
||||
\noindent\rule{\linewidth}{0.4pt}\\[0.3em]
|
||||
{\footnotesize\textcolor{UPSbrown}{Disclaimer:} 图示为通用物流自提逻辑的教学草稿,与 UPS 任何地区正式产品文档无关。配色仅作风格参考。}
|
||||
|
||||
\end{document}
|
||||
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 250 KiB |
@@ -5,7 +5,7 @@
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
#property version "1.01"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include "../_united/MagicNumberHelpers.mqh"
|
||||
@@ -92,6 +92,8 @@ void OnTick()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ResyncPositionFromMarket();
|
||||
|
||||
// Check for existing position
|
||||
CheckExistingPosition();
|
||||
@@ -120,6 +122,18 @@ bool UpdateRSI()
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResyncPositionFromMarket()
|
||||
{
|
||||
if(position_open)
|
||||
return;
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t == 0 || !PositionSelectByTicket(t))
|
||||
return;
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check existing position for exit conditions |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -272,20 +286,22 @@ void OpenSellPosition()
|
||||
//+------------------------------------------------------------------+
|
||||
void ClosePosition()
|
||||
{
|
||||
// Close position using helper function that verifies symbol AND magic number
|
||||
if(ClosePositionByMagic(trade, _Symbol, MagicNumber))
|
||||
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
// Position doesn't exist or wrong magic number - reset tracking anyway
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
Print("RSIScalpingXAUUSD: close failed (will retry on next bar). retcode=",
|
||||
trade.ResultRetcode(), " lastError=", GetLastError());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DeepMarkovRegimeModel.mqh |
|
||||
//| Hierarchical latent Markov stack + online regime-conditioned |
|
||||
//| RSI parameter blending and self-tuning from trade feedback. |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026"
|
||||
#property strict
|
||||
|
||||
#define DMR_NUM_STATES 4
|
||||
|
||||
void DMR_NormalizePi(double &p[])
|
||||
{
|
||||
double s = 0.0;
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
s += p[i];
|
||||
if(s <= 0.0)
|
||||
{
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
p[j] = 1.0 / DMR_NUM_STATES;
|
||||
return;
|
||||
}
|
||||
for(int k = 0; k < DMR_NUM_STATES; k++)
|
||||
p[k] /= s;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Two-level "deep" Markov: macro volatility x micro RSI momentum |
|
||||
//| Combined state s in {0..3} = macro*2 + micro. |
|
||||
//| Belief filtered each bar; transitions learned online. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDeepMarkovRegimeModel
|
||||
{
|
||||
private:
|
||||
int m_seed;
|
||||
double m_learning_trans; // transition matrix EMA
|
||||
double m_learning_emit; // emission center EMA
|
||||
double m_learning_param; // per-state param nudge on wins
|
||||
double m_penalty_param; // nudge on losses
|
||||
|
||||
// Forward belief pi(s), row-stochastic T[s_prev][s_next]
|
||||
double m_pi[DMR_NUM_STATES];
|
||||
double m_T[DMR_NUM_STATES][DMR_NUM_STATES];
|
||||
|
||||
// Gaussian emission centers in feature space (3D): RSI/100, dRSI norm, ATR ratio
|
||||
double m_center[DMR_NUM_STATES][3];
|
||||
double m_emit_sigma; // shared diagonal sigma^2 for simplicity
|
||||
|
||||
// Per-state RSI strategy parameters (learned offsets around base inputs)
|
||||
double m_d_overbought[DMR_NUM_STATES];
|
||||
double m_d_oversold[DMR_NUM_STATES];
|
||||
double m_d_target_buy[DMR_NUM_STATES];
|
||||
double m_d_target_sell[DMR_NUM_STATES];
|
||||
double m_d_bars_scale[DMR_NUM_STATES]; // multiplicative around base BarsToWait
|
||||
|
||||
double m_base_overbought;
|
||||
double m_base_oversold;
|
||||
double m_base_target_buy;
|
||||
double m_base_target_sell;
|
||||
int m_base_bars_wait;
|
||||
|
||||
void NormalizePi()
|
||||
{
|
||||
DMR_NormalizePi(m_pi);
|
||||
}
|
||||
|
||||
void RowNormalizeT()
|
||||
{
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
{
|
||||
double row = 0.0;
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
row += m_T[i][j];
|
||||
if(row <= 0.0)
|
||||
{
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
m_T[i][j] = 1.0 / DMR_NUM_STATES;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
m_T[i][j] /= row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double FeatureDist2(const double f0, const double f1, const double f2, const int state) const
|
||||
{
|
||||
double d0 = f0 - m_center[state][0];
|
||||
double d1 = f1 - m_center[state][1];
|
||||
double d2 = f2 - m_center[state][2];
|
||||
return d0 * d0 + d1 * d1 + d2 * d2;
|
||||
}
|
||||
|
||||
static double Clamp(const double x, const double lo, const double hi)
|
||||
{
|
||||
if(x < lo) return lo;
|
||||
if(x > hi) return hi;
|
||||
return x;
|
||||
}
|
||||
|
||||
public:
|
||||
CDeepMarkovRegimeModel()
|
||||
{
|
||||
m_seed = 0;
|
||||
m_learning_trans = 0.05;
|
||||
m_learning_emit = 0.02;
|
||||
m_learning_param = 0.03;
|
||||
m_penalty_param = 0.015;
|
||||
m_emit_sigma = 0.35;
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
{
|
||||
m_pi[i] = 1.0 / DMR_NUM_STATES;
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
m_T[i][j] = (i == j) ? 0.55 : 0.15;
|
||||
m_d_overbought[i] = 0.0;
|
||||
m_d_oversold[i] = 0.0;
|
||||
m_d_target_buy[i] = 0.0;
|
||||
m_d_target_sell[i] = 0.0;
|
||||
m_d_bars_scale[i] = 1.0;
|
||||
// Spread default emission prototypes across feature cube corners
|
||||
m_center[i][0] = ((i & 1) != 0) ? 0.75 : 0.35;
|
||||
m_center[i][1] = ((i & 2) != 0) ? 0.6 : 0.25;
|
||||
m_center[i][2] = (double)(i % 3) * 0.25 + 0.2;
|
||||
}
|
||||
RowNormalizeT();
|
||||
}
|
||||
|
||||
void SetLearningRates(const double lr_trans, const double lr_emit, const double lr_win, const double lr_loss)
|
||||
{
|
||||
m_learning_trans = lr_trans;
|
||||
m_learning_emit = lr_emit;
|
||||
m_learning_param = lr_win;
|
||||
m_penalty_param = lr_loss;
|
||||
}
|
||||
|
||||
void SetBaseThresholds(const double ob, const double os, const double tb, const double ts, const int bars_wait)
|
||||
{
|
||||
m_base_overbought = ob;
|
||||
m_base_oversold = os;
|
||||
m_base_target_buy = tb;
|
||||
m_base_target_sell = ts;
|
||||
m_base_bars_wait = bars_wait;
|
||||
}
|
||||
|
||||
void SetSeed(const int seed) { m_seed = seed; }
|
||||
|
||||
// f0: RSI/100, f1: tanh-like scaled delta RSI, f2: ATR short/long ratio capped
|
||||
void Update(const double f0, const double f1, const double f2)
|
||||
{
|
||||
double emit[DMR_NUM_STATES];
|
||||
double max_ll = -1.0e100;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
{
|
||||
double d2 = FeatureDist2(f0, f1, f2, s);
|
||||
emit[s] = MathExp(-0.5 * d2 / (m_emit_sigma * m_emit_sigma + 1.0e-12));
|
||||
if(emit[s] > max_ll) max_ll = emit[s];
|
||||
}
|
||||
// numerical safety
|
||||
for(int s2 = 0; s2 < DMR_NUM_STATES; s2++)
|
||||
if(emit[s2] != emit[s2] || emit[s2] < 1.0e-12)
|
||||
emit[s2] = 1.0e-12;
|
||||
|
||||
double pi_new[DMR_NUM_STATES];
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
{
|
||||
double sum = 0.0;
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
sum += m_pi[i] * m_T[i][j];
|
||||
pi_new[j] = sum * emit[j];
|
||||
}
|
||||
DMR_NormalizePi(pi_new);
|
||||
|
||||
int imax_prev = ArgMaxPi();
|
||||
int imax_new = 0;
|
||||
double best = pi_new[0];
|
||||
for(int j = 1; j < DMR_NUM_STATES; j++)
|
||||
if(pi_new[j] > best)
|
||||
{
|
||||
best = pi_new[j];
|
||||
imax_new = j;
|
||||
}
|
||||
|
||||
// Online transition nudge toward observed edge imax_prev -> imax_new
|
||||
for(int j = 0; j < DMR_NUM_STATES; j++)
|
||||
m_T[imax_prev][j] *= (1.0 - m_learning_trans);
|
||||
m_T[imax_prev][imax_new] += m_learning_trans;
|
||||
RowNormalizeT();
|
||||
|
||||
// Pull emission center of dominant new state toward observation
|
||||
for(int d = 0; d < 3; d++)
|
||||
{
|
||||
double obs[3] = {f0, f1, f2};
|
||||
m_center[imax_new][d] = (1.0 - m_learning_emit) * m_center[imax_new][d] + m_learning_emit * obs[d];
|
||||
}
|
||||
|
||||
for(int k = 0; k < DMR_NUM_STATES; k++)
|
||||
m_pi[k] = pi_new[k];
|
||||
NormalizePi();
|
||||
}
|
||||
|
||||
int ArgMaxPi() const
|
||||
{
|
||||
int idx = 0;
|
||||
double best = m_pi[0];
|
||||
for(int i = 1; i < DMR_NUM_STATES; i++)
|
||||
if(m_pi[i] > best)
|
||||
{
|
||||
best = m_pi[i];
|
||||
idx = i;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
double Belief(const int s) const
|
||||
{
|
||||
if(s < 0 || s >= DMR_NUM_STATES) return 0.0;
|
||||
return m_pi[s];
|
||||
}
|
||||
|
||||
// Blended effective thresholds (self-optimized offsets)
|
||||
double EffectiveOverbought() const
|
||||
{
|
||||
double v = 0.0;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
v += m_pi[s] * (m_base_overbought + m_d_overbought[s]);
|
||||
return Clamp(v, 50.0, 95.0);
|
||||
}
|
||||
|
||||
double EffectiveOversold() const
|
||||
{
|
||||
double v = 0.0;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
v += m_pi[s] * (m_base_oversold + m_d_oversold[s]);
|
||||
return Clamp(v, 5.0, 50.0);
|
||||
}
|
||||
|
||||
double EffectiveTargetBuy() const
|
||||
{
|
||||
double v = 0.0;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
v += m_pi[s] * (m_base_target_buy + m_d_target_buy[s]);
|
||||
return Clamp(v, 55.0, 99.0);
|
||||
}
|
||||
|
||||
double EffectiveTargetSell() const
|
||||
{
|
||||
double v = 0.0;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
v += m_pi[s] * (m_base_target_sell + m_d_target_sell[s]);
|
||||
return Clamp(v, 1.0, 50.0);
|
||||
}
|
||||
|
||||
int EffectiveBarsToWait() const
|
||||
{
|
||||
double acc = 0.0;
|
||||
for(int s = 0; s < DMR_NUM_STATES; s++)
|
||||
acc += m_pi[s] * m_d_bars_scale[s];
|
||||
acc = Clamp(acc, 0.5, 2.0);
|
||||
int b = (int)MathRound((double)m_base_bars_wait * acc);
|
||||
return (int)Clamp((double)b, 1.0, 20.0);
|
||||
}
|
||||
|
||||
// Reinforce or soften parameters for the regime active at entry
|
||||
void OnTradeClosed(const int dominant_state_at_entry, const double profit_money)
|
||||
{
|
||||
if(dominant_state_at_entry < 0 || dominant_state_at_entry >= DMR_NUM_STATES)
|
||||
return;
|
||||
const int s = dominant_state_at_entry;
|
||||
const double mag = MathMin(1.0, MathAbs(profit_money) / 100.0 + 0.2);
|
||||
if(profit_money > 0.0)
|
||||
{
|
||||
// Slightly widen capture: push targets outward in favorable direction
|
||||
m_d_target_buy[s] += m_learning_param * mag * 0.5;
|
||||
m_d_target_sell[s] -= m_learning_param * mag * 0.5;
|
||||
m_d_overbought[s] += m_learning_param * mag * 0.25;
|
||||
m_d_oversold[s] -= m_learning_param * mag * 0.25;
|
||||
m_d_bars_scale[s] += m_learning_param * 0.05 * mag;
|
||||
}
|
||||
else if(profit_money < 0.0)
|
||||
{
|
||||
// Tighten: mean-revert offsets toward 0 and shorten patience
|
||||
m_d_target_buy[s] *= (1.0 - m_penalty_param * mag);
|
||||
m_d_target_sell[s] *= (1.0 - m_penalty_param * mag);
|
||||
m_d_overbought[s] *= (1.0 - m_penalty_param * mag);
|
||||
m_d_oversold[s] *= (1.0 - m_penalty_param * mag);
|
||||
m_d_bars_scale[s] -= m_penalty_param * 0.05 * mag;
|
||||
}
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
{
|
||||
m_d_overbought[i] = Clamp(m_d_overbought[i], -15.0, 15.0);
|
||||
m_d_oversold[i] = Clamp(m_d_oversold[i], -15.0, 15.0);
|
||||
m_d_target_buy[i] = Clamp(m_d_target_buy[i], -20.0, 20.0);
|
||||
m_d_target_sell[i] = Clamp(m_d_target_sell[i], -20.0, 20.0);
|
||||
m_d_bars_scale[i] = Clamp(m_d_bars_scale[i], 0.5, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
string DebugStateLine() const
|
||||
{
|
||||
string t = StringFormat("DMR pi=[%.2f,%.2f,%.2f,%.2f] OB=%.1f OS=%.1f TB=%.1f TS=%.1f BW=%d",
|
||||
m_pi[0], m_pi[1], m_pi[2], m_pi[3],
|
||||
EffectiveOverbought(), EffectiveOversold(),
|
||||
EffectiveTargetBuy(), EffectiveTargetSell(),
|
||||
EffectiveBarsToWait());
|
||||
return t;
|
||||
}
|
||||
|
||||
bool SaveToGlobals(const string prefix) const
|
||||
{
|
||||
string p = prefix + IntegerToString(m_seed) + "_";
|
||||
GlobalVariableSet(p + "pi0", m_pi[0]);
|
||||
GlobalVariableSet(p + "pi1", m_pi[1]);
|
||||
GlobalVariableSet(p + "pi2", m_pi[2]);
|
||||
GlobalVariableSet(p + "pi3", m_pi[3]);
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
{
|
||||
GlobalVariableSet(p + "dob" + IntegerToString(i), m_d_overbought[i]);
|
||||
GlobalVariableSet(p + "dos" + IntegerToString(i), m_d_oversold[i]);
|
||||
GlobalVariableSet(p + "dtb" + IntegerToString(i), m_d_target_buy[i]);
|
||||
GlobalVariableSet(p + "dts" + IntegerToString(i), m_d_target_sell[i]);
|
||||
GlobalVariableSet(p + "dbs" + IntegerToString(i), m_d_bars_scale[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadFromGlobals(const string prefix)
|
||||
{
|
||||
string p = prefix + IntegerToString(m_seed) + "_";
|
||||
if(!GlobalVariableCheck(p + "pi0"))
|
||||
return false;
|
||||
m_pi[0] = GlobalVariableGet(p + "pi0");
|
||||
m_pi[1] = GlobalVariableGet(p + "pi1");
|
||||
m_pi[2] = GlobalVariableGet(p + "pi2");
|
||||
m_pi[3] = GlobalVariableGet(p + "pi3");
|
||||
for(int i = 0; i < DMR_NUM_STATES; i++)
|
||||
{
|
||||
m_d_overbought[i] = GlobalVariableGet(p + "dob" + IntegerToString(i));
|
||||
m_d_oversold[i] = GlobalVariableGet(p + "dos" + IntegerToString(i));
|
||||
m_d_target_buy[i] = GlobalVariableGet(p + "dtb" + IntegerToString(i));
|
||||
m_d_target_sell[i] = GlobalVariableGet(p + "dts" + IntegerToString(i));
|
||||
m_d_bars_scale[i] = GlobalVariableGet(p + "dbs" + IntegerToString(i));
|
||||
}
|
||||
NormalizePi();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,157 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MagicNumberHelpers.mqh |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelect(symbol))
|
||||
return false;
|
||||
|
||||
if(PositionGetInteger(POSITION_MAGIC) != magic_number)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
if(PositionGetTicket(i) > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify magic number and symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketAndMagic(ulong ticket, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify symbol, magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketSymbolAndMagic(ulong ticket, string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if position exists with correct magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionExistsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
return PositionSelectByMagic(symbol, magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position ticket by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong GetPositionTicketByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return ticket;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ClosePositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionClose(ticket);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modify position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ModifyPositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number,
|
||||
double sl, double tp)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionModify(ticket, sl, tp);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position profit by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetPositionProfitByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return 0.0;
|
||||
|
||||
return PositionGetDouble(POSITION_PROFIT);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position type by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_POSITION_TYPE GetPositionTypeByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return WRONG_VALUE;
|
||||
|
||||
return (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Count positions by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
int CountPositionsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,350 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIScalpingXAUUSD_DeepMarkov.mq5 |
|
||||
//| RSI scalping with online deep Markov regime filter + self-tune. |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026"
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
#include "DeepMarkovRegimeModel.mqh"
|
||||
|
||||
//--- Input parameters
|
||||
input group "=== Chart / RSI ==="
|
||||
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;
|
||||
input int RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE;
|
||||
|
||||
input group "=== Base RSI levels (Markov blends & learns offsets) ==="
|
||||
input double RSI_Overbought = 71;
|
||||
input double RSI_Oversold = 57;
|
||||
input double RSI_Target_Buy = 80;
|
||||
input double RSI_Target_Sell = 57;
|
||||
input int BarsToWait = 4;
|
||||
|
||||
input group "=== Execution ==="
|
||||
input double LotSize = 0.1;
|
||||
input int MagicNumber = 129102316;
|
||||
input int Slippage = 3;
|
||||
|
||||
input group "=== Deep Markov self-optimization ==="
|
||||
input double DMR_LearnTransition = 0.05;
|
||||
input double DMR_LearnEmission = 0.02;
|
||||
input double DMR_LearnWin = 0.03;
|
||||
input double DMR_LearnLoss = 0.015;
|
||||
input bool DMR_PersistGlobals = true;
|
||||
input string DMR_GlobalPrefix = "DMR_XAU_";
|
||||
input bool DMR_LogEachBar = false;
|
||||
|
||||
//--- Global variables
|
||||
CTrade trade;
|
||||
CDeepMarkovRegimeModel g_dm;
|
||||
|
||||
int rsi_handle;
|
||||
int atr_fast_handle;
|
||||
int atr_slow_handle;
|
||||
double rsi_buffer[];
|
||||
double rsi_prev, rsi_current, rsi_two_bars_ago;
|
||||
double atr_fast, atr_slow;
|
||||
|
||||
bool position_open = false;
|
||||
int position_ticket = 0;
|
||||
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
|
||||
datetime last_bar_time = 0;
|
||||
bool rsi_against_position = false;
|
||||
int bars_against_count = 0;
|
||||
|
||||
int entry_regime = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
if(rsi_handle == INVALID_HANDLE)
|
||||
return(INIT_FAILED);
|
||||
|
||||
atr_fast_handle = iATR(_Symbol, TimeFrame, 8);
|
||||
atr_slow_handle = iATR(_Symbol, TimeFrame, 34);
|
||||
if(atr_fast_handle == INVALID_HANDLE || atr_slow_handle == INVALID_HANDLE)
|
||||
return(INIT_FAILED);
|
||||
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
trade.SetDeviationInPoints(Slippage);
|
||||
trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
ArraySetAsSeries(rsi_buffer, true);
|
||||
|
||||
g_dm.SetSeed(MagicNumber);
|
||||
g_dm.SetLearningRates(DMR_LearnTransition, DMR_LearnEmission, DMR_LearnWin, DMR_LearnLoss);
|
||||
g_dm.SetBaseThresholds(RSI_Overbought, RSI_Oversold, RSI_Target_Buy, RSI_Target_Sell, BarsToWait);
|
||||
|
||||
if(DMR_PersistGlobals)
|
||||
{
|
||||
if(g_dm.LoadFromGlobals(DMR_GlobalPrefix))
|
||||
Print("RSIScalpingXAUUSD_DeepMarkov: loaded persisted Markov state from globals.");
|
||||
}
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(DMR_PersistGlobals)
|
||||
g_dm.SaveToGlobals(DMR_GlobalPrefix);
|
||||
|
||||
if(rsi_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(rsi_handle);
|
||||
if(atr_fast_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(atr_fast_handle);
|
||||
if(atr_slow_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(atr_slow_handle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
if(Bars(_Symbol, TimeFrame) < RSI_Period + 5)
|
||||
return;
|
||||
|
||||
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
|
||||
if(current_bar_time == last_bar_time)
|
||||
return;
|
||||
|
||||
last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI())
|
||||
return;
|
||||
|
||||
if(!UpdateATR())
|
||||
return;
|
||||
|
||||
const double f0 = rsi_current / 100.0;
|
||||
const double dr = rsi_current - rsi_prev;
|
||||
const double f1 = MathTanh(dr / 10.0) * 0.5 + 0.5;
|
||||
double ratio = 1.0;
|
||||
if(atr_slow > 1.0e-12)
|
||||
ratio = atr_fast / atr_slow;
|
||||
if(ratio < 0.15)
|
||||
ratio = 0.15;
|
||||
if(ratio > 2.5)
|
||||
ratio = 2.5;
|
||||
const double f2 = ratio / 2.5;
|
||||
|
||||
g_dm.Update(f0, f1, f2);
|
||||
|
||||
if(DMR_LogEachBar)
|
||||
Print(g_dm.DebugStateLine());
|
||||
|
||||
ResyncPositionFromMarket();
|
||||
|
||||
CheckExistingPosition();
|
||||
|
||||
if(!position_open && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
|
||||
CheckEntrySignals();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateRSI()
|
||||
{
|
||||
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
|
||||
return false;
|
||||
|
||||
rsi_current = rsi_buffer[0];
|
||||
rsi_prev = rsi_buffer[1];
|
||||
rsi_two_bars_ago = rsi_buffer[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateATR()
|
||||
{
|
||||
double af[], as[];
|
||||
ArrayResize(af, 1);
|
||||
ArrayResize(as, 1);
|
||||
ArraySetAsSeries(af, true);
|
||||
ArraySetAsSeries(as, true);
|
||||
if(CopyBuffer(atr_fast_handle, 0, 0, 1, af) < 1)
|
||||
return false;
|
||||
if(CopyBuffer(atr_slow_handle, 0, 0, 1, as) < 1)
|
||||
return false;
|
||||
atr_fast = af[0];
|
||||
atr_slow = as[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void ResyncPositionFromMarket()
|
||||
{
|
||||
if(position_open)
|
||||
return;
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t == 0 || !PositionSelectByTicket(t))
|
||||
return;
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
entry_regime = g_dm.ArgMaxPi();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
double EffectiveOverbought() { return g_dm.EffectiveOverbought(); }
|
||||
double EffectiveOversold() { return g_dm.EffectiveOversold(); }
|
||||
double EffectiveTargetBuy() { return g_dm.EffectiveTargetBuy(); }
|
||||
double EffectiveTargetSell() { return g_dm.EffectiveTargetSell(); }
|
||||
int EffectiveBarsToWait() { return g_dm.EffectiveBarsToWait(); }
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckExistingPosition()
|
||||
{
|
||||
if(!position_open)
|
||||
return;
|
||||
|
||||
if(!PositionSelectByTicketAndMagic((ulong)position_ticket, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const double ob = EffectiveOverbought();
|
||||
const double os = EffectiveOversold();
|
||||
const double tb = EffectiveTargetBuy();
|
||||
const double ts = EffectiveTargetSell();
|
||||
const int bw = EffectiveBarsToWait();
|
||||
|
||||
if(current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(rsi_current < os)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
bars_against_count++;
|
||||
|
||||
if(bars_against_count >= bw)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
if(rsi_current >= tb)
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
else if(current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(rsi_current > ob)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
bars_against_count++;
|
||||
|
||||
if(bars_against_count >= bw)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
if(rsi_current <= ts)
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckEntrySignals()
|
||||
{
|
||||
const double os = EffectiveOversold();
|
||||
const double ob = EffectiveOverbought();
|
||||
|
||||
if(rsi_two_bars_ago <= os && rsi_prev > os)
|
||||
OpenBuyPosition();
|
||||
|
||||
if(rsi_two_bars_ago >= ob && rsi_prev < ob)
|
||||
OpenSellPosition();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenBuyPosition()
|
||||
{
|
||||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
entry_regime = g_dm.ArgMaxPi();
|
||||
|
||||
if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI DM Buy"))
|
||||
{
|
||||
ulong pt = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
position_ticket = (int)pt;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_BUY;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenSellPosition()
|
||||
{
|
||||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
entry_regime = g_dm.ArgMaxPi();
|
||||
|
||||
if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI DM Sell"))
|
||||
{
|
||||
ulong pt = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
position_ticket = (int)pt;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void ClosePosition()
|
||||
{
|
||||
double profit = 0.0;
|
||||
if(PositionSelectByTicket(position_ticket))
|
||||
profit = PositionGetDouble(POSITION_PROFIT);
|
||||
|
||||
const int regime = entry_regime;
|
||||
|
||||
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
g_dm.OnTradeClosed(regime, profit);
|
||||
return;
|
||||
}
|
||||
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
g_dm.OnTradeClosed(regime, profit);
|
||||
return;
|
||||
}
|
||||
Print("RSIScalpingXAUUSD_DeepMarkov: close failed (will retry). retcode=",
|
||||
trade.ResultRetcode(), " lastError=", GetLastError());
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIScalpingXAUUSD_PlusHours.mq5 |
|
||||
//| Same logic as RSIScalpingXAUUSD + trading session filter |
|
||||
//| (server time), day-of-week filter, and optional close-all when |
|
||||
//| outside allowed hours/days |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include "../_united/MagicNumberHelpers.mqh"
|
||||
|
||||
input group "=== RSI (same as RSIScalpingXAUUSD) ==="
|
||||
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;
|
||||
input int RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RSI_Overbought = 71;
|
||||
input double RSI_Oversold = 57;
|
||||
input double RSI_Target_Buy = 80;
|
||||
input double RSI_Target_Sell = 57;
|
||||
input int BarsToWait = 4;
|
||||
input double LotSize = 0.1;
|
||||
input int MagicNumber = 129102317;
|
||||
input int Slippage = 3;
|
||||
|
||||
input group "=== Trading hours (broker server time) ==="
|
||||
input bool InpUseTradingHours = true;
|
||||
input int InpTradeHourStart = 8;
|
||||
input int InpTradeHourEnd = 22;
|
||||
input bool InpCloseOutsideTradingHours = true;
|
||||
|
||||
input group "=== Trading days (broker server time) ==="
|
||||
input bool InpUseTradingDays = true;
|
||||
input bool InpTradeMonday = true;
|
||||
input bool InpTradeTuesday = true;
|
||||
input bool InpTradeWednesday = true;
|
||||
input bool InpTradeThursday = true;
|
||||
input bool InpTradeFriday = true;
|
||||
input bool InpTradeSaturday = true;
|
||||
input bool InpTradeSunday = true;
|
||||
input bool InpCloseOutsideTradingDays = true;
|
||||
|
||||
CTrade trade;
|
||||
int rsi_handle;
|
||||
double rsi_buffer[];
|
||||
double rsi_prev, rsi_current, rsi_two_bars_ago;
|
||||
bool position_open = false;
|
||||
int position_ticket = 0;
|
||||
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
|
||||
datetime last_bar_time = 0;
|
||||
bool rsi_against_position = false;
|
||||
int bars_against_count = 0;
|
||||
|
||||
bool IsWithinTradingHours()
|
||||
{
|
||||
if(!InpUseTradingHours)
|
||||
return true;
|
||||
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
const int h = dt.hour;
|
||||
const int hs = MathMax(0, MathMin(23, InpTradeHourStart));
|
||||
const int he = MathMax(0, MathMin(23, InpTradeHourEnd));
|
||||
|
||||
if(hs == he)
|
||||
return true;
|
||||
|
||||
if(hs < he)
|
||||
return (h >= hs && h < he);
|
||||
|
||||
return (h >= hs || h < he);
|
||||
}
|
||||
|
||||
bool IsTradingDayAllowed()
|
||||
{
|
||||
if(!InpUseTradingDays)
|
||||
return true;
|
||||
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
switch(dt.day_of_week)
|
||||
{
|
||||
case 0: return InpTradeSunday;
|
||||
case 1: return InpTradeMonday;
|
||||
case 2: return InpTradeTuesday;
|
||||
case 3: return InpTradeWednesday;
|
||||
case 4: return InpTradeThursday;
|
||||
case 5: return InpTradeFriday;
|
||||
case 6: return InpTradeSaturday;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
if(rsi_handle == INVALID_HANDLE)
|
||||
return(INIT_FAILED);
|
||||
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
trade.SetDeviationInPoints(Slippage);
|
||||
trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
ArraySetAsSeries(rsi_buffer, true);
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(rsi_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(rsi_handle);
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
|
||||
return;
|
||||
|
||||
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
|
||||
if(current_bar_time == last_bar_time)
|
||||
return;
|
||||
|
||||
last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI())
|
||||
return;
|
||||
|
||||
ResyncPositionFromMarket();
|
||||
|
||||
const bool inHours = IsWithinTradingHours();
|
||||
const bool inDays = IsTradingDayAllowed();
|
||||
const bool inSession = inHours && inDays;
|
||||
|
||||
if(position_open && !inSession &&
|
||||
((InpUseTradingHours && InpCloseOutsideTradingHours && !inHours) ||
|
||||
(InpUseTradingDays && InpCloseOutsideTradingDays && !inDays)))
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
|
||||
CheckExistingPosition();
|
||||
|
||||
if(!position_open && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber) && inSession)
|
||||
CheckEntrySignals();
|
||||
}
|
||||
|
||||
bool UpdateRSI()
|
||||
{
|
||||
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
|
||||
return false;
|
||||
|
||||
rsi_current = rsi_buffer[0];
|
||||
rsi_prev = rsi_buffer[1];
|
||||
rsi_two_bars_ago = rsi_buffer[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResyncPositionFromMarket()
|
||||
{
|
||||
if(position_open)
|
||||
return;
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t == 0 || !PositionSelectByTicket(t))
|
||||
return;
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
void CheckExistingPosition()
|
||||
{
|
||||
if(!position_open)
|
||||
return;
|
||||
|
||||
if(!PositionSelectByTicketAndMagic(position_ticket, MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(rsi_current < RSI_Oversold)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
bars_against_count++;
|
||||
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(rsi_current >= RSI_Target_Buy)
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
else if(current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(rsi_current > RSI_Overbought)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
bars_against_count++;
|
||||
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(rsi_current <= RSI_Target_Sell)
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckEntrySignals()
|
||||
{
|
||||
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
|
||||
OpenBuyPosition();
|
||||
|
||||
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought)
|
||||
OpenSellPosition();
|
||||
}
|
||||
|
||||
void OpenBuyPosition()
|
||||
{
|
||||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Hours Buy"))
|
||||
{
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
position_ticket = (int)t;
|
||||
position_open = (position_ticket != 0);
|
||||
current_position_type = POSITION_TYPE_BUY;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSellPosition()
|
||||
{
|
||||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Hours Sell"))
|
||||
{
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
position_ticket = (int)t;
|
||||
position_open = (position_ticket != 0);
|
||||
current_position_type = POSITION_TYPE_SELL;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ClosePosition()
|
||||
{
|
||||
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
Print("RSIScalpingXAUUSD_PlusHours: close failed (will retry). retcode=",
|
||||
trade.ResultRetcode(), " lastError=", GetLastError());
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIScalpingXAUUSD_Trailing.mq5 |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.06"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include "../_united/MagicNumberHelpers.mqh"
|
||||
|
||||
//--- Input parameters
|
||||
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis
|
||||
input int RSI_Period = 14; // RSI Period
|
||||
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
|
||||
input double RSI_Overbought = 71; // RSI Overbought Level
|
||||
input double RSI_Oversold = 57; // RSI Oversold Level
|
||||
input double RSI_Target_Buy = 80; // RSI Target for Buy Exit
|
||||
input double RSI_Target_Sell = 57; // RSI Target for Sell Exit
|
||||
input int BarsToWait = 4; // Bars to wait when RSI goes against position
|
||||
input bool UseRSI_StopLoss = true; // Close on RSI stop (separate timeframe below)
|
||||
input ENUM_TIMEFRAMES RSI_StopLoss_TimeFrame = PERIOD_H1; // RSI timeframe for stop-loss only
|
||||
input double RSI_StopLoss_BuyBelow = 30; // Close buy when stop-timeframe RSI drops below this
|
||||
input double RSI_StopLoss_SellAbove = 70; // Close sell when stop-timeframe RSI rises above this
|
||||
input double LotSize = 0.1; // Lot Size
|
||||
input int MagicNumber = 129102316; // Magic Number (distinct from non-trailing EA)
|
||||
input int Slippage = 3; // Slippage in points
|
||||
|
||||
//--- Global variables
|
||||
CTrade trade;
|
||||
int rsi_handle;
|
||||
int rsi_stoploss_handle = INVALID_HANDLE;
|
||||
double rsi_buffer[];
|
||||
double rsi_stoploss_buffer[];
|
||||
double rsi_prev, rsi_current, rsi_two_bars_ago;
|
||||
double rsi_stoploss_current = 0.0;
|
||||
MqlTick rsi_stoploss_last_tick;
|
||||
bool position_open = false;
|
||||
int position_ticket = 0;
|
||||
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
|
||||
datetime last_bar_time = 0;
|
||||
bool rsi_against_position = false;
|
||||
int bars_against_count = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
if(rsi_handle == INVALID_HANDLE)
|
||||
{
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
rsi_stoploss_handle = iRSI(_Symbol, RSI_StopLoss_TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
if(rsi_stoploss_handle == INVALID_HANDLE)
|
||||
{
|
||||
IndicatorRelease(rsi_handle);
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
trade.SetDeviationInPoints(Slippage);
|
||||
trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
ArraySetAsSeries(rsi_buffer, true);
|
||||
ArraySetAsSeries(rsi_stoploss_buffer, true);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(rsi_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(rsi_handle);
|
||||
if(rsi_stoploss_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(rsi_stoploss_handle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
ResyncPositionFromMarket();
|
||||
|
||||
const int min_bars = RSI_Period + 2;
|
||||
if(position_open)
|
||||
{
|
||||
if(UseRSI_StopLoss && Bars(_Symbol, RSI_StopLoss_TimeFrame) >= min_bars)
|
||||
{
|
||||
if(UpdateRSI_StopLoss())
|
||||
CheckRSIStopLossClose();
|
||||
}
|
||||
}
|
||||
|
||||
if(Bars(_Symbol, TimeFrame) < min_bars)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
|
||||
if(current_bar_time == last_bar_time)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ResyncPositionFromMarket();
|
||||
|
||||
CheckExistingPosition();
|
||||
|
||||
if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber))
|
||||
{
|
||||
CheckEntrySignals();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update RSI values |
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateRSI()
|
||||
{
|
||||
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rsi_current = rsi_buffer[0];
|
||||
rsi_prev = rsi_buffer[1];
|
||||
rsi_two_bars_ago = rsi_buffer[2];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stop-loss RSI (RSI_StopLoss_TimeFrame) |
|
||||
//| Uses latest MqlTick before CopyBuffer so RSI matches current quote. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateRSI_StopLoss()
|
||||
{
|
||||
if(rsi_stoploss_handle == INVALID_HANDLE)
|
||||
return false;
|
||||
if(!SymbolInfoTick(_Symbol, rsi_stoploss_last_tick))
|
||||
return false;
|
||||
|
||||
int calc = BarsCalculated(rsi_stoploss_handle);
|
||||
if(calc <= 0)
|
||||
return false;
|
||||
|
||||
if(CopyBuffer(rsi_stoploss_handle, 0, 0, 1, rsi_stoploss_buffer) < 1)
|
||||
return false;
|
||||
rsi_stoploss_current = rsi_stoploss_buffer[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResyncPositionFromMarket()
|
||||
{
|
||||
if(position_open)
|
||||
return;
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t == 0 || !PositionSelectByTicket(t))
|
||||
return;
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSI-based stop: RSI_StopLoss_TimeFrame series (independent of TimeFrame) |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckRSIStopLossClose()
|
||||
{
|
||||
if(!UseRSI_StopLoss || !position_open)
|
||||
return;
|
||||
|
||||
if(!PositionSelectByTicketAndMagic(position_ticket, MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(rsi_stoploss_current < RSI_StopLoss_BuyBelow)
|
||||
ClosePosition();
|
||||
}
|
||||
else if(current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(rsi_stoploss_current > RSI_StopLoss_SellAbove)
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check existing position for exit conditions |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckExistingPosition()
|
||||
{
|
||||
if(!position_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!PositionSelectByTicketAndMagic(position_ticket, MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(rsi_current < RSI_Oversold)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bars_against_count++;
|
||||
}
|
||||
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(rsi_current >= RSI_Target_Buy)
|
||||
{
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(rsi_current > RSI_Overbought)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bars_against_count++;
|
||||
}
|
||||
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(rsi_current <= RSI_Target_Sell)
|
||||
{
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check for entry signals |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckEntrySignals()
|
||||
{
|
||||
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
|
||||
OpenBuyPosition();
|
||||
|
||||
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought)
|
||||
OpenSellPosition();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open buy position |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenBuyPosition()
|
||||
{
|
||||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
|
||||
if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy"))
|
||||
{
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t != 0)
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_BUY;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open sell position |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenSellPosition()
|
||||
{
|
||||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
|
||||
if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell"))
|
||||
{
|
||||
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
|
||||
if(t != 0)
|
||||
position_ticket = (int)t;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close current position |
|
||||
//+------------------------------------------------------------------+
|
||||
void ClosePosition()
|
||||
{
|
||||
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
Print("RSIScalpingXAUUSD: close failed (will retry on next bar). retcode=",
|
||||
trade.ResultRetcode(), " lastError=", GetLastError());
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
//--- Input Parameters
|
||||
input group "=== Trading Settings ==="
|
||||
input string InpSymbol = "XAUUSD"; // Trading Symbol (set was tuned on BTCUSD)
|
||||
input string InpSymbol = "XAUUSD"; // Default gold; same numbers as secret_sauce.set (that file uses BTCUSD as symbol)
|
||||
input double InpLotSize = 0.1; // Lot Size (Profiles/Tester/secret_sauce.set)
|
||||
input int InpMagicNumber = 789012; // Magic Number
|
||||
input int InpSlippage = 10; // Slippage in points
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
; SuperEMA — defaults aligned with lab/EAs/SuperEMA.mq5 (v1.01)
|
||||
; Load from Strategy Tester → Inputs → context menu → Load
|
||||
;
|
||||
; === Market ===
|
||||
InpSymbol=
|
||||
InpTimeframe=15||15||0||49153||N
|
||||
InpLots=0.01||0.01||0.01||0.10||N
|
||||
InpSlippagePoints=55||20||5||120||Y
|
||||
InpMagic=940001||940001||1||9400010||N
|
||||
; === EMA (trend & structure) ===
|
||||
InpEmaFast=40||20||10||120||Y
|
||||
InpEmaMid=180||60||15||200||Y
|
||||
InpEmaSlow=125||100||25||400||Y
|
||||
InpEmaTrendBars=3||1||1||3||Y
|
||||
; === CCI ===
|
||||
InpCciPeriod=17||7||1||28||Y
|
||||
InpCciOverbought=80.0||80.0||10.0||140.0||Y
|
||||
InpCciOversold=-140.0||-140.0||10.0||-80.0||Y
|
||||
InpPullbackCciLookback=20||4||2||24||Y
|
||||
; === MACD (histogram = main - signal) ===
|
||||
InpMacdFast=14||8||2||20||Y
|
||||
InpMacdSlow=38||20||2||40||Y
|
||||
InpMacdSignal=9||5||1||15||Y
|
||||
; === Strategy ===
|
||||
InpEntryStyle=1||0||1||2||Y
|
||||
InpOneTradeOnly=true||false||0||true||N
|
||||
InpUseStructuralSL=false||false||0||true||Y
|
||||
InpSlBufferPoints=110.0||20.0||10.0||200.0||Y
|
||||
; === Exits (so trades do not run forever) ===
|
||||
InpExitOnTrendFlip=false||false||0||true||Y
|
||||
InpExitOnMacdFlip=false||false||0||true||Y
|
||||
InpExitOnCciZeroCross=true||false||0||true||Y
|
||||
InpMaxHoldingBars=168||48||24||480||Y
|
||||
InpExitBelowMidEma=false||false||0||true||Y
|
||||
; === Debug ===
|
||||
InpDebugLogs=false||false||0||true||N
|
||||
@@ -0,0 +1,448 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SuperEMA.mq5 |
|
||||
//| EMA + CCI + MACD histogram — trend filter, momentum confirmation |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
#property version "1.01"
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
enum ENUM_ENTRY_STYLE
|
||||
{
|
||||
ENTRY_CCIZERO_MACD = 0, // EMA trend + CCI crosses zero + MACD histogram agrees
|
||||
ENTRY_LAMBERT = 1, // EMA trend + CCI crosses ±100 + MACD histogram agrees
|
||||
ENTRY_PULLBACK = 2 // Uptrend: pullback to fast EMA + CCI was oversold + CCI crosses up through 0 + MACD > 0 (mirror for sells)
|
||||
};
|
||||
|
||||
input group "=== Market ==="
|
||||
input string InpSymbol = "";
|
||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
|
||||
input double InpLots = 0.01;
|
||||
input int InpSlippagePoints = 55;
|
||||
input int InpMagic = 940001;
|
||||
|
||||
input group "=== EMA (trend & structure) ==="
|
||||
input int InpEmaFast = 40;
|
||||
input int InpEmaMid = 180;
|
||||
input int InpEmaSlow = 125;
|
||||
input int InpEmaTrendBars = 3; // closed bar shift for EMA reads
|
||||
|
||||
input group "=== CCI ==="
|
||||
input int InpCciPeriod = 17;
|
||||
input double InpCciOverbought = 80.0;
|
||||
input double InpCciOversold = -140.0;
|
||||
input int InpPullbackCciLookback = 20; // bars to check prior CCI oversold/overbought
|
||||
|
||||
input group "=== MACD (histogram = main - signal) ==="
|
||||
input int InpMacdFast = 14;
|
||||
input int InpMacdSlow = 38;
|
||||
input int InpMacdSignal = 9;
|
||||
|
||||
input group "=== Strategy ==="
|
||||
input ENUM_ENTRY_STYLE InpEntryStyle = ENTRY_LAMBERT;
|
||||
input bool InpOneTradeOnly = true;
|
||||
input bool InpUseStructuralSL = false;
|
||||
input double InpSlBufferPoints = 110;
|
||||
|
||||
input group "=== Exits (so trades do not run forever) ==="
|
||||
input bool InpExitOnTrendFlip = false; // close when price vs slow EMA flips against position
|
||||
input bool InpExitOnMacdFlip = false; // close when MACD histogram flips against position
|
||||
input bool InpExitOnCciZeroCross = true; // long: CCI crosses below 0; short: CCI crosses above 0
|
||||
input int InpMaxHoldingBars = 168; // 0 = disabled (e.g. ~8 days M15)
|
||||
input bool InpExitBelowMidEma = false; // long: close if close < mid EMA (invalidation)
|
||||
|
||||
input group "=== Debug ==="
|
||||
input bool InpDebugLogs = false;
|
||||
|
||||
CTrade trade;
|
||||
datetime g_lastBarTime = 0;
|
||||
|
||||
string WorkSymbol()
|
||||
{
|
||||
return (InpSymbol == "" || InpSymbol == NULL) ? _Symbol : InpSymbol;
|
||||
}
|
||||
|
||||
void Log(const string s)
|
||||
{
|
||||
if(InpDebugLogs)
|
||||
Print("[SuperEMA] ", s);
|
||||
}
|
||||
|
||||
bool IsNewBar(const string sym, const ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
datetime t = iTime(sym, tf, 0);
|
||||
if(t <= 0 || t == g_lastBarTime)
|
||||
return false;
|
||||
g_lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
double EmaAt(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int h = iMA(sym, tf, period, 0, MODE_EMA, PRICE_CLOSE);
|
||||
if(h == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double b[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return 0.0;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
double CciAt(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int h = iCCI(sym, tf, period, PRICE_TYPICAL);
|
||||
if(h == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double b[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return 0.0;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
bool MacdHistAt(const string sym, const ENUM_TIMEFRAMES tf, const int fast, const int slow, const int signal, const int shift, double &hist)
|
||||
{
|
||||
int h = iMACD(sym, tf, fast, slow, signal, PRICE_CLOSE);
|
||||
if(h == INVALID_HANDLE)
|
||||
return false;
|
||||
double mainLine[1], sigLine[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, mainLine) <= 0 || CopyBuffer(h, 1, shift, 1, sigLine) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return false;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
hist = mainLine[0] - sigLine[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrendUp(const string sym, const int sh)
|
||||
{
|
||||
double c = iClose(sym, InpTimeframe, sh);
|
||||
double emaS = EmaAt(sym, InpTimeframe, InpEmaSlow, sh);
|
||||
return (emaS > 0.0 && c > emaS);
|
||||
}
|
||||
|
||||
bool TrendDown(const string sym, const int sh)
|
||||
{
|
||||
double c = iClose(sym, InpTimeframe, sh);
|
||||
double emaS = EmaAt(sym, InpTimeframe, InpEmaSlow, sh);
|
||||
return (emaS > 0.0 && c < emaS);
|
||||
}
|
||||
|
||||
bool CciCrossAboveZero(const string sym)
|
||||
{
|
||||
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
|
||||
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
|
||||
return (c2 <= 0.0 && c1 > 0.0);
|
||||
}
|
||||
|
||||
bool CciCrossBelowZero(const string sym)
|
||||
{
|
||||
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
|
||||
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
|
||||
return (c2 >= 0.0 && c1 < 0.0);
|
||||
}
|
||||
|
||||
bool CciCrossAbove100(const string sym)
|
||||
{
|
||||
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
|
||||
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
|
||||
return (c2 < InpCciOverbought && c1 > InpCciOverbought);
|
||||
}
|
||||
|
||||
bool CciCrossBelowMinus100(const string sym)
|
||||
{
|
||||
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
|
||||
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
|
||||
return (c2 > InpCciOversold && c1 < InpCciOversold);
|
||||
}
|
||||
|
||||
bool HadCciOversoldRecently(const string sym)
|
||||
{
|
||||
for(int i = 2; i <= InpPullbackCciLookback + 1; i++)
|
||||
{
|
||||
double v = CciAt(sym, InpTimeframe, InpCciPeriod, i);
|
||||
if(v <= InpCciOversold)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HadCciOverboughtRecently(const string sym)
|
||||
{
|
||||
for(int i = 2; i <= InpPullbackCciLookback + 1; i++)
|
||||
{
|
||||
double v = CciAt(sym, InpTimeframe, InpCciPeriod, i);
|
||||
if(v >= InpCciOverbought)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PullbackNearFastEmaLong(const string sym)
|
||||
{
|
||||
double emaF = EmaAt(sym, InpTimeframe, InpEmaFast, 1);
|
||||
double lo = iLow(sym, InpTimeframe, 1);
|
||||
if(emaF <= 0.0)
|
||||
return false;
|
||||
return (lo <= emaF + InpSlBufferPoints * _Point * 3.0);
|
||||
}
|
||||
|
||||
bool PullbackNearFastEmaShort(const string sym)
|
||||
{
|
||||
double emaF = EmaAt(sym, InpTimeframe, InpEmaFast, 1);
|
||||
double hi = iHigh(sym, InpTimeframe, 1);
|
||||
if(emaF <= 0.0)
|
||||
return false;
|
||||
return (hi >= emaF - InpSlBufferPoints * _Point * 3.0);
|
||||
}
|
||||
|
||||
int PositionsByMagic(const string sym, const int magic)
|
||||
{
|
||||
int n = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == sym && (int)PositionGetInteger(POSITION_MAGIC) == magic)
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void ComputeSLTP(const bool isBuy, const double entry, double &sl, double &tp)
|
||||
{
|
||||
const string sym = WorkSymbol();
|
||||
sl = 0.0;
|
||||
tp = 0.0;
|
||||
if(!InpUseStructuralSL)
|
||||
return;
|
||||
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, InpEmaTrendBars);
|
||||
double buf = InpSlBufferPoints * _Point;
|
||||
if(isBuy)
|
||||
sl = emaM - buf;
|
||||
else
|
||||
sl = emaM + buf;
|
||||
}
|
||||
|
||||
int BarsSinceOpen(const string sym, const datetime openTime)
|
||||
{
|
||||
if(openTime <= 0)
|
||||
return 0;
|
||||
int sh = iBarShift(sym, InpTimeframe, openTime, false);
|
||||
if(sh < 0)
|
||||
return 999999;
|
||||
return sh;
|
||||
}
|
||||
|
||||
void ClosePositionTicket(const ulong ticket, const string reason)
|
||||
{
|
||||
trade.SetExpertMagicNumber(InpMagic);
|
||||
if(trade.PositionClose(ticket))
|
||||
Log("Close: " + reason);
|
||||
}
|
||||
|
||||
void ManageSuperEMAExits(const string sym)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0)
|
||||
continue;
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) != sym)
|
||||
continue;
|
||||
if((int)PositionGetInteger(POSITION_MAGIC) != InpMagic)
|
||||
continue;
|
||||
|
||||
ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
|
||||
double h1 = 0.0;
|
||||
if(!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 1, h1))
|
||||
continue;
|
||||
|
||||
bool closeLong = false;
|
||||
bool closeShort = false;
|
||||
string reason = "";
|
||||
|
||||
if(InpMaxHoldingBars > 0)
|
||||
{
|
||||
int held = BarsSinceOpen(sym, openTime);
|
||||
if(held >= InpMaxHoldingBars)
|
||||
{
|
||||
if(ptype == POSITION_TYPE_BUY)
|
||||
closeLong = true;
|
||||
else
|
||||
closeShort = true;
|
||||
reason = "time stop (max bars)";
|
||||
}
|
||||
}
|
||||
|
||||
if(ptype == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(InpExitOnTrendFlip && TrendDown(sym, InpEmaTrendBars))
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "trend flip (below slow EMA)";
|
||||
}
|
||||
if(InpExitOnMacdFlip && h1 < 0.0)
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "MACD histogram < 0";
|
||||
}
|
||||
if(InpExitOnCciZeroCross && CciCrossBelowZero(sym))
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "CCI crossed below zero";
|
||||
}
|
||||
if(InpExitBelowMidEma)
|
||||
{
|
||||
double c = iClose(sym, InpTimeframe, 1);
|
||||
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, 1);
|
||||
if(emaM > 0.0 && c < emaM)
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "close below mid EMA";
|
||||
}
|
||||
}
|
||||
if(closeLong)
|
||||
ClosePositionTicket(ticket, reason);
|
||||
}
|
||||
else if(ptype == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(InpExitOnTrendFlip && TrendUp(sym, InpEmaTrendBars))
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "trend flip (above slow EMA)";
|
||||
}
|
||||
if(InpExitOnMacdFlip && h1 > 0.0)
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "MACD histogram > 0";
|
||||
}
|
||||
if(InpExitOnCciZeroCross && CciCrossAboveZero(sym))
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "CCI crossed above zero";
|
||||
}
|
||||
if(InpExitBelowMidEma)
|
||||
{
|
||||
double c = iClose(sym, InpTimeframe, 1);
|
||||
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, 1);
|
||||
if(emaM > 0.0 && c > emaM)
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "close above mid EMA";
|
||||
}
|
||||
}
|
||||
if(closeShort)
|
||||
ClosePositionTicket(ticket, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
string sym = WorkSymbol();
|
||||
if(!SymbolSelect(sym, true))
|
||||
{
|
||||
Print("SuperEMA: cannot select symbol ", sym);
|
||||
return INIT_FAILED;
|
||||
}
|
||||
trade.SetExpertMagicNumber(InpMagic);
|
||||
trade.SetDeviationInPoints(InpSlippagePoints);
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
string sym = WorkSymbol();
|
||||
if(_Symbol != sym)
|
||||
{
|
||||
static datetime lastLog = 0;
|
||||
datetime tb = iTime(_Symbol, PERIOD_M1, 0);
|
||||
if(tb != lastLog && InpDebugLogs)
|
||||
{
|
||||
lastLog = tb;
|
||||
Log("Chart symbol differs from WorkSymbol; attach to " + sym + " or set InpSymbol empty.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!IsNewBar(sym, InpTimeframe))
|
||||
return;
|
||||
|
||||
// Exits must run every bar; do not skip when a position exists (otherwise trades never close with SL=0/TP=0).
|
||||
ManageSuperEMAExits(sym);
|
||||
|
||||
if(InpOneTradeOnly && PositionsByMagic(sym, InpMagic) > 0)
|
||||
return;
|
||||
|
||||
const int sh = InpEmaTrendBars;
|
||||
double h1 = 0.0, h2 = 0.0;
|
||||
if(!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 1, h1) ||
|
||||
!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 2, h2))
|
||||
return;
|
||||
|
||||
bool up = TrendUp(sym, sh);
|
||||
bool dn = TrendDown(sym, sh);
|
||||
|
||||
bool wantBuy = false;
|
||||
bool wantSell = false;
|
||||
|
||||
switch(InpEntryStyle)
|
||||
{
|
||||
case ENTRY_CCIZERO_MACD:
|
||||
if(up && CciCrossAboveZero(sym) && h1 > 0.0)
|
||||
wantBuy = true;
|
||||
if(dn && CciCrossBelowZero(sym) && h1 < 0.0)
|
||||
wantSell = true;
|
||||
break;
|
||||
|
||||
case ENTRY_LAMBERT:
|
||||
if(up && CciCrossAbove100(sym) && h1 > 0.0)
|
||||
wantBuy = true;
|
||||
if(dn && CciCrossBelowMinus100(sym) && h1 < 0.0)
|
||||
wantSell = true;
|
||||
break;
|
||||
|
||||
case ENTRY_PULLBACK:
|
||||
if(up && HadCciOversoldRecently(sym) && CciCrossAboveZero(sym) && h1 > 0.0 && PullbackNearFastEmaLong(sym))
|
||||
wantBuy = true;
|
||||
if(dn && HadCciOverboughtRecently(sym) && CciCrossBelowZero(sym) && h1 < 0.0 && PullbackNearFastEmaShort(sym))
|
||||
wantSell = true;
|
||||
break;
|
||||
}
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(sym, tick))
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
|
||||
if(wantBuy && !wantSell)
|
||||
{
|
||||
ComputeSLTP(true, tick.ask, sl, tp);
|
||||
if(trade.Buy(InpLots, sym, tick.ask, sl, tp, "SuperEMA long"))
|
||||
Log(StringFormat("BUY ask=%.5f sl=%.5f cci=%.2f macdHist=%.5f", tick.ask, sl,
|
||||
CciAt(sym, InpTimeframe, InpCciPeriod, 1), h1));
|
||||
}
|
||||
else if(wantSell && !wantBuy)
|
||||
{
|
||||
ComputeSLTP(false, tick.bid, sl, tp);
|
||||
if(trade.Sell(InpLots, sym, tick.bid, sl, tp, "SuperEMA short"))
|
||||
Log(StringFormat("SELL bid=%.5f sl=%.5f cci=%.2f macdHist=%.5f", tick.bid, sl,
|
||||
CciAt(sym, InpTimeframe, InpCciPeriod, 1), h1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,639 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| AdaptiveMonthlyRegime.mqh |
|
||||
//| Streak unit (input): closed calendar MONTHS or closed DAYS |
|
||||
//| (server time). Losing streak -> optional CANARY (next full month |
|
||||
//| or next full day at InpAdaptiveCanaryLotMult). Canary P/L > 0 -> |
|
||||
//| full size; else HARD PAUSE. CanaryLotMult==0 -> hard pause, no |
|
||||
//| canary. Per-strat DD lot cap still uses last closed *month* P/L. |
|
||||
//| Include after all `input` blocks. |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef ADAPTIVE_MONTHLY_REGIME_MQH
|
||||
#define ADAPTIVE_MONTHLY_REGIME_MQH
|
||||
|
||||
#define UNITED_ADAPTIVE_N 13
|
||||
#define UNITED_AD_MAX_DAY_BUCKETS 400
|
||||
|
||||
#define UNITED_AD_DARVAS 0
|
||||
#define UNITED_AD_ES 1
|
||||
#define UNITED_AD_RC 2
|
||||
#define UNITED_AD_RM 3
|
||||
#define UNITED_AD_RS_APPL 4
|
||||
#define UNITED_AD_RS_BTC 5
|
||||
#define UNITED_AD_RS_NVDA 6
|
||||
#define UNITED_AD_RS_TSLA 7
|
||||
#define UNITED_AD_RS_XAU 8
|
||||
#define UNITED_AD_RRA_EUR 9
|
||||
#define UNITED_AD_RRA_AUD 10
|
||||
#define UNITED_AD_RSS 11
|
||||
#define UNITED_AD_SUPEREMA 12
|
||||
|
||||
bool g_adHardPaused[UNITED_ADAPTIVE_N];
|
||||
bool g_adCanaryWaiting[UNITED_ADAPTIVE_N];
|
||||
bool g_adCanaryActive[UNITED_ADAPTIVE_N];
|
||||
datetime g_adCanaryMonthStart[UNITED_ADAPTIVE_N];
|
||||
datetime g_adCanaryMonthEnd[UNITED_ADAPTIVE_N];
|
||||
datetime g_adHardPauseUntil[UNITED_ADAPTIVE_N];
|
||||
datetime g_adPostCanaryCooldownUntil[UNITED_ADAPTIVE_N];
|
||||
|
||||
double g_adLastClosedMonthPl[UNITED_ADAPTIVE_N];
|
||||
|
||||
datetime g_unitedAdaptiveLastUpdate = 0;
|
||||
|
||||
string UnitedAdaptive_StratName(const int s)
|
||||
{
|
||||
const string names[] =
|
||||
{
|
||||
"DarvasBox", "EMASlope", "RSICrossOver", "RM_MidPoint",
|
||||
"RS_Scalp_AAPL", "RS_Scalp_BTC", "RS_Scalp_NVDA", "RS_Scalp_TSLA", "RS_Scalp_XAU",
|
||||
"RRA_EURUSD", "RRA_AUDUSD", "SecretSauce", "SuperEMA"
|
||||
};
|
||||
if(s >= 0 && s < UNITED_ADAPTIVE_N)
|
||||
return names[s];
|
||||
return "?";
|
||||
}
|
||||
|
||||
void UnitedAdaptive_Init()
|
||||
{
|
||||
for(int i = 0; i < UNITED_ADAPTIVE_N; i++)
|
||||
{
|
||||
g_adHardPaused[i] = false;
|
||||
g_adCanaryWaiting[i] = false;
|
||||
g_adCanaryActive[i] = false;
|
||||
g_adCanaryMonthStart[i] = 0;
|
||||
g_adCanaryMonthEnd[i] = 0;
|
||||
g_adHardPauseUntil[i] = 0;
|
||||
g_adPostCanaryCooldownUntil[i] = 0;
|
||||
g_adLastClosedMonthPl[i] = 0.0;
|
||||
}
|
||||
g_unitedAdaptiveLastUpdate = 0;
|
||||
}
|
||||
|
||||
datetime UnitedAdaptive_MonthStartInt(const int y, const int m)
|
||||
{
|
||||
MqlDateTime d;
|
||||
d.year = y;
|
||||
d.mon = m;
|
||||
d.day = 1;
|
||||
d.hour = 0;
|
||||
d.min = 0;
|
||||
d.sec = 0;
|
||||
return StructToTime(d);
|
||||
}
|
||||
|
||||
void UnitedAdaptive_NextYm(int &y, int &m)
|
||||
{
|
||||
m++;
|
||||
if(m > 12)
|
||||
{
|
||||
m = 1;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
void UnitedAdaptive_ClosedMonthYm(const int offsetFromLastComplete, int &y, int &m)
|
||||
{
|
||||
MqlDateTime now;
|
||||
TimeToStruct(TimeCurrent(), now);
|
||||
int ly = now.year;
|
||||
int lm = now.mon - 1;
|
||||
if(lm < 1)
|
||||
{
|
||||
lm = 12;
|
||||
ly--;
|
||||
}
|
||||
for(int i = 0; i < offsetFromLastComplete; i++)
|
||||
{
|
||||
lm--;
|
||||
if(lm < 1)
|
||||
{
|
||||
lm = 12;
|
||||
ly--;
|
||||
}
|
||||
}
|
||||
y = ly;
|
||||
m = lm;
|
||||
}
|
||||
|
||||
// Start of calendar day: offset 0 = yesterday 00:00 (last fully closed day), 1 = day before, ...
|
||||
datetime UnitedAdaptive_ClosedDayStart(const int offsetFromLastCompleteDay)
|
||||
{
|
||||
MqlDateTime n;
|
||||
TimeToStruct(TimeCurrent(), n);
|
||||
n.hour = 0;
|
||||
n.min = 0;
|
||||
n.sec = 0;
|
||||
const datetime today0 = StructToTime(n);
|
||||
return today0 - (datetime)((offsetFromLastCompleteDay + 1) * 86400);
|
||||
}
|
||||
|
||||
// Bucket index 0 = yesterday. -1 = today (incomplete) or invalid.
|
||||
int UnitedAdaptive_ClosedDayOffsetFromDealTime(const datetime dt)
|
||||
{
|
||||
MqlDateTime d, n;
|
||||
TimeToStruct(dt, d);
|
||||
d.hour = 0;
|
||||
d.min = 0;
|
||||
d.sec = 0;
|
||||
const datetime dealDay0 = StructToTime(d);
|
||||
TimeToStruct(TimeCurrent(), n);
|
||||
n.hour = 0;
|
||||
n.min = 0;
|
||||
n.sec = 0;
|
||||
const datetime today0 = StructToTime(n);
|
||||
const long deltaSec = (long)(today0 - dealDay0);
|
||||
if(deltaSec < 86400L)
|
||||
return -1;
|
||||
const int daysAgo = (int)(deltaSec / 86400L);
|
||||
return daysAgo - 1;
|
||||
}
|
||||
|
||||
datetime UnitedAdaptive_AddMonthsWallClock(const datetime dt0, const int months)
|
||||
{
|
||||
MqlDateTime t;
|
||||
TimeToStruct(dt0, t);
|
||||
for(int i = 0; i < months; i++)
|
||||
{
|
||||
t.mon++;
|
||||
if(t.mon > 12)
|
||||
{
|
||||
t.mon = 1;
|
||||
t.year++;
|
||||
}
|
||||
}
|
||||
return StructToTime(t);
|
||||
}
|
||||
|
||||
bool UnitedAdaptive_RMDealMatches(const long mg)
|
||||
{
|
||||
if(EnableRSIMidPointHijack)
|
||||
{
|
||||
if(RM_InpEnableRSIFollow && mg == (long)RM_InpMagicNumberRSIFollow)
|
||||
return true;
|
||||
if(RM_InpEnableRSIReverse && mg == (long)RM_InpMagicNumberRSIReverse)
|
||||
return true;
|
||||
if(RM_InpEnableEMACross && mg == (long)RM_InpMagicNumberEMACross)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnitedAdaptive_DealBelongsToStrat(const int s, const long mg)
|
||||
{
|
||||
if(s == UNITED_AD_DARVAS)
|
||||
return EnableDarvasBox && mg == (long)DB_MagicNumber;
|
||||
if(s == UNITED_AD_ES)
|
||||
return EnableEMASlopeDistance && mg == (long)ES_MagicNumber;
|
||||
if(s == UNITED_AD_RC)
|
||||
return EnableRSICrossOverReversal && mg == (long)RC_MagicNumber;
|
||||
if(s == UNITED_AD_RM)
|
||||
return UnitedAdaptive_RMDealMatches(mg);
|
||||
if(s == UNITED_AD_RS_APPL)
|
||||
return EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber;
|
||||
if(s == UNITED_AD_RS_BTC)
|
||||
return EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber;
|
||||
if(s == UNITED_AD_RS_NVDA)
|
||||
return EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber;
|
||||
if(s == UNITED_AD_RS_TSLA)
|
||||
return EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber;
|
||||
if(s == UNITED_AD_RS_XAU)
|
||||
return EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber;
|
||||
if(s == UNITED_AD_RRA_EUR)
|
||||
return EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber;
|
||||
if(s == UNITED_AD_RRA_AUD)
|
||||
return EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber;
|
||||
if(s == UNITED_AD_RSS)
|
||||
return EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber;
|
||||
if(s == UNITED_AD_SUPEREMA)
|
||||
return EnableSuperEMA && mg == (long)SE_MagicNumber;
|
||||
return false;
|
||||
}
|
||||
|
||||
double UnitedAdaptive_SumStratDealsRange(const int s, const datetime from, const datetime to)
|
||||
{
|
||||
if(from >= to)
|
||||
return 0.0;
|
||||
if(!HistorySelect(from, to))
|
||||
return 0.0;
|
||||
double sum = 0.0;
|
||||
const int n = HistoryDealsTotal();
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
const ulong t = HistoryDealGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
const long mg = (long)HistoryDealGetInteger(t, DEAL_MAGIC);
|
||||
if(!UnitedAdaptive_DealBelongsToStrat(s, mg))
|
||||
continue;
|
||||
sum += HistoryDealGetDouble(t, DEAL_PROFIT);
|
||||
sum += HistoryDealGetDouble(t, DEAL_SWAP);
|
||||
sum += HistoryDealGetDouble(t, DEAL_COMMISSION);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void UnitedAdaptive_StartCanaryWait(const int s)
|
||||
{
|
||||
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
|
||||
{
|
||||
MqlDateTime t;
|
||||
TimeToStruct(TimeCurrent(), t);
|
||||
t.hour = 0;
|
||||
t.min = 0;
|
||||
t.sec = 0;
|
||||
const datetime today0 = StructToTime(t);
|
||||
g_adCanaryMonthStart[s] = today0 + 86400;
|
||||
g_adCanaryMonthEnd[s] = g_adCanaryMonthStart[s] + 86400;
|
||||
g_adCanaryWaiting[s] = true;
|
||||
g_adCanaryActive[s] = false;
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" -> CANARY WAIT until ", TimeToString(g_adCanaryMonthStart[s], TIME_DATE),
|
||||
" then 1 day at lot x ", DoubleToString(InpAdaptiveCanaryLotMult, 4));
|
||||
return;
|
||||
}
|
||||
MqlDateTime t;
|
||||
TimeToStruct(TimeCurrent(), t);
|
||||
t.mon++;
|
||||
if(t.mon > 12)
|
||||
{
|
||||
t.mon = 1;
|
||||
t.year++;
|
||||
}
|
||||
t.day = 1;
|
||||
t.hour = 0;
|
||||
t.min = 0;
|
||||
t.sec = 0;
|
||||
g_adCanaryMonthStart[s] = StructToTime(t);
|
||||
int ey = t.year;
|
||||
int em = t.mon;
|
||||
UnitedAdaptive_NextYm(ey, em);
|
||||
g_adCanaryMonthEnd[s] = UnitedAdaptive_MonthStartInt(ey, em);
|
||||
g_adCanaryWaiting[s] = true;
|
||||
g_adCanaryActive[s] = false;
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" -> CANARY WAIT until ", TimeToString(g_adCanaryMonthStart[s], TIME_DATE),
|
||||
" then 1 month at lot x ", DoubleToString(InpAdaptiveCanaryLotMult, 4));
|
||||
}
|
||||
|
||||
void UnitedAdaptive_TryExpireHardPauses()
|
||||
{
|
||||
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
|
||||
{
|
||||
if(InpAdaptiveHardRetryDays <= 0)
|
||||
return;
|
||||
}
|
||||
else if(InpAdaptiveHardRetryMonths <= 0)
|
||||
return;
|
||||
|
||||
const datetime now = TimeCurrent();
|
||||
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
|
||||
{
|
||||
if(!g_adHardPaused[s])
|
||||
continue;
|
||||
if(g_adHardPauseUntil[s] > 0 && now >= g_adHardPauseUntil[s])
|
||||
{
|
||||
g_adHardPaused[s] = false;
|
||||
g_adHardPauseUntil[s] = 0;
|
||||
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" hard pause RETRY (after ", InpAdaptiveHardRetryDays, " d)");
|
||||
else
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" hard pause RETRY (after ", InpAdaptiveHardRetryMonths, " mo)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnitedAdaptive_ProcessCanaryTransitions()
|
||||
{
|
||||
if(!InpAdaptiveEnable)
|
||||
return;
|
||||
|
||||
UnitedAdaptive_TryExpireHardPauses();
|
||||
|
||||
const datetime now = TimeCurrent();
|
||||
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
|
||||
{
|
||||
if(g_adCanaryWaiting[s] && !g_adCanaryActive[s] && now >= g_adCanaryMonthStart[s])
|
||||
{
|
||||
g_adCanaryWaiting[s] = false;
|
||||
g_adCanaryActive[s] = true;
|
||||
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " CANARY ACTIVE (probation day)");
|
||||
else
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " CANARY ACTIVE (probation month)");
|
||||
}
|
||||
|
||||
if(g_adCanaryActive[s] && now >= g_adCanaryMonthEnd[s])
|
||||
{
|
||||
const double pl = UnitedAdaptive_SumStratDealsRange(s, g_adCanaryMonthStart[s], g_adCanaryMonthEnd[s]);
|
||||
g_adCanaryActive[s] = false;
|
||||
g_adCanaryWaiting[s] = false;
|
||||
if(pl > 0.0)
|
||||
{
|
||||
if(InpAdaptivePostCanaryCooldownDays > 0)
|
||||
g_adPostCanaryCooldownUntil[s] = TimeCurrent() + InpAdaptivePostCanaryCooldownDays * 86400;
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" canary OK P/L=", DoubleToString(pl, 2), " -> full size");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_adHardPaused[s] = true;
|
||||
if(InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY)
|
||||
{
|
||||
if(InpAdaptiveHardRetryDays > 0)
|
||||
g_adHardPauseUntil[s] = now + (datetime)InpAdaptiveHardRetryDays * 86400;
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" canary FAIL P/L=", DoubleToString(pl, 2), " -> HARD PAUSE",
|
||||
(InpAdaptiveHardRetryDays > 0 ? " (auto-retry later)" : ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(InpAdaptiveHardRetryMonths > 0)
|
||||
g_adHardPauseUntil[s] = UnitedAdaptive_AddMonthsWallClock(now, InpAdaptiveHardRetryMonths);
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" canary FAIL P/L=", DoubleToString(pl, 2), " -> HARD PAUSE",
|
||||
(InpAdaptiveHardRetryMonths > 0 ? " (auto-retry later)" : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UnitedAdaptive_StratLastMonthIsLosing(const int s)
|
||||
{
|
||||
if(s < 0 || s >= UNITED_ADAPTIVE_N)
|
||||
return false;
|
||||
const double thr = MathMax(0.0, InpDdLotCapStratLossThreshold);
|
||||
return g_adLastClosedMonthPl[s] < -thr;
|
||||
}
|
||||
|
||||
void UnitedAdaptive_RecomputeStreaks()
|
||||
{
|
||||
const bool needMonthPlCap = InpDdLotCapEnable && InpDdLotCapPerStratEnable;
|
||||
const bool adaptMonth = InpAdaptiveEnable && InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_MONTH;
|
||||
const bool adaptDay = InpAdaptiveEnable && InpAdaptiveStreakUnit == ADAPTIVE_STREAK_BY_DAY;
|
||||
|
||||
int nMonthOff = 0;
|
||||
int streakReqM = 1;
|
||||
if(adaptMonth)
|
||||
{
|
||||
streakReqM = MathMax(1, InpAdaptiveRedStreak);
|
||||
const int L = MathMax(InpAdaptiveLookbackMonths, streakReqM + 1);
|
||||
nMonthOff = MathMin(L, 63);
|
||||
}
|
||||
else if(needMonthPlCap)
|
||||
nMonthOff = 2;
|
||||
|
||||
int nDayOff = 0;
|
||||
int streakReqD = 1;
|
||||
if(adaptDay)
|
||||
{
|
||||
streakReqD = MathMax(1, InpAdaptiveRedStreak);
|
||||
const int L = MathMax(InpAdaptiveLookbackDays, streakReqD + 1);
|
||||
nDayOff = MathMin(L, UNITED_AD_MAX_DAY_BUCKETS);
|
||||
}
|
||||
|
||||
if(nMonthOff == 0 && nDayOff == 0)
|
||||
return;
|
||||
|
||||
const datetime to = TimeCurrent() + 60;
|
||||
datetime from = to;
|
||||
if(nMonthOff > 0)
|
||||
{
|
||||
int oy = 0, om = 0;
|
||||
UnitedAdaptive_ClosedMonthYm(nMonthOff - 1, oy, om);
|
||||
const datetime mf = UnitedAdaptive_MonthStartInt(oy, om);
|
||||
if(mf < from)
|
||||
from = mf;
|
||||
}
|
||||
if(nDayOff > 0)
|
||||
{
|
||||
const datetime df = UnitedAdaptive_ClosedDayStart(nDayOff - 1);
|
||||
if(df < from)
|
||||
from = df;
|
||||
}
|
||||
|
||||
if(from >= to || !HistorySelect(from, to))
|
||||
return;
|
||||
|
||||
double monthBuck[UNITED_ADAPTIVE_N][64];
|
||||
double dayBuck[UNITED_ADAPTIVE_N][UNITED_AD_MAX_DAY_BUCKETS];
|
||||
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
|
||||
{
|
||||
for(int o = 0; o < 64; o++)
|
||||
monthBuck[s][o] = 0.0;
|
||||
for(int o = 0; o < UNITED_AD_MAX_DAY_BUCKETS; o++)
|
||||
dayBuck[s][o] = 0.0;
|
||||
}
|
||||
|
||||
const int total = HistoryDealsTotal();
|
||||
for(int i = 0; i < total; i++)
|
||||
{
|
||||
const ulong tk = HistoryDealGetTicket(i);
|
||||
if(tk == 0)
|
||||
continue;
|
||||
const long mg = (long)HistoryDealGetInteger(tk, DEAL_MAGIC);
|
||||
const datetime dt = (datetime)HistoryDealGetInteger(tk, DEAL_TIME);
|
||||
const double pl = HistoryDealGetDouble(tk, DEAL_PROFIT)
|
||||
+ HistoryDealGetDouble(tk, DEAL_SWAP)
|
||||
+ HistoryDealGetDouble(tk, DEAL_COMMISSION);
|
||||
|
||||
if(nMonthOff > 0)
|
||||
{
|
||||
for(int o = 0; o < nMonthOff; o++)
|
||||
{
|
||||
int y = 0, m = 0;
|
||||
UnitedAdaptive_ClosedMonthYm(o, y, m);
|
||||
const datetime ms = UnitedAdaptive_MonthStartInt(y, m);
|
||||
int ny = y, nm = m;
|
||||
UnitedAdaptive_NextYm(ny, nm);
|
||||
const datetime me = UnitedAdaptive_MonthStartInt(ny, nm);
|
||||
if(dt < ms || dt >= me)
|
||||
continue;
|
||||
|
||||
if(EnableDarvasBox && mg == (long)DB_MagicNumber)
|
||||
monthBuck[UNITED_AD_DARVAS][o] += pl;
|
||||
if(EnableEMASlopeDistance && mg == (long)ES_MagicNumber)
|
||||
monthBuck[UNITED_AD_ES][o] += pl;
|
||||
if(EnableRSICrossOverReversal && mg == (long)RC_MagicNumber)
|
||||
monthBuck[UNITED_AD_RC][o] += pl;
|
||||
if(UnitedAdaptive_RMDealMatches(mg))
|
||||
monthBuck[UNITED_AD_RM][o] += pl;
|
||||
if(EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber)
|
||||
monthBuck[UNITED_AD_RS_APPL][o] += pl;
|
||||
if(EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber)
|
||||
monthBuck[UNITED_AD_RS_BTC][o] += pl;
|
||||
if(EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber)
|
||||
monthBuck[UNITED_AD_RS_NVDA][o] += pl;
|
||||
if(EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber)
|
||||
monthBuck[UNITED_AD_RS_TSLA][o] += pl;
|
||||
if(EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber)
|
||||
monthBuck[UNITED_AD_RS_XAU][o] += pl;
|
||||
if(EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber)
|
||||
monthBuck[UNITED_AD_RRA_EUR][o] += pl;
|
||||
if(EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber)
|
||||
monthBuck[UNITED_AD_RRA_AUD][o] += pl;
|
||||
if(EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber)
|
||||
monthBuck[UNITED_AD_RSS][o] += pl;
|
||||
if(EnableSuperEMA && mg == (long)SE_MagicNumber)
|
||||
monthBuck[UNITED_AD_SUPEREMA][o] += pl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nDayOff > 0)
|
||||
{
|
||||
const int dOff = UnitedAdaptive_ClosedDayOffsetFromDealTime(dt);
|
||||
if(dOff >= 0 && dOff < nDayOff)
|
||||
{
|
||||
if(EnableDarvasBox && mg == (long)DB_MagicNumber)
|
||||
dayBuck[UNITED_AD_DARVAS][dOff] += pl;
|
||||
if(EnableEMASlopeDistance && mg == (long)ES_MagicNumber)
|
||||
dayBuck[UNITED_AD_ES][dOff] += pl;
|
||||
if(EnableRSICrossOverReversal && mg == (long)RC_MagicNumber)
|
||||
dayBuck[UNITED_AD_RC][dOff] += pl;
|
||||
if(UnitedAdaptive_RMDealMatches(mg))
|
||||
dayBuck[UNITED_AD_RM][dOff] += pl;
|
||||
if(EnableRSIScalpingAPPL && mg == (long)RS_APPL_MagicNumber)
|
||||
dayBuck[UNITED_AD_RS_APPL][dOff] += pl;
|
||||
if(EnableRSIScalpingBTCUSD && mg == (long)RS_BTCUSD_MagicNumber)
|
||||
dayBuck[UNITED_AD_RS_BTC][dOff] += pl;
|
||||
if(EnableRSIScalpingNVDA && mg == (long)RS_NVDA_MagicNumber)
|
||||
dayBuck[UNITED_AD_RS_NVDA][dOff] += pl;
|
||||
if(EnableRSIScalpingTSLA && mg == (long)RS_TSLA_MagicNumber)
|
||||
dayBuck[UNITED_AD_RS_TSLA][dOff] += pl;
|
||||
if(EnableRSIScalpingXAUUSD && mg == (long)RS_XAUUSD_MagicNumber)
|
||||
dayBuck[UNITED_AD_RS_XAU][dOff] += pl;
|
||||
if(EnableRSIReversalEURUSD && mg == (long)RRA_EURUSD_MagicNumber)
|
||||
dayBuck[UNITED_AD_RRA_EUR][dOff] += pl;
|
||||
if(EnableRSIReversalAUDUSD && mg == (long)RRA_AUDUSD_MagicNumber)
|
||||
dayBuck[UNITED_AD_RRA_AUD][dOff] += pl;
|
||||
if(EnableRSISecretSauceXAUUSD && mg == (long)RSS_XAUUSD_MagicNumber)
|
||||
dayBuck[UNITED_AD_RSS][dOff] += pl;
|
||||
if(EnableSuperEMA && mg == (long)SE_MagicNumber)
|
||||
dayBuck[UNITED_AD_SUPEREMA][dOff] += pl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nMonthOff > 0)
|
||||
{
|
||||
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
|
||||
g_adLastClosedMonthPl[s] = monthBuck[s][0];
|
||||
}
|
||||
|
||||
if(!InpAdaptiveEnable)
|
||||
return;
|
||||
|
||||
const double thr = MathMax(0.0, InpAdaptiveRedThreshold);
|
||||
const bool useDay = adaptDay;
|
||||
const int streakReq = useDay ? streakReqD : streakReqM;
|
||||
const int nOff = useDay ? nDayOff : nMonthOff;
|
||||
|
||||
for(int s = 0; s < UNITED_ADAPTIVE_N; s++)
|
||||
{
|
||||
if(g_adHardPaused[s])
|
||||
continue;
|
||||
if(g_adCanaryActive[s] || g_adCanaryWaiting[s])
|
||||
{
|
||||
int consecOk = 0;
|
||||
for(int o = 0; o < streakReq && o < nOff; o++)
|
||||
{
|
||||
const double bpl = useDay ? dayBuck[s][o] : monthBuck[s][o];
|
||||
if(bpl < -thr)
|
||||
consecOk++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
const bool streakBad = (consecOk >= streakReq);
|
||||
if(!streakBad && g_adCanaryWaiting[s] && !g_adCanaryActive[s])
|
||||
{
|
||||
g_adCanaryWaiting[s] = false;
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s), " canary wait CANCELLED (streak cleared)");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int consec = 0;
|
||||
for(int o = 0; o < streakReq && o < nOff; o++)
|
||||
{
|
||||
const double bpl = useDay ? dayBuck[s][o] : monthBuck[s][o];
|
||||
if(bpl < -thr)
|
||||
consec++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
const bool streakBad = (consec >= streakReq);
|
||||
if(!streakBad)
|
||||
continue;
|
||||
|
||||
const bool prevHard = g_adHardPaused[s];
|
||||
if(InpAdaptiveCanaryLotMult > 0.0)
|
||||
{
|
||||
if(!g_adCanaryWaiting[s] && !g_adCanaryActive[s])
|
||||
{
|
||||
if(g_adPostCanaryCooldownUntil[s] > TimeCurrent())
|
||||
continue;
|
||||
UnitedAdaptive_StartCanaryWait(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_adHardPaused[s] = true;
|
||||
if(!prevHard && useDay && InpAdaptiveHardRetryDays > 0)
|
||||
g_adHardPauseUntil[s] = TimeCurrent() + (datetime)InpAdaptiveHardRetryDays * 86400;
|
||||
else if(!prevHard && !useDay && InpAdaptiveHardRetryMonths > 0)
|
||||
g_adHardPauseUntil[s] = UnitedAdaptive_AddMonthsWallClock(TimeCurrent(), InpAdaptiveHardRetryMonths);
|
||||
if(!prevHard)
|
||||
Print("AdaptiveRegime: ", UnitedAdaptive_StratName(s),
|
||||
" HARD PAUSE (streak, canary disabled)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnitedAdaptive_UpdateIfDue()
|
||||
{
|
||||
if(!InpAdaptiveEnable && (!InpDdLotCapEnable || !InpDdLotCapPerStratEnable))
|
||||
{
|
||||
UnitedAdaptive_Init();
|
||||
return;
|
||||
}
|
||||
|
||||
int everySec = 3600;
|
||||
if(InpAdaptiveEnable)
|
||||
everySec = MathMin(everySec, MathMax(60, InpAdaptiveUpdateSeconds));
|
||||
if(InpDdLotCapEnable && InpDdLotCapPerStratEnable)
|
||||
everySec = MathMin(everySec, MathMax(60, InpDdLotCapUpdateSeconds));
|
||||
|
||||
if(g_unitedAdaptiveLastUpdate > 0 && (TimeCurrent() - g_unitedAdaptiveLastUpdate) < everySec)
|
||||
return;
|
||||
|
||||
g_unitedAdaptiveLastUpdate = TimeCurrent();
|
||||
UnitedAdaptive_RecomputeStreaks();
|
||||
}
|
||||
|
||||
double UnitedAdaptive_GetLotMult(const int stratId)
|
||||
{
|
||||
if(stratId < 0 || stratId >= UNITED_ADAPTIVE_N)
|
||||
return 1.0;
|
||||
if(!InpAdaptiveEnable)
|
||||
return 1.0;
|
||||
if(g_adCanaryActive[stratId])
|
||||
return MathMax(0.0, InpAdaptiveCanaryLotMult);
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
bool UnitedAdaptive_StrategyActive(const int stratId)
|
||||
{
|
||||
if(stratId < 0 || stratId >= UNITED_ADAPTIVE_N)
|
||||
return true;
|
||||
if(!InpAdaptiveEnable)
|
||||
return true;
|
||||
if(g_adHardPaused[stratId])
|
||||
return false;
|
||||
if(g_adCanaryWaiting[stratId] && !g_adCanaryActive[stratId])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSISecretSauceStrategy.mqh |
|
||||
//| RSI Secret Sauce: leave 70/30 zone, re-enter, peak/bottom entry |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct RSISecretSauceData
|
||||
{
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
CTrade trade;
|
||||
CPositionInfo positionInfo;
|
||||
int rsiHandle;
|
||||
int atrHandle;
|
||||
double rsiBuffer[];
|
||||
double atrBuffer[];
|
||||
double highBuffer[];
|
||||
double lowBuffer[];
|
||||
bool rsiWasOverbought;
|
||||
bool rsiWasOversold;
|
||||
bool rsiBackInRange;
|
||||
datetime lastRSIExitTime;
|
||||
datetime lastRSIReentryTime;
|
||||
datetime lastTradeTime;
|
||||
datetime lastBarTime;
|
||||
ENUM_TIMEFRAMES timeframe;
|
||||
int rsiPeriod;
|
||||
double rsiOverbought;
|
||||
double rsiOversold;
|
||||
int rsiLookback;
|
||||
int peakBars;
|
||||
bool requireDivergence;
|
||||
double stopLossATR;
|
||||
double takeProfitATR;
|
||||
int atrPeriod;
|
||||
bool useSwingStopLoss;
|
||||
int swingLookback;
|
||||
int maxPositions;
|
||||
int minBarsBetweenTrades;
|
||||
int magicNumber;
|
||||
int slippage;
|
||||
};
|
||||
|
||||
bool RSS_UpdateIndicators(RSISecretSauceData& d);
|
||||
void RSS_UpdateRSIState(RSISecretSauceData& d);
|
||||
bool RSS_CanOpenNewPosition(RSISecretSauceData& d);
|
||||
void RSS_CheckEntrySignals(RSISecretSauceData& d, const double lotSize);
|
||||
bool RSS_IsRSIPeak(RSISecretSauceData& d);
|
||||
bool RSS_IsRSIBottom(RSISecretSauceData& d);
|
||||
void RSS_OpenPosition(RSISecretSauceData& d, ENUM_POSITION_TYPE type, const double lotSize);
|
||||
bool RSS_CalculateStops(RSISecretSauceData& d, double price, ENUM_POSITION_TYPE type, double& sl, double& tp);
|
||||
double RSS_GetSwingStopLoss(RSISecretSauceData& d, ENUM_POSITION_TYPE type);
|
||||
|
||||
bool InitRSISecretSauce(RSISecretSauceData& d,
|
||||
const string symbol,
|
||||
const ENUM_TIMEFRAMES timeframe,
|
||||
const int rsiPeriod,
|
||||
const double rsiOverbought,
|
||||
const double rsiOversold,
|
||||
const int rsiLookback,
|
||||
const int peakBars,
|
||||
const bool requireDivergence,
|
||||
const double stopLossATR,
|
||||
const double takeProfitATR,
|
||||
const int atrPeriod,
|
||||
const bool useSwingStopLoss,
|
||||
const int swingLookback,
|
||||
const int maxPositions,
|
||||
const int minBarsBetweenTrades,
|
||||
const int magicNumber,
|
||||
const int slippage)
|
||||
{
|
||||
d.symbol = symbol;
|
||||
if(StringLen(d.symbol) == 0)
|
||||
d.symbol = _Symbol;
|
||||
d.isInitialized = false;
|
||||
d.rsiHandle = INVALID_HANDLE;
|
||||
d.atrHandle = INVALID_HANDLE;
|
||||
d.rsiWasOverbought = false;
|
||||
d.rsiWasOversold = false;
|
||||
d.rsiBackInRange = false;
|
||||
d.lastRSIExitTime = 0;
|
||||
d.lastRSIReentryTime = 0;
|
||||
d.lastTradeTime = 0;
|
||||
d.lastBarTime = 0;
|
||||
|
||||
if(!SymbolSelect(d.symbol, true))
|
||||
{
|
||||
Print("RSISecretSauce: Symbol '", d.symbol, "' not available in Market Watch.");
|
||||
return false;
|
||||
}
|
||||
|
||||
d.timeframe = timeframe;
|
||||
d.rsiPeriod = rsiPeriod;
|
||||
d.rsiOverbought = rsiOverbought;
|
||||
d.rsiOversold = rsiOversold;
|
||||
d.rsiLookback = rsiLookback;
|
||||
d.peakBars = peakBars;
|
||||
d.requireDivergence = requireDivergence;
|
||||
d.stopLossATR = stopLossATR;
|
||||
d.takeProfitATR = takeProfitATR;
|
||||
d.atrPeriod = atrPeriod;
|
||||
d.useSwingStopLoss = useSwingStopLoss;
|
||||
d.swingLookback = swingLookback;
|
||||
d.maxPositions = maxPositions;
|
||||
d.minBarsBetweenTrades = minBarsBetweenTrades;
|
||||
d.magicNumber = magicNumber;
|
||||
d.slippage = slippage;
|
||||
|
||||
Sleep(100);
|
||||
int retry = 0;
|
||||
while(retry < 5 && d.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
d.rsiHandle = iRSI(d.symbol, d.timeframe, d.rsiPeriod, PRICE_CLOSE);
|
||||
if(d.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
if(GetLastError() == 4805 && retry < 4)
|
||||
{
|
||||
Sleep(1000);
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
Print("RSISecretSauce: Failed to create RSI for '", d.symbol, "'");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
retry = 0;
|
||||
while(retry < 5 && d.atrHandle == INVALID_HANDLE)
|
||||
{
|
||||
d.atrHandle = iATR(d.symbol, d.timeframe, d.atrPeriod);
|
||||
if(d.atrHandle == INVALID_HANDLE)
|
||||
{
|
||||
if(GetLastError() == 4805 && retry < 4)
|
||||
{
|
||||
Sleep(1000);
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
Print("RSISecretSauce: Failed to create ATR for '", d.symbol, "'");
|
||||
IndicatorRelease(d.rsiHandle);
|
||||
d.rsiHandle = INVALID_HANDLE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ArraySetAsSeries(d.rsiBuffer, true);
|
||||
ArraySetAsSeries(d.atrBuffer, true);
|
||||
ArraySetAsSeries(d.highBuffer, true);
|
||||
ArraySetAsSeries(d.lowBuffer, true);
|
||||
|
||||
d.trade.SetExpertMagicNumber(d.magicNumber);
|
||||
d.trade.SetDeviationInPoints(d.slippage);
|
||||
d.trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
d.isInitialized = true;
|
||||
Print("RSISecretSauce: Initialized for '", d.symbol, "' TF=", EnumToString(d.timeframe));
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitRSISecretSauce(RSISecretSauceData& d)
|
||||
{
|
||||
if(d.rsiHandle != INVALID_HANDLE)
|
||||
IndicatorRelease(d.rsiHandle);
|
||||
if(d.atrHandle != INVALID_HANDLE)
|
||||
IndicatorRelease(d.atrHandle);
|
||||
d.rsiHandle = INVALID_HANDLE;
|
||||
d.atrHandle = INVALID_HANDLE;
|
||||
d.isInitialized = false;
|
||||
}
|
||||
|
||||
bool RSS_UpdateIndicators(RSISecretSauceData& d)
|
||||
{
|
||||
int rsiBarsNeeded = d.rsiLookback + 5;
|
||||
if(CopyBuffer(d.rsiHandle, 0, 0, rsiBarsNeeded, d.rsiBuffer) < rsiBarsNeeded)
|
||||
return false;
|
||||
if(CopyBuffer(d.atrHandle, 0, 0, 2, d.atrBuffer) < 2)
|
||||
return false;
|
||||
if(CopyHigh(d.symbol, d.timeframe, 0, d.swingLookback + 5, d.highBuffer) < d.swingLookback + 5)
|
||||
return false;
|
||||
if(CopyLow(d.symbol, d.timeframe, 0, d.swingLookback + 5, d.lowBuffer) < d.swingLookback + 5)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RSS_UpdateRSIState(RSISecretSauceData& d)
|
||||
{
|
||||
double rsiCurrent = d.rsiBuffer[0];
|
||||
double rsiPrev = d.rsiBuffer[1];
|
||||
|
||||
if(rsiPrev >= d.rsiOverbought && rsiCurrent < d.rsiOverbought)
|
||||
{
|
||||
d.rsiWasOverbought = true;
|
||||
d.rsiBackInRange = true;
|
||||
d.lastRSIExitTime = TimeCurrent();
|
||||
d.lastRSIReentryTime = TimeCurrent();
|
||||
}
|
||||
|
||||
if(rsiPrev <= d.rsiOversold && rsiCurrent > d.rsiOversold)
|
||||
{
|
||||
d.rsiWasOversold = true;
|
||||
d.rsiBackInRange = true;
|
||||
d.lastRSIExitTime = TimeCurrent();
|
||||
d.lastRSIReentryTime = TimeCurrent();
|
||||
}
|
||||
|
||||
if(rsiCurrent >= d.rsiOverbought)
|
||||
{
|
||||
d.rsiWasOverbought = false;
|
||||
d.rsiBackInRange = false;
|
||||
}
|
||||
|
||||
if(rsiCurrent <= d.rsiOversold)
|
||||
{
|
||||
d.rsiWasOversold = false;
|
||||
d.rsiBackInRange = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RSS_CanOpenNewPosition(RSISecretSauceData& d)
|
||||
{
|
||||
int positionCount = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
if(d.positionInfo.SelectByIndex(i))
|
||||
{
|
||||
if(d.positionInfo.Symbol() == d.symbol && d.positionInfo.Magic() == d.magicNumber)
|
||||
positionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(positionCount >= d.maxPositions)
|
||||
return false;
|
||||
|
||||
if(d.lastTradeTime > 0)
|
||||
{
|
||||
int barsSince = Bars(d.symbol, d.timeframe, d.lastTradeTime, TimeCurrent());
|
||||
if(barsSince < d.minBarsBetweenTrades)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RSS_IsRSIPeak(RSISecretSauceData& d)
|
||||
{
|
||||
if(ArraySize(d.rsiBuffer) < d.peakBars + 2)
|
||||
return false;
|
||||
|
||||
double currentRSI = d.rsiBuffer[0];
|
||||
bool isPeak = true;
|
||||
|
||||
for(int i = 1; i <= d.peakBars; i++)
|
||||
{
|
||||
if(d.rsiBuffer[i] >= currentRSI)
|
||||
{
|
||||
isPeak = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(d.rsiBuffer[1] >= currentRSI)
|
||||
isPeak = false;
|
||||
|
||||
return isPeak;
|
||||
}
|
||||
|
||||
bool RSS_IsRSIBottom(RSISecretSauceData& d)
|
||||
{
|
||||
if(ArraySize(d.rsiBuffer) < d.peakBars + 2)
|
||||
return false;
|
||||
|
||||
double currentRSI = d.rsiBuffer[0];
|
||||
bool isBottom = true;
|
||||
|
||||
for(int i = 1; i <= d.peakBars; i++)
|
||||
{
|
||||
if(d.rsiBuffer[i] <= currentRSI)
|
||||
{
|
||||
isBottom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(d.rsiBuffer[1] <= currentRSI)
|
||||
isBottom = false;
|
||||
|
||||
return isBottom;
|
||||
}
|
||||
|
||||
void RSS_CheckEntrySignals(RSISecretSauceData& d, const double lotSize)
|
||||
{
|
||||
if(d.rsiWasOverbought && d.rsiBackInRange)
|
||||
{
|
||||
if(d.rsiBuffer[0] < d.rsiOverbought)
|
||||
{
|
||||
if(RSS_IsRSIPeak(d))
|
||||
RSS_OpenPosition(d, POSITION_TYPE_BUY, lotSize);
|
||||
}
|
||||
}
|
||||
|
||||
if(d.rsiWasOversold && d.rsiBackInRange)
|
||||
{
|
||||
if(d.rsiBuffer[0] > d.rsiOversold)
|
||||
{
|
||||
if(RSS_IsRSIBottom(d))
|
||||
RSS_OpenPosition(d, POSITION_TYPE_SELL, lotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RSS_CalculateStops(RSISecretSauceData& d, double price, ENUM_POSITION_TYPE type, double& sl, double& tp)
|
||||
{
|
||||
double atrValue = d.atrBuffer[0];
|
||||
if(atrValue <= 0)
|
||||
atrValue = price * 0.01;
|
||||
|
||||
double slDistance = atrValue * d.stopLossATR;
|
||||
double tpDistance = atrValue * d.takeProfitATR;
|
||||
|
||||
int digits = (int)SymbolInfoInteger(d.symbol, SYMBOL_DIGITS);
|
||||
double point = SymbolInfoDouble(d.symbol, SYMBOL_POINT);
|
||||
int stopsLevel = (int)SymbolInfoInteger(d.symbol, SYMBOL_TRADE_STOPS_LEVEL);
|
||||
double minStopDistance = MathMax(stopsLevel * point, point * 10);
|
||||
|
||||
if(d.useSwingStopLoss)
|
||||
{
|
||||
double swingStop = RSS_GetSwingStopLoss(d, type);
|
||||
if(swingStop > 0)
|
||||
{
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(swingStop < price && (price - swingStop) > minStopDistance)
|
||||
slDistance = price - swingStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(swingStop > price && (swingStop - price) > minStopDistance)
|
||||
slDistance = swingStop - price;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(slDistance < minStopDistance)
|
||||
slDistance = minStopDistance;
|
||||
if(tpDistance < minStopDistance)
|
||||
tpDistance = minStopDistance;
|
||||
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
{
|
||||
sl = NormalizeDouble(price - slDistance, digits);
|
||||
tp = NormalizeDouble(price + tpDistance, digits);
|
||||
}
|
||||
else
|
||||
{
|
||||
sl = NormalizeDouble(price + slDistance, digits);
|
||||
tp = NormalizeDouble(price - tpDistance, digits);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double RSS_GetSwingStopLoss(RSISecretSauceData& d, ENUM_POSITION_TYPE type)
|
||||
{
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double lowestLow = d.lowBuffer[0];
|
||||
for(int i = 1; i < d.swingLookback && i < ArraySize(d.lowBuffer); i++)
|
||||
{
|
||||
if(d.lowBuffer[i] < lowestLow)
|
||||
lowestLow = d.lowBuffer[i];
|
||||
}
|
||||
return lowestLow;
|
||||
}
|
||||
|
||||
double highestHigh = d.highBuffer[0];
|
||||
for(int i = 1; i < d.swingLookback && i < ArraySize(d.highBuffer); i++)
|
||||
{
|
||||
if(d.highBuffer[i] > highestHigh)
|
||||
highestHigh = d.highBuffer[i];
|
||||
}
|
||||
return highestHigh;
|
||||
}
|
||||
|
||||
void RSS_OpenPosition(RSISecretSauceData& d, ENUM_POSITION_TYPE type, const double lotSize)
|
||||
{
|
||||
double price = (type == POSITION_TYPE_BUY) ?
|
||||
SymbolInfoDouble(d.symbol, SYMBOL_ASK) :
|
||||
SymbolInfoDouble(d.symbol, SYMBOL_BID);
|
||||
|
||||
if(price <= 0)
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(!RSS_CalculateStops(d, price, type, sl, tp))
|
||||
return;
|
||||
|
||||
string comment = "RSI_Secret_" + (type == POSITION_TYPE_BUY ? "LONG" : "SHORT");
|
||||
|
||||
bool result = false;
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
result = d.trade.Buy(lotSize, d.symbol, 0, sl, tp, comment);
|
||||
else
|
||||
result = d.trade.Sell(lotSize, d.symbol, 0, sl, tp, comment);
|
||||
|
||||
if(result)
|
||||
{
|
||||
d.lastTradeTime = TimeCurrent();
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
d.rsiWasOverbought = false;
|
||||
else
|
||||
d.rsiWasOversold = false;
|
||||
d.rsiBackInRange = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessRSISecretSauce(RSISecretSauceData& d, const double lotSize)
|
||||
{
|
||||
if(!d.isInitialized)
|
||||
return;
|
||||
|
||||
int requiredBars = MathMax(d.rsiLookback, d.swingLookback) + 10;
|
||||
if(Bars(d.symbol, d.timeframe) < requiredBars)
|
||||
return;
|
||||
|
||||
datetime currentBarTime = iTime(d.symbol, d.timeframe, 0);
|
||||
if(currentBarTime == d.lastBarTime)
|
||||
return;
|
||||
|
||||
d.lastBarTime = currentBarTime;
|
||||
|
||||
if(!RSS_UpdateIndicators(d))
|
||||
return;
|
||||
|
||||
RSS_UpdateRSIState(d);
|
||||
|
||||
if(RSS_CanOpenNewPosition(d))
|
||||
RSS_CheckEntrySignals(d, lotSize);
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SuperEMAStrategy.mqh — EMA + CCI + MACD (United EA module) |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef SUPER_EMA_STRATEGY_MQH
|
||||
#define SUPER_EMA_STRATEGY_MQH
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
enum ENUM_SE_ENTRY_STYLE
|
||||
{
|
||||
SE_ENTRY_CCIZERO_MACD = 0,
|
||||
SE_ENTRY_LAMBERT = 1,
|
||||
SE_ENTRY_PULLBACK = 2
|
||||
};
|
||||
|
||||
struct SuperEMAData
|
||||
{
|
||||
string symbol;
|
||||
ENUM_TIMEFRAMES tf;
|
||||
datetime lastBarTime;
|
||||
CTrade trade;
|
||||
bool isInitialized;
|
||||
int slippagePoints;
|
||||
int magic;
|
||||
int emaFast;
|
||||
int emaMid;
|
||||
int emaSlow;
|
||||
int emaTrendBars;
|
||||
int cciPeriod;
|
||||
double cciOverbought;
|
||||
double cciOversold;
|
||||
int pullbackCciLookback;
|
||||
int macdFast;
|
||||
int macdSlow;
|
||||
int macdSignal;
|
||||
ENUM_SE_ENTRY_STYLE entryStyle;
|
||||
bool oneTradeOnly;
|
||||
bool useStructuralSL;
|
||||
double slBufferPoints;
|
||||
bool exitOnTrendFlip;
|
||||
bool exitOnMacdFlip;
|
||||
bool exitOnCciZeroCross;
|
||||
int maxHoldingBars;
|
||||
bool exitBelowMidEma;
|
||||
bool debugLogs;
|
||||
};
|
||||
|
||||
void SuperEMA_Log(SuperEMAData &d, const string s)
|
||||
{
|
||||
if(d.debugLogs)
|
||||
Print("[SuperEMA] ", s);
|
||||
}
|
||||
|
||||
bool SuperEMA_IsNewBar(SuperEMAData &d)
|
||||
{
|
||||
datetime t = iTime(d.symbol, d.tf, 0);
|
||||
if(t <= 0 || t == d.lastBarTime)
|
||||
return false;
|
||||
d.lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
double SuperEMA_EmaAt(SuperEMAData &d, const int period, const int shift)
|
||||
{
|
||||
int h = iMA(d.symbol, d.tf, period, 0, MODE_EMA, PRICE_CLOSE);
|
||||
if(h == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double b[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return 0.0;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
double SuperEMA_CciAt(SuperEMAData &d, const int shift)
|
||||
{
|
||||
int h = iCCI(d.symbol, d.tf, d.cciPeriod, PRICE_TYPICAL);
|
||||
if(h == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double b[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return 0.0;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
bool SuperEMA_MacdHistAt(SuperEMAData &d, const int shift, double &hist)
|
||||
{
|
||||
int h = iMACD(d.symbol, d.tf, d.macdFast, d.macdSlow, d.macdSignal, PRICE_CLOSE);
|
||||
if(h == INVALID_HANDLE)
|
||||
return false;
|
||||
double mainLine[1], sigLine[1];
|
||||
if(CopyBuffer(h, 0, shift, 1, mainLine) <= 0 || CopyBuffer(h, 1, shift, 1, sigLine) <= 0)
|
||||
{
|
||||
IndicatorRelease(h);
|
||||
return false;
|
||||
}
|
||||
IndicatorRelease(h);
|
||||
hist = mainLine[0] - sigLine[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SuperEMA_TrendUp(SuperEMAData &d, const int sh)
|
||||
{
|
||||
double c = iClose(d.symbol, d.tf, sh);
|
||||
double emaS = SuperEMA_EmaAt(d, d.emaSlow, sh);
|
||||
return (emaS > 0.0 && c > emaS);
|
||||
}
|
||||
|
||||
bool SuperEMA_TrendDown(SuperEMAData &d, const int sh)
|
||||
{
|
||||
double c = iClose(d.symbol, d.tf, sh);
|
||||
double emaS = SuperEMA_EmaAt(d, d.emaSlow, sh);
|
||||
return (emaS > 0.0 && c < emaS);
|
||||
}
|
||||
|
||||
bool SuperEMA_CciCrossAboveZero(SuperEMAData &d)
|
||||
{
|
||||
double c1 = SuperEMA_CciAt(d, 1);
|
||||
double c2 = SuperEMA_CciAt(d, 2);
|
||||
return (c2 <= 0.0 && c1 > 0.0);
|
||||
}
|
||||
|
||||
bool SuperEMA_CciCrossBelowZero(SuperEMAData &d)
|
||||
{
|
||||
double c1 = SuperEMA_CciAt(d, 1);
|
||||
double c2 = SuperEMA_CciAt(d, 2);
|
||||
return (c2 >= 0.0 && c1 < 0.0);
|
||||
}
|
||||
|
||||
bool SuperEMA_CciCrossAbove100(SuperEMAData &d)
|
||||
{
|
||||
double c1 = SuperEMA_CciAt(d, 1);
|
||||
double c2 = SuperEMA_CciAt(d, 2);
|
||||
return (c2 < d.cciOverbought && c1 > d.cciOverbought);
|
||||
}
|
||||
|
||||
bool SuperEMA_CciCrossBelowMinus100(SuperEMAData &d)
|
||||
{
|
||||
double c1 = SuperEMA_CciAt(d, 1);
|
||||
double c2 = SuperEMA_CciAt(d, 2);
|
||||
return (c2 > d.cciOversold && c1 < d.cciOversold);
|
||||
}
|
||||
|
||||
bool SuperEMA_HadCciOversoldRecently(SuperEMAData &d)
|
||||
{
|
||||
for(int i = 2; i <= d.pullbackCciLookback + 1; i++)
|
||||
{
|
||||
double v = SuperEMA_CciAt(d, i);
|
||||
if(v <= d.cciOversold)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SuperEMA_HadCciOverboughtRecently(SuperEMAData &d)
|
||||
{
|
||||
for(int i = 2; i <= d.pullbackCciLookback + 1; i++)
|
||||
{
|
||||
double v = SuperEMA_CciAt(d, i);
|
||||
if(v >= d.cciOverbought)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SuperEMA_PullbackNearFastEmaLong(SuperEMAData &d)
|
||||
{
|
||||
double emaF = SuperEMA_EmaAt(d, d.emaFast, 1);
|
||||
double lo = iLow(d.symbol, d.tf, 1);
|
||||
if(emaF <= 0.0)
|
||||
return false;
|
||||
return (lo <= emaF + d.slBufferPoints * _Point * 3.0);
|
||||
}
|
||||
|
||||
bool SuperEMA_PullbackNearFastEmaShort(SuperEMAData &d)
|
||||
{
|
||||
double emaF = SuperEMA_EmaAt(d, d.emaFast, 1);
|
||||
double hi = iHigh(d.symbol, d.tf, 1);
|
||||
if(emaF <= 0.0)
|
||||
return false;
|
||||
return (hi >= emaF - d.slBufferPoints * _Point * 3.0);
|
||||
}
|
||||
|
||||
int SuperEMA_PositionsByMagic(SuperEMAData &d)
|
||||
{
|
||||
int n = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == d.symbol && (int)PositionGetInteger(POSITION_MAGIC) == d.magic)
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void SuperEMA_ComputeSLTP(SuperEMAData &d, const bool isBuy, double &sl, double &tp)
|
||||
{
|
||||
sl = 0.0;
|
||||
tp = 0.0;
|
||||
if(!d.useStructuralSL)
|
||||
return;
|
||||
double emaM = SuperEMA_EmaAt(d, d.emaMid, d.emaTrendBars);
|
||||
double buf = d.slBufferPoints * _Point;
|
||||
if(isBuy)
|
||||
sl = emaM - buf;
|
||||
else
|
||||
sl = emaM + buf;
|
||||
}
|
||||
|
||||
int SuperEMA_BarsSinceOpen(SuperEMAData &d, const datetime openTime)
|
||||
{
|
||||
if(openTime <= 0)
|
||||
return 0;
|
||||
int sh = iBarShift(d.symbol, d.tf, openTime, false);
|
||||
if(sh < 0)
|
||||
return 999999;
|
||||
return sh;
|
||||
}
|
||||
|
||||
void SuperEMA_CloseTicket(SuperEMAData &d, const ulong ticket, const string reason)
|
||||
{
|
||||
d.trade.SetExpertMagicNumber(d.magic);
|
||||
if(d.trade.PositionClose(ticket))
|
||||
SuperEMA_Log(d, "Close: " + reason);
|
||||
}
|
||||
|
||||
void SuperEMA_ManageExits(SuperEMAData &d)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0)
|
||||
continue;
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) != d.symbol)
|
||||
continue;
|
||||
if((int)PositionGetInteger(POSITION_MAGIC) != d.magic)
|
||||
continue;
|
||||
|
||||
ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
|
||||
double h1 = 0.0;
|
||||
if(!SuperEMA_MacdHistAt(d, 1, h1))
|
||||
continue;
|
||||
|
||||
bool closeLong = false;
|
||||
bool closeShort = false;
|
||||
string reason = "";
|
||||
|
||||
if(d.maxHoldingBars > 0)
|
||||
{
|
||||
int held = SuperEMA_BarsSinceOpen(d, openTime);
|
||||
if(held >= d.maxHoldingBars)
|
||||
{
|
||||
if(ptype == POSITION_TYPE_BUY)
|
||||
closeLong = true;
|
||||
else
|
||||
closeShort = true;
|
||||
reason = "time stop (max bars)";
|
||||
}
|
||||
}
|
||||
|
||||
if(ptype == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(d.exitOnTrendFlip && SuperEMA_TrendDown(d, d.emaTrendBars))
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "trend flip (below slow EMA)";
|
||||
}
|
||||
if(d.exitOnMacdFlip && h1 < 0.0)
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "MACD histogram < 0";
|
||||
}
|
||||
if(d.exitOnCciZeroCross && SuperEMA_CciCrossBelowZero(d))
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "CCI crossed below zero";
|
||||
}
|
||||
if(d.exitBelowMidEma)
|
||||
{
|
||||
double c = iClose(d.symbol, d.tf, 1);
|
||||
double emaM = SuperEMA_EmaAt(d, d.emaMid, 1);
|
||||
if(emaM > 0.0 && c < emaM)
|
||||
{
|
||||
closeLong = true;
|
||||
reason = "close below mid EMA";
|
||||
}
|
||||
}
|
||||
if(closeLong)
|
||||
SuperEMA_CloseTicket(d, ticket, reason);
|
||||
}
|
||||
else if(ptype == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(d.exitOnTrendFlip && SuperEMA_TrendUp(d, d.emaTrendBars))
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "trend flip (above slow EMA)";
|
||||
}
|
||||
if(d.exitOnMacdFlip && h1 > 0.0)
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "MACD histogram > 0";
|
||||
}
|
||||
if(d.exitOnCciZeroCross && SuperEMA_CciCrossAboveZero(d))
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "CCI crossed above zero";
|
||||
}
|
||||
if(d.exitBelowMidEma)
|
||||
{
|
||||
double c = iClose(d.symbol, d.tf, 1);
|
||||
double emaM = SuperEMA_EmaAt(d, d.emaMid, 1);
|
||||
if(emaM > 0.0 && c > emaM)
|
||||
{
|
||||
closeShort = true;
|
||||
reason = "close above mid EMA";
|
||||
}
|
||||
}
|
||||
if(closeShort)
|
||||
SuperEMA_CloseTicket(d, ticket, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InitSuperEMA(SuperEMAData &d,
|
||||
const string symbol,
|
||||
const ENUM_TIMEFRAMES tf,
|
||||
const int slippagePoints,
|
||||
const int magic,
|
||||
const int emaFast,
|
||||
const int emaMid,
|
||||
const int emaSlow,
|
||||
const int emaTrendBars,
|
||||
const int cciPeriod,
|
||||
const double cciOverbought,
|
||||
const double cciOversold,
|
||||
const int pullbackCciLookback,
|
||||
const int macdFast,
|
||||
const int macdSlow,
|
||||
const int macdSignal,
|
||||
const ENUM_SE_ENTRY_STYLE entryStyle,
|
||||
const bool oneTradeOnly,
|
||||
const bool useStructuralSL,
|
||||
const double slBufferPoints,
|
||||
const bool exitOnTrendFlip,
|
||||
const bool exitOnMacdFlip,
|
||||
const bool exitOnCciZeroCross,
|
||||
const int maxHoldingBars,
|
||||
const bool exitBelowMidEma,
|
||||
const bool debugLogs)
|
||||
{
|
||||
d.symbol = symbol;
|
||||
if(StringLen(d.symbol) == 0)
|
||||
d.symbol = _Symbol;
|
||||
d.tf = tf;
|
||||
d.lastBarTime = 0;
|
||||
d.isInitialized = false;
|
||||
d.slippagePoints = slippagePoints;
|
||||
d.magic = magic;
|
||||
d.emaFast = emaFast;
|
||||
d.emaMid = emaMid;
|
||||
d.emaSlow = emaSlow;
|
||||
d.emaTrendBars = emaTrendBars;
|
||||
d.cciPeriod = cciPeriod;
|
||||
d.cciOverbought = cciOverbought;
|
||||
d.cciOversold = cciOversold;
|
||||
d.pullbackCciLookback = pullbackCciLookback;
|
||||
d.macdFast = macdFast;
|
||||
d.macdSlow = macdSlow;
|
||||
d.macdSignal = macdSignal;
|
||||
d.entryStyle = entryStyle;
|
||||
d.oneTradeOnly = oneTradeOnly;
|
||||
d.useStructuralSL = useStructuralSL;
|
||||
d.slBufferPoints = slBufferPoints;
|
||||
d.exitOnTrendFlip = exitOnTrendFlip;
|
||||
d.exitOnMacdFlip = exitOnMacdFlip;
|
||||
d.exitOnCciZeroCross = exitOnCciZeroCross;
|
||||
d.maxHoldingBars = maxHoldingBars;
|
||||
d.exitBelowMidEma = exitBelowMidEma;
|
||||
d.debugLogs = debugLogs;
|
||||
|
||||
if(!SymbolSelect(d.symbol, true))
|
||||
{
|
||||
Print("SuperEMA: symbol not available: ", d.symbol);
|
||||
return false;
|
||||
}
|
||||
d.trade.SetExpertMagicNumber(d.magic);
|
||||
d.trade.SetDeviationInPoints(d.slippagePoints);
|
||||
d.isInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessSuperEMA(SuperEMAData &d, const double lots)
|
||||
{
|
||||
if(!d.isInitialized)
|
||||
return;
|
||||
|
||||
if(!SuperEMA_IsNewBar(d))
|
||||
return;
|
||||
|
||||
SuperEMA_ManageExits(d);
|
||||
|
||||
if(d.oneTradeOnly && SuperEMA_PositionsByMagic(d) > 0)
|
||||
return;
|
||||
|
||||
const int sh = d.emaTrendBars;
|
||||
double h1 = 0.0, h2 = 0.0;
|
||||
if(!SuperEMA_MacdHistAt(d, 1, h1) || !SuperEMA_MacdHistAt(d, 2, h2))
|
||||
return;
|
||||
|
||||
bool up = SuperEMA_TrendUp(d, sh);
|
||||
bool dn = SuperEMA_TrendDown(d, sh);
|
||||
|
||||
bool wantBuy = false;
|
||||
bool wantSell = false;
|
||||
|
||||
switch(d.entryStyle)
|
||||
{
|
||||
case SE_ENTRY_CCIZERO_MACD:
|
||||
if(up && SuperEMA_CciCrossAboveZero(d) && h1 > 0.0)
|
||||
wantBuy = true;
|
||||
if(dn && SuperEMA_CciCrossBelowZero(d) && h1 < 0.0)
|
||||
wantSell = true;
|
||||
break;
|
||||
|
||||
case SE_ENTRY_LAMBERT:
|
||||
if(up && SuperEMA_CciCrossAbove100(d) && h1 > 0.0)
|
||||
wantBuy = true;
|
||||
if(dn && SuperEMA_CciCrossBelowMinus100(d) && h1 < 0.0)
|
||||
wantSell = true;
|
||||
break;
|
||||
|
||||
case SE_ENTRY_PULLBACK:
|
||||
if(up && SuperEMA_HadCciOversoldRecently(d) && SuperEMA_CciCrossAboveZero(d) && h1 > 0.0 && SuperEMA_PullbackNearFastEmaLong(d))
|
||||
wantBuy = true;
|
||||
if(dn && SuperEMA_HadCciOverboughtRecently(d) && SuperEMA_CciCrossBelowZero(d) && h1 < 0.0 && SuperEMA_PullbackNearFastEmaShort(d))
|
||||
wantSell = true;
|
||||
break;
|
||||
}
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(d.symbol, tick))
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
|
||||
if(wantBuy && !wantSell)
|
||||
{
|
||||
SuperEMA_ComputeSLTP(d, true, sl, tp);
|
||||
if(d.trade.Buy(lots, d.symbol, tick.ask, sl, tp, "United SuperEMA long"))
|
||||
SuperEMA_Log(d, StringFormat("BUY ask=%.5f sl=%.5f", tick.ask, sl));
|
||||
}
|
||||
else if(wantSell && !wantBuy)
|
||||
{
|
||||
SuperEMA_ComputeSLTP(d, false, sl, tp);
|
||||
if(d.trade.Sell(lots, d.symbol, tick.bid, sl, tp, "United SuperEMA short"))
|
||||
SuperEMA_Log(d, StringFormat("SELL bid=%.5f sl=%.5f", tick.bid, sl));
|
||||
}
|
||||
}
|
||||
|
||||
void DeinitSuperEMA(SuperEMAData &d)
|
||||
{
|
||||
d.isInitialized = false;
|
||||
}
|
||||
|
||||
#endif // SUPER_EMA_STRATEGY_MQH
|
||||
@@ -0,0 +1,437 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| UnitedProfitPanel.mqh — chart object P&L by strategy / magic |
|
||||
//| One OBJ_LABEL per line (MT5 often ignores \n in a single label). |
|
||||
//| Include only after all United EA `input` declarations. |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef UNITED_PROFIT_PANEL_MQH
|
||||
#define UNITED_PROFIT_PANEL_MQH
|
||||
|
||||
#define UNITED_PNL_MAX_LINES 48
|
||||
|
||||
struct UnitedPnLRow
|
||||
{
|
||||
string name;
|
||||
long magic;
|
||||
};
|
||||
|
||||
UnitedPnLRow g_unitedPnLRows[];
|
||||
int g_unitedPnLRowCount = 0;
|
||||
int g_unitedPnL_visibleLineCount = 0;
|
||||
|
||||
string UnitedPnL_Obj(const string suffix) { return "UnitedPnL_" + suffix; }
|
||||
|
||||
long UnitedPnL_ChartId() { return ChartID(); }
|
||||
|
||||
string UnitedPnL_LineObjName(const int idx) { return UnitedPnL_Obj("L") + IntegerToString(idx); }
|
||||
|
||||
datetime UnitedPnL_StartOfYear(const datetime now)
|
||||
{
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(now, dt);
|
||||
dt.mon = 1;
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
return StructToTime(dt);
|
||||
}
|
||||
|
||||
datetime UnitedPnL_StartOfMonth(const datetime now)
|
||||
{
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(now, dt);
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
return StructToTime(dt);
|
||||
}
|
||||
|
||||
int UnitedPnL_FindRowIndex(const long magic)
|
||||
{
|
||||
for(int r = 0; r < g_unitedPnLRowCount; r++)
|
||||
{
|
||||
if(g_unitedPnLRows[r].magic == magic)
|
||||
return r;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool UnitedPnL_ScanDealsOnce(double &yearPl[], double &monthPl[], const datetime y0, const datetime m0, const datetime now)
|
||||
{
|
||||
const int R = g_unitedPnLRowCount;
|
||||
ArrayResize(yearPl, R);
|
||||
ArrayResize(monthPl, R);
|
||||
for(int j = 0; j < R; j++)
|
||||
{
|
||||
yearPl[j] = 0.0;
|
||||
monthPl[j] = 0.0;
|
||||
}
|
||||
|
||||
if(R <= 0 || y0 >= now)
|
||||
return true;
|
||||
|
||||
datetime to = now;
|
||||
if(to <= y0)
|
||||
to = y0 + 1;
|
||||
|
||||
if(!HistorySelect(y0, to))
|
||||
return false;
|
||||
|
||||
const int n = HistoryDealsTotal();
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
const ulong dealTicket = HistoryDealGetTicket(i);
|
||||
if(dealTicket == 0)
|
||||
continue;
|
||||
|
||||
const long mg = (long)HistoryDealGetInteger(dealTicket, DEAL_MAGIC);
|
||||
const int idx = UnitedPnL_FindRowIndex(mg);
|
||||
if(idx < 0)
|
||||
continue;
|
||||
|
||||
const datetime dt = (datetime)HistoryDealGetInteger(dealTicket, DEAL_TIME);
|
||||
const double p = HistoryDealGetDouble(dealTicket, DEAL_PROFIT)
|
||||
+ HistoryDealGetDouble(dealTicket, DEAL_SWAP)
|
||||
+ HistoryDealGetDouble(dealTicket, DEAL_COMMISSION);
|
||||
|
||||
yearPl[idx] += p;
|
||||
if(dt >= m0)
|
||||
monthPl[idx] += p;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double UnitedPnL_SumFloatingForMagic(const long magic)
|
||||
{
|
||||
double sum = 0.0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
const ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0)
|
||||
continue;
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
if((long)PositionGetInteger(POSITION_MAGIC) != magic)
|
||||
continue;
|
||||
sum += PositionGetDouble(POSITION_PROFIT);
|
||||
sum += PositionGetDouble(POSITION_SWAP);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void UnitedPnL_CollectRows()
|
||||
{
|
||||
g_unitedPnLRowCount = 0;
|
||||
ArrayResize(g_unitedPnLRows, 24);
|
||||
|
||||
if(EnableDarvasBox)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "DarvasBox";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)DB_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableEMASlopeDistance)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "EMASlope";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)ES_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSICrossOverReversal)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RSICrossOver";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RC_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIMidPointHijack)
|
||||
{
|
||||
if(RM_InpEnableRSIFollow)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RM_RSIFollow";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RM_InpMagicNumberRSIFollow;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(RM_InpEnableRSIReverse)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RM_RSIRev";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RM_InpMagicNumberRSIReverse;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(RM_InpEnableEMACross)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RM_EMACross";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RM_InpMagicNumberEMACross;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
}
|
||||
if(EnableRSIScalpingAPPL)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RS_Scalp_AAPL";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RS_APPL_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIScalpingBTCUSD)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RS_Scalp_BTC";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RS_BTCUSD_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIScalpingNVDA)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RS_Scalp_NVDA";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RS_NVDA_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIScalpingTSLA)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RS_Scalp_TSLA";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RS_TSLA_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RS_Scalp_XAU";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RS_XAUUSD_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIReversalEURUSD)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RRA_EURUSD";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RRA_EURUSD_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSIReversalAUDUSD)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "RRA_AUDUSD";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RRA_AUDUSD_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableRSISecretSauceXAUUSD)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "SecretSauce";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)RSS_XAUUSD_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
if(EnableSuperEMA)
|
||||
{
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].name = "SuperEMA";
|
||||
g_unitedPnLRows[g_unitedPnLRowCount].magic = (long)SE_MagicNumber;
|
||||
g_unitedPnLRowCount++;
|
||||
}
|
||||
|
||||
ArrayResize(g_unitedPnLRows, MathMax(g_unitedPnLRowCount, 1));
|
||||
}
|
||||
|
||||
void UnitedPnL_EnsureObjects()
|
||||
{
|
||||
const long ch = UnitedPnL_ChartId();
|
||||
const string bg = UnitedPnL_Obj("BG");
|
||||
if(ObjectFind(ch, bg) < 0)
|
||||
{
|
||||
if(!ObjectCreate(ch, bg, OBJ_RECTANGLE_LABEL, 0, 0, 0))
|
||||
{
|
||||
Print("UnitedPnL: BG ObjectCreate failed, err=", GetLastError());
|
||||
return;
|
||||
}
|
||||
ObjectSetInteger(ch, bg, OBJPROP_BORDER_TYPE, BORDER_FLAT);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_COLOR, C'90,90,90');
|
||||
ObjectSetInteger(ch, bg, OBJPROP_BGCOLOR, C'25,25,30');
|
||||
ObjectSetInteger(ch, bg, OBJPROP_WIDTH, 1);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_BACK, false);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_SELECTABLE, false);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_HIDDEN, false);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_ZORDER, 0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < UNITED_PNL_MAX_LINES; i++)
|
||||
{
|
||||
const string nm = UnitedPnL_LineObjName(i);
|
||||
if(ObjectFind(ch, nm) >= 0)
|
||||
continue;
|
||||
if(!ObjectCreate(ch, nm, OBJ_LABEL, 0, 0, 0))
|
||||
{
|
||||
Print("UnitedPnL: line ", i, " ObjectCreate failed, err=", GetLastError());
|
||||
continue;
|
||||
}
|
||||
ObjectSetString(ch, nm, OBJPROP_FONT, "Arial");
|
||||
ObjectSetInteger(ch, nm, OBJPROP_FONTSIZE, UnitedPanel_FontSize);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_BACK, false);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_SELECTABLE, false);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_HIDDEN, false);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_ZORDER, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitedPnL_ApplyGeometry()
|
||||
{
|
||||
if(!UnitedPanel_Enable)
|
||||
return;
|
||||
const long ch = UnitedPnL_ChartId();
|
||||
const string bg = UnitedPnL_Obj("BG");
|
||||
if(ObjectFind(ch, bg) < 0)
|
||||
return;
|
||||
|
||||
const int lineH = UnitedPanel_FontSize + 5;
|
||||
const int vis = MathMax(g_unitedPnL_visibleLineCount, 6);
|
||||
const int h = UnitedPanel_YMargin * 2 + lineH * vis;
|
||||
|
||||
const ENUM_BASE_CORNER corner = (ENUM_BASE_CORNER)UnitedPanel_Corner;
|
||||
ObjectSetInteger(ch, bg, OBJPROP_CORNER, corner);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_XDISTANCE, UnitedPanel_X);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_YDISTANCE, UnitedPanel_Y);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_XSIZE, UnitedPanel_Width);
|
||||
ObjectSetInteger(ch, bg, OBJPROP_YSIZE, MathMax(h, 80));
|
||||
|
||||
const int baseX = UnitedPanel_X + UnitedPanel_XMargin;
|
||||
const int baseY = UnitedPanel_Y + UnitedPanel_YMargin;
|
||||
for(int i = 0; i < UNITED_PNL_MAX_LINES; i++)
|
||||
{
|
||||
const string nm = UnitedPnL_LineObjName(i);
|
||||
if(ObjectFind(ch, nm) < 0)
|
||||
continue;
|
||||
ObjectSetInteger(ch, nm, OBJPROP_CORNER, corner);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_XDISTANCE, baseX);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_YDISTANCE, baseY + i * lineH);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_FONTSIZE, UnitedPanel_FontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitedPnL_RefreshText()
|
||||
{
|
||||
const long ch = UnitedPnL_ChartId();
|
||||
const string bg = UnitedPnL_Obj("BG");
|
||||
if(ObjectFind(ch, bg) < 0)
|
||||
return;
|
||||
|
||||
UnitedPnL_CollectRows();
|
||||
|
||||
const datetime now = TimeCurrent();
|
||||
const datetime y0 = UnitedPnL_StartOfYear(now);
|
||||
const datetime m0 = UnitedPnL_StartOfMonth(now);
|
||||
const string cur = AccountInfoString(ACCOUNT_CURRENCY);
|
||||
|
||||
double yearPl[];
|
||||
double monthPl[];
|
||||
const bool histOk = UnitedPnL_ScanDealsOnce(yearPl, monthPl, y0, m0, now);
|
||||
const string histNote = histOk ? "" : " [hist fail: Toolbox>History]";
|
||||
|
||||
double sumY = 0.0, sumM = 0.0, sumF = 0.0;
|
||||
|
||||
string lines[];
|
||||
int n = 0;
|
||||
ArrayResize(lines, UNITED_PNL_MAX_LINES);
|
||||
|
||||
lines[n++] = "United EA " + cur + histNote;
|
||||
lines[n++] = UnitedPanel_ShowFloating
|
||||
? "Y/M = closed deals | F = open P/L+swap"
|
||||
: "Y/M = closed deal P/L+swap+comm";
|
||||
lines[n++] = "----------------------------------";
|
||||
|
||||
for(int r = 0; r < g_unitedPnLRowCount; r++)
|
||||
{
|
||||
const long mg = g_unitedPnLRows[r].magic;
|
||||
double yv = 0.0, mv = 0.0;
|
||||
if(histOk && r < ArraySize(yearPl))
|
||||
yv = yearPl[r];
|
||||
if(histOk && r < ArraySize(monthPl))
|
||||
mv = monthPl[r];
|
||||
const double fv = UnitedPanel_ShowFloating ? UnitedPnL_SumFloatingForMagic(mg) : 0.0;
|
||||
sumY += yv;
|
||||
sumM += mv;
|
||||
sumF += fv;
|
||||
}
|
||||
|
||||
string tot = "TOTAL Y:" + DoubleToString(sumY, 2) + " M:" + DoubleToString(sumM, 2);
|
||||
if(UnitedPanel_ShowFloating)
|
||||
tot += " F:" + DoubleToString(sumF, 2);
|
||||
lines[n++] = tot;
|
||||
lines[n++] = "----------------------------------";
|
||||
|
||||
if(g_unitedPnLRowCount == 0)
|
||||
lines[n++] = "(no strategies enabled)";
|
||||
else
|
||||
{
|
||||
for(int r = 0; r < g_unitedPnLRowCount; r++)
|
||||
{
|
||||
if(n >= UNITED_PNL_MAX_LINES - 1)
|
||||
break;
|
||||
const long mg = g_unitedPnLRows[r].magic;
|
||||
double yv = 0.0, mv = 0.0;
|
||||
if(histOk && r < ArraySize(yearPl))
|
||||
yv = yearPl[r];
|
||||
if(histOk && r < ArraySize(monthPl))
|
||||
mv = monthPl[r];
|
||||
const double fv = UnitedPanel_ShowFloating ? UnitedPnL_SumFloatingForMagic(mg) : 0.0;
|
||||
|
||||
lines[n++] = g_unitedPnLRows[r].name + " [" + IntegerToString((int)mg) + "]";
|
||||
string row2 = " Y:" + DoubleToString(yv, 2) + " M:" + DoubleToString(mv, 2);
|
||||
if(UnitedPanel_ShowFloating)
|
||||
row2 += " F:" + DoubleToString(fv, 2);
|
||||
lines[n++] = row2;
|
||||
}
|
||||
}
|
||||
|
||||
g_unitedPnL_visibleLineCount = n;
|
||||
|
||||
color c = clrSilver;
|
||||
if(sumM > 0.0001)
|
||||
c = clrPaleGreen;
|
||||
else if(sumM < -0.0001)
|
||||
c = clrTomato;
|
||||
|
||||
for(int i = 0; i < UNITED_PNL_MAX_LINES; i++)
|
||||
{
|
||||
const string nm = UnitedPnL_LineObjName(i);
|
||||
if(ObjectFind(ch, nm) < 0)
|
||||
continue;
|
||||
if(i < n)
|
||||
{
|
||||
ObjectSetString(ch, nm, OBJPROP_TEXT, lines[i]);
|
||||
ObjectSetInteger(ch, nm, OBJPROP_COLOR, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectSetString(ch, nm, OBJPROP_TEXT, "");
|
||||
}
|
||||
}
|
||||
|
||||
UnitedPnL_ApplyGeometry();
|
||||
ChartRedraw(ch);
|
||||
}
|
||||
|
||||
void UnitedProfitPanelInit()
|
||||
{
|
||||
if(!UnitedPanel_Enable)
|
||||
return;
|
||||
UnitedPnL_EnsureObjects();
|
||||
UnitedPnL_CollectRows();
|
||||
g_unitedPnL_visibleLineCount = 6;
|
||||
UnitedPnL_ApplyGeometry();
|
||||
UnitedPnL_RefreshText();
|
||||
}
|
||||
|
||||
void UnitedProfitPanelDeinit()
|
||||
{
|
||||
ObjectsDeleteAll(UnitedPnL_ChartId(), "UnitedPnL_");
|
||||
}
|
||||
|
||||
void UnitedProfitPanelRefresh()
|
||||
{
|
||||
if(!UnitedPanel_Enable)
|
||||
return;
|
||||
UnitedPnL_RefreshText();
|
||||
}
|
||||
|
||||
void UnitedProfitPanelOnChartEvent(const int id)
|
||||
{
|
||||
if(!UnitedPanel_Enable)
|
||||
return;
|
||||
if(id == CHARTEVENT_CHART_CHANGE)
|
||||
{
|
||||
UnitedPnL_CollectRows();
|
||||
UnitedPnL_ApplyGeometry();
|
||||
ChartRedraw(UnitedPnL_ChartId());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,7 @@
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.07"
|
||||
#property version "1.17"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
@@ -20,6 +20,8 @@ double g_RC_LotSize;
|
||||
double g_RM_LotSize;
|
||||
double g_DB_LotSize;
|
||||
double g_DynMultLast = 1.0;
|
||||
double g_equityPeakHighWater = 0.0; // for drawdown lot cap (updated each tick via Refresh)
|
||||
datetime g_ddLotCapAnchorTime = 0; // tester/attach start — grace period before DD cap may apply
|
||||
|
||||
// Include strategy implementations early so structs are available
|
||||
#include "Strategies/DarvasBoxStrategy.mqh"
|
||||
@@ -28,6 +30,8 @@ double g_DynMultLast = 1.0;
|
||||
#include "Strategies/RSIMidPointHijackStrategy.mqh"
|
||||
#include "Strategies/RSIScalpingStrategy.mqh"
|
||||
#include "Strategies/RSIReversalAsianStrategy.mqh"
|
||||
#include "Strategies/RSISecretSauceStrategy.mqh"
|
||||
#include "Strategies/SuperEMAStrategy.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy Enable/Disable Switches |
|
||||
@@ -42,8 +46,41 @@ input bool EnableRSIScalpingBTCUSD = true;
|
||||
input bool EnableRSIScalpingNVDA = true;
|
||||
input bool EnableRSIScalpingTSLA = true;
|
||||
input bool EnableRSIScalpingXAUUSD = true;
|
||||
input bool EnableRSIReversalAsianEURUSD = true;
|
||||
input bool EnableRSIReversalAsianAUDUSD = true;
|
||||
input bool EnableRSIReversalEURUSD = true; // RSI Reversal Asian session (EURUSD)
|
||||
input bool EnableRSIReversalAUDUSD = true; // RSI Reversal Asian session (AUDUSD)
|
||||
input bool EnableRSISecretSauceXAUUSD = true;
|
||||
input bool EnableSuperEMA = true;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SuperEMA — EMA + CCI + MACD (XAUUSD default) |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== SuperEMA (EMA + CCI + MACD) ==="
|
||||
input string SE_Symbol = "XAUUSD";
|
||||
input ENUM_TIMEFRAMES SE_Timeframe = PERIOD_M15;
|
||||
input double SE_LotSize = 0.01;
|
||||
input int SE_SlippagePoints = 55;
|
||||
input int SE_MagicNumber = 940001;
|
||||
input int SE_EmaFast = 40;
|
||||
input int SE_EmaMid = 180;
|
||||
input int SE_EmaSlow = 125;
|
||||
input int SE_EmaTrendBars = 3;
|
||||
input int SE_CciPeriod = 17;
|
||||
input double SE_CciOverbought = 80.0;
|
||||
input double SE_CciOversold = -140.0;
|
||||
input int SE_PullbackCciLookback = 20;
|
||||
input int SE_MacdFast = 14;
|
||||
input int SE_MacdSlow = 38;
|
||||
input int SE_MacdSignal = 9;
|
||||
input ENUM_SE_ENTRY_STYLE SE_EntryStyle = SE_ENTRY_LAMBERT;
|
||||
input bool SE_OneTradeOnly = true;
|
||||
input bool SE_UseStructuralSL = false;
|
||||
input double SE_SlBufferPoints = 110;
|
||||
input bool SE_ExitOnTrendFlip = false;
|
||||
input bool SE_ExitOnMacdFlip = false;
|
||||
input bool SE_ExitOnCciZeroCross = true;
|
||||
input int SE_MaxHoldingBars = 168;
|
||||
input bool SE_ExitBelowMidEma = false;
|
||||
input bool SE_DebugLogs = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot sizing — scale base lots vs reference deposit |
|
||||
@@ -58,6 +95,21 @@ input double InpDynamicMaxMult = 0.0; // <=0 动态倍数不封
|
||||
input bool InpDynamicUseEquity = true; // true=ACCOUNT_EQUITY, false=ACCOUNT_BALANCE
|
||||
input double InpDynamicStockLotCap = 0.0; // Extra cap for stock CFDs (0 = none)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Lot cap: optional account-wide DD from peak, and/or per-strategy |
|
||||
//| (last *closed* calendar month losing for that magic). |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Drawdown / loser lot cap ==="
|
||||
input bool InpDdLotCapEnable = true; // master: allow clamping when a mode below triggers
|
||||
input bool InpDdLotCapGlobalEquityEnable = false; // cap *all* robots when equity DD from peak >= X% (after grace)
|
||||
input bool InpDdLotCapPerStratEnable = true; // cap only robots whose last closed month was red (by magic)
|
||||
input bool InpDdLotCapUseEquity = true; // true=ACCOUNT_EQUITY, false=BALANCE (global mode + peak tracking)
|
||||
input double InpDdLotCapFromPeakPercent = 7.0; // global: trigger if (peak-equity)/peak*100 >= this
|
||||
input double InpDdLotCapMaxLots = 0.01; // max volume per order while that mode is triggered
|
||||
input int InpDdLotCapGraceDays = 90; // global only: wait N days from attach before DD cap can apply (0=immediate)
|
||||
input double InpDdLotCapStratLossThreshold = 0.0; // per-strat: month P/L < -this counts as losing (0 = any loss)
|
||||
input int InpDdLotCapUpdateSeconds = 3600; // min 60; refresh last-month P/L when adaptive monthly is off
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 1: DarvasBoxXAUUSD |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -267,12 +319,34 @@ input int RS_XAUUSD_MagicNumber = 129102315;
|
||||
input int RS_XAUUSD_Slippage = 3;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 11-12: RSI Reversal Asian Strategies |
|
||||
//| Each RSI Reversal Asian strategy trades on its own symbol: |
|
||||
//| - EURUSD: Euro/USD |
|
||||
//| - AUDUSD: Australian Dollar/USD |
|
||||
//| Strategy: RSI Secret Sauce XAUUSD (leave zone → re-entry peak/bottom) |
|
||||
//| Defaults match secret_sauce.set except symbol stays XAUUSD here. |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI Reversal Asian EURUSD ==="
|
||||
input group "=== RSI Secret Sauce XAUUSD ==="
|
||||
input string RSS_XAUUSD_Symbol = "XAUUSD"; // not BTCUSD — gold chart / portfolio default
|
||||
input double RSS_XAUUSD_LotSize = 0.1;
|
||||
input int RSS_XAUUSD_MagicNumber = 789012;
|
||||
input int RSS_XAUUSD_Slippage = 10;
|
||||
input ENUM_TIMEFRAMES RSS_XAUUSD_Timeframe = PERIOD_M30;
|
||||
input int RSS_XAUUSD_RSIPeriod = 16;
|
||||
input double RSS_XAUUSD_RSIOverbought = 72.5;
|
||||
input double RSS_XAUUSD_RSIOversold = 32.5;
|
||||
input int RSS_XAUUSD_RSILookback = 60;
|
||||
input int RSS_XAUUSD_PeakBars = 2;
|
||||
input bool RSS_XAUUSD_RequireDivergence = false;
|
||||
input double RSS_XAUUSD_StopLossATR = 2.75;
|
||||
input double RSS_XAUUSD_TakeProfitATR = 5.0;
|
||||
input int RSS_XAUUSD_ATRPeriod = 14;
|
||||
input bool RSS_XAUUSD_UseSwingStopLoss = false;
|
||||
input int RSS_XAUUSD_SwingLookback = 30;
|
||||
input int RSS_XAUUSD_MaxPositions = 1;
|
||||
input int RSS_XAUUSD_MinBarsBetweenTrades = 7;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 11-12: RSI Reversal (Asian session) EURUSD & AUDUSD |
|
||||
//| Same logic as RSIReversalAsianEURUSD / RSIReversalAsianAUDUSD EAs |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI Reversal EURUSD (Asian session) ==="
|
||||
input string RRA_EURUSD_Symbol = "EURUSD";
|
||||
input int RRA_EURUSD_RSIPeriod = 28;
|
||||
input double RRA_EURUSD_OverboughtLevel = 60;
|
||||
@@ -291,7 +365,7 @@ input ENUM_TIMEFRAMES RRA_EURUSD_TimeFrame = PERIOD_M15;
|
||||
input int RRA_EURUSD_MagicNumber = 30001;
|
||||
input int RRA_EURUSD_Slippage = 3;
|
||||
|
||||
input group "=== RSI Reversal Asian AUDUSD ==="
|
||||
input group "=== RSI Reversal AUDUSD (Asian session) ==="
|
||||
input string RRA_AUDUSD_Symbol = "AUDUSD";
|
||||
input int RRA_AUDUSD_RSIPeriod = 28;
|
||||
input double RRA_AUDUSD_OverboughtLevel = 68;
|
||||
@@ -310,6 +384,46 @@ input ENUM_TIMEFRAMES RRA_AUDUSD_TimeFrame = PERIOD_M15;
|
||||
input int RRA_AUDUSD_MagicNumber = 30002;
|
||||
input int RRA_AUDUSD_Slippage = 3;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Chart panel: closed-deal P&L by strategy (magic) + optional open |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Chart profit panel (by magic) ==="
|
||||
input bool UnitedPanel_Enable = false; // OBJ_LABEL + background on chart
|
||||
input int UnitedPanel_Seconds = 60; // refresh interval (min 5); history scan once per tick
|
||||
input int UnitedPanel_Corner = 0; // ENUM_BASE_CORNER e.g. 0=left upper
|
||||
input int UnitedPanel_X = 8;
|
||||
input int UnitedPanel_Y = 24;
|
||||
input int UnitedPanel_Width = 360;
|
||||
input int UnitedPanel_FontSize = 9;
|
||||
input int UnitedPanel_XMargin = 6;
|
||||
input int UnitedPanel_YMargin = 6;
|
||||
input bool UnitedPanel_ShowFloating = false; // open P/L+swap per magic
|
||||
|
||||
enum ENUM_ADAPTIVE_STREAK_UNIT
|
||||
{
|
||||
ADAPTIVE_STREAK_BY_MONTH = 0, // consecutive closed calendar months
|
||||
ADAPTIVE_STREAK_BY_DAY = 1 // consecutive closed calendar days (server time)
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Pause strategies after consecutive losing periods (month or day)|
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Adaptive regime (per robot / magic) ==="
|
||||
input bool InpAdaptiveEnable = true; // If false, every other InpAdaptive* input is ignored (no streak / canary / pause). Set true to optimize or use adaptive regime.
|
||||
input ENUM_ADAPTIVE_STREAK_UNIT InpAdaptiveStreakUnit = ADAPTIVE_STREAK_BY_DAY;
|
||||
input int InpAdaptiveRedStreak = 5; // consecutive red months OR red days (see streak unit)
|
||||
input double InpAdaptiveRedThreshold = 0.0; // period P/L < -threshold counts red (0 = any loss)
|
||||
input int InpAdaptiveLookbackMonths = 14; // if unit=MONTH: history depth in months (>= streak+1)
|
||||
input int InpAdaptiveLookbackDays = 36; // if unit=DAY: closed days of history (>= streak+1)
|
||||
input int InpAdaptiveUpdateSeconds = 3600; // min 60; how often to recompute
|
||||
input double InpAdaptiveCanaryLotMult = 0.07; // probation: scale lots (0 = hard pause on streak, no canary)
|
||||
input int InpAdaptiveHardRetryMonths = 3; // if unit=MONTH: 0=no auto retry; else retry after N months
|
||||
input int InpAdaptiveHardRetryDays = 32; // if unit=DAY: 0=no auto retry; else retry after N days
|
||||
input int InpAdaptivePostCanaryCooldownDays = 37; // after successful canary, block re-arming another canary (days)
|
||||
|
||||
#include "UnitedProfitPanel.mqh"
|
||||
#include "AdaptiveMonthlyRegime.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - DarvasBox |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -412,6 +526,8 @@ RSIScalpingData rsXAUUSDData;
|
||||
//+------------------------------------------------------------------+
|
||||
RSIReversalAsianData rraEURUSDData;
|
||||
RSIReversalAsianData rraAUDUSDData;
|
||||
RSISecretSauceData rsSecretSauceXAUUSDData;
|
||||
SuperEMAData seData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot helpers |
|
||||
@@ -444,6 +560,53 @@ double NormalizeVolumeForSymbol(const string symbol, double lots)
|
||||
return lots;
|
||||
}
|
||||
|
||||
void UpdateEquityPeakForDdCap()
|
||||
{
|
||||
if(!InpDdLotCapEnable || !InpDdLotCapGlobalEquityEnable)
|
||||
return;
|
||||
const double cur = InpDdLotCapUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(cur > g_equityPeakHighWater)
|
||||
g_equityPeakHighWater = cur;
|
||||
}
|
||||
|
||||
// After dynamic sizing: global equity DD and/or per-strategy last-month loser -> clamp to InpDdLotCapMaxLots.
|
||||
double LotsAfterDrawdownCap(const string symbol, const double lotsRaw, const int ddStratId = -1)
|
||||
{
|
||||
double lots = NormalizeVolumeForSymbol(symbol, lotsRaw);
|
||||
if(!InpDdLotCapEnable)
|
||||
return lots;
|
||||
|
||||
bool needCap = false;
|
||||
|
||||
if(InpDdLotCapGlobalEquityEnable)
|
||||
{
|
||||
bool globalCheck = true;
|
||||
if(InpDdLotCapGraceDays > 0 && g_ddLotCapAnchorTime > 0)
|
||||
{
|
||||
const long needSec = (long)InpDdLotCapGraceDays * 86400L;
|
||||
if((long)(TimeCurrent() - g_ddLotCapAnchorTime) < needSec)
|
||||
globalCheck = false;
|
||||
}
|
||||
if(globalCheck && g_equityPeakHighWater > 0.0)
|
||||
{
|
||||
const double cur = InpDdLotCapUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(cur < g_equityPeakHighWater)
|
||||
{
|
||||
const double ddPct = 100.0 * (g_equityPeakHighWater - cur) / g_equityPeakHighWater;
|
||||
if(ddPct >= InpDdLotCapFromPeakPercent)
|
||||
needCap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(InpDdLotCapPerStratEnable && ddStratId >= 0 && UnitedAdaptive_StratLastMonthIsLosing(ddStratId))
|
||||
needCap = true;
|
||||
|
||||
if(!needCap)
|
||||
return lots;
|
||||
return NormalizeVolumeForSymbol(symbol, MathMin(lots, InpDdLotCapMaxLots));
|
||||
}
|
||||
|
||||
double GetDynamicMultiplier()
|
||||
{
|
||||
if(!InpDynamicLotEnable)
|
||||
@@ -460,31 +623,33 @@ double GetDynamicMultiplier()
|
||||
}
|
||||
|
||||
// baseLot = size at reference deposit; optionalCap 0 = no extra ceiling (broker min/max still apply)
|
||||
double DynamicLotForSymbol(const string symbol, const double baseLot, const double optionalCap = 0.0)
|
||||
double DynamicLotForSymbol(const string symbol, const double baseLot, const double optionalCap = 0.0, const int ddStratId = -1)
|
||||
{
|
||||
double mult = GetDynamicMultiplier();
|
||||
g_DynMultLast = mult;
|
||||
double v = baseLot * mult;
|
||||
if(optionalCap > 0.0 && v > optionalCap)
|
||||
v = optionalCap;
|
||||
return NormalizeVolumeForSymbol(symbol, v);
|
||||
return LotsAfterDrawdownCap(symbol, v, ddStratId);
|
||||
}
|
||||
|
||||
void RefreshDynamicStrategyLots()
|
||||
{
|
||||
UpdateEquityPeakForDdCap();
|
||||
|
||||
if(!InpDynamicLotEnable)
|
||||
{
|
||||
g_ES_LotSize = NormalizeVolumeForSymbol(ES_Symbol, ES_LotGröße);
|
||||
g_RC_LotSize = NormalizeVolumeForSymbol(RC_Symbol, RC_lotSize);
|
||||
g_RM_LotSize = NormalizeVolumeForSymbol(RM_Symbol, RM_InpLotSize);
|
||||
g_DB_LotSize = NormalizeVolumeForSymbol(DB_Symbol, DB_BaseLotSize);
|
||||
g_ES_LotSize = LotsAfterDrawdownCap(ES_Symbol, ES_LotGröße * UnitedAdaptive_GetLotMult(UNITED_AD_ES), UNITED_AD_ES);
|
||||
g_RC_LotSize = LotsAfterDrawdownCap(RC_Symbol, RC_lotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RC), UNITED_AD_RC);
|
||||
g_RM_LotSize = LotsAfterDrawdownCap(RM_Symbol, RM_InpLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RM), UNITED_AD_RM);
|
||||
g_DB_LotSize = LotsAfterDrawdownCap(DB_Symbol, DB_BaseLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_DARVAS), UNITED_AD_DARVAS);
|
||||
g_DynMultLast = 1.0;
|
||||
return;
|
||||
}
|
||||
g_ES_LotSize = DynamicLotForSymbol(ES_Symbol, ES_LotGröße);
|
||||
g_RC_LotSize = DynamicLotForSymbol(RC_Symbol, RC_lotSize);
|
||||
g_RM_LotSize = DynamicLotForSymbol(RM_Symbol, RM_InpLotSize);
|
||||
g_DB_LotSize = DynamicLotForSymbol(DB_Symbol, DB_BaseLotSize);
|
||||
g_ES_LotSize = DynamicLotForSymbol(ES_Symbol, ES_LotGröße * UnitedAdaptive_GetLotMult(UNITED_AD_ES), 0.0, UNITED_AD_ES);
|
||||
g_RC_LotSize = DynamicLotForSymbol(RC_Symbol, RC_lotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RC), 0.0, UNITED_AD_RC);
|
||||
g_RM_LotSize = DynamicLotForSymbol(RM_Symbol, RM_InpLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RM), 0.0, UNITED_AD_RM);
|
||||
g_DB_LotSize = DynamicLotForSymbol(DB_Symbol, DB_BaseLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_DARVAS), 0.0, UNITED_AD_DARVAS);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -493,7 +658,16 @@ void RefreshDynamicStrategyLots()
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
|
||||
UnitedAdaptive_Init();
|
||||
|
||||
g_equityPeakHighWater = InpDdLotCapUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(g_equityPeakHighWater <= 0.0)
|
||||
g_equityPeakHighWater = MathMax(InpDynamicRefDeposit, 1.0);
|
||||
g_ddLotCapAnchorTime = TimeCurrent();
|
||||
|
||||
UnitedAdaptive_UpdateIfDue();
|
||||
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
// Initialize strategies - log warnings but don't fail entire EA if symbol unavailable
|
||||
@@ -530,21 +704,39 @@ int OnInit()
|
||||
InitRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price, RS_XAUUSD_MagicNumber, RS_XAUUSD_Slippage);
|
||||
|
||||
// Initialize RSI Reversal Asian strategies
|
||||
if(EnableRSIReversalAsianEURUSD)
|
||||
if(EnableRSIReversalEURUSD)
|
||||
if(!InitRSIReversalAsian(rraEURUSDData, RRA_EURUSD_Symbol, RRA_EURUSD_RSIPeriod, RRA_EURUSD_OverboughtLevel, RRA_EURUSD_OversoldLevel,
|
||||
RRA_EURUSD_TakeProfitPips, RRA_EURUSD_StopLossPips, RRA_EURUSD_MaxLotSize,
|
||||
RRA_EURUSD_MaxSpread, RRA_EURUSD_MaxDuration, RRA_EURUSD_UseStopLoss,
|
||||
RRA_EURUSD_UseTakeProfit, RRA_EURUSD_UseRSIExit, RRA_EURUSD_RSIExitLevel,
|
||||
RRA_EURUSD_CloseOutsideSession, RRA_EURUSD_TimeFrame, RRA_EURUSD_MagicNumber, RRA_EURUSD_Slippage))
|
||||
Print("Warning: RSIReversalAsianEURUSD strategy failed to initialize for symbol '", RRA_EURUSD_Symbol, "'");
|
||||
Print("Warning: RSIReversalEURUSD strategy failed to initialize for symbol '", RRA_EURUSD_Symbol, "'");
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
if(EnableRSIReversalAUDUSD)
|
||||
if(!InitRSIReversalAsian(rraAUDUSDData, RRA_AUDUSD_Symbol, RRA_AUDUSD_RSIPeriod, RRA_AUDUSD_OverboughtLevel, RRA_AUDUSD_OversoldLevel,
|
||||
RRA_AUDUSD_TakeProfitPips, RRA_AUDUSD_StopLossPips, RRA_AUDUSD_MaxLotSize,
|
||||
RRA_AUDUSD_MaxSpread, RRA_AUDUSD_MaxDuration, RRA_AUDUSD_UseStopLoss,
|
||||
RRA_AUDUSD_UseTakeProfit, RRA_AUDUSD_UseRSIExit, RRA_AUDUSD_RSIExitLevel,
|
||||
RRA_AUDUSD_CloseOutsideSession, RRA_AUDUSD_TimeFrame, RRA_AUDUSD_MagicNumber, RRA_AUDUSD_Slippage))
|
||||
Print("Warning: RSIReversalAsianAUDUSD strategy failed to initialize for symbol '", RRA_AUDUSD_Symbol, "'");
|
||||
Print("Warning: RSIReversalAUDUSD strategy failed to initialize for symbol '", RRA_AUDUSD_Symbol, "'");
|
||||
|
||||
if(EnableRSISecretSauceXAUUSD)
|
||||
if(!InitRSISecretSauce(rsSecretSauceXAUUSDData, RSS_XAUUSD_Symbol, RSS_XAUUSD_Timeframe, RSS_XAUUSD_RSIPeriod,
|
||||
RSS_XAUUSD_RSIOverbought, RSS_XAUUSD_RSIOversold, RSS_XAUUSD_RSILookback, RSS_XAUUSD_PeakBars,
|
||||
RSS_XAUUSD_RequireDivergence, RSS_XAUUSD_StopLossATR, RSS_XAUUSD_TakeProfitATR, RSS_XAUUSD_ATRPeriod,
|
||||
RSS_XAUUSD_UseSwingStopLoss, RSS_XAUUSD_SwingLookback, RSS_XAUUSD_MaxPositions,
|
||||
RSS_XAUUSD_MinBarsBetweenTrades, RSS_XAUUSD_MagicNumber, RSS_XAUUSD_Slippage))
|
||||
Print("Warning: RSISecretSauceXAUUSD failed to initialize for symbol '", RSS_XAUUSD_Symbol, "'");
|
||||
|
||||
if(EnableSuperEMA)
|
||||
if(!InitSuperEMA(seData, SE_Symbol, SE_Timeframe, SE_SlippagePoints, SE_MagicNumber,
|
||||
SE_EmaFast, SE_EmaMid, SE_EmaSlow, SE_EmaTrendBars,
|
||||
SE_CciPeriod, SE_CciOverbought, SE_CciOversold, SE_PullbackCciLookback,
|
||||
SE_MacdFast, SE_MacdSlow, SE_MacdSignal,
|
||||
SE_EntryStyle, SE_OneTradeOnly, SE_UseStructuralSL, SE_SlBufferPoints,
|
||||
SE_ExitOnTrendFlip, SE_ExitOnMacdFlip, SE_ExitOnCciZeroCross,
|
||||
SE_MaxHoldingBars, SE_ExitBelowMidEma, SE_DebugLogs))
|
||||
Print("Warning: SuperEMA failed to initialize for symbol '", SE_Symbol, "'");
|
||||
|
||||
string acctCur = AccountInfoString(ACCOUNT_CURRENCY);
|
||||
double eq0 = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
@@ -554,7 +746,7 @@ int OnInit()
|
||||
capInit = refvInit;
|
||||
double ratioInit = capInit / refvInit;
|
||||
double rawPowInit = MathPow(ratioInit, InpDynamicExponent);
|
||||
Print("United EA v1.07 ", acctCur, " equity=", DoubleToString(eq0, 2), " equity/ref=", DoubleToString(ratioInit, 6),
|
||||
Print("United EA v1.17 ", acctCur, " equity=", DoubleToString(eq0, 2), " equity/ref=", DoubleToString(ratioInit, 6),
|
||||
" raw^exp=", DoubleToString(rawPowInit, 6), " multOut=", DoubleToString(g_DynMultLast, 6),
|
||||
" minM=", InpDynamicMinMult, " maxM=", InpDynamicMaxMult, " ref=", InpDynamicRefDeposit, " exp=", InpDynamicExponent,
|
||||
" lots ES=", g_ES_LotSize, " RC=", g_RC_LotSize, " RM=", g_RM_LotSize, " DB=", g_DB_LotSize);
|
||||
@@ -568,9 +760,29 @@ int OnInit()
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""),
|
||||
(EnableRSIReversalAsianEURUSD ? "RSIReversalAsianEURUSD " : ""),
|
||||
(EnableRSIReversalAsianAUDUSD ? "RSIReversalAsianAUDUSD " : ""));
|
||||
|
||||
(EnableRSIReversalEURUSD ? "RSIReversalEURUSD " : ""),
|
||||
(EnableRSIReversalAUDUSD ? "RSIReversalAUDUSD " : ""),
|
||||
(EnableRSISecretSauceXAUUSD ? "RSISecretSauceXAUUSD " : ""),
|
||||
(EnableSuperEMA ? "SuperEMA " : ""));
|
||||
|
||||
EventSetTimer(0);
|
||||
int timerSec = 0;
|
||||
if(UnitedPanel_Enable)
|
||||
timerSec = MathMax(5, UnitedPanel_Seconds);
|
||||
if(InpAdaptiveEnable)
|
||||
{
|
||||
const int adSec = MathMax(60, InpAdaptiveUpdateSeconds);
|
||||
timerSec = (timerSec == 0) ? adSec : MathMin(timerSec, adSec);
|
||||
}
|
||||
if(InpDdLotCapEnable && InpDdLotCapPerStratEnable && !InpAdaptiveEnable)
|
||||
{
|
||||
const int ddSec = MathMax(60, InpDdLotCapUpdateSeconds);
|
||||
timerSec = (timerSec == 0) ? ddSec : MathMin(timerSec, ddSec);
|
||||
}
|
||||
if(timerSec > 0)
|
||||
EventSetTimer(timerSec);
|
||||
UnitedProfitPanelInit();
|
||||
|
||||
return initResult;
|
||||
}
|
||||
|
||||
@@ -579,6 +791,9 @@ int OnInit()
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
EventSetTimer(0);
|
||||
UnitedProfitPanelDeinit();
|
||||
|
||||
if(EnableDarvasBox)
|
||||
DeinitDarvasBox();
|
||||
|
||||
@@ -606,11 +821,17 @@ void OnDeinit(const int reason)
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
DeinitRSIScalping(rsXAUUSDData);
|
||||
|
||||
if(EnableRSIReversalAsianEURUSD)
|
||||
if(EnableRSIReversalEURUSD)
|
||||
DeinitRSIReversalAsian(rraEURUSDData);
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
if(EnableRSIReversalAUDUSD)
|
||||
DeinitRSIReversalAsian(rraAUDUSDData);
|
||||
|
||||
if(EnableRSISecretSauceXAUUSD)
|
||||
DeinitRSISecretSauce(rsSecretSauceXAUUSDData);
|
||||
|
||||
if(EnableSuperEMA)
|
||||
DeinitSuperEMA(seData);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
@@ -620,56 +841,84 @@ void OnDeinit(const int reason)
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
UnitedAdaptive_ProcessCanaryTransitions();
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
if(EnableDarvasBox)
|
||||
if(EnableDarvasBox && UnitedAdaptive_StrategyActive(UNITED_AD_DARVAS))
|
||||
ProcessDarvasBox(DB_Symbol);
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
if(EnableEMASlopeDistance && UnitedAdaptive_StrategyActive(UNITED_AD_ES))
|
||||
ProcessEMASlopeDistance(ES_Symbol);
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
if(EnableRSICrossOverReversal && UnitedAdaptive_StrategyActive(UNITED_AD_RC))
|
||||
ProcessRSICrossOverReversal(RC_Symbol);
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
if(EnableRSIMidPointHijack && UnitedAdaptive_StrategyActive(UNITED_AD_RM))
|
||||
ProcessRSIMidPointHijack(RM_Symbol);
|
||||
|
||||
if(EnableRSIScalpingAPPL)
|
||||
if(EnableRSIScalpingAPPL && UnitedAdaptive_StrategyActive(UNITED_AD_RS_APPL))
|
||||
ProcessRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price,
|
||||
RS_APPL_RSI_Overbought, RS_APPL_RSI_Oversold, RS_APPL_RSI_Target_Buy, RS_APPL_RSI_Target_Sell,
|
||||
RS_APPL_BarsToWait,
|
||||
DynamicLotForSymbol(RS_APPL_Symbol, RS_APPL_LotSize, InpDynamicStockLotCap),
|
||||
DynamicLotForSymbol(RS_APPL_Symbol, RS_APPL_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RS_APPL), InpDynamicStockLotCap, UNITED_AD_RS_APPL),
|
||||
RS_APPL_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingBTCUSD)
|
||||
if(EnableRSIScalpingBTCUSD && UnitedAdaptive_StrategyActive(UNITED_AD_RS_BTC))
|
||||
ProcessRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price,
|
||||
RS_BTCUSD_RSI_Overbought, RS_BTCUSD_RSI_Oversold, RS_BTCUSD_RSI_Target_Buy, RS_BTCUSD_RSI_Target_Sell,
|
||||
RS_BTCUSD_BarsToWait, DynamicLotForSymbol(RS_BTCUSD_Symbol, RS_BTCUSD_LotSize), RS_BTCUSD_MagicNumber);
|
||||
RS_BTCUSD_BarsToWait, DynamicLotForSymbol(RS_BTCUSD_Symbol, RS_BTCUSD_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RS_BTC), 0.0, UNITED_AD_RS_BTC), RS_BTCUSD_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingNVDA)
|
||||
if(EnableRSIScalpingNVDA && UnitedAdaptive_StrategyActive(UNITED_AD_RS_NVDA))
|
||||
ProcessRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price,
|
||||
RS_NVDA_RSI_Overbought, RS_NVDA_RSI_Oversold, RS_NVDA_RSI_Target_Buy, RS_NVDA_RSI_Target_Sell,
|
||||
RS_NVDA_BarsToWait,
|
||||
DynamicLotForSymbol(RS_NVDA_Symbol, RS_NVDA_LotSize, InpDynamicStockLotCap),
|
||||
DynamicLotForSymbol(RS_NVDA_Symbol, RS_NVDA_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RS_NVDA), InpDynamicStockLotCap, UNITED_AD_RS_NVDA),
|
||||
RS_NVDA_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingTSLA)
|
||||
if(EnableRSIScalpingTSLA && UnitedAdaptive_StrategyActive(UNITED_AD_RS_TSLA))
|
||||
ProcessRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price,
|
||||
RS_TSLA_RSI_Overbought, RS_TSLA_RSI_Oversold, RS_TSLA_RSI_Target_Buy, RS_TSLA_RSI_Target_Sell,
|
||||
RS_TSLA_BarsToWait,
|
||||
DynamicLotForSymbol(RS_TSLA_Symbol, RS_TSLA_LotSize, InpDynamicStockLotCap),
|
||||
DynamicLotForSymbol(RS_TSLA_Symbol, RS_TSLA_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RS_TSLA), InpDynamicStockLotCap, UNITED_AD_RS_TSLA),
|
||||
RS_TSLA_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
if(EnableRSIScalpingXAUUSD && UnitedAdaptive_StrategyActive(UNITED_AD_RS_XAU))
|
||||
ProcessRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price,
|
||||
RS_XAUUSD_RSI_Overbought, RS_XAUUSD_RSI_Oversold, RS_XAUUSD_RSI_Target_Buy, RS_XAUUSD_RSI_Target_Sell,
|
||||
RS_XAUUSD_BarsToWait, DynamicLotForSymbol(RS_XAUUSD_Symbol, RS_XAUUSD_LotSize), RS_XAUUSD_MagicNumber);
|
||||
RS_XAUUSD_BarsToWait, DynamicLotForSymbol(RS_XAUUSD_Symbol, RS_XAUUSD_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RS_XAU), 0.0, UNITED_AD_RS_XAU), RS_XAUUSD_MagicNumber);
|
||||
|
||||
if(EnableRSIReversalAsianEURUSD)
|
||||
ProcessRSIReversalAsian(rraEURUSDData, DynamicLotForSymbol(RRA_EURUSD_Symbol, RRA_EURUSD_MaxLotSize));
|
||||
if(EnableRSIReversalEURUSD && UnitedAdaptive_StrategyActive(UNITED_AD_RRA_EUR))
|
||||
ProcessRSIReversalAsian(rraEURUSDData, DynamicLotForSymbol(RRA_EURUSD_Symbol, RRA_EURUSD_MaxLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RRA_EUR), 0.0, UNITED_AD_RRA_EUR));
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
ProcessRSIReversalAsian(rraAUDUSDData, DynamicLotForSymbol(RRA_AUDUSD_Symbol, RRA_AUDUSD_MaxLotSize));
|
||||
if(EnableRSIReversalAUDUSD && UnitedAdaptive_StrategyActive(UNITED_AD_RRA_AUD))
|
||||
ProcessRSIReversalAsian(rraAUDUSDData, DynamicLotForSymbol(RRA_AUDUSD_Symbol, RRA_AUDUSD_MaxLotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RRA_AUD), 0.0, UNITED_AD_RRA_AUD));
|
||||
|
||||
if(EnableRSISecretSauceXAUUSD && UnitedAdaptive_StrategyActive(UNITED_AD_RSS))
|
||||
ProcessRSISecretSauce(rsSecretSauceXAUUSDData, DynamicLotForSymbol(RSS_XAUUSD_Symbol, RSS_XAUUSD_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_RSS), 0.0, UNITED_AD_RSS));
|
||||
|
||||
if(EnableSuperEMA && UnitedAdaptive_StrategyActive(UNITED_AD_SUPEREMA))
|
||||
ProcessSuperEMA(seData, DynamicLotForSymbol(SE_Symbol, SE_LotSize * UnitedAdaptive_GetLotMult(UNITED_AD_SUPEREMA), 0.0, UNITED_AD_SUPEREMA));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Timer — refresh profit panel (history scan) |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTimer()
|
||||
{
|
||||
if(InpAdaptiveEnable)
|
||||
UnitedAdaptive_ProcessCanaryTransitions();
|
||||
if(InpAdaptiveEnable || (InpDdLotCapEnable && InpDdLotCapPerStratEnable))
|
||||
UnitedAdaptive_UpdateIfDue();
|
||||
if(UnitedPanel_Enable)
|
||||
UnitedProfitPanelRefresh();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Chart events — panel layout on resize |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
UnitedProfitPanelOnChartEvent(id);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
\begin{figure}[t]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{frontline/MQL5/_united_dynamic/report/pnl_by_magic_robot.pdf}
|
||||
\caption{Net closed P\&L by robot magic number from the united\_dynamic live report export. Bars show net realized P\&L (USD) and the label \texttt{n} is the number of closed trades. Because the MT5 report does not expose per-deal magic directly in this extract, XAUUSD trades that come from multiple XAU strategies are shown as one mixed bucket.}
|
||||
\label{fig:united-dynamic-pnl-by-magic}
|
||||
\end{figure}
|
||||
@@ -0,0 +1,6 @@
|
||||
\begin{figure*}[t]
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{frontline/MQL5/_united_dynamic/report/pnl_timeseries_by_robot.pdf}
|
||||
\caption{Cumulative closed P\&L over time split by robot. Non-XAU robots are mapped directly by symbol-to-magic configuration; XAU trades are assigned by ticket-matched strategy comments when available, and otherwise grouped into an unattributed XAU bucket.}
|
||||
\label{fig:united-dynamic-pnl-timeseries-by-robot}
|
||||
\end{figure*}
|
||||
@@ -0,0 +1,6 @@
|
||||
\begin{figure}[t]
|
||||
\centering
|
||||
\includegraphics[width=\linewidth]{frontline/MQL5/_united_dynamic/report/pnl_timeseries_line.pdf}
|
||||
\caption{Cumulative closed P\&L over time for the united\_dynamic account history in \texttt{ReportHistory-51389369.xlsx}. The curve is formed by sorting closed deals by close timestamp and cumulatively summing realized deal P\&L.}
|
||||
\label{fig:united-dynamic-pnl-timeseries}
|
||||
\end{figure}
|
||||
@@ -0,0 +1,9 @@
|
||||
symbol,magic_number,robot,count,sum
|
||||
MSFT.US,20002,RSI Scalping MSFT,12,-1042.0
|
||||
EURUSD,30001,RSI Reversal Asian EURUSD,20,-264.84999999999997
|
||||
BTCUSD,123459123,RSI Scalping BTCUSD,11,-203.41000000000003
|
||||
NVDA.US,20003,RSI Scalping NVDA,32,-42.54000000000002
|
||||
AAPL.US,20001,RSI Scalping AAPL,5,-2.0
|
||||
AUDUSD,30002,RSI Reversal Asian AUDUSD,14,78.08000000000001
|
||||
XAUUSD,MIXED,XAUUSD Multi-Strategy Bucket,291,1953.66
|
||||
TSLA.US,125421321,RSI Scalping TSLA,16,2352.57
|
||||
|
|
After Width: | Height: | Size: 137 KiB |
@@ -0,0 +1,386 @@
|
||||
close_time,125421321 RSI Scalping TSLA,XAU Unattributed (multiple robots),129102315 RSI Scalping XAUUSD,30002 RSI Reversal Asian AUDUSD,20003 RSI Scalping NVDA,12350 EMA Slope Distance (XAU),123459123 RSI Scalping BTCUSD,30001 RSI Reversal Asian EURUSD,20002 RSI Scalping MSFT
|
||||
2026-01-05 08:00:00,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
2026-01-05 12:06:01,0.0,0.0,0.0,0.0,0.0,61.98,0.0,0.0,0.0
|
||||
2026-01-05 18:06:21,0.0,0.0,0.0,0.0,0.0,86.07,0.0,0.0,0.0
|
||||
2026-01-06 07:55:38,0.0,0.0,0.0,0.0,0.0,86.07,0.0,-3.0,0.0
|
||||
2026-01-06 08:00:00,0.0,0.0,0.0,4.2,0.0,86.07,0.0,-3.0,0.0
|
||||
2026-01-06 12:00:00,0.0,0.0,-81.78,4.2,0.0,86.07,0.0,-3.0,0.0
|
||||
2026-01-06 15:13:04,0.0,0.0,-78.69,4.2,0.0,86.07,0.0,-3.0,0.0
|
||||
2026-01-06 16:39:10,0.0,0.0,-78.69,4.2,0.0,111.69,0.0,-3.0,0.0
|
||||
2026-01-06 19:42:51,0.0,0.0,-78.69,4.2,0.0,101.72999999999999,0.0,-3.0,0.0
|
||||
2026-01-07 08:00:00,0.0,0.0,-78.69,12.2,0.0,101.72999999999999,0.0,-3.0,0.0
|
||||
2026-01-07 11:00:00,0.0,0.0,-78.69,12.2,0.0,29.189999999999984,0.0,-3.0,0.0
|
||||
2026-01-08 08:21:15,0.0,0.0,-78.69,12.2,0.0,29.339999999999982,0.0,-3.0,0.0
|
||||
2026-01-08 18:00:00,0.0,0.0,-78.69,12.2,0.0,29.339999999999982,0.0,-3.0,-49.1
|
||||
2026-01-09 07:00:00,0.0,0.0,-78.69,12.2,0.0,29.339999999999982,0.0,-3.0,-49.1
|
||||
2026-01-12 03:00:00,0.0,0.0,296.85,12.2,0.0,29.339999999999982,0.0,-3.0,-49.1
|
||||
2026-01-12 05:43:32,0.0,0.0,296.85,12.2,0.0,36.11999999999998,0.0,-3.0,-49.1
|
||||
2026-01-12 06:00:00,0.0,0.0,296.85,12.2,0.0,35.399999999999984,0.0,-3.0,-49.1
|
||||
2026-01-12 06:01:28,0.0,0.0,296.85,12.2,0.0,35.399999999999984,0.0,-3.8,-49.1
|
||||
2026-01-13 00:01:01,0.0,0.0,296.85,12.2,0.0,35.399999999999984,0.0,-10.2,-49.1
|
||||
2026-01-13 03:00:00,0.0,0.0,246.06000000000003,12.2,0.0,35.399999999999984,0.0,-10.2,-49.1
|
||||
2026-01-13 16:28:43,0.0,0.0,267.48,12.2,0.0,56.819999999999986,0.0,-10.2,-49.1
|
||||
2026-01-13 20:00:00,0.0,0.0,267.48,12.2,0.0,-63.00000000000001,0.0,-10.2,-49.1
|
||||
2026-01-14 05:28:14,0.0,0.0,267.48,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-14 07:19:03,0.0,0.0,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-14 15:00:44,0.0,-11.19,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-14 17:11:47,49.1,-11.19,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-15 03:00:00,49.1,-74.88,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-15 07:28:43,49.1,-69.75,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-15 17:00:00,49.1,-141.66,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-16 08:00:00,49.1,-152.35999999999999,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-19 01:01:01,49.1,-348.98,305.1,12.2,0.0,-72.63000000000001,0.0,-10.2,-49.1
|
||||
2026-01-19 02:08:19,49.1,-348.98,305.1,12.2,0.0,-72.63000000000001,0.0,-0.6999999999999993,-49.1
|
||||
2026-01-19 03:00:46,49.1,-354.74,305.1,12.2,0.0,-72.63000000000001,0.0,-0.6999999999999993,-49.1
|
||||
2026-01-19 04:00:26,49.1,-354.74,305.1,12.2,0.0,-72.63000000000001,0.0,9.4,-49.1
|
||||
2026-01-20 00:01:00,49.1,-354.74,305.1,12.2,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 07:24:12,49.1,-282.38,305.1,12.2,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 08:00:00,49.1,-282.38,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 09:51:16,49.1,-271.4,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 10:19:24,49.1,-254.29999999999998,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 12:00:07,49.1,-247.93999999999997,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-20 15:34:19,49.1,-237.22999999999996,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-5.199999999999999,-49.1
|
||||
2026-01-21 00:01:00,49.1,-237.22999999999996,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-21 17:24:43,49.1,-145.00999999999996,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 02:00:00,49.1,-361.5799999999999,305.1,-4.199999999999999,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 08:00:00,49.1,-459.2299999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 18:00:00,23.700000000000003,-459.2299999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 18:30:02,23.700000000000003,-434.1799999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 21:27:07,23.700000000000003,-334.9099999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-22 22:00:00,23.700000000000003,-335.6599999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-23 03:00:00,23.700000000000003,-498.8299999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.3,-49.1
|
||||
2026-01-23 04:44:42,23.700000000000003,-498.8299999999999,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-23 05:16:54,23.700000000000003,-506.74999999999994,305.1,-31.4,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-23 08:00:00,23.700000000000003,-506.74999999999994,305.1,-46.0,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-23 11:00:00,23.700000000000003,-388.3399999999999,305.1,-46.0,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-26 04:00:00,23.700000000000003,34.3300000000001,305.1,-46.0,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-26 08:00:00,23.700000000000003,34.3300000000001,305.1,-34.4,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-26 21:00:00,23.700000000000003,65.1700000000001,305.1,-34.4,0.0,-72.63000000000001,0.0,-81.39999999999999,-49.1
|
||||
2026-01-27 00:01:00,23.700000000000003,65.1700000000001,305.1,-34.4,0.0,-72.63000000000001,0.0,-214.09999999999997,-49.1
|
||||
2026-01-27 04:00:00,23.700000000000003,-41.089999999999904,305.1,-34.4,0.0,-72.63000000000001,0.0,-214.09999999999997,-49.1
|
||||
2026-01-27 05:07:00,23.700000000000003,-41.089999999999904,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 06:09:45,23.700000000000003,-40.60999999999991,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 08:50:00,23.700000000000003,-5.089999999999904,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 09:12:16,23.700000000000003,-0.25999999999990386,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 11:45:33,23.700000000000003,2.560000000000096,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 16:00:00,23.700000000000003,-61.159999999999904,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 17:03:41,54.300000000000004,-61.159999999999904,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-27 23:00:30,54.300000000000004,159.3400000000001,305.1,-34.4,0.0,-72.63000000000001,0.0,-207.59999999999997,-49.1
|
||||
2026-01-28 03:31:17,54.300000000000004,159.3400000000001,305.1,-34.4,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 07:01:59,54.300000000000004,588.97,305.1,-34.4,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 08:00:00,54.300000000000004,588.97,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 09:00:38,54.300000000000004,601.69,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 10:12:05,54.300000000000004,603.82,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 14:12:22,54.300000000000004,604.0,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 17:12:17,54.300000000000004,647.86,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,-49.1
|
||||
2026-01-28 18:53:19,54.300000000000004,647.86,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,2.3999999999999986
|
||||
2026-01-28 19:08:19,54.300000000000004,645.46,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,2.3999999999999986
|
||||
2026-01-29 02:00:01,54.300000000000004,-0.8899999999999864,305.1,-27.2,0.0,-72.63000000000001,0.0,-171.69999999999996,2.3999999999999986
|
||||
2026-01-29 07:58:06,54.300000000000004,-0.8899999999999864,305.1,-27.2,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-29 08:00:00,54.300000000000004,-0.8899999999999864,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-29 12:38:43,54.300000000000004,8.890000000000013,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 01:01:01,54.300000000000004,-650.63,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 04:00:00,54.300000000000004,-1064.69,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 06:00:34,54.300000000000004,-1001.1800000000001,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 07:00:00,54.300000000000004,-1003.58,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 09:00:00,54.300000000000004,-1044.07,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 11:00:10,54.300000000000004,-873.4,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 20:00:04,54.300000000000004,-397.51,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-01-30 23:00:03,54.300000000000004,-318.01,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 02:00:00,54.300000000000004,-244.57,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 04:00:10,54.300000000000004,-85.47999999999999,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 07:13:20,54.300000000000004,-60.609999999999985,305.1,-57.8,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 08:00:00,54.300000000000004,-60.609999999999985,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 08:12:16,54.300000000000004,-30.879999999999985,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 09:16:31,54.300000000000004,-23.319999999999986,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 10:24:18,54.300000000000004,32.72000000000001,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-03 17:27:59,154.4,32.72000000000001,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-159.99999999999997,2.3999999999999986
|
||||
2026-02-04 04:50:05,154.4,32.72000000000001,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-152.49999999999997,2.3999999999999986
|
||||
2026-02-04 07:00:00,154.4,31.830000000000013,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-152.49999999999997,2.3999999999999986
|
||||
2026-02-04 07:00:02,154.4,482.03999999999996,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-152.49999999999997,2.3999999999999986
|
||||
2026-02-04 12:13:15,154.4,487.61999999999995,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-152.49999999999997,2.3999999999999986
|
||||
2026-02-04 18:24:11,154.4,558.9,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-152.49999999999997,2.3999999999999986
|
||||
2026-02-05 00:01:00,154.4,558.9,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-05 01:01:00,154.4,305.93999999999994,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-05 04:00:00,154.4,145.13999999999993,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-05 08:00:12,154.4,155.80999999999992,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-05 17:48:31,154.4,177.07999999999993,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-05 23:01:58,154.4,181.36999999999992,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-06 01:01:01,154.4,131.0399999999999,305.1,-61.599999999999994,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-06 04:01:08,154.4,131.0399999999999,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-06 08:00:00,154.4,-452.8200000000001,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 03:51:31,154.4,-249.7200000000001,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 03:59:22,154.4,-83.5700000000001,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 07:00:00,154.4,-87.02000000000011,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 13:00:00,154.4,73.72999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 15:00:02,154.4,69.55999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-09 17:43:21,-126.6,69.55999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 05:00:00,-126.6,-29.140000000000114,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 07:00:00,-126.6,-30.010000000000115,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 07:15:30,-126.6,50.63999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 10:50:55,-126.6,76.61999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 11:13:05,-126.6,111.65999999999988,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 12:54:34,-126.6,123.17999999999988,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 13:18:10,-126.6,126.59999999999988,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 16:25:00,-126.6,213.71999999999989,305.1,9.400000000000006,0.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 16:45:00,-126.6,213.71999999999989,305.1,9.400000000000006,2.0,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 17:00:00,-126.6,213.71999999999989,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 17:15:40,-126.6,213.8999999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,2.3999999999999986
|
||||
2026-02-10 21:00:01,-126.6,213.8999999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 04:02:06,-126.6,237.0299999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 07:48:46,-126.6,237.9299999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 08:00:00,-126.6,218.2799999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 11:49:18,-126.6,235.7999999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 12:27:16,-126.6,295.1599999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 13:24:06,-126.6,304.6699999999999,305.1,9.400000000000006,2.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 17:25:57,-126.6,304.6699999999999,305.1,9.400000000000006,3.0,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-11 19:20:00,-126.6,304.6699999999999,305.1,9.400000000000006,3.0,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 05:00:00,-126.6,174.6699999999999,305.1,9.400000000000006,3.0,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 07:00:00,-126.6,173.1699999999999,305.1,9.400000000000006,3.0,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 09:00:00,-126.6,14.919999999999902,305.1,9.400000000000006,3.0,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 17:45:00,-126.6,14.919999999999902,305.1,9.400000000000006,17.45,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 18:00:01,-126.6,14.919999999999902,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 20:01:58,-126.6,43.119999999999905,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-12 23:02:07,-126.6,97.1499999999999,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 05:18:27,-126.6,105.3999999999999,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 08:00:00,-126.6,0.9699999999998994,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 15:42:45,-126.6,-294.7100000000001,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 19:00:00,-126.6,-488.5700000000001,305.1,9.400000000000006,19.849999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 21:42:00,-126.6,-488.5700000000001,305.1,9.400000000000006,28.349999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 21:58:36,-126.6,-446.1500000000001,305.1,9.400000000000006,28.349999999999998,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-13 22:00:00,-126.6,-446.1500000000001,305.1,9.400000000000006,32.55,-72.63000000000001,0.0,-129.39999999999998,-20.5
|
||||
2026-02-16 02:00:00,-126.6,-446.1500000000001,305.1,9.400000000000006,32.55,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-16 05:00:00,-126.6,-579.1000000000001,305.1,9.400000000000006,32.55,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-17 17:00:00,-49.8,-579.1000000000001,305.1,9.400000000000006,32.55,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-17 17:45:00,-49.8,-579.1000000000001,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-19 22:00:00,-49.8,-133.80000000000013,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-20 07:00:00,-49.8,-201.30000000000013,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-23 02:00:00,-49.8,1316.8999999999999,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 02:00:00,-49.8,407.79999999999984,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 04:00:00,-49.8,860.9999999999998,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 10:01:34,-49.8,880.3799999999998,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 14:01:01,-49.8,873.7799999999997,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 18:00:00,-49.8,759.9899999999998,305.1,9.400000000000006,26.449999999999996,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-24 18:15:00,-49.8,759.9899999999998,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-25 05:55:01,-49.8,762.1799999999998,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-25 08:00:56,-49.8,811.8899999999999,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-25 16:00:00,-49.8,634.3899999999999,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-25 18:07:26,-49.8,624.6399999999999,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-25 23:00:03,-49.8,442.65999999999985,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-26 03:00:00,-49.8,375.05999999999983,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,-16.6,-129.39999999999998,-20.5
|
||||
2026-02-26 06:00:00,-49.8,375.05999999999983,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 13:00:00,-49.8,293.0099999999998,305.1,9.400000000000006,-58.300000000000004,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 16:45:00,-49.8,293.0099999999998,305.1,9.400000000000006,21.699999999999996,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 16:46:48,-49.8,293.0099999999998,305.1,9.400000000000006,26.399999999999995,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 16:46:53,-49.8,293.0099999999998,305.1,9.400000000000006,52.099999999999994,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 16:46:56,-49.8,293.0099999999998,305.1,9.400000000000006,89.94999999999999,-72.63000000000001,106.34,-129.39999999999998,-20.5
|
||||
2026-02-26 18:56:28,-49.8,293.0099999999998,305.1,9.400000000000006,89.94999999999999,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-26 20:45:00,-49.8,293.0099999999998,305.1,9.400000000000006,40.44999999999999,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-26 22:30:01,-49.8,293.0099999999998,305.1,9.400000000000006,3.6999999999999886,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 07:00:01,-49.8,292.3299999999998,305.1,9.400000000000006,3.6999999999999886,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 16:45:00,-49.8,292.3299999999998,305.1,9.400000000000006,5.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 18:00:00,-49.8,292.3299999999998,305.1,9.400000000000006,13.199999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 18:00:33,-49.8,329.3799999999998,305.1,9.400000000000006,13.199999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 18:15:00,-49.8,329.3799999999998,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 20:15:53,-49.8,337.0899999999998,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 21:03:14,187.2,337.0899999999998,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-02-27 23:01:44,187.2,377.5299999999998,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 01:03:37,187.2,1653.3299999999997,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 02:00:03,187.2,1747.1699999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 06:01:54,187.2,1803.8999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 09:01:24,187.2,1889.0999999999997,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 09:13:03,187.2,1095.8999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 17:00:00,187.2,1730.3999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 18:00:30,187.2,1378.8899999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-02 23:30:48,187.2,1418.6999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 02:00:21,187.2,1442.7299999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 05:17:20,187.2,1477.2599999999995,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 11:00:00,187.2,530.9999999999995,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 12:00:00,187.2,529.2599999999995,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 13:00:18,187.2,593.6999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-18.25
|
||||
2026-03-03 16:31:02,187.2,593.6999999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-03 17:00:05,187.2,897.6599999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-03 20:00:21,187.2,935.6399999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-03 22:00:04,187.2,996.3299999999997,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-04 18:00:00,187.2,828.2399999999997,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-04 20:00:10,187.2,844.6499999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,106.34,-129.39999999999998,-98.75
|
||||
2026-03-05 04:00:00,187.2,844.6499999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 05:00:00,187.2,668.1899999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 09:00:00,187.2,415.9899999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 16:00:00,187.2,371.4299999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 16:00:11,187.2,456.3299999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 19:02:14,187.2,515.6099999999996,305.1,9.400000000000006,11.449999999999989,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-05 20:30:00,187.2,515.6099999999996,305.1,9.400000000000006,-1.0500000000000114,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-06 12:00:00,187.2,417.5299999999996,305.1,9.400000000000006,-1.0500000000000114,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-06 15:00:00,187.2,355.42999999999955,305.1,9.400000000000006,-1.0500000000000114,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-06 17:00:00,187.2,209.44999999999956,305.1,9.400000000000006,-1.0500000000000114,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-06 22:30:00,187.2,209.44999999999956,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 01:01:22,187.2,288.10999999999956,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 04:06:01,187.2,357.8299999999996,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 05:00:00,187.2,-362.5700000000004,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 09:00:00,187.2,-525.8900000000003,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 12:01:35,187.2,-530.5700000000003,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 17:00:00,599.95,-530.5700000000003,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-09 17:00:25,599.95,-500.0600000000003,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 01:01:33,599.95,-490.52000000000027,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 05:02:32,599.95,-405.5600000000003,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 08:00:01,599.95,-407.40000000000026,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 09:05:27,599.95,-379.41000000000025,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 11:03:06,599.95,-369.30000000000024,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 17:00:17,599.95,-311.97000000000025,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-10 19:03:01,599.95,-253.23000000000025,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-11 07:00:00,599.95,-253.71000000000024,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-11 10:00:00,599.95,299.38999999999976,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-11 15:00:01,599.95,158.68999999999977,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-11 16:31:01,510.95000000000005,158.68999999999977,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-98.75
|
||||
2026-03-11 18:00:00,510.95000000000005,158.68999999999977,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 03:09:47,510.95000000000005,155.53999999999976,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 06:01:28,510.95000000000005,152.23999999999975,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 11:00:00,510.95000000000005,32.05999999999975,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 12:00:00,510.95000000000005,40.11999999999975,305.1,9.400000000000006,-71.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 17:30:01,510.95000000000005,40.11999999999975,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 18:46:42,510.95000000000005,102.39999999999975,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 19:04:29,510.95000000000005,151.41999999999976,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-131.25
|
||||
2026-03-12 21:00:02,510.95000000000005,151.41999999999976,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-12 21:01:15,510.95000000000005,196.56999999999977,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-12 23:01:04,510.95000000000005,216.24999999999977,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-13 08:00:00,510.95000000000005,195.32999999999976,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-13 18:00:14,510.95000000000005,286.34999999999974,305.1,9.400000000000006,27.19999999999999,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-13 19:30:00,510.95000000000005,286.34999999999974,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,259.51,-129.39999999999998,-174.5
|
||||
2026-03-13 23:00:00,510.95000000000005,286.34999999999974,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-13 23:00:35,510.95000000000005,330.9299999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 03:00:15,510.95000000000005,355.52999999999975,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 05:00:33,510.95000000000005,376.43999999999977,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 11:00:31,510.95000000000005,392.00999999999976,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 13:09:14,510.95000000000005,429.08999999999975,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 14:00:00,510.95000000000005,457.3099999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,28.92999999999998,-129.39999999999998,-174.5
|
||||
2026-03-16 15:00:00,510.95000000000005,457.3099999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-1.2600000000000229,-129.39999999999998,-174.5
|
||||
2026-03-16 17:00:00,501.95000000000005,457.3099999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-1.2600000000000229,-129.39999999999998,-174.5
|
||||
2026-03-17 11:00:01,501.95000000000005,457.3099999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-17 14:00:00,501.95000000000005,401.4499999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-17 14:08:21,501.95000000000005,421.4899999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-17 19:18:11,501.95000000000005,429.28999999999974,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-17 23:04:43,501.95000000000005,424.45999999999975,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 05:00:33,501.95000000000005,418.78999999999974,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 06:00:00,501.95000000000005,401.00999999999976,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 07:24:05,501.95000000000005,394.76999999999975,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 14:14:57,501.95000000000005,443.4299999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 16:31:00,503.70000000000005,443.4299999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 16:42:22,503.70000000000005,580.7099999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 18:00:39,503.70000000000005,597.5699999999997,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 22:04:29,503.70000000000005,618.3899999999998,305.1,9.400000000000006,-16.55000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-18 22:45:00,503.70000000000005,618.3899999999998,305.1,9.400000000000006,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 01:01:09,503.70000000000005,647.6999999999997,305.1,9.400000000000006,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 05:07:38,503.70000000000005,647.6999999999997,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 09:00:35,503.70000000000005,659.9999999999997,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 11:00:07,503.70000000000005,761.2199999999997,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 13:00:36,503.70000000000005,783.0299999999996,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 16:20:36,503.70000000000005,1087.8299999999997,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 16:31:00,1279.2,1087.8299999999997,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-19 18:00:12,1279.2,1136.1899999999996,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-129.39999999999998,-174.5
|
||||
2026-03-20 04:50:41,1279.2,1136.1899999999996,305.1,51.60000000000001,-35.05000000000001,-72.63000000000001,-142.25000000000003,-109.49999999999997,-174.5
|
||||
2026-03-20 18:00:00,1279.2,1136.1899999999996,305.1,51.60000000000001,-186.55,-72.63000000000001,-142.25000000000003,-109.49999999999997,-174.5
|
||||
2026-03-20 20:45:00,1279.2,1136.1899999999996,305.1,51.60000000000001,-275.05,-72.63000000000001,-142.25000000000003,-109.49999999999997,-174.5
|
||||
2026-03-23 23:00:00,1279.2,1136.1899999999996,305.1,51.60000000000001,-275.05,-72.63000000000001,-225.91000000000003,-109.49999999999997,-174.5
|
||||
2026-03-24 04:00:00,1279.2,1009.8699999999997,305.1,51.60000000000001,-275.05,-72.63000000000001,-225.91000000000003,-109.49999999999997,-174.5
|
||||
2026-03-24 17:30:00,1279.2,1009.8699999999997,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-109.49999999999997,-174.5
|
||||
2026-03-25 02:00:30,1279.2,1028.9499999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-109.49999999999997,-174.5
|
||||
2026-03-25 04:00:04,1279.2,1065.3699999999997,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-109.49999999999997,-174.5
|
||||
2026-03-25 04:54:18,1279.2,1065.3699999999997,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-25 16:31:01,871.7,1065.3699999999997,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-25 23:00:00,871.7,871.1799999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 01:01:01,871.7,1292.4799999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 05:00:47,871.7,1284.1699999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 12:00:55,871.7,1305.8899999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 13:00:00,871.7,1353.8899999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 15:00:47,871.7,1347.1999999999996,305.1,51.60000000000001,-392.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 17:30:00,871.7,1347.1999999999996,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 20:00:33,871.7,1457.0299999999995,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-26 23:11:44,871.7,1488.7099999999996,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 04:00:00,871.7,1421.1099999999997,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 04:00:03,871.7,1417.3899999999996,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 09:00:00,871.7,1308.3699999999997,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 14:00:12,871.7,1330.2699999999998,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 16:31:00,1699.7,1330.2699999999998,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 18:00:01,1699.7,1054.2399999999998,305.1,51.60000000000001,-391.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 20:30:01,1699.7,1054.2399999999998,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-174.5
|
||||
2026-03-27 21:00:00,1699.7,1054.2399999999998,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 03:00:01,1699.7,828.9099999999997,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 04:00:13,1699.7,70.40999999999974,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 05:00:00,1699.7,-33.84000000000026,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 09:00:03,1699.7,33.29999999999974,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 10:00:00,1699.7,32.679999999999744,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 12:06:36,1699.7,44.169999999999746,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 15:00:29,1699.7,113.01999999999974,305.1,51.60000000000001,-477.05,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 22:30:00,1699.7,113.01999999999974,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-30 23:00:00,1699.7,37.119999999999735,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-102.99999999999997,-117.5
|
||||
2026-03-31 04:50:01,1699.7,37.119999999999735,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 05:00:17,1699.7,129.66999999999973,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 07:00:00,1699.7,129.30999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 09:00:13,1699.7,122.34999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 11:02:00,1699.7,133.98999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 15:14:01,1699.7,167.58999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 17:09:58,1699.7,253.86999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 21:10:02,1699.7,253.86999999999972,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-03-31 22:08:48,1699.7,448.26999999999975,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-04-01 03:00:31,1699.7,475.2399999999998,305.1,51.60000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-04-01 08:00:00,1699.7,475.2399999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-94.59999999999997,-117.5
|
||||
2026-04-02 00:01:00,1699.7,475.2399999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-02 08:00:00,1699.7,1736.6399999999999,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-02 18:00:01,1699.7,1470.8999999999999,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-06 03:01:14,1699.7,1538.61,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-06 08:00:00,1699.7,1426.62,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-06 12:50:29,1699.7,1448.79,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-06 17:00:00,1699.7,1295.09,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-117.5
|
||||
2026-04-06 18:00:00,1699.7,1295.09,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-188.5
|
||||
2026-04-06 18:40:05,1699.7,1295.09,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-188.5
|
||||
2026-04-06 20:00:00,1699.7,1195.1899999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-188.5
|
||||
2026-04-06 20:00:01,2471.7,1195.1899999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-225.91000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 01:00:00,2471.7,1195.1899999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-113.86000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 08:00:01,2471.7,1094.1499999999999,305.1,99.80000000000001,-642.55,-72.63000000000001,-113.86000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 14:00:00,2471.7,998.3899999999999,305.1,99.80000000000001,-642.55,-72.63000000000001,-113.86000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 16:00:00,2471.7,684.1899999999998,305.1,99.80000000000001,-642.55,-72.63000000000001,-113.86000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 17:30:00,2471.7,684.1899999999998,305.1,99.80000000000001,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-188.5
|
||||
2026-04-07 18:00:01,2471.7,684.1899999999998,305.1,99.80000000000001,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-07 21:00:00,2471.7,555.0999999999998,305.1,99.80000000000001,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-08 01:01:06,2471.7,678.7299999999998,305.1,99.80000000000001,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-08 03:00:07,2471.7,712.4799999999998,305.1,99.80000000000001,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-08 08:00:00,2471.7,712.4799999999998,305.1,-72.39999999999998,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-08 09:08:23,2471.7,730.9599999999998,305.1,-72.39999999999998,-264.04999999999995,-72.63000000000001,-113.86000000000003,-138.49999999999997,-356.5
|
||||
2026-04-08 10:00:00,2471.7,730.9599999999998,305.1,-72.39999999999998,-264.04999999999995,-72.63000000000001,-96.76000000000002,-138.49999999999997,-356.5
|
||||
2026-04-08 16:31:00,2471.7,730.9599999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-138.49999999999997,-356.5
|
||||
2026-04-08 18:20:00,2471.7,730.9599999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-138.49999999999997,-356.5
|
||||
2026-04-08 20:00:00,2471.7,1312.6599999999999,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-138.49999999999997,-356.5
|
||||
2026-04-08 21:00:01,2471.7,1056.0099999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-138.49999999999997,-356.5
|
||||
2026-04-09 00:01:00,2471.7,1056.0099999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-356.5
|
||||
2026-04-09 13:00:01,2471.7,978.8799999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-356.5
|
||||
2026-04-09 16:31:01,2471.7,978.8799999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-09 17:00:38,2471.7,995.0199999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-09 19:13:39,2471.7,1057.1799999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-09 21:01:21,2471.7,1073.4099999999999,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-10 01:01:52,2471.7,1075.2699999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-10 05:00:02,2471.7,1155.7699999999998,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-10 05:00:30,2471.7,1149.5899999999997,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-10 17:00:01,2471.7,1149.9499999999996,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-953.0
|
||||
2026-04-10 18:36:21,2471.7,1149.9499999999996,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-10 21:00:00,2471.7,985.5499999999996,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-13 01:01:02,2471.7,641.7499999999995,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-13 01:01:03,2471.7,1087.5699999999995,305.1,-72.39999999999998,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-13 07:33:34,2471.7,1087.5699999999995,305.1,78.08000000000001,198.95000000000005,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-13 18:00:01,2471.7,1087.5699999999995,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-13 20:00:00,2352.5699999999997,787.4099999999994,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-14 04:00:02,2352.5699999999997,813.0899999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-14 06:00:57,2352.5699999999997,833.8799999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-14 08:02:23,2352.5699999999997,847.8799999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-14 09:00:04,2352.5699999999997,844.2399999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-96.76000000000002,-211.49999999999997,-1042.0
|
||||
2026-04-14 09:00:07,2352.5699999999997,844.2399999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,0.9899999999999807,-211.49999999999997,-1042.0
|
||||
2026-04-14 12:05:23,2352.5699999999997,851.1599999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,0.9899999999999807,-211.49999999999997,-1042.0
|
||||
2026-04-14 18:00:36,2352.5699999999997,939.3599999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,0.9899999999999807,-211.49999999999997,-1042.0
|
||||
2026-04-14 21:21:16,2352.5699999999997,1039.9199999999994,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,0.9899999999999807,-211.49999999999997,-1042.0
|
||||
2026-04-14 23:00:00,2352.5699999999997,1039.9199999999994,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-211.49999999999997,-1042.0
|
||||
2026-04-14 23:04:34,2352.5699999999997,1068.0699999999995,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-211.49999999999997,-1042.0
|
||||
2026-04-15 00:01:00,2352.5699999999997,1068.0699999999995,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-264.84999999999997,-1042.0
|
||||
2026-04-15 05:15:57,2352.5699999999997,1086.4199999999994,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-264.84999999999997,-1042.0
|
||||
2026-04-15 08:30:19,2352.5699999999997,1076.7199999999993,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-264.84999999999997,-1042.0
|
||||
2026-04-15 12:00:00,2352.5699999999997,1796.5999999999995,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-264.84999999999997,-1042.0
|
||||
2026-04-15 14:00:00,2352.5699999999997,1721.9599999999994,305.1,78.08000000000001,-42.539999999999964,-72.63000000000001,-203.41000000000003,-264.84999999999997,-1042.0
|
||||
|
|
After Width: | Height: | Size: 267 KiB |
@@ -0,0 +1,102 @@
|
||||
close_time,daily_pnl,cum_pnl
|
||||
2026-01-05,85.61999999999999,85.61999999999999
|
||||
2026-01-06,-61.83,23.789999999999992
|
||||
2026-01-07,-64.69000000000001,-40.90000000000002
|
||||
2026-01-08,-48.95,-89.85000000000002
|
||||
2026-01-09,-0.17,-90.02000000000002
|
||||
2026-01-10,0.0,-90.02000000000002
|
||||
2026-01-11,0.0,-90.02000000000002
|
||||
2026-01-12,380.8,290.78
|
||||
2026-01-13,-134.17,156.60999999999999
|
||||
2026-01-14,65.9,222.51
|
||||
2026-01-15,-130.47,92.03999999999999
|
||||
2026-01-16,-10.7,81.33999999999999
|
||||
2026-01-17,0.0,81.33999999999999
|
||||
2026-01-18,0.0,81.33999999999999
|
||||
2026-01-19,-182.78,-101.44000000000001
|
||||
2026-01-20,86.51,-14.930000000000007
|
||||
2026-01-21,16.120000000000005,1.1899999999999977
|
||||
2026-01-22,-243.25,-242.06
|
||||
2026-01-23,-67.38,-309.44
|
||||
2026-01-24,0.0,-309.44
|
||||
2026-01-25,0.0,-309.44
|
||||
2026-01-26,465.11,155.67000000000002
|
||||
2026-01-27,-1.4299999999999784,154.24000000000004
|
||||
2026-01-28,580.72,734.96
|
||||
2026-01-29,-655.47,79.49000000000001
|
||||
2026-01-30,-326.9,-247.40999999999997
|
||||
2026-01-31,0.0,-247.40999999999997
|
||||
2026-02-01,0.0,-247.40999999999997
|
||||
2026-02-02,0.0,-247.40999999999997
|
||||
2026-02-03,447.03,199.62
|
||||
2026-02-04,533.68,733.3
|
||||
2026-02-05,-354.43,378.86999999999995
|
||||
2026-02-06,-563.19,-184.3200000000001
|
||||
2026-02-07,0.0,-184.3200000000001
|
||||
2026-02-08,0.0,-184.3200000000001
|
||||
2026-02-09,241.38,57.05999999999989
|
||||
2026-02-10,123.99000000000001,181.0499999999999
|
||||
2026-02-11,111.97,293.01999999999987
|
||||
2026-02-12,-190.67000000000002,102.34999999999985
|
||||
2026-02-13,-530.6,-428.25000000000017
|
||||
2026-02-14,0.0,-428.25000000000017
|
||||
2026-02-15,0.0,-428.25000000000017
|
||||
2026-02-16,-149.54999999999998,-577.8000000000002
|
||||
2026-02-17,70.7,-507.1000000000002
|
||||
2026-02-18,0.0,-507.1000000000002
|
||||
2026-02-19,445.3,-61.80000000000018
|
||||
2026-02-20,-67.5,-129.30000000000018
|
||||
2026-02-21,0.0,-129.30000000000018
|
||||
2026-02-22,0.0,-129.30000000000018
|
||||
2026-02-23,1518.2,1388.8999999999999
|
||||
2026-02-24,-656.6600000000001,732.2399999999998
|
||||
2026-02-25,-317.33,414.9099999999998
|
||||
2026-02-26,37.540000000000006,452.4499999999998
|
||||
2026-02-27,329.27,781.7199999999998
|
||||
2026-02-28,0.0,781.7199999999998
|
||||
2026-03-01,0.0,781.7199999999998
|
||||
2026-03-02,1041.1699999999998,1822.8899999999996
|
||||
2026-03-03,-502.8700000000001,1320.0199999999995
|
||||
2026-03-04,-151.68,1168.3399999999995
|
||||
2026-03-05,-188.37,979.9699999999995
|
||||
2026-03-06,-376.65999999999997,603.3099999999995
|
||||
2026-03-07,0.0,603.3099999999995
|
||||
2026-03-08,0.0,603.3099999999995
|
||||
2026-03-09,-296.76,306.5499999999995
|
||||
2026-03-10,246.82999999999998,553.3799999999994
|
||||
2026-03-11,290.42,843.7999999999995
|
||||
2026-03-12,113.06,956.8599999999994
|
||||
2026-03-13,-159.65000000000003,797.2099999999994
|
||||
2026-03-14,0.0,797.2099999999994
|
||||
2026-03-15,0.0,797.2099999999994
|
||||
2026-03-16,87.19,884.3999999999994
|
||||
2026-03-17,-173.84,710.5599999999994
|
||||
2026-03-18,177.18,887.7399999999993
|
||||
2026-03-19,1335.5,2223.2399999999993
|
||||
2026-03-20,-220.1,2003.1399999999994
|
||||
2026-03-21,0.0,2003.1399999999994
|
||||
2026-03-22,0.0,2003.1399999999994
|
||||
2026-03-23,-83.66,1919.4799999999993
|
||||
2026-03-24,-243.82,1675.6599999999994
|
||||
2026-03-25,-539.69,1135.9699999999993
|
||||
2026-03-26,618.53,1754.4999999999993
|
||||
2026-03-27,365.03,2119.5299999999993
|
||||
2026-03-28,0.0,2119.5299999999993
|
||||
2026-03-29,0.0,2119.5299999999993
|
||||
2026-03-30,-1182.6200000000001,936.9099999999992
|
||||
2026-03-31,425.55,1362.4599999999991
|
||||
2026-04-01,75.17,1437.6299999999992
|
||||
2026-04-02,951.76,2389.3899999999994
|
||||
2026-04-03,0.0,2389.3899999999994
|
||||
2026-04-04,0.0,2389.3899999999994
|
||||
2026-04-05,0.0,2389.3899999999994
|
||||
2026-04-06,421.78999999999996,2811.1799999999994
|
||||
2026-04-07,-317.53999999999996,2493.6399999999994
|
||||
2026-04-08,798.5600000000001,3292.1999999999994
|
||||
2026-04-09,-652.1,2640.0999999999995
|
||||
2026-04-10,-176.86,2463.2399999999993
|
||||
2026-04-11,0.0,2463.2399999999993
|
||||
2026-04-12,0.0,2463.2399999999993
|
||||
2026-04-13,-408.28000000000003,2054.959999999999
|
||||
2026-04-14,174.01000000000002,2228.9699999999993
|
||||
2026-04-15,600.54,2829.5099999999993
|
||||
|
|
After Width: | Height: | Size: 139 KiB |
@@ -0,0 +1,256 @@
|
||||
#property strict
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input group "=== Market ==="
|
||||
input string InpSymbol = "BTCUSD";
|
||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
|
||||
input double InpLots = 0.01;
|
||||
input int InpSlippagePoints = 30;
|
||||
input int InpMagic = 930101;
|
||||
input int InpMaxPositions = 6;
|
||||
input bool InpDebugLogs = true;
|
||||
|
||||
input group "=== EMA Trend State ==="
|
||||
input int InpEmaPeriod = 200;
|
||||
input int InpTrendLookbackBars = 12;
|
||||
input double InpTrendMinPoints = 120; // total EMA delta over lookback
|
||||
input double InpFlatMaxPoints = 40; // dead-flat band over lookback
|
||||
|
||||
input group "=== RSI Entries ==="
|
||||
input int InpRsiPeriod = 14;
|
||||
input double InpRsiDipLevel = 35.0; // buy dip in uptrend
|
||||
input double InpRsiSurgeLevel = 65.0; // sell surge in downtrend
|
||||
input bool InpUseCrossSignal = true; // true=cross, false=state-based
|
||||
|
||||
input group "=== Risk ==="
|
||||
input bool InpUseHardSLTP = false;
|
||||
input double InpSLPoints = 2500;
|
||||
input double InpTPPoints = 4500;
|
||||
|
||||
enum TrendState
|
||||
{
|
||||
TREND_FLAT = 0,
|
||||
TREND_UP = 1,
|
||||
TREND_DOWN = -1
|
||||
};
|
||||
|
||||
CTrade trade;
|
||||
datetime g_lastBarTime = 0;
|
||||
|
||||
void DebugLog(const string msg)
|
||||
{
|
||||
if(InpDebugLogs)
|
||||
Print("[EMARSIWarm] ", msg);
|
||||
}
|
||||
|
||||
bool IsNewBar(const string symbol, ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
datetime t = iTime(symbol, tf, 0);
|
||||
if(t <= 0 || t == g_lastBarTime)
|
||||
return false;
|
||||
g_lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
double GetIndicatorValue(const int handle, const int bufferIdx, const int shift)
|
||||
{
|
||||
if(handle == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double v[1];
|
||||
if(CopyBuffer(handle, bufferIdx, shift, 1, v) <= 0)
|
||||
return 0.0;
|
||||
return v[0];
|
||||
}
|
||||
|
||||
double GetEma(const string symbol, ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int h = iMA(symbol, tf, period, 0, MODE_EMA, PRICE_CLOSE);
|
||||
double val = GetIndicatorValue(h, 0, shift);
|
||||
if(h != INVALID_HANDLE)
|
||||
IndicatorRelease(h);
|
||||
return val;
|
||||
}
|
||||
|
||||
double GetRsi(const string symbol, ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int h = iRSI(symbol, tf, period, PRICE_CLOSE);
|
||||
double val = GetIndicatorValue(h, 0, shift);
|
||||
if(h != INVALID_HANDLE)
|
||||
IndicatorRelease(h);
|
||||
return val;
|
||||
}
|
||||
|
||||
TrendState GetTrendState()
|
||||
{
|
||||
double emaNow = GetEma(InpSymbol, InpTimeframe, InpEmaPeriod, 1);
|
||||
double emaPast = GetEma(InpSymbol, InpTimeframe, InpEmaPeriod, 1 + InpTrendLookbackBars);
|
||||
if(emaNow == 0.0 || emaPast == 0.0)
|
||||
return TREND_FLAT;
|
||||
|
||||
double deltaPts = (emaNow - emaPast) / _Point;
|
||||
if(MathAbs(deltaPts) <= InpFlatMaxPoints)
|
||||
return TREND_FLAT;
|
||||
if(deltaPts >= InpTrendMinPoints)
|
||||
return TREND_UP;
|
||||
if(deltaPts <= -InpTrendMinPoints)
|
||||
return TREND_DOWN;
|
||||
return TREND_FLAT;
|
||||
}
|
||||
|
||||
int CountPositionsByMagic(const string symbol, const int magic)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
(int)PositionGetInteger(POSITION_MAGIC) == magic)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
string TrendStateToString(const TrendState s)
|
||||
{
|
||||
if(s == TREND_UP) return "UP";
|
||||
if(s == TREND_DOWN) return "DOWN";
|
||||
return "FLAT";
|
||||
}
|
||||
|
||||
void CloseAllByMagic(const string symbol, const int magic)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
(int)PositionGetInteger(POSITION_MAGIC) == magic)
|
||||
trade.PositionClose(t);
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeSLTP(const bool isBuy, const double entry, double &sl, double &tp)
|
||||
{
|
||||
if(!InpUseHardSLTP)
|
||||
{
|
||||
sl = 0.0;
|
||||
tp = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(isBuy)
|
||||
{
|
||||
sl = entry - InpSLPoints * _Point;
|
||||
tp = entry + InpTPPoints * _Point;
|
||||
}
|
||||
else
|
||||
{
|
||||
sl = entry + InpSLPoints * _Point;
|
||||
tp = entry - InpTPPoints * _Point;
|
||||
}
|
||||
}
|
||||
|
||||
bool BuySignal()
|
||||
{
|
||||
double r1 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 1);
|
||||
double r2 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 2);
|
||||
if(r1 == 0.0 || r2 == 0.0)
|
||||
return false;
|
||||
|
||||
if(InpUseCrossSignal)
|
||||
return (r2 > InpRsiDipLevel && r1 <= InpRsiDipLevel); // fresh dip
|
||||
return (r1 <= InpRsiDipLevel);
|
||||
}
|
||||
|
||||
bool SellSignal()
|
||||
{
|
||||
double r1 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 1);
|
||||
double r2 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 2);
|
||||
if(r1 == 0.0 || r2 == 0.0)
|
||||
return false;
|
||||
|
||||
if(InpUseCrossSignal)
|
||||
return (r2 < InpRsiSurgeLevel && r1 >= InpRsiSurgeLevel); // fresh surge
|
||||
return (r1 >= InpRsiSurgeLevel);
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(_Symbol != InpSymbol)
|
||||
{
|
||||
static datetime lastMismatchLog = 0;
|
||||
datetime nowBar = iTime(_Symbol, PERIOD_M1, 0);
|
||||
if(nowBar != lastMismatchLog)
|
||||
{
|
||||
lastMismatchLog = nowBar;
|
||||
DebugLog(StringFormat("Skipped: chart symbol=%s but InpSymbol=%s. Attach EA to %s chart or set InpSymbol=%s.",
|
||||
_Symbol, InpSymbol, InpSymbol, _Symbol));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!IsNewBar(InpSymbol, InpTimeframe))
|
||||
return;
|
||||
|
||||
TrendState state = GetTrendState();
|
||||
double rsi1 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 1);
|
||||
double rsi2 = GetRsi(InpSymbol, InpTimeframe, InpRsiPeriod, 2);
|
||||
int posCount = CountPositionsByMagic(InpSymbol, InpMagic);
|
||||
DebugLog(StringFormat("Bar=%s state=%s rsi1=%.2f rsi2=%.2f positions=%d",
|
||||
TimeToString(iTime(InpSymbol, InpTimeframe, 1), TIME_DATE|TIME_MINUTES),
|
||||
TrendStateToString(state), rsi1, rsi2, posCount));
|
||||
|
||||
// Core idea: when EMA is "dead flat", flatten everything.
|
||||
if(state == TREND_FLAT)
|
||||
{
|
||||
DebugLog("Action: EMA flat -> closing all positions for this magic.");
|
||||
CloseAllByMagic(InpSymbol, InpMagic);
|
||||
return;
|
||||
}
|
||||
|
||||
if(posCount >= InpMaxPositions)
|
||||
{
|
||||
DebugLog(StringFormat("Skipped: max positions reached (%d).", InpMaxPositions));
|
||||
return;
|
||||
}
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
{
|
||||
DebugLog("Skipped: SymbolInfoTick failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
trade.SetExpertMagicNumber(InpMagic);
|
||||
trade.SetDeviationInPoints(InpSlippagePoints);
|
||||
|
||||
if(state == TREND_UP && BuySignal())
|
||||
{
|
||||
ComputeSLTP(true, tick.ask, sl, tp);
|
||||
if(trade.Buy(InpLots, InpSymbol, tick.ask, sl, tp, "EMAUp_RSIDip_Buy"))
|
||||
DebugLog(StringFormat("BUY opened lots=%.2f price=%.2f sl=%.2f tp=%.2f", InpLots, tick.ask, sl, tp));
|
||||
else
|
||||
DebugLog(StringFormat("BUY failed retcode=%d", trade.ResultRetcode()));
|
||||
}
|
||||
else if(state == TREND_DOWN && SellSignal())
|
||||
{
|
||||
ComputeSLTP(false, tick.bid, sl, tp);
|
||||
if(trade.Sell(InpLots, InpSymbol, tick.bid, sl, tp, "EMADown_RSISurge_Sell"))
|
||||
DebugLog(StringFormat("SELL opened lots=%.2f price=%.2f sl=%.2f tp=%.2f", InpLots, tick.bid, sl, tp));
|
||||
else
|
||||
DebugLog(StringFormat("SELL failed retcode=%d", trade.ResultRetcode()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(state == TREND_UP)
|
||||
DebugLog("No entry: UP trend but RSI dip condition not met.");
|
||||
else if(state == TREND_DOWN)
|
||||
DebugLog("No entry: DOWN trend but RSI surge condition not met.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
\section{Simple EMA Price-Action: V1 Exploration Roadmap}
|
||||
\label{sec:simple-ema-v1-roadmap}
|
||||
|
||||
\textbf{Objective (V1).}
|
||||
Establish a robust baseline for the BTCUSD EMA price-action cross strategy before adding complexity. V1 prioritizes stability, explainability, and out-of-sample consistency.
|
||||
|
||||
\begin{enumerate}
|
||||
\item \textbf{Baseline calibration}: optimize core parameters ($EMA$ period, minimum candle body, ATR stop/take-profit multipliers) with bounded search ranges and fixed transaction-cost assumptions.
|
||||
\item \textbf{Regime segmentation}: split results by volatility/trend regime (e.g., ATR percentile and ADX bins) to identify where the strategy has structural edge.
|
||||
\item \textbf{Session effects}: evaluate performance across Asia, London, and New York sessions; test session-specific body-size and risk multipliers.
|
||||
\item \textbf{Exit policy comparison}: compare fixed ATR exits vs. trailing stop and partial take-profit exits; report trade duration, payoff skew, and drawdown impact.
|
||||
\item \textbf{Execution stress test}: re-run with adverse spread/slippage scenarios to measure fragility and realistic live-trading degradation.
|
||||
\item \textbf{Position-sizing study}: benchmark fixed lot, volatility targeting, and capped fractional sizing with drawdown constraints.
|
||||
\item \textbf{Signal quality filters}: test wick/body ratio and momentum confirmation to reduce false crosses; quantify precision-recall tradeoff.
|
||||
\item \textbf{Walk-forward validation}: use rolling train-test windows and report parameter drift, out-of-sample Sharpe, and failure periods.
|
||||
\item \textbf{Statistical confidence}: include bootstrap confidence intervals for Sharpe, profit factor, win rate, and max drawdown.
|
||||
\item \textbf{Portfolio contribution}: evaluate correlation-adjusted P\&L contribution when combined with other robots in the united\_dynamic stack.
|
||||
\end{enumerate}
|
||||
|
||||
\textbf{V1 deliverables.}
|
||||
For each experiment, report: net P\&L, Sharpe, Sortino, max drawdown, profit factor, win rate, average trade duration, and out-of-sample performance delta.
|
||||
@@ -0,0 +1,179 @@
|
||||
#property strict
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input group "=== Market ==="
|
||||
input string InpSymbol = "BTCUSD";
|
||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
|
||||
input double InpLots = 0.01;
|
||||
input int InpSlippagePoints = 30;
|
||||
input int InpMagic = 910001;
|
||||
|
||||
input group "=== Signal ==="
|
||||
input int InpEmaPeriod = 50;
|
||||
input int InpBodyMinPoints = 100; // Minimal candle body size
|
||||
|
||||
input group "=== Risk ==="
|
||||
input bool InpUseAtrStops = true;
|
||||
input int InpAtrPeriod = 14;
|
||||
input double InpSlAtrMult = 1.8;
|
||||
input double InpTpAtrMult = 3.0;
|
||||
input double InpFallbackSLPoints = 2500;
|
||||
input double InpFallbackTPPoints = 4500;
|
||||
|
||||
CTrade trade;
|
||||
datetime g_lastBarTime = 0;
|
||||
|
||||
bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
datetime t = iTime(symbol, tf, 0);
|
||||
if(t <= 0)
|
||||
return false;
|
||||
|
||||
if(t == g_lastBarTime)
|
||||
return false;
|
||||
|
||||
g_lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SelectOwnPosition(const string symbol, const int magic)
|
||||
{
|
||||
if(!PositionSelect(symbol))
|
||||
return false;
|
||||
return (int)PositionGetInteger(POSITION_MAGIC) == magic;
|
||||
}
|
||||
|
||||
double GetAtrPoints(const string symbol, const ENUM_TIMEFRAMES tf, const int period)
|
||||
{
|
||||
int hAtr = iATR(symbol, tf, period);
|
||||
if(hAtr == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
|
||||
double atrBuff[1];
|
||||
if(CopyBuffer(hAtr, 0, 1, 1, atrBuff) <= 0)
|
||||
{
|
||||
IndicatorRelease(hAtr);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
IndicatorRelease(hAtr);
|
||||
return atrBuff[0] / _Point;
|
||||
}
|
||||
|
||||
double GetEmaValue(const string symbol, const ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int hEma = iMA(symbol, tf, period, 0, MODE_EMA, PRICE_CLOSE);
|
||||
if(hEma == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
|
||||
double emaBuff[1];
|
||||
if(CopyBuffer(hEma, 0, shift, 1, emaBuff) <= 0)
|
||||
{
|
||||
IndicatorRelease(hEma);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
IndicatorRelease(hEma);
|
||||
return emaBuff[0];
|
||||
}
|
||||
|
||||
void ComputeStops(const bool isBuy, const double entry, double &sl, double &tp)
|
||||
{
|
||||
double slPts = InpFallbackSLPoints;
|
||||
double tpPts = InpFallbackTPPoints;
|
||||
|
||||
if(InpUseAtrStops)
|
||||
{
|
||||
double atrPts = GetAtrPoints(InpSymbol, InpTimeframe, InpAtrPeriod);
|
||||
if(atrPts > 0.0)
|
||||
{
|
||||
slPts = MathMax(atrPts * InpSlAtrMult, 100.0);
|
||||
tpPts = MathMax(atrPts * InpTpAtrMult, 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
if(isBuy)
|
||||
{
|
||||
sl = entry - slPts * _Point;
|
||||
tp = entry + tpPts * _Point;
|
||||
}
|
||||
else
|
||||
{
|
||||
sl = entry + slPts * _Point;
|
||||
tp = entry - tpPts * _Point;
|
||||
}
|
||||
}
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
if(!SymbolSelect(InpSymbol, true))
|
||||
{
|
||||
Print("Failed to select symbol: ", InpSymbol);
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
trade.SetDeviationInPoints(InpSlippagePoints);
|
||||
trade.SetExpertMagicNumber(InpMagic);
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(_Symbol != InpSymbol)
|
||||
return;
|
||||
|
||||
if(!IsNewBar(InpSymbol, InpTimeframe))
|
||||
return;
|
||||
|
||||
// Use closed candles (shift 1 and 2) to avoid intrabar repainting behavior.
|
||||
double o1 = iOpen(InpSymbol, InpTimeframe, 1);
|
||||
double c1 = iClose(InpSymbol, InpTimeframe, 1);
|
||||
double o2 = iOpen(InpSymbol, InpTimeframe, 2);
|
||||
double c2 = iClose(InpSymbol, InpTimeframe, 2);
|
||||
double e1 = GetEmaValue(InpSymbol, InpTimeframe, InpEmaPeriod, 1);
|
||||
double e2 = GetEmaValue(InpSymbol, InpTimeframe, InpEmaPeriod, 2);
|
||||
|
||||
if(e1 == 0.0 || e2 == 0.0)
|
||||
return;
|
||||
|
||||
bool bullishBody = (c1 > o1) && ((c1 - o1) / _Point >= InpBodyMinPoints);
|
||||
bool bearishBody = (o1 > c1) && ((o1 - c1) / _Point >= InpBodyMinPoints);
|
||||
bool crossedUp = (c2 <= e2 && c1 > e1);
|
||||
bool crossedDown = (c2 >= e2 && c1 < e1);
|
||||
|
||||
bool longSignal = crossedUp && bullishBody;
|
||||
bool shortSignal = crossedDown && bearishBody;
|
||||
|
||||
bool hasPos = SelectOwnPosition(InpSymbol, InpMagic);
|
||||
if(hasPos)
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if((posType == POSITION_TYPE_BUY && shortSignal) ||
|
||||
(posType == POSITION_TYPE_SELL && longSignal))
|
||||
{
|
||||
trade.PositionClose(InpSymbol);
|
||||
hasPos = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasPos)
|
||||
return;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(longSignal)
|
||||
{
|
||||
ComputeStops(true, tick.ask, sl, tp);
|
||||
trade.Buy(InpLots, InpSymbol, tick.ask, sl, tp, "Simple EMA PA Cross");
|
||||
}
|
||||
else if(shortSignal)
|
||||
{
|
||||
ComputeStops(false, tick.bid, sl, tp);
|
||||
trade.Sell(InpLots, InpSymbol, tick.bid, sl, tp, "Simple EMA PA Cross");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
#property strict
|
||||
#property version "1.10"
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input group "=== Market ==="
|
||||
input string InpSymbol = "BTCUSD";
|
||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
|
||||
input double InpLots = 0.01;
|
||||
input int InpSlippagePoints = 30;
|
||||
input int InpMagic = 910011;
|
||||
|
||||
input group "=== Signal ==="
|
||||
input int InpEmaPeriod = 50;
|
||||
input int InpBodyMinPoints = 100;
|
||||
input bool InpUseAdxFilter = true;
|
||||
input int InpAdxPeriod = 14;
|
||||
input double InpAdxMin = 18.0;
|
||||
|
||||
input group "=== Session Filter (Server Hour) ==="
|
||||
input bool InpUseSessionFilter = false;
|
||||
input int InpSessionStartHour = 6;
|
||||
input int InpSessionEndHour = 22;
|
||||
|
||||
input group "=== Risk ==="
|
||||
input bool InpUseAtrStops = true;
|
||||
input int InpAtrPeriod = 14;
|
||||
input double InpSlAtrMult = 1.8;
|
||||
input double InpTpAtrMult = 3.0;
|
||||
input bool InpUseHardSL = true;
|
||||
input bool InpUseHardTP = false;
|
||||
input bool InpUseTrailingStop = true;
|
||||
input double InpTrailAtrMult = 1.2;
|
||||
input bool InpUseBreakEven = true;
|
||||
input double InpBreakEvenAtrTrigger = 1.0;
|
||||
input double InpBreakEvenLockPoints = 100;
|
||||
input double InpFallbackSLPoints = 2500;
|
||||
input double InpFallbackTPPoints = 4500;
|
||||
|
||||
CTrade trade;
|
||||
datetime g_lastBarTime = 0;
|
||||
|
||||
bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
datetime t = iTime(symbol, tf, 0);
|
||||
if(t <= 0 || t == g_lastBarTime)
|
||||
return false;
|
||||
g_lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsInAllowedSession()
|
||||
{
|
||||
if(!InpUseSessionFilter)
|
||||
return true;
|
||||
|
||||
MqlDateTime dt;
|
||||
if(!TimeToStruct(TimeCurrent(), dt))
|
||||
return true;
|
||||
int h = dt.hour;
|
||||
if(InpSessionStartHour <= InpSessionEndHour)
|
||||
return (h >= InpSessionStartHour && h < InpSessionEndHour);
|
||||
|
||||
// Overnight window, e.g. 22 -> 6
|
||||
return (h >= InpSessionStartHour || h < InpSessionEndHour);
|
||||
}
|
||||
|
||||
bool SelectOwnPosition(const string symbol, const int magic)
|
||||
{
|
||||
if(!PositionSelect(symbol))
|
||||
return false;
|
||||
return (int)PositionGetInteger(POSITION_MAGIC) == magic;
|
||||
}
|
||||
|
||||
double GetIndicatorValue(const int handle, const int bufferIndex, const int shift)
|
||||
{
|
||||
if(handle == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
|
||||
double buff[1];
|
||||
if(CopyBuffer(handle, bufferIndex, shift, 1, buff) <= 0)
|
||||
return 0.0;
|
||||
return buff[0];
|
||||
}
|
||||
|
||||
double GetAtrPoints(const string symbol, const ENUM_TIMEFRAMES tf, const int period)
|
||||
{
|
||||
int hAtr = iATR(symbol, tf, period);
|
||||
double atr = GetIndicatorValue(hAtr, 0, 1);
|
||||
if(hAtr != INVALID_HANDLE)
|
||||
IndicatorRelease(hAtr);
|
||||
if(atr <= 0.0)
|
||||
return 0.0;
|
||||
return atr / _Point;
|
||||
}
|
||||
|
||||
double GetEmaValue(const string symbol, const ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int hEma = iMA(symbol, tf, period, 0, MODE_EMA, PRICE_CLOSE);
|
||||
double ema = GetIndicatorValue(hEma, 0, shift);
|
||||
if(hEma != INVALID_HANDLE)
|
||||
IndicatorRelease(hEma);
|
||||
return ema;
|
||||
}
|
||||
|
||||
double GetAdxValue(const string symbol, const ENUM_TIMEFRAMES tf, const int period, const int shift)
|
||||
{
|
||||
int hAdx = iADX(symbol, tf, period);
|
||||
double adx = GetIndicatorValue(hAdx, 0, shift);
|
||||
if(hAdx != INVALID_HANDLE)
|
||||
IndicatorRelease(hAdx);
|
||||
return adx;
|
||||
}
|
||||
|
||||
void ComputeStops(const bool isBuy, const double entry, double &sl, double &tp)
|
||||
{
|
||||
double slPts = InpFallbackSLPoints;
|
||||
double tpPts = InpFallbackTPPoints;
|
||||
|
||||
if(InpUseAtrStops)
|
||||
{
|
||||
double atrPts = GetAtrPoints(InpSymbol, InpTimeframe, InpAtrPeriod);
|
||||
if(atrPts > 0.0)
|
||||
{
|
||||
slPts = MathMax(atrPts * InpSlAtrMult, 100.0);
|
||||
tpPts = MathMax(atrPts * InpTpAtrMult, 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
if(isBuy)
|
||||
{
|
||||
sl = InpUseHardSL ? (entry - slPts * _Point) : 0.0;
|
||||
tp = InpUseHardTP ? (entry + tpPts * _Point) : 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sl = InpUseHardSL ? (entry + slPts * _Point) : 0.0;
|
||||
tp = InpUseHardTP ? (entry - tpPts * _Point) : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ManageOpenPosition()
|
||||
{
|
||||
if(!SelectOwnPosition(InpSymbol, InpMagic))
|
||||
return;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return;
|
||||
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double curSL = PositionGetDouble(POSITION_SL);
|
||||
double curTP = PositionGetDouble(POSITION_TP);
|
||||
|
||||
double atrPts = GetAtrPoints(InpSymbol, InpTimeframe, InpAtrPeriod);
|
||||
if(atrPts <= 0.0)
|
||||
atrPts = InpFallbackSLPoints;
|
||||
|
||||
double triggerPts = atrPts * InpBreakEvenAtrTrigger;
|
||||
double trailPts = MathMax(atrPts * InpTrailAtrMult, 50.0);
|
||||
|
||||
double newSL = curSL;
|
||||
bool needModify = false;
|
||||
|
||||
if(posType == POSITION_TYPE_BUY)
|
||||
{
|
||||
double profitPts = (tick.bid - openPrice) / _Point;
|
||||
|
||||
if(InpUseBreakEven && profitPts >= triggerPts)
|
||||
{
|
||||
double beSL = openPrice + InpBreakEvenLockPoints * _Point;
|
||||
if(newSL == 0.0 || beSL > newSL)
|
||||
{
|
||||
newSL = beSL;
|
||||
needModify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(InpUseTrailingStop)
|
||||
{
|
||||
double trailSL = tick.bid - trailPts * _Point;
|
||||
if((newSL == 0.0 || trailSL > newSL) && trailSL < tick.bid)
|
||||
{
|
||||
newSL = trailSL;
|
||||
needModify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(posType == POSITION_TYPE_SELL)
|
||||
{
|
||||
double profitPts = (openPrice - tick.ask) / _Point;
|
||||
|
||||
if(InpUseBreakEven && profitPts >= triggerPts)
|
||||
{
|
||||
double beSL = openPrice - InpBreakEvenLockPoints * _Point;
|
||||
if(newSL == 0.0 || beSL < newSL)
|
||||
{
|
||||
newSL = beSL;
|
||||
needModify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(InpUseTrailingStop)
|
||||
{
|
||||
double trailSL = tick.ask + trailPts * _Point;
|
||||
if((newSL == 0.0 || trailSL < newSL) && trailSL > tick.ask)
|
||||
{
|
||||
newSL = trailSL;
|
||||
needModify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(needModify)
|
||||
trade.PositionModify(InpSymbol, newSL, curTP);
|
||||
}
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
if(!SymbolSelect(InpSymbol, true))
|
||||
{
|
||||
Print("Failed to select symbol: ", InpSymbol);
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
trade.SetDeviationInPoints(InpSlippagePoints);
|
||||
trade.SetExpertMagicNumber(InpMagic);
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(_Symbol != InpSymbol)
|
||||
return;
|
||||
|
||||
ManageOpenPosition();
|
||||
if(!IsInAllowedSession())
|
||||
return;
|
||||
if(!IsNewBar(InpSymbol, InpTimeframe))
|
||||
return;
|
||||
|
||||
double o1 = iOpen(InpSymbol, InpTimeframe, 1);
|
||||
double c1 = iClose(InpSymbol, InpTimeframe, 1);
|
||||
double c2 = iClose(InpSymbol, InpTimeframe, 2);
|
||||
double e1 = GetEmaValue(InpSymbol, InpTimeframe, InpEmaPeriod, 1);
|
||||
double e2 = GetEmaValue(InpSymbol, InpTimeframe, InpEmaPeriod, 2);
|
||||
if(e1 == 0.0 || e2 == 0.0)
|
||||
return;
|
||||
|
||||
if(InpUseAdxFilter)
|
||||
{
|
||||
double adx = GetAdxValue(InpSymbol, InpTimeframe, InpAdxPeriod, 1);
|
||||
if(adx < InpAdxMin)
|
||||
return;
|
||||
}
|
||||
|
||||
bool bullishBody = (c1 > o1) && ((c1 - o1) / _Point >= InpBodyMinPoints);
|
||||
bool bearishBody = (o1 > c1) && ((o1 - c1) / _Point >= InpBodyMinPoints);
|
||||
bool crossedUp = (c2 <= e2 && c1 > e1);
|
||||
bool crossedDown = (c2 >= e2 && c1 < e1);
|
||||
|
||||
bool longSignal = crossedUp && bullishBody;
|
||||
bool shortSignal = crossedDown && bearishBody;
|
||||
|
||||
bool hasPos = SelectOwnPosition(InpSymbol, InpMagic);
|
||||
if(hasPos)
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if((posType == POSITION_TYPE_BUY && shortSignal) ||
|
||||
(posType == POSITION_TYPE_SELL && longSignal))
|
||||
{
|
||||
trade.PositionClose(InpSymbol);
|
||||
hasPos = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasPos)
|
||||
return;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(longSignal)
|
||||
{
|
||||
ComputeStops(true, tick.ask, sl, tp);
|
||||
trade.Buy(InpLots, InpSymbol, tick.ask, sl, tp, "Simple EMA PA Cross V1");
|
||||
}
|
||||
else if(shortSignal)
|
||||
{
|
||||
ComputeStops(false, tick.bid, sl, tp);
|
||||
trade.Sell(InpLots, InpSymbol, tick.bid, sl, tp, "Simple EMA PA Cross V1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
#property strict
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input group "=== Common ==="
|
||||
input string InpSymbol = "BTCUSD";
|
||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
|
||||
input int InpSlippagePoints = 30;
|
||||
input int InpPivotLookbackBars = 120;
|
||||
input int InpMinSwingPoints = 500;
|
||||
|
||||
input group "=== Robot 1: Fibonacci Retracement ==="
|
||||
input bool FR_Enabled = true;
|
||||
input int FR_Magic = 920101;
|
||||
input double FR_Lots = 0.01;
|
||||
input bool FR_BuyAt618 = true;
|
||||
input bool FR_BuyAt500 = false;
|
||||
input bool FR_UseHardSLTP = true;
|
||||
input double FR_SL_BufferPoints = 400;
|
||||
input double FR_TP_BufferPoints = 400;
|
||||
input int FR_MaxHoldingBars = 96; // time-stop safety
|
||||
input bool FR_CloseOnStructureBreak = true; // close if recent swing low breaks
|
||||
|
||||
input group "=== Robot 2: Fibonacci Trend Extension ==="
|
||||
input bool FE_Enabled = true;
|
||||
input int FE_Magic = 920202;
|
||||
input double FE_Lots = 0.01;
|
||||
input bool FE_UseHardSLTP = true;
|
||||
input double FE_SL_BufferPoints = 400;
|
||||
input double FE_ExtensionLevel = 1.272; // Common values: 1.272 / 1.618
|
||||
input int FE_MinBarsBetweenTrades = 6;
|
||||
input double FE_MinStopPoints = 3000;
|
||||
input int FE_AtrPeriod = 14;
|
||||
input double FE_MinStopAtrMult = 1.2;
|
||||
input double FE_MinRR = 1.5;
|
||||
|
||||
CTrade trade;
|
||||
datetime g_lastBarTime = 0;
|
||||
datetime g_lastFEEntryTime = 0;
|
||||
datetime g_lastFREntryTime = 0;
|
||||
|
||||
bool IsNewBar(const string symbol, ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
datetime t = iTime(symbol, tf, 0);
|
||||
if(t <= 0 || t == g_lastBarTime)
|
||||
return false;
|
||||
g_lastBarTime = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetLowestLow(const string symbol, ENUM_TIMEFRAMES tf, const int bars, int &idx, double &price)
|
||||
{
|
||||
idx = iLowest(symbol, tf, MODE_LOW, bars, 1);
|
||||
if(idx < 0)
|
||||
return false;
|
||||
price = iLow(symbol, tf, idx);
|
||||
return (price > 0.0);
|
||||
}
|
||||
|
||||
bool GetHighestHigh(const string symbol, ENUM_TIMEFRAMES tf, const int bars, int &idx, double &price)
|
||||
{
|
||||
idx = iHighest(symbol, tf, MODE_HIGH, bars, 1);
|
||||
if(idx < 0)
|
||||
return false;
|
||||
price = iHigh(symbol, tf, idx);
|
||||
return (price > 0.0);
|
||||
}
|
||||
|
||||
double GetAtrPrice(const string symbol, ENUM_TIMEFRAMES tf, const int period)
|
||||
{
|
||||
int hAtr = iATR(symbol, tf, period);
|
||||
if(hAtr == INVALID_HANDLE)
|
||||
return 0.0;
|
||||
double b[1];
|
||||
if(CopyBuffer(hAtr, 0, 1, 1, b) <= 0)
|
||||
{
|
||||
IndicatorRelease(hAtr);
|
||||
return 0.0;
|
||||
}
|
||||
IndicatorRelease(hAtr);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
bool PositionExistsByMagic(const string symbol, const int magic)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
(int)PositionGetInteger(POSITION_MAGIC) == magic)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetPositionByMagic(const string symbol, const int magic, ulong &ticket, ENUM_POSITION_TYPE &posType, datetime &openTime)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0)
|
||||
continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
(int)PositionGetInteger(POSITION_MAGIC) == magic)
|
||||
{
|
||||
ticket = t;
|
||||
posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double NormalizePrice(const string symbol, const double price)
|
||||
{
|
||||
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
return NormalizeDouble(price, digits);
|
||||
}
|
||||
|
||||
bool ValidateAndAdjustStops(const bool isBuy, double &sl, double &tp)
|
||||
{
|
||||
if(sl == 0.0 && tp == 0.0)
|
||||
return true;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return false;
|
||||
|
||||
int stopsLevelPts = (int)SymbolInfoInteger(InpSymbol, SYMBOL_TRADE_STOPS_LEVEL);
|
||||
int freezeLevelPts = (int)SymbolInfoInteger(InpSymbol, SYMBOL_TRADE_FREEZE_LEVEL);
|
||||
double minDist = (double)MathMax(stopsLevelPts, freezeLevelPts) * _Point + 2.0 * _Point;
|
||||
|
||||
if(isBuy)
|
||||
{
|
||||
if(sl > 0.0 && sl >= tick.bid - minDist)
|
||||
sl = tick.bid - minDist;
|
||||
if(tp > 0.0 && tp <= tick.ask + minDist)
|
||||
tp = tick.ask + minDist;
|
||||
if(sl > 0.0 && sl >= tick.bid)
|
||||
return false;
|
||||
if(tp > 0.0 && tp <= tick.ask)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sl > 0.0 && sl <= tick.ask + minDist)
|
||||
sl = tick.ask + minDist;
|
||||
if(tp > 0.0 && tp >= tick.bid - minDist)
|
||||
tp = tick.bid - minDist;
|
||||
if(sl > 0.0 && sl <= tick.ask)
|
||||
return false;
|
||||
if(tp > 0.0 && tp >= tick.bid)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sl > 0.0)
|
||||
sl = NormalizePrice(InpSymbol, sl);
|
||||
if(tp > 0.0)
|
||||
tp = NormalizePrice(InpSymbol, tp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenBuy(const int magic, const double lots, const string comment, const double sl, const double tp)
|
||||
{
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return false;
|
||||
double useSL = sl, useTP = tp;
|
||||
if(!ValidateAndAdjustStops(true, useSL, useTP))
|
||||
return false;
|
||||
trade.SetExpertMagicNumber(magic);
|
||||
bool ok = trade.Buy(lots, InpSymbol, tick.ask, useSL, useTP, comment);
|
||||
if(ok && magic == FR_Magic)
|
||||
g_lastFREntryTime = iTime(InpSymbol, InpTimeframe, 0);
|
||||
if(ok && magic == FE_Magic)
|
||||
g_lastFEEntryTime = iTime(InpSymbol, InpTimeframe, 0);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool OpenSell(const int magic, const double lots, const string comment, const double sl, const double tp)
|
||||
{
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return false;
|
||||
double useSL = sl, useTP = tp;
|
||||
if(!ValidateAndAdjustStops(false, useSL, useTP))
|
||||
return false;
|
||||
trade.SetExpertMagicNumber(magic);
|
||||
bool ok = trade.Sell(lots, InpSymbol, tick.bid, useSL, useTP, comment);
|
||||
if(ok && magic == FE_Magic)
|
||||
g_lastFEEntryTime = iTime(InpSymbol, InpTimeframe, 0);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void RunFibonacciRetracement()
|
||||
{
|
||||
if(!FR_Enabled)
|
||||
return;
|
||||
if(PositionExistsByMagic(InpSymbol, FR_Magic))
|
||||
return;
|
||||
|
||||
int idxLow = -1, idxHigh = -1;
|
||||
double swingLow = 0.0, swingHigh = 0.0;
|
||||
if(!GetLowestLow(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxLow, swingLow))
|
||||
return;
|
||||
if(!GetHighestHigh(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxHigh, swingHigh))
|
||||
return;
|
||||
|
||||
double rangePts = (swingHigh - swingLow) / _Point;
|
||||
if(rangePts < InpMinSwingPoints)
|
||||
return;
|
||||
|
||||
// Uptrend retracement model: low appears before high.
|
||||
bool upSwing = (idxLow > idxHigh);
|
||||
if(!upSwing)
|
||||
return;
|
||||
|
||||
double fib50 = swingHigh - (swingHigh - swingLow) * 0.500;
|
||||
double fib61 = swingHigh - (swingHigh - swingLow) * 0.618;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return;
|
||||
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(FR_UseHardSLTP)
|
||||
{
|
||||
// Positional levels: SL below swing low, TP near prior swing high breakout.
|
||||
sl = swingLow - FR_SL_BufferPoints * _Point;
|
||||
tp = swingHigh + FR_TP_BufferPoints * _Point;
|
||||
}
|
||||
|
||||
if(FR_BuyAt618 && tick.ask <= fib61)
|
||||
OpenBuy(FR_Magic, FR_Lots, "FiboRetrace-61.8 Buy", sl, tp);
|
||||
else if(FR_BuyAt500 && tick.ask <= fib50)
|
||||
OpenBuy(FR_Magic, FR_Lots, "FiboRetrace-50.0 Buy", sl, tp);
|
||||
}
|
||||
|
||||
void ManageFibonacciRetracementExit()
|
||||
{
|
||||
if(!FR_Enabled)
|
||||
return;
|
||||
|
||||
ulong ticket = 0;
|
||||
ENUM_POSITION_TYPE posType = WRONG_VALUE;
|
||||
datetime openTime = 0;
|
||||
if(!GetPositionByMagic(InpSymbol, FR_Magic, ticket, posType, openTime))
|
||||
return;
|
||||
|
||||
int tfSec = PeriodSeconds(InpTimeframe);
|
||||
if(tfSec <= 0)
|
||||
tfSec = 60;
|
||||
int barsHeld = (int)((iTime(InpSymbol, InpTimeframe, 0) - openTime) / tfSec);
|
||||
|
||||
// 1) Time stop: force close stale retracement trades.
|
||||
if(FR_MaxHoldingBars > 0 && barsHeld >= FR_MaxHoldingBars)
|
||||
{
|
||||
trade.PositionClose(ticket);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) Structure invalidation: if latest swing violates the trade idea, exit.
|
||||
if(FR_CloseOnStructureBreak)
|
||||
{
|
||||
int idxLow = -1, idxHigh = -1;
|
||||
double swingLow = 0.0, swingHigh = 0.0;
|
||||
if(GetLowestLow(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxLow, swingLow) &&
|
||||
GetHighestHigh(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxHigh, swingHigh))
|
||||
{
|
||||
MqlTick tick;
|
||||
if(SymbolInfoTick(InpSymbol, tick))
|
||||
{
|
||||
double invalidateBuffer = FR_SL_BufferPoints * _Point;
|
||||
if(posType == POSITION_TYPE_BUY && tick.bid < (swingLow - invalidateBuffer))
|
||||
trade.PositionClose(ticket);
|
||||
else if(posType == POSITION_TYPE_SELL && tick.ask > (swingHigh + invalidateBuffer))
|
||||
trade.PositionClose(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunFibonacciExtension()
|
||||
{
|
||||
if(!FE_Enabled)
|
||||
return;
|
||||
if(PositionExistsByMagic(InpSymbol, FE_Magic))
|
||||
return;
|
||||
if(g_lastFEEntryTime > 0)
|
||||
{
|
||||
int tfSec = PeriodSeconds(InpTimeframe);
|
||||
if(tfSec > 0)
|
||||
{
|
||||
int barsSince = (int)((iTime(InpSymbol, InpTimeframe, 0) - g_lastFEEntryTime) / tfSec);
|
||||
if(barsSince < FE_MinBarsBetweenTrades)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int idxLow = -1, idxHigh = -1;
|
||||
double swingLow = 0.0, swingHigh = 0.0;
|
||||
if(!GetLowestLow(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxLow, swingLow))
|
||||
return;
|
||||
if(!GetHighestHigh(InpSymbol, InpTimeframe, InpPivotLookbackBars, idxHigh, swingHigh))
|
||||
return;
|
||||
|
||||
double rangePts = (swingHigh - swingLow) / _Point;
|
||||
if(rangePts < InpMinSwingPoints)
|
||||
return;
|
||||
|
||||
MqlTick tick;
|
||||
if(!SymbolInfoTick(InpSymbol, tick))
|
||||
return;
|
||||
|
||||
// Continuation breakout model:
|
||||
// - If up swing (low before high), buy above swing high and target extension.
|
||||
// - If down swing (high before low), sell below swing low and target extension.
|
||||
bool upSwing = (idxLow > idxHigh);
|
||||
|
||||
if(upSwing && tick.ask > swingHigh)
|
||||
{
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(FE_UseHardSLTP)
|
||||
{
|
||||
sl = swingHigh - FE_SL_BufferPoints * _Point;
|
||||
double extTP = swingLow + (swingHigh - swingLow) * FE_ExtensionLevel;
|
||||
double atr = GetAtrPrice(InpSymbol, InpTimeframe, FE_AtrPeriod);
|
||||
double minRisk = MathMax(FE_MinStopPoints * _Point, atr * FE_MinStopAtrMult);
|
||||
double risk = tick.ask - sl;
|
||||
if(risk < minRisk)
|
||||
return; // Skip fragile entries with overly tight stop.
|
||||
double rrTP = tick.ask + risk * FE_MinRR;
|
||||
tp = MathMax(extTP, rrTP);
|
||||
}
|
||||
OpenBuy(FE_Magic, FE_Lots, "FiboExtension Buy", sl, tp);
|
||||
}
|
||||
else if(!upSwing && tick.bid < swingLow)
|
||||
{
|
||||
double sl = 0.0, tp = 0.0;
|
||||
if(FE_UseHardSLTP)
|
||||
{
|
||||
sl = swingLow + FE_SL_BufferPoints * _Point;
|
||||
double extTP = swingHigh - (swingHigh - swingLow) * FE_ExtensionLevel;
|
||||
double atr = GetAtrPrice(InpSymbol, InpTimeframe, FE_AtrPeriod);
|
||||
double minRisk = MathMax(FE_MinStopPoints * _Point, atr * FE_MinStopAtrMult);
|
||||
double risk = sl - tick.bid;
|
||||
if(risk < minRisk)
|
||||
return; // Skip fragile entries with overly tight stop.
|
||||
double rrTP = tick.bid - risk * FE_MinRR;
|
||||
tp = MathMin(extTP, rrTP);
|
||||
}
|
||||
OpenSell(FE_Magic, FE_Lots, "FiboExtension Sell", sl, tp);
|
||||
}
|
||||
}
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
if(!SymbolSelect(InpSymbol, true))
|
||||
return(INIT_FAILED);
|
||||
trade.SetDeviationInPoints(InpSlippagePoints);
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(_Symbol != InpSymbol)
|
||||
return;
|
||||
if(!IsNewBar(InpSymbol, InpTimeframe))
|
||||
return;
|
||||
|
||||
ManageFibonacciRetracementExit();
|
||||
RunFibonacciRetracement();
|
||||
RunFibonacciExtension();
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| rsi-scalping.mq5 |
|
||||
//| Lab EA: EMA 9/21 + Stochastic RSI — M1 scalping rules (tutorial) |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Lab"
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
|
||||
//--- inputs: indicator tuning (video defaults)
|
||||
input ENUM_TIMEFRAMES InpTf = PERIOD_M1; // Chart / signal timeframe
|
||||
input int InpEmaFast = 9; // EMA fast (short-term)
|
||||
input int InpEmaSlow = 21; // EMA slow (trend)
|
||||
input int InpRsiLen = 14; // RSI length (Stoch RSI core)
|
||||
input int InpStochLen = 14; // Stochastic lookback on RSI
|
||||
input int InpStochK = 4; // Stoch RSI %K smoothing
|
||||
input int InpStochD = 7; // Stoch RSI %D smoothing
|
||||
input double InpObLevel = 80.0; // Overbought line
|
||||
input double InpOsLevel = 20.0; // Oversold line
|
||||
//--- filters
|
||||
input bool InpUseMidZoneFilter = true; // Skip if K,D in 40–60 (indecision)
|
||||
input int InpMinBarsSinceCross = 10; // Min bars between EMA crosses
|
||||
input bool InpUseHtfFilter = false; // Align with higher TF EMAs
|
||||
input ENUM_TIMEFRAMES InpHtf = PERIOD_M5; // Higher timeframe
|
||||
input double InpMinEmaSepPts = 0.0; // Min |EMA9-EMA21| in points (0=off)
|
||||
//--- risk
|
||||
input double InpLots = 0.01;
|
||||
input int InpSlBufferPts = 20; // Extra SL beyond last 2-bar extreme
|
||||
input double InpTpRiskMultiple = 1.75; // TP = risk * this (1.5–2.0 typical)
|
||||
input bool InpExitOnEma9Break = true; // Close long if close < EMA9 (vice versa shorts)
|
||||
input bool InpExitOnStochZone = true; // Close long at Stoch RSI ≥ OB; short at ≤ OS
|
||||
//--- session
|
||||
input ulong InpMagic = 20260412;
|
||||
input int InpSlippagePts = 30;
|
||||
|
||||
CTrade g_trade;
|
||||
|
||||
int g_hEmaFast = INVALID_HANDLE;
|
||||
int g_hEmaSlow = INVALID_HANDLE;
|
||||
int g_hRsi = INVALID_HANDLE;
|
||||
int g_hEmaFastHtf = INVALID_HANDLE;
|
||||
int g_hEmaSlowHtf = INVALID_HANDLE;
|
||||
|
||||
double g_emaFast[];
|
||||
double g_emaSlow[];
|
||||
double g_rsi[];
|
||||
double g_stochK[];
|
||||
double g_stochD[];
|
||||
double g_emaFastHtf[];
|
||||
double g_emaSlowHtf[];
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
g_trade.SetExpertMagicNumber(InpMagic);
|
||||
g_trade.SetDeviationInPoints(InpSlippagePts);
|
||||
SetTradeFillingBySymbol();
|
||||
|
||||
g_hEmaFast = iMA(_Symbol, InpTf, InpEmaFast, 0, MODE_EMA, PRICE_CLOSE);
|
||||
g_hEmaSlow = iMA(_Symbol, InpTf, InpEmaSlow, 0, MODE_EMA, PRICE_CLOSE);
|
||||
g_hRsi = iRSI(_Symbol, InpTf, InpRsiLen, PRICE_CLOSE);
|
||||
if(InpUseHtfFilter)
|
||||
{
|
||||
g_hEmaFastHtf = iMA(_Symbol, InpHtf, InpEmaFast, 0, MODE_EMA, PRICE_CLOSE);
|
||||
g_hEmaSlowHtf = iMA(_Symbol, InpHtf, InpEmaSlow, 0, MODE_EMA, PRICE_CLOSE);
|
||||
}
|
||||
|
||||
if(g_hEmaFast == INVALID_HANDLE || g_hEmaSlow == INVALID_HANDLE || g_hRsi == INVALID_HANDLE)
|
||||
return INIT_FAILED;
|
||||
if(InpUseHtfFilter && (g_hEmaFastHtf == INVALID_HANDLE || g_hEmaSlowHtf == INVALID_HANDLE))
|
||||
return INIT_FAILED;
|
||||
|
||||
ArraySetAsSeries(g_emaFast, true);
|
||||
ArraySetAsSeries(g_emaSlow, true);
|
||||
ArraySetAsSeries(g_rsi, true);
|
||||
ArraySetAsSeries(g_stochK, true);
|
||||
ArraySetAsSeries(g_stochD, true);
|
||||
ArraySetAsSeries(g_emaFastHtf, true);
|
||||
ArraySetAsSeries(g_emaSlowHtf, true);
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(g_hEmaFast != INVALID_HANDLE) IndicatorRelease(g_hEmaFast);
|
||||
if(g_hEmaSlow != INVALID_HANDLE) IndicatorRelease(g_hEmaSlow);
|
||||
if(g_hRsi != INVALID_HANDLE) IndicatorRelease(g_hRsi);
|
||||
if(g_hEmaFastHtf != INVALID_HANDLE) IndicatorRelease(g_hEmaFastHtf);
|
||||
if(g_hEmaSlowHtf != INVALID_HANDLE) IndicatorRelease(g_hEmaSlowHtf);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
static datetime last_bar = 0;
|
||||
datetime t = iTime(_Symbol, InpTf, 0);
|
||||
if(t == last_bar)
|
||||
{
|
||||
// Still manage exits on tick if you use break-even / trailing — here bar-based only
|
||||
return;
|
||||
}
|
||||
last_bar = t;
|
||||
|
||||
const int need = 400;
|
||||
if(CopyBuffer(g_hEmaFast, 0, 0, need, g_emaFast) < need) return;
|
||||
if(CopyBuffer(g_hEmaSlow, 0, 0, need, g_emaSlow) < need) return;
|
||||
if(CopyBuffer(g_hRsi, 0, 0, need + InpStochLen + InpStochK + InpStochD + 5, g_rsi) < need) return;
|
||||
|
||||
if(!ComputeStochRsi(g_rsi, InpStochLen, InpStochK, InpStochD, g_stochK, g_stochD, need))
|
||||
return;
|
||||
|
||||
if(InpUseHtfFilter)
|
||||
{
|
||||
if(CopyBuffer(g_hEmaFastHtf, 0, 0, 3, g_emaFastHtf) < 3) return;
|
||||
if(CopyBuffer(g_hEmaSlowHtf, 0, 0, 3, g_emaSlowHtf) < 3) return;
|
||||
}
|
||||
|
||||
// bar 1 = last closed candle (tutorial: trade after confirmation candle closes)
|
||||
const int c = 1;
|
||||
const int p = 2;
|
||||
|
||||
if(PositionExistsForMagic())
|
||||
{
|
||||
ManageOpenPosition(c, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!PassesFlatEmaFilter(c))
|
||||
return;
|
||||
|
||||
// Long: EMA9 crosses EMA21 up at bar 1 close; Stoch RSI K,D leave oversold with bullish K/D cross
|
||||
const bool bull_cross = (g_emaFast[p] < g_emaSlow[p] && g_emaFast[c] > g_emaSlow[c]);
|
||||
const bool bear_cross = (g_emaFast[p] > g_emaSlow[p] && g_emaFast[c] < g_emaSlow[c]);
|
||||
|
||||
if(!bull_cross && !bear_cross)
|
||||
return;
|
||||
|
||||
if(InpUseHtfFilter)
|
||||
{
|
||||
if(bull_cross && !(g_emaFastHtf[c] > g_emaSlowHtf[c]))
|
||||
return;
|
||||
if(bear_cross && !(g_emaFastHtf[c] < g_emaSlowHtf[c]))
|
||||
return;
|
||||
}
|
||||
|
||||
if(!MinBarsSincePreviousCrossOk())
|
||||
return;
|
||||
|
||||
const bool stoch_long_ok =
|
||||
(g_stochK[p] < InpOsLevel && g_stochD[p] < InpOsLevel) &&
|
||||
(g_stochK[c] > g_stochD[c] && g_stochK[p] <= g_stochD[p]) &&
|
||||
(g_stochK[c] > InpOsLevel * 0.9); // "left" oversold — allow ~18 if OS=20
|
||||
|
||||
const bool stoch_short_ok =
|
||||
(g_stochK[p] > InpObLevel && g_stochD[p] > InpObLevel) &&
|
||||
(g_stochK[c] < g_stochD[c] && g_stochK[p] >= g_stochD[p]) &&
|
||||
(g_stochK[c] < InpObLevel * 1.05);
|
||||
|
||||
if(InpUseMidZoneFilter)
|
||||
{
|
||||
if(g_stochK[c] > 40.0 && g_stochK[c] < 60.0 && g_stochD[c] > 40.0 && g_stochD[c] < 60.0)
|
||||
return;
|
||||
}
|
||||
|
||||
if(bull_cross && stoch_long_ok)
|
||||
{
|
||||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||
int dg = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||||
double low12 = MathMin(iLow(_Symbol, InpTf, c), iLow(_Symbol, InpTf, p));
|
||||
double sl = low12 - InpSlBufferPts * pt;
|
||||
sl = NormalizeDouble(sl, dg);
|
||||
if(sl >= ask - pt)
|
||||
sl = ask - 10 * pt;
|
||||
double risk = ask - sl;
|
||||
if(risk <= 0) return;
|
||||
double tp = ask + risk * InpTpRiskMultiple;
|
||||
tp = NormalizeDouble(tp, dg);
|
||||
g_trade.Buy(InpLots, _Symbol, ask, sl, tp, "EMA+StochRSI long");
|
||||
return;
|
||||
}
|
||||
|
||||
if(bear_cross && stoch_short_ok)
|
||||
{
|
||||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||
int dg = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||||
double hi12 = MathMax(iHigh(_Symbol, InpTf, c), iHigh(_Symbol, InpTf, p));
|
||||
double sl = hi12 + InpSlBufferPts * pt;
|
||||
sl = NormalizeDouble(sl, dg);
|
||||
if(sl <= bid + pt)
|
||||
sl = bid + 10 * pt;
|
||||
double risk = sl - bid;
|
||||
if(risk <= 0) return;
|
||||
double tp = bid - risk * InpTpRiskMultiple;
|
||||
tp = NormalizeDouble(tp, dg);
|
||||
g_trade.Sell(InpLots, _Symbol, bid, sl, tp, "EMA+StochRSI short");
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool ComputeStochRsi(const double &rsi[], const int stoch_len, const int k_len, const int d_len,
|
||||
double &out_k[], double &out_d[], const int out_count)
|
||||
{
|
||||
int rsi_count = ArraySize(rsi);
|
||||
static double raw[];
|
||||
ArrayResize(raw, rsi_count);
|
||||
ArraySetAsSeries(raw, true);
|
||||
|
||||
for(int i = 0; i < rsi_count; i++)
|
||||
{
|
||||
if(i + stoch_len > rsi_count)
|
||||
{
|
||||
raw[i] = 50.0;
|
||||
continue;
|
||||
}
|
||||
double lo = rsi[i];
|
||||
double hi = rsi[i];
|
||||
for(int j = 0; j < stoch_len; j++)
|
||||
{
|
||||
double v = rsi[i + j];
|
||||
if(v < lo) lo = v;
|
||||
if(v > hi) hi = v;
|
||||
}
|
||||
if(hi == lo)
|
||||
raw[i] = 50.0;
|
||||
else
|
||||
raw[i] = (rsi[i] - lo) / (hi - lo) * 100.0;
|
||||
}
|
||||
|
||||
ArrayResize(out_k, out_count);
|
||||
ArrayResize(out_d, out_count);
|
||||
ArraySetAsSeries(out_k, true);
|
||||
ArraySetAsSeries(out_d, true);
|
||||
|
||||
static double k_unsm[];
|
||||
ArrayResize(k_unsm, rsi_count);
|
||||
ArraySetAsSeries(k_unsm, true);
|
||||
|
||||
for(int i = 0; i < rsi_count; i++)
|
||||
{
|
||||
if(i + k_len > rsi_count)
|
||||
{
|
||||
k_unsm[i] = raw[i];
|
||||
continue;
|
||||
}
|
||||
double s = 0.0;
|
||||
for(int j = 0; j < k_len; j++)
|
||||
s += raw[i + j];
|
||||
k_unsm[i] = s / (double)k_len;
|
||||
}
|
||||
|
||||
for(int i = 0; i < out_count; i++)
|
||||
{
|
||||
if(i + d_len > rsi_count)
|
||||
{
|
||||
out_k[i] = k_unsm[i];
|
||||
out_d[i] = k_unsm[i];
|
||||
continue;
|
||||
}
|
||||
double sk = 0.0;
|
||||
for(int j = 0; j < d_len; j++)
|
||||
sk += k_unsm[i + j];
|
||||
out_d[i] = sk / (double)d_len;
|
||||
out_k[i] = k_unsm[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool PassesFlatEmaFilter(const int c)
|
||||
{
|
||||
if(InpMinEmaSepPts <= 0.0)
|
||||
return true;
|
||||
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||
double sep = MathAbs(g_emaFast[c] - g_emaSlow[c]) / pt;
|
||||
return (sep >= InpMinEmaSepPts);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool MinBarsSincePreviousCrossOk()
|
||||
{
|
||||
if(InpMinBarsSinceCross <= 0)
|
||||
return true;
|
||||
// Cross under test completed on bar 1 (index c=1): between shift 2 and 1.
|
||||
// Earliest earlier cross: between i+1 and i for i >= 3.
|
||||
for(int i = 3; i < 300; i++)
|
||||
{
|
||||
const bool cu = (g_emaFast[i + 1] < g_emaSlow[i + 1] && g_emaFast[i] > g_emaSlow[i]);
|
||||
const bool cd = (g_emaFast[i + 1] > g_emaSlow[i + 1] && g_emaFast[i] < g_emaSlow[i]);
|
||||
if(cu || cd)
|
||||
return (i - 1 >= InpMinBarsSinceCross);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionExistsForMagic()
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0) continue;
|
||||
if(!PositionSelectByTicket(ticket)) continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
||||
if((ulong)PositionGetInteger(POSITION_MAGIC) == InpMagic)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void SetTradeFillingBySymbol()
|
||||
{
|
||||
long mask = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
|
||||
if((mask & SYMBOL_FILLING_IOC) != 0)
|
||||
g_trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
else if((mask & SYMBOL_FILLING_FOK) != 0)
|
||||
g_trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
else
|
||||
g_trade.SetTypeFilling(ORDER_FILLING_RETURN);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void ManageOpenPosition(const int c, const int p)
|
||||
{
|
||||
if(!PositionSelectBySymbolForMagic())
|
||||
return;
|
||||
ulong ticket = (ulong)PositionGetInteger(POSITION_TICKET);
|
||||
long type = PositionGetInteger(POSITION_TYPE);
|
||||
double k1 = g_stochK[c];
|
||||
double d1 = g_stochD[c];
|
||||
|
||||
if(InpExitOnEma9Break)
|
||||
{
|
||||
double close1 = iClose(_Symbol, InpTf, c);
|
||||
if(type == POSITION_TYPE_BUY && close1 < g_emaFast[c])
|
||||
{
|
||||
g_trade.PositionClose(ticket);
|
||||
return;
|
||||
}
|
||||
if(type == POSITION_TYPE_SELL && close1 > g_emaFast[c])
|
||||
{
|
||||
g_trade.PositionClose(ticket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(InpExitOnStochZone)
|
||||
{
|
||||
if(type == POSITION_TYPE_BUY && k1 >= InpObLevel && d1 >= InpObLevel * 0.95)
|
||||
{
|
||||
g_trade.PositionClose(ticket);
|
||||
return;
|
||||
}
|
||||
if(type == POSITION_TYPE_SELL && k1 <= InpOsLevel && d1 <= InpOsLevel * 1.05)
|
||||
{
|
||||
g_trade.PositionClose(ticket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectBySymbolForMagic()
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong t = PositionGetTicket(i);
|
||||
if(t == 0) continue;
|
||||
if(!PositionSelectByTicket(t)) continue;
|
||||
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
||||
if((ulong)PositionGetInteger(POSITION_MAGIC) == InpMagic)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,25 @@
|
||||
; saved for genetic optimization — rsi-scalping (rsisauce) lab EA
|
||||
; copy to: ...\MQL5\Profiles\Tester\ then Load from Inputs tab
|
||||
; last field: Y = optimize, N = fixed
|
||||
;
|
||||
InpTf=1||0||0||49153||N
|
||||
InpEmaFast=9||5||1||15||Y
|
||||
InpEmaSlow=21||15||1||34||Y
|
||||
InpRsiLen=14||10||1||21||Y
|
||||
InpStochLen=14||8||1||24||Y
|
||||
InpStochK=4||3||1||8||Y
|
||||
InpStochD=7||3||1||12||Y
|
||||
InpObLevel=80.0||72.0||1.0||88.0||Y
|
||||
InpOsLevel=20.0||12.0||1.0||28.0||Y
|
||||
InpUseMidZoneFilter=true||false||0||true||N
|
||||
InpMinBarsSinceCross=10||4||1||18||Y
|
||||
InpUseHtfFilter=false||false||0||true||N
|
||||
InpHtf=5||0||0||49153||N
|
||||
InpMinEmaSepPts=0.0||0.0||2.0||40.0||Y
|
||||
InpLots=0.01||0.01||0.001000||0.100000||N
|
||||
InpSlBufferPts=20||5||2||60||Y
|
||||
InpTpRiskMultiple=1.75||1.25||0.05||2.50||Y
|
||||
InpExitOnEma9Break=true||false||0||true||N
|
||||
InpExitOnStochZone=true||false||0||true||N
|
||||
InpMagic=20260412||20260412||1||202604120||N
|
||||
InpSlippagePts=30||30||1||300||N
|
||||