sar02mod7b начальные параметры недооптимизированы под пару eur/usd. Как обещал, публикую.

Параметры под центовый счёт алпари. Пара евро-бакс. Параметров много, некоторые взаимоисключающие. Конструктивные замечания по коду с удовольствием рассмотрю.

Тег «коде» не обеспечивает нормальный моноширинный шрифт. Пробелы проседают. Минус заводчикам.

/***************************************************************************************************
*         Copyright 2014, zoolook@netfram.com                                                      *
*                         http://www.netfram.com                                                   *
***************************************************************************************************/
#property copyright                       "zoolook@netfram.com"
#property link                            "http://www.netfram.com"
#define   version                         "sar02mod7b"
//+------------------------------------------------------------------------------------------------+
extern double    BaseLot = 0.01;    // начальный/минимальный лот
extern double    MaxiLot = 10.0;    // максимально допустимый лот
extern double     LotExp = 1.7;     // мартингейл
extern bool       EquLot = false;   // lot_buy = lot_sell, актуален только для LotExp > 1
extern int    DynamicLot = 1;       // 0=BaseLot, 1=FreeMargin, 2=Equity, 3=Balance
extern double RiskFactor = 0.0001;  // риск от средств счёта для динамического лота
extern int      RaisePct = 0;       // процент доливки по тренду от объема позиций (0 = нет доливки)
extern bool     RaiseAll = false;   // игнорировать убыточные позиции при доливке
//+------------------------------------------------------------------------------------------------+
extern int    TakeProfit = 263;     // финальная прибыль в пунктах для всех ордеров серии (0 = нет)
extern int    StopProfit = 114;     // мин. прибыль в пунктах для начала трейлинга (0 = нет трейла)
extern int      Trailing = 7;       // дистанция трейлинг-стопа до Bid/Ask
//+------------------------------------------------------------------------------------------------+
extern int       PipStep = 1;       // базовая дистанция между ордерами
extern double     PipExp = 1.0;     // приращение дистанции в серии
extern bool  DynamicPips = false;   // динамический расчёт дистанции на истории
extern int      DynPipTF = 240;     // таймфрейм истории для динамики
extern int    DynPipBars = 4;       // глубина истории для динамики
extern double   DynPipCo = 2.0;     // множитель|делитель для динамики
//+------------------------------------------------------------------------------------------------+
extern bool  ClOverInner = true;    // закрывать перекрытые ордера внутренние или внешние
extern int    ClOverPips = 15;      // закрывать перекрытые ордера с заданной дельтой
extern int    ClOverDay  = 5;       // пятница     > для отключения данного функционала  <
extern int    ClOverHour = 22;      // 23 часа     > достаточно поставить несуществующий <
extern int  ClOverMinute = 50;      // 59 минут    > день недели или время               <
//+------------------------------------------------------------------------------------------------+
extern bool     BarsOnly = false;   // работа только на новых барах
extern bool    AllOrders = false;   // все ордера, игнор Magic
extern bool     AutoStop = true;    // false = только с явно заданным стопом
//+------------------------------------------------------------------------------------------------+
extern double OrderAccel = 0.047;   // ускорение SAR для отложников
extern int    OrderShift = 0;       // сдвиг SAR для отложников
extern double TrailAccel = 0.13;    // ускорение SAR для трейлинг-стопа
extern int    TrailShift = 0;       // сдвиг SAR для трейлинг-стопа
//+------------------------------------------------------------------------------------------------+
extern int    MaxTickets = 9;       // максимальное число ордеров в серии
extern int      Slippage = 3;       // допустимое проскальзывание при входе с рынка
extern int      GlobalTF = 5;       // актуальный таймфрейм пары (0 = работа по текущему TF графика)
extern int       TrailTF = 5;       // таймфрейм трейлинга стопов по SAR (0 = по текущему)
//+------------------------------------------------------------------------------------------------+
extern bool  ShowAvg = true;        // показывать уровни усреднений, тейков и объемы
extern color    cMPB = DodgerBlue;  // цвет средневзвешенного buy
extern color    cMPS = DeepPink;    // цвет средневзвешенного sell
//+------------------------------------------------------------------------------------------------+
extern int     Magic = 20150305;    // уникальный ИД ордеров
//+------------------------------------------------------------------------------------------------+

