When I first deployed my Python crypto trading bot to an AWS EC2 instance, I thought Telegram notifications would be enough. Getting a ping for every entry, stop-loss, or take-profit felt sufficient.
But over time, the limitations became glaring. What's my current win rate? How is v8.03 performing compared to v8.02? What's the exact PnL curve looking like? Telegram gives you isolated moments; it doesn't give you the narrative. But to see the big picture, I had to RDP into my Windows EC2 server, open CSV files, and manually calculate stats. I needed a dashboard, but I had one strict rule: Do not touch the core trading logic.
Here is how I built a real-time web dashboard for my bot with minimal footprint.
The Architecture: Decoupled by Design
Injecting UI or heavy API logic directly into a live trading bot is a recipe for disaster. If the UI thread crashes, I don't want it bringing down the trading engine during a volatile market move.
I opted for a completely decoupled file-based architecture:
-
The Bot (Writer): Runs as usual. At the end of every candle evaluation, it simply writes its current state (balance, open positions, active settings) to a
bot_state.jsonfile. -
The Flask API (Reader): A lightweight separate process that reads the
.jsonand.csvtrade logs and serves them via REST endpoints. - The Frontend: A Vanilla JS + Chart.js static HTML page that polls the API every 15 seconds.
Step 1: The Lightweight Flask API
I created a dashboard_api.py script. It exposes endpoints like:
-
/api/status: Bot version, strategy, ADX levels. -
/api/balance: Current USDT balance. -
/api/trades: Parses the CSV trade logs. -
/api/stats: Calculates win rate and total PnL.
Inside the main bot script, I only added three lines of code inside the start() method to launch the Flask server as a daemon thread. The trading logic remained untouched.
Step 2: The Vanilla JS Frontend
I didn't want to over-engineer this with React or Vue. A single index.html file using Vanilla JS and Chart.js for the PnL curve was perfect.
It fetches data asynchronously every 15 seconds. The dashboard displays active parameters, a live PnL chart, currently open positions, a recent trade ledger, and a historical comparison of bot versions (e.g., v8.00 vs v8.01 vs v8.02).
Challenges & Troubleshooting
1. The Flask Threading Bottleneck
Initially, the dashboard kept hanging. The browser was trying to fetch 6 API endpoints simultaneously, but the default Flask development server runs on a single thread. Requests were timing out.
Fix: Simply setting threaded=True in the app.run() parameters solved the concurrency issue.
2. Legacy CSV Ghost Data
My total PnL suddenly showed +$3,700 USDT (which I definitely didn't make). The API was reading old v7.x CSV files sitting in the logs/ directory. Because the column structures had changed between versions, the parser was reading random timestamp strings as PnL floats.
Fix: Added a strict date filter and outlier rejection logic to ignore corrupted or legacy data rows.
3. The AWS + Windows Double Firewall
I opened port 8765 (API) and 3000 (HTML) in my AWS Security Group, restricted to my IP. But I still couldn't connect. I forgot that I was running a Windows EC2 instance, which has its own internal firewall.
Fix: Had to add an inbound rule via the command line:
netsh advfirewall firewall add rule name="Dashboard" dir=in action=allow protocol=TCP localport=8765
Conclusion
Building this dashboard was a game-changer. Staring at raw numbers in a terminal is one thing, but seeing a visual PnL curve and a comparative table of version win rates immediately highlights structural flaws in your strategy.
If you are building an algo-trading bot, spend a weekend building a visual dashboard. Data visualization is the first real step toward strategy optimization.

Top comments (0)