[Concepts]
This page
📊 Signals & Trade Spec
This document details the exact specifications, JSON validation schemas, and internal translation logic that occurs when an external trade signal (such as a TradingView® alert or Email parser) is ingested by the Hoox Gateway and mapped to an active exchange order.
1. Webhook Signal Ingestion Schema
Every signal received by the public gateway at /webhook must contain a valid, authenticated JSON payload. Below is the strict TypeScript interface and parameter schema validated by the gateway's validation middleware:
export interface WebhookSignal {
apiKey: string; // Authentication token matching CONFIG_KV webhooks:api_key
exchange: "binance" | "bybit" | "mexc"; // Target exchange router
action: "LONG" | "SHORT" | "CLOSE_LONG" | "CLOSE_SHORT"; // Position intent
symbol: string; // Asset symbol (e.g. "BTCUSDT", "ETHUSDT")
quantity: number; // Order size (amount of asset or contracts)
leverage?: number; // Optional leverage multiplier (default: 1, max: 125)
idempotencyKey?: string; // Optional unique signature for dedup (auto-generated if omitted)
price?: number; // Optional limit price (default: market price)
/**
* When true, execute on the exchange testnet/sandbox (Binance Futures
* testnet, Bybit testnet). MEXC has no public REST sandbox and rejects
* the request. Prefer dedicated BINANCE_TESTNET_* / BYBIT_TESTNET_* secrets.
*/
test?: boolean;
}
Parameter Rules & Type Constraints
| Parameter | Type | Required | Constraints |
|---|---|---|---|
apiKey | string | Yes | Must match the encrypted webhooks:api_key hash in your CONFIG_KV namespace |
exchange | string | Yes | One of: binance, bybit, mexc — must match a configured exchange router |
action | string | Yes | One of: LONG, SHORT, CLOSE_LONG, CLOSE_SHORT |
symbol | string | Yes | Parsed and standardized — BTC-USDT, BTC_USDT, and btc/usdt all become BTCUSDT |
quantity | number | Yes | Must be greater than zero; checked against exchange minimum order size |
leverage | number | No | Range: 1 to 125 depending on exchange margin profiles; defaults to 1 (spot) |
idempotencyKey | string | No | If omitted, auto-generated including live/test mode so modes do not dedupe each other |
price | number | No | Limit price; defaults to current market price if omitted |
test | boolean | No | true → testnet for Binance/Bybit; MEXC returns TEST_TRADING_UNSUPPORTED |
Test trading
| Exchange | Supports test: true | API host when enabled |
|---|---|---|
| Binance | Yes | testnet.binancefuture.com |
| Bybit | Yes | api-testnet.bybit.com |
| MEXC | No | Rejected (no public REST sandbox) |
| Side effect | Live | Test (test: true) |
|---|---|---|
| D1 trade status | EXECUTED | TEST_EXECUTED |
| D1 position id | {ex}-{sym}-{side} | {ex}-testnet-{sym}-{side} |
| Telegram label | exchange name | {exchange} [TEST] |
| Analytics exchange blob | bybit | bybit:test |
| WebSocket DO | optional | always REST testnet |
| Agent risk loop | manages OPEN | skips *-testnet-* ids |
| Dashboard stats | counted | excluded from headlines |
Credentials: prefer BINANCE_TESTNET_KEY_BINDING / BINANCE_TESTNET_SECRET_BINDING and BYBIT_TESTNET_*. If unset, live bindings are used (warning logged).
Full operator guide: Test Trading.
2. Dynamic Payload Translation & Side Mapping
Exchanges do not understand actions like LONG or SHORT. They process order instructions in terms of Side (BUY or SELL) and PositionSide (LONG or SHORT for multi-margin hedge modes).
The trade-worker parses the incoming signal and translates the business logic into exchange-specific API calls:
A. Translation Table (One-Way Margin / Spot)
| Action | Translated Exchange Side | Operation Type |
|---|---|---|
LONG | BUY | Opens a long position |
SHORT | SELL | Opens a short position |
CLOSE_LONG | SELL | Closes an existing long (reduceOnly) |
CLOSE_SHORT | BUY | Closes an existing short (reduceOnly) |
B. Hedge-Mode PositionSide Mapping
When running in hedge mode (supported on Bybit and Binance futures), both LONG and SHORT positions can coexist:
Hedge Mode:
LONG PositionSide = LONG → BUY opens LONG, SELL closes LONG
SHORT PositionSide = SHORT → SELL opens SHORT, BUY closes SHORT
One-Way Mode:
BUY always opens/increases, SELL always closes/reduces
C. Dynamic Position Resolution
When the action is CLOSE, the trade-worker automatically performs a sub-millisecond edge check:
- Queries your local D1 transaction ledger to resolve the active position direction for the symbol.
- If no position is tracked locally, it performs a real-time portfolio balance check against the exchange's private position endpoint.
- Automatically sets the order quantity to match your current open exposure, ensuring a perfect, slippage-free execution that flattens the position without leaving residual micro-contracts.
3. Leverage Scaling & Order Math
If the signal includes a leverage parameter greater than 1 (e.g., "leverage": 10), the trade-worker automatically executes a secure margin transition sequence:
- Set Margin Mode: Configures the symbol's margin structure (Isolated vs. Cross) via the exchange API, matching your manifest defaults.
- Set Leverage Coefficient: Submits a leverage update payload to the exchange prior to routing the order.
- Calculate Collateral: If the order size is defined in USDT terms, the worker scales the execution quantity mathematically: $$\text{Contract Quantity} = \frac{\text{Order Size (USDT)} \times \text{Leverage}}{\text{Current Market Price}}$$
- Precision Rounding: Automatically rounds the calculated quantity down to match the exchange's strict asset decimal precision requirements, preventing API rejects.
Precision Table by Exchange
| Exchange | Price Precision | Quantity Precision | Min Order Size |
|---|---|---|---|
| Binance | Varies by symbol | Varies by symbol | ~$10 equivalent |
| Bybit | 0.1 – 0.001 | 3–6 decimal places | Varies by tier |
| MEXC | 0.1 – 0.00000001 | 2–8 decimal places | ~$5 equivalent |
4. D1 Database Transaction Ledger
Every filled order is persistently written to your globally distributed edge SQLite table. The schema ensures a clean audit log:
CREATE TABLE trades (
id TEXT PRIMARY KEY, -- UUID v4 generated by trade-worker
request_id TEXT NOT NULL, -- Distributed trace ID from gateway
exchange TEXT NOT NULL, -- 'bybit', 'binance', or 'mexc'
symbol TEXT NOT NULL, -- e.g. 'BTCUSDT'
action TEXT NOT NULL, -- 'LONG', 'SHORT', or 'CLOSE'
side TEXT NOT NULL, -- 'BUY' or 'SELL' (exchange-side)
quantity REAL NOT NULL, -- Filled asset quantity
price REAL NOT NULL, -- Execution entry price (USDT)
leverage INTEGER DEFAULT 1, -- Applied leverage multiplier
fee REAL NOT NULL, -- Exchange transaction fees (USDT)
order_id TEXT NOT NULL, -- Exchange-provided order hash
status TEXT NOT NULL, -- 'Filled', 'Rejected', 'Failed', 'Partial'
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE positions (
id TEXT PRIMARY KEY,
symbol TEXT NOT NULL UNIQUE,
side TEXT NOT NULL, -- 'LONG' or 'SHORT'
quantity REAL NOT NULL,
entry_price REAL NOT NULL,
mark_price REAL, -- Last known market price
leverage INTEGER DEFAULT 1,
unrealized_pnl REAL DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
You can query the ledger at any time from your local terminal:
# Query the 10 most recent trades in your D1 database
hoox db query "SELECT created_at, exchange, symbol, action, price, quantity FROM trades ORDER BY created_at DESC LIMIT 10"
# Check open positions
hoox db query "SELECT symbol, side, quantity, entry_price FROM positions WHERE quantity > 0"
5. Queue Failover & Guaranteed Delivery
When the exchange API returns an error (timeout, rate limit, HTTP 5xx), the gateway automatically enqueues the trade payload into Cloudflare® Queues for guaranteed delivery:
| Retry Attempt | Delay | Trigger Condition |
|---|---|---|
| 1 | Immediate | First failure |
| 2 | 30 seconds | Network timeout |
| 3 | 1 minute | Rate limit (429) |
| 4 | 5 minutes | Exchange error (502/503) |
| 5 | 15 minutes | Extended maintenance |
| 6 | 30 minutes | Final retry before logging as failed |
After max retries, the trade is logged to D1 with status = 'Failed' — not lost, but visibly flagged for manual review.
Tip
By utilizing time-series logging via Cloudflare® Analytics Engine, Hoox tracks
the exact execution duration of each pipeline step. You can audit the latency
breakdown (e.g., Gateway auth took 1.2ms, Trade-worker signing took 0.8ms,
Bybit API roundtrip took 18.5ms) directly in your Next.js dashboard!
🔗 Next Steps
- Autonomous AI Risk Management — Learn how agent-worker tracks D1 entries to manage trailing stops and drawdowns.
- CLI Reference Manual — Review commands to manage D1 tables, perform dry runs, and tail logs.
- Error Models & Status Codes — Understand all gateway error responses.