↦ Arbitrage Bot

v— Unknown Unknown Last cycle: —
↻ auto-refresh 🔒 checking…
Dashboard Activity Started just now
Loading dashboard…
Connecting to the dashboard API and loading the Overview.
Dashboard loading and refresh activity will appear here.
Engine Process
Stopped
Engine is not running
Engine Activity Checking now
Loading engine activity…
Waiting for the dashboard API to respond.
Activity changes observed on this page will appear here.
The dashboard stays up even when the engine is stopped.
Safety Mode Read-only
While Dry Run is on, the bot evaluates and logs every trade but places no orders and makes no withdrawals. The one exception is the admin's Test withdrawal (RM1) in Settings → Luno MYR Auto-Withdrawal, which always sends real money. Switch Dry Run off only after you have checked the API keys, fees and balances.
DRY RUN — safe, no live orders
The operator controls this setting. Viewer access cannot change trading mode.
Holdings live exchange balances
Loading…
BTC delta—
Total BTC—
Total MYR—
Trades until rebal—
Owned vs held—
Exchanges
Connected platforms and their monitoring state. Disabling an exchange removes it from future engine cycles (in-flight trades are not cancelled).
ExchangeHealthMonitoringPairsCapabilitiesAction
Loading…
Loading pair data…
Monitored Pairs
Select which pairs the bot scans and trades. Only pairs available on both exchanges are shown.
Loading available pairs…
Live Spreads
Gross and net (after fees) spread for every enabled route across all exchanges.
Pair Route Qty Spread Profit Status
Loading…
Routes
Each limit route is enabled per ROW, not per platform — a row disabled at row level renders "disabled" regardless of the platform's own state. Each platform also has a Monitoring switch (whether the engine connects to it at all; a separate gate applied on top of the row flags below) and a one-click Disable limit routes action — a convenience that turns off every currently-enabled route touching that platform, and never turns one on. Re-enabling a route is always an individual click on its own row in the expandable list under each platform. A route is evaluated only when its row is enabled, both its platforms are monitored, it is supported on both legs, and its adapters are ready. The table below is read-only; use the per-platform controls above it to change enablement. The OTC route has its own toggle on the Runtime Config tab's OTC Desk card (operator-only) and is unaffected by these controls.
Loading platforms…
Pair Buy on Sell on Status Rebalance Notes
Loading…
P&L Summary
The date range below filters both this P&L summary and the Trade History table. "Today's P&L" always reflects today regardless of the range.
All time
Filters this summary and the Trade History table below.
Live real orders, exchange fills
Total P&L (MYR)
—
Today's P&L (MYR)
—
Total Trades
—
Win Rate / Avg Spread
—
Avg Exec Time
—
Avg Trade Size (MYR)
—
Most Traded Size (MYR)
—
Transfer Fees: Actual vs Assumed
—
Pre-Funded by Trades (MYR)
—
Net After Settlements (MYR)
—
Dry run simulated — no orders placed, estimates only
Total P&L (MYR)
—
Today's P&L (MYR)
—
Total Trades
—
Win Rate / Avg Spread
—
Avg Exec Time
—
Avg Trade Size (MYR)
—
Most Traded Size (MYR)
—
Transfer Fees Assumed (MYR)
—
no real settlements in dry run
Trade History LIVE
The date range above also applies here.
Time ▼ Exec time Pair Side Exchange Qty VWAP (MYR) Total (MYR) Fee Order ID Spread Profit MYR Max Viable (MYR)
Loading…
Opportunity Scans
Every window the market showed at your configured trade size, traded or not. Blocked rows are windows your balances or the order book could not take; their figures are at the configured size and never count as viable capacity, and they appear only when the window cleared your spread threshold.
Time Pair Route Mode Best Spread Best Profit (MYR) Max Viable (MYR) Outcome
Loading…
Arb Windows
Total size deployed per arbitrage window. A window opens on the first trade and spans the selected length (a 12:21 trade with a 1-hour window covers 12:21–13:21); the first trade after it closes opens the next window. Size = executed buy notional (MYR) per arb.
Window Start Window End Trades Total Size (MYR)
Loading…
Settlement Costs what each real transfer actually cost · live only
The spread charges every trade a transfer fee as if it moved its own funds back. In reality OTC returns come home in one on-chain move and the desk is settled by one bank transfer, so the REAL fee is recorded when you settle. Every row here is bound to the settlement that created it: Mark all complete or Mark complete on a transfer (the on-chain or bank fee, against those transfer ids) and Record settlement on the desk credit (the Luno withdrawal fee and the bank fee, against that ledger entry). Nothing is typed in here directly; a wrong row is voided on this table and re-entered from its settlement on the Inventory tab. The P&L above shows actual against assumed and nets the actual figure.
WhenKindFeePriceFee (MYR)ReferenceTransfers
No settlement costs recorded yet.
Holdings by Exchange live exchange balances · every asset
Loading…
Inventory Cost Basis cost basis vs Luno mid · live trades only · observation, not a trading input
One card per coin — loading…. Enter each deposit as the exchange shows it (amount, price, fee); the ledger works out what you hold and what it cost. Observation only.
Loading inventory…
Safety Mode
While Dry Run is on, the bot evaluates and logs every trade but places no orders and makes no withdrawals. The one exception is the admin's Test withdrawal (RM1) in Settings → Luno MYR Auto-Withdrawal, which always sends real money. Switch Dry Run off only after you have checked the API keys, fees and balances. The change applies from the next engine cycle, with no restart.
DRY RUN — safe, no live orders
Exchange Fees
Taker fees per (exchange, pair) used in spread math. A manual row is locked — the engine never overwrites it. An api row is auto-seeded from the exchange's fee API on each engine boot. Editing a row locks it (manual); use Set auto / Lock in the Source column to switch modes (auto is only available for exchanges with a fee API).
ExchangePairBuy %Sell %SourceUpdatedAction
Loading…
Bot Mode
Which kind of arbitrage the engine evaluates. Exactly one at a time, applied on the next engine cycle — no restart. Your per-route enable switches are never changed by this, so switching back restores the same selection.
Loading…
All values write to the project's .env file. Secrets are masked — click Show to reveal.
Exchange Credentials
API keys for each exchange. Binance is optional — leave its keys blank to disable it entirely. Restart the engine after changing these.
Loading…
Synthetic-MYR FX (XE Crawler)
Binance and Kraken hold no MYR — their *_MYR pricing is synthetic (BASE/USD × USD→MYR FX). Those pairs are only queryable when the self-hosted XE currency crawler is wired here. Leave the key blank to keep them metadata-only.
Loading…
Deposit Addresses
Required for auto-rebalance transfers into an exchange. Leave blank for coins you don't trade; a missing address forces that transfer to be manual.
Loading…
Luno MYR Auto-Withdrawal
Where the bot sends OTC sale proceeds (MYR) from Luno. Only a bank account already saved in your Luno app can be used; the bot re-checks it with Luno before every withdrawal.
Loading…
Loading…
Notifications
Discord webhook for trade alerts, heartbeat, and error notifications.
Loading…
Portal Integration
The internal Portal reaches this bot over loopback using a shared secret. Set the key to the Portal's configured value for this app — a blank key fails closed (the Portal sees the bot as unauthorized). The base path is where the adapter mounts (default /portal). Restart the engine after changing these.
Loading…
Server & Application
API server bind + auth token and the database path. Restart required after changes. Dry-run mode is controlled by the toggle on Overview / Runtime Config, not here.
Loading…
Startup Fee Defaults
Read at engine startup only. For live changes without a restart, use Runtime Config → Fees.
Loading…
Engine Log (tail)
Last 300 lines from logs/engine.log. Refreshes on demand.
Logs will appear here once the engine is started.
Dashboard Authentication
The token is auto-generated on first run; the browser fetches it automatically over loopback — you don't need to touch this. Only use manual entry when opening the dashboard from a different machine (e.g. through the Portal or an RDP tunnel).
checking…
Danger Zone — Reset Engine State
For when the engine is stopped but the status badge still says EXECUTING, SCANNING or TRANSFERRING, or Start keeps being refused: the engine died without cleaning up and left its lease, owner latch or pid behind. This clears those leftovers. It is refused while any engine process is alive, it never clears a HALT (use Resume on the Overview after you have verified the exchanges), and if any order intent is still unfinished it leaves the bot halted instead of idle, because an order whose fate is unknown must not be traded past. Every use is written to the audit log with your reason.
Portal Adapter — API Test
Exercises the adapter endpoints on this bot's loopback listener and shows the raw results. The key auto-fills from the bot; enable/disable/stop change the run state and ask to confirm.
Base path
X-Portal-Key
Auto-filled on the local machine (loopback only). Clear it to test the fail-closed 401.
Endpoints