mirror of
https://github.com/quachtinh113/main-fx.git
synced 2026-08-01 21:07:46 +00:00
upade
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"python-envs.defaultEnvManager": "ms-python.python:system"
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
export default function ForexOpenClawDashboard() {
|
||||
const overview = {
|
||||
botStatus: "Running",
|
||||
mt5: "Connected",
|
||||
provider: "Anthropic",
|
||||
openPositions: 4,
|
||||
balance: 10342.18,
|
||||
equity: 10196.42,
|
||||
drawdownPct: 1.41,
|
||||
latestSignal: "BUY EURUSDm",
|
||||
lastUpdate: "2026-03-21 10:25",
|
||||
};
|
||||
|
||||
const signals = [
|
||||
{
|
||||
symbol: "EURUSDm",
|
||||
bias: "BUY",
|
||||
score: 82,
|
||||
regime: "TREND",
|
||||
entry: "1.0842 - 1.0848",
|
||||
rsiH1: 58,
|
||||
rsiM15: 34,
|
||||
adx: 27,
|
||||
atr: 0.00086,
|
||||
note: "H1 bullish, M15 pullback",
|
||||
},
|
||||
{
|
||||
symbol: "USDJPYm",
|
||||
bias: "SELL",
|
||||
score: 74,
|
||||
regime: "TREND",
|
||||
entry: "148.20 - 148.35",
|
||||
rsiH1: 43,
|
||||
rsiM15: 67,
|
||||
adx: 29,
|
||||
atr: 0.118,
|
||||
note: "Sell pullback in downtrend",
|
||||
},
|
||||
{
|
||||
symbol: "XAUUSDm",
|
||||
bias: "NO TRADE",
|
||||
score: 49,
|
||||
regime: "RANGE",
|
||||
entry: "Wait",
|
||||
rsiH1: 51,
|
||||
rsiM15: 53,
|
||||
adx: 18,
|
||||
atr: 7.2,
|
||||
note: "Range, no edge",
|
||||
},
|
||||
];
|
||||
|
||||
const positions = [
|
||||
{ ticket: 120381, symbol: "EURUSDm", side: "BUY", lot: 0.1, pnl: 24.8, opened: "09:12" },
|
||||
{ ticket: 120382, symbol: "EURUSDm", side: "BUY", lot: 0.2, pnl: -12.4, opened: "09:35" },
|
||||
{ ticket: 120410, symbol: "USDJPYm", side: "SELL", lot: 0.1, pnl: 31.2, opened: "10:01" },
|
||||
{ ticket: 120425, symbol: "GBPUSDm", side: "BUY", lot: 0.1, pnl: -5.6, opened: "10:14" },
|
||||
];
|
||||
|
||||
const riskChecks = [
|
||||
{ name: "Daily Loss Limit", value: "Pass", detail: "-1.41% / max 3.00%" },
|
||||
{ name: "Symbol Exposure", value: "Pass", detail: "EURUSDm 0.3 / max 0.5 lot" },
|
||||
{ name: "Basket Layers", value: "Warn", detail: "EURUSDm 2 / max 3 layers" },
|
||||
{ name: "Spread Filter", value: "Pass", detail: "All symbols within threshold" },
|
||||
{ name: "Kill Switch", value: "Off", detail: "No emergency lock" },
|
||||
];
|
||||
|
||||
const logs = [
|
||||
"10:25 Analyze EURUSDm -> BUY score 82",
|
||||
"10:24 Risk check EURUSDm BUY 0.1 -> approved",
|
||||
"10:24 Execute EURUSDm BUY 0.1 -> queued",
|
||||
"10:12 Analyze XAUUSDm -> NO TRADE score 49",
|
||||
"10:07 MT5 heartbeat OK",
|
||||
];
|
||||
|
||||
const StatCard = ({ title, value, sub }) => (
|
||||
<div className="rounded-2xl border bg-white p-4 shadow-sm">
|
||||
<div className="text-xs text-slate-500">{title}</div>
|
||||
<div className="mt-2 text-2xl font-semibold text-slate-900">{value}</div>
|
||||
{sub ? <div className="mt-1 text-sm text-slate-500">{sub}</div> : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
const Pill = ({ children, tone = "slate" }) => {
|
||||
const tones = {
|
||||
green: "bg-green-100 text-green-700",
|
||||
red: "bg-red-100 text-red-700",
|
||||
amber: "bg-amber-100 text-amber-700",
|
||||
blue: "bg-blue-100 text-blue-700",
|
||||
slate: "bg-slate-100 text-slate-700",
|
||||
};
|
||||
|
||||
return (
|
||||
<span className={`inline-flex rounded-full px-2.5 py-1 text-xs font-medium ${tones[tone]}`}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const toneForBias = (bias) => {
|
||||
if (bias === "BUY") return "green";
|
||||
if (bias === "SELL") return "red";
|
||||
return "amber";
|
||||
};
|
||||
|
||||
const toneForRisk = (value) => {
|
||||
if (value === "Pass") return "green";
|
||||
if (value === "Warn") return "amber";
|
||||
if (value === "Off") return "slate";
|
||||
return "red";
|
||||
};
|
||||
|
||||
const pnlTone = (pnl) => (pnl >= 0 ? "text-green-600" : "text-red-600");
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-50 text-slate-900">
|
||||
<div className="mx-auto max-w-7xl p-6">
|
||||
<div className="mb-6 flex flex-col gap-4 rounded-3xl border bg-white p-6 shadow-sm md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<div className="text-sm text-slate-500">OpenClaw + Forex Copilot</div>
|
||||
<h1 className="text-3xl font-bold">Dashboard v1</h1>
|
||||
<div className="mt-2 text-sm text-slate-500">Giám sát bot, tín hiệu, risk và lệnh mở trong một màn hình.</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Pill tone="green">Bot {overview.botStatus}</Pill>
|
||||
<Pill tone="blue">MT5 {overview.mt5}</Pill>
|
||||
<Pill tone="slate">LLM {overview.provider}</Pill>
|
||||
<Pill tone="amber">Updated {overview.lastUpdate}</Pill>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<StatCard title="Balance" value={`$${overview.balance.toFixed(2)}`} sub="Account balance" />
|
||||
<StatCard title="Equity" value={`$${overview.equity.toFixed(2)}`} sub="Real-time equity" />
|
||||
<StatCard title="Drawdown" value={`${overview.drawdownPct.toFixed(2)}%`} sub="Current floating DD" />
|
||||
<StatCard title="Open Positions" value={overview.openPositions} sub={`Latest: ${overview.latestSignal}`} />
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid gap-6 xl:grid-cols-3">
|
||||
<div className="xl:col-span-2 rounded-3xl border bg-white p-5 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">Latest Signals</h2>
|
||||
<div className="text-sm text-slate-500">Rule-based core, OpenClaw orchestration</div>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b text-left text-slate-500">
|
||||
<th className="py-3 pr-4">Symbol</th>
|
||||
<th className="py-3 pr-4">Bias</th>
|
||||
<th className="py-3 pr-4">Score</th>
|
||||
<th className="py-3 pr-4">Regime</th>
|
||||
<th className="py-3 pr-4">Entry</th>
|
||||
<th className="py-3 pr-4">RSI H1/M15</th>
|
||||
<th className="py-3 pr-4">ADX</th>
|
||||
<th className="py-3 pr-4">ATR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{signals.map((row) => (
|
||||
<tr key={row.symbol} className="border-b last:border-0">
|
||||
<td className="py-3 pr-4 font-medium">{row.symbol}</td>
|
||||
<td className="py-3 pr-4"><Pill tone={toneForBias(row.bias)}>{row.bias}</Pill></td>
|
||||
<td className="py-3 pr-4">{row.score}</td>
|
||||
<td className="py-3 pr-4">{row.regime}</td>
|
||||
<td className="py-3 pr-4">{row.entry}</td>
|
||||
<td className="py-3 pr-4">{row.rsiH1} / {row.rsiM15}</td>
|
||||
<td className="py-3 pr-4">{row.adx}</td>
|
||||
<td className="py-3 pr-4">{row.atr}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="mt-4 grid gap-3 md:grid-cols-3">
|
||||
{signals.map((row) => (
|
||||
<div key={`${row.symbol}-note`} className="rounded-2xl bg-slate-50 p-3 text-sm">
|
||||
<div className="font-medium">{row.symbol}</div>
|
||||
<div className="mt-1 text-slate-600">{row.note}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-3xl border bg-white p-5 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">Risk Guard</h2>
|
||||
<Pill tone="blue">Live</Pill>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{riskChecks.map((item) => (
|
||||
<div key={item.name} className="rounded-2xl border p-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="font-medium">{item.name}</div>
|
||||
<Pill tone={toneForRisk(item.value)}>{item.value}</Pill>
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-500">{item.detail}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid gap-6 xl:grid-cols-2">
|
||||
<div className="rounded-3xl border bg-white p-5 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">Open Positions</h2>
|
||||
<Pill tone="slate">{positions.length} tickets</Pill>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b text-left text-slate-500">
|
||||
<th className="py-3 pr-4">Ticket</th>
|
||||
<th className="py-3 pr-4">Symbol</th>
|
||||
<th className="py-3 pr-4">Side</th>
|
||||
<th className="py-3 pr-4">Lot</th>
|
||||
<th className="py-3 pr-4">PnL</th>
|
||||
<th className="py-3 pr-4">Opened</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{positions.map((p) => (
|
||||
<tr key={p.ticket} className="border-b last:border-0">
|
||||
<td className="py-3 pr-4 font-medium">#{p.ticket}</td>
|
||||
<td className="py-3 pr-4">{p.symbol}</td>
|
||||
<td className="py-3 pr-4"><Pill tone={p.side === "BUY" ? "green" : "red"}>{p.side}</Pill></td>
|
||||
<td className="py-3 pr-4">{p.lot}</td>
|
||||
<td className={`py-3 pr-4 font-medium ${pnlTone(p.pnl)}`}>{p.pnl >= 0 ? `+$${p.pnl}` : `-$${Math.abs(p.pnl)}`}</td>
|
||||
<td className="py-3 pr-4">{p.opened}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-3xl border bg-white p-5 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">Recent Logs</h2>
|
||||
<Pill tone="amber">Heartbeat OK</Pill>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{logs.map((line, idx) => (
|
||||
<div key={idx} className="rounded-2xl bg-slate-50 px-3 py-2 text-sm text-slate-700">
|
||||
{line}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-4 rounded-2xl border border-dashed p-4 text-sm text-slate-500">
|
||||
Nút v1 cần thêm sau: Kill Switch, Refresh Signal, Pause New Entries, Export Report.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -1,9 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
|
||||
from src.strategies.smart_money_adx_atr_rsi_strategy import SmartMoneyADXATRRSIStrategy
|
||||
sys.path.append(str(Path(__file__).parent.parent.parent))
|
||||
from strategies.smart_money_adx_atr_rsi_strategy import SmartMoneyADXATRRSIStrategy
|
||||
|
||||
|
||||
def load_processed(symbol: str, timeframe: str, suffix: str = "clean") -> pd.DataFrame:
|
||||
|
||||
Reference in New Issue
Block a user