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
)
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
)
Key differences:
-
Symbol format:
BTCUSDT→BTC-USD - Auth: Coinbase uses JWT-signed requests, not HMAC
-
Order size: Binance takes
quantity(units), Coinbase takesbase_size(also units, but string) -
Price feed: Coinbase's
get_best_bid_askis the low-latency equivalent
The Migration Checklist
- Install
coinbase-advanced-py(official SDK) - Generate API key at coinbase.com/settings/api — enable
trade+viewscopes - Map symbol names (create a lookup dict if you have many pairs)
- Swap order placement logic — test with tiny sizes first
- 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)
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
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)