/* global React, AURA_DATA, Icon, Spark, EquityChart, BarChart, Donut */
const D3 = window.AURA_DATA;
const { useState, useEffect, useMemo } = React;
function ActiveTrades({ state }) {
const { openTrades, setOpenTrades, activeAccount } = state;
const unrealized = openTrades.reduce((a, b) => a + (b.pnl || 0), 0);
const refresh = () => {
if (activeAccount) window.api.openTrades(activeAccount.id).then(setOpenTrades).catch(() => {});
};
return (
<>
Active Trades
{openTrades.length} open · Unrealized {D3.fmtSigned(unrealized)}
{[
{ l: "Open Positions", v: openTrades.length.toString() },
{ l: "Unrealized P&L", v: D3.fmtSigned(unrealized), c: unrealized >= 0 ? "pos" : "neg" },
{ l: "Total Volume", v: `${openTrades.reduce((a, b) => a + b.volume, 0).toFixed(2)} lots` },
{ l: "Positions", v: openTrades.length === 0 ? "No open trades" : `${openTrades.filter(t => t.pnl >= 0).length}W / ${openTrades.filter(t => t.pnl < 0).length}L` },
].map((m) => (
))}
{openTrades.length === 0 ? (
No open positions — bot will show trades here when active
) : (
| Ticket | Symbol | Dir | Entry | SL | TP | Vol | P&L | Duration |
{openTrades.map((p) => (
| #{p.ticket} |
{p.symbol} |
{p.direction} |
{p.entry_price.toFixed(2)} |
{p.sl.toFixed(2)} |
{p.tp.toFixed(2)} |
{p.volume.toFixed(2)} |
= 0 ? "pos" : "neg"}`} style={{ fontWeight: 600 }}>{D3.fmtSigned(p.pnl || 0)} |
{D3.fmtDuration(p.open_time)} |
))}
)}
>
);
}
function TradeHistory({ state }) {
const { activeAccount } = state;
const [trades, setTrades] = useState([]);
const [filter, setFilter] = useState("all");
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!activeAccount) return;
setLoading(true);
window.api.tradeHistory(activeAccount.id, 200).then((t) => { setTrades(t || []); setLoading(false); }).catch(() => setLoading(false));
}, [activeAccount]);
const filtered = filter === "all" ? trades : trades.filter((t) => filter === "win" ? (t.pnl || 0) > 0 : (t.pnl || 0) <= 0);
const totalPnL = filtered.reduce((a, b) => a + (b.pnl || 0), 0);
const wins = trades.filter((t) => (t.pnl || 0) > 0).length;
const losses = trades.filter((t) => (t.pnl || 0) <= 0).length;
return (
<>
Trade History
{trades.length} trades · {wins}W / {losses}L
{[["all", "All"], ["win", "Wins"], ["loss", "Losses"]].map(([k, v]) => (
))}
Total: = 0 ? "pos" : "neg"}>{D3.fmtSigned(totalPnL)}
{loading ? (
Loading…
) : filtered.length === 0 ? (
No trades found
) : (
| Time | Ticket | Symbol | Dir | Entry | Exit | Vol | P&L | Reason |
{filtered.map((t) => (
| {D3.fmtDateTime(t.close_time)} |
#{t.ticket} |
{t.symbol} |
{t.direction} |
{t.entry_price.toFixed(2)} |
{t.exit_price != null ? t.exit_price.toFixed(2) : "—"} |
{t.volume.toFixed(2)} |
= 0 ? "pos" : "neg"}`} style={{ fontWeight: 600 }}>{D3.fmtSigned(t.pnl || 0)} |
{t.close_reason || "—"}
|
))}
)}
>
);
}
function SignalLog({ state }) {
const { activeAccount } = state;
const [signals, setSignals] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!activeAccount) return;
setLoading(true);
window.api.signals(activeAccount.id, 100).then((s) => { setSignals(s || []); setLoading(false); }).catch(() => setLoading(false));
}, [activeAccount]);
return (
<>
Signal Log
Bot reasoning for every cycle · last {signals.length} entries
{loading ? (
Loading…
) : signals.length === 0 ? (
No signals yet — signals appear here once the bot is running
) : (
{signals.map((s, i) => (
{D3.fmtDateTime(s.created_at)}
{s.direction}
{s.reasoning}
{s.action}
))}
)}
>
);
}
function Performance({ state }) {
const { activeAccount } = state;
const [perf, setPerf] = useState(null);
const [days, setDays] = useState(30);
useEffect(() => {
if (!activeAccount) return;
window.api.performance(activeAccount.id, days).then(setPerf).catch(() => {});
}, [activeAccount, days]);
const equity = useMemo(() => D3.generateEquityCurve(perf ? perf.equity_curve : []), [perf]);
const bars = useMemo(() => D3.generateBars(perf ? perf.daily_pnl : []), [perf]);
const wins = perf ? Math.round(perf.total_trades * perf.win_rate / 100) : 0;
const losses = perf ? perf.total_trades - wins : 0;
return (
<>
Performance & Analytics
Last {days} days · {perf ? perf.total_trades : "—"} trades
{[7, 30, 90].map((d) => (
))}
{[
{ l: "Total Trades", v: perf ? perf.total_trades : "—" },
{ l: "Win Rate", v: perf ? `${perf.win_rate.toFixed(1)}%` : "—", c: "pos" },
{ l: "Net P&L", v: perf ? D3.fmtSigned(perf.net_pnl) : "—", c: perf && perf.net_pnl >= 0 ? "pos" : "neg" },
{ l: "Max DD", v: perf ? `-${perf.max_drawdown_pct.toFixed(2)}%` : "—", c: "neg" },
].map((m) => (
))}
Wins {wins}
Losses {losses}
>
);
}
window.ActiveTrades = ActiveTrades;
window.TradeHistory = TradeHistory;
window.SignalLog = SignalLog;
window.Performance = Performance;