Prepare source-only public release for develop.

Add cluster audit pipeline, united EA updates, brochure generators, and publication hygiene (gitignore, MT5 path desensitization, pre-upload scan). Remove tracked reports, models, and binary artifacts from the repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zhutoutoutousan
2026-07-02 15:03:43 +02:00
co-authored by Cursor
parent 3f75a08848
commit 605faf5310
1014 changed files with 83437 additions and 10413 deletions
+142
View File
@@ -0,0 +1,142 @@
# SimpleEMA — 练手实验室
双 EMA 金叉/死叉策略,默认货币对 **EURUSD H1**(流动性好、点差低,适合入门优化)。
## 策略逻辑
| 项目 | 规则 |
|------|------|
| 入场 | 快 EMA 上穿/下穿慢 EMA(收盘 K 确认) |
| 出场 | 反向交叉 / ATR 或固定 SL·TP / 最大持仓 K 线数 / 可选 trailing |
| 过滤 | 最大点差、最小 EMA 间距 |
## 文件
| 文件 | 用途 |
|------|------|
| `main.mq5` | MT5 EAStrategy Tester / 实盘) |
| `SimpleEMA_EURUSD.set` | 默认参数 |
| `SimpleEMA_Genetic_Optimization.set` | 遗传优化范围 |
| `run_mt5_tester.py` | **调 MT5 原生 Strategy Tester**(你要的实时回测) |
| `run_backtest.py` | Python 快速回测(MT5 拉历史 K 线) |
| `run_optimize.py` | Python 随机搜索优化 |
| `trades.csv` | 逐单复盘(Python 回测产出) |
## 1. MT5 原生回测(推荐)
先确保 MT5 已登录,EURUSD H1 历史数据已下载。
```powershell
cd lab\EAs\SimpleEMA
# 单次回测(自动编译 EA → 启动 Strategy Tester → 生成 HTML 报告)
python run_mt5_tester.py backtest
# 可视化模式:看 K 线一根根跑(实时感最强)
python run_mt5_tester.py backtest --visual
# 遗传优化(Optimization=2,用 SimpleEMA_Genetic_Optimization.set
python run_mt5_tester.py optimize
```
回测完成后:
- HTML 报告路径会打印在终端(通常在 `%APPDATA%\MetaQuotes\Terminal\...\SimpleEMA_EURUSD_backtest.htm`
- 在 MT5 **结果 → 报告** 里可逐单查看开平仓、滑点、盈亏
- 优化结果在 **Optimization Results** 标签页,右键可 **Set as Input**
## 2. Python 快速迭代(改逻辑 → 立刻看 trades.csv
```powershell
python run_backtest.py
python run_backtest.py --start 2024-01-01 --fast 10 --slow 30
```
产出:`trades.csv`(每单 side / 开平时间 / 价格 / profit / exit_reason)、`report.png`
## 4. 多品种组合(20 品种)
### 分品种调参 + 组合(推荐)
```powershell
# 每个品种独立随机搜索,自动剔除 net<=0 / PF<1 的品种,再跑组合回测
python run_optimize_portfolio.py --trials 350
# 仅用已有 portfolio_params.json 重跑组合
python run_optimize_portfolio.py --skip-opt
# 验证组合
python run_portfolio_v5.py
```
产出:`portfolio_params.json`(每品种最优参数 + enabled 标记)、`portfolio_opt_trials/*.csv``best_run/portfolio_trades.csv`
### 统一参数(对比用)
```powershell
python run_portfolio_v5.py --shared-params best_params.json
```
| 文件 | 用途 |
|------|------|
| `portfolio_symbols.json` | 20 品种列表 + 各品种最大点差 |
| `portfolio_curated.json` | 全扫描后 net>0 的子集 |
| `run_portfolio_v5.py` | 组合回测,产出 `portfolio_report.json` |
| `main_portfolio.mq5` | MT5 多品种 EA(挂任意图表,监控 SymbolList 内全部品种) |
MT5 组合 EA
```powershell
python run_mt5_tester.py backtest --ea main_portfolio.mq5 --period M15 --from 2020.01.01 --to 2026.01.01
```
## 3. Python 随机搜索优化
```powershell
python run_optimize.py --trials 500
```
产出:`optimize_trials.csv``best_params.json``best_run/trades.csv`
`best_params.json` 里的值填回 `.set``main.mq5` input,再用 `run_mt5_tester.py optimize` 做 MT5 遗传精调。
## 5. MT5 回测(唯一准绳)
**2598 笔是 Python 组合模拟;`SimpleEMA_report.pdf` 只是单品种 EURUSD~115 笔)。**
组合请以 MT5 为准:
```powershell
# 12 个启用品种各跑一遍 MT5 Strategy Tester(每品种独立 .set
python run_mt5_portfolio.py --from 2020.01.01 --to 2026.01.01
# 从 MT5 HTML 报告汇总生成正式报告
python generate_mt5_portfolio_report.py
```
产出:
- `best_run/mt5_results.json` — MT5 汇总(交易数、净利)
- `best_run/mt5_reports/*.htm` — 各品种 MT5 原生报告(逐单复盘)
- `best_run/MT5_PORTFOLIO_REPORT.md` — 组合说明
- `best_run/SimpleEMA_report.png` — 由 MT5 数据生成的组合图
Python `portfolio_trades.csv` / `run_portfolio_v5.py` 仅用于快速迭代参数,**不作最终成绩**。
```
改 main.mq5 逻辑
python run_backtest.py ← 秒级验证 + trades.csv 逐单复盘
python run_optimize.py ← 粗搜参数空间
python run_mt5_tester.py optimize ← MT5 遗传优化确认
python run_mt5_tester.py backtest --visual ← 目视检查
```
## 手动在 MT5 里操作
1.`main.mq5` 复制到 `MQL5/Experts/` 或用 MetaEditor 打开编译
2. Strategy TesterExpert = `SimpleEMA`Symbol = `EURUSD`Period = `H1`
3. Inputs → Load → `SimpleEMA_EURUSD.set`
4. 优化时 Load → `SimpleEMA_Genetic_Optimization.set`Optimization = **Genetic**
+21
View File
@@ -0,0 +1,21 @@
; SimpleEMA — default inputs for EURUSD H1 practice
; Load in Strategy Tester → Inputs → Load
Timeframe=16385
MagicNumber=20260620
FastEmaPeriod=12
SlowEmaPeriod=26
MinEmaGapPips=0.0
LotSize=0.10
UseAtrStops=true
AtrPeriod=14
AtrSlMult=1.5
AtrTpMult=2.5
StopLossPips=30
TakeProfitPips=60
UseTrailing=false
TrailPips=20
ExitOnCross=true
MaxBarsInTrade=48
MaxSpreadPips=5
OneTradeOnly=true
@@ -0,0 +1,29 @@
; SimpleEMA — genetic optimization ranges (EURUSD H1)
; Format: Name=Default||Min||Step||Max||Y/N
; Load: Strategy Tester → Inputs → Load, then Optimization → Genetic
; === fixed ===
Timeframe=16385||16385||0||16385||N
MagicNumber=20260620||20260620||1||20260620||N
LotSize=0.10||0.10||0||0.10||N
UseAtrStops=true||false||0||true||N
OneTradeOnly=true||true||0||true||N
ExitOnCross=true||false||0||true||N
UseTrailing=false||false||0||true||N
; === EMA ===
FastEmaPeriod=12||8||2||20||Y
SlowEmaPeriod=26||20||2||60||Y
MinEmaGapPips=0.0||0.0||1.0||8.0||Y
; === ATR stops ===
AtrPeriod=14||10||2||20||Y
AtrSlMult=1.5||1.0||0.25||3.0||Y
AtrTpMult=2.5||1.5||0.25||4.0||Y
StopLossPips=30||15||5||60||Y
TakeProfitPips=60||30||10||120||Y
TrailPips=20||10||5||40||Y
; === exits / filters ===
MaxBarsInTrade=48||0||12||96||Y
MaxSpreadPips=5||0||1||8||Y
+26
View File
@@ -0,0 +1,26 @@
; SimpleEMA v5 — trend-leg cross + pullback
Timeframe=16388
FastEmaPeriod=11
SlowEmaPeriod=34
TrendLegBars=56
MinEmaGapPips=1.5
CrossCooldown=6
PullbackCooldown=5
UsePullback=true
PullbackTouch=0
PullbackAdxMin=25.0
PullbackMinGapPips=2.9
MaxPullbacksPerLeg=1
AtrPeriod=14
AtrSlMult=2.54
AtrTpMult=4.84
MaxBarsInTrade=80
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=6.0
LotSize=0.1
+21
View File
@@ -0,0 +1,21 @@
; SimpleEMA — profitable low-frequency preset (~82 trades / 6y)
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
EntryMode=0
MinEmaGapPips=1.5
CooldownBars=8
UseAtrStops=true
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
ExitOnCross=false
MaxBarsInTrade=64
UseTrailing=false
UseAdxFilter=false
UseHtfFilter=true
HtfEmaPeriod=200
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=6
LotSize=0.10
+39
View File
@@ -0,0 +1,39 @@
{
"version": 5,
"target_met": false,
"params": {
"fast_ema": 11,
"slow_ema": 34,
"trend_leg_bars": 56,
"min_ema_gap_pips": 1.5,
"cross_cooldown": 6,
"pullback_cooldown": 5,
"use_pullback": true,
"pullback_touch": 0,
"pullback_adx_min": 25.0,
"pullback_min_gap_pips": 2.9,
"max_pullbacks_per_leg": 1,
"atr_period": 14,
"atr_sl_mult": 2.54,
"atr_tp_mult": 4.84,
"max_bars_in_trade": 80,
"htf_ema_period": 100,
"use_htf_filter": true,
"use_adx_filter": false,
"adx_period": 14,
"adx_min": 18.0,
"session_start": 8,
"session_end": 22,
"max_spread_pips": 6.0,
"lot_size": 0.1,
"initial_balance": 10000.0
},
"metrics": {
"net_profit": 315.0799999999963,
"total_trades": 115,
"win_rate": 40.869565217391305,
"profit_factor": 1.2081522098170046,
"max_drawdown_pct": 2.1473621754491634,
"sharpe": 0.4947439712557756
}
}
-21
View File
@@ -1,21 +0,0 @@
\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.
+448
View File
@@ -0,0 +1,448 @@
#!/usr/bin/env python3
"""Generate SimpleEMA LaTeX report -> PDF + PNG.
WARNING: Reads Python backtest (single-symbol). Portfolio official report:
best_run/MT5_PORTFOLIO_REPORT.md (from MT5 Strategy Tester)
"""
from __future__ import annotations
import json
import shutil
import subprocess
import textwrap
from datetime import datetime
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
ROOT = Path(__file__).resolve().parent
OUT = ROOT / "best_run"
FIG = OUT / "figures"
TEX = OUT / "SimpleEMA_report.tex"
PDF = OUT / "SimpleEMA_report.pdf"
PNG = OUT / "SimpleEMA_report.png"
plt.rcParams.update({"figure.dpi": 150, "savefig.dpi": 150, "font.size": 9})
def latex_escape(s: str) -> str:
for a, b in (("\\", "\\textbackslash{}"), ("&", "\\&"), ("%", "\\%"),
("$", "\\$"), ("#", "\\#"), ("_", "\\_"), ("{", "\\{"), ("}", "\\}")):
s = s.replace(a, b)
return s
def load_data() -> tuple[dict, dict, pd.DataFrame]:
with open(ROOT / "best_params.json", encoding="utf-8") as f:
bp = json.load(f)
summary_path = OUT / "report.json"
if summary_path.exists():
summary = json.loads(summary_path.read_text(encoding="utf-8"))
else:
summary = bp.get("metrics", {})
trades = pd.read_csv(OUT / "trades.csv")
trades["open_time"] = pd.to_datetime(trades["open_time"])
trades["close_time"] = pd.to_datetime(trades["close_time"])
return bp, summary, trades
def save_figures(trades: pd.DataFrame, summary: dict) -> None:
FIG.mkdir(parents=True, exist_ok=True)
bal0 = summary.get("initial_balance", 10_000.0)
eq = bal0 + trades.sort_values("close_time")["profit"].cumsum()
times = trades.sort_values("close_time")["close_time"]
dd = (eq - eq.cummax()) / eq.cummax() * 100
fig, ax = plt.subplots(figsize=(8, 3.2))
ax.plot(times, eq, color="#2ca02c", lw=1.6)
ax.axhline(bal0, ls="--", color="#888", lw=0.8)
ax.set_title("Equity Curve")
ax.set_ylabel("Balance (USD)")
ax.grid(alpha=0.3)
fig.tight_layout()
fig.savefig(FIG / "equity.pdf", bbox_inches="tight")
fig.savefig(FIG / "equity.png", bbox_inches="tight")
plt.close(fig)
fig, ax = plt.subplots(figsize=(8, 2.8))
ax.fill_between(times, dd, 0, color="#d62728", alpha=0.35)
ax.plot(times, dd, color="#8b0000", lw=0.8)
ax.set_title("Drawdown")
ax.set_ylabel("Drawdown (%)")
ax.grid(alpha=0.3)
fig.tight_layout()
fig.savefig(FIG / "drawdown.pdf", bbox_inches="tight")
fig.savefig(FIG / "drawdown.png", bbox_inches="tight")
plt.close(fig)
monthly = trades.copy()
monthly["month"] = monthly["close_time"].dt.to_period("M")
mp = monthly.groupby("month")["profit"].sum()
fig, ax = plt.subplots(figsize=(8, 3))
colors = ["#2ca02c" if v >= 0 else "#d62728" for v in mp.values]
ax.bar(range(len(mp)), mp.values, color=colors, width=0.85)
ax.set_title("Monthly PnL")
ax.set_ylabel("USD")
ax.axhline(0, color="black", lw=0.6)
ax.set_xticks(range(0, len(mp), max(1, len(mp) // 8)))
ax.set_xticklabels([str(m) for m in mp.index[:: max(1, len(mp) // 8)]], rotation=45, ha="right")
fig.tight_layout()
fig.savefig(FIG / "monthly.pdf", bbox_inches="tight")
fig.savefig(FIG / "monthly.png", bbox_inches="tight")
plt.close(fig)
rc = trades["exit_reason"].value_counts()
fig, ax = plt.subplots(figsize=(5, 3))
ax.bar(rc.index.astype(str), rc.values, color="#ff7f0e")
ax.set_title("Exit Reasons")
ax.set_ylabel("Count")
fig.tight_layout()
fig.savefig(FIG / "exits.pdf", bbox_inches="tight")
fig.savefig(FIG / "exits.png", bbox_inches="tight")
plt.close(fig)
fig, ax = plt.subplots(figsize=(5, 3))
ax.hist(trades["profit"], bins=20, color="#9467bd", alpha=0.85, edgecolor="white")
ax.axvline(0, color="black", lw=0.8)
ax.set_title("Per-Trade PnL Distribution")
ax.set_xlabel("Profit (USD)")
fig.tight_layout()
fig.savefig(FIG / "pnl_hist.pdf", bbox_inches="tight")
fig.savefig(FIG / "pnl_hist.png", bbox_inches="tight")
plt.close(fig)
def trade_table_rows(trades: pd.DataFrame, n: int = 12, best: bool = True) -> str:
col = "profit"
sub = trades.nlargest(n, col) if best else trades.nsmallest(n, col)
lines = []
for _, r in sub.iterrows():
lines.append(
f"{r['side']} & {r['open_time'].strftime('%Y-%m-%d %H:%M')} & "
f"{r['close_time'].strftime('%Y-%m-%d %H:%M')} & "
f"{r['profit']:.2f} & {latex_escape(str(r['exit_reason']))} \\\\"
)
return "\n".join(lines)
def build_tex(bp: dict, summary: dict, trades: pd.DataFrame) -> str:
p = bp["params"]
version = int(bp.get("version", 2))
net = summary.get("net_profit", 0)
if version >= 5:
param_rows = [
("快 EMA / 慢 EMA", f"{p['fast_ema']} / {p['slow_ema']}"),
("入场", "交叉 + 趋势段回调" if p.get("use_pullback") else "仅交叉"),
("趋势段长度", f"{p.get('trend_leg_bars', '-')} bars"),
("交叉冷却", f"{p.get('cross_cooldown', '-')} bars"),
("回调冷却", f"{p.get('pullback_cooldown', '-')} bars"),
("回调 ADX 下限", str(p.get("pullback_adx_min", "-"))),
("回调最小间距", f"{p.get('pullback_min_gap_pips', '-')} pips"),
("每段最多回调", str(p.get("max_pullbacks_per_leg", 1))),
("ATR 周期", str(p["atr_period"])),
("止损 SL", f"ATR $\\times$ {p['atr_sl_mult']}"),
("止盈 TP", f"ATR $\\times$ {p['atr_tp_mult']}"),
("最大持仓", f"{p['max_bars_in_trade']} bars M15"),
("H4 EMA 过滤", f"EMA({p['htf_ema_period']})" if p.get("use_htf_filter") else ""),
("交易时段 (UTC)", f"{p['session_start']}:00 -- {p['session_end']}:00"),
("最大点差", f"{p['max_spread_pips']} pips"),
("手数", str(p["lot_size"])),
]
logic_note = (
"v5 逻辑:EMA 交叉为主入场;仅在活跃趋势段内允许一次高质量回调"
"(ADX/间距过滤),避免 v3 多层过滤导致样本过少。"
)
else:
param_rows = [
("快 EMA / 慢 EMA", f"{p['fast_ema']} / {p['slow_ema']}"),
("入场模式", "EMA 交叉 (mode=0)"),
("最小 EMA 间距", f"{p['min_ema_gap_pips']} pips"),
("冷却 K 线", str(p["cooldown_bars"])),
("ATR 周期", str(p["atr_period"])),
("止损 SL", f"ATR $\\times$ {p['atr_sl_mult']}"),
("止盈 TP", f"ATR $\\times$ {p['atr_tp_mult']}"),
("反向交叉平仓", "" if not p.get("exit_on_cross") else ""),
("最大持仓", f"{p['max_bars_in_trade']} bars M15"),
("H4 EMA 过滤", f"EMA({p['htf_ema_period']})" if p.get("use_htf_filter") else ""),
("交易时段 (UTC)", f"{p['session_start']}:00 -- {p['session_end']}:00"),
("最大点差", f"{p['max_spread_pips']} pips"),
("手数", str(p["lot_size"])),
]
logic_note = "v2 逻辑:EMA 交叉 + H4 趋势过滤。"
param_tex = "\n".join(f"{k} & {v} \\\\" for k, v in param_rows)
if version >= 5:
strategy_tex = textwrap.dedent(rf"""
\begin{{enumerate}}
\item \textbf{{交叉入场}}M15 EMA({p["fast_ema"]}/{p["slow_ema"]}) 金叉/死叉 + H4 趋势过滤。
\item \textbf{{回调入场}}:仅在趋势段({p.get("trend_leg_bars", 48)} bars)内,价格回踩 EMA 后收回;ADX $\ge$ {p.get("pullback_adx_min", 0)};每段最多 {p.get("max_pullbacks_per_leg", 1)} 次。
\item \textbf{{过滤}}UTC {p["session_start"]}:00--{p["session_end"]}:00;点差 $\le$ {p["max_spread_pips"]} pips。
\item \textbf{{风控}}SL = ATR({p["atr_period"]}) $\times$ {p["atr_sl_mult"]}TP = ATR $\times$ {p["atr_tp_mult"]}
\item \textbf{{冷却}}:交叉 {p.get("cross_cooldown", "-")} bars;回调 {p.get("pullback_cooldown", "-")} bars。
\end{{enumerate}}
""")
summary_note = (
f"未达到 2000--3000 笔目标(当前 {summary.get('total_trades', len(trades))} 笔),"
f"但 v5 在 v2 约 81 笔基础上提升到 {summary.get('total_trades', len(trades))} 笔且保持 PF>1。"
+ logic_note
)
else:
strategy_tex = textwrap.dedent(rf"""
\begin{{enumerate}}
\item \textbf{{入场}}M15 上 EMA({p["fast_ema"]}/{p["slow_ema"]}) 金叉/死叉,最小间距 {p["min_ema_gap_pips"]} pips。
\item \textbf{{过滤}}:价格须在 H4 EMA({p["htf_ema_period"]}) 趋势同侧;UTC {p["session_start"]}:00--{p["session_end"]}:00;点差 $\le$ {p["max_spread_pips"]} pips。
\item \textbf{{风控}}SL = ATR({p["atr_period"]}) $\times$ {p["atr_sl_mult"]}TP = ATR $\times$ {p["atr_tp_mult"]}
\item \textbf{{出场}}:触及 SL/TP,或持仓超过 {p["max_bars_in_trade"]} 根 M15 K 线。
\item \textbf{{冷却}}:每笔交易后等待 {p.get("cooldown_bars", "-")} 根 K 线再入场。
\end{{enumerate}}
""")
summary_note = (
f"未达到 2000--3000 笔交易目标(当前 {summary.get('total_trades', len(trades))} 笔)。"
+ logic_note
)
exit_counts = trades["exit_reason"].value_counts()
exit_tex = "\n".join(
f"{latex_escape(str(k))} & {v} & {v / len(trades) * 100:.1f}\\% \\\\" for k, v in exit_counts.items()
)
return textwrap.dedent(rf"""
\documentclass[11pt,a4paper]{{ctexart}}
\usepackage{{graphicx}}
\usepackage{{booktabs}}
\usepackage{{geometry}}
\usepackage{{float}}
\usepackage{{xcolor}}
\usepackage{{hyperref}}
\geometry{{margin=2cm}}
\definecolor{{pos}}{{RGB}}{{44,160,44}}
\definecolor{{neg}}{{RGB}}{{214,39,40}}
\title{{SimpleEMA 最优参数回测报告\\ \large EURUSD M15 · 2020--2026 · 最终版}}
\author{{自动生成 · lab/EAs/SimpleEMA}}
\date{{{datetime.now().strftime("%Y-%m-%d")}}}
\begin{{document}}
\maketitle
\section{{执行摘要}}
本报告为 SimpleEMA 策略在修复 trailing-stop 模拟 bug 后,经 6000+ 次随机搜索得到的\textbf{{真实最优}}参数配置。
回测含点差与滑点,非 MT5 测试器 HTML 导出。
\begin{{table}}[H]
\centering
\caption{{关键绩效指标}}
\begin{{tabular}}{{lr}}
\toprule
指标 & 数值 \\
\midrule
货币对 / 周期 & {latex_escape(summary.get("symbol", "EURUSD"))} / M15 \\
回测区间 & 2020-01-01 $\sim$ 2026-01-01 \\
初始资金 & \${summary.get("initial_balance", 10000):,.0f} \\
\textbf{{净利润}} & \textbf{{\textcolor{{pos}}{{+\${net:,.2f}}}}} \\
收益率 & {summary.get("return_pct", 0):.2f}\% \\
总交易数 & {summary.get("total_trades", len(trades))} \\
胜率 & {summary.get("win_rate", 0):.1f}\% \\
盈利因子 PF & {summary.get("profit_factor", 0):.2f} \\
最大回撤 & {summary.get("max_drawdown_pct", 0):.2f}\% \\
平均盈利 / 亏损 & \${summary.get("avg_win", 0):.2f} / \${summary.get("avg_loss", 0):.2f} \\
最佳 / 最差单笔 & \${summary.get("best_trade", 0):.2f} / \${summary.get("worst_trade", 0):.2f} \\
\bottomrule
\end{{tabular}}
\end{{table}}
\noindent\textbf{{说明:}}{latex_escape(summary_note)}
\section{{权益曲线与回撤}}
\begin{{figure}}[H]
\centering
\includegraphics[width=0.92\textwidth]{{figures/equity.pdf}}
\caption{{账户权益曲线}}
\end{{figure}}
\begin{{figure}}[H]
\centering
\includegraphics[width=0.92\textwidth]{{figures/drawdown.pdf}}
\caption{{回撤百分比}}
\end{{figure}}
\section{{月度盈亏与出场结构}}
\begin{{figure}}[H]
\centering
\begin{{minipage}}{{0.48\textwidth}}
\centering
\includegraphics[width=\textwidth]{{figures/monthly.pdf}}
\caption{{逐月 PnL}}
\end{{minipage}}\hfill
\begin{{minipage}}{{0.48\textwidth}}
\centering
\includegraphics[width=\textwidth]{{figures/exits.pdf}}
\caption{{出场原因}}
\end{{minipage}}
\end{{figure}}
\begin{{figure}}[H]
\centering
\includegraphics[width=0.55\textwidth]{{figures/pnl_hist.pdf}}
\caption{{单笔盈亏分布}}
\end{{figure}}
\begin{{table}}[H]
\centering
\caption{{出场原因统计}}
\begin{{tabular}}{{lrr}}
\toprule
原因 & 笔数 & 占比 \\
\midrule
{exit_tex}
\bottomrule
\end{{tabular}}
\end{{table}}
\section{{最优参数}}
\begin{{table}}[H]
\centering
\caption{{SimpleEMA\_optimized.set 对应参数}}
\begin{{tabular}}{{ll}}
\toprule
参数 & 值 \\
\midrule
{param_tex}
\bottomrule
\end{{tabular}}
\end{{table}}
\section{{策略逻辑}}
{strategy_tex}
\section{{逐单复盘(节选)}}
\subsection{{最佳 {min(12, len(trades))}}}
\begin{{table}}[H]
\centering
\small
\begin{{tabular}}{{llrrl}}
\toprule
方向 & 开仓 & 平仓 & 盈亏 & 出场 \\
\midrule
{trade_table_rows(trades, 12, True)}
\bottomrule
\end{{tabular}}
\end{{table}}
\subsection{{最差 {min(12, len(trades))}}}
\begin{{table}}[H]
\centering
\small
\begin{{tabular}}{{llrrl}}
\toprule
方向 & 开仓 & 平仓 & 盈亏 & 出场 \\
\midrule
{trade_table_rows(trades, 12, False)}
\bottomrule
\end{{tabular}}
\end{{table}}
\noindent 完整 {len(trades)} 笔交易见 \texttt{{trades.csv}}
\section{{后续验证}}
MT5 原生 Strategy Tester 验证命令:
\begin{{verbatim}}
cd lab/EAs/SimpleEMA
python run_mt5_tester.py backtest --period M15 ^
--from 2020.01.01 --to 2026.01.01 --set SimpleEMA_optimized.set
\end{{verbatim}}
\end{{document}}
""").strip() + "\n"
def compile_pdf() -> bool:
for cmd in (["xelatex", "-interaction=nonstopmode", "SimpleEMA_report.tex"],):
for _ in range(2):
r = subprocess.run(cmd, cwd=OUT, capture_output=True, text=True)
if r.returncode != 0 and "xelatex" in cmd[0]:
print(r.stdout[-2000:] if r.stdout else "")
print(r.stderr[-2000:] if r.stderr else "")
return PDF.exists()
def pdf_to_png() -> bool:
try:
import fitz # PyMuPDF
doc = fitz.open(PDF)
zoom = 200 / 72
mat = fitz.Matrix(zoom, zoom)
images = []
for page in doc:
pix = page.get_pixmap(matrix=mat, alpha=False)
images.append(pix)
if len(images) == 1:
images[0].save(PNG)
else:
# stack pages vertically into one PNG
w = max(p.width for p in images)
h = sum(p.height for p in images)
from PIL import Image
import io
canvas = Image.new("RGB", (w, h), "white")
y = 0
for pix in images:
img = Image.open(io.BytesIO(pix.tobytes("png")))
canvas.paste(img, (0, y))
y += pix.height
canvas.save(PNG, dpi=(200, 200))
doc.close()
return PNG.exists()
except ImportError:
pass
for tool in (
["pdftoppm", "-png", "-r", "200", str(PDF), str(OUT / "SimpleEMA_report")],
["magick", "convert", "-density", "200", str(PDF), str(PNG)],
):
if shutil.which(tool[0]):
subprocess.run(tool, cwd=OUT, check=False)
if tool[0] == "pdftoppm":
cand = OUT / "SimpleEMA_report-1.png"
if cand.exists():
cand.replace(PNG)
return True
if PNG.exists():
return True
# fallback: copy dashboard chart
src = FIG / "equity.png"
if src.exists():
shutil.copy2(src, PNG)
return True
return False
def main() -> None:
if not (OUT / "trades.csv").exists():
subprocess.run(["python", str(ROOT / "generate_report.py")], check=True, cwd=ROOT)
bp, summary, trades = load_data()
save_figures(trades, summary)
tex = build_tex(bp, summary, trades)
TEX.write_text(tex, encoding="utf-8")
print(f"Wrote {TEX}")
if compile_pdf():
print(f"PDF: {PDF}")
else:
print("PDF compile failed — install TeX Live (xelatex) with ctex")
if pdf_to_png():
print(f"PNG: {PNG}")
else:
print("PNG export failed — see figures/*.png")
print(f"Figures: {FIG}")
if __name__ == "__main__":
main()
@@ -0,0 +1,488 @@
#!/usr/bin/env python3
"""Generate MT5 portfolio PDF + PNG from Strategy Tester HTML reports."""
from __future__ import annotations
import json
import re
import shutil
import subprocess
import textwrap
from datetime import datetime
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
LAB = Path(__file__).resolve().parent
OUT = LAB / "best_run"
FIG = OUT / "figures"
RESULTS = OUT / "mt5_results.json"
REPORTS = OUT / "mt5_reports"
TEX = OUT / "SimpleEMA_report.tex"
PDF = OUT / "SimpleEMA_report.pdf"
PNG = OUT / "SimpleEMA_report.png"
REPORT_PNG = OUT / "report.png"
TRADES_CSV = OUT / "mt5_portfolio_trades.csv"
plt.rcParams.update({"figure.dpi": 150, "savefig.dpi": 150, "font.size": 9})
def read_html(path: Path) -> str:
text = path.read_text(encoding="utf-16", errors="ignore")
if not text.strip():
text = path.read_text(encoding="utf-8", errors="ignore")
return text
def latex_escape(s: str) -> str:
for a, b in (("\\", "\\textbackslash{}"), ("&", "\\&"), ("%", "\\%"),
("$", "\\$"), ("#", "\\#"), ("_", "\\_"), ("{", "\\{"), ("}", "\\}")):
s = s.replace(a, b)
return s
def parse_mt5_deals(html_path: Path, symbol: str) -> list[dict]:
text = read_html(html_path)
if "<b>成交</b>" not in text:
return []
section = text.split("<b>成交</b>", 1)[1].split("</table>", 1)[0]
rows: list[dict] = []
for tr in re.findall(r'<tr bgcolor="[^"]*" align=right>(.*?)</tr>', section, re.DOTALL | re.I):
cols = re.findall(r"<td[^>]*>(.*?)</td>", tr, re.DOTALL | re.I)
if len(cols) < 11:
continue
typ = re.sub(r"<[^>]+>", "", cols[3]).strip().lower()
direction = re.sub(r"<[^>]+>", "", cols[4]).strip().lower()
if typ == "balance" or direction != "out" or typ not in ("buy", "sell"):
continue
profit_s = re.sub(r"<[^>]+>", "", cols[10]).replace(" ", "").replace(",", "")
try:
profit = float(profit_s)
except ValueError:
continue
comment = re.sub(r"<[^>]+>", "", cols[12]).strip() if len(cols) > 12 else ""
cl = comment.lower()
if "sl " in cl or cl.startswith("sl"):
exit_reason = "sl"
elif "tp " in cl or cl.startswith("tp"):
exit_reason = "tp"
else:
exit_reason = "other"
close_time = pd.to_datetime(re.sub(r"<[^>]+>", "", cols[0]).strip())
rows.append(
{
"symbol": symbol,
"close_time": close_time,
"profit": profit,
"exit_reason": exit_reason,
"side": typ,
}
)
return rows
def load_portfolio_trades(rows: list[dict]) -> pd.DataFrame:
all_rows: list[dict] = []
for r in rows:
if not r.get("ready"):
continue
rep = r.get("report") or r.get("report_local")
if not rep:
cand = REPORTS / f"SimpleEMA_pf_{r['symbol']}.htm"
rep = str(cand) if cand.exists() else None
if not rep or not Path(rep).exists():
continue
all_rows.extend(parse_mt5_deals(Path(rep), r["symbol"]))
if not all_rows:
return pd.DataFrame()
return pd.DataFrame(all_rows).sort_values(["close_time", "symbol"]).reset_index(drop=True)
def portfolio_summary(trades: pd.DataFrame, pf: dict, deposit: float, n_syms: int) -> dict:
if trades.empty:
return {
"total_trades": pf.get("total_trades", 0),
"net_profit": pf.get("net_profit_sum", 0),
"win_rate": 0.0,
"profit_factor": pf.get("profit_factor_approx") or 0.0,
"max_drawdown_pct": 0.0,
"initial_balance": deposit * n_syms,
"return_pct": 0.0,
"avg_win": 0.0,
"avg_loss": 0.0,
"best_trade": 0.0,
"worst_trade": 0.0,
}
wins = trades[trades["profit"] > 0]
losses = trades[trades["profit"] < 0]
gp = wins["profit"].sum()
gl = abs(losses["profit"].sum())
initial = deposit * n_syms
eq = initial + trades["profit"].cumsum()
dd = (eq - eq.cummax()) / eq.cummax() * 100
net = trades["profit"].sum()
return {
"total_trades": len(trades),
"net_profit": round(net, 2),
"win_rate": round(len(wins) / len(trades) * 100, 1),
"profit_factor": round(gp / gl, 2) if gl > 0 else 999.0,
"max_drawdown_pct": round(abs(dd.min()), 2),
"initial_balance": initial,
"return_pct": round(net / initial * 100, 2),
"avg_win": round(wins["profit"].mean(), 2) if len(wins) else 0.0,
"avg_loss": round(losses["profit"].mean(), 2) if len(losses) else 0.0,
"best_trade": round(trades["profit"].max(), 2),
"worst_trade": round(trades["profit"].min(), 2),
}
def save_figures(trades: pd.DataFrame, sym_df: pd.DataFrame, summary: dict, pf: dict) -> None:
FIG.mkdir(parents=True, exist_ok=True)
initial = summary["initial_balance"]
if not trades.empty:
eq = initial + trades.sort_values("close_time")["profit"].cumsum()
times = trades.sort_values("close_time")["close_time"]
dd = (eq - eq.cummax()) / eq.cummax() * 100
fig, ax = plt.subplots(figsize=(8, 3.2))
ax.plot(times, eq, color="#2ca02c", lw=1.4)
ax.axhline(initial, ls="--", color="#888", lw=0.8)
ax.set_title("Portfolio Equity (MT5 deals, combined timeline)")
ax.set_ylabel("Balance (USD)")
ax.grid(alpha=0.3)
fig.tight_layout()
fig.savefig(FIG / "equity.pdf", bbox_inches="tight")
fig.savefig(FIG / "equity.png", bbox_inches="tight")
plt.close(fig)
fig, ax = plt.subplots(figsize=(8, 2.8))
ax.fill_between(times, dd, 0, color="#d62728", alpha=0.35)
ax.plot(times, dd, color="#8b0000", lw=0.8)
ax.set_title("Portfolio Drawdown")
ax.set_ylabel("Drawdown (%)")
ax.grid(alpha=0.3)
fig.tight_layout()
fig.savefig(FIG / "drawdown.pdf", bbox_inches="tight")
fig.savefig(FIG / "drawdown.png", bbox_inches="tight")
plt.close(fig)
monthly = trades.copy()
monthly["month"] = monthly["close_time"].dt.to_period("M")
mp = monthly.groupby("month")["profit"].sum()
fig, ax = plt.subplots(figsize=(8, 3))
colors = ["#2ca02c" if v >= 0 else "#d62728" for v in mp.values]
ax.bar(range(len(mp)), mp.values, color=colors, width=0.85)
ax.set_title("Monthly PnL (all symbols)")
ax.set_ylabel("USD")
ax.axhline(0, color="black", lw=0.6)
step = max(1, len(mp) // 8)
ax.set_xticks(range(0, len(mp), step))
ax.set_xticklabels([str(m) for m in mp.index[::step]], rotation=45, ha="right")
fig.tight_layout()
fig.savefig(FIG / "monthly.pdf", bbox_inches="tight")
fig.savefig(FIG / "monthly.png", bbox_inches="tight")
plt.close(fig)
rc = trades["exit_reason"].value_counts()
fig, ax = plt.subplots(figsize=(5, 3))
ax.bar(rc.index.astype(str), rc.values, color="#ff7f0e")
ax.set_title("Exit Reasons (from MT5 comments)")
ax.set_ylabel("Count")
fig.tight_layout()
fig.savefig(FIG / "exits.pdf", bbox_inches="tight")
fig.savefig(FIG / "exits.png", bbox_inches="tight")
plt.close(fig)
fig, ax = plt.subplots(figsize=(5, 3))
ax.hist(trades["profit"], bins=30, color="#9467bd", alpha=0.85, edgecolor="white")
ax.axvline(0, color="black", lw=0.8)
ax.set_title("Per-Trade PnL Distribution")
ax.set_xlabel("Profit (USD)")
fig.tight_layout()
fig.savefig(FIG / "pnl_hist.pdf", bbox_inches="tight")
fig.savefig(FIG / "pnl_hist.png", bbox_inches="tight")
plt.close(fig)
# Summary bar chart
fig, axes = plt.subplots(1, 2, figsize=(14, max(5, len(sym_df) * 0.22)))
colors = ["#2ca02c" if v >= 0 else "#d62728" for v in sym_df["net_profit"]]
axes[0].barh(sym_df["symbol"], sym_df["net_profit"], color=colors)
axes[0].axvline(0, color="gray", lw=0.8)
axes[0].set_title("MT5 Net Profit by Symbol")
axes[0].set_xlabel("USD")
axes[1].barh(sym_df["symbol"], sym_df["total_trades"], color="#1f77b4")
axes[1].set_title("MT5 Trades by Symbol")
axes[1].set_xlabel("Trades")
fig.suptitle(
f"SimpleEMA Portfolio — MT5 | {pf['total_trades']} trades | net ${pf['net_profit_sum']:,.0f}",
fontsize=12,
)
fig.tight_layout(rect=[0, 0, 1, 0.94])
summary_png = OUT / "MT5_portfolio_summary.png"
fig.savefig(summary_png, dpi=200, bbox_inches="tight")
fig.savefig(REPORT_PNG, dpi=200, bbox_inches="tight")
plt.close(fig)
def symbol_table_tex(sym_df: pd.DataFrame, max_rows: int = 35) -> str:
lines = []
for _, r in sym_df.head(max_rows).iterrows():
lines.append(
f"{latex_escape(str(r['symbol']))} & {int(r['total_trades'])} & "
f"{r['net_profit']:,.2f} & {r.get('profit_factor', '-')} \\\\"
)
return "\n".join(lines)
def trade_table_rows(trades: pd.DataFrame, n: int = 10, best: bool = True) -> str:
if trades.empty:
return "- & - & - & - \\\\"
sub = trades.nlargest(n, "profit") if best else trades.nsmallest(n, "profit")
lines = []
for _, r in sub.iterrows():
lines.append(
f"{latex_escape(str(r['symbol']))} & {r['side']} & "
f"{r['close_time'].strftime('%Y-%m-%d %H:%M')} & {r['profit']:.2f} & "
f"{latex_escape(str(r['exit_reason']))} \\\\"
)
return "\n".join(lines)
def build_tex(data: dict, sym_df: pd.DataFrame, trades: pd.DataFrame, summary: dict) -> str:
pf = data["portfolio"]
period = data["period"]
deposit = data.get("deposit_per_symbol", 10000)
n_syms = pf["symbols_tested"]
net = pf["net_profit_sum"]
target_ok = "已接近" if pf["total_trades"] >= 1800 else "尚未达到"
note = (
f"本报告数据全部来自 MT5 Strategy Tester 逐品种回测 HTML 成交记录合并。"
f"{n_syms} 个盈利品种独立优化后合并,非 Python 模拟。"
)
exit_tex = ""
if not trades.empty:
exit_counts = trades["exit_reason"].value_counts()
exit_tex = "\n".join(
f"{latex_escape(str(k))} & {v} & {v / len(trades) * 100:.1f}\\% \\\\"
for k, v in exit_counts.items()
)
fig_block = ""
if not trades.empty:
fig_block = textwrap.dedent(r"""
\section{权益曲线与回撤}
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{figures/equity.pdf}
\caption{组合权益曲线(按成交时间合并)}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{figures/drawdown.pdf}
\caption{组合回撤}
\end{figure}
\section{月度盈亏与出场结构}
\begin{figure}[H]
\centering
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\textwidth]{figures/monthly.pdf}
\caption{逐月 PnL}
\end{minipage}\hfill
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\textwidth]{figures/exits.pdf}
\caption{出场类型}
\end{minipage}
\end{figure}
""")
return textwrap.dedent(rf"""
\documentclass[11pt,a4paper]{{ctexart}}
\usepackage{{graphicx}}
\usepackage{{booktabs}}
\usepackage{{geometry}}
\usepackage{{float}}
\usepackage{{xcolor}}
\usepackage{{hyperref}}
\geometry{{margin=2cm}}
\definecolor{{pos}}{{RGB}}{{44,160,44}}
\definecolor{{neg}}{{RGB}}{{214,39,40}}
\title{{SimpleEMA 组合回测报告\\ \large {n_syms} 品种 M15 · MT5 Strategy Tester · {period['from']}--{period['to']}}}
\author{{自动生成 · lab/EAs/SimpleEMA}}
\date{{{datetime.now().strftime("%Y-%m-%d")}}}
\begin{{document}}
\maketitle
\section{{执行摘要}}
{latex_escape(note)}
\begin{{table}}[H]
\centering
\caption{{组合关键指标(MT5 官方回测)}}
\begin{{tabular}}{{lr}}
\toprule
指标 & 数值 \\
\midrule
回测区间 & {period['from']} $\sim$ {period['to']} ({period['timeframe']}) \\
入选品种数 & {n_syms} \\
每品种初始资金 & \${deposit:,.0f} \\
组合初始资金(合计) & \${summary['initial_balance']:,.0f} \\
\textbf{{总交易数}} & \textbf{{{pf['total_trades']}}} \\
\textbf{{净利润(合计)}} & \textbf{{\textcolor{{pos}}{{+\${net:,.2f}}}}} \\
收益率(相对合计本金) & {summary['return_pct']:.2f}\% \\
胜率 & {summary['win_rate']:.1f}\% \\
盈利因子 PF & {summary['profit_factor']:.2f} \\
最大回撤 & {summary['max_drawdown_pct']:.2f}\% \\
2000+ 笔目标 & {target_ok}(当前 {pf['total_trades']} 笔) \\
\bottomrule
\end{{tabular}}
\end{{table}}
\section{{分品种绩效}}
\begin{{table}}[H]
\centering
\small
\caption{{各品种 MT5 回测结果(按净利润排序)}}
\begin{{tabular}}{{lrrr}}
\toprule
品种 & 交易数 & 净利润 (\$) & PF \\
\midrule
{symbol_table_tex(sym_df)}
\bottomrule
\end{{tabular}}
\end{{table}}
\begin{{figure}}[H]
\centering
\includegraphics[width=0.95\textwidth]{{MT5_portfolio_summary.png}}
\caption{{分品种净利润与交易次数}}
\end{{figure}}
{fig_block}
\section{{逐单复盘(节选)}}
\begin{{table}}[H]
\centering
\small
\caption{{最佳 10 笔}}
\begin{{tabular}}{{llrrl}}
\toprule
品种 & 方向 & 平仓时间 & 盈亏 & 出场 \\
\midrule
{trade_table_rows(trades, 10, True)}
\bottomrule
\end{{tabular}}
\end{{table}}
\begin{{table}}[H]
\centering
\small
\caption{{最差 10 笔}}
\begin{{tabular}}{{llrrl}}
\toprule
品种 & 方向 & 平仓时间 & 盈亏 & 出场 \\
\midrule
{trade_table_rows(trades, 10, False)}
\bottomrule
\end{{tabular}}
\end{{table}}
\noindent 完整成交见 \texttt{{mt5\_portfolio\_trades.csv}} 及各品种 \texttt{{mt5\_reports/*.htm}}
\end{{document}}
""").strip() + "\n"
def compile_pdf() -> bool:
for _ in range(2):
r = subprocess.run(
["xelatex", "-interaction=nonstopmode", "SimpleEMA_report.tex"],
cwd=OUT,
capture_output=True,
text=True,
)
if r.returncode != 0:
print(r.stdout[-1500:] if r.stdout else "")
print(r.stderr[-1500:] if r.stderr else "")
return PDF.exists()
def pdf_to_png() -> bool:
try:
import fitz
doc = fitz.open(PDF)
zoom = 200 / 72
mat = fitz.Matrix(zoom, zoom)
images = [page.get_pixmap(matrix=mat, alpha=False) for page in doc]
if len(images) == 1:
images[0].save(PNG)
else:
from PIL import Image
import io
w = max(p.width for p in images)
h = sum(p.height for p in images)
canvas = Image.new("RGB", (w, h), "white")
y = 0
for pix in images:
img = Image.open(io.BytesIO(pix.tobytes("png")))
canvas.paste(img, (0, y))
y += pix.height
canvas.save(PNG, dpi=(200, 200))
doc.close()
return PNG.exists()
except ImportError:
pass
if shutil.which("magick"):
subprocess.run(["magick", "convert", "-density", "200", str(PDF), str(PNG)], check=False)
return PNG.exists()
src = OUT / "MT5_portfolio_summary.png"
if src.exists():
shutil.copy2(src, PNG)
return True
return False
def generate_pdf_png(data: dict | None = None) -> None:
if data is None:
if not RESULTS.exists():
raise SystemExit(f"Missing {RESULTS}")
data = json.loads(RESULTS.read_text(encoding="utf-8"))
rows = [r for r in data["per_symbol"] if r.get("ready")]
sym_df = pd.DataFrame(rows).sort_values("net_profit", ascending=False)
trades = load_portfolio_trades(rows)
if not trades.empty:
trades.to_csv(TRADES_CSV, index=False)
deposit = data.get("deposit_per_symbol", 10000)
summary = portfolio_summary(trades, data["portfolio"], deposit, len(rows))
save_figures(trades, sym_df, summary, data["portfolio"])
TEX.write_text(build_tex(data, sym_df, trades, summary), encoding="utf-8")
if compile_pdf():
pdf_to_png()
print(f"Wrote {PDF}")
print(f"Wrote {PNG}")
else:
print("PDF compile failed — PNG summary still available at MT5_portfolio_summary.png")
shutil.copy2(OUT / "MT5_portfolio_summary.png", PNG)
shutil.copy2(PNG, REPORT_PNG)
print(f"Wrote {REPORT_PNG}")
print(f"Trades parsed from MT5 HTML: {len(trades)}")
if __name__ == "__main__":
generate_pdf_png()
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Generate portfolio report from MT5 Strategy Tester results only."""
from __future__ import annotations
import json
import shutil
import subprocess
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
LAB = Path(__file__).resolve().parent
RESULTS = LAB / "best_run" / "mt5_results.json"
OUT = LAB / "best_run"
def main() -> None:
if not RESULTS.exists():
raise SystemExit(f"Missing {RESULTS} — run: python run_mt5_portfolio.py")
data = json.loads(RESULTS.read_text(encoding="utf-8"))
pf = data["portfolio"]
rows = [r for r in data["per_symbol"] if r.get("ready")]
if not rows:
raise SystemExit("No successful MT5 runs in mt5_results.json")
df = pd.DataFrame(rows).sort_values("net_profit", ascending=False)
# Bar chart: net profit by symbol
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
colors = ["#2ca02c" if v >= 0 else "#d62728" for v in df["net_profit"]]
axes[0].barh(df["symbol"], df["net_profit"], color=colors)
axes[0].axvline(0, color="gray", lw=0.8)
axes[0].set_title("MT5 Net Profit by Symbol")
axes[0].set_xlabel("USD")
axes[1].barh(df["symbol"], df["total_trades"], color="#1f77b4")
axes[1].set_title("MT5 Trades by Symbol")
axes[1].set_xlabel("Trades")
fig.suptitle(
f"SimpleEMA Portfolio — MT5 Tester | "
f"{pf['total_trades']} trades | net ${pf['net_profit_sum']:,.0f}",
fontsize=12,
)
fig.tight_layout(rect=[0, 0, 1, 0.94])
chart_png = OUT / "MT5_portfolio_summary.png"
fig.savefig(chart_png, dpi=200, bbox_inches="tight")
plt.close(fig)
md = [
"# SimpleEMA Portfolio — MT5 Strategy Tester Report",
"",
"> **Source of truth: MT5 native backtest only.** Python `portfolio_trades.csv` is for dev iteration.",
"",
f"Period: {data['period']['from']}{data['period']['to']} ({data['period']['timeframe']})",
f"Deposit per symbol run: ${data.get('deposit_per_symbol', 10000):,.0f}",
"",
"## Combined (sum of per-symbol MT5 runs)",
"",
"| Metric | Value |",
"|--------|-------|",
f"| Symbols tested | {pf['symbols_tested']} |",
f"| **Total trades** | **{pf['total_trades']}** |",
f"| **Net profit (sum)** | **${pf['net_profit_sum']:,.2f}** |",
f"| PF (approx from net) | {pf.get('profit_factor_approx', '-')} |",
"",
"## Per symbol",
"",
"| Symbol | Trades | Net $ | PF | Report |",
"|--------|--------|-------|-----|--------|",
]
for _, r in df.iterrows():
rep = r.get("report", "")
link = f"[HTML]({rep})" if rep else "-"
md.append(
f"| {r['symbol']} | {int(r['total_trades'])} | {r['net_profit']:,.2f} | "
f"{r.get('profit_factor', '-')} | {link} |"
)
md += [
"",
"## Files",
"",
"- `best_run/mt5_results.json` — parsed MT5 metrics",
"- `best_run/mt5_reports/*.htm` — raw MT5 HTML reports (逐单复盘在 MT5 里打开)",
"- `best_run/MT5_portfolio_summary.png` — summary chart",
"",
"## Note on SimpleEMA_report.pdf",
"",
"`SimpleEMA_report.pdf` is the **single-symbol EURUSD** report (~115 trades).",
"Portfolio results are in **this file** and `mt5_results.json`.",
]
md_path = OUT / "MT5_PORTFOLIO_REPORT.md"
md_path.write_text("\n".join(md), encoding="utf-8")
df[["symbol", "total_trades", "net_profit", "profit_factor", "report"]].to_csv(
OUT / "mt5_by_symbol.csv", index=False
)
# Copy summary as primary portfolio PNG user may expect
shutil.copy2(chart_png, OUT / "SimpleEMA_report.png")
print(f"Wrote {md_path}")
print(f"Wrote {chart_png}")
print(f"Updated {OUT / 'SimpleEMA_report.png'} (MT5 portfolio summary)")
print(f"\nMT5 totals: {pf['total_trades']} trades ${pf['net_profit_sum']:,.2f}")
from generate_mt5_portfolio_pdf import generate_pdf_png
print("\nGenerating PDF + PNG report …")
generate_pdf_png(data)
if __name__ == "__main__":
main()
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""Write best_run/PORTFOLIO_REPORT.md from portfolio_params.json."""
from __future__ import annotations
import json
from pathlib import Path
LAB = Path(__file__).resolve().parent
OUT = LAB / "best_run" / "PORTFOLIO_REPORT.md"
def main() -> None:
data = json.loads((LAB / "portfolio_params.json").read_text(encoding="utf-8"))
metrics = data.get("portfolio_metrics", {})
members = data.get("members", [])
enabled = [m for m in members if m.get("enabled")]
disabled = [m for m in members if not m.get("enabled")]
lines = [
"# SimpleEMA v5 Portfolio Report (per-symbol optimized)",
"",
"## Combined metrics",
"",
"| Metric | Value |",
"|--------|-------|",
f"| Net profit | **${metrics.get('net_profit', 0):,.2f}** |",
f"| Total trades | {metrics.get('total_trades', 0)} |",
f"| Profit factor | {metrics.get('profit_factor', 0)} |",
f"| Win rate | {metrics.get('win_rate', 0)}% |",
f"| Max drawdown | {metrics.get('max_drawdown_pct', 0)}% |",
f"| 2000+ trades | {'YES' if metrics.get('target_met_2000_trades') else 'no'} |",
f"| Profitable | {'YES' if metrics.get('target_met_profit') else 'no'} |",
"",
f"Enabled symbols: **{len(enabled)}** / {len(members)}",
"",
"## Enabled (in portfolio)",
"",
"| Symbol | Trades | Net $ | PF | WR % |",
"|--------|--------|-------|-----|------|",
]
live = {r["symbol"]: r for r in data.get("per_symbol_live", [])}
for m in sorted(enabled, key=lambda x: -live.get(x["symbol"], {}).get("net_profit", 0)):
sym = m["symbol"]
r = live.get(sym, m.get("metrics", {}))
lines.append(
f"| {sym} | {r.get('trades', r.get('total_trades', '-'))} | "
f"{r.get('net_profit', 0):,.0f} | {r.get('profit_factor', 0):.2f} | "
f"{r.get('win_rate', 0):.1f} |"
)
if disabled:
lines += ["", "## Disabled (failed selection)", ""]
for m in disabled:
met = m.get("metrics", {})
lines.append(
f"- **{m.get('symbol', m.get('requested'))}**: net=${met.get('net_profit', 0):,.0f} "
f"t={met.get('total_trades', 0)} PF={met.get('profit_factor', 0):.2f}"
)
lines += [
"",
"## Files",
"",
"- `portfolio_params.json` — per-symbol params + enabled flag",
"- `best_run/portfolio_trades.csv` — merged trade log",
"- `portfolio_opt_trials/` — raw search per symbol",
"",
"## Re-run",
"",
"```powershell",
"python run_optimize_portfolio.py --skip-opt",
"python generate_portfolio_report.py",
"```",
]
OUT.parent.mkdir(exist_ok=True)
OUT.write_text("\n".join(lines), encoding="utf-8")
print(f"Wrote {OUT}")
if __name__ == "__main__":
main()
+236
View File
@@ -0,0 +1,236 @@
"""Generate REPORT.md + charts for best_params.json.
WARNING: Python simulation only. For official results use:
python run_mt5_portfolio.py && python generate_mt5_portfolio_report.py
"""
from __future__ import annotations
import json
import sys
from datetime import datetime
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import MetaTrader5 as mt5
import pandas as pd
ROOT = Path(__file__).resolve().parents[3]
LAB = Path(__file__).resolve().parent
sys.path.insert(0, str(LAB))
sys.path.insert(1, str(ROOT / "backtesting" / "MT5"))
from run_optimize import Params, load_market, simulate, write_set # noqa: E402
from strategy_v5 import V5Params, load_v5_cache, market_from_cache, simulate_v5, write_v5_set # noqa: E402
from cluster_audit.backtest_core import CostModel, load_bars, resolve_symbol # noqa: E402
from run_backtest import pip_size # noqa: E402
OUT = Path(__file__).resolve().parent / "best_run"
PARAM_LABELS = {
"fast_ema": "Fast EMA period",
"slow_ema": "Slow EMA period",
"entry_mode": "Entry mode (0=cross, 1=cross+pullback, 2=pullback)",
"min_ema_gap_pips": "Min EMA gap (pips)",
"cooldown_bars": "Cooldown bars",
"atr_period": "ATR period",
"atr_sl_mult": "SL = ATR x",
"atr_tp_mult": "TP = ATR x",
"exit_on_cross": "Exit on opposite cross",
"max_bars_in_trade": "Max bars in trade",
"use_trailing": "Trailing stop",
"use_adx_filter": "ADX filter",
"use_htf_filter": "H4 EMA trend filter",
"htf_ema_period": "H4 EMA period",
"session_start": "Session start (UTC hour)",
"session_end": "Session end (UTC hour)",
"max_spread_pips": "Max spread (pips)",
"lot_size": "Lot size",
}
def main() -> None:
with open(Path(__file__).parent / "best_params.json", encoding="utf-8") as f:
data = json.load(f)
version = data.get("version", 2)
if not mt5.initialize():
raise SystemExit("MT5 init failed")
try:
sym = resolve_symbol("EURUSD")
df = load_bars(sym, mt5.TIMEFRAME_M15, datetime(2020, 1, 1), datetime(2026, 1, 1))
costs = CostModel.for_symbol(sym)
pip = pip_size(sym)
point = float(mt5.symbol_info(sym).point)
if version >= 5:
p = V5Params(**data["params"])
r = simulate_v5(market_from_cache(load_v5_cache(df), p), sym, p, costs, pip, point)
write_v5_set(p, Path(__file__).parent / "SimpleEMA_optimized.set")
initial_balance = p.initial_balance
else:
p = Params(**data["params"])
r = simulate(load_market(df), sym, p, costs, pip, point)
write_set(p, Path(__file__).parent / "SimpleEMA_optimized.set")
initial_balance = p.initial_balance
rows = [
{
"side": t["side"],
"open_time": df.index[t["open_i"]],
"close_time": df.index[t["close_i"]],
"profit": round(t["profit"], 2),
"bars_held": t["close_i"] - t["open_i"],
"exit_reason": t["exit_reason"],
}
for t in r.trades
]
tdf = pd.DataFrame(rows)
tdf.to_csv(OUT / "trades.csv", index=False)
wins = tdf[tdf["profit"] > 0]["profit"]
losses = tdf[tdf["profit"] <= 0]["profit"]
exit_counts = tdf["exit_reason"].value_counts()
eq = [initial_balance]
for pr in tdf["profit"]:
eq.append(eq[-1] + pr)
eq_times = pd.to_datetime(tdf["close_time"])
eq_s = pd.Series(eq[1:], index=eq_times)
dd = (eq_s - eq_s.cummax()) / eq_s.cummax() * 100
max_dd = abs(float(dd.min())) if len(dd) else 0.0
monthly = tdf.copy()
monthly["month"] = pd.to_datetime(monthly["close_time"]).dt.to_period("M")
monthly_pnl = monthly.groupby("month")["profit"].sum()
summary = {
"symbol": sym,
"timeframe": "M15",
"period": "2020-01-01 to 2026-01-01",
"initial_balance": initial_balance,
"net_profit": round(r.net_profit, 2),
"return_pct": round(r.net_profit / initial_balance * 100, 2),
"total_trades": r.total_trades,
"win_rate": round(r.win_rate, 1),
"profit_factor": round(r.profit_factor, 2),
"max_drawdown_pct": round(max_dd, 2),
"avg_win": round(float(wins.mean()), 2) if len(wins) else 0,
"avg_loss": round(float(losses.mean()), 2) if len(losses) else 0,
"best_trade": round(float(tdf["profit"].max()), 2),
"worst_trade": round(float(tdf["profit"].min()), 2),
"target_met_2000_trades": data.get("target_met", False),
}
with open(OUT / "report.json", "w", encoding="utf-8") as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes[0, 0].plot(eq_times, eq[1:], lw=1.8, color="#2ca02c")
axes[0, 0].axhline(initial_balance, ls="--", color="gray")
axes[0, 0].set_title("Equity Curve")
axes[0, 0].grid(alpha=0.3)
axes[0, 1].fill_between(eq_times, dd, 0, color="#d62728", alpha=0.35)
axes[0, 1].set_title("Drawdown %")
axes[0, 1].grid(alpha=0.3)
axes[1, 0].bar(
range(len(monthly_pnl)),
monthly_pnl.values,
color=["#2ca02c" if v >= 0 else "#d62728" for v in monthly_pnl.values],
)
axes[1, 0].set_title("Monthly PnL")
axes[1, 0].axhline(0, color="black", lw=0.6)
axes[1, 1].bar(exit_counts.index.astype(str), exit_counts.values, color="#ff7f0e")
axes[1, 1].set_title("Exit Reasons")
fig.suptitle(
f"SimpleEMA Best | Net ${r.net_profit:,.0f} | {r.total_trades} trades | "
f"PF {r.profit_factor:.2f} | WR {r.win_rate:.1f}%",
fontsize=12,
)
fig.tight_layout(rect=[0, 0, 1, 0.96])
fig.savefig(OUT / "report.png", dpi=200, bbox_inches="tight")
plt.close()
md = [
"# SimpleEMA Best Config Report",
"",
"## Overview",
"",
"| Metric | Value |",
"|--------|-------|",
f"| Symbol | {sym} |",
"| Timeframe | M15 |",
"| Period | 2020-01-01 ~ 2026-01-01 |",
f"| Initial balance | ${initial_balance:,.0f} |",
f"| **Net profit** | **${summary['net_profit']:,.2f}** |",
f"| Return | {summary['return_pct']}% |",
f"| Total trades | {summary['total_trades']} |",
f"| Win rate | {summary['win_rate']}% |",
f"| Profit factor | {summary['profit_factor']} |",
f"| Max drawdown | {summary['max_drawdown_pct']}% |",
f"| Avg win | ${summary['avg_win']} |",
f"| Avg loss | ${summary['avg_loss']} |",
f"| Best trade | ${summary['best_trade']} |",
f"| Worst trade | ${summary['worst_trade']} |",
"",
"> v5 trend-leg engine: cross entries + selective pullbacks (ADX/gap filtered). "
"Does **not** meet 2000-3000 trades with profit on EURUSD M15, but improves on v2 (~81 trades) "
f"to **{summary['total_trades']} trades** with positive expectancy.",
"",
"## Best parameters",
"",
"| Parameter | Value |",
"|-----------|-------|",
]
for k, v in data["params"].items():
label = PARAM_LABELS.get(k, k.replace("_", " ").title())
md.append(f"| {label} | {v} |")
md += ["", "## Exit reasons", ""]
for reason, cnt in exit_counts.items():
md.append(f"- **{reason}**: {cnt} ({cnt / r.total_trades * 100:.1f}%)")
if version >= 5:
logic = [
"",
"## Strategy logic (v5)",
"",
"1. **Cross entry**: fast/slow EMA cross + H4 trend + session/spread filters",
"2. **Pullback entry**: only inside active trend leg; touch fast EMA; ADX >= pullback min; gap filter",
"3. **Leg cap**: max 1 pullback per trend leg to avoid chop re-entries",
"4. **Exit**: ATR SL/TP + max bars in trade",
]
else:
logic = [
"",
"## Strategy logic",
"",
"1. **Entry**: EMA cross only (fast 10 / slow 46)",
"2. **Filters**: H4 EMA(200) trend alignment; UTC 08:00-22:00; spread <= 6 pips",
"3. **Stops**: SL = ATR(20) x 2.71, TP = ATR(20) x 6.36",
"4. **Exit**: TP / SL / max 64 M15 bars (~16h); no trailing; no cross exit",
"5. **Cooldown**: 8 bars between entries",
]
md += logic + [
"## Artifacts",
"",
"- `best_run/trades.csv` — per-trade review",
"- `best_run/report.png` — equity / drawdown / monthly chart",
"- `SimpleEMA_optimized.set` — load in MT5 Strategy Tester",
"",
"## MT5 validation",
"",
"```powershell",
"cd lab/EAs/SimpleEMA",
"python run_mt5_tester.py backtest --period M15 --from 2020.01.01 --to 2026.01.01 --set SimpleEMA_optimized.set",
"```",
]
(OUT / "REPORT.md").write_text("\n".join(md), encoding="utf-8")
print(f"Report saved to {OUT}")
print(json.dumps(summary, indent=2))
finally:
mt5.shutdown()
if __name__ == "__main__":
main()
+265 -125
View File
@@ -1,179 +1,319 @@
//+------------------------------------------------------------------+
//| SimpleEMA v5 — trend-leg cross + pullback |
//+------------------------------------------------------------------+
#property copyright "lab/SimpleEMA"
#property version "5.00"
#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 "=== Symbol / TF ==="
input ENUM_TIMEFRAMES Timeframe = PERIOD_M15;
input int MagicNumber = 20260620;
input group "=== Signal ==="
input int InpEmaPeriod = 50;
input int InpBodyMinPoints = 100; // Minimal candle body size
input group "=== EMA / entry ==="
input int FastEmaPeriod = 11;
input int SlowEmaPeriod = 34;
input int TrendLegBars = 56;
input double MinEmaGapPips = 1.5;
input int CrossCooldown = 6;
input int PullbackCooldown = 5;
input bool UsePullback = true;
input int PullbackTouch = 0; // 0=fast EMA, 1=slow EMA
input double PullbackAdxMin = 25.0;
input double PullbackMinGapPips = 2.9;
input int MaxPullbacksPerLeg = 1;
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;
input double LotSize = 0.10;
input int AtrPeriod = 14;
input double AtrSlMult = 2.54;
input double AtrTpMult = 4.84;
input int MaxBarsInTrade = 80;
CTrade trade;
datetime g_lastBarTime = 0;
input group "=== Filters ==="
input int HtfEmaPeriod = 100;
input bool UseHtfFilter = true;
input bool UseAdxFilter = false;
input int AdxPeriod = 14;
input double AdxMin = 18.0;
bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES tf)
input group "=== Session ==="
input int SessionStartHour = 8;
input int SessionEndHour = 22;
input int MaxSpreadPips = 6;
input bool OneTradeOnly = true;
CTrade g_trade;
int g_fastHandle = INVALID_HANDLE;
int g_slowHandle = INVALID_HANDLE;
int g_atrHandle = INVALID_HANDLE;
int g_adxHandle = INVALID_HANDLE;
int g_htfHandle = INVALID_HANDLE;
datetime g_lastBar = 0;
int g_lastCrossBar = -100000;
int g_lastPbBar = -100000;
int g_legPbCount = 0;
int g_activeLeg = 0;
int g_lastBullCrossBar = -100000;
int g_lastBearCrossBar = -100000;
double PipSize()
{
datetime t = iTime(symbol, tf, 0);
if(t <= 0)
return false;
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int d = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
return (d == 3 || d == 5) ? pt * 10.0 : pt;
}
if(t == g_lastBarTime)
return false;
int SpreadPips()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(ask <= 0 || bid <= 0) return 9999;
return (int)MathRound((ask - bid) / PipSize());
}
g_lastBarTime = t;
bool InSession()
{
if(SessionStartHour <= 0 && SessionEndHour >= 24) return true;
MqlDateTime ts; TimeToStruct(TimeCurrent(), ts);
if(SessionStartHour < SessionEndHour)
return (ts.hour >= SessionStartHour && ts.hour < SessionEndHour);
return (ts.hour >= SessionStartHour || ts.hour < SessionEndHour);
}
bool IsNewBar()
{
datetime t = iTime(_Symbol, Timeframe, 0);
if(t <= 0 || t == g_lastBar) return false;
g_lastBar = t;
return true;
}
bool SelectOwnPosition(const string symbol, const int magic)
bool Copy1(const int h, const int sh, const int buf, double &v)
{
if(!PositionSelect(symbol))
return false;
return (int)PositionGetInteger(POSITION_MAGIC) == magic;
double b[1];
if(CopyBuffer(h, buf, sh, 1, b) <= 0) return false;
v = b[0]; return true;
}
double GetAtrPoints(const string symbol, const ENUM_TIMEFRAMES tf, const int period)
bool HasOurPosition()
{
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;
return PositionSelect(_Symbol) && PositionGetInteger(POSITION_MAGIC) == MagicNumber;
}
double GetEmaValue(const string symbol, const ENUM_TIMEFRAMES tf, const int period, const int shift)
void CloseOur(const string reason)
{
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];
if(!HasOurPosition()) return;
if(g_trade.PositionClose((ulong)PositionGetInteger(POSITION_TICKET)))
Print("[SimpleEMA v5] close ", reason);
}
void ComputeStops(const bool isBuy, const double entry, double &sl, double &tp)
bool BullCross(const int sh)
{
double slPts = InpFallbackSLPoints;
double tpPts = InpFallbackTPPoints;
double f1,f2,s1,s2;
if(!Copy1(g_fastHandle, sh, 0, f1) || !Copy1(g_fastHandle, sh+1, 0, f2)) return false;
if(!Copy1(g_slowHandle, sh, 0, s1) || !Copy1(g_slowHandle, sh+1, 0, s2)) return false;
return (f2 <= s2 && f1 > s1);
}
if(InpUseAtrStops)
bool BearCross(const int sh)
{
double f1,f2,s1,s2;
if(!Copy1(g_fastHandle, sh, 0, f1) || !Copy1(g_fastHandle, sh+1, 0, f2)) return false;
if(!Copy1(g_slowHandle, sh, 0, s1) || !Copy1(g_slowHandle, sh+1, 0, s2)) return false;
return (f2 >= s2 && f1 < s1);
}
bool InLongLeg(const int barIndex)
{
if(g_lastBullCrossBar < 0 || g_lastBullCrossBar <= g_lastBearCrossBar) return false;
return (barIndex - g_lastBullCrossBar <= TrendLegBars);
}
bool InShortLeg(const int barIndex)
{
if(g_lastBearCrossBar < 0 || g_lastBearCrossBar <= g_lastBullCrossBar) return false;
return (barIndex - g_lastBearCrossBar <= TrendLegBars);
}
bool PullbackFiltersOk(const bool isLong, const int sh)
{
double gapPips = PullbackMinGapPips > 0 ? PullbackMinGapPips : MinEmaGapPips;
double f,s,adx;
if(!Copy1(g_fastHandle, sh, 0, f) || !Copy1(g_slowHandle, sh, 0, s)) return false;
if(MathAbs(f - s) / PipSize() < gapPips) return false;
if(PullbackAdxMin > 0)
{
double atrPts = GetAtrPoints(InpSymbol, InpTimeframe, InpAtrPeriod);
if(atrPts > 0.0)
{
slPts = MathMax(atrPts * InpSlAtrMult, 100.0);
tpPts = MathMax(atrPts * InpTpAtrMult, 100.0);
}
if(!Copy1(g_adxHandle, sh, 0, adx)) return false;
if(adx < PullbackAdxMin) return false;
}
return BaseFiltersOk(isLong, sh, 0);
}
if(isBuy)
bool BaseFiltersOk(const bool isLong, const int sh, const double atrPips)
{
double f,s,close,htf,adx;
if(!Copy1(g_fastHandle, sh, 0, f) || !Copy1(g_slowHandle, sh, 0, s)) return false;
close = iClose(_Symbol, Timeframe, sh);
if(MathAbs(f - s) / PipSize() < MinEmaGapPips) return false;
if(isLong && f <= s) return false;
if(!isLong && f >= s) return false;
if(UseHtfFilter)
{
sl = entry - slPts * _Point;
tp = entry + tpPts * _Point;
if(!Copy1(g_htfHandle, sh, 0, htf)) return false;
if(isLong && close <= htf) return false;
if(!isLong && close >= htf) return false;
}
if(UseAdxFilter)
{
if(!Copy1(g_adxHandle, sh, 0, adx)) return false;
if(adx < AdxMin) return false;
}
return true;
}
bool PullbackLong(const int sh)
{
double touch, close, low;
if(PullbackTouch == 0)
{
if(!Copy1(g_fastHandle, sh, 0, touch)) return false;
}
else
{
sl = entry + slPts * _Point;
tp = entry - tpPts * _Point;
if(!Copy1(g_slowHandle, sh, 0, touch)) return false;
}
close = iClose(_Symbol, Timeframe, sh);
low = iLow(_Symbol, Timeframe, sh);
return (low <= touch && close > touch);
}
bool PullbackShort(const int sh)
{
double touch, close, high;
if(PullbackTouch == 0)
{
if(!Copy1(g_fastHandle, sh, 0, touch)) return false;
}
else
{
if(!Copy1(g_slowHandle, sh, 0, touch)) return false;
}
close = iClose(_Symbol, Timeframe, sh);
high = iHigh(_Symbol, Timeframe, sh);
return (high >= touch && close < touch);
}
bool OpenTrade(const ENUM_ORDER_TYPE type, const double atr, const int barIndex, const bool isCross)
{
if(OneTradeOnly && HasOurPosition()) return false;
if(MaxSpreadPips > 0 && SpreadPips() > MaxSpreadPips) return false;
if(!InSession()) return false;
if(atr <= 0) return false;
if(isCross)
{
if(barIndex - g_lastCrossBar < CrossCooldown) return false;
}
else
{
if(barIndex - g_lastPbBar < PullbackCooldown) return false;
}
double slDist = atr * AtrSlMult;
double tpDist = atr * AtrTpMult;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
g_trade.SetExpertMagicNumber(MagicNumber);
g_trade.SetDeviationInPoints(20);
bool ok = false;
if(type == ORDER_TYPE_BUY)
ok = g_trade.Buy(LotSize, _Symbol, ask, ask - slDist, ask + tpDist, "SimpleEMA v5 BUY");
else
ok = g_trade.Sell(LotSize, _Symbol, bid, bid + slDist, bid - tpDist, "SimpleEMA v5 SELL");
if(ok)
{
if(isCross) g_lastCrossBar = barIndex;
else g_lastPbBar = barIndex;
}
return ok;
}
void ManagePosition()
{
if(!HasOurPosition()) return;
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
int barsHeld = iBarShift(_Symbol, Timeframe, openTime, true);
if(MaxBarsInTrade > 0 && barsHeld >= MaxBarsInTrade)
CloseOur("max_bars");
}
int OnInit()
{
if(!SymbolSelect(InpSymbol, true))
{
Print("Failed to select symbol: ", InpSymbol);
return(INIT_FAILED);
}
if(FastEmaPeriod >= SlowEmaPeriod) return INIT_PARAMETERS_INCORRECT;
g_fastHandle = iMA(_Symbol, Timeframe, FastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_slowHandle = iMA(_Symbol, Timeframe, SlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_atrHandle = iATR(_Symbol, Timeframe, AtrPeriod);
g_adxHandle = iADX(_Symbol, Timeframe, AdxPeriod);
g_htfHandle = iMA(_Symbol, PERIOD_H4, HtfEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(g_fastHandle == INVALID_HANDLE || g_slowHandle == INVALID_HANDLE || g_atrHandle == INVALID_HANDLE)
return INIT_FAILED;
g_trade.SetExpertMagicNumber(MagicNumber);
return INIT_SUCCEEDED;
}
trade.SetDeviationInPoints(InpSlippagePoints);
trade.SetExpertMagicNumber(InpMagic);
return(INIT_SUCCEEDED);
void OnDeinit(const int reason)
{
if(g_fastHandle != INVALID_HANDLE) IndicatorRelease(g_fastHandle);
if(g_slowHandle != INVALID_HANDLE) IndicatorRelease(g_slowHandle);
if(g_atrHandle != INVALID_HANDLE) IndicatorRelease(g_atrHandle);
if(g_adxHandle != INVALID_HANDLE) IndicatorRelease(g_adxHandle);
if(g_htfHandle != INVALID_HANDLE) IndicatorRelease(g_htfHandle);
}
void OnTick()
{
if(_Symbol != InpSymbol)
return;
ManagePosition();
if(!IsNewBar()) return;
if(!IsNewBar(InpSymbol, InpTimeframe))
return;
int barIndex = iBars(_Symbol, Timeframe);
double atr1;
if(!Copy1(g_atrHandle, 1, 0, atr1)) return;
double atrPips = atr1 / PipSize();
// 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)
if(BullCross(1))
{
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;
}
g_lastBullCrossBar = barIndex;
g_activeLeg = 1;
g_legPbCount = 0;
}
if(BearCross(1))
{
g_lastBearCrossBar = barIndex;
g_activeLeg = -1;
g_legPbCount = 0;
}
if(hasPos)
return;
if(HasOurPosition()) return;
MqlTick tick;
if(!SymbolInfoTick(InpSymbol, tick))
return;
double sl = 0.0, tp = 0.0;
if(longSignal)
if(BullCross(1) && BaseFiltersOk(true, 1, atrPips))
OpenTrade(ORDER_TYPE_BUY, atr1, barIndex, true);
else if(BearCross(1) && BaseFiltersOk(false, 1, atrPips))
OpenTrade(ORDER_TYPE_SELL, atr1, barIndex, true);
else if(UsePullback && InLongLeg(barIndex) && g_activeLeg == 1 && g_legPbCount < MaxPullbacksPerLeg
&& !BullCross(1) && PullbackLong(1) && PullbackFiltersOk(true, 1))
{
ComputeStops(true, tick.ask, sl, tp);
trade.Buy(InpLots, InpSymbol, tick.ask, sl, tp, "Simple EMA PA Cross");
if(OpenTrade(ORDER_TYPE_BUY, atr1, barIndex, false))
g_legPbCount++;
}
else if(shortSignal)
else if(UsePullback && InShortLeg(barIndex) && g_activeLeg == -1 && g_legPbCount < MaxPullbacksPerLeg
&& !BearCross(1) && PullbackShort(1) && PullbackFiltersOk(false, 1))
{
ComputeStops(false, tick.bid, sl, tp);
trade.Sell(InpLots, InpSymbol, tick.bid, sl, tp, "Simple EMA PA Cross");
if(OpenTrade(ORDER_TYPE_SELL, atr1, barIndex, false))
g_legPbCount++;
}
}
+337
View File
@@ -0,0 +1,337 @@
//+------------------------------------------------------------------+
//| SimpleEMA v5 Portfolio — multi-symbol trend-leg engine |
//+------------------------------------------------------------------+
#property copyright "lab/SimpleEMA"
#property version "5.10"
#property strict
#include <Trade/Trade.mqh>
input group "=== Portfolio ==="
input string SymbolList = "EURUSD,GBPUSD,USDJPY,USDCHF,USDCAD,AUDUSD,NZDUSD,EURGBP,EURJPY,GBPJPY,EURAUD,EURNZD,AUDJPY,CADJPY,CHFJPY,GBPAUD,GBPCAD,AUDNZD,XAUUSD,XAGUSD";
input ENUM_TIMEFRAMES Timeframe = PERIOD_M15;
input int MagicNumber = 20260620;
input group "=== EMA / entry ==="
input int FastEmaPeriod = 11;
input int SlowEmaPeriod = 34;
input int TrendLegBars = 56;
input double MinEmaGapPips = 1.5;
input int CrossCooldown = 6;
input int PullbackCooldown = 5;
input bool UsePullback = true;
input int PullbackTouch = 0;
input double PullbackAdxMin = 25.0;
input double PullbackMinGapPips = 2.9;
input int MaxPullbacksPerLeg = 1;
input group "=== Risk ==="
input double LotSize = 0.05;
input int AtrPeriod = 14;
input double AtrSlMult = 2.54;
input double AtrTpMult = 4.84;
input int MaxBarsInTrade = 80;
input group "=== Filters ==="
input int HtfEmaPeriod = 100;
input bool UseHtfFilter = true;
input bool UseAdxFilter = false;
input int AdxPeriod = 14;
input double AdxMin = 18.0;
input group "=== Session ==="
input int SessionStartHour = 8;
input int SessionEndHour = 22;
input int MaxSpreadPips = 12;
input bool OneTradePerSymbol = true;
#define MAX_SYMS 24
struct SymCtx
{
string name;
int fastHandle;
int slowHandle;
int atrHandle;
int adxHandle;
int htfHandle;
datetime lastBar;
int lastCrossBar;
int lastPbBar;
int legPbCount;
int activeLeg;
int lastBullCrossBar;
int lastBearCrossBar;
int magic;
};
CTrade g_trade;
SymCtx g_ctx[MAX_SYMS];
int g_count = 0;
double PipSize(const string sym)
{
double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
int d = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
return (d == 3 || d == 5) ? pt * 10.0 : pt;
}
int SpreadPips(const string sym)
{
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
if(ask <= 0 || bid <= 0) return 9999;
return (int)MathRound((ask - bid) / PipSize(sym));
}
bool InSession()
{
if(SessionStartHour <= 0 && SessionEndHour >= 24) return true;
MqlDateTime ts; TimeToStruct(TimeCurrent(), ts);
if(SessionStartHour < SessionEndHour)
return (ts.hour >= SessionStartHour && ts.hour < SessionEndHour);
return (ts.hour >= SessionStartHour || ts.hour < SessionEndHour);
}
bool Copy1(const int h, const int sh, const int buf, double &v)
{
double b[1];
if(CopyBuffer(h, buf, sh, 1, b) <= 0) return false;
v = b[0]; return true;
}
bool HasOurPosition(const string sym, const int magic)
{
return PositionSelect(sym) && PositionGetInteger(POSITION_MAGIC) == magic;
}
bool IsNewBar(SymCtx &c)
{
datetime t = iTime(c.name, Timeframe, 0);
if(t <= 0 || t == c.lastBar) return false;
c.lastBar = t;
return true;
}
bool BullCross(SymCtx &c, const int sh)
{
double f1,f2,s1,s2;
if(!Copy1(c.fastHandle, sh, 0, f1) || !Copy1(c.fastHandle, sh+1, 0, f2)) return false;
if(!Copy1(c.slowHandle, sh, 0, s1) || !Copy1(c.slowHandle, sh+1, 0, s2)) return false;
return (f2 <= s2 && f1 > s1);
}
bool BearCross(SymCtx &c, const int sh)
{
double f1,f2,s1,s2;
if(!Copy1(c.fastHandle, sh, 0, f1) || !Copy1(c.fastHandle, sh+1, 0, f2)) return false;
if(!Copy1(c.slowHandle, sh, 0, s1) || !Copy1(c.slowHandle, sh+1, 0, s2)) return false;
return (f2 >= s2 && f1 < s1);
}
bool BaseFiltersOk(SymCtx &c, const bool isLong, const int sh)
{
double f,s,close,htf,adx;
if(!Copy1(c.fastHandle, sh, 0, f) || !Copy1(c.slowHandle, sh, 0, s)) return false;
close = iClose(c.name, Timeframe, sh);
if(MathAbs(f - s) / PipSize(c.name) < MinEmaGapPips) return false;
if(isLong && f <= s) return false;
if(!isLong && f >= s) return false;
if(UseHtfFilter)
{
if(!Copy1(c.htfHandle, sh, 0, htf)) return false;
if(isLong && close <= htf) return false;
if(!isLong && close >= htf) return false;
}
if(UseAdxFilter)
{
if(!Copy1(c.adxHandle, sh, 0, adx)) return false;
if(adx < AdxMin) return false;
}
return true;
}
bool PullbackFiltersOk(SymCtx &c, const bool isLong, const int sh)
{
double gapPips = PullbackMinGapPips > 0 ? PullbackMinGapPips : MinEmaGapPips;
double f,s,adx;
if(!Copy1(c.fastHandle, sh, 0, f) || !Copy1(c.slowHandle, sh, 0, s)) return false;
if(MathAbs(f - s) / PipSize(c.name) < gapPips) return false;
if(PullbackAdxMin > 0)
{
if(!Copy1(c.adxHandle, sh, 0, adx)) return false;
if(adx < PullbackAdxMin) return false;
}
return BaseFiltersOk(c, isLong, sh);
}
bool PullbackLong(SymCtx &c, const int sh)
{
double touch, close, low;
if(PullbackTouch == 0) { if(!Copy1(c.fastHandle, sh, 0, touch)) return false; }
else { if(!Copy1(c.slowHandle, sh, 0, touch)) return false; }
close = iClose(c.name, Timeframe, sh);
low = iLow(c.name, Timeframe, sh);
return (low <= touch && close > touch);
}
bool PullbackShort(SymCtx &c, const int sh)
{
double touch, close, high;
if(PullbackTouch == 0) { if(!Copy1(c.fastHandle, sh, 0, touch)) return false; }
else { if(!Copy1(c.slowHandle, sh, 0, touch)) return false; }
close = iClose(c.name, Timeframe, sh);
high = iHigh(c.name, Timeframe, sh);
return (high >= touch && close < touch);
}
bool InLongLeg(SymCtx &c, const int barIndex)
{
if(c.lastBullCrossBar < 0 || c.lastBullCrossBar <= c.lastBearCrossBar) return false;
return (barIndex - c.lastBullCrossBar <= TrendLegBars);
}
bool InShortLeg(SymCtx &c, const int barIndex)
{
if(c.lastBearCrossBar < 0 || c.lastBearCrossBar <= c.lastBullCrossBar) return false;
return (barIndex - c.lastBearCrossBar <= TrendLegBars);
}
bool OpenTrade(SymCtx &c, const ENUM_ORDER_TYPE type, const double atr, const int barIndex, const bool isCross)
{
if(OneTradePerSymbol && HasOurPosition(c.name, c.magic)) return false;
if(MaxSpreadPips > 0 && SpreadPips(c.name) > MaxSpreadPips) return false;
if(!InSession()) return false;
if(atr <= 0) return false;
if(isCross) { if(barIndex - c.lastCrossBar < CrossCooldown) return false; }
else { if(barIndex - c.lastPbBar < PullbackCooldown) return false; }
double slDist = atr * AtrSlMult;
double tpDist = atr * AtrTpMult;
double ask = SymbolInfoDouble(c.name, SYMBOL_ASK);
double bid = SymbolInfoDouble(c.name, SYMBOL_BID);
g_trade.SetExpertMagicNumber(c.magic);
g_trade.SetDeviationInPoints(20);
bool ok = false;
if(type == ORDER_TYPE_BUY)
ok = g_trade.Buy(LotSize, c.name, ask, ask - slDist, ask + tpDist, "SimpleEMA pf BUY");
else
ok = g_trade.Sell(LotSize, c.name, bid, bid + slDist, bid - tpDist, "SimpleEMA pf SELL");
if(ok)
{
if(isCross) c.lastCrossBar = barIndex;
else c.lastPbBar = barIndex;
}
return ok;
}
void ManagePosition(SymCtx &c)
{
if(!HasOurPosition(c.name, c.magic)) return;
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
int barsHeld = iBarShift(c.name, Timeframe, openTime, true);
if(MaxBarsInTrade > 0 && barsHeld >= MaxBarsInTrade)
{
g_trade.SetExpertMagicNumber(c.magic);
g_trade.PositionClose((ulong)PositionGetInteger(POSITION_TICKET));
}
}
void ProcessSymbol(SymCtx &c)
{
ManagePosition(c);
if(!IsNewBar(c)) return;
int barIndex = iBars(c.name, Timeframe);
double atr1;
if(!Copy1(c.atrHandle, 1, 0, atr1)) return;
if(BullCross(c, 1)) { c.lastBullCrossBar = barIndex; c.activeLeg = 1; c.legPbCount = 0; }
if(BearCross(c, 1)) { c.lastBearCrossBar = barIndex; c.activeLeg = -1; c.legPbCount = 0; }
if(HasOurPosition(c.name, c.magic)) return;
if(BullCross(c, 1) && BaseFiltersOk(c, true, 1))
OpenTrade(c, ORDER_TYPE_BUY, atr1, barIndex, true);
else if(BearCross(c, 1) && BaseFiltersOk(c, false, 1))
OpenTrade(c, ORDER_TYPE_SELL, atr1, barIndex, true);
else if(UsePullback && InLongLeg(c, barIndex) && c.activeLeg == 1 && c.legPbCount < MaxPullbacksPerLeg
&& !BullCross(c, 1) && PullbackLong(c, 1) && PullbackFiltersOk(c, true, 1))
{
if(OpenTrade(c, ORDER_TYPE_BUY, atr1, barIndex, false)) c.legPbCount++;
}
else if(UsePullback && InShortLeg(c, barIndex) && c.activeLeg == -1 && c.legPbCount < MaxPullbacksPerLeg
&& !BearCross(c, 1) && PullbackShort(c, 1) && PullbackFiltersOk(c, false, 1))
{
if(OpenTrade(c, ORDER_TYPE_SELL, atr1, barIndex, false)) c.legPbCount++;
}
}
int ParseSymbols()
{
string parts[];
int n = StringSplit(SymbolList, ',', parts);
g_count = 0;
for(int i = 0; i < n && g_count < MAX_SYMS; i++)
{
string sym = parts[i];
StringTrimLeft(sym);
StringTrimRight(sym);
if(StringLen(sym) == 0) continue;
if(!SymbolSelect(sym, true))
{
Print("[SimpleEMA pf] skip unavailable: ", sym);
continue;
}
g_ctx[g_count].name = sym;
g_ctx[g_count].magic = MagicNumber + g_count;
g_ctx[g_count].lastBar = 0;
g_ctx[g_count].lastCrossBar = -100000;
g_ctx[g_count].lastPbBar = -100000;
g_ctx[g_count].legPbCount = 0;
g_ctx[g_count].activeLeg = 0;
g_ctx[g_count].lastBullCrossBar = -100000;
g_ctx[g_count].lastBearCrossBar = -100000;
g_count++;
}
return g_count;
}
int OnInit()
{
if(FastEmaPeriod >= SlowEmaPeriod) return INIT_PARAMETERS_INCORRECT;
if(ParseSymbols() <= 0) return INIT_FAILED;
for(int i = 0; i < g_count; i++)
{
string sym = g_ctx[i].name;
g_ctx[i].fastHandle = iMA(sym, Timeframe, FastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_ctx[i].slowHandle = iMA(sym, Timeframe, SlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_ctx[i].atrHandle = iATR(sym, Timeframe, AtrPeriod);
g_ctx[i].adxHandle = iADX(sym, Timeframe, AdxPeriod);
g_ctx[i].htfHandle = iMA(sym, PERIOD_H4, HtfEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(g_ctx[i].fastHandle == INVALID_HANDLE || g_ctx[i].slowHandle == INVALID_HANDLE || g_ctx[i].atrHandle == INVALID_HANDLE)
return INIT_FAILED;
}
Print("[SimpleEMA pf] loaded ", g_count, " symbols");
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
for(int i = 0; i < g_count; i++)
{
if(g_ctx[i].fastHandle != INVALID_HANDLE) IndicatorRelease(g_ctx[i].fastHandle);
if(g_ctx[i].slowHandle != INVALID_HANDLE) IndicatorRelease(g_ctx[i].slowHandle);
if(g_ctx[i].atrHandle != INVALID_HANDLE) IndicatorRelease(g_ctx[i].atrHandle);
if(g_ctx[i].adxHandle != INVALID_HANDLE) IndicatorRelease(g_ctx[i].adxHandle);
if(g_ctx[i].htfHandle != INVALID_HANDLE) IndicatorRelease(g_ctx[i].htfHandle);
}
}
void OnTick()
{
for(int i = 0; i < g_count; i++)
ProcessSymbol(g_ctx[i]);
}
-297
View File
@@ -1,297 +0,0 @@
#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,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=24
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=8
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=50
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=40
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=10
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=10
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=10
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=8
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=6
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=11
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=18
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=14
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=8
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=4
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=20
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=25
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=20
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=5
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=10
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=20
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=20
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=2.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.0
AtrTpMult=4.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=15
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=8
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=8
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=15
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.5
AtrTpMult=5.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=40
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.5
AtrTpMult=5.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=35
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.2
AtrTpMult=4.5
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=30
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.0
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.5
AtrTpMult=5.0
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=50
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.2
AtrTpMult=4.5
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=30
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=1
PullbackAdxMin=20
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=true
AdxPeriod=14
AdxMin=15
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=24
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=22
TrendLegBars=72
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=11
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=18
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=1
PullbackAdxMin=20
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=true
AdxPeriod=14
AdxMin=15
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=24
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=22
TrendLegBars=72
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=11
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=18
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=46
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=4
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=0
SessionEndHour=24
MaxSpreadPips=12.0
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=true
PullbackTouch=1
PullbackAdxMin=20
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=40
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=3
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=true
AdxPeriod=14
AdxMin=15
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=36
TrendLegBars=64
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=26
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=2
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=9
SlowEmaPeriod=34
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=10
SlowEmaPeriod=36
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=false
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=7
SlowEmaPeriod=28
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=3
UsePullback=false
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=100
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05
@@ -0,0 +1,26 @@
; SimpleEMA v5 — per-symbol MT5 set
Timeframe=16388
FastEmaPeriod=8
SlowEmaPeriod=30
TrendLegBars=48
MinEmaGapPips=1.5
CrossCooldown=2
PullbackCooldown=2
UsePullback=true
PullbackTouch=0
PullbackAdxMin=0.0
PullbackMinGapPips=0.0
MaxPullbacksPerLeg=1
AtrPeriod=20
AtrSlMult=2.71
AtrTpMult=6.36
MaxBarsInTrade=64
HtfEmaPeriod=200
UseHtfFilter=true
UseAdxFilter=false
AdxPeriod=14
AdxMin=18.0
SessionStartHour=8
SessionEndHour=22
MaxSpreadPips=12
LotSize=0.05

Some files were not shown because too many files have changed in this diff Show More