MtClient/MtApi5: async command API with request pipelining#310
Open
biohazardxxx wants to merge 4 commits into
Open
MtClient/MtApi5: async command API with request pipelining#310biohazardxxx wants to merge 4 commits into
biohazardxxx wants to merge 4 commits into
Conversation
Add SendCommandAsync alongside the sync SendCommand. CommandTask now completes a TaskCompletionSource (created with RunContinuationsAsynchronously so awaiter continuations never run inline on the receive thread) in addition to the existing EventWaitHandle. Timeout semantics mirror the sync path: on timeout the current response value (null if none arrived) is returned and the task entry is removed. No existing signature or behavior changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a private SendCommandAsync<T> mirroring SendCommand<T> (same response parsing and ExecutionException semantics) and public async variants: PositionsTotalAsync, OrdersTotalAsync, AccountInfoDoubleAsync, AccountInfoIntegerAsync, SymbolInfoTickAsync, SymbolInfoDoubleAsync, SymbolInfoIntegerAsync, CopyRatesAsync (x3 overloads returning the array directly instead of out params), CopyTicksAsync, TimeCurrentAsync. Multiple in-flight commands are pipelined and typically served in a single expert wake-up. Trade operations are intentionally excluded: OrderSendAsync already exists as a sync wrapper of MQL's OrderSendAsync command and must not be shadowed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New button on the Time and Date tab runs 20 sequential sync calls (PositionsTotal/TimeCurrent alternating) followed by the same 20 calls concurrently via Task.WhenAll on the async variants, and logs both wall-clock times to demonstrate command pipelining. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches the observable behavior of the sync CopyRates overloads (ratesArray is never null) and the CopyTicksAsync/CopyTicks parity. Review finding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4 tasks
hosseinkhojany
pushed a commit
to hosseinkhojany/mtapi
that referenced
this pull request
Jul 22, 2026
…equest pipelining # Conflicts: # TestClients/MtApi5TestClient/MainWindow.xaml # TestClients/MtApi5TestClient/ViewModel.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The RPC core already supports multiple in-flight commands (responses are correlated by
commandId, and the expert drains its whole command queue per wake-up), but the public API is strictly synchronous — one blocked thread per outstanding command. This PR adds a first-class async path so callers can pipeline requests:CommandTaskgains aTaskCompletionSource(created withRunContinuationsAsynchronously— continuations never run inline on the receive thread); newTask<string?> SendCommandAsync(...)mirrorsSendCommand's registration, locking, and timeout semantics exactly. Purely additive — MT4'sMtApiClientcompiles untouched (verified).SendCommandAsync<T>mirrorsSendCommand<T>exception semantics; public async variants for the read-heavy hot set:PositionsTotalAsync,OrdersTotalAsync,AccountInfoDouble/IntegerAsync,SymbolInfoTickAsync,SymbolInfoDouble/IntegerAsync,CopyRatesAsync(3 overloads, returningTask<MqlRates[]>directly instead of out params),CopyTicksAsync,TimeCurrentAsync.AsyncPipelineDemoaction comparing 20 sequential sync calls vs 20 concurrent async calls.No async variants for trade operations by design —
OrderSendAsyncalready exists as a synchronous wrapper of MQL5'sOrderSendAsynccommand and aTask-returning overload of that name would be a foot-gun.Implementation notes
ConfigureAwait(false); noasync voidin library code.CopyRatesAsyncreturns[](never null) on a null response, matching the observable behavior of the sync overloads (review finding, fixed in c236352).Testing
MtClient,MtApi5,MtApi— proving the MT4 surface untouched — and the test client).CopyRatesAsyncnull/empty drift, which is fixed.PositionsTotalAsync/TimeCurrentAsyncresults equal their sync counterparts.🤖 Generated with Claude Code