How Trade Execution Works
A concise end-to-end walkthrough of how OpenTrader goes from a market scan to a live bracket order on Binance.
The 5-layer pipeline
SCOUT → COO → BOSS → FINANCE → BOT API → BINANCE
Layer 1 — SCOUT scans the market (automatic, every 5 min)
Scout calls GET /scan?bot=ta_trend. The bot runs technical analysis (RSI, MACD, Bollinger Bands, volume ratio) across the full watchlist and returns a list of candidates that pass the filter.
Layer 2 — Signal submitted to COO
Scout calls POST /api/signal with a full JSON payload (symbol, price, SL %, TP %, TA checklist). The bot stores the signal in memory and automatically sends a Telegram message to BOSS with a summary and YES / NO prompt.
A 5-minute expiry is enforced from this point. If BOSS confirms after 5 minutes the signal is rejected and no trade is placed.
Layer 3 — BOSS confirms (human-in-the-loop)
BOSS replies 1-YES ETHUSDT or 0-NO ETHUSDT on Telegram. COO receives the reply, fetches the signal from GET /api/signal/ETHUSDT, and spawns the Finance agent.
Layer 4 — FINANCE runs AI confirmation
Finance receives the signal JSON from COO, performs an AI analysis, and outputs a structured result:
{
"confirm": true,
"ev": 32.5,
"confidence": 8,
"reason": "RSI oversold + MACD cross + volume spike",
"stop_loss_pct": 3.0,
"take_profit_pct": 6.5
}
Both conditions must be met to proceed:
| Criterion | Threshold | Result if not met |
|---|---|---|
| Expected value | ev > 25 | confirm=false, trade blocked |
| Confidence | confidence >= 8 | confirm=false, trade blocked |
Finance never calls /trade before outputting this JSON. This is a hard rule — not a guideline.
Layer 5 — Order execution on Binance
Finance calls POST /trade. The bot calculates position size from portfolio %, then places 3 orders simultaneously as a bracket:
BUY ETHUSDT ← entry (MARKET)
SELL ETHUSDT ← stop-loss (STOP_LIMIT) ┐ OCO pair
SELL ETHUSDT ← take-profit (LIMIT) ┘
After a successful fill, Finance calls POST /api/signal/ETHUSDT/confirm to remove the signal from memory. Scout can then signal again for the same symbol once the position closes.
After entry
| Event | Handled by |
|---|---|
| Price moves in favor | Trailing stop raises SL automatically (every 1 min) |
| Stop-loss hit | Binance closes automatically (OCO triggers) |
| Take-profit hit | Binance closes automatically (OCO triggers) |
| Manual close by BOSS | POST /api/closeall → cancel OCO → MARKET SELL |
Summary
Scout detects signal → Bot notifies BOSS via Telegram → BOSS confirms → Finance AI validates (EV + confidence) → Bot places bracket order on Binance → OCO pair manages SL/TP automatically.
Bracket order in detail
Binance Spot has no native bracket order type. OpenTrader simulates one by placing 3 separate orders in sequence.
Step 1 — Entry
MARKET BUY ETHUSDT
Fills immediately at the current market price. The next two orders are placed only after this fill is confirmed.
Step 2 — OCO (One-Cancels-the-Other)
A single OCO submission places two linked SELL orders simultaneously:
LIMIT_MAKER SELL @ tp_px ← take-profit (above entry)
STOP_LOSS_LIMIT SELL @ sl_px ← stop-loss (below entry)
When either order fills, Binance automatically cancels the other. The two orders share one orderListId — they cannot exist independently.
Example
Entry: BUY ETH @ $2,450 (MARKET)
Stop-loss: SELL ETH @ $2,377 (STOP_LOSS_LIMIT, -3%)
Take-profit: SELL ETH @ $2,622 (LIMIT_MAKER, +7%)
Price rises to $2,622 → TP fills → SL is auto-cancelled.
Price drops to $2,377 → SL triggers → TP is auto-cancelled.
How SL and TP behave during fast moves
Take-profit — reliable
LIMIT_MAKER only fills at the specified price or better. If price spikes through the TP level the order fills immediately with no adverse slippage.
Stop-loss — has slippage risk
STOP_LOSS_LIMIT uses two price levels:
stopPrice = sl_px ← trigger price
price = sl_px × 0.998 ← actual limit price (−0.2% buffer)
When stopPrice is touched, Binance places a LIMIT SELL at price. That limit order then waits in the order book for a fill.
Risk: If the coin gaps down faster than the 0.2% buffer — for example on a sudden news dump — the limit order sits below the market and does not fill. The position stays open and the loss continues to grow.
| Scenario | 0.2% buffer |
|---|---|
| BTC / ETH normal volatility | Sufficient |
| Altcoin on sudden bad news | Likely insufficient (2–5% gap) |
| Market-wide flash crash | Likely insufficient |
Adjusting the buffer
The buffer is set in app/adapters/binance.py line 125:
stop_limit_px = round(sl_px * (0.998 if is_buy else 1.002), pd)
Increase to 0.995 (0.5%) or 0.99 (1%) for coins with higher volatility. The trade-off: a wider buffer guarantees a fill but sells at a slightly worse price than sl_px.
Why OCO must be cancelled before manual close
The two OCO orders lock the coin balance on Binance. Attempting a MARKET SELL while OCO orders are active will fail with APIError(-2010): Account has insufficient balance — the coins are already committed to the pending SELL orders.
POST /api/closeall handles this correctly: it cancels the OCO first, waits for the balance to free up, then places the MARKET SELL.