diff --git a/web/app/backtest/page.tsx b/web/app/backtest/page.tsx
index 9ef3d61..bad153e 100644
--- a/web/app/backtest/page.tsx
+++ b/web/app/backtest/page.tsx
@@ -3,35 +3,62 @@ import Link from "next/link";
export const metadata: Metadata = {
title: "Backtest Results",
- description: "ARES backtest results: M5 Momentum FVG scalper on XAUUSDm and BTCUSDm. London session filter, EMA-20 trend filter.",
+ description: "ARES v1.4.0 backtest results: M5 Momentum FVG scalper on XAUUSDm. ATR quality filter, EMA-20 trend filter, entry zone 75%, London session.",
};
const results: Array<{
- symbol: string; period: string; tf: string; risk: string;
+ symbol: string; period: string; tf: string; risk: string; version: string;
trades: number | null; wr: number; pf: number | null; ret: number | null; dd: number | null;
highlight: boolean; note?: string;
}> = [
- { symbol: "XAUUSDm", period: "1 Month", tf: "M5", risk: "1%", trades: 159, wr: 55.3, pf: 1.42, ret: 43.2, dd: -11.5, highlight: true },
- { symbol: "XAUUSDm", period: "50k bars", tf: "M5", risk: "5%", trades: 1421, wr: 50.3, pf: 1.17, ret: null, dd: null, highlight: false, note: "Session 08–13 UTC" },
- { symbol: "BTCUSDm", period: "50k bars", tf: "M5", risk: "5%", trades: null, wr: 56.9, pf: 1.11, ret: null, dd: null, highlight: false, note: "Session 08–13 UTC" },
- { symbol: "XAUUSDm", period: "1 Month", tf: "M5", risk: "5%", trades: 159, wr: 55.3, pf: 1.26, ret: 390, dd: -156, highlight: false },
- { symbol: "XAUUSDm", period: "1 Week", tf: "M5", risk: "1%", trades: 34, wr: 47.1, pf: 0.94, ret: -6.2, dd: -8.1, highlight: false },
+ { symbol: "XAUUSDm", period: "50k bars (~8 mo)", tf: "M5", risk: "5%", version: "v1.4.0", trades: 83, wr: 62.7, pf: 2.08, ret: 448.7, dd: null, highlight: true, note: "Session 08–13 UTC" },
+ { symbol: "XAUUSDm", period: "2025 Full Year", tf: "M5", risk: "5%", version: "v1.4.0", trades: 26, wr: 65.4, pf: 2.08, ret: 78.8, dd: null, highlight: false, note: "Session 08–13 UTC" },
+ { symbol: "XAUUSDm", period: "50k bars (~8 mo)", tf: "M5", risk: "1%", version: "v1.4.0", trades: 59, wr: 61.0, pf: 1.93, ret: 25.4, dd: -4.8, highlight: false, note: "Session 08–13 UTC" },
+ { symbol: "XAUUSDm", period: "50k bars (~8 mo)", tf: "M5", risk: "5%", version: "v1.3.0", trades: 224, wr: 50.0, pf: 1.17, ret: 174.7, dd: null, highlight: false, note: "No ATR filter" },
];
const params = [
- ["Timeframe", "M5"],
- ["Symbols", "XAUUSDm · BTCUSDm"],
- ["Session", "08:00–13:00 UTC"],
- ["EMA Period", "20"],
- ["Min FVG Pips", "1"],
- ["Min SL Pips", "5"],
- ["Min RR", "1.5×"],
- ["FVG Expiry", "10 candles"],
- ["Body PCT Min", "60%"],
- ["Close PCT Min", "80%"],
+ ["Timeframe", "M5"],
+ ["Symbol", "XAUUSDm"],
+ ["Session", "08:00–13:00 UTC"],
+ ["EMA Period", "20"],
+ ["ATR FVG Filter", "≥ 0.3× ATR(14)"],
+ ["ATR Impulse Filter","≥ 1.0× ATR(14)"],
+ ["Entry Zone", "75% into FVG"],
+ ["Min RR", "1.5×"],
+ ["FVG Expiry", "10 candles"],
+ ["Body PCT Min", "50%"],
+ ["Close PCT Min", "80%"],
+];
+
+// Simplified balance milestones for equity progression (50k bars, 5% risk, v1.4.0)
+// $5,000 start → $27,439 end
+const equityPoints = [
+ { label: "Start", value: 5000 },
+ { label: "Oct '25", value: 4953 },
+ { label: "Nov '25", value: 5173 },
+ { label: "Dec '25", value: 5901 },
+ { label: "Jan '26", value: 6902 },
+ { label: "Feb '26", value: 8240 },
+ { label: "Mar '26", value: 12440 },
+ { label: "Apr '26", value: 15600 },
+ { label: "May '26", value: 16038 },
+ { label: "Jun '26", value: 27439 },
];
export default function BacktestPage() {
+ const maxEquity = Math.max(...equityPoints.map(p => p.value));
+ const minEquity = Math.min(...equityPoints.map(p => p.value));
+
+ // Normalise to SVG viewBox height 80px
+ const h = 80;
+ const w = 340;
+ const pts = equityPoints.map((p, i) => {
+ const x = (i / (equityPoints.length - 1)) * w;
+ const y = h - ((p.value - minEquity) / (maxEquity - minEquity)) * h;
+ return `${x},${y}`;
+ }).join(" ");
+
return (
<>
- Historical simulation on real MT5 tick data. Includes spread costs, commission, and slippage.
+ Historical simulation on real MT5 tick data. Includes spread, commission ($7/lot), and slippage.
London session filter (08–13 UTC) applied.
XAUUSDm · Exness Demo
+ v1.4.0 · Best Result +XAUUSDm · Sep 2025 – Jun 2026
{label}
@@ -71,6 +98,145 @@ export default function BacktestPage() {Equity Progression
+50k M5 bars · 5% risk · XAUUSDm
+$27,439
+from $5,000
+What Changed in v1.4.0
+ATR Quality Gate
++ FVG zone ≥ 0.3× ATR(14) and impulse body ≥ 1.0× ATR(14). Weak, low-energy setups are discarded before entry. +
+Trades cut
+224 → 83
+PF impact
+1.17 → 2.08
+Entry Zone 75%
++ Limit order placed 75% deep into the FVG instead of the midpoint. Forces price to retest the level, confirming it as real support/resistance. +
+DD reduction
+−63%
+Win rate
+50% → 62.7%
+Session 08–13 UTC
++ Entries restricted to London open + early NY overlap. XAU liquidity and directional moves concentrate in this window — other hours produce noise. +
+vs all sessions
+PF ↑ best
+DD vs no filter
+lowest
+| {h} | ))}{r.period} | {r.tf} | {r.risk} | +{r.version} | {r.trades ?? "—"} | {r.wr.toFixed(1)}% |
@@ -133,13 +300,13 @@ export default function BacktestPage() {
How It Works -
Open-source algorithmic trading bot built in Rust. Momentum FVG scalper - with EMA trend filter, configurable session window, automatic position - sizing, and Telegram alerts — runs on any MT5 symbol. + with ATR quality filter, EMA trend filter, configurable session window, + automatic position sizing, and Telegram alerts — runs on any MT5 symbol.
View Trades
@@ -27,21 +27,26 @@ export default function DashboardPage() {
{/* Strategy */}
Strategy -
+
-
Full Results →
@@ -62,14 +67,15 @@ export default function DashboardPage() {
Backtest Highlight +Backtest Highlight · v1.4.0 - M5 · 1 Month · 1% Risk + M5 · 50k Bars · 5% Risk-XAUUSDm · 159 trades · Exness Demo +XAUUSDm · Sep 2025 – Jun 2026 · 83 trades
{[
- { label: "Profit Factor", value: "1.42" },
- { label: "Net Return", value: "+43.2%" },
- { label: "Max Drawdown", value: "−11.5%" },
- { label: "Win Rate", value: "55.3%" },
- ].map(({ label, value }) => (
+ { label: "Profit Factor", value: "2.08", sub: "vs 1.17 in v1.3.0" },
+ { label: "Net Return", value: "+448.7%", sub: "$5k → $27,439" },
+ { label: "Win Rate", value: "62.7%", sub: "vs 50% in v1.3.0" },
+ { label: "Max Drawdown", value: "−$2,669", sub: "vs −$5,482 in v1.3.0" },
+ ].map(({ label, value, sub }) => (
diff --git a/web/app/trades/page.tsx b/web/app/trades/page.tsx
index dfb04eb..14c95fb 100644
--- a/web/app/trades/page.tsx
+++ b/web/app/trades/page.tsx
@@ -18,22 +18,39 @@ export default async function TradesPage() {
let error = false;
try {
- [account, deals] = await Promise.all([
- getAccount(),
- getAllDeals(),
- ]);
+ [account, deals] = await Promise.all([getAccount(), getAllDeals()]);
} catch { error = true; }
const aresDeals = deals.filter(d => d.magic === MAGIC && d.type !== 2);
const closed = aresDeals.filter(d => d.entry === 1);
- const wins = closed.filter(d => d.profit > 0);
- const losses = closed.filter(d => d.profit < 0);
- const netPnl = closed.reduce((s, d) => s + d.profit + d.swap + d.commission, 0);
- const grossW = wins.reduce((s, d) => s + d.profit, 0);
- const grossL = Math.abs(losses.reduce((s, d) => s + d.profit, 0));
- const pf = grossL > 0 ? grossW / grossL : 0;
- const wr = closed.length > 0 ? (wins.length / closed.length) * 100 : 0;
- const currency = account?.currency ?? "USD";
+ const wins = closed.filter(d => d.profit > 0);
+ const losses = closed.filter(d => d.profit < 0);
+ const netPnl = closed.reduce((s, d) => s + d.profit + d.swap + d.commission, 0);
+ const totalFriction = closed.reduce((s, d) => s + d.swap + d.commission, 0);
+ const grossW = wins.reduce((s, d) => s + d.profit, 0);
+ const grossL = Math.abs(losses.reduce((s, d) => s + d.profit, 0));
+ const pf = grossL > 0 ? grossW / grossL : 0;
+ const wr = closed.length > 0 ? (wins.length / closed.length) * 100 : 0;
+ const avgWin = wins.length > 0 ? grossW / wins.length : 0;
+ const avgLoss = losses.length > 0 ? grossL / losses.length : 0;
+ const currency = account?.currency ?? "USD";
+
+ const bestTrade = closed.reduce{label} {value} +{sub}
+
{[
- { label: "Total Trades", value: closed.length.toString(), mono: true },
- { label: "Win Rate", value: `${wr.toFixed(1)}%`, mono: true },
- { label: "Profit Factor",value: pf > 0 ? pf.toFixed(2) : "—", mono: true },
- { label: "Net P&L", value: formatCurrency(netPnl, currency), mono: true, colored: netPnl !== 0 ? netPnl > 0 : undefined },
- { label: "W / L", value: `${wins.length} / ${losses.length}`, mono: true },
+ { label: "Total Trades", value: closed.length.toString(), mono: true },
+ { label: "Win Rate", value: `${wr.toFixed(1)}%`, mono: true },
+ { label: "Profit Factor", value: pf > 0 ? pf.toFixed(2) : "—", mono: true },
+ { label: "Net P&L", value: formatCurrency(netPnl, currency), mono: true, colored: netPnl !== 0 ? netPnl > 0 : undefined },
].map(({ label, value, mono, colored }) => (
{label} @@ -75,6 +91,103 @@ export default async function TradesPage() { ))}
+
+
+ {/* Win/Loss bar */}
+ {closed.length > 0 && (
+
+
+ Avg Win ++ {avgWin > 0 ? `+${formatCurrency(avgWin, currency)}` : "—"} + +
+
+ Avg Loss ++ {avgLoss > 0 ? `−${formatCurrency(avgLoss, currency)}` : "—"} + +
+
+ Total Friction ++ {formatCurrency(totalFriction, currency)} + +
+
+ Current Streak + {streak.count === 0 ? ( +— + ) : ( ++ {streak.count}× {streak.type === "win" ? "W" : "L"} + + )} +
+
+ )}
+
+ {/* Best / Worst trade */}
+ {(bestTrade || worstTrade) && (
+
+
+ Win / Loss Distribution +{wins.length}W · {losses.length}L +
+
+
+
+
+ {wr.toFixed(1)}% wins
+ {(100 - wr).toFixed(1)}% losses
+
+
+ {bestTrade && (
+
+ )}
+
{/* Equity curve */}
+
+ )}
+ {worstTrade && (
+ Best Trade +
+
+
+
+
+ {bestTrade.type === 0 ? "BUY" : "SELL"}
+
+ + +{formatCurrency(bestTrade.profit, currency)} + ++ {bestTrade.symbol} · {formatDate(bestTrade.time)} + +
+
+ )}
+ Worst Trade +
+
+
+
+
+ {worstTrade.type === 0 ? "BUY" : "SELL"}
+
+ + {formatCurrency(worstTrade.profit, currency)} + ++ {worstTrade.symbol} · {formatDate(worstTrade.time)} + +Equity Curve @@ -83,8 +196,9 @@ export default async function TradesPage() { {/* Trade table */}
-
+ Closed Trades +{closed.length} trades No closed trades yet.
@@ -110,8 +224,10 @@ export default async function TradesPage() {
|
{d.volume} | {d.price.toFixed(2)} | -= 0 ? "text-bull" : "text-bear"}`}> - {formatCurrency(d.profit, currency)} + | + = 0 ? "text-bull" : "text-bear"}`}> + {formatCurrency(d.profit, currency)} + | ))} @@ -125,4 +241,3 @@ export default async function TradesPage() { > ); } -
|---|