> ## Documentation Index
> Fetch the complete documentation index at: https://uncoded.ch/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Binance Test Coverage

> **Trust, but verify.** Binance is unCoded's reference exchange — and we treat it like one. Every release passes through a comprehensive, code-level test suite that exercises Binance integration end-to-end before any change reaches users. This page documents exactly what gets tested, why it matters, and what the current pass status looks like.
>
> The full test suite below runs as part of every release pipeline. Tests are categorized into 7 sections (A–G), covering everything from byte-exact regression checks to concurrency, error taxonomy, security, and live API fidelity.

***

## Why we test this thoroughly

Trading bots fail in subtle ways. A symbol-format bug, an unhandled error code, a misclassified network timeout, or a race condition during reconnection can each turn into real money lost. We've seen these failure modes in the wild — on other platforms — and we've designed our test suite specifically to catch them before they ship.

For Binance specifically, we maintain a **byte-identical regression policy**: the bot's behavior on Binance must match the pre-refactor reference exactly. Any change that would alter how an order is placed, how a symbol is resolved, how an error is classified, or how a fee is calculated has to either preserve existing behavior or be explicitly justified.

The tests below are not marketing fluff — they are the actual checks that run in CI, and they are documented here so you can see exactly what guarantees you get when running unCoded on Binance.

***

## A. Binance Regression Tests (byte-identical behavior)

These tests verify that the Binance integration behaves **exactly** as the original reference implementation. Every change must pass these tests unchanged.

### A.1 Profile configuration

| #     | Test                                                                   | Expected                                 | Status |
| :---- | :--------------------------------------------------------------------- | :--------------------------------------- | :----- |
| A.1.1 | Default exchange resolves to `binance`                                 | `EXCHANGE_ID` defaults to `binance`      | ✅ PASS |
| A.1.2 | Profile hostnames are exactly `api.binance.com` + `stream.binance.com` | Both hostnames present, no extras        | ✅ PASS |
| A.1.3 | Required credentials are exactly `apiKey` + `secret`                   | No passphrase, no UID, no extra fields   | ✅ PASS |
| A.1.4 | Default symbol is `BTCUSDT`                                            | Used when no symbol explicitly specified | ✅ PASS |
| A.1.5 | Fee token is `BNB`                                                     | Used for fee-discount tracking           | ✅ PASS |
| A.1.6 | Default quote asset is `USDT`                                          | Used as fallback for symbol parsing      | ✅ PASS |

### A.2 API options (must match pre-refactor values exactly)

| #     | Test                                        | Expected                                      | Status |
| :---- | :------------------------------------------ | :-------------------------------------------- | :----- |
| A.2.1 | `recvWindow` is exactly `60000` ms          | Maximum allowed by Binance API                | ✅ PASS |
| A.2.2 | `fetchCurrencies` is exactly `false`        | Avoids unnecessary auth-required call at boot | ✅ PASS |
| A.2.3 | `adjustForTimeDifference` is exactly `true` | Continuous clock-drift correction             | ✅ PASS |
| A.2.4 | `defaultType` is exactly `spot`             | Spot trading only — never margin or futures   | ✅ PASS |

### A.3 Adapter capabilities

| #     | Test                                                         | Expected                          | Status |
| :---- | :----------------------------------------------------------- | :-------------------------------- | :----- |
| A.3.1 | `watchTrades` capability is `true`                           | Live trade stream available       | ✅ PASS |
| A.3.2 | `watchOrders` capability is `true`                           | Live order updates via WS         | ✅ PASS |
| A.3.3 | `watchBalance` capability is `true`                          | Live balance updates via WS       | ✅ PASS |
| A.3.4 | Adapter is **not** REST-only                                 | WebSocket-driven execution active | ✅ PASS |
| A.3.5 | `privateGetAccount` exists on the underlying exchange object | Used for account balance fetches  | ✅ PASS |
| A.3.6 | `account()` has explicit Binance/Binance.US handling         | Correct routing for both venues   | ✅ PASS |

### A.4 Symbol roundtrip

| #     | Test                                         | Expected                       | Status |
| :---- | :------------------------------------------- | :----------------------------- | :----- |
| A.4.1 | `BTCUSDT` → internal format → `BTC/USDT`     | Symbol normalization works in  | ✅ PASS |
| A.4.2 | `BTC/USDT` → bot-internal format → `BTCUSDT` | Symbol normalization works out | ✅ PASS |

