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_keyand 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.3035instead of$0.31).
- Kept this strictly as a presentation-layer concern, without touching stored values or trading logic.
- Implemented a shared price formatter for:
- 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:clearruns 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.
- Updated project rules to ensure
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.
