Egis Technical Journal — Signal Hook & Order Execution Debugging

1. Context & Goal

Project: Egis – private mobile-first trading system
Stack: Laravel 12, Inertia + React, shadcn/ui, Binance Futures Testnet
Core rule: Internal positions table is the single source of truth

Goal of this phase:

  • Introduce a new strategy Signal Hook
  • Accept trading signals from external platforms
  • Automatically place orders with:
    • Correct sizing (respect bot budget)
    • Correct side (long / short)
    • Proper Stop Loss (SL) and Take Profit (TP)
  • Maintain system safety, auditability, and determinism

2. Signal Hook Strategy (Design Decision)

Strategy definition

  • New strategy: signal_hook
  • Required field on bot: signal_key
  • A bot using this strategy listens for external signals via webhook

Why

  • Decouple signal generation from execution
  • Allow TradingView / custom systems to trigger Egis bots
  • Keep execution logic centralized and controlled

3. Signal Hook Webhook Design

Endpoint

POST /api/signal-hook

Payload format (wrapper required)

{
  "payloads": {
    "signal_key": "ZEN_PULSE_1MIN",
    "symbol": "AVNTUSDT.P",
    "side": "long",
    "price": "1.245",
    "stop_loss": "1.180",
    "take_profit": "1.360"
  }
}

Key rules

  • payloads wrapper is mandatory
  • pricestop_losstake_profit:
    • Accepted as strings
    • Must represent numeric values
    • Converted to decimals internally
  • symbol normalization:
    • If ends with .P → strip suffix
    • "AVNTUSDT.P" → "AVNTUSDT"
  • No CSRF (API route only)

4. Persistence: signal_hook_events

Every request is stored — no exceptions

Stored fields include:

  • bot_id (nullable)
  • signal_key
  • symbol (normalized)
  • side
  • pricestop_losstake_profit (decimal)
  • statusinvalid | rejected | accepted | failed | processed
  • error_message
  • raw_payload
  • processed_at
  • Result metadata (exchange order IDs, messages)

Reasoning

  • Webhooks are external and unreliable
  • Storage-first allows replay, debugging, and audit
  • Execution must never depend on ephemeral requests

5. Execution Flow (Signal → Order)

Step 1: Receive & Validate

  • Validate wrapper + payload
  • Resolve bot by signal_key
  • Strategy must be signal_hook
  • Store event
  • If accepted → dispatch job

Step 2: Job — PlaceOrderFromSignalHookEvent

Job responsibilities:

  1. Load signal event
  2. Ensure:
    • status = accepted
    • processed_at = null
  3. Load bot and exchange connection
  4. Compute order size safely
  5. Place entry order
  6. Confirm fill
  7. Place SL & TP orders
  8. Persist results

6. Critical Bug #1 — Wrong Order Size ($100 vs $10)

Symptom

  • Bot budget: $10
  • Order placed: $100

Root Cause

  • Signal Hook job used:
    • Hardcoded default size
    • Or fallback not tied to available budget

Fix

  • Signal Hook job must:
    • Compute available budget from internal positions
    • Clamp order size:requested_size_usd <= available_budget
    • If budget ≤ 0 → do not place order

Lesson

Signal-driven automation must NEVER bypass risk/budget logic used by manual trading.


7. Critical Bug #2 — SL / TP Not Placed

Symptom

  • Entry order placed successfully
  • No SL / TP orders appear on Binance

Investigation

  • Compared Egis implementation with previous working system (Samir)
  • Found SL/TP logic:
    • Either not executed
    • Or using incorrect Binance params
    • Or exiting early after entry fill

Correct Binance Futures Pattern (from Samir)

Important Binance rule

MARKET entry + SL/TP must be two-step

Correct flow

  1. Place ENTRY order (MARKET)
  2. Confirm fill (executed qty > 0)
  3. Place protective orders:
    • STOP / STOP_MARKET (SL)
    • TAKE_PROFIT / TAKE_PROFIT_MARKET (TP)
  4. Must be:
    • reduceOnly or closePosition=true
    • Correct side mapping

Side mapping

PositionSL / TP Order Side
LONGSELL
SHORTBUY

Key mistake

  • SL/TP code path was never reached after fill confirmation
  • Or parameters didn’t match Binance Futures expectations

Lesson

Protective orders are not “configuration”; they are separate, explicit actions.


8. Debugging Method Used (Important)

Instead of guessing:

  1. Read real logsstorage/logs/laravel.log
  2. Search for:
    • Entry order success
    • SL / TP placement attempts
    • Binance errors
  3. Add explicit logs:
    • “Placing SL”
    • “Placing TP”
    • Final signed params (signature redacted)
    • Binance responses

Lesson

If it’s not in logs, it didn’t happen.


9. Safety & Architecture Principles Reinforced

  • Internal positions is always authoritative
  • Exchange tables are derived and repairable
  • Orders are immutable facts
  • No “delete order”
  • Jobs must be idempotent
  • External success ≠ internal success
  • Store → then execute → then protect

10. Key Takeaways (For Future Rebuild)

  1. Webhook systems must be storage-first
  2. Signal ≠ execution
  3. Budget logic must be centralized
  4. SL/TP must be explicit, post-fill actions
  5. Never trust default sizing
  6. Logs are the real truth
  7. If it worked before, diff against the working system