### A.5 Order placement contract

| #     | Test                                                            | Expected                                      | Status |
| :---- | :-------------------------------------------------------------- | :-------------------------------------------- | :----- |
| A.5.1 | LINK\_ID `x-PB3GHEZA-B-42-abc` preserved as-is in clientOrderId | Required for Binance broker rebate            | ✅ PASS |
| A.5.2 | `createOrder` receives full LINK\_ID in `newClientOrderId`      | Forwarded byte-exact to API                   | ✅ PASS |
| A.5.3 | `createOrder` receives `timeInForce=GTC` correctly              | Standard limit-order behavior                 | ✅ PASS |
| A.5.4 | `LIMIT_MAKER` order type → `postOnly=true`                      | Maker-only mode correctly mapped              | ✅ PASS |
| A.5.5 | `LIMIT_MAKER` order type → no `timeInForce` field               | Binance rejects LIMIT\_MAKER with timeInForce | ✅ PASS |

### A.6 Binance error code preservation

The bot must preserve all 8 critical Binance error codes for downstream handling:

| #     | Test                         | Code    | Meaning                                    | Status |
| :---- | :--------------------------- | :------ | :----------------------------------------- | :----- |
| A.6.1 | Error code `-2015` preserved | `-2015` | Invalid API-key or IP/permissions          | ✅ PASS |
| A.6.2 | Error code `-1013` preserved | `-1013` | Filter failure (PRICE\_FILTER / LOT\_SIZE) | ✅ PASS |
| A.6.3 | Error code `-2011` preserved | `-2011` | Unknown order / order not found            | ✅ PASS |
| A.6.4 | Error code `-1003` preserved | `-1003` | Too many requests (rate limited)           | ✅ PASS |
| A.6.5 | Error code `-2010` preserved | `-2010` | New order rejected                         | ✅ PASS |
| A.6.6 | Error code `-1021` preserved | `-1021` | Timestamp outside of recvWindow            | ✅ PASS |
| A.6.7 | Error code `-1121` preserved | `-1121` | Invalid symbol                             | ✅ PASS |
| A.6.8 | Error code `-2008` preserved | `-2008` | Invalid Api-Key ID                         | ✅ PASS |

### A.7 Error class → kind mapping

| #     | Test                                              | Expected                         | Status |
| :---- | :------------------------------------------------ | :------------------------------- | :----- |
| A.7.1 | `AuthenticationError` → kind `AUTH`, code `-2015` | Auth errors classified correctly | ✅ PASS |

**Section A summary: 28/28 tests passing ✅**

***

## B. Live Public-API Fidelity Tests

These tests confirm that what unCoded reads from Binance matches what Binance actually serves — byte-exact, no rounding, no transformation drift.

### B.1 Live exchangeInfo load

| #     | Test                                           | Expected                          | Status |
| :---- | :--------------------------------------------- | :-------------------------------- | :----- |
| B.1.1 | `exchangeInfo()` completes within 10 s timeout | Fast enough for boot-time checks  | ✅ PASS |
| B.1.2 | At least 100 markets returned                  | Real API, real markets loaded     | ✅ PASS |
| B.1.3 | `BTCUSDT` market is present in returned set    | Reference symbol always available | ✅ PASS |
| B.1.4 | `baseAsset` for BTCUSDT is exactly `BTC`       | Standard symbol structure         | ✅ PASS |
| B.1.5 | `quoteAsset` for BTCUSDT is exactly `USDT`     | Standard symbol structure         | ✅ PASS |

### B.2 Filter fidelity (vs. raw Binance API)

The bot fetches `tickSize`, `stepSize`, and `minNotional` from Binance. Each value must match the raw Binance response **byte-exactly** — any rounding or string-to-float conversion would cause silent precision loss in order placement.

| #     | Test                                                                                                       | Expected                              | Status |
| :---- | :--------------------------------------------------------------------------------------------------------- | :------------------------------------ | :----- |
| B.2.1 | `PRICE_FILTER.tickSize` byte-identical to raw `https://api.binance.com/api/v3/exchangeInfo?symbol=BTCUSDT` | Exact string match, no precision loss | ✅ PASS |
| B.2.2 | `LOT_SIZE.stepSize` byte-identical to raw API response                                                     | Exact string match                    | ✅ PASS |
| B.2.3 | `NOTIONAL.minNotional` byte-identical to raw API response                                                  | Exact string match                    | ✅ PASS |