static double MinLot;               // минимальный лот на рынке
static int    LotDec;               // количество знаков после запятой для Lot
static int    Spread;               // спрэд в пунктах

//+------------------------------------------------------------------------------------------------+
//| expert initialization function                                                                 |
//+------------------------------------------------------------------------------------------------+
int init()
{
   MinLot = MarketInfo(Symbol(), MODE_MINLOT);
   LotDec = log10(1 / MarketInfo(Symbol(), MODE_LOTSTEP));
   Spread = MarketInfo(Symbol(), MODE_SPREAD);

   Print("");
   Print("-----------------------------------");
   if (MinLot > BaseLot)
   {
      Print("!!!! WARNING: setting 'BaseLot' = ", MinLot);
      Print("!!!! WARNING: 'BaseLot' less than market minimal lot");
      BaseLot = MinLot;
   }
   Print("LotDecimal: ", LotDec);
   Print("    MinLot: ", MinLot);
   Print("    Spread: ", Spread);
   Print("     Point: ", DTS(Point));
   Print("    Digits: ", Digits);
   Print("---------- ", version, " ----------");
   Print("");

   return(0);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
   draw_median(0, 0, 0, 0, 0);
   return(0);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   static bool       DoRecalcBuy = true;     // требуется пересчет тейков бычьей серии
   static bool      DoRecalcSell = true;     // требуется пересчет тейков медвежьей серии
   static double  old_median_buy = 0;
   static double old_median_sell = 0;

   static datetime last_global_tf = 0;
   static datetime last_trailing_tf = 0;

   // закрываем перекрытые ордера в конце торговой недели
   if(DayOfWeek() == ClOverDay && Hour() >= ClOverHour && Minute() >= ClOverMinute)
   {
      close_overlapped(ClOverPips); /* ВНИМАНИЕ!!!: вызывается на каждый тик! доработать! */
      return (0);
   }

   if (BarsOnly == false || new_bar(last_trailing_tf, TrailTF)) traileraiser();


   double median_buy  = price_median(OP_BUY);
   double median_sell = price_median(OP_SELL);

   if (ShowAvg)
   {
      double vol_buy  = get_volume(OP_BUY);
      double vol_sell = get_volume(OP_SELL);
      Comment("-- Volume --", "\n Buy: ", DTS(vol_buy,  LotDec), "\n Sell: ", DTS(vol_sell, LotDec));
      draw_median(median_buy, vol_buy, median_sell, vol_sell/*, realtp*/);
   }

   if (median_buy  != old_median_buy)  { old_median_buy  = median_buy ;  DoRecalcBuy  = true; }
   if (median_sell != old_median_sell) { old_median_sell = median_sell ; DoRecalcSell = true; }

   int i;
   double realtp = (TakeProfit + Spread) * Point;

   if (DoRecalcBuy == true && median_buy > 0)
   {
      DoRecalcBuy = false;
      for (i = OrdersTotal() - 1; i >= 0; i--)
         if (is_mine_by_index(i) && OrderType() == OP_BUY)
            DoRecalcBuy |= (order_mod(0 /* price */, 0 /* SL */,  median_buy + realtp)  != 0);
   } else DoRecalcBuy = false;

   if (DoRecalcSell == true && median_sell > 0)
   {
      DoRecalcSell = false;
      for (i = OrdersTotal() - 1; i >= 0; i--)
         if (is_mine_by_index(i) && OrderType() == OP_SELL)
            DoRecalcSell |= (order_mod(0 /* price */, 0 /* SL */, median_sell - realtp) != 0);
   } else DoRecalcSell = false;

   if (DoRecalcBuy || DoRecalcSell) // что-то пошло не так при корректировке тейка
      Print("!!! WARNING: DoRecalcBuy || DoRecalcSell [", DoRecalcBuy, " | ", DoRecalcSell, "] !!!");

   // индикатор SAR изменяется только на новых барах
   if (BarsOnly && new_bar(last_global_tf, GlobalTF) == false) return (0);

   int count_buy  = order_count(OP_BUY);
   int count_sell = order_count(OP_SELL);

   // динамический лот рассчитывается исходя из текущего размера собственных средств
   // эмпирика: каждые 100$ свободных средств = 0.1 лота при EquityRisk = 0.1
   // без динамики hi/lo по барам и учёта максимального количества ордеров
   // внешняя переменная DynamicLot определяет источник (в порядке убывания агрессивности):
   // 1) свободные для открытия ордера, 2) средства без учёта маржи, 3) баланс (практики не имеет)

   double lot, lot_sell, lot_buy;

   switch(DynamicLot)
   {
      case 1:  lot = AccountFreeMargin() / 100 * RiskFactor; break;
      case 2:  lot = AccountEquity()     / 100 * RiskFactor; break;
      case 3:  lot = AccountBalance()    / 100 * RiskFactor; break;
      default: lot = BaseLot; break;
   }

   if (EquLot)
   {
      lot_buy = NormalizeDouble(lot * MathPow(LotExp, MathMax(count_buy, count_sell)), LotDec);
      lot_sell = lot_buy = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
   }
   else
   {
      lot_buy  = NormalizeDouble(lot * MathPow(LotExp, count_buy),  LotDec);
      lot_buy  = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
      lot_sell = NormalizeDouble(lot * MathPow(LotExp, count_sell), LotDec);
      lot_sell = MathMin(MathMax(lot_buy, BaseLot), MaxiLot);
   }

   /* вычисляем динамический шаг ордера, честно спизжено из робота Ilan1.6Dynamic
      идея: попробовать разный шаг для buy/sell от близости Bid/Ask к hi и lo */
   if (DynamicPips)
   {
      double pips = ( High[iHighest(NULL, DynPipTF, MODE_HIGH, DynPipBars, 1)]
                    - Low[iLowest(NULL,   DynPipTF, MODE_LOW,  DynPipBars, 1)] )
                    / Point / DynPipCo;
      // компактно   \            (PipStep/DynPipCo) <= pips <= (PipStep*DynPipCo)
      // реализует    >      if (pips < PipStep / DynPipCo) pips = PipStep / DynPipCo;
      // алгоритм    /       if (pips > PipStep * DynPipCo) pips = PipStep * DynPipCo;
      pips = NormalizeDouble(MathMin(MathMax(pips, PipStep / DynPipCo), PipStep * DynPipCo), 0);
   } else pips = PipStep;

   double dist_buy  = Point * pips * MathPow( (count_buy  > 1) ? PipExp : 1, count_buy  );
   double dist_sell = Point * pips * MathPow( (count_sell > 1) ? PipExp : 1, count_sell );

   double sar0 = iSAR(Symbol(), GlobalTF, OrderAccel, OrderAccel * 10.0, 0);
   double sar  = iSAR(Symbol(), GlobalTF, OrderAccel, OrderAccel * 10.0, OrderShift);

   if ( (sar > sar0 || (sar == sar0 && OrderShift == 0)) && sar0 > Ask /* + dist_buy /  3.0 */) // медвежий тренд
      if (get_any_order(OP_BUYSTOP) >= 0) order_mod(sar, 0, sar + realtp);
         else if (count_buy == 0 || (count_buy < MaxTickets && (sar + dist_buy) < price_edge(OP_BUY)))
            order_open(OP_BUYSTOP, lot_buy, sar, 0, sar + realtp);

   if ( (sar < sar0 || (sar == sar0 && OrderShift == 0)) && sar0 < Bid /* - dist_sell / 3.0 */) // бычий тренд
      if (get_any_order(OP_SELLSTOP) >= 0) order_mod(sar, 0, sar - realtp);
         else if (count_sell == 0 || (count_sell < MaxTickets && (sar - dist_sell) > price_edge(OP_SELL)))
            order_open(OP_SELLSTOP, lot_sell, sar, 0, sar - realtp);

   return(0);
}


