Connecting a trading bot to Binance is the first step that most tutorials rush through. Create API keys, paste them into code, start trading. This approach works until someone gains access to your keys and drains your account. The setup process matters because API keys are the credentials that control your exchange access.
We connect 45 bots to Binance mainnet API for paper trading with real market data. Our security practices protect against both external attacks and internal mistakes.
API Key Creation
Binance API keys are created in the API Management section of your account settings. Each key pair consists of an API Key (public identifier) and a Secret Key (private credential). The Secret Key is shown only once during creation and cannot be retrieved later. Store it immediately in a secure location.
Create a dedicated API key for your trading bot. Do not reuse keys across applications. If one application is compromised, only its key is exposed. Label the key clearly (for example, "QuantForge Paper Trading") so you can identify and revoke it quickly if needed.
Permission Configuration
This is the most important security decision. Binance API keys support three permission levels: read-only (market data and account info), trading (place and cancel orders), and withdrawal (transfer funds out of the account).
Our keys use read and trade permissions only. Withdrawal is explicitly disabled. This means that even if someone obtains our API keys, they cannot transfer any funds out of our Binance account. They could potentially place destructive trades (buying illiquid tokens, selling at market), but they cannot steal funds directly.
Never enable withdrawal permissions on API keys used by automated systems. The risk-reward is catastrophically asymmetric. If your bot needs to withdraw, create a separate key with withdrawal permissions that is used only for that specific operation and is stored with additional security.
IP Whitelisting
Binance supports IP restrictions on API keys. When enabled, the key only works from specified IP addresses. Requests from any other IP are rejected regardless of the key credentials.
For a self-hosted bot running on a single machine, whitelist that machine's public IP address. If your IP changes (dynamic IP from your ISP), you will need to update the whitelist periodically. For bots running on cloud VMs, whitelist the VM's IP.
Our setup uses Tailscale for network connectivity between the Mac (running bots) and the distributed worker VMs. The Binance API key is whitelisted to the Mac's public IP only. Workers do not need exchange access because they only run backtests on historical data.
Encrypted Key Storage
Our platform stores API keys using Fernet symmetric encryption with PBKDF2 key derivation. The encryption key is derived from a password using PBKDF2 with a random salt and 100,000 iterations. The encrypted keys are stored in the SQLite database alongside other operational data.
This means the API keys are encrypted at rest. Even if someone accesses the database file, they cannot read the keys without the encryption password. The password is stored in the environment variables (loaded from .env) and never committed to version control.
The .env file is in .gitignore and never leaves the local machine. It contains: BINANCE_API_KEY (the public key), BINANCE_API_SECRET (the private key), and other sensitive configuration. On our production setup, the .env file has restricted file permissions (readable only by the owner).
Connection Configuration
Our ccxt exchange initialization configures several security-relevant parameters. The exchange connects to Binance mainnet (not testnet) for real market data. Paper mode is enabled at the application level, not the exchange level — the exchange connection is real, but orders are simulated by our paper trader rather than submitted to Binance.
Rate limiting is configured at 1,200 weighted requests per minute, matching Binance's spot API limits. Request deduplication across 45 bots prevents multiple identical requests from consuming rate limit budget. Timeout is set to 30 seconds per request with automatic retry on transient errors.
The BINANCE_TESTNET flag in our configuration controls whether the ccxt client connects to the Binance testnet (different API endpoints, test funds) or mainnet. For paper trading with real market data, we use mainnet with our paper execution layer handling the simulation.
The Paper Trading Security Model
Our paper trading configuration connects to Binance mainnet to receive real market prices but never submits real orders. The paper trader intercepts the order execution path and simulates fills with realistic slippage and fees.
This means our API keys are used for read operations (fetching candles, checking prices) and never for trade operations during paper trading. The trade permission on the key exists for the future transition to live trading but is not exercised during the paper phase.
The benefit of this approach is that paper trading results are based on real market data (actual bid-ask spreads, actual volume, actual price movements) rather than simulated or historical data. The downside is that the API keys have more permissions than strictly needed for paper trading. We accept this trade-off because the transition to live trading will be a configuration change rather than a key change.
What Happens If Keys Are Compromised
If you suspect your API keys are compromised, immediately delete them from the Binance API Management page. This instantly invalidates the key pair. No further requests using those credentials will be accepted.
Then create a new key pair with the same permissions and IP whitelist. Update your .env file and restart the bot. The interruption is typically under 5 minutes.
For additional protection, enable 2FA on your Binance account and set up anti-phishing codes. These do not directly protect API keys but protect the account from unauthorized access that could be used to create new API keys or modify existing ones.
The FastAPI Server
Our FastAPI server binds to localhost (127.0.0.1) by default, meaning it is only accessible from the local machine. For distributed worker mode, we bind to 0.0.0.0 (all interfaces) with bearer token authentication. The API_BEARER_TOKEN in .env must match between the coordinator (Mac) and the workers (VMs).
The CORS configuration restricts which origins can make requests to the API. In local mode, only localhost:3000 (the React dev server) is allowed. In distributed mode, worker IPs are added to the allowed origins.
This layered approach (localhost binding, bearer token auth, CORS restrictions) ensures that even on a network where other devices can reach the server, unauthorized access is blocked at multiple levels.
Checklist
Before connecting any bot to Binance: create a dedicated API key with trade permission only (no withdrawal). Enable IP whitelisting to your bot's IP. Store keys encrypted (never in plaintext, never in code, never in git). Bind your server to localhost unless distributed workers need access. Use bearer token authentication for any non-local connections. Test with paper trading before enabling live execution. Keep a record of which keys are used where so you can revoke quickly if needed.