The case 3) has better client-server throughput, as each instance of MT4 Terminal platform contains it's own internal engine ( a Trade (management) Context instance ). This internal engine is technically invisible to user, but user has a responsibility to check the cases, when this engine is blocking the XTO's instructed to be fulfilled on the Server-side.
Fact #1: The platform evolves.
In early years, the MetaTrader Terminal 4 platform was quite often reporting cases, when it's internal implementation of a trade-management factory-pattern, dwelt in a state, which avoided any further request(s) from being processed.
Such indications were not asynchronously reported / did not interface with the flow of the MQL4-code execution, but was just indirectly accessible, after the code tried to inspect the GetLastError()
or _LastError
or via the IsTradeContextBusy()
value:
#include <stdlib.mqh>
#include <stderror.mqh>
...
ErrorDescription( GetLastError() ); // was available for showing an Error state
and
in cases, where _LastError == 146
== ERR_TRADE_CONTEXT_BUSY
reports a state, when a Trade context was busy.
In other words, each XTO-operation in the workflow was thus typically surrounded by a careful Error-State-detection analysis code and included ( in some feasible form, where possible ) some sort of remedy actions, so as to overcome the blocked ( refused ) XTO-operation, until possible or having some time-out watchdog-controlled exit path.
After some years, maybe after Build 509, definitely after a Build 624+ came into deployment, this so far common ( hidden ) blocking-state ceased to appear so often.
If you observe cases, when a _LastError
indeed reports the ERR_TRADE_CONTEXT_BUSY
again, there will be more care needed so as to isolate such state, so best use a detailed logging of all the steps in the flow of the code-execution, so as to map the actual platform state.
switch( Error )
{ case ...
case ERR_TRADE_CONTEXT_BUSY: { // ERR_TRADE_CONTEXT_BUSY
aLogSTRING = StringConcatenate( msLIB.anElapsedTimeSTRING(), "[ ", DoubleToStr( GetTickCount(), 0 ), " ] Trying to OrderModify() aPendingOrderOBJECT for this SONAR_BEEP Monitor at MT4Server side. <localhost>MT4Terminal reports: [ERR_TRADE_CONTEXT_BUSY] <state>. Will Sleep() here a bit more." );
aComment.ADD( aLogSTRING );
aMXact.aDeferredLOGGER( aLogSTRING, TRUE );
Sleep( 60 * 1000 );
break;
}
...
default: { ...
}
}
If testing durations, for which the situation gets not resolved, may use something like this:
while ( !IsStopped() ) { // LOOP FOREVER, UNTIL IsStopped()
tix.START = GetTickCount(); // STO()_______pre-STORE()_________________________ .START
if ( IsTradeContextBusy() ) { // if BUSY().......MEASURE......................... .START inner-LOOP
while ( IsTradeContextBusy() && !IsStopped() ) { // LOOP @BUSY()_________________________________________________________________________ tix
Sleep( msLIB.RT.LOOP_inMeasureSleep.ms ); // Sleep(*)
} // .............................................// LOOP .or. !BUSY()--------------------------------------------------------<_LOOP_>---- .or. { !IsTradeContextBusy() | IsStopped() }
tix.END = GetTickCount(); // STO()__________________ .END inner-LOOP _____________________________________________________________________ tix
tix.BUSY = tix.END - tix.START;
// aString2LOG= StringConcatenate( TimeToStr( TimeCurrent(), _time2str.MASK ),";", DoubleToStr( tix.START, 0 ), ";", DoubleToStr( tix.BUSY, 0 ) );
aString2LOG= StringConcatenate( TimeToStr( TimeLocal(), _time2str.MASK ),";", DoubleToStr( tix.START, 0 ), ";", DoubleToStr( tix.BUSY, 0 ) ); // TimeLocal() works either before/after Market Closes and no quotes arrive ( thus avoiding the hanging at TimeCurrent() at the time of the last known Quote.... )
// LOG.append
// LOG ------------------------|||||||||||||||--------------------------
aMXact.aDeferredLOGGER( aString2LOG, ( IsStopped() ) );
aComment.ADD( StringConcatenate( msLIB.anElapsedTimeSTRING(),
" <localhost>.<aTradingCONTEXT>.BUSY was <OBSERVED> at ",
DoubleToStr( aLoopCOUNTER.RollOVER * msLIB.RT.LOOP_nLoops2ShowGuiMSG + aLoopCOUNTER, 0 ),
" loop, < cpuClockTIXs.START | cpuClockTIXs.DURATION> ",
aString2LOG
)
);
aLoopCOUNTER.RollOVER = 0;
aLoopCOUNTER = 0;
}