/**************************************************************************************************
                                  ТРЕЙЛИНГ СТОПОВ И ДОЛИВКА ПО ТРЕНДУ
 **************************************************************************************************
 Доливка по тренду лотом заданного процента от объема уже открытых позиций, при которой обеспечена
 заданная StopProfit минимальная прибыль в случае хода цены против ставки и срабатывания stop-loss.
 **************************************************************************************************/

void traileraiser()
{
   static double old_sar = 0;

   int i;

   // SAR для трейл-стопа и доливки по тренду
   double sar0 = iSAR(Symbol(), TrailTF, TrailAccel, TrailAccel * 10.0, 0);
   double sar  = iSAR(Symbol(), TrailTF, TrailAccel, TrailAccel * 10.0, TrailShift);

   // текущие объемы открытых позиций
   double buy_vol = get_volume(OP_BUY);

   bool bullish = (sar <= sar0 && sar0 < Bid);

   if (bullish && buy_vol > 0)   // тренд "бычий", есть открытые позиции BUY
   {
      // текущее усреднение и цель
      double buy_avg = price_median(OP_BUY);
      double buy_tgt = buy_avg + (StopProfit + Spread) * Point;

      // если значение SAR изменилось, а также
      // цель < SAR и SAR + трейлинг < Bid, двигаем стопы всех BUY ордеров по SAR
      if (sar != old_sar && sar > buy_tgt && sar < Bid - Trailing * Point)
      {
         for (i = OrdersTotal() - 1; i >= 0; i--)
            if (is_mine_by_index(i, OP_BUY) == true)
               order_mod(0 /* price*/, (TrailShift > 0) ? sar : sar0 /* SL, TP, arrow */);
         
         old_sar = sar;
      }

      // Доливка по тренду ( price_edge() может вернуть '0' при ошибке )
      if (RaisePct > 0 && (RaiseAll || price_edge(OP_BUY, true) - Bid < 0))
      {
         // размер лота для "доливки" вычисляется как процент от текущих объемов открытых позиций,
         // ограничен снизу и сверху значениями BaseLot и MaxiLot
         double buy_raise = NormalizeDouble(MathMin(MathMax(buy_vol * RaisePct / 100, BaseLot), MaxiLot), LotDec);

         /* расчитываем потенциальный уровень стопа после доливки:
               new_buy_vol = buy_vol + buy_raise;
               new_buy_avg = (buy_avg * buy_vol + Ask * buy_raise) / new_buy_vol;
               new_buy_tgt = new_buy_avg + (StopProfit + Spread) * Point;

            если new_buy_tgt укладывается в прибыль по StopProfit и находится выше SAR,
            открываем ордер на продажу с рынка и ставим стоп по SAR
         */
         if (sar < Bid - Trailing * Point && /* вычисление new_buy_tgt одной строкой */
             sar > ((buy_avg * buy_vol + Ask * buy_raise) / (buy_vol + buy_raise) + (StopProfit + Spread) * Point) &&
             price_edge(OP_BUY, true) < Bid - PipStep * Point && /* Ask - (PipStep + Spread) * Point */
             order_open(OP_BUY, buy_raise, Ask) >= 0) order_mod(0 /* price*/, sar /* SL, TP, arrow */);
       }
   }

   /////////////////////////////////////////// аналогично для SELL ///////////////////////////////////////////

   // текущие объемы открытых позиций
   double sell_vol = get_volume(OP_SELL);

   bool bearish = (sar >= sar0 && sar0 > Ask);

   if (bearish && sell_vol > 0)   // тренд "медвежий", есть открытые позиции SELL
   {
      // текущее усреднение и цель
      double sell_avg = price_median(OP_SELL);
      double sell_tgt = sell_avg - (StopProfit + Spread) * Point;

      // если значение SAR изменилось, а также
      // цель > SAR и SAR - трейлинг > Ask, двигаем стопы всех SELL ордеров по SAR
      if (sar != old_sar && sar < sell_tgt && sar > Ask + Trailing * Point)
      {
         for (i = OrdersTotal() - 1; i >= 0; i--)
            if (is_mine_by_index(i, OP_SELL) == true)
               order_mod(0 /* price*/, (TrailShift > 0) ? sar : sar0 /* SL, TP, arrow */);
         
         old_sar = sar;
      }

      // Доливка по тренду
      if (RaisePct > 0 && (RaiseAll || price_edge(OP_SELL, true) > Ask))
      {
         // размер лота для "доливки" вычисляется как процент от текущих объемов открытых позиций,
         // ограничен снизу и сверху значениями BaseLot и MaxiLot
         double sell_raise = NormalizeDouble(MathMin(MathMax(sell_vol * RaisePct / 100, BaseLot), MaxiLot), LotDec);

         /* расчитываем потенциальный уровень стопа после доливки:
               new_sell_vol = sell_vol + sell_raise;
               new_sell_avg = (sell_avg * sell_vol + Ask * sell_raise) / new_sell_vol;
               new_sell_tgt = new_sell_avg - (StopProfit + Spread) * Point;

            если new_sell_tgt укладывается в прибыль по StopProfit и находится выше SAR,
            открываем ордер на продажу с рынка и ставим стоп по SAR
         */
         if (sar > Ask + Trailing * Point && /* вычисление new_sell_tgt одной строкой */
             sar < ((sell_avg * sell_vol + Bid * sell_raise) / (sell_vol + sell_raise) - (StopProfit + Spread) * Point) &&
             price_edge(OP_SELL, true) > Ask + PipStep * Point && /* Bid + (PipStep + Spread) * Point */
             order_open(OP_SELL, sell_raise, Bid) >= 0) order_mod(0 /* price*/, sar /* SL, TP, arrow */);
       }
   }

   /* return (void); */
}


