Diagnostic Report — MA Crossover Bot

Prepared by Circuit Breaker Labs · Scope: Debug & Stabilize tier ($409) · Files reviewed: bot.py (~70 lines) + exchange integration layer

This is a sample deliverable built on a composite, fictional bot written to illustrate the class of bugs we see most often in retail crypto trading bots. It is not a real client's code. It's here so you can see the format and depth of what you get for $409 before you send us yours.

Symptoms reported

  1. Bot stops trading overnight with nothing in the console, no crash message.
  2. After a restart, the bot sometimes places two orders for what should have been one signal.
  3. Orders are occasionally rejected by the exchange for "invalid precision."

All three are explained below — each maps to a specific, fixable bug, not a vague "the bot is flaky" problem.

Bugs found

#SeverityBugSymptom it causes
1HighAPI credentials hardcoded in sourceSecret leaks the moment the file is shared, committed, or pasted anywhere
2CriticalPosition state kept only in memoryRestart forgets any open position → re-buys into it → symptom 2
3MediumMoving average divides by the fixed window, not the samples availableFires real signals off partial, meaningless data right after startup, no error
4HighOrder quantity computed with plain float divisionQuantity drifts past exchange precision → order rejected → symptom 3
5Mediumprint() used instead of real loggingNo timestamps, nothing persisted — the trail is gone once the terminal closes
6CriticalBare except: pass around every order attemptRate limits, insufficient funds, invalid orders, and real bugs all vanish silently
7CriticalNo error handling around the main polling loopA single dropped connection kills the entire process → symptom 1
8MediumFixed 1-second poll, no rate-limit awarenessGuarantees throttling under real volume, which then hits bug 6 and disappears
9MediumNo signal handling for Ctrl+C / process stopIn-memory state (see bug 2) is lost on any shutdown, planned or not
10HighNo idempotency key on order submissionA retried request after a timeout can't tell it already succeeded — can double-submit

10 bugs found. 3 Critical, 4 High, 3 Medium. Bugs 2, 6, and 7 are the critical ones — between them they explain all three reported symptoms.

The fix that shows up most often

Bug 6 — a bare except: pass — is the single most common failure pattern across the bots we've reviewed. It looks harmless. It is not: it means every real error the exchange can throw (rate limits, insufficient funds, invalid orders) is treated identically to "nothing happened," with no log line, no retry, and no way for the trader to ever find out.

#  before/bot.py
def place_order(side, symbol, amount):
    global position_open
    try:
        price = client.get_ticker(symbol)["last"]
        qty = amount / price
        order = client.create_order(symbol, side, qty)
        print(f"Order placed: {order}")
        position_open = (side == "buy")
    except:
        pass   # <-- every failure, real or trivial, disappears here


#  after/bot.py
def place_order(client, state, side, symbol, amount_usd, signal_id):
    client_order_id = f"{signal_id}-{side}"
    if state.get("last_client_order_id") == client_order_id:
        logger.info("Order for signal %s already submitted; skipping duplicate.", signal_id)
        return
    try:
        ticker = call_with_retry(client.get_ticker, symbol)
        precision = client.get_precision(symbol)
        qty = quantity_for(amount_usd, ticker["last"], precision)
        order = call_with_retry(client.create_order, symbol, side, qty, client_order_id=client_order_id)
        logger.info("Order placed: %s", order)
        state["position_open"] = side == "buy"
        state["last_client_order_id"] = client_order_id
        save_state(state)
    except InsufficientFunds as exc:
        logger.error("Insufficient funds for %s %s: %s -- skipping this signal.", side, symbol, exc)
    except InvalidOrder as exc:
        logger.error("Order rejected as invalid for %s %s: %s -- skipping this signal.", side, symbol, exc)
    except ExchangeError:
        logger.exception("Unrecoverable exchange error placing %s order for %s", side, symbol)

Fixes applied

How this was verified

Not just "it compiles." A test suite reproduces each symptom against the original code first — proving the bugs are real — then proves the same scenario now behaves correctly against the fixed code, including a direct regression test that throws three consecutive dropped connections at the stabilized bot's main loop and confirms it keeps running instead of dying.

15 passed in 0.22s

What a real engagement looks like

For your bot, this same process applies: full read-through, a report like this one naming every bug with severity and root cause, then — at the Debug & Stabilize tier and above — the fixes applied in place against your actual code and exchange integration, with tests covering the failure paths that used to crash silently. If your bot uses ccxt, python-binance, or a native exchange SDK, the same error-handling and retry patterns shown here apply directly.

Send your bot's code and get a report like this one

Diagnostic Sprint from $149. Debug & Stabilize (fixes included) is $409.

Get a diagnostic →