I also canceled that restriction, but it doesn't go through again with the message
test on EURUSD, H1
Try using this code , it checks everything
Forum on trading, automated trading systems and testing trading strategies
Automatic validation for my EA
Lorentzos Roussos, 2022.12.29 15:47
Okay i think some checks changed again . I just passed the below code .
If i'm not mistaken the tester may fail in SymbolInfo requests so it should have an alternative for MarketInfo on lots.(that or i should use Symbol() , or they are testing on old terminals too)
The following code may have issues in the margin calculation , does not account for ECN types and does not handle Freeze Level which i'm not experienced with.
The rest is okay and passed in a hidden project that i have in the market for testing .
here is the all in one trade code in its test form (this ea passed as is).
#property version "33.00" #property strict datetime barstamp=0; int clock=0,clock_limit=7; int OnInit() { barstamp=0; clock=0; return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { } void OnTick() { if(Time[0]>barstamp){ barstamp=Time[0]; clock++; if(clock==clock_limit){ clock=0; if(MathRand()>16000){ trade_result result=SafeMarketTrade(OP_BUY,0.01,10,false,10,false,false,1.5,10,333,1000,23,NULL,clrBlue); if(!result.success){ Print(result.error_message); } } else{ trade_result result=SafeMarketTrade(OP_SELL,0.01,Ask+(10*_Point),true,0.0,false,false,1.5,10,333,1000,23,NULL,clrRed); if(!result.success){ Print(result.error_message); } } }} } struct trade_result{ bool success; int ticket; double open_price; double initial_price,ask,bid,spread; double stop_loss; double take_profit; double lots; double margin_used; datetime open_time; int slippage; int attempts; long time_to_open_ms; string error_message; trade_result(void){reset();} ~trade_result(void){reset();} void reset(){ success=false; ticket=-1; attempts=0; error_message=""; } }; trade_result SafeMarketTrade(ENUM_ORDER_TYPE direction,//buy or sell double lots,//the volume of the trade double sl,//stop loss price or distance from entry price bool sl_is_price,//true if stop loss is not distance double tp,//take profit price or distance from entry price bool tp_is_price,//true if take profit is not distance bool reject_if_stops_too_close,//reject trade if stops are too close for broker double stops_expansion_multiple_of_limit,//if not rejecting trade for stop level , expand by this much (off of the limit) int max_attempts,//max attempts to open uint timeout,//timeout between attempts int max_slippage,//max allowed slippage int magic_number, string order_comment, color clr){ trade_result result; //log the start ms result.time_to_open_ms=GetTickCount(); //create id for the order attempt string id="{"+_Symbol+" "+EnumToString(direction)+" "+DoubleToString(lots,2)+" #Magic("+IntegerToString(magic_number)+")'"+order_comment+"'}"; //Proper Type if(direction==OP_BUY||direction==OP_SELL) { //Context and Connection if(!IsTradeContextBusy()&&IsConnected()) { //total orders and account limits ResetLastError(); int account_orders_limit=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); if(GetLastError()==0&&OrdersTotal()<account_orders_limit){ //Trade allowance ResetLastError(); if(IsTradeAllowed(_Symbol,TimeCurrent())&&(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)==1)&&GetLastError()==0){ //minlot , maxlot , step , total max ResetLastError(); bool volumes_acquired=true; double volume_min=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); if(GetLastError()!=0){ ResetLastError(); volume_min=(double)MarketInfo(_Symbol,MODE_MINLOT); if(GetLastError()!=0){volumes_acquired=false;} } ResetLastError(); double volume_max=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); if(GetLastError()!=0&&volumes_acquired){ ResetLastError(); volume_max=(double)MarketInfo(_Symbol,MODE_MAXLOT); if(GetLastError()!=0){volumes_acquired=false;} } ResetLastError(); double volume_step=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); if(GetLastError()!=0&&volumes_acquired){ ResetLastError(); volume_step=(double)MarketInfo(_Symbol,MODE_LOTSTEP); if(GetLastError()!=0){volumes_acquired=false;} } ResetLastError(); double volume_limit=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT); if(GetLastError()!=0){volume_limit=0.0;} if(volumes_acquired){ //check against step int steps=(int)(MathFloor(lots/volume_step)); lots=((double)steps)*volume_step; if(lots<volume_min){lots=volume_min;} else if(lots>volume_max){lots=volume_max;} //Total symbol volume double total_symbol_volume=get_symbol_volume(_Symbol,true)+lots; if(total_symbol_volume<volume_limit||volume_limit<=0.0){ //get max available margin with margin of error on top double max_available_margin=get_max_available_margin_with_error_margin(0.2);//20% buffer //free margin check //the free margin remaining must be above free margin - max available free margin double margin_min=AccountFreeMargin()-max_available_margin; ResetLastError(); if(AccountFreeMarginCheck(_Symbol,direction,lots)>margin_min&&GetLastError()==0){ //turn all stops to distance if they are not and catch the first price double sl_ticks=0.0,tp_ticks=0.0; RefreshRates(); result.ask=Ask; result.bid=Bid; if(direction==OP_BUY){result.initial_price=Ask;} else{result.initial_price=Bid;} //get stop level limit ResetLastError(); double stop_limit=((double)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL))*_Point; if(GetLastError()==0){ //stop loss if(sl!=0.0){ if(sl_is_price){ if(direction==OP_BUY){ sl_ticks=result.bid-sl; }else{ sl_ticks=sl-result.ask; } } else{ sl_ticks=sl*_Point; } //if the stop loss is below the limit and the limit is not zero if(stop_limit>0.0&&sl_ticks<=stop_limit){ //adjust or reject if(reject_if_stops_too_close){ result.error_message="SL is too close , rejecting trade "+id; return(result); } else{ sl_ticks=NormalizeDouble(stop_limit*stops_expansion_multiple_of_limit,_Digits); } } } //stop loss ends here //take profit if(tp!=0.0){ if(tp_is_price){ if(direction==OP_BUY){ tp_ticks=tp-result.ask; }else{ tp_ticks=result.bid-tp; } } else{ tp_ticks=tp*_Point; } //if the take profit is below the limit and the limit is not zero if(stop_limit>0.0&&tp_ticks<=stop_limit){ //adjust or reject if(reject_if_stops_too_close){ result.error_message="TP is too close , rejecting trade "+id; return(result); } else{ tp_ticks=NormalizeDouble(stop_limit*stops_expansion_multiple_of_limit,_Digits); } } } //take profit ends here /* At this point we have everything we need now we will start attempting to place the trade */ //TRADE double fm_snap=0.0; while(result.ticket==-1&&result.attempts<max_attempts){ result.attempts++; RefreshRates(); result.ask=Ask; result.bid=Bid; fm_snap=AccountFreeMargin(); if(direction==OP_BUY){result.open_price=Ask;}else{result.open_price=Bid;} //format sl + tp ,we have the ticks so we can use sl , tp variables if(sl_ticks!=0.0){ if(direction==OP_BUY){ sl=result.bid-sl_ticks; }else{ sl=result.ask+sl_ticks; } } if(tp_ticks!=0.0){ if(direction==OP_BUY){ tp=result.ask+tp_ticks; }else{ tp=result.bid-tp_ticks; } } ResetLastError(); result.ticket=OrderSend(_Symbol,direction,lots,result.open_price,max_slippage,sl,tp,order_comment,magic_number,0,clr); Sleep(timeout); } //TRADE ENDS HERE //if trade failed if(result.ticket==-1){ result.error_message="Trade failed error#"+IntegerToString(GetLastError())+" "; } //if trade succeeded else{ result.success=true; //time to open long endms=GetTickCount(); if(endms<result.time_to_open_ms){ result.time_to_open_ms=UINT_MAX-result.time_to_open_ms+endms; }else{ result.time_to_open_ms=endms-result.time_to_open_ms; } //spread result.spread=result.ask-result.bid; //margin used result.margin_used=fm_snap-AccountFreeMargin(); //select for more info if(OrderSelect(result.ticket,SELECT_BY_TICKET)){ result.open_price=OrderOpenPrice(); result.open_time=OrderOpenTime(); result.lots=OrderLots(); result.stop_loss=OrderStopLoss(); result.take_profit=OrderTakeProfit(); //slippage if(direction==OP_BUY){ result.slippage=(int)((result.initial_price-result.open_price)/_Point); }else{ result.slippage=(int)((result.open_price-result.initial_price)/_Point); } } } //if trade succeeded ends here } else{ result.error_message="Cannot get stops level "; } //get stop level limit ends here }else{ result.error_message="Not enough margin for lots "; } //free margin check ends here }else{ result.error_message="Volume will exceed total limit "; } //Total symbol volume ends here }else{ result.error_message="Cannot acquire symbol volume info "; } //minlot , maxlot , step ,total max ends here }else{ if(!IsTradeAllowed(_Symbol,TimeCurrent())){result.error_message="Trade not possible for symbol ";} if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)==0){result.error_message+="Trade switch is off ";} } //Trade allowance ends here }else{ result.error_message="Total orders account limit reached "; } //total orders and account limits ends here }else{ if(IsTradeContextBusy()){result.error_message="Trade Context Busy ";} if(!IsConnected()){result.error_message+="No Connection ";} } //Context and Connection Ends Here }else{ result.error_message="Wrong trade type.Market orders only please "; } //Proper Type Ends Here result.error_message+=id; return(result); } double get_symbol_volume(string _symbol,bool only_live_orders){ double sum=0.0; for(int i=0;i<OrdersTotal();i++){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){ if(!only_live_orders||(OrderType()==OP_BUY||OrderType()==OP_SELL)){ sum+=OrderLots(); }}} return(sum); } double get_max_available_margin_with_error_margin(double error_margin_buffer_percent){ double avail_margin=0.0; ResetLastError(); int margin_call_mode=AccountStopoutMode();//https://docs.mql4.com/account/accountstopoutmode if(GetLastError()==0){ //if absolute value mode if(margin_call_mode==1){ avail_margin=AccountFreeMargin()-AccountStopoutLevel(); } //if % mode else if(margin_call_mode==0){ double min_ratio=AccountStopoutLevel(); //at min ratio the margin must be double margin_at_min=AccountEquity()/(min_ratio/100.0); avail_margin=MathMin(margin_at_min-AccountMargin(),AccountFreeMargin()); } //and margin of error avail_margin-=avail_margin*error_margin_buffer_percent; } return(avail_margin); }Edit : Volume limit should not reject the acquisition switch of lots in case the broker does not support it , or its not supported at all i guess . That means maybe the symbol info doubles are working too . This works however .
I check on the strategy tester and everything is fine
Symbol | EURCHF (Euro vs Swiss Franc) | ||||
Period | 1 Hour (H1) 2022.12.01 00:00 - 2023.01.03 23:00 (2022.12.01 - 2023.01.04) | ||||
Model | Every tick (the most precise method based on all available least timeframes) | ||||
Parameters | Lot=0.01; distance=50; doubleDistance=100; takeProfit=100; stopLoss=200; increaseLot=0.01; setTarget=false; closeFriday=false; | ||||
Bars in test | 1565 | Ticks modelled | 2072034 | Modelling quality | 90.00% |
Mismatched charts errors | 0 | ||||
Initial deposit | 1000.00 | Spread | Current (26) | ||
Total net profit | 82.53 | Gross profit | 98.33 | Gross loss | -15.80 |
Profit factor | 6.23 | Expected payoff | 1.38 | ||
Absolute drawdown | 1.94 | Maximal drawdown | 9.86 (0.96%) | Relative drawdown | 0.96% (9.86) |
Total trades | 60 | Short positions (won %) | 29 (93.10%) | Long positions (won %) | 31 (90.32%) |
Profit trades (% of total) | 55 (91.67%) | Loss trades (% of total) | 5 (8.33%) | ||
Largest | profit trade | 7.45 | loss trade | -3.93 | |
Average | profit trade | 1.79 | loss trade | -3.16 | |
Maximum | consecutive wins (profit in money) | 22 (39.77) | consecutive losses (loss in money) | 1 (-3.93) | |
Maximal | consecutive profit (count of wins) | 39.77 (22) | consecutive loss (count of losses) | -3.93 (1) | |
Average | consecutive wins | 9 | consecutive losses | 1 |
Test it on other symbols in the Strategy Tester, not just EURCHF. It must be able to trade on ANY symbol, even if it is unprofitable.
Those are the conditions and rules for Market products. It MUST be able to trade on any and all symbols.

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use