/******************************************************************************
   Возвращает глобальный ID первого попавшегося ордера по его типу,
   или (-1) если таких ордеров нет
******************************************************************************/
int get_any_order(int type)
{
   for (int i = OrdersTotal() - 1; i >= 0; i--)
      if ( is_mine_by_index(i) && (OrderType() == type) )
         return (OrderTicket());

   return (-1);
}

/******************************************************************************
   Возвращает флаг включения выбранного ордера в обработку (свой/чужой)
   Использует глобальные переменные:

   AllOrders   AutoStop
   true        true     -- все ордера
   true        false    -- все с явно заданным стопом
   false       *        -- только свои (magic)

   NB: Ордер должен быть предварительно выбран через 'OrderSelect'
******************************************************************************/
bool _is_mine()
{
   return (OrderSymbol() == Symbol() &&
          (OrderMagicNumber() == Magic || AllOrders) &&
          (OrderMagicNumber() == Magic || OrderStopLoss() > 0 || AutoStop));
}
//-----------------------------------------------------------------------------
bool is_mine_by_ticket(int ticket)
{
   return (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES) && _is_mine());
}
//-----------------------------------------------------------------------------
bool is_mine_by_index(int i)
{
   return (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && _is_mine());
}

//-----------------------------------------------------------------------------
bool is_mine_by_index(int i, int type)
{
   return (is_mine_by_index(i) && OrderType() == type);
}