### B.3 WebSocket connectivity

| #     | Test                                                                  | Expected                   | Status |
| :---- | :-------------------------------------------------------------------- | :------------------------- | :----- |
| B.3.1 | WebSocket connection to `stream.binance.com` establishes successfully | Live stream active         | ✅ PASS |
| B.3.2 | First trade event arrives within 30 s of connection                   | Stream is live and active  | ✅ PASS |
| B.3.3 | listenKey is created via `POST /api/v3/userDataStream`                | User data stream available | ✅ PASS |
| B.3.4 | listenKey is refreshed every 30 minutes                               | Prevents 60-minute expiry  | ✅ PASS |
| B.3.5 | HTTP 410 listenKey-expired response triggers reconnect                | Recovery handler works     | ✅ PASS |

**Section B summary: 13/13 tests passing ✅**

***

## C. Edge Case Tests

Real-world weirdness that has tripped up other platforms in the past — verified here for Binance specifically.

### C.1 Symbol parsing edge cases

| #     | Test                                                                                             | Expected                            | Status |
| :---- | :----------------------------------------------------------------------------------------------- | :---------------------------------- | :----- |
| C.1.1 | All known Binance quote assets parse correctly: USDT, USDC, BUSD, BTC, ETH, BNB, EUR, TRY, FDUSD | All quote assets recognized         | ✅ PASS |
| C.1.2 | Mixed-case input `btcusdt` normalized to uppercase `BTCUSDT`                                     | Case-insensitive symbol parsing     | ✅ PASS |
| C.1.3 | Symbol with separator `BTC-USDT` resolves to `BTCUSDT`                                           | Multiple separator formats accepted | ✅ PASS |
| C.1.4 | Symbol with separator `BTC/USDT` resolves to `BTCUSDT`                                           | Standard separator accepted         | ✅ PASS |
| C.1.5 | Symbol with separator `BTC_USDT` resolves to `BTCUSDT`                                           | Underscore separator accepted       | ✅ PASS |
| C.1.6 | Tag format `BTCUSDT:3` parsed as symbol + mode                                                   | Multi-pair tag format works         | ✅ PASS |

### C.2 Client order ID adaptation

Binance is the **only** supported exchange where the full LINK\_ID prefix must be preserved end-to-end (for the broker rebate program). Other exchanges strip or truncate the prefix.

| #     | Test                                                    | Expected                  | Status |
| :---- | :------------------------------------------------------ | :------------------------ | :----- |
| C.2.1 | Binance: `x-PB3GHEZA-B-42-abc` preserved as-is          | Full prefix preserved     | ✅ PASS |
| C.2.2 | Binance LINK\_ID survives buy / sell / cancel roundtrip | Same ID returned in fills | ✅ PASS |

### C.3 Price-tick and lot-size precision

| #     | Test                                                                         | Expected               | Status |
| :---- | :--------------------------------------------------------------------------- | :--------------------- | :----- |
| C.3.1 | Buy at 50000.123456 on BTCUSDT (tickSize=0.01) → price rounded to `50000.12` | Tick rounding correct  | ✅ PASS |
| C.3.2 | Quantity 0.000123456 on BTCUSDT (stepSize=0.00001) → rounded to `0.00012`    | Step rounding correct  | ✅ PASS |
| C.3.3 | Order below `minNotional` is rejected client-side before submission          | Avoid wasted API calls | ✅ PASS |

### C.4 Time synchronization

| #     | Test                                                                               | Expected                         | Status |
| :---- | :--------------------------------------------------------------------------------- | :------------------------------- | :----- |
| C.4.1 | Bot adjusts for 30-second clock drift without rejected orders                      | Time-difference adjustment works | ✅ PASS |
| C.4.2 | Bot recovers from `-1021` (timestamp out of recvWindow) by re-syncing and retrying | Auto-recovery active             | ✅ PASS |

**Section C summary: 13/13 tests passing ✅**

***

## D. Error Taxonomy Tests

Every Binance error must map cleanly into unCoded's standardized error kinds — so the rest of the bot can react correctly without parsing exchange-specific codes everywhere.

### D.1 Standardized error kinds

The bot defines 11 error kinds, each tested for definition:

| #      | Test                         | Status |
| :----- | :--------------------------- | :----- |
| D.1.1  | `AUTH` defined               | ✅ PASS |
| D.1.2  | `PERMISSION` defined         | ✅ PASS |
| D.1.3  | `RATE_LIMIT` defined         | ✅ PASS |
| D.1.4  | `INSUFFICIENT_FUNDS` defined | ✅ PASS |
| D.1.5  | `ORDER_NOT_FOUND` defined    | ✅ PASS |
| D.1.6  | `BAD_SYMBOL` defined         | ✅ PASS |
| D.1.7  | `INVALID_ORDER` defined      | ✅ PASS |
| D.1.8  | `TIMESTAMP_SYNC` defined     | ✅ PASS |
| D.1.9  | `NETWORK` defined            | ✅ PASS |
| D.1.10 | `SERVER_ERROR` defined       | ✅ PASS |
| D.1.11 | `UNKNOWN` defined            | ✅ PASS |

### D.2 Binance code → kind mapping

| #     | Binance error                                     | Maps to              | Status |
| :---- | :------------------------------------------------ | :------------------- | :----- |
| D.2.1 | `-2015 Invalid API-key`                           | `AUTH`               | ✅ PASS |
| D.2.2 | `-2011 Unknown order`                             | `ORDER_NOT_FOUND`    | ✅ PASS |
| D.2.3 | `-1003 Too many requests`                         | `RATE_LIMIT`         | ✅ PASS |
| D.2.4 | `-1021 Timestamp outside recvWindow`              | `TIMESTAMP_SYNC`     | ✅ PASS |
| D.2.5 | `-2010 New order rejected (insufficient balance)` | `INSUFFICIENT_FUNDS` | ✅ PASS |
| D.2.6 | `-1013 Filter failure`                            | `INVALID_ORDER`      | ✅ PASS |
| D.2.7 | `-1121 Invalid symbol`                            | `BAD_SYMBOL`         | ✅ PASS |
| D.2.8 | `-2008 Invalid Api-Key ID`                        | `AUTH`               | ✅ PASS |

### D.3 Network-level error classification

| #     | Test                                    | Expected                                     | Status |
| :---- | :-------------------------------------- | :------------------------------------------- | :----- |
| D.3.1 | `ECONNRESET` → kind `NETWORK`           | Connection reset classified correctly        | ✅ PASS |
| D.3.2 | `ETIMEDOUT` → kind `NETWORK`            | Network timeout classified correctly         | ✅ PASS |
| D.3.3 | DNS resolution failure → kind `NETWORK` | DNS errors classified correctly              | ✅ PASS |
| D.3.4 | HTTP 5xx → kind `SERVER_ERROR`          | Exchange-side errors distinguished from auth | ✅ PASS |

### D.4 Error body integrity

| #     | Test                                            | Expected                          | Status |
| :---- | :---------------------------------------------- | :-------------------------------- | :----- |
| D.4.1 | Wrapped error `body` is valid JSON              | Downstream parsers can rely on it | ✅ PASS |
| D.4.2 | Wrapped error `code` matches parsed `body.code` | Code is consistent end-to-end     | ✅ PASS |

**Section D summary: 25/25 tests passing ✅**

***

## E. Memory Safety Tests

Long-running processes that leak memory eventually crash. These tests verify that unCoded on Binance can run for weeks without resource buildup.

### E.1 Adapter lifecycle

| #     | Test                                                        | Expected                    | Status |
| :---- | :---------------------------------------------------------- | :-------------------------- | :----- |
| E.1.1 | `Adapter.close()` is a function                             | Explicit cleanup API exists | ✅ PASS |
| E.1.2 | Adapter has `_wsStopFlags` Map for cooperative cancellation | Stop signaling implemented  | ✅ PASS |
| E.1.3 | Stop-flags Map is empty on a fresh adapter                  | No leftover state           | ✅ PASS |
| E.1.4 | `close()` on idle adapter does not throw                    | Safe to call always         | ✅ PASS |
| E.1.5 | Multiple `close()` calls are idempotent                     | Calling close twice is safe | ✅ PASS |

### E.2 Symbol map bounds

| #     | Test                                             | Expected                        | Status |
| :---- | :----------------------------------------------- | :------------------------------ | :----- |
| E.2.1 | `_symbolMap` size is bounded by market count     | No accumulation across reloads  | ✅ PASS |
| E.2.2 | Rebuilding the symbol map clears old entries     | `map.clear()` called in rebuild | ✅ PASS |
| E.2.3 | Symbol map size after rebuild equals size before | No leak across rebuild cycles   | ✅ PASS |

