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:
co-authored by
Cursor
parent
3f75a08848
commit
605faf5310
@@ -0,0 +1,142 @@
|
||||
# SimpleEMA — 练手实验室
|
||||
|
||||
双 EMA 金叉/死叉策略,默认货币对 **EURUSD H1**(流动性好、点差低,适合入门优化)。
|
||||
|
||||
## 策略逻辑
|
||||
|
||||
| 项目 | 规则 |
|
||||
|------|------|
|
||||
| 入场 | 快 EMA 上穿/下穿慢 EMA(收盘 K 确认) |
|
||||
| 出场 | 反向交叉 / ATR 或固定 SL·TP / 最大持仓 K 线数 / 可选 trailing |
|
||||
| 过滤 | 最大点差、最小 EMA 间距 |
|
||||
|
||||
## 文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `main.mq5` | MT5 EA(Strategy 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 Tester:Expert = `SimpleEMA`,Symbol = `EURUSD`,Period = `H1`
|
||||
3. Inputs → Load → `SimpleEMA_EURUSD.set`
|
||||
4. 优化时 Load → `SimpleEMA_Genetic_Optimization.set`,Optimization = **Genetic**
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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()
|
||||
@@ -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
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user