/******************************************************************************
   Возвращает признак новой свечи [в заданном таймфрейме]
******************************************************************************/
bool new_bar(datetime &last, int tf = 0 /* '0' - текущий ТФ */)
{
   datetime current = iTime(Symbol(), tf, 0);
   bool result = (last != current);
   last = current;
   return (result);
}

/******************************************************************************
   Возвращает суммарный объем в лотах открытых позиций указанного типа.
******************************************************************************/
double get_volume(int type, bool all = true /* false = только прибыльных*/)
{
   double vol = 0;

   for (int i = OrdersTotal() - 1; i >= 0; i--)
      if (is_mine_by_index(i) && OrderType() == type && (all || OrderProfit() > 0))
         vol += OrderLots();

   return (vol);
}

/******************************************************************************
   Возвращает количество открытых позиций заданного типа (-1 == все типы)
******************************************************************************/
int order_count(int type)
{
   int result = 0;

   for (int i = OrdersTotal() - 1; i >= 0; i--)
      if (is_mine_by_index(i) && (type == -1 || OrderType() == type))
         result++;

   return (result);
}

/******************************************************************************
   Возвращает усреднение открытых ордеров по заданному типу
******************************************************************************/
double price_median(int type)
{
   double vol = 0, lot = 0;

   for (int i = OrdersTotal() - 1; i >= 0; i--)
      if (is_mine_by_index(i) && OrderType() == type)
      {
         lot += OrderLots();
         vol += OrderOpenPrice() * OrderLots();
      }

   return ( (lot == 0) ? 0 : NormalizeDouble(vol / lot, Digits) );
}

