How I Built a Crypto Trading Bot (And Made It a Product)
This is the story of how I went from manually checking charts to running an automated trading system, and eventually packaging it as a product others can use.
Disclaimer: Trading involves risk. This bot doesn't guarantee profits. Past performance doesn't predict future results. Use at your own risk.
The Problem
I was spending 2-3 hours daily checking crypto charts, setting alerts, and executing trades. Most of my "strategy" was:
- Watch for price crossing moving averages
- Check RSI for overbought/oversold
- Look at volume for confirmation
- Execute trade on Binance
This is exactly the kind of repetitive, rule-based work that a bot can handle.
Architecture Overview
Market Data → Technical Analysis → Signal Generation → Risk Check → Execution → Monitoring
| | | | | |
Binance TA-Lib Strategy Engine Position Binance Telegram
WebSocket Indicators (configurable) Sizing API Alerts
Core Components
1. Market Data Feed
import asyncio
from binance import AsyncClient, BinanceSocketManager
async def start_socket(client, symbol):
bm = BinanceSocketManager(client)
ts = bm.kline_socket(symbol, interval='1h')
async with ts as stream:
while True:
msg = await stream.recv()
candle = msg['k']
if candle['x']: # Candle closed
await process_candle(symbol, candle)
Real-time WebSocket for live data, with REST API fallback for historical candles.
2. Technical Analysis
import talib
import numpy as np
def analyze(candles):
closes = np.array([c['close'] for c in candles], dtype=float)
signals = {
'sma_20': talib.SMA(closes, timeperiod=20)[-1],
'sma_50': talib.SMA(closes, timeperiod=50)[-1],
'rsi': talib.RSI(closes, timeperiod=14)[-1],
'macd': talib.MACD(closes)[0][-1],
'volume_sma': talib.SMA(
np.array([c['volume'] for c in candles], dtype=float),
timeperiod=20
)[-1]
}
return signals
I use TA-Lib for indicators. The strategy is configurable via YAML:
strategy:
name: "MA Crossover + RSI"
timeframe: "1h"
entry:
conditions:
- sma_20 > sma_50 # Golden cross
- rsi < 70 # Not overbought
- volume > volume_sma * 1.2 # Volume confirmation
exit:
conditions:
- sma_20 < sma_50 # Death cross
- rsi > 80 # Overbought
risk:
max_position_pct: 5 # Max 5% of portfolio per trade
stop_loss_pct: 3 # 3% stop loss
take_profit_pct: 9 # 9% take profit (3:1 ratio)
3. Risk Management
This is the most important part. The bot enforces:
- Maximum position size (% of portfolio)
- Stop-loss on every trade
- Maximum daily loss limit
- Maximum concurrent positions
- Cooldown period after losses
class RiskManager:
def __init__(self, config):
self.max_position_pct = config['max_position_pct']
self.max_daily_loss = config['max_daily_loss_pct']
self.daily_pnl = 0
def can_trade(self, signal, portfolio_value):
if self.daily_pnl < -self.max_daily_loss:
return False, "Daily loss limit reached"
position_size = portfolio_value * (self.max_position_pct / 100)
return True, position_size
4. Execution
from binance import Client
async def execute_trade(client, signal):
if signal['action'] == 'BUY':
order = await client.create_order(
symbol=signal['symbol'],
side='BUY',
type='MARKET',
quoteOrderQty=signal['size']
)
# Set stop-loss
await client.create_order(
symbol=signal['symbol'],
side='SELL',
type='STOP_LOSS_LIMIT',
stopPrice=signal['stop_loss'],
price=signal['stop_loss'] * 0.995,
quantity=order['executedQty']
)
return order
5. Monitoring
Every trade triggers a Telegram notification:
BUY BTCUSDT
Price: $67,432.50
Size: $500.00
Stop Loss: $65,409.53 (-3%)
Take Profit: $73,501.43 (+9%)
RSI: 45.2 | SMA20 > SMA50
Backtesting
Before running with real money, I backtested against 2 years of data:
def backtest(candles, strategy, initial_balance=10000):
balance = initial_balance
trades = []
for i in range(50, len(candles)):
window = candles[i-50:i]
signals = analyze(window)
if should_enter(signals, strategy):
# Simulate entry
entry_price = candles[i]['close']
# ... simulate trade with stop-loss and take-profit
return {
'total_return': (balance - initial_balance) / initial_balance * 100,
'win_rate': wins / total_trades * 100,
'max_drawdown': max_drawdown,
'sharpe_ratio': sharpe
}
Backtest results (2023-2024, BTC/USDT, 1h candles):
| Metric | Value |
|---|---|
| Total Return | +47% |
| Win Rate | 58% |
| Max Drawdown | -12% |
| Sharpe Ratio | 1.8 |
| Total Trades | 142 |
Note: Backtests are optimistic. Real-world performance is always lower due to slippage, fees, and timing.
What I Learned
- Risk management > strategy. A mediocre strategy with great risk management beats a great strategy with no risk management.
- Start with paper trading. Run the bot on testnet for at least 1 month.
- Keep strategies simple. MA crossover + RSI + volume is boring but works.
- Monitor constantly at first. Bugs in trading bots cost real money.
- Never all-in. Max 5% per position, always.
The Product
I packaged the bot with configurable strategies, backtesting tools, and deployment guides:
- Starter ($99): Bot code, 3 strategies, backtester, Telegram alerts, community support
- Professional ($299): All strategies, custom strategy builder, priority support, 1-on-1 setup call
Blog post with more details: Crypto Trading Bot Architecture
Questions about bot architecture or trading strategies? Happy to discuss in the comments. And again - trade responsibly, never invest more than you can afford to lose.
Top comments (0)