2,9 КиБ
2,9 КиБ
ADR-003: Behavior Injection via Function Pointers for Dynamic Mocking
Status: Accepted
Context
In high-reliability institutional algorithmic trading engines, execution modules must be validated against unexpected terminal and broker behaviors (Chaos Engineering):
- Successive requotes during low liquidity
- Order rejections and price slippages
- Gateway/network disconnects (
TRADE_RETCODE_CONNECTION) - Custom Depth of Market (DOM) snapshots
In languages like C++ or C#, mocking frameworks (e.g., GoogleMock, Moq) use dynamic proxies, closures/lambdas, or template metaprogramming to configure mock responses on the fly.
MQL5 has strict language constraints:
- No native lambda functions or true closure captures.
- No reflection or runtime type introspection.
- No compile-time mock generation libraries.
Previous iterations of the test harness relied solely on static tick arrays (MockTick.injected_error), which required constructing rigid multi-tick datasets to test dynamic scenarios like retry loops.
Decision
Use C-style function pointers (typedef) to implement Behavior Injection directly into CSyntheticEngine:
- Define delegate signatures in
BehaviorDelegates.mqhmirroring theIMarketEnvironmentinterface methods. - Provide setter methods in
CSyntheticEngine(e.g.,MockOrderSend(),MockMarketBookGet()) to inject delegate function pointers at runtime. - Use a Dual-Mode Priority Resolution:
- Behavior Injection Hook (Highest Priority): If a function pointer is non-NULL, execute it immediately.
- Tick-Driven Simulation (Fallback): If no delegate is assigned, fall back to sequential
MockTickreplay. - Default Safe State: If no ticks are loaded and no behavior is set, return safe defaults.
- For stateful behaviors across successive calls (such as counting requote retries), use local static variables inside standalone behavior functions (
BehaviorLibrary.mqh).
Consequences
Positive
- Dynamic Chaos Engineering: Behaviors can be hot-swapped mid-flight in unit tests without recreating tick arrays or restarting the test environment.
- Zero Overhead in Production:
CLiveEnvironmentcontinues to delegate directly to global MT5 functions via the scope resolution operator (::), unaffected by function pointer indirection. - Clean Architecture & Decoupling: Separation of behavior definitions (
BehaviorDelegates.mqh), behavior implementations (BehaviorLibrary.mqh), and the mock engine (CSyntheticEngine.mqh). - Idiomatic MQL5: Full compatibility with strict MQL5 compiler without requiring external tooling.
Negative
- Manual State Reset: Stateful behavior functions relying on internal
staticvariables require careful sequencing or automatic reset after completion cycles. - Function Signature Constraints: Injected functions must strictly adhere to the
typedefdelegate signature.