### E.3 Polling loop cleanup

| #     | Test                                                           | Expected                 | Status |
| :---- | :------------------------------------------------------------- | :----------------------- | :----- |
| E.3.1 | `_runTradePollingLoop` checks `flag.stop` on every iteration   | Cooperative cancel works | ✅ PASS |
| E.3.2 | `_runBalancePollingLoop` checks `flag.stop` on every iteration | Cooperative cancel works | ✅ PASS |
| E.3.3 | `_runOrderPollingLoop` checks `flag.stop` on every iteration   | Cooperative cancel works | ✅ PASS |
| E.3.4 | All polling loops exit within one iteration of `close()`       | No orphaned timers       | ✅ PASS |

### E.4 24-hour soak test

| #     | Test                                                        | Expected                    | Status |
| :---- | :---------------------------------------------------------- | :-------------------------- | :----- |
| E.4.1 | RAM usage stable after 24 h continuous operation on BTCUSDT | \< 5% drift over 24 h       | ✅ PASS |
| E.4.2 | No file-descriptor leaks after 24 h                         | FD count stable             | ✅ PASS |
| E.4.3 | No socket leaks after 24 h                                  | TCP connection count stable | ✅ PASS |

**Section E summary: 15/15 tests passing ✅**

***

## F. Concurrency / Lifecycle Tests

What happens when the bot has to do multiple things at once — handle a price update during an order placement, recover from a failed call, restart the WebSocket while an order is in flight.

### F.1 Multi-instance coexistence

| #     | Test                                                                      | Expected                | Status |
| :---- | :------------------------------------------------------------------------ | :---------------------- | :----- |
| F.1.1 | Two adapter instances on different exchanges coexist without interference | Independent state       | ✅ PASS |
| F.1.2 | Two adapter instances on Binance with different sub-accounts coexist      | Independent credentials | ✅ PASS |

### F.2 Mutex protection

| #     | Test                                                                 | Expected                      | Status |
| :---- | :------------------------------------------------------------------- | :---------------------------- | :----- |
| F.2.1 | 3 concurrent calls to `_ensureMarkets()` resolve cleanly             | Mutex prevents double-load    | ✅ PASS |
| F.2.2 | After concurrent loads, `_marketsLoaded` flag is exactly `true` once | Single market load occurs     | ✅ PASS |
| F.2.3 | Concurrent `buy()` calls do not interleave order params              | Each call gets correct params | ✅ PASS |

### F.3 Failure isolation

| #     | Test                                                                         | Expected                            | Status |
| :---- | :--------------------------------------------------------------------------- | :---------------------------------- | :----- |
| F.3.1 | A failed `prices()` call does not poison the adapter                         | Adapter remains usable              | ✅ PASS |
| F.3.2 | After a `BadSymbol` error, subsequent `buy()` calls succeed                  | Error state does not propagate      | ✅ PASS |
| F.3.3 | WebSocket disconnect during order placement → order still completes via REST | Hybrid resilience                   | ✅ PASS |
| F.3.4 | listenKey expiry mid-order → order completes; listenKey re-acquired          | No order loss on listenKey rotation | ✅ PASS |

**Section F summary: 9/9 tests passing ✅**

***

## G. Security Tests

The bot handles real API keys for real money. Security tests are non-negotiable.

### G.1 Credential leak prevention

| #     | Test                                                                      | Expected                         | Status |
| :---- | :------------------------------------------------------------------------ | :------------------------------- | :----- |
| G.1.1 | API key is **not** present in any log line during adapter construction    | No leak on startup               | ✅ PASS |
| G.1.2 | API secret is **not** present in any log line during adapter construction | No leak on startup               | ✅ PASS |
| G.1.3 | API key is **not** present in any error message wrapper                   | No leak in error paths           | ✅ PASS |
| G.1.4 | API secret is **not** present in any error message wrapper                | No leak in error paths           | ✅ PASS |
| G.1.5 | Credentials are loaded from `process.env` only — never from the database  | No persistent credential storage | ✅ PASS |
| G.1.6 | No `SELECT ... api_key ...` queries exist in the codebase                 | Credentials never persisted      | ✅ PASS |

### G.2 SQL injection prevention

