OrderSendAsync
Zlecenie wysłane asynchronicznie wraca natychmiast, zanim serwer cokolwiek zrobi. Jak śledzić jego stan i dlaczego lokalna baza bywa nieaktualna.
1 fragment kodu z tej strony przeszedł przez kompilator MetaEditor build 6090, 2026-08-05.
Jednym z najbardziej bolesnych doświadczeń dla programistów przechodzących z MQL4 do MQL5 (lub z języków skryptowych takich jak Python do algorytmicznego tradingu) jest zderzenie z asynchroniczną naturą wysyłania zleceń. W MQL4 funkcja OrderSend była blokująca – program czekał na odpowiedź serwera, a po jej zakończeniu zlecenie było już w systemie. W MQL5 ten paradygmat uległ drastycznej zmianie.
Wielu początkujących programistów pisze kod, który wysyła zlecenie, a w kolejnej linijce sprawdza, czy pozycja została otwarta, używając do tego np. PositionsTotal(). Prowadzi to do katastrofalnych w skutkach błędów logicznych: zlecenia nie ma, bo serwer jeszcze go nie przetworzył, a EA uznaje, że wystąpił błąd i próbuje wysłać je ponownie, zazwyczaj kończąc z dziesiątkami duplikatów.
Podział ról: Wątek Klienta a Wątek Sieciowy
Terminal MetaTrader 5 zarządza komunikacją sieciową w osobnym wątku. Kiedy wywołujesz OrderSend() (wersja synchroniczna w MQL5), terminal w rzeczywistości oddaje żądanie do wątku sieciowego i czeka na wynik. To "czekanie" jest w MQL5 często przerywane przez timeouty. Jednak prawdziwa moc (i problematyczność) leży w funkcji OrderSendAsync().
Stan Transakcji: Maszyna Stanów (State Machine)
W MQL5 zlecenie przechodzi przez wiele etapów: ORDER_STATE_STARTED, ORDER_STATE_PLACED, ORDER_STATE_PARTIAL, ORDER_STATE_FILLED itd. Aby bezpiecznie zarządzać asynchronicznymi zleceniami, musisz zaimplementować maszynę stanów opartą na zdarzeniach. Służy do tego funkcja OnTradeTransaction().
// Zmienna globalna śledząca stan naszego oczekującego zlecenia
ulong pendingOrderTicket = 0;
void OpenPositionAsync() {
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 20;
request.magic = 12345;
// Wysyłamy asynchronicznie. Funkcja wraca natychmiast.
if(OrderSendAsync(request, result)) {
if(result.retcode == TRADE_RETCODE_PLACED || result.retcode == TRADE_RETCODE_DONE) {
pendingOrderTicket = result.order;
Print("Zlecenie wysłane, czekam na potwierdzenie. Ticket: ", pendingOrderTicket);
}
} else {
Print("Błąd wysyłania asynchronicznego: ", GetLastError());
}
}
// To jest nasz "wywoływacz zwrotny" (callback) z wątku sieciowego
void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
// Interesują nas tylko zdarzenia dotyczące zleceń
if(trans.type == TRADE_TRANSACTION_ORDER_ADD ||
trans.type == TRADE_TRANSACTION_ORDER_UPDATE) {
if(trans.order == pendingOrderTicket) {
// Sprawdzamy aktualny stan zlecenia na serwerze
if(trans.order_state == ORDER_STATE_FILLED) {
Print("Zlecenie zrealizowane! Pozycja otwarta.");
pendingOrderTicket = 0; // Resetujemy
} else if(trans.order_state == ORDER_STATE_REJECTED) {
Print("Zlecenie odrzucone przez serwer! Kod: ", result.retcode);
pendingOrderTicket = 0;
}
}
}
}Zrozumienie asynchroniczności to nie tylko kwestia uniknięcia błędów, ale przede wszystkim optymalizacji HFT (High-Frequency Trading). Wykorzystując OrderSendAsync w połączeniu z OnTradeTransaction, EA może wysyłać setki zleceń na sekundę bez blokowania głównego wątku przetwarzającego ticki.