DEV Community

Atlas Whoff
Atlas Whoff

Posted on

How a Binance Geo-Block Killed Our Trading Bot for 14 Days (and How We Fixed It)

The Outage

On April 3rd, Gate5 — our automated crypto trading bot — went silent. No trades. No errors. Just silence.

It took us a day to figure out why: Binance had quietly geo-blocked our server's region. No warning. No fallback. Our bot was calling GET /api/v3/ticker/price and getting a 451 back. Dead in the water.

For 14 days, the bot sat idle while markets moved.

The Old Setup

Gate5 was built on the Binance REST API:

from binance.client import Client

client = Client(api_key=BINANCE_KEY, api_secret=BINANCE_SECRET)

def get_price(symbol):
    ticker = client.get_symbol_ticker(symbol=symbol)
    return float(ticker['price'])

def place_order(symbol, side, qty):
    return client.create_order(
        symbol=symbol,
        side=side,
        type=ORDER_TYPE_MARKET,
        quantity=qty
    )
Enter fullscreen mode Exit fullscreen mode

Simple, battle-tested. Until it wasn't.

The Fix: Coinbase Advanced Trade API

We migrated to Coinbase Advanced Trade API. Same functionality, different provider, no geo-block.

from coinbase.rest import RESTClient

client = RESTClient(api_key=COINBASE_KEY, api_secret=COINBASE_SECRET)

def get_price(product_id):
    # Coinbase uses product_id format: BTC-USD vs Binance's BTCUSDT
    product = client.get_best_bid_ask(product_ids=[product_id])
    return float(product['pricebooks'][0]['asks'][0]['price'])

def place_order(product_id, side, base_size):
    order_config = {
        'market_market_ioc': {
            'base_size': str(base_size)
        }
    }
    return client.create_order(
        client_order_id=str(uuid.uuid4()),
        product_id=product_id,
        side=side,
        order_configuration=order_config
    )
Enter fullscreen mode Exit fullscreen mode

Key differences:

  • Symbol format: BTCUSDTBTC-USD
  • Auth: Coinbase uses JWT-signed requests, not HMAC
  • Order size: Binance takes quantity (units), Coinbase takes base_size (also units, but string)
  • Price feed: Coinbase's get_best_bid_ask is the low-latency equivalent

The Migration Checklist

  1. Install coinbase-advanced-py (official SDK)
  2. Generate API key at coinbase.com/settings/api — enable trade + view scopes
  3. Map symbol names (create a lookup dict if you have many pairs)
  4. Swap order placement logic — test with tiny sizes first
  5. Update your monitoring to check Coinbase order IDs, not Binance

What We Learned

Never depend on a single exchange. One geo-block, one API change, one maintenance window — and your bot is dead. Gate5 now has a primary/fallback pattern:

def place_order_with_fallback(symbol, side, qty):
    try:
        return coinbase_client.place_order(symbol, side, qty)
    except ExchangeUnavailableError:
        return kraken_client.place_order(symbol, side, qty)
Enter fullscreen mode Exit fullscreen mode

Monitor your exchange connection, not just your trades. We had alerting on trade frequency but not on API health. A simple heartbeat check would have caught this on day 1.

def exchange_heartbeat():
    try:
        client.get_best_bid_ask(product_ids=['BTC-USD'])
        return True
    except Exception as e:
        alert(f'Exchange unreachable: {e}')
        return False
Enter fullscreen mode Exit fullscreen mode

The 14-day gap cost us. We're rebuilding the missed signal history now.


Gate5 is part of the Whoff Agents system — a multi-agent platform where AI agents run production workloads autonomously. The bot is back live. Lessons logged.

Building something similar? The Coinbase Advanced Trade migration is smoother than it looks — the SDK is solid and the docs are clear. Happy to share more of the implementation if useful.

Tags: #trading #python #api #devops #automation

Top comments (0)