| #     | Test                                                                           | Expected                   | Status |
| :---- | :----------------------------------------------------------------------------- | :------------------------- | :----- |
| G.2.1 | All SQL queries in `index.js` use parameterized placeholders (`$1`, `$2`, ...) | No string-concat queries   | ✅ PASS |
| G.2.2 | No string-concatenation SQL in any service                                     | All services parameterized | ✅ PASS |

### G.3 Configuration safety

| #     | Test                                                                               | Expected                            | Status |
| :---- | :--------------------------------------------------------------------------------- | :---------------------------------- | :----- |
| G.3.1 | Unsupported `EXCHANGE_ID` triggers `process.exit(1)` before any DB or network call | Fail-fast on misconfig              | ✅ PASS |
| G.3.2 | Missing `BINANCE_API_KEY` triggers fatal startup error with clear message          | Clear failure mode                  | ✅ PASS |
| G.3.3 | Missing `BINANCE_API_SECRET` triggers fatal startup error with clear message       | Clear failure mode                  | ✅ PASS |
| G.3.4 | API key with withdrawal permission triggers a startup warning                      | User is alerted to misconfiguration | ✅ PASS |
| G.3.5 | API key without IP whitelist triggers a startup advisory                           | User reminded of best practice      | ✅ PASS |

### G.4 TOS gating

| #     | Test                                                                          | Expected                     | Status |
| :---- | :---------------------------------------------------------------------------- | :--------------------------- | :----- |
| G.4.1 | Bot does not place any order until `acceptTosAndStartBot=true` is set         | TOS gating active            | ✅ PASS |
| G.4.2 | License-token balance check happens before every buy attempt                  | Licensing enforcement active | ✅ PASS |
| G.4.3 | Bot stops opening new buy orders when `licenceTokens=0`                       | License-gating active        | ✅ PASS |
| G.4.4 | Existing open positions continue to be managed even when license is exhausted | Capital is never trapped     | ✅ PASS |

**Section G summary: 17/17 tests passing ✅**

***

## H. Trading Logic Tests (Binance-specific scenarios)

These tests exercise the actual trading logic against Binance's market behavior — placing orders, managing fills, calculating P\&L.

### H.1 Order placement

| #     | Test                                                                                          | Expected                     | Status |
| :---- | :-------------------------------------------------------------------------------------------- | :--------------------------- | :----- |
| H.1.1 | Limit buy order on BTCUSDT below current price → status `open`                                | Order accepted               | ✅ PASS |
| H.1.2 | Limit sell order on BTCUSDT above current price → status `open`                               | Order accepted               | ✅ PASS |
| H.1.3 | LIMIT\_MAKER buy order with price ≥ best ask is rejected with `-2010` and handled gracefully  | Maker-only enforcement works | ✅ PASS |
| H.1.4 | LIMIT\_MAKER sell order with price ≤ best bid is rejected with `-2010` and handled gracefully | Maker-only enforcement works | ✅ PASS |
| H.1.5 | Order with quantity below `LOT_SIZE.minQty` is rejected client-side                           | Pre-validation works         | ✅ PASS |
| H.1.6 | Order with notional below `MIN_NOTIONAL` is rejected client-side                              | Pre-validation works         | ✅ PASS |

### H.2 Order lifecycle

| #     | Test                                                            | Expected              | Status |
| :---- | :-------------------------------------------------------------- | :-------------------- | :----- |
| H.2.1 | Open order → partial fill event → state correctly updated       | Partial fills handled | ✅ PASS |
| H.2.2 | Open order → full fill event → moved to `fulfilledOrders` table | Persistence works     | ✅ PASS |
| H.2.3 | Open order → cancel → removed from `activeOrders` table         | Cancellation works    | ✅ PASS |
| H.2.4 | Order ID is consistent across REST and WebSocket events         | No duplicate tracking | ✅ PASS |

### H.3 Multi-symbol concurrent trading

| #     | Test                                                                              | Expected                  | Status |
| :---- | :-------------------------------------------------------------------------------- | :------------------------ | :----- |
| H.3.1 | 5 symbols active simultaneously, each with its own mode → all trade independently | Per-symbol isolation      | ✅ PASS |
| H.3.2 | Rate-limit counter is shared across all symbols (50 orders / 10 s)                | Global rate respected     | ✅ PASS |
| H.3.3 | Adding a new symbol via `tradePairs` config update is detected within 5 s         | Config-hash trigger works | ✅ PASS |
| H.3.4 | Removing a symbol cancels its open orders before unregistering                    | Clean removal             | ✅ PASS |

### H.4 BNB fee tracking

| #     | Test                                                                       | Expected                 | Status |
| :---- | :------------------------------------------------------------------------- | :----------------------- | :----- |
| H.4.1 | BNB price feed connects via WebSocket                                      | Live BNB tracking active | ✅ PASS |
| H.4.2 | Trade with BNB-paid fee → fee correctly converted to quote asset for P\&L  | Fee accounting accurate  | ✅ PASS |
| H.4.3 | BNB price update during a trade → next P\&L calculation uses updated price | Live updates applied     | ✅ PASS |

### H.5 Stop-loss and trailing stop-loss

| #     | Test                                                                         | Expected              | Status |
| :---- | :--------------------------------------------------------------------------- | :-------------------- | :----- |
| H.5.1 | Hard stop-loss at 5% triggers a market sell when price drops 5% below entry  | Stop-loss fires       | ✅ PASS |
| H.5.2 | Trailing stop-loss with 0.4% trail follows price up, never down              | Trail logic correct   | ✅ PASS |
| H.5.3 | TSL drop activation fires only once `sellActivateDistancePercentage` reached | Activation gate works | ✅ PASS |

### H.6 Time-based exit curves

| #     | Test                                                                       | Expected                   | Status |
| :---- | :------------------------------------------------------------------------- | :------------------------- | :----- |
| H.6.1 | Mode 1002 sell at 0.25% re-prices to 0.5% after 5 minutes                  | Curve advances on schedule | ✅ PASS |
| H.6.2 | Curve continues through all 15 stages (5 m → 200 m) without missing any    | Full curve traversal       | ✅ PASS |
| H.6.3 | Sell fills before next curve stage → curve cancelled, no further repricing | Clean termination          | ✅ PASS |

**Section H summary: 24/24 tests passing ✅**

***

## I. Mode-specific tests (all 9 pre-built modes on Binance)

Each pre-built mode is tested end-to-end on Binance.

| #     | Mode                                   | Test scenario                                                          | Status |
| :---- | :------------------------------------- | :--------------------------------------------------------------------- | :----- |
| I.1.1 | Mode 4 — BasicMode                     | 7 splits filled in sequence, all 7 sells placed at correct percentages | ✅ PASS |
| I.1.2 | Mode 1 — FullBullMarket                | 6-zone sell ladder, top zone at 30% target, all zones placed correctly | ✅ PASS |
| I.1.3 | Mode 2 — LongTimeLongMoreProfit        | 8 sell zones, top at 20%, volume distribution correct                  | ✅ PASS |
| I.1.4 | Mode 3 — LongTimeLong                  | 9 sell zones, top at 15%, all volumes match config                     | ✅ PASS |
| I.1.5 | Mode 5 — LowMoney                      | 2-split, \$3,000 capital, full grid fills                              | ✅ PASS |
| I.1.6 | Mode 6 — MinimalMoney                  | 1-split, \$1,500 capital, single 20% sell target placed                | ✅ PASS |
| I.1.7 | Mode 7 — Tsl2Sell                      | 2-split with TSL 0.4% / 0.6%, both trails activate correctly           | ✅ PASS |
| I.1.8 | Mode 1001 — MarketMaker (FDUSD)        | 10-target maker-only on BTCFDUSD, all orders post-only                 | ✅ PASS |
| I.1.9 | Mode 1002 — MarketMakerMinimal (FDUSD) | Single target with 15-stage time curve, full traversal verified        | ✅ PASS |

**Section I summary: 9/9 modes passing ✅**

***

## J. Static / Pre-deploy Verification Script

In addition to the runtime audit, every release runs a dedicated pre-deploy verification script: `verify-binance.js`.

This script performs the following checks against a live Binance public API connection (no credentials required):

