You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
Kategoria: Eksperci / Poziom zarządzania handlem: Średniozaawansowany / Zaawansowany Skupienie symboli: XAUUSD (dotyczy dowolnego instrumentu zmiennego)
Wprowadzenie
Jeśli kiedykolwiek prowadziłeś Gold EA przez MQL5 Strategy Tester i widziałeś to w logu:
failed market sell 0.2 XAUUSD, close #60 buy 0.2 XAUUSD 1870.33 [Modification failed due to order or position being close to market] ...Repeated twenty times in a row - you've hit the broker freeze zone problem. failed market sell 0.2 XAUUSD, close #60 buy 0.2 XAUUSD 1870.33 [Modification failed due to order or position being close to market]
Ten artykuł dokładnie wyjaśnia, co to powoduje, dlaczego większość EA źle to obsługuje oraz jak to poprawić, aby Twoje EA przeszło weryfikację MQL5 Market bez spamu błędów.
Czym jest strefa zamrożenia?
Każdy broker definiuje poziom zamrożenia dla każdego symbolu – odległość (w punktach) od aktualnej ceny rynkowej, przy której nie można zmienić otwartej pozycji.
Możesz go przeczytać od:
Gdy cena rynkowa porusza się w tym zakresie stop loss lub take profit, broker blokuje pozycję. Od tego momentu: int freezeLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_FREEZE_LEVEL);
Broker zaraz wykona zatrzymanie. Każde zakłócenie ze strony EA skutkuje błędem.
Ma to na celu ochronę integralności zamówienia przy jednoczesnym szybkim wykonywaniu. Ale większość emocjonalistów tego nie bierze na oczy.
Dlaczego większość EAs tutaj nie kwalifikuje się
Typowa sekwencja zamykająca w EA wygląda tak:
// 1. Try to clear stops before closing trade.PositionModify(ticket, 0.0, 0.0); // 2. Send close trade.PositionClose(ticket); When a position is in the freeze zone, step 1 fails. The EA detects the error, tries, fails again—and if this works in a replay loop triggered on every tick, 20+ identical error lines appear within seconds. // 1. Try to clear stops before closing trade.PositionModify(ticket, 0.0, 0.0); // 2. Send close trade.PositionClose(ticket);
Nawet surowa transakcja nie pomaga – broker odrzuca wszystkie prośby, gdy pozycja jest zamrożona. CTrade::PositionClose OrderSend TRADE_ACTION_DEAL
Właściwe rozwiązanie
Nic nie rób.
Gdy pozycja znajduje się w strefie zamrożenia, broker jest o milisekundy od wykonania zatrzymania. Prawidłową czynnością jest wykrycie stanu zamrożenia i natychmiastowy powrót — bez modyfikacji, bez zamknięcia, bez ponownej próby.
Oto funkcja użyteczności, która sprawdza, czy ograniczniki pozycji znajdują się w odległości zamrożenia:
bool StopsInFreezeZone(const string sym, const ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; double pt = SymbolInfoDouble(sym, SYMBOL_POINT); if(pt <= 0) pt = _Point; int freezeLvl = (int)SymbolInfoInteger(sym, SYMBOL_TRADE_FREEZE_LEVEL); if(freezeLvl <= 0) return false; double freezeDist = freezeLvl * pt; double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double bid = SymbolInfoDouble(sym, SYMBOL_BID); double ask = SymbolInfoDouble(sym, SYMBOL_ASK); if(ptype == POSITION_TYPE_BUY) { if(sl > 0.0 && (bid - sl) < freezeDist) return true; if(tp > 0.0 && (tp - bid) < freezeDist) return true; } else { if(sl > 0.0 && (sl - ask) < freezeDist) return true; if(tp > 0.0 && (ask - tp) < freezeDist) return true; } return false; } Korzystanie z Garda bool StopsInFreezeZone(const string sym, const ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; double pt = SymbolInfoDouble(sym, SYMBOL_POINT); if(pt <= 0) pt = _Point; int freezeLvl = (int)SymbolInfoInteger(sym, SYMBOL_TRADE_FREEZE_LEVEL); if(freezeLvl <= 0) return false; double freezeDist = freezeLvl * pt; double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double bid = SymbolInfoDouble(sym, SYMBOL_BID); double ask = SymbolInfoDouble(sym, SYMBOL_ASK); if(ptype == POSITION_TYPE_BUY) { if(sl > 0.0 && (bid - sl) < freezeDist) return true; if(tp > 0.0 && (tp - bid) < freezeDist) return true; } else { if(sl > 0.0 && (sl - ask) < freezeDist) return true; if(tp > 0.0 && (ask - tp) < freezeDist) return true; } return false; }
W twojej bliskiej roli
Dodaj check-freeze na samym górze – przed jakimkolwiek lub call: OrderSend CTrade
bool ClosePosition(ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; string sym = PositionGetString(POSITION_SYMBOL); // If frozen — broker will execute SL. Do not interfere. if(StopsInFreezeZone(sym, ticket)) return false; CTrade trade; trade.SetDeviationInPoints(50); return trade.PositionClose(ticket); } In the modification/trace function bool ClosePosition(ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; string sym = PositionGetString(POSITION_SYMBOL); // If frozen — broker will execute SL. Do not interfere. if(StopsInFreezeZone(sym, ticket)) return false; CTrade trade; trade.SetDeviationInPoints(50); return trade.PositionClose(ticket); }
Ta sama zasada – pomij wszystkie modyfikacje po zamrożonym terminie:
void TrailStop(ulong ticket) { if(!PositionSelectByTicket(ticket)) return; // Never modify stops in freeze zone if(StopsInFreezeZone(_Symbol, ticket)) return; // ... your trail logic here } W zarządzaniu stanowiskami OnTick void TrailStop(ulong ticket) { if(!PositionSelectByTicket(ticket)) return; // Never modify stops in freeze zone if(StopsInFreezeZone(_Symbol, ticket)) return; // ... your trail logic here }
If you evaluate exit conditions on every tick, guard the entire block:
void OnTick() { // ... if(g_Ticket > 0 && PositionSelectByTicket(g_Ticket)) { // Skip all management when broker has the position locked if(!StopsInFreezeZone(_Symbol, g_Ticket)) { ManagePosition(); TrailStop(g_Ticket); } } } The ClearStops-Before-Close Pattern void OnTick() { // ... if(g_Ticket > 0 && PositionSelectByTicket(g_Ticket)) { // Skip all management when broker has the position locked if(!StopsInFreezeZone(_Symbol, g_Ticket)) { ManagePosition(); TrailStop(g_Ticket); } } }
Many EAs attempt to set SL and TP to zero before sending a close order. This is valid practice in normal conditions but must also be guarded:
bool ClearStopsBeforeClose(const string sym, const ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); if(sl == 0.0 && tp == 0.0) return true; // If the current SL/TP is already in the freeze zone, // modifying to zero will also be rejected. Skip it. if(StopsInFreezeZone(sym, ticket)) return false; CTrade tr; tr.SetDeviationInPoints(30); return tr.PositionModify(ticket, 0.0, 0.0); } Zapobieganie spamowi powtórek bool ClearStopsBeforeClose(const string sym, const ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); if(sl == 0.0 && tp == 0.0) return true; // If the current SL/TP is already in the freeze zone, // modifying to zero will also be rejected. Skip it. if(StopsInFreezeZone(sym, ticket)) return false; CTrade tr; tr.SetDeviationInPoints(30); return tr.PositionModify(ticket, 0.0, 0.0); }
Even with the freeze guard, a race condition can occur: the freeze check passes, the close is sent, the market moves into the freeze zone before the request reaches the broker, and the close is rejected. On the next tick the EA tries again.
Add a pending-close flag to prevent hammering on every tick:
bool g_ClosePending = false; datetime g_CloseLastAttempt = 0; // In your position management function: if(g_ClosePending) { if(TimeCurrent() - g_CloseLastAttempt < 3) return; g_ClosePending = false; } // After a failed close attempt: if(!ClosePosition(g_Ticket)) { g_ClosePending = true; g_CloseLastAttempt = TimeCurrent(); } // In CheckPosition() when position disappears: g_ClosePending = false; This limits retries to one attempt every 3 seconds regardless of tick frequency. bool g_ClosePending = false; datetime g_CloseLastAttempt = 0; // In your position management function: if(g_ClosePending) { if(TimeCurrent() - g_CloseLastAttempt < 3) return; g_ClosePending = false; } // After a failed close attempt: if(!ClosePosition(g_Ticket)) { g_ClosePending = true; g_CloseLastAttempt = TimeCurrent(); } // In CheckPosition() when position disappears: g_ClosePending = false;
Testing in the Strategy Tester
Zachowanie strefy zamrożenia jest w pełni symulowane w MT5 Strategy Tester na XAUUSD z rzeczywistymi danymi ticków. To naprawdę przydatne — jeśli twoje EA ma problem z zawieszaniem, tester będzie go niezawodnie wykrywał, dokładnie tak, jak pokazano we wstępie.
After applying the guards above, the journal should be completely clean of "Modification failed" errors. If errors persist, check whether you have any additional close or modify calls outside the main management function — timers, , or partial-close logic are common places where secondary calls are missed. OnTradeTransaction
Podsumowanie
Strefa zamrożenia to nie jest błąd ani dziwactwa brokera, którą trzeba omijać. To celowy mechanizm ochrony przed wykonaniem działań. Najczystszym zachowaniem EA jest szybkie wykrycie i ustąpienie miejsca na bok.
Podsumowanie
Błędy strefy zamrożenia są jednym z najczęstszych powodów, dla których Gold EAs generują szumowe czasopisma i nie przechodzą weryfikacji rynku MQL5. Rozwiązanie jest sprzeczne z intuicją — zamiast bardziej się starać, by zamknąć pozycję, całkowicie przestajesz próbować i pozwalasz maklerowi wykonać pracę.
Funkcje użyteczności i wzorce opisane w tym artykule są testowane produkcyjnie na XAUUSD i działają poprawnie zarówno w handlu na żywo, jak i w MT5 Strategy Tester.
Jeśli uznałeś to za pomocne lub masz pytania dotyczące konkretnych przypadków borderline — zwłaszcza dotyczących częściowych zamknięcia i interakcji ze strefą zamrażania — śmiało podziel się nimi w komentarzach poniżej.
Słowa kluczowe: MQL5, Expert Advisor, XAUUSD, Gold EA, freeze level, stop loss, zarządzanie pozycją, Strategy Tester, zarządzanie transakcjami, MQL5 Market