// ------------------------------------------------------------------------------------------------ // Copyright © 2011, www.lifesdream.org // http://www.lifesdream.org // ------------------------------------------------------------------------------------------------ #include #include #property copyright "Copyright © 2011, www.lifesdream.org" #property link "http://www.lifesdream.org" // ------------------------------------------------------------------------------------------------ // VARIABLES EXTERNAS // ------------------------------------------------------------------------------------------------ extern int magic1 = 47291; extern int magic2 = 47292; extern int magic3 = 47293; // Configuration extern string www.lifesdream.org = "Ichimoku EA v1.3"; extern string CommonSettings = "---------------------------------------------"; extern int user_slippage = 2; extern int user_tp = 100; extern int user_sl = 100; extern int use_tp_sl = 1; extern double profit_lock = 0.90; extern int strategy1 = 1; // Tenkan Sen/Kijun Sen Cross extern int strategy2 = 1; // Kijun Sen Cross extern int strategy3 = 1; // Kumo Breakout extern int signal_strength = 1; // 1=strong | 2: neutral | 3: weak extern string MoneyManagementSettings = "---------------------------------------------"; // Money Management extern int money_management = 1; extern double min_lots = 0.1; extern int risk=1; extern int progression = 0; // 0=none | 1:ascending | 2:martingale // Indicator extern string IndicatorSettings = "---------------------------------------------"; extern int tenkan_sen=9; extern int kijun_sen=26; extern int senkou_span = 52; extern int shift = 1; // ------------------------------------------------------------------------------------------------ // VARIABLES GLOBALES // ------------------------------------------------------------------------------------------------ string key1 = "Ichimoku EA v1.3 (strategy 1)"; string key2 = "Ichimoku EA v1.3 (strategy 2)"; string key3 = "Ichimoku EA v1.3 (strategy 3)"; // Definimos 1 variable para guardar los tickets int order_ticket1,order_ticket2,order_ticket3; // Definimos 1 variable para guardar los lotes double order_lots1,order_lots2,order_lots3; // Definimos 1 variable para guardar las valores de apertura de las ordenes double order_price1,order_price2,order_price3; // Definimos 1 variable para guardar los beneficios double order_profit1,order_profit2,order_profit3; // Definimos 1 variable para guardar los tiempos int order_time1,order_time2,order_time3; // indicadores double signal1=0,signal2=0,signal3=0; // Cantidad de ordenes; int orders1 = 0; int direction1= 0; double max_profit1=0, close_profit1=0; double last_order_profit1=0, last_order_lots1=0; int orders2 = 0; int direction2= 0; double max_profit2=0, close_profit2=0; double last_order_profit2=0, last_order_lots2=0; int orders3 = 0; int direction3= 0; double max_profit3=0, close_profit3=0; double last_order_profit3=0, last_order_lots3=0; // Colores color c=Black; // Cuenta double balance, equity; int slippage=0; // OrderReliable int retry_attempts = 10; double sleep_time = 4.0; double sleep_maximum = 25.0; // in seconds string OrderReliable_Fname = "OrderReliable fname unset"; static int _OR_err = 0; string OrderReliableVersion = "V1_1_1"; // ------------------------------------------------------------------------------------------------ // START // ------------------------------------------------------------------------------------------------ int start() { int ticket, i, n; double price; bool cerrada, encontrada; if (MarketInfo(Symbol(),MODE_DIGITS)==4) { slippage = user_slippage; } else if (MarketInfo(Symbol(),MODE_DIGITS)==5) { slippage = 10*user_slippage; } if(IsTradeAllowed() == false) { Comment("Copyright © 2011, www.lifesdream.org\nTrade not allowed."); return; } if (use_tp_sl==0) Comment(StringConcatenate("\nCopyright © 2011, www.lifesdream.org\nIchimoku EA v1.3 is running.", "\nStrategy 1 (Tenkan Sen/Kijun Sen Cross). Next order lots (: ",CalcularVolumen(1), "\nStrategy 2 (Kijun Sen Cross). Next order lots (: ",CalcularVolumen(2), "\nStrategy 3 (Kumo Breakout). Next order lots (: ",CalcularVolumen(3) ) ); else if (use_tp_sl==1) Comment(StringConcatenate("\nCopyright © 2011, www.lifesdream.org\nIchimoku EA v1.3 is running.", "\nStrategy 1 (Tenkan Sen/Kijun Sen Cross). Next order lots: ",CalcularVolumen(1),"\nTake profit ($): ",CalcularVolumen(1)*10*user_tp,"\nStop loss ($): ",CalcularVolumen(1)*10*user_sl, "\nStrategy 2 (Kijun Sen Cross). Next order lots: ",CalcularVolumen(2),"\nTake profit ($): ",CalcularVolumen(2)*10*user_tp,"\nStop loss ($): ",CalcularVolumen(2)*10*user_sl, "\nStrategy 3 (Kumo Breakout). Next order lots: ",CalcularVolumen(3),"\nTake profit ($): ",CalcularVolumen(3)*10*user_tp,"\nStop loss ($): ",CalcularVolumen(3)*10*user_sl ) ); // Actualizamos el estado actual InicializarVariables(); ActualizarOrdenes(); encontrada=FALSE; if (OrdersHistoryTotal()>0) { i=1; while (i<=100 && encontrada==FALSE) { n = OrdersHistoryTotal()-i; if(OrderSelect(n,SELECT_BY_POS,MODE_HISTORY)==TRUE) { if (OrderMagicNumber()==magic1) { encontrada=TRUE; last_order_profit1=OrderProfit(); last_order_lots1=OrderLots(); } if (OrderMagicNumber()==magic2) { encontrada=TRUE; last_order_profit2=OrderProfit(); last_order_lots2=OrderLots(); } if (OrderMagicNumber()==magic3) { encontrada=TRUE; last_order_profit3=OrderProfit(); last_order_lots3=OrderLots(); } } i++; } } if (strategy1==1) Robot1(); if (strategy2==1) Robot2(); if (strategy3==1) Robot3(); return(0); } // ------------------------------------------------------------------------------------------------ // INICIALIZAR VARIABLES // ------------------------------------------------------------------------------------------------ void InicializarVariables() { orders1=0; direction1=0; order_ticket1 = 0; order_lots1 = 0; order_price1 = 0; order_time1 = 0; order_profit1 = 0; last_order_profit1 = 0; last_order_lots1 = 0; orders2=0; direction2=0; order_ticket2 = 0; order_lots2 = 0; order_price2 = 0; order_time2 = 0; order_profit2 = 0; last_order_profit2 = 0; last_order_lots2 = 0; orders3=0; direction3=0; order_ticket3 = 0; order_lots3 = 0; order_price3 = 0; order_time3 = 0; order_profit3 = 0; last_order_profit3 = 0; last_order_lots3 = 0; } // ------------------------------------------------------------------------------------------------ // ACTUALIZAR ORDENES // ------------------------------------------------------------------------------------------------ void ActualizarOrdenes() { int ordenes1=0,ordenes2=0,ordenes3=0; // Lo que hacemos es introducir los tickets, los lotes, y los valores de apertura en las matrices. // Además guardaremos el número de ordenes en una variables. // Ordenes de compra for(int i=0; iMarketInfo(Symbol(),MODE_MAXLOT)) aux=MarketInfo(Symbol(),MODE_MAXLOT); if (auxMarketInfo(Symbol(),MODE_MAXLOT)) aux=MarketInfo(Symbol(),MODE_MAXLOT); if (auxMarketInfo(Symbol(),MODE_MAXLOT)) aux=MarketInfo(Symbol(),MODE_MAXLOT); if (aux= ssB1) kt1 = ssA1; else kt1 = ssB1; if (ssA1 <= ssB1) kb1 = ssA1; else kb1 = ssB1; if (ssA2 >= ssB2) kt2 = ssA2; else kt2 = ssB2; if (ssA2 <= ssB2) kb2 = ssA2; else kb2 = ssB2; // Valores de retorno // 1. Compra // 2. Venta // STRATEGY 1: Tenkan Sen / Kijun Sen Cross if (strategy==1) { // BUY SIGNAL if (ts1>ks1 && ts2kt1) aux=1; } // NEUTRAL else if (signal_strength==2) { if (ks1>kb1) aux=1; } // WEAK else if (signal_strength==3) { aux=1; } } // SELL SIGNAL if (ts1ks2) { // STRONG if (signal_strength==1) { if (ts1ks1 && close2kt1) aux=1; } // NEUTRAL else if (signal_strength==2) { if (ks1>kb1) aux=1; } // WEAK else if (signal_strength==3) { aux=1; } } // SELL SIGNAL if (close1ks2) { // STRONG if (signal_strength==1) { if (ks1kt1 && close2kb2) { aux=2; } } return(aux); } // ------------------------------------------------------------------------------------------------ // ROBOT 1 // ------------------------------------------------------------------------------------------------ void Robot1() { int ticket=-1, i; bool cerrada=FALSE; if (orders1==0 && direction1==0) { signal1 = CalculaSignal(1,tenkan_sen,kijun_sen,senkou_span,shift); // ---------- // COMPRA // ---------- if (signal1==1) ticket = OrderSendReliable(Symbol(),OP_BUY,CalcularVolumen(1),MarketInfo(Symbol(),MODE_ASK),slippage,0,0,key1,magic1,0,Blue); // En este punto hemos ejecutado correctamente la orden de compra // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() // ---------- // VENTA // ---------- if (signal1==2) ticket = OrderSendReliable(Symbol(),OP_SELL,CalcularVolumen(1),MarketInfo(Symbol(),MODE_BID),slippage,0,0,key1,magic1,0,Red); // En este punto hemos ejecutado correctamente la orden de venta // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=1 // ************************************************** if (orders1>0 && direction1==1 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit1 > CalculaTakeProfit(1) && max_profit1==0) { max_profit1 = order_profit1; close_profit1 = profit_lock*order_profit1; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit1>0) { if (order_profit1>max_profit1) { max_profit1 = order_profit1; close_profit1 = profit_lock*order_profit1; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit1>0 && close_profit1>0 && max_profit1>close_profit1 && order_profit1>> Tenemos "size" pips de perdida if (order_profit1 <= CalculaStopLoss(1)) { cerrada=OrderCloseReliable(order_ticket1,order_lots1,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit1=0; close_profit1=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=1 // ************************************************** if (orders1>0 && direction1==2 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit1 > CalculaTakeProfit(1) && max_profit1==0) { max_profit1 = order_profit1; close_profit1 = profit_lock*order_profit1; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit1>0) { if (order_profit1>max_profit1) { max_profit1 = order_profit1; close_profit1 = profit_lock*order_profit1; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit1>0 && close_profit1>0 && max_profit1>close_profit1 && order_profit1>> Tenemos "size" pips de perdida if (order_profit1 <= CalculaStopLoss(1)) { cerrada=OrderCloseReliable(order_ticket1,order_lots1,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit1=0; close_profit1=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=0 // ************************************************** if (orders1>0 && direction1==1 && use_tp_sl==0) { signal1 = CalculaSignal(1,tenkan_sen,kijun_sen,senkou_span,shift); if (signal1==2) { cerrada=OrderCloseReliable(order_ticket1,order_lots1,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit1=0; close_profit1=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=0 // ************************************************** if (orders1>0 && direction1==2 && use_tp_sl==0) { signal1 = CalculaSignal(1,tenkan_sen,kijun_sen,senkou_span,shift); if (signal1==1) { cerrada=OrderCloseReliable(order_ticket1,order_lots1,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit1=0; close_profit1=0; } } } // ------------------------------------------------------------------------------------------------ // ROBOT // ------------------------------------------------------------------------------------------------ void Robot2() { int ticket=-1, i; bool cerrada=FALSE; if (orders2==0 && direction2==0) { signal2 = CalculaSignal(2,tenkan_sen,kijun_sen,senkou_span,shift); // ---------- // COMPRA // ---------- if (signal2==1) ticket = OrderSendReliable(Symbol(),OP_BUY,CalcularVolumen(2),MarketInfo(Symbol(),MODE_ASK),slippage,0,0,key2,magic2,0,Blue); // En este punto hemos ejecutado correctamente la orden de compra // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() // ---------- // VENTA // ---------- if (signal2==2) ticket = OrderSendReliable(Symbol(),OP_SELL,CalcularVolumen(2),MarketInfo(Symbol(),MODE_BID),slippage,0,0,key2,magic2,0,Red); // En este punto hemos ejecutado correctamente la orden de venta // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=1 // ************************************************** if (orders2>0 && direction2==1 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit2 > CalculaTakeProfit(2) && max_profit2==0) { max_profit2 = order_profit2; close_profit2 = profit_lock*order_profit2; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit2>0) { if (order_profit2>max_profit2) { max_profit2 = order_profit2; close_profit2 = profit_lock*order_profit2; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit2>0 && close_profit2>0 && max_profit2>close_profit2 && order_profit2>> Tenemos "size" pips de perdida if (order_profit2 <= CalculaStopLoss(2)) { cerrada=OrderCloseReliable(order_ticket2,order_lots2,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit2=0; close_profit2=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=1 // ************************************************** if (orders2>0 && direction2==2 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit2 > CalculaTakeProfit(2) && max_profit2==0) { max_profit2 = order_profit2; close_profit2 = profit_lock*order_profit2; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit2>0) { if (order_profit2>max_profit2) { max_profit2 = order_profit2; close_profit2 = profit_lock*order_profit2; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit2>0 && close_profit2>0 && max_profit2>close_profit2 && order_profit2>> Tenemos "size" pips de perdida if (order_profit2 <= CalculaStopLoss(2)) { cerrada=OrderCloseReliable(order_ticket2,order_lots2,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit2=0; close_profit2=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=0 // ************************************************** if (orders2 && direction2==1 && use_tp_sl==0) { signal2 = CalculaSignal(2,tenkan_sen,kijun_sen,senkou_span,shift); if (signal2==2) { cerrada=OrderCloseReliable(order_ticket2,order_lots2,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit2=0; close_profit2=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=0 // ************************************************** if (orders2>0 && direction2==2 && use_tp_sl==0) { signal2 = CalculaSignal(2,tenkan_sen,kijun_sen,senkou_span,shift); if (signal2==1) { cerrada=OrderCloseReliable(order_ticket2,order_lots2,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit2=0; close_profit2=0; } } } // ------------------------------------------------------------------------------------------------ // ROBOT 3 // ------------------------------------------------------------------------------------------------ void Robot3() { int ticket=-1, i; bool cerrada=FALSE; if (orders3==0 && direction3==0) { signal3 = CalculaSignal(3,tenkan_sen,kijun_sen,senkou_span,shift); // ---------- // COMPRA // ---------- if (signal3==1) ticket = OrderSendReliable(Symbol(),OP_BUY,CalcularVolumen(3),MarketInfo(Symbol(),MODE_ASK),slippage,0,0,key3,magic3,0,Blue); // En este punto hemos ejecutado correctamente la orden de compra // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() // ---------- // VENTA // ---------- if (signal3==2) ticket = OrderSendReliable(Symbol(),OP_SELL,CalcularVolumen(3),MarketInfo(Symbol(),MODE_BID),slippage,0,0,key3,magic3,0,Red); // En este punto hemos ejecutado correctamente la orden de venta // Los arrays se actualizarán en la siguiente ejecución de start() con ActualizarOrdenes() } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=1 // ************************************************** if (orders3>0 && direction3==1 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit3 > CalculaTakeProfit(3) && max_profit3==0) { max_profit3 = order_profit3; close_profit3 = profit_lock*order_profit3; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit3>0) { if (order_profit3>max_profit3) { max_profit3 = order_profit3; close_profit3 = profit_lock*order_profit3; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit3>0 && close_profit3>0 && max_profit3>close_profit3 && order_profit3>> Tenemos "size" pips de perdida if (order_profit3 <= CalculaStopLoss(3)) { cerrada=OrderCloseReliable(order_ticket3,order_lots3,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit3=0; close_profit3=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=1 // ************************************************** if (orders3>0 && direction3==2 && use_tp_sl==1) { // CASO 1.1 >>> Tenemos el beneficio y activamos el profit lock if (order_profit3 > CalculaTakeProfit(3) && max_profit3==0) { max_profit3 = order_profit3; close_profit3 = profit_lock*order_profit3; } // CASO 1.2 >>> Segun va aumentando el beneficio actualizamos el profit lock if (max_profit3>0) { if (order_profit3>max_profit3) { max_profit3 = order_profit3; close_profit3 = profit_lock*order_profit3; } } // CASO 1.3 >>> Cuando el beneficio caiga por debajo de profit lock cerramos las ordenes if (max_profit3>0 && close_profit3>0 && max_profit3>close_profit3 && order_profit3>> Tenemos "size" pips de perdida if (order_profit3 <= CalculaStopLoss(3)) { cerrada=OrderCloseReliable(order_ticket3,order_lots3,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit3=0; close_profit3=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=1 AND USE_TP_SL=0 // ************************************************** if (orders3>0 && direction3==1 && use_tp_sl==0) { signal3 = CalculaSignal(3,tenkan_sen,kijun_sen,senkou_span,shift); if (signal3==2) { cerrada=OrderCloseReliable(order_ticket3,order_lots3,MarketInfo(Symbol(),MODE_BID),slippage,Blue); max_profit3=0; close_profit3=0; } } // ************************************************** // ORDERS>0 AND DIRECTION=2 AND USE_TP_SL=0 // ************************************************** if (orders3>0 && direction3==2 && use_tp_sl==0) { signal3 = CalculaSignal(3,tenkan_sen,kijun_sen,senkou_span,shift); if (signal3==1) { cerrada=OrderCloseReliable(order_ticket3,order_lots3,MarketInfo(Symbol(),MODE_ASK),slippage,Red); max_profit3=0; close_profit3=0; } } } //============================================================================= // OrderSendReliable() // // This is intended to be a drop-in replacement for OrderSend() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // RETURN VALUE: // // Ticket number or -1 under some error conditions. Check // final error returned by Metatrader with OrderReliableLastErr(). // This will reset the value from GetLastError(), so in that sense it cannot // be a total drop-in replacement due to Metatrader flaw. // // FEATURES: // // * Re-trying under some error conditions, sleeping a random // time defined by an exponential probability distribution. // // * Automatic normalization of Digits // // * Automatically makes sure that stop levels are more than // the minimum stop distance, as given by the server. If they // are too close, they are adjusted. // // * Automatically converts stop orders to market orders // when the stop orders are rejected by the server for // being to close to market. NOTE: This intentionally // applies only to OP_BUYSTOP and OP_SELLSTOP, // OP_BUYLIMIT and OP_SELLLIMIT are not converted to market // orders and so for prices which are too close to current // this function is likely to loop a few times and return // with the "invalid stops" error message. // Note, the commentary in previous versions erroneously said // that limit orders would be converted. Note also // that entering a BUYSTOP or SELLSTOP new order is distinct // from setting a stoploss on an outstanding order; use // OrderModifyReliable() for that. // // * Displays various error messages on the log for debugging. // // // Matt Kennel, 2006-05-28 and following // //============================================================================= int OrderSendReliable(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration = 0, color arrow_color = CLR_NONE) { // ------------------------------------------------ // Check basic conditions see if trade is possible. // ------------------------------------------------ OrderReliable_Fname = "OrderSendReliable"; OrderReliablePrint(" attempted " + OrderReliable_CommandString(cmd) + " " + volume + " lots @" + price + " sl:" + stoploss + " tp:" + takeprofit); //if (!IsConnected()) //{ // OrderReliablePrint("error: IsConnected() == false"); // _OR_err = ERR_NO_CONNECTION; // return(-1); //} if (IsStopped()) { OrderReliablePrint("error: IsStopped() == true"); _OR_err = ERR_COMMON_ERROR; return(-1); } int cnt = 0; while(!IsTradeAllowed() && cnt < retry_attempts) { OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); cnt++; } if (!IsTradeAllowed()) { OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries."); _OR_err = ERR_TRADE_CONTEXT_BUSY; return(-1); } // Normalize all price / stoploss / takeprofit to the proper # of digits. int digits = MarketInfo(symbol, MODE_DIGITS); if (digits > 0) { price = NormalizeDouble(price, digits); stoploss = NormalizeDouble(stoploss, digits); takeprofit = NormalizeDouble(takeprofit, digits); } if (stoploss != 0) OrderReliable_EnsureValidStop(symbol, price, stoploss); int err = GetLastError(); // clear the global variable. err = 0; _OR_err = 0; bool exit_loop = false; bool limit_to_market = false; // limit/stop order. int ticket=-1; if ((cmd == OP_BUYSTOP) || (cmd == OP_SELLSTOP) || (cmd == OP_BUYLIMIT) || (cmd == OP_SELLLIMIT)) { cnt = 0; while (!exit_loop) { if (IsTradeAllowed()) { ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color); err = GetLastError(); _OR_err = err; } else { cnt++; } switch (err) { case ERR_NO_ERROR: exit_loop = true; break; // retryable errors case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: cnt++; break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: RefreshRates(); continue; // we can apparently retry immediately according to MT docs. case ERR_INVALID_STOPS: double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * MarketInfo(symbol, MODE_POINT); if (cmd == OP_BUYSTOP) { // If we are too close to put in a limit/stop order so go to market. if (MathAbs(MarketInfo(symbol,MODE_ASK) - price) <= servers_min_stop) limit_to_market = true; } else if (cmd == OP_SELLSTOP) { // If we are too close to put in a limit/stop order so go to market. if (MathAbs(MarketInfo(symbol,MODE_BID) - price) <= servers_min_stop) limit_to_market = true; } exit_loop = true; break; default: // an apparently serious error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (exit_loop) { if (err != ERR_NO_ERROR) { OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); } if (cnt > retry_attempts) { OrderReliablePrint("retry attempts maxed at " + retry_attempts); } } if (!exit_loop) { OrderReliablePrint("retryable error (" + cnt + "/" + retry_attempts + "): " + OrderReliableErrTxt(err)); OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); RefreshRates(); } } // We have now exited from loop. if (err == ERR_NO_ERROR) { OrderReliablePrint("apparently successful OP_BUYSTOP or OP_SELLSTOP order placed, details follow."); OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(ticket); // SUCCESS! } if (!limit_to_market) { OrderReliablePrint("failed to execute stop or limit order after " + cnt + " retries"); OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + "@" + price + " tp@" + takeprofit + " sl@" + stoploss); OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); return(-1); } } // end if (limit_to_market) { OrderReliablePrint("going from limit order to market order because market is too close."); if ((cmd == OP_BUYSTOP) || (cmd == OP_BUYLIMIT)) { cmd = OP_BUY; price = MarketInfo(symbol,MODE_ASK); } else if ((cmd == OP_SELLSTOP) || (cmd == OP_SELLLIMIT)) { cmd = OP_SELL; price = MarketInfo(symbol,MODE_BID); } } // we now have a market order. err = GetLastError(); // so we clear the global variable. err = 0; _OR_err = 0; ticket = -1; if ((cmd == OP_BUY) || (cmd == OP_SELL)) { cnt = 0; while (!exit_loop) { if (IsTradeAllowed()) { ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color); err = GetLastError(); _OR_err = err; } else { cnt++; } switch (err) { case ERR_NO_ERROR: exit_loop = true; break; case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: cnt++; // a retryable error break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: RefreshRates(); continue; // we can apparently retry immediately according to MT docs. default: // an apparently serious, unretryable error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("retryable error (" + cnt + "/" + retry_attempts + "): " + OrderReliableErrTxt(err)); OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); RefreshRates(); } if (exit_loop) { if (err != ERR_NO_ERROR) { OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); } if (cnt > retry_attempts) { OrderReliablePrint("retry attempts maxed at " + retry_attempts); } } } // we have now exited from loop. if (err == ERR_NO_ERROR) { OrderReliablePrint("apparently successful OP_BUY or OP_SELL order placed, details follow."); OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(ticket); // SUCCESS! } OrderReliablePrint("failed to execute OP_BUY/OP_SELL, after " + cnt + " retries"); OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + "@" + price + " tp@" + takeprofit + " sl@" + stoploss); OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); return(-1); } } //============================================================================= // OrderSendReliableMKT() // // This is intended to be an alternative for OrderSendReliable() which // will update market-orders in the retry loop with the current Bid or Ask. // Hence with market orders there is a greater likelihood that the trade will // be executed versus OrderSendReliable(), and a greater likelihood it will // be executed at a price worse than the entry price due to price movement. // // RETURN VALUE: // // Ticket number or -1 under some error conditions. Check // final error returned by Metatrader with OrderReliableLastErr(). // This will reset the value from GetLastError(), so in that sense it cannot // be a total drop-in replacement due to Metatrader flaw. // // FEATURES: // // * Most features of OrderSendReliable() but for market orders only. // Command must be OP_BUY or OP_SELL, and specify Bid or Ask at // the time of the call. // // * If price moves in an unfavorable direction during the loop, // e.g. from requotes, then the slippage variable it uses in // the real attempt to the server will be decremented from the passed // value by that amount, down to a minimum of zero. If the current // price is too far from the entry value minus slippage then it // will not attempt an order, and it will signal, manually, // an ERR_INVALID_PRICE (displayed to log as usual) and will continue // to loop the usual number of times. // // * Displays various error messages on the log for debugging. // // // Matt Kennel, 2006-08-16 // //============================================================================= int OrderSendReliableMKT(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration = 0, color arrow_color = CLR_NONE) { // ------------------------------------------------ // Check basic conditions see if trade is possible. // ------------------------------------------------ OrderReliable_Fname = "OrderSendReliableMKT"; OrderReliablePrint(" attempted " + OrderReliable_CommandString(cmd) + " " + volume + " lots @" + price + " sl:" + stoploss + " tp:" + takeprofit); if ((cmd != OP_BUY) && (cmd != OP_SELL)) { OrderReliablePrint("Improper non market-order command passed. Nothing done."); _OR_err = ERR_MALFUNCTIONAL_TRADE; return(-1); } //if (!IsConnected()) //{ // OrderReliablePrint("error: IsConnected() == false"); // _OR_err = ERR_NO_CONNECTION; // return(-1); //} if (IsStopped()) { OrderReliablePrint("error: IsStopped() == true"); _OR_err = ERR_COMMON_ERROR; return(-1); } int cnt = 0; while(!IsTradeAllowed() && cnt < retry_attempts) { OrderReliable_SleepRandomTime(sleep_time, sleep_maximum); cnt++; } if (!IsTradeAllowed()) { OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries."); _OR_err = ERR_TRADE_CONTEXT_BUSY; return(-1); } // Normalize all price / stoploss / takeprofit to the proper # of digits. int digits = MarketInfo(symbol, MODE_DIGITS); if (digits > 0) { price = NormalizeDouble(price, digits); stoploss = NormalizeDouble(stoploss, digits); takeprofit = NormalizeDouble(takeprofit, digits); } if (stoploss != 0) OrderReliable_EnsureValidStop(symbol, price, stoploss); int err = GetLastError(); // clear the global variable. err = 0; _OR_err = 0; bool exit_loop = false; // limit/stop order. int ticket=-1; // we now have a market order. err = GetLastError(); // so we clear the global variable. err = 0; _OR_err = 0; ticket = -1; if ((cmd == OP_BUY) || (cmd == OP_SELL)) { cnt = 0; while (!exit_loop) { if (IsTradeAllowed()) { double pnow = price; int slippagenow = slippage; if (cmd == OP_BUY) { // modification by Paul Hampton-Smith to replace RefreshRates() pnow = NormalizeDouble(MarketInfo(symbol,MODE_ASK),MarketInfo(symbol,MODE_DIGITS)); // we are buying at Ask if (pnow > price) { slippagenow = slippage - (pnow-price)/MarketInfo(symbol,MODE_POINT); } } else if (cmd == OP_SELL) { // modification by Paul Hampton-Smith to replace RefreshRates() pnow = NormalizeDouble(MarketInfo(symbol,MODE_BID),MarketInfo(symbol,MODE_DIGITS)); // we are buying at Ask if (pnow < price) { // moved in an unfavorable direction slippagenow = slippage - (price-pnow)/MarketInfo(symbol,MODE_POINT); } } if (slippagenow > slippage) slippagenow = slippage; if (slippagenow >= 0) { ticket = OrderSend(symbol, cmd, volume, pnow, slippagenow, stoploss, takeprofit, comment, magic, expiration, arrow_color); err = GetLastError(); _OR_err = err; } else { // too far away, manually signal ERR_INVALID_PRICE, which // will result in a sleep and a retry. err = ERR_INVALID_PRICE; _OR_err = err; } } else { cnt++; } switch (err) { case ERR_NO_ERROR: exit_loop = true; break; case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: cnt++; // a retryable error break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: // Paul Hampton-Smith removed RefreshRates() here and used MarketInfo() above instead continue; // we can apparently retry immediately according to MT docs. default: // an apparently serious, unretryable error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("retryable error (" + cnt + "/" + retry_attempts + "): " + OrderReliableErrTxt(err)); OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); } if (exit_loop) { if (err != ERR_NO_ERROR) { OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); } if (cnt > retry_attempts) { OrderReliablePrint("retry attempts maxed at " + retry_attempts); } } } // we have now exited from loop. if (err == ERR_NO_ERROR) { OrderReliablePrint("apparently successful OP_BUY or OP_SELL order placed, details follow."); OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(ticket); // SUCCESS! } OrderReliablePrint("failed to execute OP_BUY/OP_SELL, after " + cnt + " retries"); OrderReliablePrint("failed trade: " + OrderReliable_CommandString(cmd) + " " + symbol + "@" + price + " tp@" + takeprofit + " sl@" + stoploss); OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); return(-1); } } //============================================================================= // OrderModifyReliable() // // This is intended to be a drop-in replacement for OrderModify() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // RETURN VALUE: // // TRUE if successful, FALSE otherwise // // // FEATURES: // // * Re-trying under some error conditions, sleeping a random // time defined by an exponential probability distribution. // // * Displays various error messages on the log for debugging. // // // Matt Kennel, 2006-05-28 // //============================================================================= bool OrderModifyReliable(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color = CLR_NONE) { OrderReliable_Fname = "OrderModifyReliable"; OrderReliablePrint(" attempted modify of #" + ticket + " price:" + price + " sl:" + stoploss + " tp:" + takeprofit); //if (!IsConnected()) //{ // OrderReliablePrint("error: IsConnected() == false"); // _OR_err = ERR_NO_CONNECTION; // return(false); //} if (IsStopped()) { OrderReliablePrint("error: IsStopped() == true"); return(false); } int cnt = 0; while(!IsTradeAllowed() && cnt < retry_attempts) { OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); cnt++; } if (!IsTradeAllowed()) { OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries."); _OR_err = ERR_TRADE_CONTEXT_BUSY; return(false); } if (false) { // This section is 'nulled out', because // it would have to involve an 'OrderSelect()' to obtain // the symbol string, and that would change the global context of the // existing OrderSelect, and hence would not be a drop-in replacement // for OrderModify(). // // See OrderModifyReliableSymbol() where the user passes in the Symbol // manually. OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); string symbol = OrderSymbol(); int digits = MarketInfo(symbol,MODE_DIGITS); if (digits > 0) { price = NormalizeDouble(price,digits); stoploss = NormalizeDouble(stoploss,digits); takeprofit = NormalizeDouble(takeprofit,digits); } if (stoploss != 0) OrderReliable_EnsureValidStop(symbol,price,stoploss); } int err = GetLastError(); // so we clear the global variable. err = 0; _OR_err = 0; bool exit_loop = false; cnt = 0; bool result = false; while (!exit_loop) { if (IsTradeAllowed()) { result = OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color); err = GetLastError(); _OR_err = err; } else cnt++; if (result == true) exit_loop = true; switch (err) { case ERR_NO_ERROR: exit_loop = true; break; case ERR_NO_RESULT: // modification without changing a parameter. // if you get this then you may want to change the code. exit_loop = true; break; case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: case ERR_TRADE_TIMEOUT: // for modify this is a retryable error, I hope. cnt++; // a retryable error break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: RefreshRates(); continue; // we can apparently retry immediately according to MT docs. default: // an apparently serious, unretryable error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("retryable error (" + cnt + "/" + retry_attempts + "): " + OrderReliableErrTxt(err)); OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); RefreshRates(); } if (exit_loop) { if ((err != ERR_NO_ERROR) && (err != ERR_NO_RESULT)) OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); if (cnt > retry_attempts) OrderReliablePrint("retry attempts maxed at " + retry_attempts); } } // we have now exited from loop. if ((result == true) || (err == ERR_NO_ERROR)) { OrderReliablePrint("apparently successful modification order, updated trade details follow."); OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(true); // SUCCESS! } if (err == ERR_NO_RESULT) { OrderReliablePrint("Server reported modify order did not actually change parameters."); OrderReliablePrint("redundant modification: " + ticket + " " + symbol + "@" + price + " tp@" + takeprofit + " sl@" + stoploss); OrderReliablePrint("Suggest modifying code logic to avoid."); return(true); } OrderReliablePrint("failed to execute modify after " + cnt + " retries"); OrderReliablePrint("failed modification: " + ticket + " " + symbol + "@" + price + " tp@" + takeprofit + " sl@" + stoploss); OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); return(false); } //============================================================================= // // OrderModifyReliableSymbol() // // This has the same calling sequence as OrderModify() except that the // user must provide the symbol. // // This function will then be able to ensure proper normalization and // stop levels. // //============================================================================= bool OrderModifyReliableSymbol(string symbol, int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color = CLR_NONE) { int digits = MarketInfo(symbol, MODE_DIGITS); if (digits > 0) { price = NormalizeDouble(price, digits); stoploss = NormalizeDouble(stoploss, digits); takeprofit = NormalizeDouble(takeprofit, digits); } if (stoploss != 0) OrderReliable_EnsureValidStop(symbol, price, stoploss); return(OrderModifyReliable(ticket, price, stoploss, takeprofit, expiration, arrow_color)); } //============================================================================= // OrderCloseReliable() // // This is intended to be a drop-in replacement for OrderClose() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // RETURN VALUE: // // TRUE if successful, FALSE otherwise // // // FEATURES: // // * Re-trying under some error conditions, sleeping a random // time defined by an exponential probability distribution. // // * Displays various error messages on the log for debugging. // // // Derk Wehler, ashwoods155@yahoo.com 2006-07-19 // //============================================================================= bool OrderCloseReliable(int ticket, double lots, double price, int slippage, color arrow_color = CLR_NONE) { int nOrderType; string strSymbol; OrderReliable_Fname = "OrderCloseReliable"; OrderReliablePrint(" attempted close of #" + ticket + " price:" + price + " lots:" + lots + " slippage:" + slippage); // collect details of order so that we can use GetMarketInfo later if needed if (!OrderSelect(ticket,SELECT_BY_TICKET)) { _OR_err = GetLastError(); OrderReliablePrint("error: " + ErrorDescription(_OR_err)); return(false); } else { nOrderType = OrderType(); strSymbol = OrderSymbol(); } if (nOrderType != OP_BUY && nOrderType != OP_SELL) { _OR_err = ERR_INVALID_TICKET; OrderReliablePrint("error: trying to close ticket #" + ticket + ", which is " + OrderReliable_CommandString(nOrderType) + ", not OP_BUY or OP_SELL"); return(false); } //if (!IsConnected()) //{ // OrderReliablePrint("error: IsConnected() == false"); // _OR_err = ERR_NO_CONNECTION; // return(false); //} if (IsStopped()) { OrderReliablePrint("error: IsStopped() == true"); return(false); } int cnt = 0; /* Commented out by Paul Hampton-Smith due to a bug in MT4 that sometimes incorrectly returns IsTradeAllowed() = false while(!IsTradeAllowed() && cnt < retry_attempts) { OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); cnt++; } if (!IsTradeAllowed()) { OrderReliablePrint("error: no operation possible because IsTradeAllowed()==false, even after retries."); _OR_err = ERR_TRADE_CONTEXT_BUSY; return(false); } */ int err = GetLastError(); // so we clear the global variable. err = 0; _OR_err = 0; bool exit_loop = false; cnt = 0; bool result = false; while (!exit_loop) { if (IsTradeAllowed()) { result = OrderClose(ticket, lots, price, slippage, arrow_color); err = GetLastError(); _OR_err = err; } else cnt++; if (result == true) exit_loop = true; switch (err) { case ERR_NO_ERROR: exit_loop = true; break; case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: case ERR_TRADE_TIMEOUT: // for modify this is a retryable error, I hope. cnt++; // a retryable error break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: continue; // we can apparently retry immediately according to MT docs. default: // an apparently serious, unretryable error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("retryable error (" + cnt + "/" + retry_attempts + "): " + OrderReliableErrTxt(err)); OrderReliable_SleepRandomTime(sleep_time,sleep_maximum); // Added by Paul Hampton-Smith to ensure that price is updated for each retry if (nOrderType == OP_BUY) price = NormalizeDouble(MarketInfo(strSymbol,MODE_BID),MarketInfo(strSymbol,MODE_DIGITS)); if (nOrderType == OP_SELL) price = NormalizeDouble(MarketInfo(strSymbol,MODE_ASK),MarketInfo(strSymbol,MODE_DIGITS)); } if (exit_loop) { if ((err != ERR_NO_ERROR) && (err != ERR_NO_RESULT)) OrderReliablePrint("non-retryable error: " + OrderReliableErrTxt(err)); if (cnt > retry_attempts) OrderReliablePrint("retry attempts maxed at " + retry_attempts); } } // we have now exited from loop. if ((result == true) || (err == ERR_NO_ERROR)) { OrderReliablePrint("apparently successful close order, updated trade details follow."); OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(true); // SUCCESS! } OrderReliablePrint("failed to execute close after " + cnt + " retries"); OrderReliablePrint("failed close: Ticket #" + ticket + ", Price: " + price + ", Slippage: " + slippage); OrderReliablePrint("last error: " + OrderReliableErrTxt(err)); return(false); } //============================================================================= //============================================================================= // Utility Functions //============================================================================= //============================================================================= int OrderReliableLastErr() { return (_OR_err); } string OrderReliableErrTxt(int err) { return ("" + err + ":" + ErrorDescription(err)); } void OrderReliablePrint(string s) { // Print to log prepended with stuff; if (!(IsTesting() || IsOptimization())) Print(OrderReliable_Fname + " " + OrderReliableVersion + ":" + s); } string OrderReliable_CommandString(int cmd) { if (cmd == OP_BUY) return("OP_BUY"); if (cmd == OP_SELL) return("OP_SELL"); if (cmd == OP_BUYSTOP) return("OP_BUYSTOP"); if (cmd == OP_SELLSTOP) return("OP_SELLSTOP"); if (cmd == OP_BUYLIMIT) return("OP_BUYLIMIT"); if (cmd == OP_SELLLIMIT) return("OP_SELLLIMIT"); return("(CMD==" + cmd + ")"); } //============================================================================= // // OrderReliable_EnsureValidStop() // // Adjust stop loss so that it is legal. // // Matt Kennel // //============================================================================= void OrderReliable_EnsureValidStop(string symbol, double price, double& sl) { // Return if no S/L if (sl == 0) return; double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * MarketInfo(symbol, MODE_POINT); if (MathAbs(price - sl) <= servers_min_stop) { // we have to adjust the stop. if (price > sl) sl = price - servers_min_stop; // we are long else if (price < sl) sl = price + servers_min_stop; // we are short else OrderReliablePrint("EnsureValidStop: error, passed in price == sl, cannot adjust"); sl = NormalizeDouble(sl, MarketInfo(symbol, MODE_DIGITS)); } } //============================================================================= // // OrderReliable_SleepRandomTime() // // This sleeps a random amount of time defined by an exponential // probability distribution. The mean time, in Seconds is given // in 'mean_time'. // // This is the back-off strategy used by Ethernet. This will // quantize in tenths of seconds, so don't call this with a too // small a number. This returns immediately if we are backtesting // and does not sleep. // // Matt Kennel mbkennelfx@gmail.com. // //============================================================================= void OrderReliable_SleepRandomTime(double mean_time, double max_time) { if (IsTesting()) return; // return immediately if backtesting. double tenths = MathCeil(mean_time / 0.1); if (tenths <= 0) return; int maxtenths = MathRound(max_time/0.1); double p = 1.0 - 1.0 / tenths; Sleep(100); // one tenth of a second PREVIOUS VERSIONS WERE STUPID HERE. for(int i=0; i < maxtenths; i++) { if (MathRand() > p*32768) break; // MathRand() returns in 0..32767 Sleep(100); } }