/******************************************************************************
   Возвращает пограничную цену открытого ордера по заданному типу
   для OP_SELL: верхний ордер
   для  OP_BUY: нижний ордер
******************************************************************************/
double price_edge(int type, bool inner = true)
{
   int ticket = order_edge(type, inner, false);

   if (ticket >= 0 && OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
      return (OrderOpenPrice());

   return (0);
}

/******************************************************************************
   Возвращает номер тикета нижнего/верхнего пограничного ордера
-------------------------------------------------------------------------------
     type - тип ордеров (buy/sell)
    inner - внутренний/внешний ордер в позиции "замка":
            MIN, sell_2, sell_1, Bid, Ask, buy_1, buy_2, MAX
            * для SELL внутренний - с наибольшей ценой - "sell_1"
            * для  BUY внутренний - с наименьшей ценой - "buy_1"
   maxvol - наибольший/наименьший объем при одинаковой цене
******************************************************************************/
int order_edge(int type, bool inner = false, bool maxvol = false)
{
   int    ticket = -1;
   double price = 0, vol;

   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (is_mine_by_index(i) && OrderType() == type)
      {
         int    ot = OrderTicket();
         double ov = OrderLots();
         double op = OrderOpenPrice();

         if (price == 0) { ticket = ot; vol = ov; price = op; continue; }  // первый в цикле

         if (price == op)
         {
            if (ov > vol && maxvol == true)  { ticket = ot; vol = ov; /* continue; */}
            if (ov < vol && maxvol == false) { ticket = ot; vol = ov; /* continue; */}
            continue;
         }

         switch (type)
         {
            case OP_BUY:
               if (op < price && inner == true)  { ticket = ot; vol = ov; price = op; /* break; */}
               if (op > price && inner == false) { ticket = ot; vol = ov; price = op; /* break; */}
               break;
            case OP_SELL:
               if (op > price && inner == true)  { ticket = ot; vol = ov; price = op; /* break; */}
               if (op < price && inner == false) { ticket = ot; vol = ov; price = op; /* break; */}
               break;
         }
      }
   }

   return (ticket);
}

