Installation Guide
Everything you need to go from a fresh VPS to a live running bot. Follow each step in order — don't skip ahead.
Before You Begin
Make sure you have the following before starting. No license key needed for the 30-day trial — it activates automatically on first run.
- A Binance account with Spot trading enabled
- A Telegram account to create your control bot
- A VPS (cloud server) — we recommend Vultr, DigitalOcean, or Linode
- Basic familiarity with copy-pasting terminal commands
Need help? Use the dashboard Support tab
The fastest way to get support is the built-in 🆘 Support tab in your ApexQuant dashboard. It opens a form that:
- Auto-attaches a diagnostic bundle (recent logs, redacted
.envwith NO secrets, system info, recent trades) - Lets you set severity (Low / Normal / High / Critical)
- Sends the ticket directly — no copy-pasting logs into email
With diagnostics attached, troubleshooting completes 3–5× faster than email-only tickets.
If you can't reach your dashboard (e.g. install failed before first launch), email {email} directly.
Choose your installation path
⚡ Quick install (recommended)
~15 minutes — guided installer, a few commands. Best for most customers.
Quick install →ⓘ Manual install
Step-by-step. Best for custom setups or learning what each step does.
Continue manual ↓🤝 Done-With-You Setup (guided by us)
We guide you through deploying ApexQuant on your VPS — you keep full custody of keys and funds. Non-refundable once payment is made.
Done-With-You →Before you start — services you'll need
⏱ ~30 minGather these before SSH'ing into your VPS. The 🔴 Required ones are non-negotiable. The 🟢 Recommended ones unlock more bot features (you can add them later via helper scripts).
🔴 Required — bot cannot trade without these
- Ubuntu 24.04 LTS VPS — 1 vCPU + 2 GB RAM minimum (2 vCPU + 2 GB recommended); a standard SSD is fine — NVMe isn't needed, root SSH access. Vultr / DigitalOcean / Linode. Step 1 covers VPS setup in detail.
- Binance Sub-Account API key + secret (strongly recommended over master account) — Spot trading enabled, withdrawals DISABLED, IP whitelist set to VPS IP. Create API keys. Step 4b covers sub-account creation; Step 4 covers loading keys. Sub-account isolates the bot — only sub-account funds at risk if API key ever compromised.
🟢 Recommended — unlocks more bot features
- Telegram bot token + chat ID — Optional but recommended. Get a free token from @BotFather for phone alerts (entries, exits, kill-switch) and remote control (
/balance,/positions,/buy,/sell,/killswitch). Step 5 covers setup; add anytime in the setup wizard or viaapexquant --config-gui. - Domain name — Optional but recommended for HTTPS dashboard. A record → VPS IP. nginx + Let's Encrypt setup covered later.
- FRED API key — Free from St. Louis Fed. Powers macro filter (FOMC + 10Y yield). Step 7 covers loading.
- Cloudflare Turnstile (optional) — free CAPTCHA for dashboard login; skip if your VPS is behind a VPN.
🟡 Tier-specific (Pro & Elite)
- Binance Futures access — only for the Funding Rate Harvest module. Binance has conditions for turning it on (an account opened first, a new key, the server's IP, no portfolio margin): they are listed under Funding Rate Harvest and in the FAQ.
- TradingView Pro (~$14.95+/mo, billed by TradingView) — for the TradingView Webhook strategy, which is coming soon (not available yet).
- AI provider API key — Anthropic / OpenAI / Gemini / DeepSeek / MiMo (Elite also: custom). Pro = Anthropic; Elite = all providers + choice. BYO key, ~$1–5/month typical.
🔵 ApexQuant license — optional
Have your license key (AQP-XXXX-XXXX-XXXX-XXXX)? Step 8 covers activation. No license yet? Skip Step 8 — bot runs in 30-day trial mode (paper/testnet). Buy from pricing when ready.
Set Up Your VPS
⏱ ~15 minApexQuant runs on a Linux server (VPS) that stays online 24/7. A laptop or desktop can technically run the bot, but is not recommended — if it sleeps, restarts, or loses internet, the bot stops and may miss critical exits on open positions. A VPS stays online 24/7 with no interruptions.
Create an account at your chosen provider. Deploy a new server with these specs:
💡 The installer automatically adds a 2 GB swapfile so the weekly ML retrain has headroom on a 2 GB VPS — no manual step needed.
Should work (community-supported, no guarantees): Debian 11/12 (use
apt as documented).Probably works with adjustments: RHEL 9 / Rocky / AlmaLinux / Fedora — translate
apt commands to dnf. systemd service file works as-is.Not supported: Alpine (no systemd by default), FreeBSD, macOS. Windows requires WSL2.
For trouble-free experience and fastest support, use Ubuntu 24.04 LTS (Vultr, DigitalOcean, Linode, AWS Lightsail).
Once your VPS is running, connect to it. Your provider will email you the IP address and root password, or you can use SSH keys (recommended).
Harden SSH Access
⏱ ~10 min · Highly Recommendedssh-copy-id root@YOUR_VPS_IP — this copies the key automatically.Keep Your VPS Patched 🛡️
⏱ ~5 min/month · CriticalReal-world examples: in 2026, Linux had two critical local privilege escalation vulnerabilities (Copy Fail and Dirty Frag) that allowed any local user to gain root access. Customers running unpatched kernels were exposed for weeks until they updated.
ApexQuant's systemd service auto-restarts after reboot. Open positions are persisted in the local database and restored automatically. No manual intervention needed.
Ubuntu can apply security patches automatically without manual apt upgrade. This catches critical patches between your monthly checks.
Note: kernel updates require a reboot to take effect. Unattended-upgrades will install them but won't reboot automatically. Schedule a monthly maintenance window to apply pending kernel updates and reboot.
Subscribe to your VPS provider's security mailing list or status page. Apply critical kernel patches within 48 hours of release for high-severity CVEs.
- Vultr: status.vultr.com
- DigitalOcean: status.digitalocean.com
- Linode: status.linode.com
- AWS Lightsail: health.aws.amazon.com
- Ubuntu security advisories: ubuntu.com/security/notices
Setup takes about 5 minutes:
- Sign up at dash.cloudflare.com (free, no credit card needed).
- In your Cloudflare dashboard sidebar, find Turnstile. Click Add widget.
- Widget name: e.g., "ApexQuant Login"
- Hostname: Enter your root domain (e.g.,
yourdomain.com). Turnstile automatically covers all subdomains — so the widget works onapp.yourdomain.com,bot.yourdomain.com, or any subdomain you choose later, with no reconfig needed. - Widget mode: Select Managed (recommended — Cloudflare auto-decides when to challenge).
- Click Create. Cloudflare displays your sitekey and secret key.
- Add both keys to your bot's
.envfile:
Easiest: run apexquant --config-gui (guided, no file editing). To edit manually instead:
Verification: visit your dashboard login URL. You should see a Turnstile widget below the password field. Without solving the challenge, login is rejected.
.env.
Backup & VPS Migration 💾
ApexQuant includes an encrypted Backup & Restore feature. Use it to protect your trading state (positions, DCA baskets, grid state, settings, equity history) and to migrate to a new VPS. Find it in the dashboard at Settings → Backup & Restore.
Restore recovers the bot's bookkeeping — entry basis, DCA baskets, grid state, baseline, and history. The exchange is always the source of truth: money that has already moved on the exchange stays moved. Restore does not undo trades.
There are two backup types:
- Routine backup — trading state + settings only: trade history, open positions, DCA baskets, grid state, settings, equity snapshots, baseline, and profile. Credentials (
.env) are excluded. This is the default and the safer choice for regular backups. - Migration backup — everything above plus your credentials (
.env: Binance API key/secret, Telegram token, etc.), passphrase-protected. Use this when moving to a new server and you want a near-complete restore.
Your license key is never in any backup — for security we don't store it in a form we can read, and we can't resend it. Keep your purchase email from {email} or a printout; you'll paste the key during setup.
In the dashboard: Settings → Backup & Restore → Create Backup. Enter a strong passphrase (store it safely — a lost passphrase means the backup is unreadable). Choose scope (Essential recommended). Click Download Backup. Store the .aqbackup file somewhere safe (offline storage recommended).
Restore stages the switch — it no longer refuses when positions are open. The engine boots in Restore Review mode (PAUSED) so you can review the state before resuming.
- Upload & restore — dashboard Backup tab → upload your
.aqbackupfile + passphrase. - Restore Review mode: trading is PAUSED, no entries or exits fire.
- Review the reconciliation report — the dashboard shows a banner with a report comparing the restored bookkeeping against live exchange holdings. Resolve any flagged orphans (adopt or sell).
- Recover trade history (optional) — use the Recover trade history from exchange section in the banner. Click Preview to see which ApexQuant-placed trades occurred after the backup, then Apply to import them and replay PnL. Only trades with an
aq_client order ID are imported — your manual trades are never touched. - Resume — click Resume Trading when satisfied.
What gets restored / recovered / not restored:
| Bucket | What |
|---|---|
| ✓ Restored from backup | Settings & config; ApexQuant trade ledger up to backup time; open-position bookkeeping (exit-manager / DCA / grid) as of backup. |
| ↻ Recovered from exchange | Current real holdings reconciled against exchange (Restore Review); ApexQuant-placed gap trades backfilled with FIFO PnL replay (aq_ prefix only). |
| — Not restored | Manually-placed Binance trades (never enter ApexQuant's books — bot-scope boundary); diagnostic logs; on-exchange trades are never reversed by restore. |
The fastest way to move to a new VPS is to restore right in the setup wizard. After bash install.sh, run apexquant --setup-gui and choose Restore from backup at the first step. Upload your .aqbackup file and passphrase — you'll see a preview of exactly what will and won't be restored, then confirm (or choose a fresh setup instead). The bot starts paused so you can review before resuming.
Before you restore, have these ready:
- Your license key — from your purchase email ({email}). See below — it's never in a backup.
- If you used a Routine backup: your Binance API key + secret (the wizard prompts for them since credentials aren't included).
- If you used a Migration backup: credentials are restored automatically — just confirm they look right in the preview.
Alternatively, on an already-running box, you can restore via Settings → Backup & Restore in the dashboard without stopping the setup wizard. Either path produces the same result: the bot boots paused in Restore Review mode.
Restore ≠ software update. To update the bot software on the same VPS, use Mode A (code-only) deploy — pull the new code and restart. No backup/restore involved. Back up your DB before any major update as a precaution.
Deploy ApexQuant
⏱ ~10 minVisit apexquant.tech/download and complete the challenge to get the latest ApexQuant setup zip.
From your local machine:
SSH into your VPS, then:
The installer will:
- Set up Python 3.12 venv + all dependencies
- Prompt for your license key — or skip for 30-day trial (paper/testnet)
- Ask about domain: YES → nginx + free Let's Encrypt SSL; NO → VPS IP on port 5005
- Configure systemd auto-start (restarts on reboot)
- Start the bot in paper mode — safe, no real orders
After install, the terminal shows your dashboard URL and PIN. Note them.
Configure .env
install.sh generates your .env file automatically and never asks for your Binance or Telegram credentials — for security, those are entered afterward through the guided setup wizard (apexquant --setup-gui; see Steps 4 and 5).
- Everything you can configure (trading mode, strategy, capital, risk, AI settings, and everything else in the Bot Config tab) — all set in the dashboard, never in
.env. This is the only documented way to change these. - The 13 keys that genuinely only live in
.env— Binance API keys (spot and futures), the dashboard password, the admin PIN, the session secret, the FRED API key, the Telegram token and chat ID, the Turnstile site key and secret, and the server timezone. These are secrets or one-time setup values — managed through the setup wizard orapexquant --config-gui, never through the Bot Config tab.
apexquant --config-gui or the dashboard is stored in the bot's database and takes precedence over the same key in .env. .env is only read for a key the database has no value for. So if you edit .env for a setting you've already changed via the config-GUI or dashboard, the edit is saved to the file but has no effect — the database value keeps winning until you change it the same way you set it.If you edit .env directly (e.g. with nano) for a Binance key, Telegram token, or another of the 13 .env-only values, restart the bot to load the change:
apexquant --config-gui prompts a bot restart after saving — no manual restart needed.
Beyond the 13 keys above, seven more settings genuinely only live in .env — they govern automatic halt protection or low-level server behavior, and are deliberately kept out of the Bot Config tab so they cannot be loosened accidentally from the dashboard. Most installs never need to touch these; they exist for operators who understand the consequences of changing them.
KILL_SWITCH_* settings and MIN_HALT_USDT_DROP govern the bot's own automatic halt protection — the system that stops trading when something looks wrong (equity implausibility, drawdown breaches). Loosening these (larger tick counts, longer delays, higher drop thresholds) makes the bot slower to halt on a genuine problem. Don't change them unless you understand exactly what each one gates.
| Key | Default | What it does |
|---|---|---|
KILL_SWITCH_SETTLE_DELAY_S | 5.0 | Seconds to wait after a trade before trusting the next equity reading — avoids a false implausibility trigger from a balance that hasn't settled yet post-fill. |
KILL_SWITCH_RESYNC_TICKS | 3 | Consecutive ticks of a persistent equity mismatch required before the kill switch treats it as a genuine re-sync (not a transient glitch) and adjusts its own baseline. |
KILL_SWITCH_DD_CONFIRM_TICKS | 3 | Consecutive ticks a daily or weekly drawdown breach must persist before the kill switch actually halts — a single-tick spike doesn't trigger a halt on its own. |
KILL_SWITCH_WARMUP_TICKS | 5 | Ticks after bot startup during which automatic halts are suppressed, giving the engine time to establish a stable baseline before the guards start evaluating it. |
MIN_HALT_USDT_DROP | 50.0 | Minimum absolute drop, in your account's currency (in addition to the % drawdown limit), required before a daily-drawdown halt fires — prevents a halt on a tiny account where the % limit alone would trigger on a trivial dollar amount. |
DASHBOARD_CORS_ORIGINS | (blank) | Comma-separated list of extra origins allowed to make cross-origin requests to the dashboard API. Blank (the default) means same-origin only — the dashboard and API are served from the same process, so no cross-origin access is needed for normal use. Only set this if you're building a separate frontend that calls the API directly. |
DASHBOARD_HTTPS | true | Whether the dashboard expects to be served over HTTPS (affects cookie security flags). Leave true unless you have a specific reason to serve the dashboard over plain HTTP — nginx setup in this guide always terminates HTTPS in front of the bot. |
Binance API Keys
- Go to Binance API Management.
- Create a new API key (type: System Generated).
- Enable: Enable Spot & Margin Trading.
- Disable: Enable Withdrawals — must be OFF.
- Set IP restriction: whitelist your VPS IP address.
- Save your API Key and Secret — the Secret is shown only once.
Only for the Funding Rate Harvest module. Binance has conditions for turning Futures on (an account opened first, a new key, the server's IP, no portfolio margin): see Funding Rate Harvest and the FAQ. Enter the keys via apexquant --config-gui (Binance panel).
See also: Step 4b — Binance Sub-account (recommended for stricter isolation).
The script prompts for API key, secret, and (optionally) a separate futures key. It writes them to .env and restarts the bot.
Binance Sub-Account 🔐
Sub-account creation is done from the Binance web UI. The exact menu path varies by account type and region. Use the official guide:
Binance: How to create sub-accounts →
[email protected]). Do not use your master-account email or an existing sub-account email. A fresh dedicated identity keeps the bot's sub fully isolated for login, 2FA, and API scope. Reusing an existing/master-mapped email still works functionally (funds are isolated), but a dedicated email is the recommended clean setup — easiest to get right at creation time and awkward to change later.
Once the sub-account exists, create an API key on the sub-account (not your main account) using the same settings as Step 4:
- Enable: Spot & Margin Trading
- Disable: Withdrawals — must be OFF
- IP whitelist: your VPS IP
Then load the sub-account API key via apexquant --config-gui (Binance panel).
Ed25519 Keys (Optional) 🔒
⏱ ~5 minApexQuant listens for your order fills in real time over a Binance connection called the order-update stream. Binance is moving that connection toward a newer, asymmetric key type called Ed25519 — it's faster and Binance is investing in it as the long-term standard. Your regular API key (Step 4) still works today and will keep working; setting up an Ed25519 key is simply getting ahead of that shift on your own schedule, rather than in a hurry later.
Once set up, ApexQuant uses the Ed25519 key automatically for order-update tracking. Your regular API key keeps handling everything else (placing/canceling orders, checking balances) exactly as before — nothing changes there.
- Go to the official Binance Asymmetric Keys Generator guide and download the generator tool from Binance's own site (linked from that page).
- Run the generator, choose Ed25519 as the key type (it's the default).
- Generate a new key pair. Save both files — you'll need the private key file in Step 3 below. Never share the private key file with anyone, including us.
- Go to Binance API Management.
- Create a new API key, choose type Self-Generated Ed25519 Key when prompted, and paste the public key from Step 1.
- Enable: Enable Spot & Margin Trading (this key only needs to read order updates, but Binance requires the permission to exist on the key for the subscription to authenticate — it is never used to place, cancel, or modify anything).
- Disable: Enable Withdrawals — must be OFF, same as every ApexQuant key.
- Set IP restriction: whitelist your VPS IP address, same as Step 4.
- Copy the API Key string Binance shows you — this is different from your regular (Step 4) API key.
.env file is loaded by a system service that does not support pasting a private key across multiple lines the way it normally looks in the downloaded file. You must collapse it to a single line first — the steps below show exactly how.
Open the private key file the generator saved in Step 1. It looks like this:
You need to turn every line break into the two characters \n (backslash, then the letter n) so the whole key becomes one line. The easiest way is a single command on your VPS — this reads the key file and prints the correctly-formatted single-line version for you to copy:
This prints one long line starting with -----BEGIN PRIVATE KEY-----\n and ending with \n-----END PRIVATE KEY-----\n. Copy that entire output — that's the value you'll paste into .env.
Now edit .env directly:
Add two lines (paste the single-line key from the command above — do not add extra quotes around it):
Save, then restart the bot to load the new keys:
Check the bot's own logs shortly after restart:
Look for a line mentioning session.logon succeeded and, shortly after, subscribed. If instead you see a line about falling back to the regular key, double-check the API key string and the private key formatting from Step 3 — the bot keeps trading normally either way, so there's no urgency, but you can fix it and restart again whenever convenient.
Telegram Bot
Telegram integration is optional but strongly recommended — it delivers trade alerts (entries, exits, kill-switch) and enables remote commands like /balance, /positions, /buy, /sell, and /killswitch from your phone. Everything stays between your own private bot and you — no third party is involved.
- Open Telegram and start a chat with @BotFather.
- Send
/newbotand follow the prompts to name your bot. - Copy the token BotFather sends you (format:
123456789:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx). Keep it secret — anyone with this token can control your bot. - (Optional) Verify the token: open
https://api.telegram.org/bot123456789:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/getMein a browser (replace the example token with your real bot token) — you should see your bot's details in the response. Note: the digits before the colon are your bot's own numeric ID — they're part of the token, not your chat ID.getMeneeds no chat ID.
- Start a chat with @userinfobot — it replies with your numeric chat ID (e.g.
123456789). - Alternative: send any message to your new bot first, then open
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdatesand look for"chat":{"id":…}— that number is your chat ID.
The script prompts for your bot token and chat ID, writes them to .env, and restarts the bot. You can also enter Telegram Bot Token (TELEGRAM_TOKEN) and Telegram Chat ID (TELEGRAM_CHAT_ID) in dashboard Settings and save instead.
/revoke to invalidate it and issue a new one.Admin PIN (Recommended)
A PIN protects destructive actions in the dashboard and Telegram. Recommended for live mode.
- Open dashboard → Profile tab → 🔐 Admin PIN section
- Leave "Current PIN" blank for your first setup
- Choose a 4–8 digit PIN. Confirm it. Click Update PIN.
A modal will appear before any of these actions:
Enter PIN → action proceeds. The PIN is remembered for a short while — subsequent actions don’t re-prompt.
For /buy, /sell, /restart commands when PIN is enabled:
You: /buy BTC 25
Bot: 🔒 PIN required. Reply with your 4-6 digit PIN as your next message.
Send /cancel to abort.
You: 1234
Bot: ✓ PIN verified. [shows BUY preview card]
Set Admin PIN (APEXQUANT_PIN) to a new value in .env (or leave it unset to clear the PIN), add RESET_ADMIN_PIN=1, and restart the bot. Then open dashboard → Profile → Admin PIN to set a fresh PIN, and remove RESET_ADMIN_PIN from .env and restart again. No database editing required.
Switching Trading Mode (PAPER ↔ TESTNET ↔ LIVE)
From 4.9.0 onwards, trading mode is controlled entirely in the Dashboard — you no longer edit .env for this. Open Dashboard → Bot Config tab → Trading Mode:
- PAPER: simulated orders against live prices. No Binance API key required. Default and safe.
- TESTNET: real Binance testnet API with fake funds. Validates your full configuration end-to-end before risking real money.
- LIVE: real money trading. Requires Starter tier or above, plus a typed
I CONFIRMphrase, risk-acknowledgement checkbox, and your Admin PIN. Once confirmed, restart the bot for the change to activate.
Switching away from LIVE (e.g. back to TESTNET) requires only the Admin PIN — no typed phrase.
Legacy installs: if your existing .env has CONFIRM_LIVE=YES_I_KNOW, the bot will auto-migrate this to the dashboard flag on first start of 4.9.0 and log a deprecation notice. You can safely remove the line from .env after that.
Install Your License Key
⏱ ~2 minYour license key looks like AQP-XXXX-XXXX-XXXX-XXXX. It was sent to you by email after purchase.
First Run — TESTNET
⏱ ~10 minVerify everything works on Testnet before touching real money. This is the most important step.
Every time you open a new terminal session, activate the venv before running any Python commands:
Open your browser and visit:
You should see the bot status, regime indicator, and price feeds. If Telegram is configured, send /status to your bot.
Go Live (When Ready)
⏱ ~5 minEasiest: run apexquant --config-gui (guided, no file editing). To edit your Binance keys manually instead — Trading Mode itself is switched in Dashboard → Bot Config tab, not here (editing TRADING_MODE in .env has no effect once you've set it via the dashboard; see Configure .env):
Then switch Trading Mode to LIVE in Dashboard → Bot Config tab and confirm you see [ENGINE] LIVE mode active in the log.
SSL & nginx Setup
⏱ ~20 min · Highly RecommendedThis setup: nginx handles HTTPS on port 443, forwards traffic to the bot on port 5005 (localhost only). Port 5005 is never exposed to the internet.
Do you have a domain name?
With Domain (nginx + Let's Encrypt SSL)
You need a domain or subdomain pointing to your VPS IP. Recommended: use app.yourdomain.com.
Let's Encrypt is free SSL. Certbot automates certificate issuance and renewal.
Monitor API Health
The dashboard's API Health card on the Live tab monitors connectivity and authentication status for every external service ApexQuant depends on. This is your single-glance early-warning system: if something breaks (Binance API key revoked, License Server unreachable, FRED API key expired), you see it here before trades start failing.
- Binance API — connection + permission audit (LIVE mode only). Alerts if withdrawal permission is enabled (security risk).
- License Server — your ApexQuant license validation server. Required.
- Telegram Bot API — only if you've configured Telegram commands.
- FRED Macro Data — only if you've set FRED_API_KEY (used for macro gate).
- AI Provider — your configured AI Commentary provider (Anthropic, OpenAI, Gemini, DeepSeek, MiMo, or custom — per AI Commentary Provider (
AI_PROVIDER)), shown when an AI key is set. Pro & Elite — see the AI Commentary section for the full list. - TradingView — only for the TradingView webhook strategy (coming soon).
- Fear & Greed Index — sentiment data source (no API key required).
- CoinGecko — market data fallback (no API key required).
The card defaults to a compact summary. Click View details ▾ to expand:
- ✓ All systems operational — every required service is healthy. Green.
- ⚠ ServiceName: warning — something is degraded (e.g., license expiring soon). Yellow.
- ✗ ServiceName: error — a required service is down. Red. Investigate immediately.
Services without API keys show as ○ Not configured — gray, neutral. Informational, not an error.
The ↻ Refresh all button forces a fresh parallel check of every service (~3–5 seconds). Per-service ↻ buttons recheck individual services. Data is cached per-service (5–15 minutes) so the card doesn't hammer external APIs on every page load.
In TESTNET mode (TRADING_MODE=TESTNET), the Binance permission audit shows as informational gray ℹ because Binance testnet doesn't implement the permission endpoint. Expected behaviour — switch to LIVE mode to enable the full audit.
Restarting the Bot
ApexQuant supports safe in-place restarts that preserve all open positions, halt state, and trade history. Use this whenever you change configuration that requires a restart.
- Go to the Settings tab
- Scroll to the bottom — Restart Now button
- Confirm in the popup
- Enter your 2FA code (if 2FA enabled) or PIN (if APEXQUANT_PIN set)
- Bot restarts in ~10 seconds, page auto-reloads
Type /restart in your bot chat → tap Confirm → enter your APEXQUANT_PIN → restart triggers. Bot sends a status message once back online.
- Open positions (exit_manager re-attaches on startup)
- Halt state, kill-switch state, daily/weekly DD limits
- Trade history (DB unaffected)
- Pending orders on Binance (Binance-side, not affected)
- Websocket connections to Binance (~3–5 seconds)
- License heartbeat to License Server (~10 seconds)
- Telegram polling thread
Every restart is logged with trigger source and authentication method:
[SYSTEM] Restart scheduled via dashboard by web ✓ PIN verified — flag in 1.5s
[SYSTEM] Restart scheduled via telegram by 12345 ✓ PIN verified — flag in 1.5s
Restarts are rate-limited. If you restart again too soon, you'll see a message asking you to wait before the next restart.
Enable Two-Factor Authentication (Recommended)
ApexQuant supports TOTP-based 2FA for the dashboard, gating sensitive actions like Settings save, restart, and license entry behind a 6-digit code from your authenticator app. Strongly recommended for production deployments.
Log in to the dashboard. Go to the Settings tab. Scroll to the Two-Factor Authentication section near the top.
Click Set up 2FA. The dashboard generates a TOTP secret and displays a QR code. Open your authenticator app and scan it.
If your phone is not handy, click Show secret to manually enter the base32 secret into the app instead.
Your authenticator app shows a 6-digit code that rotates every 30 seconds. Enter the current code into the verification field on the dashboard to confirm setup.
On successful verification, the dashboard generates 10 single-use recovery codes. Copy them now — they are shown only once. Store them in a password manager or print and lock away. If you lose your authenticator app and have no recovery codes, delete ~/.apexquant_2fa on your VPS to reset 2FA.
- Dashboard login — required after session expires
- Settings save — protects against misconfiguration if session is hijacked
- Restart Now button — prevents unauthorized restarts
- License key entry — protects your license from being changed
After several wrong codes the action is locked for a while.
Telegram commands are gated by a separate PIN (Admin PIN, set via APEXQUANT_PIN env var), not by TOTP. Set a 4–6 digit PIN in your .env:
Asked for every time, never remembered: /buy and its buttons, /sell, /forcesell, /dca buy, /dca resume, /dca reset, /dca close, /dca sell, /grid resume, /grid recenter, /grid extend, /grid stop, /grid rebuild, /set (for a money setting; the other settings are free), /mode (a change), /resume, /restart, Stop & Quit, /recalibrate, /setkey, /aibudget RAISE, and license commands. With 2FA on, the bot asks for the 6-digit code instead of the PIN. A code you entered for one of these is used by that one action only: Telegram's five-minute pass is not used for them (/grid pause and /grid drain keep it). /stop and /emergency (halt immediately: positions are kept, nothing is sold) ask for nothing, because the chat is yours.
On the dashboard, every action that moves money or changes what the bot does with it needs the PIN (or the 2FA code), asked each time: the Sell and Buy buttons (position, part of a position, held position, leftover coin), Stop & Liquidate, Reset & Rebuild, Resume, Restart, Stop & Quit, the grid controls, the currency switch, the strategy and trading-mode switches, saving or resetting any money setting, taking over coin, a backup restore, the licence key and the TradingView secret. Emergency Stop is the exception: it asks for your dashboard password typed again, no PIN and no 2FA code. With neither a PIN nor 2FA set up there is no manual sale or buy: ApexQuant says “To sell manually, set an Admin PIN or turn on 2FA first.” (or “To do this, set an Admin PIN or turn on 2FA first.”). The same in paper, testnet and live mode, and while halted. The bot's own exits (stop-loss, trailing stop, take-profit, grid sells, DCA exit) never ask.
Go to Settings → Two-Factor Authentication → Disable 2FA. Enter your current TOTP code to confirm.
Emergency reset (lost authenticator + no recovery codes):
Live Tab — Real-time Dashboard
📊 Live tab
The Live tab is your real-time view of the bot's activity. At the top, your Account Equity is shown prominently with today's profit or loss. Status pills below show whether the bot is running, in testnet or live mode, and which strategy is active.
Below the equity card is an 🧠 AI Commentary panel — your AI provider analyzes current market conditions and your portfolio, giving you context on what to expect (Elite tier).
The 📍 Open Positions table shows every asset the bot is currently holding, with entry price, current price, market value, and unrealised P&L. Every plan has SELL buttons to manually close positions.
Use the ⚡ Manual Trade controls to place a buy outside the bot's automatic logic. Buys are added to the DCA basket (or whichever strategy is active).
The 📜 Recent Trades table lists the bot's last 20 closed trades with filters for All / Auto entries / Manual entries / Managed.
For deeper insight, expand ▸ Strategy & System Details to see ML Gate confidence, current market regime, coin selection mode, API health, license status, daily drawdown, holdings count, and engine ticks. Or expand 📈 Equity Curve for a chart of your balance over time.
Privacy tip: click the 👁 icon next to "Account Equity" to mask all dollar values when sharing your screen or recording videos.
Quick system check: the status indicator in the top-right header shows the overall system state at a glance — click it for an instant diagnostics modal with API health, license verification, regime, ML gate, and drawdown details. Useful when you're on another tab and want to peek at system health.
Dashboard Profile Tab 👤
⏱ ReferenceThe Profile tab is your single place for personal identity, authentication, and license info. It replaces the old separate "License" tab.
- Display Name — your shown name in the dashboard header. Defaults to "User" until you set one.
- Avatar — upload a PNG or JPG (max 256KB). Or leave blank to show your initial as a styled letter circle.
- Change Password — change your dashboard login password without editing
.env. Old password required for verification. Forces re-login on save. - License — view your license key (with reveal/copy/save), tier, expiry, and status. Same functionality as the previous old dedicated tab (now consolidated here). The Renew button appears 30 days before expiry (and immediately if lapsed) — click it to renew using the same email, keeping your existing key and earning early-renewal bonus days.
- Connections — read-only view of your Telegram chat ID. To change, edit Telegram Chat ID (
TELEGRAM_CHAT_ID) in.envand restart. - Language — currently English only. More languages coming soon.
📊 Performance tab — daily, monthly, and yearly P&L breakdowns. Use the pill switcher at the top to toggle between views. A bar chart shows P&L for the selected period.
.env value, so editing .env alone may not work if you previously changed it in-app. Reset it without touching your database:
- Set
DASHBOARD_PASSWORD=<your-new-strong-password>in.env. - Add
RESET_DASHBOARD_PASSWORD=1to.env. - Restart the bot (
systemctl restart apexquant). Log in with the new password. - Remove the
RESET_DASHBOARD_PASSWORDline from.envand restart once more.
This clears the in-app hash so your .env password is used. Your trading data is completely unaffected.
Why did my bot halt?
Common license-binding causes and how to recover without contacting support.
| Cause | What happened | Recovery |
|---|---|---|
| New server detected | You migrated to a new VPS and the license sees a different machine ID. | Click Re-bind this device in the dashboard halt overlay. (Limit: 2 re-binds / 30 days.) |
| Binance API key changed | You rotated your Binance API key after activation. | Click Re-bind API key in the dashboard halt overlay. |
| Account conflict | Another ApexQuant instance is running on the same Binance account. | Run one instance per Binance account. Use a sub-account for a second bot — each sub-account is treated as a distinct account. If your old server is gone, click Claim this account in the overlay. |
| License expired | Your license period ended. | Renew at apexquant.tech/renew. |
When a loss limit stops ApexQuant (a safety stop)
If your daily or weekly loss limit is reached, ApexQuant stops trading for you and says why in plain words, for example:
The money ApexQuant watches is your cash plus the cost of the coin you hold. A coin's price going up or down does not move it. Money that leaves the account (a withdrawal, a Binance test-network reset) does count, because it really is gone from the account.
- No new buys; selling still works. A halt blocks new buys only. Your open positions are still watched and still sold at their stop-loss, trailing stop, take-profit or DCA exit. Sell orders already on Binance stay and can still fill, and a grid still puts a sell on coin it holds (for example the part of a buy that filled before the stop took the rest of that buy off). Your own sells work too: the dashboard's Sell, the Sell buttons in Telegram, the typed
/selland/forcesell, each confirmed with your PIN or 2FA code. (If three stop-losses fire within ten seconds, ApexQuant treats it as a cascade and stops its automatic exits until you resume.) - A grid's waiting buy orders are taken off Binance, once. They were placed before the stop and could fill while ApexQuant is not allowed to buy. If Binance does not confirm the cancel, ApexQuant tries again every minute until it does. When trading resumes, the grid puts a buy back on every empty level below the price by itself. This is true for your own Emergency Stop too.
- It is said once, not over and over. The log says it when it starts, with the reason. While it lasts, one reminder every 15 minutes says how long it has lasted (“Still halted after 1 h 30 min”). When it ends, one line says so and how long it lasted (“The halt is over after 42 min; entries are allowed again”).
- It survives a restart. A stop that was in force when ApexQuant restarted is restored, and its message says its figures are as of the halt. Send
/resumeor press Resume when you are ready.
When ApexQuant starts, its safety monitor reads your account first. The log line says what it counts: “Now protecting your account — your money counts as 1,000.00 USDT (cash plus the cost of the coin you hold)”, with your daily and weekly limits. No grid is started and no order is sent before the monitor is ready, and a stop that was in force is restored first. In those first moments a grid that has not started shows “The safety monitor is starting, so no new grid is started yet.” and starts by itself a moment later. If a stop is in force it shows “Trading is halted, so no new grid is started. Press Resume when you're ready.”
Health warnings (self-check)
ApexQuant runs a background self-check. If something looks off it shows a cautious warning, keeps running, and usually self-recovers. Here's what each warning means and what to do.
| Warning | What it means | What to do |
|---|---|---|
| Equity Snapshot | The engine hasn't recorded the balance recently. | Usually self-recovers. If it lasts more than 10 minutes, restart the bot. |
| Exit Checks | Stop-loss / take-profit checks look delayed. | Self-recovers. If it persists with open positions, restart the bot. |
| Kill-Switch Feed | The risk-limit monitor hasn't refreshed. | Usually a brief pause that self-recovers. If it lasts more than 10 minutes, restart the bot. |
| Strategy Dispatch | The active strategy hasn't run a cycle recently. | Self-recovers. If it persists, restart the bot. |
| Strategy Not Cycling | The strategy is enabled but hasn't advanced a cycle. | May be stuck. Restart the bot if it persists. |
| Background Worker Stopped | A background thread has stopped. | Restart the bot from your VPS. |
| Strategy Not Running | Config selects a strategy that isn't actually running. | Restart the bot and re-check your strategy config. |
| Halted But Strategy Active | The safety halt is on but a strategy is still running — new entries may fire. | Restart the bot from your VPS. |
| Halt Consistency | New trades were seen while the safety halt is on. | Restart the bot and review. Contact support if it repeats. |
| Trades vs Equity | Trading activity while balance recording is frozen. | Restart the bot. |
| Assets Sanity | Open positions aren't reflected in bot equity. | Restart the bot. |
| Config Drift | Saved configuration differs from what the running engine is using. | Restart the bot to apply the saved configuration. |
| Any warning > 10 min | The condition didn't self-clear. | Restart the bot. Contact support if it repeats. |
| Balance Temporarily Unavailable | The bot couldn't read your exchange balance for a moment, so it paused risk checks and kept using the last known value. Your funds and positions are untouched. | Self-recovers automatically once the balance reads again — usually seconds. No action needed unless it persists past 10 minutes. |
| Verification Pending | Right after startup, the bot is still confirming the exchange connection. It shows "connected, verification pending" until the first check completes. | Normal on boot. Clears within the first cycle — no action needed. |
| Request Timestamp Rejected | The exchange rejected a request because it arrived slightly outside the allowed time window — almost always brief network latency, not your server clock. The bot resynced and retried automatically. | Self-resolves. No action needed. If it happens constantly, check your VPS network connection to the exchange. |
| Request Slow to Respond | A request to the exchange was slow and the bot safely abandoned and retried it, rather than waiting indefinitely. | Normal under occasional exchange latency. Self-recovers. No action needed. |
| Insufficient Trading Capital | An order wasn't placed because the available balance couldn't cover it. Nothing was sent to the exchange and nothing was sold. | Add funds or lower the per-order size in your config if you want more orders to place. Shown once per shortfall, not repeatedly. |
| Holding Adjusted (tracked separately) | The bot found inventory that didn't map to a grid level and moved it to a separately-tracked holding so it's protected and visible. Nothing was sold, nothing was lost. | Informational only. The holding stays protected and appears in Holdings. No action needed. |
| Waiting for Binance | Binance cannot be reached right now. The dashboard still opens and shows what ApexQuant last knew; nothing is ordered until Binance answers again. See What happens during an API outage. | Nothing to do. ApexQuant keeps trying on its own and says once when Binance is back. |
| Currency Balance Empty | Your account's currency has less than the smallest order, but another stablecoin in your wallet holds at least that much. For example: “Your USDT balance is 0, but you hold 500.00 USDC. ApexQuant trades in USDT, so it can't use that. Switch your currency to USDC in Settings, or convert on Binance (Binance charges a small trading fee).” It is said once in the log and once on Telegram, and the dashboard keeps the notice for as long as it is true. | Nothing is switched or converted for you. Switch the currency in Settings, or convert on Binance (Binance charges a small trading fee). The notice clears by itself when the balance is back above the smallest order or the currency is switched. Another stablecoin the bot cannot use is never counted as money it can trade with. |
| Duplicate Order Cleanup | The bot found more than one order on the same price level and cleaned up the extra (which held no coins), keeping the real one. | Automatic housekeeping. No action needed. |
Emergency Stop
The 🛑 EMERGENCY STOP button on the Live tab halts the bot immediately. Use when you've lost confidence in the running configuration, suspect a bug, or want to pause before making changes.
- Creates a STOP file in the bot folder
- Bot halts at the next tick — no new entries open
- Telegram alert fires confirming the stop
- Open positions remain, and every sell still works (stop-loss, trailing stop, take-profit, DCA exit, grid sells and your own sells); only new buys are blocked until you resume
- You spot unexpected behaviour and want to investigate
- Market making a violent move outside your strategy's design
- Before changing config you don't trust
- Loss of confidence in the running state
Emergency Stop asks for your dashboard password typed again (when you have set one), and nothing else: never your PIN and never a 2FA code, so you can stop the bot in a hurry without finding your phone. It works on every account, with or without a PIN or 2FA. In Telegram, /stop and /emergency ask for nothing, because the chat is yours. To start again, Resume needs your PIN (or your 2FA code), and so does Stop & Quit.
- Click ▶ Resume Bot on the Live tab (or send
/resumein Telegram) - Bot resumes from current state — open positions are managed normally again
| Action | Triggered by | Cleared by | When to use |
|---|---|---|---|
| Kill Switch | Auto: drawdown / loss streak / balance floor | /resume | System auto-halts on risk limits — investigate then resume |
| Emergency Stop | Manual: 🛑 button or /stop in Telegram | /resume | You decide to halt right now |
| Restart Bot | Manual: the Restart button on the dashboard | ApexQuant starts again by itself | Apply env changes, recover from crash, refresh state |
AI Commentary Pro & Elite
⏱ ~5 min setupThe AI Commentary feature adds an AI analysis layer that runs before every BUY entry. It reads all available signal data and provides informational analysis — confidence assessment, market reasoning, and context — to inform the trade decision. This is informational output; it does not guarantee outcomes. Supported providers: Anthropic Claude (Pro & Elite), OpenAI ChatGPT, Google Gemini, DeepSeek, Xiaomi MiMo, and any custom OpenAI-compatible endpoint (Elite). You supply your own API key and pay the provider directly — $0 cost to us.
All AI features are opt-in. Starting v4.9.5, no AI feature fires automatically by default. You explicitly enable what you want:
- AI Commentary — click the “🧠 Generate” button in the Live tab to refresh on demand (15-min cooldown).
- AI Trade Coach — click the 💡 button on any closed trade to get a 2-sentence explanation.
- AI Symbol Suggester — click “Suggest Symbols” in Settings to get 3 new symbols based on your trading history.
- AI Weekly Digest — opt-in via Settings → Elite AI. When enabled, sends every Monday 9am via Telegram + dashboard widget.
- Manual BUY/SELL Pre-flight — AI verdict appears automatically when you click a BUY/SELL button (no separate enable needed).
All AI calls share your monthly AI Budget Cap (Settings → Elite AI → AI Monthly Budget Cap). Auto-disabled at 100% spend.
.env. Changes take effect on the next trade cycle.What it does
Before every BUY, your AI provider reviews: signal confidence, ML score, Fear & Greed, VIX, FOMC proximity, sentiment, and macro. It approves, blocks, or adjusts confidence based on context a rule-based system would miss.
Your AI provider reads live market data every hour and scores overall market sentiment (-1.0 to +1.0). This replaces keyword matching with genuine language understanding — "Fed pause feared" vs "Fed pause expected" get opposite scores correctly.
The bot auto-scans all Binance pairs in your account's currency (USDT or USDC) every 24 hours and picks the top 10 by momentum + volume, replacing your fixed symbol list automatically.
Real example decisions
⛔ BLOCK — ML=0.61, regime=NEUTRAL, F&G=84 (Extreme Greed), FOMC in 2 days → Too risky near Fed event
~ ADJUST — ML=0.68 → 0.74 (+0.06), F&G=22, regime=BULL → Extreme fear boosted confidence
Setup
Choose ONE provider and get an API key. Only one provider is active at a time — configure it in Dashboard → Settings → AI Commentary.
console.anthropic.com → API Keys → Create Key. Set AI Commentary Provider (
AI_PROVIDER) to anthropic and add Anthropic API Key (ANTHROPIC_API_KEY) in Settings. Default model: claude-haiku-4-5-20251001 (fast, $1/$5 per 1M). Override with Anthropic Model (ANTHROPIC_MODEL) for Sonnet/Opus. Best reasoning quality for trading signals. Pro & Eliteplatform.openai.com → API keys → Create. Set AI Commentary Provider (
AI_PROVIDER) to openai and add OpenAI API Key (OPENAI_API_KEY) in Settings. Default model: gpt-4o-mini (cheapest, $0.15/$0.60 per 1M). Selectable via OpenAI Model (OPENAI_MODEL): gpt-4o, gpt-4-turbo. Eliteaistudio.google.com → Get API key. Set AI Commentary Provider (
AI_PROVIDER) to gemini and add Gemini API Key (GEMINI_API_KEY) in Settings. Default model: gemini-2.5-flash (~$0.30/$2.50 per 1M). Override with Gemini Model (GEMINI_MODEL) for other Gemini models. Eliteplatform.deepseek.com → API Keys → Create Key. Set AI Commentary Provider (
AI_PROVIDER) to deepseek and add DeepSeek API Key (DEEPSEEK_API_KEY) in Settings. Default model: deepseek-v4-flash (cheapest, $0.14/$0.28 per 1M). Override DeepSeek Model (DEEPSEEK_MODEL) to deepseek-v4-pro for stronger reasoning. Eliteapi.xiaomimimo.com → Create an API key. Set AI Commentary Provider (
AI_PROVIDER) to mimo and add Xiaomi MiMo API Key (MIMO_API_KEY) in Settings. Default model: mimo-v2.5-pro ($0.435/$0.87 per 1M). Override Xiaomi MiMo Model (MIMO_MODEL) to mimo-v2.5 for the base tier ($0.14/$0.28). EliteAny OpenAI-compatible endpoint — OpenRouter, Together AI, Fireworks, Azure OpenAI, or a self-hosted vLLM/Ollama box. Set AI Commentary Provider (
AI_PROVIDER) to custom with Custom Endpoint Base URL (AI_BASE_URL), Custom Model ID (AI_MODEL), and Custom Endpoint API Key (AI_API_KEY). HTTPS only (localhost exempt). Use Test Connection before saving. See setup below. EliteAny endpoint implementing the OpenAI Chat Completions API (a de-facto standard — not OpenAI itself): OpenRouter, Together AI, Fireworks, Azure OpenAI, or a self-hosted vLLM/Ollama box. Set AI Commentary Provider (
AI_PROVIDER) to custom and configure Custom Endpoint Base URL (AI_BASE_URL), Custom Model ID (AI_MODEL), and Custom Endpoint API Key (AI_API_KEY) in Settings → Elite AI.
HTTPS public endpoints only (HTTP permitted only for localhost). Internal/private addresses are rejected. Use the Test Connection button before saving — Save is gated until the test passes.
Local Ollama: set Base URL
http://localhost:11434/v1, get the model name from ollama list (e.g. llama3.1), and use any placeholder API key (Ollama ignores it). The bot and Ollama must be on the same machine for localhost — a remote model needs a tunnel that provides HTTPS.
| Provider | Model | Input $/1M | Output $/1M | Est. monthly |
|---|---|---|---|---|
| Anthropic Claude | claude-haiku-4-5 | $1.00 | $5.00 | ~$1.50 |
| claude-sonnet-4-5 | $3.00 | $15.00 | ~$4.50 | |
| claude-opus-4-5 | $5.00 | $25.00 | ~$7.50 | |
| OpenAI ChatGPT | gpt-4o-mini | $0.15 | $0.60 | ~$0.20 |
| gpt-4o | $2.50 | $10.00 | ~$3.50 | |
| gpt-4-turbo | $10.00 | $30.00 | ~$13.00 | |
| Google Gemini | gemini-1.5-flash | $0.075 | $0.30 | ~$0.10 |
| gemini-1.5-pro | $1.25 | $5.00 | ~$1.75 | |
| gemini-2.5-flash | free* | free* | free* | |
| DeepSeek | deepseek-v4-flash | $0.14 | $0.28 | ~$0.50 |
| deepseek-v4-pro | $0.44 | $0.87 | ~$1.80 | |
| Xiaomi MiMo | mimo-v2.5-pro | $0.44 | $0.87 | ~$1.80 |
| mimo-v2.5 | $0.14 | $0.28 | ~$0.50 | |
| Custom endpoint | any OpenAI-compatible | varies — check your provider | ||
Rates as of June 2026 — confirm at provider; prices change. Cache hits bill far lower. Based on ~600 input + 80 output tokens per call, ~1,500 calls/month. You supply your own API key and pay the provider directly. Pro tier: Anthropic only. Elite: all providers + custom. Rates as of June 2026 — confirm at provider; prices change. Cache hits bill far lower.
💡 Recommendation: Start with the cheapest tier. Set AI Monthly Budget Cap (USD) (AI_MONTHLY_BUDGET_USD, registered default 10.0, group Elite AI) to 5 in Settings until you understand your actual usage pattern.
Paste your API key directly into Dashboard → ⚙ Bot Config tab (Elite AI group) — for example, Anthropic API Key (ANTHROPIC_API_KEY), OpenAI API Key (OPENAI_API_KEY), or Gemini API Key (GEMINI_API_KEY), depending on your chosen provider. No SSH or restart needed.
Then turn the feature on and tune it in the same Bot Config tab:
- AI Commentary Enabled (
ELITE_AI_ENABLED, default on) - AI Commentary Cooldown (
ELITE_AI_COOLDOWN, default 300 seconds) — minimum time between AI calls per symbol
Set AI Commentary Provider (AI_PROVIDER, Bot Config → Elite AI group) to one of: anthropic (Pro & Elite) | openai | gemini | deepseek | mimo | custom. Then set the matching key (all keys below are in the Bot Config → Elite AI group unless noted):
AI Commentary Provider (AI_PROVIDER) |
Key env | Model env (optional override) | Default model |
|---|---|---|---|
| anthropic | Anthropic API Key (ANTHROPIC_API_KEY) | AI Commentary Model (legacy) (ELITE_AI_MODEL) or Anthropic Model (ANTHROPIC_MODEL) — both work | claude-haiku-4-5-20251001 |
| openai | OpenAI API Key (OPENAI_API_KEY) | OpenAI Model (OPENAI_MODEL) | gpt-4o-mini |
| gemini | Gemini API Key (GEMINI_API_KEY) | Gemini Model (GEMINI_MODEL) | gemini-2.5-flash |
| deepseek | DeepSeek API Key (DEEPSEEK_API_KEY) | DeepSeek Model (DEEPSEEK_MODEL) | deepseek-v4-flash (or deepseek-v4-pro) |
| mimo | Xiaomi MiMo API Key (MIMO_API_KEY) | Xiaomi MiMo Model (MIMO_MODEL) | mimo-v2.5-pro (or mimo-v2.5) |
| custom | Custom Endpoint API Key (AI_API_KEY) | Custom Model ID (AI_MODEL) + Custom Endpoint Base URL (AI_BASE_URL) | any OpenAI-compatible endpoint |
AI providers operate from different jurisdictions; regardless of provider, only a sanitized market-context prompt is sent — no API keys, balances, trade history, or personal data. See the Privacy Policy for details.
The AI gate and AI sentiment synthesis both activate automatically on restart. You'll see [ELITE-AI] BTCUSDT — APPROVE | adj=+0.00 in the logs when it runs.
How it fits into the signal chain
→ ✓ Regime gate (EMA + ADX)
→ ✓ FOMC blackout check
→ ✓ Macro gate (FRED)
→ ✓ Sentiment gate (F&G + news + AI synthesis on Elite)
→ ✓ Signal engine (EMA + RSI + MACD + BB)
→ ✓ ML gate (XGBoost, 18 features)
→ ✓ AI Commentary ← Pro (Anthropic) and Elite (all providers)
→ ✓ Kelly sizing → BUY executed
Directional Strategy
In plain terms: Imagine you have one fruit basket that holds exactly one apple. Directional trading means: buy the apple when prices are rising, sell when prices fall. You can only hold one apple at a time — to buy another, you must first sell the one you have. The bot uses ML signals + technical indicators to decide WHEN to swap apples. Endgame: Each apple is sold individually when the price target hits (or stop-loss triggers), then the bot looks for the next opportunity to buy.
Other strategies you may consider: DCA Bot — buy steadily over time. Grid Bot — profit from sideways markets.
Directional strategy uses ML signals and technical indicators to time entry and exit. It is the original ApexQuant strategy. Set Primary Strategy (PRIMARY_STRATEGY) to Directional via the Bot Config tab.
| Variable | Default | What it does |
|---|---|---|
Signal Threshold (SIGNAL_THRESHOLD) — group Strategy | 0.48 | Minimum signal score to open a trade. Lower = more trades, higher = fewer but better quality. Range: 0.45–0.58. |
Kelly Multiplier (KELLY_MULT) — group Kelly | 0.5 | Position sizing aggressiveness. 0.25 = very safe, 0.5 = balanced, 1.0 = full Kelly (risky). Start at 0.25. |
Kelly Maximum Position (KELLY_MAX_FRAC) — group Kelly | 0.10 | Maximum % of balance per trade. 10% default. Never set above 0.15 until you have 50+ live trades of history. |
Hard Stop ATR Multiplier (HARD_STOP_ATR) — group Risk | 1.5 | Stop-loss = entry price minus this many ATR widths. 1.5 is balanced. Increase to 2.0 for wider stops in volatile markets. |
Partial Take-Profit ATR (PARTIAL_TP_ATR) — group Risk | 4.0 | First take-profit target = entry + this many ATR. Higher = more ambitious target. 3.0–5.0 is reasonable range. |
Order Cooldown (ORDER_COOLDOWN) — group Trading Mechanics | 60 | Seconds between entries on same symbol. 60 = 1 min. Prevents overtrading in choppy conditions. |
KELLY_MULT) and Kelly Maximum Position (KELLY_MAX_FRAC) scale your position size directly — higher values mean larger positions and larger swings, both gains and losses. Widening Hard Stop ATR Multiplier (HARD_STOP_ATR) increases the loss the bot will accept on a single trade before exiting. Primary Strategy (PRIMARY_STRATEGY) changes which engine trades your account entirely — switching away from Directional stops this strategy's own open-position handling and hands control to whichever strategy you switch to.
AI Bundle Elite
Beyond AI Commentary on signals, ApexQuant Elite tier includes additional AI features. These use your configured AI provider key (any supported provider; configured in Settings).
- AI Weekly Digest (Mon 9am) (
AI_BUNDLE_DIGEST_ENABLED, Elite, default off) — every Monday 9am, a summary of last week's trades is sent to Telegram and shown in the dashboard Performance tab (Daily view). Best/worst trade, win rate, P&L, suggestions. Cached 7 days. On-demand via/digest. Toggle in Bot Config → Elite AI group. - AI Trade Coach (post-trade) (
AI_BUNDLE_COACH_ENABLED, Elite, default on) — after every closed trade, a 💡 button appears in the trade log. Click for a 2-sentence AI explanation of why the trade played out the way it did. Cached forever per trade. - AI Symbol Suggester (
AI_BUNDLE_SUGGESTER_ENABLED, Elite, default on) — on-demand button in Settings → AI Commentary group. AI analyzes last 90 days of trades + current portfolio, suggests 3 new symbols with reasoning. Cached 24h. - AI Strategy Compare Narration (Elite) (
AI_BUNDLE_NARRATE_ENABLED, Elite, default on) — when comparing two backtests, AI narrates the trade-off in plain English.
Estimated cost: ~$0.05–$0.10/month at typical usage. Each feature can be toggled individually. All AI Bundle features are informational only — they never influence trade decisions.
DCA Bot
In plain terms: DCA is like buying one apple every week regardless of price — sometimes the apple costs $1, sometimes $2. Over time, your basket fills up with apples bought at different prices, and the average cost-per-apple smooths out. You don't time the market; you let time do the work. Endgame: When the total basket value reaches your profit target (e.g. +5%), the bot sells all apples at once and starts a fresh basket. (Alternative: set “none” mode for pure accumulation — you decide when to sell.)
How often does DCA buy?
By default, ApexQuant's DCA strategy buys once per week per symbol
(Time Interval (hours) (DCA_INTERVAL_HOURS) = 168). This is the recommended cadence — frequent
enough to average down through volatility, infrequent enough that fees don't erode returns.
If your dashboard shows the last DCA buy was yesterday, the next buy for that symbol
is scheduled approximately 7 days from then. To buy more frequently, lower
Time Interval (hours) (DCA_INTERVAL_HOURS) in Settings → DCA. To buy on price drops instead
of a fixed schedule, switch DCA Mode (DCA_MODE) from time to drop.
Other strategies: Directional — time the market with ML. Smart DCA — Buy The Dip mode. Grid Bot — profit from sideways markets.
How exits work in DCA
DCA is fundamentally different from Directional in how positions are closed:
- Auto-managed basket: Every buy (whether automated by the bot or manual via dashboard/Telegram) goes into the same DCA basket. The basket has ONE exit target — when total ROI hits Take-Profit Target (%) (
DCA_TP_PCT) (default 5%), the entire basket sells at once. - You don't control individual exits: Unlike Directional where each buy can have its own SL/TP, DCA treats all legs as one position. The "exit mode" selector in the manual buy form is hidden when DCA is active because it has no effect.
- To close the basket early: Use the SELL button on the dashboard, or
/dca closevia Telegram. Either way, all positions in the basket sell at market price and the basket resets. - Three exit modes (set in DCA settings):
tp(default): basket sells when ROI hits Take-Profit Target (%) (DCA_TP_PCT)trail: basket arms a trailing stop after Trail Arm Threshold (%) (DCA_TRAIL_ARM_PCT), exits on retracementnone: basket never auto-sells; you decide when to close
DCA is an accumulation strategy. Positions do not auto-sell on losses — only on take-profit (TP) above your average entry, or trailing stops above your peak. If price falls 20%, your basket stays open and the bot may add more legs (if budget allows).
This is intentional. DCA assumes you have a long-term thesis and are willing to hold through drawdowns. If you want automatic stop-loss protection on every trade, use Directional strategy instead.
Per-strategy kill-switch behavior: Every strategy uses the same measure: your cash plus the cost of the coin you hold. Unrealized basket drawdown (price falling on open positions) does not trip a halt — the bot keeps averaging in as designed. Realised losses and money that really leaves the account do count.
Unrealized basket drawdown is surfaced as warnings in the dashboard budget cell: 🟡 >20%, 🟠 >35%, 🔴 >50% — informational only, never a halt. The daily limit resets at your local midnight.
Because DCA does not halt on unrealized drawdown, your real risk control is exposure. Set these in Settings → DCA:
DCA Budget per Symbol (USDT or USDC)— basket stops averaging in once this amount is spent. Total DCA exposure ≈ budget × active symbols.DCA Max Averaging Legs— maximum averaging buys per basket. Works alongside budget to cap deployment.- Trading Capital (
CAPITAL_MODE, defaultall, group Capital) set tofixed+ Fixed Capital Amount (USDT or USDC) (TRADING_CAPITAL_USDT, default 0.0 = all available, group Capital) — hard account-wide ceiling (recommended). Prevents any strategy deploying beyond the set amount. Set in Settings → Capital. Raising this directly increases how much of your account can be deployed at once.
Strategy switching requires no open positions. Close all positions first (Manual /sell). Switching while a DCA basket is open is blocked — one strategy manages one symbol at a time.
Dollar-Cost Averaging is a rule-based accumulation strategy. The bot buys an asset at regular intervals or when the price drops by a set percentage — without attempting to time the market. You define the parameters; the bot executes them mechanically.
Two Modes
Time mode (DCA_MODE=time)
Buys a fixed amount (in your account's currency) at a fixed interval (daily, weekly, monthly — you decide). Suitable for long-term accumulation of assets you believe will appreciate over months or years. No dip-detection is involved.
Drop mode (DCA_MODE=drop)
Opens an initial position, then buys more each time the price falls by your configured percentage from the last buy (Drop Step (%) (DCA_DROP_STEP_PCT)). Reduces your average cost per unit. Suitable for catching dips on assets you expect to recover. Stops adding legs after Max Buy Legs (DCA_MAX_LEGS) is reached or budget is exhausted.
Three Exit Modes
None (DCA_EXIT=none)
Pure accumulation. The bot never sells automatically. You close the position manually via /dca close or from the dashboard.
Take-profit (DCA_EXIT=tp)
Sells the entire position when your average-entry ROI (after fees) reaches Take-Profit Target (%) (DCA_TP_PCT). After selling, the budget resets and a new DCA cycle may begin.
Trailing TP (DCA_EXIT=trail)
Arms when ROI reaches Trail Arm Threshold (%) (DCA_TRAIL_ARM_PCT). Tracks the peak price from that point forward. Sells when price retraces from the peak by Trail Distance (%) (DCA_TRAIL_DISTANCE_PCT)%. Locks in gains as the asset runs up; exits on the pullback.
Trailing Stop Config
Switch DCA Exit Mode (DCA_EXIT) to trail for trending markets where you want to let winners run:
- Arm threshold (
DCA_TRAIL_ARM_PCT, default 3%) — trail activates only after basket reaches this ROI. Below this, position stays open normally. - Trail distance (
DCA_TRAIL_DISTANCE_PCT, default 1.5%) — maximum retracement from peak before exit fires.
Example: armed at +3%, peak hits +10%, price retraces to +8.5% (1.5% from peak) → sell. Locks in 8.5% gain instead of selling at the original 5% TP. When to use: BULL regime, trending markets. When not to use: choppy ranging markets — frequent retraces will trigger early exits.
Enabling DCA
Set Primary Strategy to DCA via the Bot Config tab. DCA is a primary strategy — it replaces Directional as the engine's main strategy. Harvest can still run concurrently.
Configure these in the Bot Config tab (group DCA unless noted). Values below are a reasonable starting point:
| GUI Label (key) | Value used below | What it does |
|---|---|---|
Primary Strategy (PRIMARY_STRATEGY) — group Features & Gates | dca | Switches the engine's main strategy to DCA. |
DCA Mode (DCA_MODE) | time | Time-based (fixed intervals) vs. Price-drop (buy on dips). Only applies when Primary Strategy is DCA. |
DCA Exit Mode (DCA_EXIT) | tp | Accumulate only (manual exit), Take-Profit %, or Trailing Stop. |
Take-Profit Target (%) (DCA_TP_PCT) | 5.0 | TP mode only: sell when ROI (after fees) reaches this %. Registered default matches this value. |
Budget per Symbol (USDT or USDC) (DCA_BUDGET_USDT) | 500 | The most to spend on this coin before stopping new buys. Budget resets after sell. Registered default matches this value. Restart to apply. |
Per-Buy Size (USDT or USDC) (DCA_BUY_SIZE_USDT) | 50 | Amount per individual buy order. It cannot be below the bot's minimum order size (11 by default). Registered default matches this value. |
Time Interval (hours) (DCA_INTERVAL_HOURS) | 168 | Time mode only: hours between buys (168 = weekly). |
Amounts are in your account's currency (USDT or USDC).
If using Drop mode instead of Time mode: Drop Step (%) (DCA_DROP_STEP_PCT, default 5.0) and Max Buy Legs (DCA_MAX_LEGS, default 10) — restart to apply. If using Trailing Stop instead of Take-Profit: Trail Arm Threshold (%) (DCA_TRAIL_ARM_PCT, default 3.0) and Trail Distance (%) (DCA_TRAIL_DISTANCE_PCT, default 1.5) — both only shown in the GUI once DCA Exit Mode is set to Trailing Stop.
DCA_MAX_LEGS) caps how many averaging buys a basket can add per symbol — raising it increases how much capital can be committed to one losing position before the cap stops new buys. Take-Profit Target (%) (DCA_TP_PCT) directly sets how much profit you're aiming to lock in per exit — lowering it exits sooner for smaller, more frequent gains; raising it holds out for more but risks giving profit back on a reversal.
Telegram Commands
/dca status— all open positions: leg count, avg entry, current ROI, budget used/dca pause— stop new buys (existing positions still exit via TP/trail)/dca resume— restart buys after pause/dca buy BTC— force a manual buy outside the normal schedule (still checks budget)/dca close BTC— close the DCA position immediately at market/dca reset BTC— reset budget for a symbol (allows a new DCA cycle)
State Persistence
DCA position state (legs, avg entry, budget used, last buy time) is saved to apexquant.db after every buy and sell. If the service restarts, it resumes exactly where it left off. No manual recovery needed.
Smart DCA: Buy The Dip Pro · Elite
In plain terms: Classic DCA buys on a fixed schedule regardless of market state. Smart DCA tilts your buys based on a Fear Score from 5 macro and sentiment signals — bigger when the market shows fear, smaller (or skipped) when greed peaks. Result: capital protection in volatile markets — your buys lean into dips and step aside during euphoria.
Other strategies: Directional — time the market with ML. DCA Bot — classic DCA. Grid Bot — profit from sideways markets.
The 5 signals
| Signal | Weight | Source |
|---|---|---|
| Fear & Greed Index | 35% | alternative.me |
| FRED Macro Health | 25% | St. Louis Fed (FRED API) |
| News Sentiment | 20% | CoinDesk + Binance L/S ratio |
| Market Regime | 10% | Bitcoin BULL / NEUTRAL / BEAR / CRISIS |
| FOMC Week | 10% | Federal Reserve schedule (auto-fetched monthly) |
Market Signals — 200-Week Moving Average
The 200-week moving average is a long-term cycle gauge. ApexQuant compares the current price to its 200-week MA (a simple ratio) to judge whether price is sitting below historical support or stretched well above it. This biases how cautiously or confidently the bot sizes new positions — it never forces a buy or a sell, and it makes no promise about outcomes. It runs on Binance weekly candles only (no external paid data) and is available on every tier. It affects DCA and directional sizing; the Grid strategy uses fixed per-level allocation and is unaffected.
How the zones work (ratio = price ÷ 200-week MA):
- Below Deep Value (default 0.85): price is deep under its long-term average — strongest buy-bias (sizes up).
- Between Deep Value and Support (0.85–1.0): mild buy-bias.
- Between Support and Extended: neutral.
- At or above Extended (default 2.4): price is stretched well above its long-term average — caution, reduced buy-bias (sizes down).
The sizing adjustment is bounded (a nudge of roughly ±15–30%, not a swing), and falls back to neutral (no effect) when there is not enough weekly history yet or data cannot be fetched.
Recommended settings (defaults — load optimally out of the box):
| Setting | Recommended | What it does |
|---|---|---|
| 200-Week MA Signal | On | Master toggle. On by default. |
| Deep Value threshold | 0.85 | Ratio below this = deep-value zone (strongest buy-bias). |
| Support threshold | 1.0 | Ratio below this but above Deep Value = mild buy-bias. |
| Extended threshold | 2.4 | Ratio at/above this = extended zone (caution, reduce buy-bias). |
| Refresh interval (hours) | 12 | How often weekly candles are re-fetched. 12h is ample. |
Thresholds must satisfy Deep Value < Support < Extended — the dashboard enforces this and will reject an out-of-order save.
Which strategies use the market signals?
ApexQuant's signal pipeline is not bot-wide — each strategy uses it differently. Here's an at-a-glance breakdown:
| Layer | Directional | DCA | Grid | TradingView (coming soon) |
|---|---|---|---|---|
| Entry timing source | Internal 8-factor signal engine + ML | Fixed schedule (interval / dip) | Fixed price levels in your range | Your TradingView alert (internal signals off) |
| Market-bias signals — regime, Fear & Greed, macro + FOMC, funding, 200-week MA | ✓ (entry + sizing) | ✓ (Smart-DCA sizing) | ✗ — not used | ✓ — applied as risk gates |
| ML gate | ✓ | ✗ | ✗ | ✓ |
| AI Commentary (informational, pre-BUY; Pro/Elite) | ✓ | ✓ | ✗ | — * |
| Risk rails — kill-switch halt, daily drawdown limit, API-outage block, price > 0 | ✓ | ✓ | ✓ | ✓ |
Grid is a rule-based range trader — it deliberately ignores the market-signal pipeline (it's meant to buy dips and sell rips inside your range regardless of trend or sentiment). It still obeys the risk rails: a kill-switch halt or a Binance API outage stops it immediately. The signal pipeline shapes Directional and DCA entries and sizing. TradingView (coming soon) supplies its own entry but still passes the risk gates.
* AI Commentary availability on the TradingView path (coming soon) is configurable; see the TradingView section.
The 4 modes
- Pure — no scaling. Identical to Classic DCA — used as a comparison baseline.
- Conservative — 0.5×–1.5× scaling, no skips.
- Balanced (default) — 0.5×–2.0× scaling, skips buys when greed is high.
- Aggressive — 0.5×–3.0× scaling, larger swings, skips buys when greed is high.
Backtest results
BTCUSDT, daily buys, 2024-05 → 2026-05, $50 per buy:
| Mode | Invested | Final Value | ROI |
|---|---|---|---|
| Classic DCA (pure) | $37,500 | $35,242 | -6.02% |
| Conservative | $27,092 | $26,101 | -3.66% |
| Balanced (default) | $15,672 | $16,015 | +2.19% |
| Aggressive | $21,370 | $21,871 | +2.34% |
Balanced/Aggressive modes deployed less capital (skipped greed-zone buys per Fear Score), which protected against the BTC drawdown over this period. Smart DCA’s edge is capital protection in volatile markets, not raw alpha.
⚠ Disclaimer: Backtested on 22 May 2026 using historical BTCUSDT hourly klines from Binance + alternative.me Fear & Greed Index. Backtest assumes ideal fill execution at hourly close prices with no slippage. Past performance is not indicative of future results. Actual live trading results will vary due to spread, slippage, and Binance fee structure. Backtest results are illustrative only and do not constitute investment advice.
How to enable
- Dashboard → Settings → DCA section → toggle Buy The Dip (Smart DCA) on (default ON for Pro/Elite).
- Pick your mode from the dropdown (default: Balanced).
- Watch the Fear Score card on the Live tab — updates every 15 seconds.
Grid Bot
Pro · EliteIn plain terms: Grid trading is like running a fruit stall. You have multiple baskets at fixed price levels: buy an apple at $1, sell at $2, buy again at $1.50, sell at $2.50, and repeat. The bot profits from price oscillating within a range, not from picking direction. Best for sideways markets — bad for strong trends in either direction (you'd run out of selling-baskets in a rally, or buying-baskets in a crash). Endgame: When price exits your set range, you choose what happens — close (stand down and hand inventory to stop-loss/take-profit protection — not force-sold; the default), pause (stop new orders, keep existing apples, auto-resumes when price returns via Grid Auto-Resume (GRID_AUTO_RESUME)), or hold (do nothing and wait for price to come back). There's also a fourth option that doesn't stop the stall at all: Smart Grid, which grows the range instead of exiting it — see the Smart Grid subsection below.
Other strategies: Directional — time the market with ML. DCA Bot — buy steadily over time.
Grid trading divides a price range into evenly spaced levels and automatically places buy orders below the current price. Each time a buy fills, a sell order is placed one level higher — capturing the spacing as profit. Each time a sell fills, a new buy is placed one level lower, ready to repeat the cycle. The strategy earns small, frequent profits as long as the price oscillates within the range.
A level's buy may fill in a few pieces rather than all at once — they add up to the level's full amount, so seeing more than one row for the same level in your trade history is normal.
Grid bot is rule-based. It does not consult AI Commentary, ML signals, or regime detection. It simply places and replaces limit orders at fixed price levels. This makes it predictable, but entirely dependent on the market staying range-bound.
It does, however, still obey the safety rails every strategy shares: if the kill-switch halts the bot or Binance goes unreachable, the grid stops placing and filling orders until conditions clear.
Good conditions: Sideways, choppy, or ranging markets where price repeatedly bounces between support and resistance. Coins with high intraday volatility but no clear directional trend. Post-breakout consolidations where a new range is forming.
Avoid in: Strong trending markets (bull or bear). A breakout above the upper bound leaves open buy orders with no fills. A breakdown below the lower bound fills all buy levels, accumulating an inventory that continues to lose value. Your range bounds and Range Break Action (GRID_BREAK_ACTION) limit this downside but do not eliminate it.
ApexQuant supports concurrent grids across multiple symbols. Each symbol gets an independent grid with its own price levels, inventory, and PnL — all running in parallel under the same bot instance.
Tier limits:
- Trial — grid on 1 symbol, TESTNET / PAPER only
- Starter — Grid Bot not included
- Pro — grid on 1 symbol, live (mainnet) trading
- Elite — grids on up to 5 symbols, live trading
How allocation works: Total Allocation (USDT or USDC) (GRID_TOTAL_ALLOCATION_USDT) is split equally across every coin in Grid Coins (GRID_SYMBOLS). Example: Total Allocation = 1000 with Grid Coins = BTC, ETH, SOL allocates $333.33 per grid.
How to configure: set Grid Coins (GRID_SYMBOLS) in the Bot Config tab (Grid Bot group) to a comma-separated list of coins, e.g. BTC, ETH. Restart the bot. Each grid initialises independently — if one symbol fails to start (capital check, range invalid), other symbols continue.
How to control individual grids: the dashboard Live tab shows one card per active grid with per-symbol Pause / Resume / Stop & Liquidate / Reset & Rebuild buttons. Telegram commands accept an optional symbol argument: /grid pause BTC targets one grid, /grid pause with no argument targets all.
If you exceed your tier limit: the bot logs a warning and truncates the list to the tier maximum (e.g. Pro user with BTC, ETH in Grid Coins (GRID_SYMBOLS) will only run BTC). Upgrade to Elite to run grids on up to 5 symbols.
| Variable | Default | What it does |
|---|---|---|
Primary Strategy (PRIMARY_STRATEGY) — group Features & Gates | dca | Set to grid to activate the Grid Bot. |
Grid Lower Price (USDT or USDC) (GRID_LOWER_PRICE) — group Grid | 0 | Lower bound of the grid, in your account's currency. e.g. 75000. Leave at 0 if using auto-range. |
Grid Upper Price (USDT or USDC) (GRID_UPPER_PRICE) — group Grid | 0 | Upper bound of the grid, in your account's currency. e.g. 80000. Leave at 0 if using auto-range. Must be greater than the lower bound. |
Auto-Range % (from current price) (GRID_AUTO_RANGE_PCT) — group Grid | 5.0 | Recommended default — builds the grid ±5% around the live price at startup, so it works on any symbol with no manual range needed. Overrides the manual bounds above. Set to 0 only if you want to enter Grid Lower/Upper Price yourself. |
Grid Levels (GRID_LEVELS) — group Grid | 10 | Number of grid levels. Range 5–50. More levels = smaller profit per round-trip but more frequent fills. |
Grid Spacing (GRID_SPACING) — group Grid | geometric | geometric (equal % gaps) or arithmetic (equal price gaps). Geometric gives uniform profit % at every level. |
Total Allocation (USDT or USDC) (GRID_TOTAL_ALLOCATION_USDT) — group Grid | 200 | Total amount committed across all levels. e.g. 200 = $200 split evenly. |
Take Profit (USDT or USDC) (GRID_TAKE_PROFIT_USDT) — group Grid | 0 | Optional: halt when cumulative realised profit reaches this amount. e.g. 50 = stop after $50 profit. Leave at 0 to run indefinitely. |
Max Open Orders (GRID_MAX_OPEN_ORDERS) — group Grid | 30 | Safety cap on total open Binance orders from this grid. Should be ≤ levels/2 for lazy placement mode. |
Range Break Action (GRID_BREAK_ACTION) — group Grid | close | What to do when price exits the range (only used when Smart Grid is OFF — see Smart Grid (GRID_SMART_MODE) below). Default: close — cancel orders and hand inventory to stop-loss/take-profit protection (NOT force-sold). pause: cancel orders, keep inventory; auto-resumes when price returns (see Grid Auto-Resume (GRID_AUTO_RESUME)). hold: do nothing, orders remain. trail_up: on an upside break, slide the range up (see Grid Trail Shift (%) (GRID_TRAIL_SHIFT_PCT)). Recommended keep-trading option is Smart Grid (see the Smart Grid subsection) — turn it on to extend instead of stop. |
Grid Auto-Resume (GRID_AUTO_RESUME) — group Grid | true | When GRID_BREAK_ACTION=pause, automatically re-activate the grid once price returns inside the configured range (with a small 0.1% margin to prevent boundary flapping). Set to false to require a manual /grid resume. Skipped while the kill-switch is halted or Binance is unreachable at the moment price re-enters. |
Grid Trail Shift (%) (GRID_TRAIL_SHIFT_PCT) — group Grid | 50 | Only when GRID_BREAK_ACTION=trail_up: when price breaks above range_high, the range shifts up by this % of the original width (buy orders below the new floor are cancelled; sell orders untouched). Example: range $80k–$90k breaks above $90k, shift 50% → new range $85k–$95k. |
Grid Trail Max Shifts (GRID_TRAIL_MAX_SHIFTS) — group Grid | 5 | Max trail-ups before the grid pauses — prevents infinite chasing in strong uptrends. Note: downside breaks (price < range_low) always pause the grid regardless of trail_up. Best for trending uptrends; in ranging markets use pause instead. |
Grid Coins (GRID_SYMBOLS) — group Grid | BTC | Comma-separated coins for concurrent grids (e.g. BTC, ETH, SOL: just the coin). Pro tier: 1 coin max. Elite: up to 5. Total Allocation (USDT or USDC) (GRID_TOTAL_ALLOCATION_USDT) is split equally across all symbols. Restart required after any change. |
Smart Grid (GRID_SMART_MODE) — group Grid | false | Master switch for Smart Grid. When on, growing the boundary replaces the Range Break Action choices above entirely for range-break handling — see the Smart Grid subsection below. Off by default. |
└ Extend Upward (GRID_AUTO_EXTEND_UPPER) — group Grid | true | Shown when Smart Grid is on. On an upside break, add sell levels above the range. Free — empty sell-slots, no capital spent. |
└ Extend Downward (buy dips, within budget) (GRID_AUTO_EXTEND_LOWER) — group Grid | false | Shown when Smart Grid is on. On a downside break, add buy levels below the range, funded only from this grid's own unused budget — never fresh funds. When it can't add another buy level safely — either the budget is spent, each level would get too thin, or the grid has grown to its size limit — it simply holds what it has and waits. It never sells at a loss and never freezes; to keep extending, recenter or add capital. |
Max Upward Extensions / session (GRID_EXTEND_MAX_UPPER) — group Grid | 5 | Max automatic upward extensions per session (flap guard). Only relevant when Smart Grid + Extend Upward are on. |
Max Downward Extensions / session (GRID_EXTEND_MAX_LOWER) — group Grid | 3 | Max automatic downward extensions per session (flap guard). Only relevant when Smart Grid + Extend Downward are on. |
Auto-Recenter when grid can't extend (GRID_AUTO_RECENTER_ON_IDLE) — group Grid | false | Shown when Smart Grid is on. When price breaks a full grid-width past the range AND the grid is already at its maximum size, automatically recenter around the current price to keep trading — useful while you're away. Held coins, cost basis, profit, and settings are never touched; only the range moves (same as a manual Recenter, never a sale). A brief spike won't trigger it; it won't thrash in a choppy market and has a daily cap. Off by default. Pro tier. |
└ Auto-Recenter Direction (GRID_AUTO_RECENTER_DIRECTION) — group Grid | above_only | Shown when Smart Grid + Auto-Recenter are on. above_only (default, safe) — only auto-recenter on an upside break (the grid sold to cash on the way up; redeploying higher is low-risk). both — also auto-recenter on a downside break, deploying remaining cash into a falling price. Only change to both if you understand the risk. |
- Total Allocation (USDT or USDC) (
GRID_TOTAL_ALLOCATION_USDT, group Grid, default200.0) is a total across ALL your grid symbols, not per symbol. Running 5 grids at $5,000 each means setting this to $25,000 total, not $5,000 — the bot divides it by the number of active grids for you. Setting $5,000 while running 5 grids gives each grid only $1,000 — double-check the math before saving. - Grid Levels (
GRID_LEVELS, group Grid, default10) — changing the count re-lays the entire grid at the new spacing. A level count whose spacing would fall below break-even is refused at save time rather than applied — you'll see the exact reason if that happens.
Smart Grid — growing the stall instead of closing it. Normally, when the price leaves your grid's range, the stall has to stop: it either pauses (keeps your apples, waits), closes (hands your apples to the safety net), or holds. Smart Grid gives the stall a fourth choice — it grows. Instead of shutting when price runs off the edge, it builds new baskets at the edge that was breached and keeps trading.
Two ways it grows, depending on which way price broke:
- Price runs UP past your top basket → the stall adds new selling-baskets higher up. Your existing baskets don't move, nothing is cancelled — the stall just gets taller so it can keep selling into the rally. This costs nothing extra: the new baskets up top are empty sell-slots waiting for price, not orders you pay for now.
- Price falls BELOW your bottom basket → the stall adds new buying-baskets lower down, so you keep buying the dip. This spends money (each new buying-basket needs cash), so Smart Grid only uses this grid's own unspent budget — never money you didn't set aside for it. When it can't safely add another buying-basket — the budget's spent, OR each basket would get too small to be worth it, OR the stall has already grown to its size limit — it holds what it has and waits. It never sells your apples at a loss to keep going, and it never freezes. To keep buying lower, recenter the stall or add more trade capital.
Example. Say you set a grid on BTC with a range of $60,000 – $66,000 and $600 budget across 5 levels ($120 per basket).
- BTC rallies to $68,000 (above your $66,000 top). Without Smart Grid the stall would pause — your top sell would fill at $66,000 and then nothing, missing the run to $68,000. With Smart Grid (Extend Upward), the stall adds new selling-baskets above $66,000 — say up to $69,000 — so your apples keep selling into the rally instead of stopping at $66,000. Your bottom ($60,000) doesn't move; the range just stretches up to $60,000 – $69,000.
- BTC drops to $58,000 (below your $60,000 floor). With Smart Grid (Extend Downward), the stall adds new buying-baskets below $60,000 — say down to $57,000 — buying the dip with your grid's own spare budget. If all $600 is already deployed, the stall stops adding baskets, holds everything it bought, and waits for recovery. It never sells those dip-buys at a loss to "escape."
A stall only takes on what it can handle. Every basket the stall adds needs somewhere to sell later and enough money behind it to matter. So the stall grows only while there's room — while each basket stays a worthwhile size and the stall hasn't hit its size limit. Once it's full, it stops adding rather than cramming in baskets it can't properly work — like a full plane not boarding more passengers than it has seats. Nothing is sold, nothing is lost; the stall just tells you it's at capacity and waits, and you can recenter or add capital if you want it bigger.
Smart Grid (Extend) vs Trail Up — what's the difference? Both react to price running up, but they do opposite things to your stall:
- Smart Grid Extend = a bigger stall. The bottom stays pinned; new baskets are added on top. Think of stretching a rubber band: one end stays put, the other stretches. You keep every basket you had, plus new ones. Range $60k–$66k becomes $60k–$69k.
- Trail Up = the same stall, moved. The whole range slides upward — the top rises AND the bottom rises, and the lowest baskets are let go. Think of carrying a ladder upward: same number of rungs, just higher; the bottom rungs leave the ground. Range $60k–$66k becomes, say, $63k–$69k — you've given up the $60k–$63k baskets.
Use Extend to keep accumulating across the whole move (widen and hold everything). Use Trail Up to follow a strong one-way trend and stop holding the now-far-below levels. Smart Grid uses Extend. Trail Up remains available as a separate Range Break Action.
(Neither one "chases profit" — that's Smart TP's job, a separate feature that rides a single sell higher when price is spiking. Extend and Trail just decide where your grid's boundaries sit.)
When Smart Grid is on vs off: Turn Smart Grid on and it takes over what happens on a range break — you'll see Extend Upward (on by default, free) and Extend Downward (off by default, spends budget) options, and the older Range Break Action list is hidden. Turn it off and you're back to the classic choices (close / pause / hold / trail up). Smart Grid is off by default — a deliberate choice you switch on.
Auto-Recenter (optional, for unattended trends). Extend grows the stall while it can. But in a strong one-way move the stall eventually reaches its maximum size and price keeps going — leaving it parked out of range until you recenter it by hand. If you're away (asleep, offline), it just sits idle and misses the move. Turn on Auto-Recenter when the grid can't extend further (GRID_AUTO_RECENTER_ON_IDLE, off by default, Smart Grid only) and the bot does that recenter for you: when price breaks a full grid-width clear of the range AND the stall is already at its maximum size, it automatically recenters around the current price to keep trading. Your held coins, cost basis, profit, and settings are unchanged — only the range moves — it's the same Recenter you can run by hand, never a sale. A brief spike won't trigger it — it waits for a clear move — and it won't repeatedly recenter in a choppy market, with a daily safety cap. By default it only acts on an upside break (the stall has already sold to cash on the way up, so redeploying higher is low-risk); set GRID_AUTO_RECENTER_DIRECTION to both only if you also want it to recenter on a downside break, which deploys remaining cash into a falling price. Off by default — leave it off and the stall holds and waits for you, exactly as before. Auto-Recenter keeps the stall trading through a move; it does not make trending markets safe — grid bots still lose in a sustained adverse trend.
Keep-trading actions (never sell): Pause/Resume, Recenter, Extend Up, Extend Down. Wind-down actions: Drain (sells at profit only), Stop & Liquidate and Reset & Rebuild (sell inventory — these ask for your PIN). Housekeeping: Clear Stats.
| Button | What it does | Sells? |
|---|---|---|
| ⏸ Pause | Freezes the stall: stops placing and filling orders, but keeps every basket, your apples (inventory), and your stats. Resume picks up exactly where it left off. | No |
| 🫗 Drain | Cancels the buying-baskets but leaves the selling-baskets live. Your apples sell off at their profit levels as price reaches them, then the grid stops on its own. Use when you want to wind down gracefully at a profit rather than dump. (If the stall grew past its normal size, the extra baskets retire themselves this same way — selling at a profit as price reaches them — bringing the stall back to its set size without selling anything at a loss.) | Only at existing profit targets — never at a loss |
| 🎯 Recenter | Rebuilds the grid range around the CURRENT price. Cancels and replaces the open orders, but does NOT sell your holdings — any apples you're holding are carried over and given a new sell target where one is possible. Use when price has drifted well outside your range and you want the grid re-anchored to where the market actually is. | No |
| 🎯 Auto-Recenter (optional) | The same Recenter above, run automatically when price breaks a full grid-width clear of the range and the stall is already at its maximum size — for when you're away and the grid would otherwise sit idle. Off by default; turn on in Bot Config (Smart Grid section). Your coins, cost basis, and profit are never touched, only the range moves. | No |
| ⬆️ Extend Up | Adds new selling-baskets above your current top, as future sell targets. Costs nothing and places no orders now — they're empty slots waiting for price. Use to keep selling into a rally without rebuilding. The manual version of what Smart Grid does automatically. | No |
| ⬇️ Extend Down | Adds new buying-baskets below your current floor, funded ONLY from this grid's own unused budget — never fresh funds from your wallet. Use to keep buying a dip. When it can't add another safely — budget spent, baskets too thin, or at the size limit — it stops adding and holds. Recenter or add capital to grow further. The manual version of what Smart Grid does automatically. | No |
| ⛔ Stop & Liquidate | Cancels all open orders AND market-sells the entire grid inventory, then stops the grid completely (no rebuild). This is the deliberate "sell everything and stand down" button. | Yes — sells everything. Confirmation + PIN required. |
| 🔄 Reset & Rebuild | Cancels orders and market-sells the current inventory, then builds a fresh grid around the current price and resumes trading. Use to start clean at today's price. | Yes — sells the existing position first. Confirmation + PIN required. |
| Clear Stats | Zeroes the realized P&L, fees, and fill counts for a fresh performance-tracking start. Does NOT touch orders or inventory. | No |
All commands accept an optional symbol argument. Omit the symbol to target all active grids.
/grid status — all active grids: state, range, fills, open orders, realised PnL/grid status BTC — specific grid only/grid pause — cancel open orders on all grids; inventory kept (PIN-gated)/grid pause BTC — pause specific grid only/grid resume — re-place buy orders on all paused grids (PIN-gated)/grid resume ETH — resume specific grid only/grid stop [SYM] — cancel all orders + market-sell inventory, then STOP the grid — no rebuild (aliases: reset, close; PIN-gated)/grid rebuild [SYM] — same liquidation, then rebuild a fresh grid at the current price ± Auto-Range % (from current price) (GRID_AUTO_RANGE_PCT) (PIN-gated)/grid drain [SYM] — cancel buy orders, keep sell orders live; inventory sells only at its existing profit targets as price reaches them, then the grid stops on its own — never sells at a loss (PIN-gated)/grid recenter [SYM] — rebuild the grid range around the current price; cancels and replaces open orders but does NOT sell your holdings — inventory is carried over with a new sell target where possible (PIN-gated)/grid extend upper [SYM] — add new sell levels above the range; free, no orders placed, nothing sold (PIN-gated)/grid extend lower [SYM] — add new buy levels below the range, funded only from that grid's own unused budget (never fresh funds); holds when the budget is spent — sells nothing (PIN-gated)You set Grid Lower Price (USDT or USDC) (GRID_LOWER_PRICE) = 75000, Grid Upper Price (USDT or USDC) (GRID_UPPER_PRICE) = 80000, Grid Levels (GRID_LEVELS) = 10, Total Allocation (USDT or USDC) (GRID_TOTAL_ALLOCATION_USDT) = 200. The bot places 10 levels spaced $555 apart. Each level gets $20 (200 ÷ 10). Below current price ($77,500), levels at $75,000, $75,555, …, $77,222 get limit buy orders. When any buy fills, a sell is placed one level higher. A complete round-trip (buy at $77,222, sell at $77,778) earns approximately $0.73 gross — minus two maker fees (~$0.04 at 0.1%) = ~$0.69 net per cycle. With frequent oscillations, these accumulate. With a sustained drop below $75,000, all buy levels fill and realised losses begin.
Profit per round-trip ≈ grid spacing % minus fees on both sides. With 10 levels across a 6.7% range, each level is ~0.74% apart. After two maker fees at 0.1% each, net profit is ~0.54% per round-trip. This compounds through frequent fills in a ranging market — but in a trending market, inventory accumulates and losses are real. Grid bot does not beat the market; it harvests volatility within a defined range. If the asset trends strongly in either direction, it will underperform a simple hold or miss the trend entirely.
Grid state (open orders, filled levels, realised PnL) is saved to apexquant.db after every fill. On restart, the bot reconciles persisted state against live Binance orders and resumes from where it left off.
Use these Telegram commands to control a running grid:
/grid pause— Pauses the grid. Open orders are canceled and the bot holds the current inventory without placing new orders. Use/grid resumeto restart the grid from its current state. Useful when you want a temporary break without fully liquidating./grid drain— The graceful exit. Cancels only the resting buy orders, keeps the resting sell orders live, and stops placing new buys. Your inventory liquidates naturally at the grid's own profit levels as price rises. Once all inventory has sold through the open sells, the grid auto-finalizes to stopped with no manual action needed. Use this when you want to exit a grid without taking a market-sell loss — the middle option between pause (hold everything) and stop (exit now). Safeguard: if price falls far below range or the drain runs longer than Grid Drain Timeout (hours) (GRID_DRAIN_TIMEOUT_H) (default 24h), the bot escalates per Grid Drain On Timeout (GRID_DRAIN_ON_TIMEOUT) (default: liquidate the remainder) so the drain never hangs indefinitely./grid stop— Full exit. Cancels all resting grid orders and market-sells the grid's entire inventory back to your account's currency in one shot. Use this when you want to recover capital, switch symbols, or migrate. After/grid stopthe grid is fully closed — no orders or inventory remain.
Capital sizing rule: each grid needs at least $50 allocated, and allocation ÷ symbols ÷ levels must be ≥ $10 per level — otherwise Binance rejects every individual order as below MIN_NOTIONAL. For example: $100 capital, 1 symbol, 5 levels = $20/level ✓. $100, 2 symbols, 10 levels = $5/level ✗.
Dashboard tip: the grid card's order list now shows the value in your account's currency alongside each coin amount — buy orders show the amount to be deployed, sell orders the amount to be returned, and held inventory shows the live value at current price.
Smart TP & Volatility-Scaled Trailing
Smart TP (Runaway Chase) arms when price blows past a take-profit by the configured gap and trails the move with a hard floor at the original TP — so the worst case is a normal exit.
Applies to all strategies — Directional, DCA and Grid all use Smart TP once enabled; it's not tied to any single one, even though the examples below use grid numbers.
Master switch
- Smart TP (Runaway Chase) (
SMART_TP_ENABLED, default off, group Features & Gates) — Pro & Elite (Trial on TESTNET only). Turns the whole feature on or off. The trail-mode settings below only take effect once this is on.
Trail mode settings
- Smart TP — Trail Mode (
SMART_TP_TRAIL_MODE, defaultfixed, group Features & Gates) —fixeduses a constant Smart TP — Trail % (SMART_TP_TRAIL_PCT, default 2.0).vol_scaledwidens or tightens the trail based on recent 24-hour volatility: trail = k × vol24h, clamped between a floor and ceiling. - Smart TP — Vol Trail Multiplier (k) (
SMART_TP_TRAIL_VOL_K, group Features & Gates) — the multiplier (default 1.5). At 4% vol, trail = 6%. Higher values ride longer but give back more. The canonical value is 1.5 — it is not recommended to tune this per-coin.
Use vol_scaled if your grid operates on volatile altcoin pairs and you find the fixed trail gets stopped out on normal noise. Leave it on fixed for BTC or when you want predictable exits.
Symbol delisting guard
If Binance marks a symbol as non-tradable (status BREAK, HALT, or the symbol is delisted), ApexQuant automatically pauses new orders for that symbol and holds any existing inventory — it will not attempt to force-sell. You will receive a Telegram alert. If the symbol later resumes TRADING status, the grid restarts automatically. If the pair is permanently delisted and inventory cannot be sold on-exchange, you will need to review it manually through the Binance web interface.
Picking Arm Gap % and Trail % — with numbers. These two only work well when they're sized to your grid. Here's why, using the same example grid from the Smart Grid section (range $60,000–$66,000, 5 levels): Your grid spans 10% ($60k to $66k), split across 5 levels — so each level is about 2.5% apart (10% ÷ 4 gaps). That 2.5% is your grid's natural profit-per-step. Smart TP's Arm Gap is how far past a sell target price must run before the chase kicks in. If you set Arm Gap to 10%, price would have to rocket 10% past a level to arm — but your whole grid is only 10% wide, so it would almost never happen. Smart TP just sits there doing nothing. This is the most common mistake. A sensible Arm Gap here is around 1–1.25% — less than one 2.5% step, so the chase can actually trigger on a normal push above a level. Trail % should be smaller than Arm Gap — say 0.75% — so once the chase arms, it locks in most of the run before exiting instead of giving it back. You don't have to work this out yourself. When Smart TP is on, the dashboard suggests sensible Arm and Trail values from your grid's range and levels (one click to apply), and warns you inline if you type a value that would stop Smart TP from working — like an Arm Gap bigger than your whole range. The suggestion is optional; your own values are never changed unless you click Apply.
Web Backtest UI Pro / Elite
From the dashboard History tab, Pro and Elite users can launch backtests with a graphical interface:
- Symbol picker — choose from your configured symbols
- Date range — calendar pickers for start and end dates
- Override parameters — optionally set SL%, TP%, leverage to test variations (whitelist-validated)
- Live progress bar — updates every 2s as Binance bars are processed (typically 30s–5min)
- Cancel button — abort runs early; other jobs continue unaffected
- Equity curve chart — SVG chart of portfolio balance over the period
- History table — last 50 backtests with 📈 Chart button to re-view equity curve
Parameter Sweep (Elite only)
Run the same backtest across a grid of parameter combinations to find optimal settings:
- Choose 2 parameters (e.g. SL_PCT and TP_PCT) and up to 4 values each
- Total grid capped at 16 combinations (4×4) to bound compute time
- Each combination runs as a separate background job with individual progress tracking
- Results aggregated showing which parameter combination yielded the highest P&L
Note: Telegram /backtest BTC continues to work for all tiers — the web UI is additive.
Without Domain (self-signed cert + VPS IP)
Generate a self-signed certificate for HTTPS without a domain:
Access the dashboard at https://YOUR_VPS_IP:5005. Your browser will show a certificate warning — accept it (you generated the cert yourself).
Common Trading Variables
These variables apply to all strategies (Directional, DCA, Grid Bot). DCA-specific variables are documented in the DCA Bot section. Grid Bot variables are in the Grid Bot section.
| Variable | Default | What it does |
|---|---|---|
Symbol Selection Mode (COIN_MODE) — group Coin Scanner | FIXED | FIXED = trade exactly the symbols in Trading Coins. SCAN = bot auto-scans Binance every 24h and picks top coins by momentum+volume. SCAN is a Pro-tier feature — exciting but requires more monitoring. Recommended: start with FIXED. |
Trade Style (TRADE_STYLE) — group Strategy | SCALP | SCALP = 1-min signals, quick in-out. SWING = 1h signals, hold for bigger moves. Start with SCALP. |
Trading Coins (SYMBOLS) — group Trading Setup | BTC,ETH | Which coins to trade. Enter just the coin — e.g. BTC, ETH, XRP, SOL, BNB; ApexQuant builds each pair from your account's currency. Starter tier: max 2. Pro tier: max 5. Recommended starting coins: BTC,ETH. |
ML Gate Enabled (ML_ENABLED) — group ML Gate | true | Enable the XGBoost signal filter. Strongly recommended — leave true. Disable only for debugging. |
ML Minimum Return (ML_MIN_RETURN) — group ML | 0.002 | ML must predict at least 0.2% move to allow entry. Higher = fewer, better-quality trades. Try 0.003–0.005 for stricter filter. |
FRED API Key (FRED_API_KEY) — .env only, not a Bot Config setting | (blank) | Free macro intelligence. Get your key at fred.stlouisfed.org — takes 2 minutes. Strongly recommended. |
Manual BUY reserve % (MANUAL_BUY_RESERVE_PCT) — group Trading Setup | 5.0 | Percentage of balance reserved as safety buffer for fees + slippage on manual BUY orders. Default 5.0 means manual BUY can use up to 95% of available balance. Range: 0–25. |
MANUAL_BUY_RESERVE_PCT) directly controls how much of your balance a manual BUY can commit — lowering it (using more of your available balance per manual buy) leaves less safety margin for fees, slippage, and other open orders.
Trading mode, symbols, timeframe, risk limits, ML gate, AI Commentary, and strategy toggles can all be changed from Dashboard → ⚙️ Bot Config tab — no SSH, no service restart needed. Changes save permanently to the database and survive reboots.
Only secrets (Binance API keys, Anthropic key, Dashboard password) require direct
.env editing.
Quick Configuration Profiles
Open apexquant --config-gui (or Dashboard → ⚙️ Bot Config) and set each field to the value shown below for the profile you want. Run a backtest after applying each one.
These match the bot's own factory defaults.
Risk Management Settings
These settings protect your capital. The bot will halt new entries (but still manage open positions) when any limit is breached. Existing positions continue to be managed.
| Variable | Default | What it does |
|---|---|---|
Daily Loss Limit (DAILY_LOSS_LIMIT) — group Risk | 0.03 | Halt if down 3% today. 0.03 = conservative (default), 0.05 = balanced, 0.08 = aggressive. |
Weekly Loss Limit (WEEKLY_LOSS_LIMIT) — group Risk | 0.10 | Halt if down 10% this week. Set this to about 2× your daily limit. |
Max Loss Streak (MAX_LOSS_STREAK) — group Risk | 4 | Halt after 4 consecutive losing trades. Forces you to review before continuing. 3 = cautious. |
Minimum Balance Stop (MIN_BALANCE_STOP) — group Risk | 50.0 | Never trade below this balance (in your account's currency). Prevents blowing out to zero. Set to 20% of your starting capital. |
Max Hold Time (MAX_HOLD_HOURS) — group Risk | 48 | Force-exit any position open longer than 48 hours. Prevents capital being stuck in stale trades. |
| TRADE SAFETY LAYER | ||
Position Reconciliation Interval (RECONCILE_INTERVAL_SEC) — group Trading Mechanics | 21600 | How often (in seconds) the bot verifies its local database matches Binance's actual trade records. Default 6 hours. Lower = more API calls; higher = more potential drift. Default is fine for most users. |
Reconcile On Startup (RECONCILE_ON_STARTUP) — group Trading Mechanics | true | Run reconciliation immediately when the bot starts, before placing any trades. Recommended — heals any state drift since the last run before trading resumes. |
Deposit Detection Interval (DEPOSIT_POLL_INTERVAL_SEC) — group Trading Mechanics | 21600 | How often the bot polls Binance for deposits and withdrawals to keep the wallet baseline accurate. Relevant if you manually move funds in or out of the account between bot restarts. |
Block on Ghost Positions (GUARD_BLOCK_ON_GHOST) — group Trading Mechanics | false | When the bot detects a "ghost order" (an order it recorded sending but Binance has no record of), controls whether to halt the bot. Default false = send a Telegram alert and continue. Set true for paranoid environments where any unconfirmed order should stop trading. |
DAILY_LOSS_LIMIT) 0.03, Weekly Loss Limit (WEEKLY_LOSS_LIMIT) 0.06, Max Loss Streak (MAX_LOSS_STREAK) 3, Kelly Multiplier (KELLY_MULT) 0.25, Kelly Maximum Position (KELLY_MAX_FRAC) 0.05. Tighter limits mean slower growth but much smaller drawdowns while you learn the system.
Wallet baseline — protecting your existing assets
When ApexQuant first connects to your Binance account, it snapshots your current asset balances. This snapshot is the baseline — the bot treats everything in this snapshot as your pre-existing assets, not bot-managed funds.
Going forward, only assets the bot acquires through its own BUY orders are considered "bot-owned" and eligible to sell. Even if the local database is corrupted or contains a phantom position record, the bot will refuse to sell quantities that don't show up as bot-acquired.
Every SELL passes three independent guards:
| Guard | Source | Catches |
|---|---|---|
| Ledger | Sum of all bot BUYs minus all bot SELLs in local trade history | Code bugs, ledger corruption — bot trying to sell more than it ever bought |
| Baseline delta | Current wallet quantity minus your baseline snapshot | Phantom position records — database has a ghost entry but no actual fill ever happened |
| Free balance | Live Binance available balance | Real-time wallet anomalies — catches anything that slipped past the first two |
A SELL only executes for the minimum of all three guards. If any guard says zero, the SELL is blocked entirely and you'll receive a Telegram alert.
/recalibrate confirm (Starter tier and above).ML Gate Settings
The ML gate is an XGBoost model that filters signals before entry. It trains automatically on your first run (~2 minutes) and retrains weekly.
| Variable | Default | What it does |
|---|---|---|
ML Training Mode (ML_MODE) — group ML | regression | Use regression (default, smarter — predicts return magnitude) or classifier (legacy). Leave as regression. |
ML Minimum Return (ML_MIN_RETURN) — group ML | 0.002 | Minimum predicted % return to allow entry. 0.002 = 0.2% move required. Try 0.003–0.005 for stricter filter. |
ML Minimum Confidence (ML_CONFIDENCE_MIN) — group ML | 0.58 | Classifier mode only: minimum probability to allow BUY. 0.55 = permissive, 0.63 = strict. |
ML Training Symbol Pool (ML_TRAIN_SYMBOLS) — group ML | multi | Train on BTC+ETH+XRP combined (multi) for more data. Recommended. Use btc for BTC-only training. |
ML Retrain Interval (ML_RETRAIN_DAYS) — group ML | 7 | Retrain every 7 days on fresh data. Pro tier and above — Starter users retrain manually with /trainml. |
ML Forward Window (ML_FORWARD_BARS) — group ML | 8 | Predict price 8 bars ahead (8 hours on 1h data). Don't change unless you understand walk-forward validation. |
/trainml in Telegram. Training takes 1–3 minutes. The bot continues trading during training and only switches to the new model after it passes validation.Dynamic Symbol Detection (Pro & Elite)
By default the bot trades a fixed list of symbols you define in Trading Coins (SYMBOLS). Pro and Elite tier users can optionally enable scan mode — the bot automatically scans Binance every 24 hours and selects the top coins by momentum and volume, then retrains the ML model on the new set.
Recommended: configure in the Bot Config tab (group Coin Scanner unless noted).
| GUI Label (key) | Value to set | What it does |
|---|---|---|
Symbol Selection Mode (COIN_MODE) | SCAN (not "DYNAMIC" — that value doesn't exist; the two valid options are FIXED and SCAN) | Switches from your fixed Trading Coins list to dynamic top-N-by-volume selection. |
Top N Symbols by Volume (COIN_SCAN_TOP_N) | 5 (registered default) | How many top coins to select per scan (max = your tier symbol limit). |
Coin Rescan Interval (COIN_SCAN_INTERVAL_HOURS) | 24 (registered default) | How often to re-scan and re-rank symbols. |
Minimum 24h Volume for Scan (COIN_SCAN_MIN_VOLUME_USDT) | 50000000 (registered default) | Removes illiquid coins — a 50M minimum 24h volume (in your account's currency) to be considered. |
Your Trading Coins (SYMBOLS) setting still matters even in SCAN mode — it's used as the fallback list before the first scan completes.
COIN_MODE=SCAN is ignored and the bot falls back to FIXED mode using your Trading Coins (SYMBOLS) setting.Funding Rate Harvest Pro & Elite
What is it?
The Harvest module earns passive income, in your account's currency, from funding rates — the periodic payments that perpetual futures traders pay each other every 8 hours on Binance. When longs are crowded (positive funding rate), long traders pay short traders. The Harvest module collects this payment by taking a position structured to receive the funding rate while eliminating directional price risk.
Before you turn it on: Futures access
Binance only allows it when all of these are true:
- Your Futures account is opened first. On a sub-account, open Futures on that sub-account.
- The API key is created after that. An older key can't get Futures, so create a new one.
- The key is restricted to your server's IP address.
- The account isn't using portfolio margin.
You only need Futures for funding-rate harvest. Everything else in ApexQuant works without it. The same answer is in the FAQ: Why can't I turn on Futures for my Binance API key?
If the key has no Futures permission, the Harvest tab shows Binance: Futures permission missing and harvest places nothing until you add it; the rest of ApexQuant is not affected.
How does it work?
When the funding rate on a perpetual futures contract is positive (above a configurable threshold), Harvest:
- Buys the asset on spot (holds actual BTC, ETH, etc.)
- Opens a short of the same size on Binance Futures, so the two price moves cancel out
- Collects the funding payment on the short every 8 hours
- Closes both when the funding rate falls below the exit threshold
The result: you collect the funding payment in your account's currency every 8 hours, and your exposure to the price of the coin is close to zero because the spot coins and the short offset each other.
Risk profile
| Risk | How it's managed |
|---|---|
| The spot buy and the futures short fill at slightly different prices | Small positions, and a cap on how much of your balance can be in harvest at all |
| Funding rate reverses (goes negative) | Exit threshold in settings — auto-exits if rate drops below Harvest Exit Threshold (HARVEST_EXIT_THRESHOLD) |
| Opportunity cost | Capital is tied up during harvest window — configurable max allocation per symbol |
| Exchange risk | Same as all Binance spot trading — keys are read-trade only, funds stay on exchange |
Key settings
| Setting | Default | What it does |
|---|---|---|
Funding Harvest Enabled (HARVEST_ENABLED) — group Features & Gates | false | Master switch — must set to true to activate. |
Harvest Minimum Funding Rate (HARVEST_MIN_RATE) — group Harvest | 0.0006 | Minimum 8h funding rate to trigger entry (0.06% = RM0.60 per RM1000 per 8h). |
Harvest Exit Threshold (HARVEST_EXIT_THRESHOLD) — group Harvest | 0.0002 | Exit when funding rate drops below this level. |
Harvest Per-Symbol Allocation % (HARVEST_PER_SYMBOL_PCT) — group Harvest | 0.15 | Max 15% of balance per symbol in harvest positions. |
Harvest Max Balance % (HARVEST_MAX_PCT) — group Harvest | 0.30 | Max 30% of total balance across all harvest positions combined. |
Harvest Max Cycles to Break Even (HARVEST_MAX_CYCLES_TO_BREAKEVEN) — group Harvest | 5 | Won't open a harvest if earning back the fees would take more than this many 8-hour funding payments. |
Harvest Check Interval (HARVEST_CHECK_INTERVAL) — group Harvest | 300 | How often, in seconds, the funding rates are checked (5 minutes). |
Harvest Coins (HARVEST_SYMBOLS) — group Features & Gates | BTC,ETH | Comma-separated list of coins; how many you can list depends on tier (Pro: 5, Elite: 10). |
Telegram commands
Monitor harvest activity from Telegram:
/harvest— show all active harvest positions and current funding rates/harvesthistory— list last 10 completed harvest trades with PnL
Manual Trade Control All plans
Manual trade control lets you force-close any open position or open a manual position at any time — via the dashboard or Telegram. This is a direct override of the bot's automated exit and entry logic.
Manual SELL
Closes the full open position immediately at the current market price. Use this when you want to exit earlier than the bot's TP/trail targets.
| Method | How to use |
|---|---|
| Dashboard | Open Positions table → click ⬛ Sell button → a fee breakdown modal shows current price, gross proceeds, sell fee, buy fee already paid, net amount back to your wallet, and net PnL after fees. Click Confirm SELL to execute. |
| Telegram | /sell BTC — closes the BTC position. Run /sell with no argument to see all open positions first. |
The SELL records as MANUAL_SELL in your trade history with the actual PnL after fees. Daily PnL counter and kill switch streak are updated exactly as with a bot-triggered exit.
The reason field in trade history includes a market context snapshot captured at the moment of execution — regime, ML last prediction, macro score, kill switch drawdown, and sentiment score. This lets you review the market conditions that prompted the manual action.
Manual BUY
Opens a new position immediately at market price. You specify the coin and the amount (in your account's currency). What happens when a position already exists depends on your active strategy: under Directional, it’s one position per symbol — the dashboard shows a warning panel (entry / qty / P&L) instead of the buy form, so close the existing position first or pick another symbol; under DCA, the buy joins (averages into) your existing basket; under Grid or TradingView, manual BUY is blocked (use the strategy’s own controls).
| Method | How to use |
|---|---|
| Dashboard | Click + Manual BUY above the positions table → select the coin, enter the amount (in your account's currency) → click Execute BUY. A fee breakdown modal shows: buy fee deducted, the amount actually deployed, quantity received, estimated balance after, hard stop level, and the maximum loss if the stop is hit. Click Confirm BUY to execute. |
| Telegram | /buy BTC 50 — opens a BTC position with 50 (in your account's currency). The bot replies with entry price, quantity, and the hard stop level. |
Manual BUY behavior by Primary Strategy (PRIMARY_STRATEGY)
Pressing BUY on the dashboard or sending /buy via Telegram has different effects depending on Primary Strategy (PRIMARY_STRATEGY):
| Strategy | What Manual BUY does |
|---|---|
| Directional (experimental) | Opens a tracked position with ATR trailing stop, hard stop, and partial TP. This is the standard behavior. |
| DCA (default) | Adds the buy to your DCA basket. No separate stop-loss applies — position follows DCA exit rules (TP/trail above average entry). An orange warning banner is shown before you confirm. |
| Grid | BLOCKED and automatically rolled back. Grid strategy manages its own inventory via limit orders; a manual buy would create an untracked position that conflicts with the grid. The order is reversed immediately (sold back to your account's currency, trade row removed). |
| TradingView (coming soon) | BLOCKED and automatically rolled back. TV strategy expects all entries from webhook signals. A manual entry would have no exit protection (no stop registered). Roll back behavior is identical to Grid. |
What the bot does after a Manual BUY
Once the position is open, the bot manages it exactly like any other position:
- ATR-based trailing stop is set immediately
- Hard stop cap (default 8% max loss) is active
- Partial TP fires if price reaches TP target (4× ATR above entry)
- Time stop fires if position is still open after Max Hold Time (
MAX_HOLD_HOURS)
Restrictions
- One position per symbol — Manual BUY rejects if a position already exists for the selected symbol. Close it first via Manual SELL or
/sell SYMBOL. For automated scale-in entries, set Primary Strategy (PRIMARY_STRATEGY) todcainstead. - Cannot buy more than 95% of your available balance
- Symbol must be in your configured Trading Coins (
SYMBOLS) list - The amount must be ≥ Minimum Order Notional (
MIN_TRADE_USDT, default 11 in your account's currency, group Trading Mechanics) - Manual trades still count toward daily drawdown calculations
Holdings card and Holdings tab
The dashboard shows your coin holdings (everything except your account's currency) in two places:
- Live tab — Holdings card. Compact view showing only assets the bot is actively trading (assets in your Trading Coins (
SYMBOLS) config). Quick reference for the assets that matter to your current strategy. Includes a summary footer showing total bot-trading value vs. everything else. Click View all → to open the full Holdings tab. - Holdings tab. Full breakdown of every coin on your Binance account (everything except your account's currency), organized into three sections:
- ✓ Trading — assets currently configured in your Trading Coins (
SYMBOLS) list (active trading) - ↻ Previously Traded — assets you've traded before but aren't in current Trading Coins (
SYMBOLS) - Other — everything else (manual deposits, testnet seed balances, dust)
- ✓ Trading — assets currently configured in your Trading Coins (
The Positions table has a Value (USDT or USDC) column showing qty × current_price for each open position. This lets you see how much capital is deployed per symbol without mental arithmetic.
The Holdings tab includes a 💰 Cash section at the top showing your cash balance in your account's currency — the same value as the Live tab Balance card, displayed here for the complete portfolio picture. The Live tab compact Holdings card does NOT show it (the Balance card next to it already does). The Cash section is hidden when your cash balance is zero.
A ↻ Refresh button at the top-right of the Holdings tab fetches the latest prices from Binance, bypassing the 30-second cache used by the background refresh. Use this when you want to verify a price change immediately rather than wait for the next background cycle.
Note: on Binance Testnet you may see many "Other" assets — these are seed balances Binance assigns to test accounts and have no real value. On mainnet, this list contains only assets you've actually deposited or acquired. Prices refresh every 30 seconds (single API call, cached to avoid rate limits).
AI Commentary enhancements Elite only
Elite tier users get AI-assisted analysis before every manual BUY or SELL. Your AI provider reviews current market conditions and gives a direct verdict.
| Trade type | AI verdicts | What the AI analyses |
|---|---|---|
| Manual BUY | GO · CAUTION · AVOID | Regime, ML confidence, macro score, sentiment F&G, ATR volatility |
| Manual SELL | EXIT · HOLD · PARTIAL | Current P&L, trail stop proximity, regime, ML, sentiment — exit now or let bot manage? |
Elite users also see a Kelly-suggested position size in the BUY modal — calculated from your actual win rate, average win/loss, and current ATR. A one-click "use" button fills the amount automatically.
Note: AI analysis uses your Anthropic API Key (ANTHROPIC_API_KEY). Typical cost per call: <RM0.01 (Haiku model).
Auto-managed vs Manual-managed exit
When placing a Manual BUY from the dashboard, a checkbox lets you choose who manages the exit:
| Mode | What the bot does | What you must do |
|---|---|---|
| 🔓 Auto-managed (default) | Manages exit using strategy rules: trailing stop, partial TP, time stop, regime exit, hard stop, kill switch | Nothing — bot handles it |
| 🔒 Manual-managed | Performs ZERO exits — no trailing stop, no TP, no hard stop, no kill switch protection. Nothing. | Must /sell SYMBOL yourself to close |
Manual-managed positions skip ALL bot-level exits and protections. The user takes 100% responsibility for closing the position via /sell SYMBOL or dashboard manual sell. The bot will NOT close a manual-managed position under any circumstances — including hard stop and kill switch.
Manual-managed mode is intentionally restrictive. When you untick auto-managed and click Confirm BUY, a separate confirmation modal appears with the warning and acknowledgment checkbox. Read the warning, tick the acknowledgment to enable the "I Understand, Execute BUY" button. This two-step flow prevents accidentally choosing manual mode without understanding the implications.
If you want the bot to close a position automatically based on price levels, use auto-managed mode and let the bot's stop logic apply. Manual mode is for traders who want full discretionary control over exits.
Telegram /buy always uses auto-managed exit. The dashboard is the only way to open manual-managed positions because the second-confirmation requirement cannot be reasonably implemented in CLI.
Account Equity card
The Account Equity card on the Live tab shows your total trading equity broken into three parts:
- Cash: free balance in your account's currency (spendable)
- Positions: Current market value of all open positions (qty × current price for each, summed into a single total). Per-symbol breakdown is in the Open Positions table below and the Holdings tab.
- Total: Cash + Positions = total equity. This is the value the kill switch monitors against your Minimum Balance Stop (
MIN_BALANCE_STOP) threshold.
Last update timestamp shown at the bottom of the card. Updates with each engine tick (typically every 1-2 seconds).
Trade attribution
Every trade is tagged with an entry source and exit source, visible in the Trade History tab and CSV export.
| Field | Values | Meaning |
|---|---|---|
entry_src | auto:directional, auto:dca, auto:grid, manual:dashboard, manual:telegram | Who initiated the buy |
exit_mode | auto, manual | Set at entry, immutable — who manages the exit |
exit_src | auto:tp, auto:sl, auto:trail, auto:time, auto:kill, auto:regime, manual:dashboard, manual:telegram | What triggered the close |
Position cards on the Live tab show two compact badges per row: a 🤖 Auto / 👤 Manual entry badge and a 🔒 Manual exit / 🔓 Auto exit badge. Both are display-only — no editing.
The Trade History tab has a filter row: All trades / Auto entries / Manual entries / Manual-managed only. Filtering is client-side. The CSV export includes entry_src, exit_mode, and exit_src columns for offline analysis.
Attribution is useful for "why did this trade close?" investigation — compare exit_src=auto:sl (hard stop hit) versus exit_src=auto:trail (trailing stop profit-locked) versus exit_src=manual:dashboard (you closed it manually).
When you open a manual SELL, you can close the whole position or sell only a portion. Pick a quick preset (25%, 50%, 75%, 100%), type any custom percentage in the % field, or enter an exact quantity in units. The remainder stays under automatic management — take-profit and trailing logic continue to run on whatever is left.
If the chosen amount would leave a remainder below the exchange’s minimum order size, the dialog blocks the partial and offers to close the whole position instead.
The same options are available in Telegram: the SELL menu offers 25/50/75/100% presets, Custom %, and Custom qty. You can also type /sell SYMBOL 30% for a quick percentage sell or /sell SYMBOL 0.5 for an exact quantity.
Performance Tab & /performance Command
The Honest Performance Report on the Performance tab (and via /performance in Telegram) shows your real live-trading results, isolated from paper/testnet noise and from old configurations.
What is scoped
- Only LIVE mode closed trades count. Paper and testnet are excluded.
- Results default to your current config era — the period since you last changed a material setting (strategy, grid range, DCA budget, Smart TP mode). Changing any of these stamps a new era boundary automatically.
- Use
/performance alltimeto see all-time LIVE results across all config eras.
Metrics shown
- Win rate, Profit factor (gross win / gross loss), Expectancy (expected value per trade).
- Net PnL and Gross PnL — the difference is fee drag, shown explicitly so fees cannot hide as profit.
- Max drawdown — peak-to-trough on the equity curve within the scoped window.
- Sharpe ratio — the average result of a trade divided by how much single trades vary; only shown when you have 30 or more closed trades. Below that threshold it is labelled “insufficient sample” rather than shown as if meaningful.
Telegram Commands
This is the same list your bot sends when you type /help, grouped the same way. A command marked 🔑 asks for your PIN (or your 2FA code, if you use 2FA) each time it acts. Some commands depend on your plan; the plan is shown beside them. /menu has the same things as buttons.
| Command | What it does |
|---|---|
| 📊 Status and info | |
/status | Engine state and a summary of your positions. |
/balance | Your wallet balances with their value. |
/positions | Your open positions in detail. |
/trades | Your recent trades. |
/daily | Today's profit and loss summary. |
/performance [alltime] | How the bot has done in the current setup, or over all time. |
/health | A one-screen health check: equity, safety state, connection. |
/explain COIN | A plain explanation of what the bot is doing with one coin and why. |
/regime | What kind of market the bot sees now. |
/coins | The coins the bot is trading and the state of the coin scanner. |
/sentiment | Market mood: news sentiment and the Fear and Greed score. |
/diagnose | Why the bot is not buying right now, check by check. |
| 🤖 Trading | |
/buy COIN [amount] 🔑 | Buy a coin by hand. |
/sell COIN 🔑 | Sell a coin you hold at the market price. |
/forcesell COIN 🔑 | Sell a coin the bot could not confirm it owns. |
/stop | Pause new entries now; coins you hold stay and their stops keep working. |
/resume 🔑 | Start trading again after a stop or a halt. |
/emergency | Halt immediately; positions are kept, nothing is sold. |
/stop_quit 🔑 | Stop and quit: halt and release management; the coins stay in your wallet. |
/recalibrate [COIN] [confirm] 🔑 | Show, or reset, the amount of each coin that was in your wallet before the bot. |
/mode 🔑 | Show the trading and coin modes; with a word after it, switch them. |
/currency | The currency switch: see the currency the bot trades in and start a switch (it asks you to confirm) |
| 📈 Grid bot | |
/grid status [COIN] | Grid state, profit and open orders. Plans that include the Grid bot |
/grid pause [COIN] 🔑 | Cancel the orders and keep the coin. Plans that include the Grid bot |
/grid drain [COIN] 🔑 | Stop buying and let the sells finish. Plans that include the Grid bot |
/grid resume [COIN] 🔑 | Place the buys again. Plans that include the Grid bot |
/grid stop [COIN] 🔑 | Cancel the orders and sell what the grid holds (also: reset, close) Plans that include the Grid bot |
/grid rebuild [COIN] 🔑 | Stop, then start a new grid around today's price. Plans that include the Grid bot |
/grid recenter [COIN] 🔑 | Move the range to today's price without selling. Plans that include the Grid bot |
/grid extend upper|lower [COIN] 🔑 | Grow the range past the edge the price went beyond. Plans that include the Grid bot |
| 📦 DCA bot | |
/dca status | DCA state, legs and profit. |
/dca pause | No new DCA buys until you resume. |
/dca resume 🔑 | Allow DCA buys again. |
/dca buy COIN 🔑 | Add a DCA buy now. |
/dca sell COIN 30% 🔑 | Sell part of a DCA basket (a percentage, or an amount of coin) |
/dca close COIN 🔑 | Sell a whole DCA basket. |
/dca reset COIN 🔑 | Give a coin's DCA budget back. |
| 🌾 Funding harvest | |
/harvest | Funding harvest: state and open positions. |
| 🛑 Safety | |
/killswitch | The safety monitor: losses so far against its limits, and the streak of losing trades. |
/macro | The macro data gate (also /fred) |
/fomc | Whether a central-bank announcement pause is on. |
| 🧠 AI, learning and backtest | |
/ai | An AI commentary on the market now. Elite |
/aiusage | This month's AI use and budget. |
/aibudget [RAISE] 🔑 | Show the AI budget; RAISE gives it more room. |
/ml | How well the learning model has been doing. |
/trainml | Retrain the learning model now. |
/backtest | Test the chosen strategy on past prices. |
/digest | The weekly digest, now. Pro and Elite |
/dailytest | Send the daily report now, to check it. Pro and Elite |
| ⚙️ Settings and logs | |
/set NAME value 🔑 | Show or change a setting (some apply after a restart) |
/settings | All the strategy and risk settings at a glance. |
/logs | The last log lines. |
| 🔐 Licence and access | |
/license | Your plan and when it ends. |
/setkey KEY 🔑 | Enter your licence key. |
/blockip [address] | List the blocked addresses, or block one. |
/unblockip address | Let an address use the dashboard again. |
/restart 🔑 | Restart the service (asks to confirm) |
/pin | Answer a request for your PIN or code. |
| 📋 Other | |
/menu | The button menu (also /start) |
/cancel | Cancel a pending request for your PIN or code. |
/help | This list. |
When NOT to recalibrate: If you have unexplained deposits or transfers you don't recognise, investigate first. Recalibrating absorbs them into the baseline and the bot may then treat them as eligible to sell.
/buy BTC 50 = 50 of BTC), base asset quantity for sell (e.g. /sell BTC 0.001 = 0.001 BTC). When in doubt, send /buy or /sell with no arguments — bot will show percentage buttons same as dashboard.
PIN entry: When prompted for PIN, you can either reply with bare digits (
1234) or use the explicit command (/pin 1234). Both work. The PIN message is auto-deleted from chat after successful verification.
Troubleshooting
The FastAPI server on port 5005 is not running or crashed on startup.
ModuleNotFoundError — run pip install -r requirements.txt inside your venv first.All API calls are returning 401 or the JS file is not loading correctly.
Check which gate is blocking entries. On the dashboard → click the Gate Audit view or check logs.
- Confirm
BINANCE_API_KEY(canonical:/root/apexquant-data/.env;/root/ApexQuant/.envshould be a symlink to it) andBINANCE_API_SECRETare set in.env - In Testnet mode: use keys from testnet.binance.vision — live keys do NOT work on testnet
- In Live mode: ensure the API key has Spot Trading enabled and IP whitelist includes your VPS IP
- Wallet must hold the currency you chose (USDT or USDC) — other stablecoins are not traded
TELEGRAM_CHAT_ID) are accepted. Make sure you're messaging from the correct account. Get your chat ID by messaging @userinfobot on Telegram.NotEnoughData, wait 24 hours for more bars to accumulate, then retrain.SELL BLOCKED by safety guard
Symptom: Telegram message: SELL BLOCKED <SYMBOL> qty requested: X.XXXXXX — BLOCKED: <guard> guard says zero owned
Cause: One of the three SELL safety guards detected the bot doesn't own enough of that asset to sell safely. Common reasons:
- Ledger guard — the bot's local trade history shows it never bought this quantity (common after restoring from an old database backup)
- Baseline guard — the current wallet quantity doesn't exceed the baseline snapshot (bot-acquired amount = 0)
- Wallet guard — Binance free balance is below the requested quantity (funds may be locked in another open order)
Fix: The Telegram alert tells you which guard fired. Investigate that specific guard:
- Ledger: review trade history for the symbol via
/tradesand confirm whether the guard was correct - Baseline: run
/recalibrate <ASSET>to check baseline vs current wallet; use/recalibrate <ASSET> confirmif you legitimately added funds to be managed - Wallet: cancel any open orders on Binance UI that may be locking the balance, then retry
SELL CLAMPED — executed for less than expected quantity
Symptom: A sell executed but for less quantity than expected. Logs show SELL <SYMBOL> CLAMPED: X.XXXXXX → Y.YYYYYY. CLAMPED: requested X, allowed Y (limited by <guard>)
Cause: One of the three safety guards limited the sell quantity. The bot sold what was provably safe and protected the remainder.
Fix: Usually no action needed — the bot acted conservatively. If you expected the full quantity to sell, investigate which guard limited it and resolve using the same steps as "SELL BLOCKED" above.
GHOST order detected
Symptom: Telegram message: ⚠ GHOST ORDER DETECTED — intent <id> (<SYMBOL> <SIDE> qty=X) was sent but Binance has no record. Marked GHOST. Bot continuing normally.
Cause: The bot recorded its intent to send an order, but Binance has no record of that order arriving. Possible reasons:
- Network hiccup between your server and Binance during the order transmission
- Binance API rejected the order before logging it on their end
- Bot crash mid-send before the order completed
Fix: This is informational. The bot continues operating normally and the intent is marked GHOST in the database for audit purposes. No immediate action required.
Investigate if:
- Multiple GHOST messages appear in a short period — could indicate network instability or Binance API issues on their end
- The GHOST is for a symbol or quantity you don't recognise — change your Binance API keys immediately and audit your account
GUARD_BLOCK_ON_GHOST) to true in the Bot Config tab (Trading Mechanics group) to halt the bot automatically on any GHOST detection. This is a paranoid-mode setting — most users should leave the default false.Recovery — Unaccounted Assets
After a database restore, a manual deposit, or certain restart scenarios, ApexQuant may detect holdings on your Binance account that don't match its internal records. The dashboard shows a Recovery banner above the equity card when this happens.
An "unaccounted asset" is a balance in a coin other than your account's currency in your Binance account that ApexQuant's own trade history doesn't explain — for example, a position you manually opened, a transfer from another account, or a trade from before this install. Only balances above the Reconciliation Minimum (USDT or USDC) setting (RECONCILE_MIN_USDT, default 50.0) are flagged — smaller amounts are treated as exchange dust and never surface here.
Before an item gets Sell/Adopt buttons, ApexQuant requires two consecutive reconciliation passes to agree on what it found — a single flaky Binance read is never enough to surface an item as actionable. Reconciliation runs on the Position Reconciliation Interval setting (RECONCILE_INTERVAL_SEC, default 6 hours), and each pass waits out the full interval first — so two agreeing passes can take up to twice the interval (up to 12 hours at the default) after a fresh restart. If the banner shows nothing but you know you have an unaccounted balance, this is normal — give it time before assuming something is wrong.
ApexQuant only flags a balance in the first place if it can trace it to a bot BUY that was never matched by a later bot SELL — a genuine deposit or a manual transfer was never a bot purchase, so it's never even a candidate for this list. As an additional backstop, adopting also runs a check against Binance's own deposit and internal-transfer records (looking back 30 days) before completing — in the rare case that check finds a genuine deposit or transfer explaining the balance, the adopt is refused and the coins are instead folded into your wallet baseline (bookkeeping only, never sold or adopted). This is expected to almost never trigger for a normal Recovery-banner item, precisely because of the FIFO matching above — it exists as defense in depth, not as the primary gate.
- Sell to USDT / Sell to USDC (the button names your account's currency): ApexQuant sells the exact flagged quantity at market price and removes it from tracking. Irreversible — you're asked to confirm the quantity and USD value first.
- Adopt DCA or Adopt Directional: tell ApexQuant to start tracking this asset under the DCA basket or the Directional (exit-protected) strategy. It will then manage the exit with stops and take-profit as configured for whichever you choose.
There's no separate "dismiss" action — an item stays in the banner, unmanaged in your wallet, until you Sell or Adopt it.
Recovery does not apply in PAPER mode — there is no real Binance wallet to reconcile against. The recovery banner does not appear in PAPER.
Held Positions
When ApexQuant stops actively managing a symbol — because you removed it from your configured list, switched strategies, or a grid/DCA/directional position was released for any other reason — the coins are never sold automatically and never silently dropped from tracking. They move to Held: visible on your Holdings tab, tracked at their average cost, and completely untouched by any automatic stop-loss, take-profit, or time-based exit until you decide what happens next.
Automatically selling a released position the moment management stops would force a sale at whatever price happens to be current — even a brief, meaningless dip. ApexQuant never does this. A released position keeps its cost basis and quantity on record, with zero auto-exit machinery attached, until you make an explicit choice.
- Keep: leave it exactly as it is — tracked, displayed, no auto-exit. The default state; you don't need to act.
- Sell: sell the position at market price right now. The only way a Held position is ever sold — always your explicit choice, always confirmed before it executes.
- Attach protection: choose a stop-loss and trailing-stop level and hand the position back to active management. Once attached, it behaves like any other auto-managed position and will exit automatically if the price hits your chosen stop.
- Re-assign: hand the position to DCA, Grid, or Directional as a fresh starting position for that strategy, using the same adoption logic as Recovery's own Adopt actions above.
There's no time limit or forced decision — a Held position can stay Held indefinitely with no consequence.
If a whole DCA basket (multiple buy-in legs across different prices) is released, ApexQuant collapses it into a single Held position at the basket's weighted average cost — matching how the position already displayed while it was active. The individual legs aren't tracked separately once Held.
If you already had a position released under an earlier version of ApexQuant with its own protective stop already attached, that protection is left exactly as it was — this feature never silently removes an existing stop from a position you already had. Only newly released positions default to the unprotected Held state described above.
What Happens During API Outage
Binance and other API services (FRED macro, CoinGecko, Anthropic) occasionally go down for maintenance or technical issues. ApexQuant detects this automatically and pauses safely — no manual intervention needed.
3 consecutive Binance errors within 60 seconds triggers the API_DOWN state. This catches HTML error pages (Binance error 0), HTTP 5xx responses, connection timeouts, and stale ticker feeds.
- ApexQuant says so once: “Binance is unreachable right now. ApexQuant keeps retrying on its own and trades nothing until it is back.” If it lasts, one reminder every 15 minutes says how long (“Binance still unreachable for 42 min; still retrying.”), and when Binance answers again one line says it is over and how long it lasted
- All new entries blocked — engine tick, TradingView webhooks (coming soon), and Telegram /buy /sell all return immediately
- All auto-exits paused — no sell attempts on a dead API (avoids partial fills and orphan orders)
- Telegram spam suppressed — one "🚨 Binance API Down" alert fires, then silence until recovery
- The dashboard still opens and loads quickly. It shows what ApexQuant last knew, and says “Waiting for Binance” instead of an error (while ApexQuant is starting up, it says what it is waiting for). The banner shows the outage status, its duration and the skipped operations count (updates every 10s)
- Buttons that need Binance (manual buy and sell, the grid controls such as Pause, Drain, Resume and Reset, the recovery sells) are greyed out with the reason, and a request that gets through anyway is refused with one sentence: “Binance can't be reached right now, so this can't be done. It works again as soon as Binance is back.” A backtest or training run says it needs Binance's price history. Right after a restart it says “ApexQuant is still starting up. Try again in a moment.”
- Settings, the Emergency Stop and reading your data keep working
- Drawdown calc falls back to entry price for open positions — avoids false drawdown halt from missing ticker data
A background monitor pings api.binance.com/api/v3/time every 30 seconds. After 3 consecutive successful pings, the bot automatically resumes and sends a "✅ Binance API Recovered" Telegram alert with the outage duration and skipped operations count.
If you need to halt the bot during or after an outage:
- Dashboard → 🛑 EMERGENCY STOP button in the Bot Status card (asks for your dashboard password again; no PIN or 2FA code)
- Telegram →
/stopcommand (asks for nothing)
To go on afterwards, press Resume on the dashboard (or send /resume in Telegram).
Updating to a New Version
ApexQuant keeps itself up to date automatically. A daily check installs any new version, verifies it (SHA-256), preserves your settings, license and database, restarts the bot, and auto-rolls-back to the previous version if anything fails.
Automatic updates are enabled by default — you were asked during setup. You can change this any time:
Automatic updates run around 04:30 server time (with a small random jitter). The full log is at /var/log/aq-update.log.
sudo aq-update.sh --disable) and run the manual command above when you have no open positions.
Prefer to update manually from a downloaded zip? The rename-and-clone steps below keep rollback simple and never touch your data, license, or settings.
- Visit apexquant.tech/download
- Download the latest
ApexQuant-Setup.zipto your local machine - Upload the zip to your VPS using SCP from your local machine:
Upload via SCPscp ApexQuant-Setup.zip root@your-vps-ip:/root/
- Or use SFTP (FileZilla, WinSCP, Cyberduck) and upload to
/root/
sha256sum /root/ApexQuant-Setup.zip and confirm it matches before extracting.
Re-creates symlinks to /root/apexquant-data/ and rebuilds the venv with any new dependencies. Your config, license, trial timer, and trade history are never touched.
Verify license shows [LICENSE] Valid | Tier: .... Open dashboard, check F12 console — no errors. Watch for 5–10 minutes.
You'll be back on the previous working version. Report the issue to support.
ApexQuant_OLD for at least 24 hours after updating. Once confirmed stable, delete it: rm -rf /root/ApexQuant_OLD
/root/apexquant-data/apexquant.db outside the app folder. Updates never touch this file.
Switching Binance Accounts
If you need to connect ApexQuant to a different Binance account, always follow the managed switch flow before editing your API keys. Changing keys directly without completing this flow may strand open orders on the old account — and on Binance testnet there is no manual cancel UI, so the bot is the only way to close them.
The safe switch procedure
- In the dashboard, go to Bot Config and click 🔄 Switch Binance Account.
- Enter your Admin PIN (and 2FA code if enabled).
- Choose your policy: Cancel orders only (default — your coins stay in your account, released to "Other"); or Also sell positions to your account's currency (opt-in — this realizes P&L and should be acknowledged).
- Tick the acknowledgement and type CONFIRM twice (two steps).
- Wait for the ✅ Current account CLEARED confirmation. Do not change keys until you see this.
- Run
bash update_keys.shon your VPS and enter the new API key and secret. - Restart ApexQuant:
systemctl restart apexquant. - ApexQuant detects the new account and starts fresh automatically.
What "fresh start" means
- ApexQuant manages your account's currency (USDT or USDC, the one you chose). Your free balance in it = ApexQuant's trading capital.
- All existing coins → "Other" (unmanaged). ApexQuant will not trade, sell, or adopt them.
- To have ApexQuant trade a coin, convert it to your account's currency in Binance first. ApexQuant will then trade from that.
- Your previous ApexQuant history (trades, equity chart, P&L) is archived, not deleted. It remains recoverable for audit purposes.
Returning to a previously connected account
If you switch back to an account ApexQuant has seen before, ApexQuant still starts fresh — it does not restore previous positions or orders. This is intentional: when you left that account, ApexQuant released it (cancelled its orders), so there is nothing meaningful to restore. Your previous data remains archived for audit.