Typed Event Bus
Expert advisors that grow past a single OnTick function usually end up with one of two shapes: a signal module that calls the risk module directly, which calls the execution module directly, with every layer needing to know about every other layer's interface; or one giant OnTick that does everything inline because splitting it out seemed like more trouble than it was worth. Both make the code harder to test in isolation and harder to change without touching three files for one new rule. This header gives both platforms a proper publish-subscribe bus. Any number of handlers subscribe to an event type; any code that publishes an event does not need to know who, if anyone, is listening. A risk module can react to a margin warning without the code that detected the margin warning importing the risk module at all - they only share the event bus and an agreed type id. Neither MQL4 nor MQL5 has function pointers or delegates, so subscribing means implementing a small interface, IEventHandler, and registering a pointer to the object. That is also why the bus never deletes what you give it: it cannot tell a stack object from a heap-allocated one, and guessing wrong either crashes on a double free or leaks a dead pointer that is never cleaned up. Ownership of every handler stays exactly where you created it - subscribe it, and delete it yourself when you are done, ideally after unsubscribing first. Delivery is synchronous: Publish() calls every matching handler before it returns, in subscription order, in the same call stack as the publisher. This is a code-structure tool, not a message queue - there is no buffering across ticks and no delivery guarantee beyond "every currently subscribed handler for this type gets called right now." A wildcard subscription (EVENTBUS_ALL_TYPES) is included for the one case that comes up in almost every project that adopts this pattern: a logger or audit trail that wants to see every event regardless of type, without maintaining its own list of every type id that might ever be published. Notes and limitations - The bus never owns or deletes handler pointers. Unsubscribe a handler before deleting it, and never publish after a handler you forgot to unsubscribe has been deleted - the bus has no way to detect a dangling pointer and will call straight into freed memory. - Delivery is synchronous and re-entrant with care needed: a handler that calls Publish() again from inside OnEvent will run nested, and a handler that unsubscribes itself or another handler mid-delivery is handled safely by this implementation (the in-flight delivery loop is bounded to the subscriber count captured at the start of that Publish call) but the ordering of any newly added subscription during delivery is not guaranteed for that same Publish call. - There is no event queue and no cross-tick buffering. If you need "handle this on the next tick" rather than "handle this now," queue it yourself and publish from OnTick. - SEventEnvelope's three payload fields are a pragmatic compromise for a language without generics or unions across value types. Document what each field means for each of your own type ids; the header cannot enforce it. - No money-per-point or contract-size calculation appears anywhere in this header on either platform - it is a generic messaging tool, so the tick- value/contract-size scaling this catalogue's house style calls out for money calculations does not apply here.
Script · MT5 · v1.0 · Free
About Typed Event Bus
Typed Event Bus is a script for MetaTrader 5. MQL source code included.
Files in the download: EventBus.mq5.mqh, EventBus.txt, EventBusDemo.ex5, EventBusDemo.mq5.
How to install
- Download the ZIP from your PolyMaria library and unzip it.
- In MetaTrader 5 open File → Open Data Folder, then go to MQL5 → Scripts.
- Copy the .mq5 file(s) there. Put any .mqh files in MQL5 → Include.
- Open the .mq5 file in MetaEditor and press Compile (F7) if MetaTrader does not show it.
- Drag the script onto a chart to run it once.
Tags: Buy/Sell Arrows · MT5 Script · MQL5 Source Code