/******************************************************************************
   Изменение SL/TP/цены ордера.
   Значение тейка или стопа означает:
      отрицательное  - сброс;
      нулевое        - оставить без изменений;
   NB: должен быть предварительно выбран через 'OrderSelect'
******************************************************************************/
int order_mod(double pr, double sl = 0, double tp = 0, bool arrow = false)
{
   static color clr[] = { clrLightSkyBlue, clrLightPink };

   int    ort = OrderType();
   double osl = NormalizeDouble(OrderStopLoss(),   Digits);
   double otp = NormalizeDouble(OrderTakeProfit(), Digits);
   double opr = NormalizeDouble(OrderOpenPrice(),  Digits);

   sl = NormalizeDouble(sl, Digits);
   tp = NormalizeDouble(tp, Digits);
   pr = NormalizeDouble(pr, Digits);

   if (ort == OP_BUY || ort == OP_SELL || pr == 0) pr = opr;

   if (sl == 0) sl = osl;  // оставляем без изменений
   if (tp == 0) tp = otp;  //
   if (sl <  0) sl = 0;    // сбрасываем в "0"
   if (tp <  0) tp = 0;    //

   if (opr == pr && osl == sl && otp == tp) return (0); /* no op */

   double level   = MarketInfo(Symbol(), MODE_STOPLEVEL);
   double lo_mark = Ask + level * Point;  // граница сверху (нижняя)
   double hi_mark = Bid - level * Point;  // граница снизу (верхняя)

   // переделано из 'case(op) {...}' - так более кратко
   if (  (ort == OP_BUY  && (sl > hi_mark || (tp > 0 && tp < lo_mark))) ||
         (ort == OP_SELL && (tp > hi_mark || (sl > 0 && sl < lo_mark))) ||
         (ort == OP_BUYLIMIT  && pr > hi_mark)                          ||
         (ort == OP_SELLLIMIT && pr < lo_mark)                          ||
         (ort == OP_BUYSTOP   && pr < lo_mark)                          ||
         (ort == OP_SELLSTOP  && pr > hi_mark)  )
      return (-1);

   int ot = OrderTicket();

   if(OrderModify(ot, pr, sl, tp, /* уже нормализованы */
      OrderExpiration(), arrow ? clr[ort % 2] : CLR_NONE)) return (0);

   Print("Order #", ot, " price: ", DTS(opr), " -> ", DTS(pr),
         " sl: ", DTS(osl), " -> ", DTS(sl), " tp: ", DTS(otp), " -> ", DTS(tp),
         " modify error: \'", GetLastError(), "\'");
   return (-1);
}

