DEV Community

J Courtney
J Courtney

Posted on

I Built an Autonomous Crypto Trading Bot — Here's What I Learned

After months of watching crypto markets and losing money to "almost" catching the right moves, I decided to automate it.

This isn't a get-rich-quick story. It's a real account of building a crypto trading bot from scratch, what worked, what spectacularly failed, and the specific technical decisions that made the difference between a bot that loses money automatically and one that actually generates consistent returns.

Why Build a Bot in the First Place?

Markets don't sleep. I do. That asymmetry alone is enough to justify automation.

But beyond the 24/7 coverage, a bot eliminates the single biggest killer of retail traders: emotion. Fear makes you sell too early. Greed makes you hold too long. A bot doesn't care about either. It executes the strategy you programmed and nothing else.

The key phrase there is the strategy you programmed. If your strategy is bad, the bot will execute it badly — consistently, at scale, around the clock. So before writing a single line of code, I spent weeks on strategy research.

The Architecture: What I Actually Built

My bot runs on Python (3.11+) and handles three core responsibilities:

1. Market Data Ingestion
I pull OHLCV data (Open, High, Low, Close, Volume) from Coinbase Advanced Trade API via WebSocket for real-time feeds and REST for historical data. WebSockets are critical — REST polling introduces latency that matters enormously when signals are time-sensitive.

import asyncio
import websockets
import json

async def connect_coinbase_ws():
    uri = "wss://advanced-trade-ws.coinbase.com"
    async with websockets.connect(uri) as ws:
        subscribe_msg = {
            "type": "subscribe",
            "product_ids": ["BTC-USD", "ETH-USD"],
            "channel": "ticker"
        }
        await ws.send(json.dumps(subscribe_msg))

        async for message in ws:
            data = json.loads(message)
            await process_tick(data)
Enter fullscreen mode Exit fullscreen mode

2. Signal Generation
This is where most bots live or die. I use a combination of:

  • RSI (Relative Strength Index) for momentum
  • Bollinger Bands for volatility context
  • Volume-weighted moving averages
  • Order book imbalance ratios

None of these are magic. The edge comes from combining them properly and knowing when not to trade.

3. Order Execution + Risk Management
Every signal goes through a risk layer before an order fires. Position sizing, stop-loss placement, max daily drawdown limits — these aren't optional features. They're what keeps a bad run from becoming a catastrophic one.

The First Version Was a Disaster

I'll be honest. Version 1 of my bot turned $500 into $280 in about three weeks.

Here's what I got wrong:

Mistake #1: Backtesting on the Same Data I Developed On

I built my strategy by looking at Bitcoin charts. I tuned my RSI thresholds, my Bollinger Band periods, my stop-loss percentages — all while staring at the same data. When I backtested, it looked incredible. 85% win rate. Massive returns.

Then I deployed it to live markets and it immediately started losing.

The problem was data leakage and curve fitting. My parameters were optimized for data I'd already seen. The bot had essentially memorized the past rather than learned to predict the future.

The fix: walk-forward analysis and out-of-sample testing. Never look at your test data while building. Treat it like a final exam — you only get to see it once.

Mistake #2: Ignoring Market Regimes

Crypto markets aren't uniform. Sometimes they trend strongly. Sometimes they chop sideways for weeks. A momentum strategy that crushes it in trending markets gets destroyed in choppy conditions.

My first bot had no concept of market regime. It ran the same strategy regardless of conditions. Version 2 added a regime classifier — a simple HMM (Hidden Markov Model) that detected whether we were in a trending or mean-reverting environment, and switched strategy parameters accordingly.

from hmmlearn import hmm
import numpy as np

def detect_regime(returns: np.ndarray, n_states: int = 2) -> int:
    """Returns 0 for low-volatility/trending, 1 for high-volatility/choppy"""
    model = hmm.GaussianHMM(n_components=n_states, covariance_type="full", n_iter=100)
    returns_reshaped = returns.reshape(-1, 1)
    model.fit(returns_reshaped)
    hidden_states = model.predict(returns_reshaped)
    return hidden_states[-1]
