Passive Income

The Complete Guide to DCA Bots: Dollar-Cost Averaging Automation

DCA (Dollar-Cost Averaging) bots automate the most proven long-term crypto investment strategy. Learn how to build and configure a DCA bot that buys BTC and ETH on schedule, regardless of market conditions.

A
AI Agents Hubยท2026-02-28ยท5 min readยท870 words

Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.

Why DCA Is the Most Underrated Crypto Strategy

Timing the market is hard. Even professional traders consistently fail at it. Dollar-Cost Averaging (DCA) sidesteps this problem entirely: you invest a fixed amount at regular intervals, regardless of price.

The math works because:

  • You buy more when prices are low
  • You buy less when prices are high
  • You average down your cost basis over time
  • You remove emotion from the equation entirely

DCA Bitcoin from January 2018 to December 2023 (through two bear markets): +312% return vs. trying to time entries would have required near-perfect execution to outperform.

Building a Basic DCA Bot

import ccxt
import schedule
import time
from datetime import datetime
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('DCA Bot')

class DCABot:
    def __init__(self, exchange_id: str, api_key: str, secret: str):
        exchange_class = getattr(ccxt, exchange_id)
        self.exchange = exchange_class({
            'apiKey': api_key,
            'secret': secret,
            'enableRateLimit': True,
        })
        self.orders_log = []
    
    def buy(self, symbol: str, usd_amount: float):
        """Execute a DCA buy order"""
        try:
            # Get current price
            ticker = self.exchange.fetch_ticker(symbol)
            current_price = ticker['last']
            
            # Calculate quantity (most exchanges need quantity in base currency)
            quantity = usd_amount / current_price
            
            # Round to exchange requirements
            market = self.exchange.market(symbol)
            quantity = self.exchange.amount_to_precision(symbol, quantity)
            
            # Place market buy order
            order = self.exchange.create_market_buy_order(
                symbol=symbol,
                amount=quantity,
                params={'quoteOrderQty': usd_amount}  # Binance: buy exactly $X worth
            )
            
            logger.info(f"โœ… DCA BUY: {quantity} {symbol.split('/')[0]} @ ${current_price:,.2f}")
            logger.info(f"   Order ID: {order['id']}")
            
            self.orders_log.append({
                'timestamp': datetime.now().isoformat(),
                'symbol': symbol,
                'amount_usd': usd_amount,
                'price': current_price,
                'quantity': float(quantity),
                'order_id': order['id'],
            })
            
            return order
            
        except Exception as e:
            logger.error(f"DCA buy failed for {symbol}: {e}")
            raise

# Initialize bot
bot = DCABot('binance', API_KEY, API_SECRET)

# Schedule DCA purchases
DCA_SCHEDULE = [
    {'symbol': 'BTC/USDT', 'amount': 100, 'frequency': 'weekly', 'day': 'monday'},
    {'symbol': 'ETH/USDT', 'amount': 50,  'frequency': 'weekly', 'day': 'monday'},
    {'symbol': 'SOL/USDT', 'amount': 25,  'frequency': 'weekly', 'day': 'wednesday'},
]

def run_dca_btc():
    bot.buy('BTC/USDT', 100)

def run_dca_eth():
    bot.buy('ETH/USDT', 50)

# Every Monday at 12:00 UTC
schedule.every().monday.at("12:00").do(run_dca_btc)
schedule.every().monday.at("12:01").do(run_dca_eth)

while True:
    schedule.run_pending()
    time.sleep(60)

Advanced DCA: Value Averaging

Value Averaging is DCA's smarter cousin โ€” you invest more when prices are low and less when they're high:

class ValueAveragingBot:
    """
    Value Averaging: maintain a target portfolio growth rate.
    If portfolio grew less than target โ†’ buy more.
    If portfolio grew more than target โ†’ buy less (or sell).
    """
    
    def __init__(self, target_monthly_growth_usd: float):
        self.target_monthly_growth = target_monthly_growth_usd
        self.target_value = 0
        self.month = 0
    
    def calculate_va_buy_amount(
        self, 
        current_portfolio_value: float,
        base_monthly_amount: float = 100
    ) -> float:
        """
        Calculate how much to buy this period.
        Returns positive = buy, negative = sell
        """
        self.month += 1
        self.target_value = self.month * self.target_monthly_growth
        
        # How much do we need to invest to hit target?
        required_investment = self.target_value - current_portfolio_value
        
        # Cap at 3x normal DCA amount (don't over-invest in crashes)
        max_buy = base_monthly_amount * 3
        
        # Never invest more than 3x base or sell more than full position
        return max(-current_portfolio_value, min(required_investment, max_buy))
    
def value_average_buy(bot: DCABot, symbol: str, va_bot: ValueAveragingBot):
    portfolio_value = get_portfolio_value(symbol)
    amount = va_bot.calculate_va_buy_amount(portfolio_value)
    
    if amount > 10:  # Minimum $10 buy
        logger.info(f"VA Buy: ${amount:.2f} (portfolio: ${portfolio_value:.2f}, target: ${va_bot.target_value:.2f})")
        bot.buy(symbol, amount)
    elif amount < -50:  # Only sell if > $50 above target
        logger.info(f"VA Sell: ${abs(amount):.2f} โ€” portfolio exceeding target by {abs(amount):.2f}")
        # sell_position(symbol, abs(amount))

Sentiment-Adjusted DCA

Combine DCA with Fear & Greed to buy more in fear:

import requests

def get_fear_greed_index() -> int:
    """Returns 0-100 (0=extreme fear, 100=extreme greed)"""
    response = requests.get('https://api.alternative.me/fng/?limit=1')
    return int(response.json()['data'][0]['value'])

def sentiment_adjusted_dca_amount(base_amount: float) -> float:
    """
    Adjust DCA amount based on market sentiment.
    Extreme fear โ†’ buy 2x. Extreme greed โ†’ buy 0.5x.
    """
    fg = get_fear_greed_index()
    
    if fg <= 20:       # Extreme Fear
        multiplier = 2.0
    elif fg <= 40:     # Fear
        multiplier = 1.5
    elif fg <= 60:     # Neutral
        multiplier = 1.0
    elif fg <= 80:     # Greed
        multiplier = 0.75
    else:              # Extreme Greed
        multiplier = 0.5
    
    adjusted = base_amount * multiplier
    logger.info(f"Fear & Greed: {fg} โ†’ DCA multiplier {multiplier}x โ†’ ${adjusted:.2f}")
    return adjusted

Tracking DCA Performance

def calculate_dca_performance(orders: list[dict], current_price: float) -> dict:
    """Calculate current P&L from DCA orders"""
    
    total_invested = sum(o['amount_usd'] for o in orders)
    total_quantity = sum(o['quantity'] for o in orders)
    current_value = total_quantity * current_price
    avg_buy_price = total_invested / total_quantity
    
    unrealized_pnl = current_value - total_invested
    roi_pct = (current_value - total_invested) / total_invested * 100
    
    return {
        'total_invested': total_invested,
        'total_quantity': total_quantity,
        'avg_buy_price': avg_buy_price,
        'current_value': current_value,
        'unrealized_pnl': unrealized_pnl,
        'roi_pct': roi_pct,
        'num_orders': len(orders),
    }

# Example output:
# Total invested: $5,200
# Average buy price: $52,847
# Current value: $7,150 (+$1,950, +37.5%)
# Orders executed: 52 (weekly for 1 year)

DCA Configuration Guide

| Strategy | Asset | Amount | Frequency | Best For | |----------|-------|--------|-----------|---------| | Conservative | BTC 80%, ETH 20% | $100/week | Weekly | Risk-averse long-term | | Balanced | BTC 60%, ETH 30%, SOL 10% | $200/week | Weekly | Moderate risk | | Aggressive | ETH 40%, SOL 30%, BTC 30% | $300/week | Weekly | Higher risk, alt exposure | | Sentiment-adjusted | BTC 70%, ETH 30% | $100-200/week | Weekly | Active but disciplined |

DCA is boring. That's the point. The bots that generate the best long-term returns for most people aren't the clever arbitrage systems โ€” they're the simple, consistent DCA bots that run for years.

Related Articles