/******************************************************************************
   Открытие ордера
   использует глобальную переменную Slippage
   Возвращает глобальный номер ордера или (-1) в случае ошибки.
******************************************************************************/
int order_open(int op, double lot, double price, double sl = 0, double tp = 0, bool arrow = false)
{
   int ticket;
   static color clr[] = { clrBlue, clrRed };
   static string sop[] = { "BUY", "SELL", "BUYLIMIT", "SELLIMIT", "BUYSTOP", "SELLSTOP" };

   ticket = OrderSend(Symbol(), op,
      NormalizeDouble(lot, Digits),
      NormalizeDouble(price, Digits),
      Slippage,
      NormalizeDouble(sl, Digits),
      NormalizeDouble(tp, Digits),
      "", Magic, 0, bif(arrow, clr[op % 2], CLR_NONE));

   if(ticket > 0 && OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        Print("new order placed : (", sop[op], ") by ", OrderOpenPrice());
   else Print(sop[op], " error : ", GetLastError());

   return ticket;
}

//---------------------------------------------------------------------------//
string DTS(double n, int d = -1)
{
   if (d < 0) d = Digits;
   return (DoubleToStr(n, d));
}

//---------------------------------------------------------------------------//
double bif(bool condition, double value_if_true, double value_if_false)
{
   if (condition) return (value_if_true);
   /* else */
   return (value_if_false);
}

//+------------------------------------------------------------------+

bool draw_level(string name, int style, color col, double price, string tooltip = "\n")
{
   bool result = true;
   long chart_id = ObjectFind(name);

   if (price == 0 && chart_id >= 0) // если price = 0, удалить
      return (ObjectDelete(name));

   if (chart_id < 0) // если не существует, создать
      result = (ObjectCreate(name, OBJ_HLINE, 0, 0, price) && (chart_id = ObjectFind(name)) >= 0);

   if (chart_id >= 0) // задать положение и tooltip (также и статические параметры, бо глюк в мт4)
      result &= ( ObjectSet(name, OBJPROP_STYLE, style) &&
                  ObjectSet(name, OBJPROP_COLOR, col) &&
                  ObjectSet(name, OBJPROP_PRICE1, price) &&
                  ObjectSetString(chart_id, name, OBJPROP_TOOLTIP, tooltip)
                );

   return (result);
}

//+------------------------------------------------------------------+

bool draw_median(double buy, double buy_vol, double sell, double sell_vol, int profit = 0)
{
   static string    MPB = "median buy";
   static string    MPS = "median sell";
   static string   MPBP = "median buy profit";
   static string   MPSP = "median sell profit";

   bool result = true;

   if (buy > 0)
   {
      result &= draw_level(MPB, STYLE_DOT, cMPB, buy, "volume: " + DTS(buy_vol, LotDec));
      if (profit > 0)
         result &= draw_level(MPBP, STYLE_DASHDOTDOT, cMPB, buy + profit * Point, "profit: " + DTS(buy_vol * profit * MathPow(10, Digits) * Point, LotDec));
   }
   else result &= (draw_level(MPB, 0, 0, 0) && draw_level(MPBP, 0, 0, 0));

   if (sell > 0)
   {
      result &= draw_level(MPS, STYLE_DOT, cMPS, sell, "volume: " + DTS(sell_vol, LotDec));
      if (profit > 0)
         result &= draw_level(MPSP, STYLE_DASHDOTDOT, cMPS, sell - profit * Point, "profit: " + DTS(sell_vol * profit * MathPow(10, Digits) * Point, LotDec));
   }
   else result &= (draw_level(MPS, 0, 0, 0) && draw_level(MPSP, 0, 0, 0));

   return (result);
}

//---------------------------------------------------------------------------//
// закрываем перекрытые ордера
//---------------------------------------------------------------------------//
int close_overlapped(int minpips)
{
   while (IsStopped() == false)
   {
      int tib = order_edge(OP_BUY,  ClOverInner, false);
      int tis = order_edge(OP_SELL, ClOverInner, false);

      // берём пару самых дальних перекрёстных ордеров
      if ( tib < 0 || tis < 0) break;

      if (OrderSelect(tib, SELECT_BY_TICKET, MODE_TRADES) == false) break;
      double tib_price = OrderOpenPrice();
      double tib_lots  = OrderLots();

      if (OrderSelect(tis, SELECT_BY_TICKET, MODE_TRADES) == false) break;
      double tis_price = OrderOpenPrice();
      double tis_lots  = OrderLots();

      // вычисляем прибыль перекрытия в пунктах
      int delta_pips = (tis_price - tib_price) / Point;

      // если прибыль меньше заданной, прекращаем работу
      if (delta_pips < minpips) break;

      // закрываем больший ордер меньшим или равным
      if (tib_lots > tis_lots) {
         Print("close(B) #", tib, "(", DTS(tib_price), ") by #", tis, "(", DTS(tis_price), ")");
         if (OrderCloseBy(tib, tis, cMPB) == false) break;
         }
      else {
         Print("close(S) #", tis, "(", DTS(tis_price), ") by #", tib, "(", DTS(tib_price), ")");
         if (OrderCloseBy(tis, tib, cMPS) == false) break;
         }
   }

   return (0);
}

/* End of file */
  • +4
  • Просмотров: 3189
  • 7 апреля 2015, 12:05
  • guest111
Понравилcя материал? Не забудьте поставить плюс и поделиться в социальной сети!

  Предыдущая запись в моем блоге
Факир был трезв, но бобик сдох
03 июля 2014

Брокер для ваших роботов, 15 лет на рынке

Комментарии (4)

комментарий был удален 2015-04-07 14:38:16 guest111

комментарий был удален 2015-04-07 14:38:10 guest111

+
0
Приветствую *hi*  А можно кратенько принцип торговли? Как понял Мартин с Пирамидой? Евро Доллар не подходит для такого сова.
avatar

  13  kipjatok001 Сообщений: 431 - Kipjatok001 Best Trader

  • 7 апреля 2015, 21:27
+
0
Можно и не мартин. А принцип я тут описывал еще много времени тому назад.
Читайте комментарии
avatar

  0  guest111 Автор Сообщений: 180

  • 8 апреля 2015, 06:00

Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий