Egis Technical Journal – 2026-01-27

What I have done

  • Extended Signal Hook execution to support multiple bots
    • Changed the signal hook flow so that when a signal is accepted, it no longer resolves a single bot.
    • The system now finds all bots that share the same signal_key and executes order placement per bot, independently.
    • Designed the flow so that one bot failing (budget, exchange error, SL/TP failure) does not block other bots.
  • Introduced per-bot execution tracking for signal hooks
    • Added a dedicated persistence layer to track signal execution per bot, instead of treating a signal event as a single outcome.
    • Each bot now has its own lifecycle: queued → entry placed → SL/TP placed → completed / failed.
    • This gives real observability into “what happened to which bot” without relying on logs alone.
  • Improved Admin observability for signal hooks
    • Added a new metric on the Admin Dashboard showing total signal hook count.
    • Made the metric clickable, leading to a new Signal Hook management page.
    • Implemented pagination, filtering, and search so I can quickly answer:
      • What signals are coming in?
      • Are they valid / rejected / accepted?
      • Which signal keys are active?
      • When things fail, why?
  • Enhanced Bot Detail page with SL/TP visibility
    • Updated the Positions section to show Stop Loss and Take Profit if they exist, using internal position data only.
    • Ensured no reliance on derived or repairable exchange tables.
    • This makes the bot’s risk posture visible at a glance.
  • Unified price formatting across the Positions UI
    • Implemented a shared price formatter for:
      • Entry price
      • Current price
      • Closed price
      • Stop Loss
      • Take Profit
    • Added conditional precision:
      • Prices ≥ 1 keep existing formatting.
      • Prices < 1 show higher precision to avoid losing meaningful information (e.g. $0.3035 instead of $0.31).
    • Kept this strictly as a presentation-layer concern, without touching stored values or trading logic.
  • Added backend reconciliation when SL/TP is hit
    • On Bot Detail page load, the backend now checks whether any open internal positions have been closed on Binance due to SL or TP.
    • If exchange evidence confirms closure, internal positions are synced:
      • status updated to closed
      • closed price and timestamp synced
    • Implemented safeguards:
      • Only runs for Binance-connected bots (skips Paper Exchange).
      • Throttled to avoid excessive exchange calls.
      • Failure-safe: page still loads even if Binance is unavailable.
  • Hardened test and tooling discipline
    • Updated project rules to ensure php artisan config:clear runs before any tests, preventing config cache leaks.
    • Reinforced SQLite-only test enforcement and Binance mocking.
    • Fixed a Symfony error-rendering fatal (highlight_file) that was masking real backend errors, restoring proper debugging flow.

What I have learned

  • Signals are not single events; they are fan-out operations
    • A signal is not “accepted or rejected” globally.
    • It is accepted once, but executed many times, once per bot.
    • Treating signal execution as per-bot state instead of per-signal state dramatically improves correctness and debuggability.
  • Observability beats assumptions
    • Without per-bot execution records, debugging SL/TP, budget, or sizing issues becomes guesswork.
    • Persisting intent, execution, and failure reasons turns production debugging into simple inspection instead of log archaeology.
  • Internal truth must be actively defended
    • Saying “positions table is the source of truth” is not enough.
    • When the exchange mutates reality asynchronously (SL/TP triggers), the system must reconcile and update its internal truth deliberately.
    • Passive truth drifts; active reconciliation restores integrity.
  • Price formatting is not cosmetic in trading systems
    • Rounding small prices destroys information and can mislead decisions.
    • Precision must adapt to scale, not symbols or exchanges.
    • Keeping this logic strictly in the presentation layer avoids corrupting domain math.
  • Admin UX is a debugging tool
    • Dashboards and management pages are not just for monitoring—they are part of the engineering feedback loop.
    • When the UI can answer “what happened?” clearly, the system becomes easier to evolve safely.
  • Error handling infrastructure matters
    • A broken error renderer can hide real bugs and waste hours.
    • Ensuring the system fails gracefully and visibly is just as important as fixing the underlying logic.

Overall, this phase reinforced a core principle for Egis:
clarity of state > cleverness of logic.
Once the system clearly records what it believes and why, the rest becomes much easier to reason about and fix.