Enter fullscreen mode Exit fullscreen mode

Mistake #3: No Slippage or Fee Modeling

Backtests are optimistic by nature. They assume you get exactly the price you want. Real markets don't work that way.

Coinbase charges fees. Market orders fill at the ask (if buying) or bid (if selling). High-frequency strategies that look great in backtests get demolished by the reality of fees and slippage.

I now model fees explicitly in every backtest and add a slippage buffer based on the asset's average bid-ask spread. A strategy that doesn't survive realistic fee modeling isn't a strategy — it's noise.

Mistake #4: Over-Leveraging

Coinbase Futures lets you trade with leverage. That sounds great when you're winning. It's catastrophic when you're wrong.

I watched my second account drop 40% in two days because I was using 5x leverage on a position that went against me. The math of loss recovery is brutal: a 40% loss requires a 67% gain just to break even.

My current rule: maximum 2x leverage, only on high-conviction setups, and always with a hard stop.

Mistake #5: Not Understanding Funding Rates

If you're trading perpetual futures (which most crypto traders do), funding rates are real money that moves in and out of your account every 8 hours. When funding rates are significantly positive, longs are paying shorts. When negative, shorts pay longs.

I've seen strategies that were net-profitable on price action but net-negative because they consistently held positions in the expensive direction. Now funding rate analysis is part of every trade decision.

Mistake #6: Manual Intervention During Drawdowns

The bot was designed to run autonomously. But the first time I saw it down $300 in a day, I panicked and manually closed positions. Then the market reversed and would have recovered most of the loss.

Emotional intervention is the single biggest source of performance degradation in algorithmic trading. If you don't trust your system enough to let it run through drawdowns, either the system isn't good enough or your risk sizing is too aggressive.

Mistake #7: No Position Correlation Management

I thought I was diversified because I was trading BTC, ETH, and SOL. What I didn't realize is that in crypto, these assets are highly correlated during risk-off events. When the market panics, everything falls together.

Running three "independent" positions that all drop simultaneously when fear spikes isn't diversification — it's concentration in disguise.

The fix: I now calculate position correlations before sizing, and reduce position sizes when correlations are high.

What Actually Works: The Production Setup

After a year of iteration, here's the system that's running profitably:

Timeframe: 4H primary signals, 1H for entry timing
Assets: BTC-USD, ETH-USD (high liquidity, tight spreads)
Strategy: Trend-following with momentum confirmation, regime-adaptive parameters
Risk: 1% portfolio risk per trade, 5% max daily drawdown, 2x max leverage
Infrastructure: Python on a 2-core VPS, PostgreSQL for data, Telegram alerts

The bot isn't always in the market. Some weeks it makes zero trades because the setup isn't right. That's intentional. Not trading is a valid position.

The Technical Stack in Detail

Data Layer

  • Coinbase Advanced Trade API for execution and market data
  • PostgreSQL for time-series storage (TimescaleDB extension for performance)
  • Redis for real-time signal caching and state management

Execution Layer

import requests

def send_telegram_alert(bot_token: str, chat_id: str, message: str):
    url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
    payload = {"chat_id": chat_id, "text": message, "parse_mode": "Markdown"}
    requests.post(url, json=payload)
Enter fullscreen mode Exit fullscreen mode

Honest Performance Numbers

  • 2023 Q4: +12% (trending market, bot performed well)
  • 2024 Q1: -4% (choppy conditions, multiple false signals)
  • 2024 Q2-Q3: +18% combined (regime detection improved)
  • 2024 Q4: +9%

That's roughly 35% over a year, beating buy-and-hold BTC on a risk-adjusted basis (lower max drawdown).

Resources

If you want to skip the expensive lessons I learned the hard way, I've documented the complete system — architecture, code patterns, backtesting methodology, and risk management framework — in a comprehensive guide: Crypto Trading Bot: Complete Implementation Guide

The biggest thing I wish someone had told me early: the bot is not the strategy. The bot is just an executor. Spend 80% of your time on strategy development and risk management, and 20% on the actual code.

Good luck building yours.

Top comments (0)