```text theme={null}
=== BINANCE READINESS CHECK ===

[1] Profile config
  ✅ displayName = Binance
  ✅ ccxtId = binance
  ✅ requiredCreds = apiKey+secret
  ✅ hostnames includes api.binance.com
  ✅ hostnames includes stream.binance.com
  ✅ defaultQuoteAsset = USDT
  ✅ defaultSymbol = BTCUSDT
  ✅ feeToken = BNB
  ✅ recvWindow = 60000
  ✅ fetchCurrencies = false
  ✅ adjustForTimeDifference = true
  ✅ defaultType = spot

[2] Credentials (apiKey + secret only)
  ✅ No missing credentials
  ✅ apiKey loaded from BINANCE_API_KEY
  ✅ secret loaded from BINANCE_API_SECRET
  ✅ No password field expected
  ✅ No uid field expected

[3] Adapter instantiation
  ✅ exchangeId = binance
  ✅ NOT REST-only
  ✅ watchTrades capable
  ✅ watchOrders capable
  ✅ watchBalance capable
  ✅ fetchTickers capable

[4] Live public API + filter fidelity vs raw Binance
  Raw Binance:    tick=0.01000000 step=0.00001000 minN=5.00000000
  Adapter:        tick=0.01000000 step=0.00001000 minN=5.00000000
  ✅ BTCUSDT market present
  ✅ tickSize byte-exact to raw
  ✅ stepSize byte-exact to raw
  ✅ minNotional byte-exact to raw
  ✅ baseAsset = BTC
  ✅ quoteAsset = USDT
  Market count: 2400+
  ✅ Real markets loaded (>100)

[5] Symbol roundtrip
  ✅ BTCUSDT → BTC/USDT
  ✅ BTC/USDT → BTCUSDT
  ✅ ETHUSDT → ETH/USDT
  ✅ ETH/USDT → ETHUSDT
  ✅ BTCFDUSD → BTC/FDUSD
  ✅ BTC/FDUSD → BTCFDUSD

[6] Error code mapping
  ✅ -2015 → AUTH
  ✅ -2011 → ORDER_NOT_FOUND
  ✅ -1003 → RATE_LIMIT
  ✅ -1021 → TIMESTAMP_SYNC
  ✅ -2010 → INSUFFICIENT_FUNDS
  ✅ -1013 → INVALID_ORDER
  ✅ -1121 → BAD_SYMBOL

[7] Fee token tracking
  ✅ BNB price stream connects
  ✅ BNB → quote asset conversion math correct
  ✅ Fee discount mode detected when account has BNB

[8] Broker LINK_ID rebate compatibility
  ✅ x-PB3GHEZA-* prefix preserved
  ✅ newClientOrderId byte-exact in createOrder params

──────────────────────────────────────────
  RESULT: 50 / 50 PASS  ✅
  Binance integration READY for production
──────────────────────────────────────────
```

***

## Test Suite Summary

| Section   | Description                         | Tests   | Pass    | Fail  |
| :-------- | :---------------------------------- | :------ | :------ | :---- |
| **A**     | Binance regression (byte-identical) | 28      | 28      | 0     |
| **B**     | Live public-API fidelity            | 13      | 13      | 0     |
| **C**     | Edge cases                          | 13      | 13      | 0     |
| **D**     | Error taxonomy                      | 25      | 25      | 0     |
| **E**     | Memory safety                       | 15      | 15      | 0     |
| **F**     | Concurrency / lifecycle             | 9       | 9       | 0     |
| **G**     | Security                            | 17      | 17      | 0     |
| **H**     | Trading logic (Binance scenarios)   | 24      | 24      | 0     |
| **I**     | All 9 pre-built modes               | 9       | 9       | 0     |
| **J**     | Pre-deploy verification script      | 50      | 50      | 0     |
| **TOTAL** |                                     | **203** | **203** | **0** |

> **✅ Binance integration: 203/203 tests passing — production ready.**

***

***

## Continuous testing policy

These tests are not a one-time audit. They are run:

* **Before every release** — the entire suite must pass before a new bot version ships.
* **On every code change** that touches the trading-bot, exchange-adapter, or exchange-profiles modules.
* **Periodically against live Binance API** — to detect upstream API changes (new error codes, modified filter formats, deprecated endpoints) before they affect users.
* **As part of the pre-deploy verification** when users redeploy unCoded — the `verify-binance.js` script can be run as a smoke test after any update.

If a test starts failing, the release is blocked until the regression is fixed. There are no "we'll fix it in the next release" exceptions for Binance — it's the reference exchange, and the standard is byte-identical behavior preservation.

***

**Bottom line:** When you run unCoded on Binance, you're running the most thoroughly tested venue in the platform. Every commit to the trading-bot repo passes through 203 automated checks specifically designed to keep the Binance integration rock-solid.

***
