Example #1
0
        /// <summary>
        /// планирование покупки или продажи.
        /// </summary>
        private int UpdateHigherTimeframesAndGetPlanDirection(CandleDataBidAsk quote, bool calcKijun)
        {
            var packers = new[] { dayCandlePacker, hourCandlePacker };

            bool[] higherThanKijuns = { false, false };

            for (var i = 0; i < subQueue.Length; i++)
            {
                var candle = packers[i].UpdateCandle(quote);
                if (candle != null)
                {
                    subQueue[i].Add(candle);
                }

                if (!calcKijun)
                {
                    continue;
                }
                var candles = candle != null
                                  ? subQueue[i].ToList()
                                  : subQueue[i].Union(new[] { packers[i].CurrentCandle }).ToList();

                var kijun = (candles.Min(c => c.low) + candles.Max(c => c.high)) / 2;
                higherThanKijuns[i] = quote.close > kijun;
            }

            if (!calcKijun || subQueue.Any(q => q.Length < q.MaxQueueLength))
            {
                return(0);
            }
            return(higherThanKijuns.Any(x => x != higherThanKijuns[0]) ? 0 : higherThanKijuns[0] ? 1 : -1);
        }
Example #2
0
        private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle)
        {
            // функция считает и округляет объем входа
            var volume = CalculateVolume(symbol, base.Leverage);

            if (volume == 0)
            {
                events.Add(string.Format("{0} {1} отменена - объем равен 0",
                                         dealSign > 0 ? "покупка" : "продажа", symbol));
                return;
            }

            var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close;
            var point      = pointCost[symbol];
            var stopLoss   = enterPrice - dealSign * (float)point * StopLossPoints;
            var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints;
            var order      = new MarketOrder
            {
                Symbol        = symbol,                     // Инструмент по которому совершается сделка
                Volume        = volume,                     // Объём средств, на который совершается сделка
                Side          = dealSign,                   // Устанавливаем тип сделки - покупка или продажа
                StopLoss      = stopLoss,                   // Устанавливаем величину Stop loss для открываемой сделки
                TakeProfit    = takeProfit,                 // Устанавливаем величину Take profit для открываемой сделки
                ExpertComment = "TornAssholeRobot"          // Комментарий по сделке, оставленный роботом
            };
            var status = NewOrder(order,
                                  OrderType.Market, // исполнение по рыночной цене - можно везде выбирать такой вариант
                                  0, 0);            // последние 2 параметра для OrderType.Market не имеют значения

            if (status != RequestStatus.OK)
            {
                events.Add(string.Format("Ошибка добавления ордера ({0}): {1}",
                                         order.ToStringShort(), status));
            }
        }
        private void MakeTrade(string name, CandleDataBidAsk quote)
        {
            var option = new Option
            {
                Symbol            = name,
                TimeEnter         = quote.timeClose,
                ExpirationMinutes = rand.Next(minStrikeMinutes, maxStrikeMinutes),
                OptionType        = rand.Next(100) < 50 ? OptionType.Call : OptionType.Put,
                Volume            = rand.Next(minVolume, maxVolume),
            };

            option.PriceEnter = (decimal)(option.OptionType == OptionType.Call
                ? quote.closeAsk
                : quote.close);
            var deltaStrikeAbs = DalSpot.Instance.GetAbsValue(name, (decimal)rand.Next(minPoints, maxPoints));
            var deltaSide      = option.OptionType == OptionType.Call ? 1 : -1;

            option.PriceStrike = option.PriceEnter + deltaSide * deltaStrikeAbs;
            CalculatePremium(option);
            if (option.Premium == 0)
            {
                return;
            }
            activeOptions.Add(option);
        }
 public void UpdateVolatility(CandleDataBidAsk candle)
 {
     deltas.Add(candle.close - candle.open);
     if (deltas.Count > maxSize)
     {
         deltas.RemoveAt(0);
     }
 }
Example #5
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            var events = new List <string>();

            if (string.IsNullOrEmpty(ticker))
            {
                return(events);
            }

            CandleDataBidAsk quote = null;

            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] != ticker)
                {
                    continue;
                }
                quote = quotes[i];
                break;
            }

            if (quote == null)
            {
                return(events);
            }

            // обновить свечку
            var candle = packer.UpdateCandle(quote);

            if (candle == null)
            {
                return(events);
            }

            // получить ордера
            List <MarketOrder> orders;

            GetMarketOrders(out orders, false);
            orders = orders.Where(o => o.Symbol == ticker).ToList();
            if (orders.Count == 0 || isHistoryStartOff)
            {
                return(events);
            }

            // проверить стоп по уровням и по индивидуальным настрофкам сделок
            if (checkIndividualStop)
            {
                DoCheckIndividualStop(candle, orders, events);
            }

            // проверить стоп по заданному уровню
            if (StopLevel != 0)
            {
                DoCheckCommonStop(candle, orders, events);
            }

            return(events);
        }
Example #6
0
        private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle, MovArgRobotTag orderTag)
        {
            var volumeMultiplier = (100 + (MartingalePercent * (orderTag.MartinChainNum - 1))) / 100M;
            var volume           = CalculateVolume(symbol,
                                                   base.Leverage == null ? null : base.Leverage * volumeMultiplier,
                                                   FixedVolume == null ? null : (int?)(FixedVolume.Value * volumeMultiplier));

            if (volume == 0)
            {
                events.Add(string.Format("{0} {1} отменена - объем равен 0", dealSign > 0 ? "покупка" : "продажа", symbol));
                return;
            }

            var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close;
            var point      = pointCost[symbol];
            var stopLoss   = enterPrice - dealSign * (float)point * StopLossPoints;
            var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints;

            var order = new MarketOrder
            {
                AccountID     = robotContext.AccountInfo.ID,
                Magic         = Magic,
                Symbol        = symbol,
                Volume        = volume,
                Side          = dealSign,
                StopLoss      = stopLoss,
                TakeProfit    = takeProfit,
                ExpertComment = ExpertComment,
                Comment       = orderTag.MakeComment()
            };
            var status = NewOrder(order,
                                  OrderType.Market,
                                  0, 0);

            if (status != RequestStatus.OK)
            {
                events.Add(string.Format("Ошибка добавления ордера {0} {1}: {2}",
                                         dealSign > 0 ? "BUY" : "SELL", symbol, status));
            }
        }
        public void UpdateVolatility(CandleDataBidAsk candle)
        {
            var x = candle.close;

            if (prevValue == null)
            {
                prevValue = x;
                return;
            }
            var delta  = x - prevValue.Value;
            var delta2 = delta * delta;

            prevValue = x;
            sum      += delta2;

            items.Add(delta2);
            if (items.Count > maxLength)
            {
                sum -= items[0];
                items.RemoveAt(0);
                volatility = Math.Sqrt(sum / maxLength);
            }
        }
Example #8
0
        private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle)
        {
            var volume = CalculateVolume(symbol, base.Leverage);

            if (volume == 0)
            {
                events.Add(string.Format("{0} {1} отменена - объем равен 0", dealSign > 0 ? "покупка" : "продажа", symbol));
                return;
            }

            var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close;
            var point      = pointCost[symbol];
            var stopLoss   = enterPrice - dealSign * (float)point * StopLossPoints;
            var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints;
            var order      = new MarketOrder
            {
                AccountID  = robotContext.AccountInfo.ID,
                Magic      = Magic,
                Symbol     = symbol,
                Volume     = volume,
                Side       = dealSign,
                StopLoss   = stopLoss,
                TakeProfit = takeProfit,
                // [A] не забывай уникальный комент
                ExpertComment = "Bollinger"
            };
            var status = NewOrder(order,
                                  OrderType.Market,
                                  0, 0);

            if (status != RequestStatus.OK)
            {
                events.Add(string.Format("Ошибка добавления ордера {0} {1}: {2}",
                                         dealSign > 0 ? "BUY" : "SELL", symbol, status));
            }
        }
Example #9
0
        private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle)
        {
            var volume = CalculateVolume(symbol, base.Leverage);

            if (volume == 0)
            {
                events.Add(string.Format("{0} {1} отменена - объем равен 0 (L:{2:f3}, #{3})",
                                         dealSign > 0 ? "покупка" : "продажа", symbol, base.Leverage, robotContext.AccountInfo.ID));
                return;
            }

            var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close;
            var stopLoss   = enterPrice - dealSign * DalSpot.Instance.GetAbsValue(symbol, (float)StopLossPoints);
            var takeProfit = enterPrice + dealSign * DalSpot.Instance.GetAbsValue(symbol, (float)TakeProfitPoints);

            var order = new MarketOrder
            {
                Symbol        = symbol,                     // Инструмент по которому совершается сделка
                Volume        = volume,                     // Объём средств, на который совершается сделка
                Side          = dealSign,                   // Устанавливаем тип сделки - покупка или продажа
                StopLoss      = stopLoss,                   // Устанавливаем величину Stop loss для открываемой сделки
                TakeProfit    = takeProfit,                 // Устанавливаем величину Take profit для открываемой сделки
                ExpertComment = "RsiDiverRobot"             // Комментарий по сделке, оставленный роботом
            };
            var status = NewOrder(order,
                                  OrderType.Market, // исполнение по рыночной цене - можно везде выбирать такой вариант
                                  0, 0);            // последние 2 параметра для OrderType.Market не имеют значения

            if (status != RequestStatus.OK)
            {
                events.Add(string.Format("Ошибка добавления ордера ({0}): {1} (#{2} bal: {3})",
                                         order, status,
                                         robotContext.AccountInfo.ID,
                                         robotContext.AccountInfo.Balance.ToStringUniformMoneyFormat(true)));
            }
        }
Example #10
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            if (/*formulaResolver == null || */ packer == null)
            {
                return(null);
            }
            curTime = quotes[0].timeClose;

            // обновить табличку цен
            for (var i = 0; i < names.Length; i++)
            {
                if (lastBids.ContainsKey(names[i]))
                {
                    lastBids[names[i]] = quotes[i].close;
                }
                else
                {
                    lastBids.Add(names[i], quotes[i].close);
                }
            }

            CandleDataBidAsk curQuote = null;

            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    curQuote = quotes[i];
                    break;
                }
            }

            // нет торгуемой котировки?
            if (curQuote == null)
            {
                return(null);
            }

            // обновить свечки
            var candle = packer.UpdateCandle(curQuote);

            if (candle == null)
            {
                return(null);
            }

            // закрылась полная свеча, проводим вычисления
            candles.Add(candle);

            // обновить очереди (для индекса, переменные вида usdjpy#15)
            if (lastBidLists.Count > 0)
            {
                foreach (var listTicker in lastBidLists)
                {
                    double price;
                    if (!lastBids.TryGetValue(listTicker.Key, out price))
                    {
                        price = 0;
                    }
                    listTicker.Value.Add(price);
                }
            }

            // посчитать индексы
            foreach (var ind in IndexList)
            {
                ind.CalculateValue(tickerNames, candles, lastBidLists, /*curTime*/ candle.timeOpen, randomGener);
            }

            // если это период "разгона" конвейера
            if (isHistoryStartOff)
            {
                return(null);
            }

            // если "наращиваем" вход - ищем последнюю сделку и входим в ее направлении,
            // если закрытие "лучше"
            List <MarketOrder> orders;

            GetMarketOrders(out orders, true);
            var hints = new List <string>();
            // следует "нарастить" объем
            var shouldEnterByChain = false;
            var lastOrderSide      = 0;

            if (EnterChain == EnterChainCondition.НаЗакрытииЛучше &&
                orders.Count > 0 && orders.Count < CountTrades)
            {
                var lastOrder = orders[orders.IndexOfMin(o => - o.TimeEnter.Ticks)];
                lastOrderSide      = lastOrder.Side;
                shouldEnterByChain = lastOrderSide > 0
                                      ? (candle.close < lastOrder.PriceEnter)
                                      : (candle.close > lastOrder.PriceEnter);
            }

            // получить торговый сигнал
            string comment, expertComment;
            var    dealSign = GetSignalSide(hints, curQuote.GetCloseQuote(), out comment, out expertComment);

            // сигнала нет
            if (dealSign == 0)
            {
                // ... но есть условие - "нарастить объем"
                if (shouldEnterByChain)
                {
                    MakeOrder("", "повторный вход", lastOrderSide, curQuote.GetCloseQuote(), hints);
                }
                return(hints);
            }

            // от одной проекции не может быть открыто более 1 ордера
            // описание проекции сохраняем в спец. коменте
            // закрыть противонаправленные сделки
            var hasSameOrder    = false;
            var hasSameDealType = false;

            foreach (var oldOrder in orders)
            {
                if (oldOrder.Side == dealSign)
                {
                    hasSameDealType = true;
                }
                if (oldOrder.Side == dealSign &&
                    oldOrder.ExpertComment == expertComment)
                {
                    hasSameOrder = true;
                    continue;
                }

                // закрыть ордер другого знака
                if (oldOrder.Side == dealSign)
                {
                    continue;
                }
                var rst = CloseMarketOrder(oldOrder.ID);
                if (rst != RequestStatus.OK)
                {
                    hints.Add("Невозможно закрыть противоположный ордер " + oldOrder.ID);
                }
            }

            if (EnterChain == EnterChainCondition.НаНовойПроекции)
            {
                if (hasSameOrder)
                {
                    return(hints);
                }
                MakeOrder(expertComment, comment, dealSign, curQuote.GetCloseQuote(), hints);
                return(hints);
            }

            if (EnterChain == EnterChainCondition.НаЗакрытииЛучше)
            {
                if (shouldEnterByChain || !hasSameDealType)
                {
                    MakeOrder(expertComment, comment, dealSign, curQuote.GetCloseQuote(), hints);
                }
                return(hints);
            }

            return(hints);
        }
Example #11
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            CandleDataBidAsk quote = null;

            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    quote = quotes[i];
                    break;
                }
            }
            var events = new List <string>();

            if (quote == null)
            {
                return(events);
            }
            // сопроводить сделки, коли треба...

            var candle = packer.UpdateCandle(quote);

            if (candle == null)
            {
                return(events);
            }
            candles.Add(candle);

            // получить уровни ЗигЗага
            var pivots = ZigZag.GetPivots(candles, ZigZagPeriodPercent, ZigZagSourceType);

            if (pivots.Count < 3)
            {
                return(events);
            }
            // проверить последнюю вершину ЗЗ - отстоит ли она от предпоследней на ZigZagPeriodPercent
            //var lastValid = Math.Abs(100*(pivots[pivots.Count - 1].b - pivots[pivots.Count - 2].b)/
            //                         pivots[pivots.Count - 2].b)
            //                >= ZigZagPeriodPercent;
            //if (!lastValid && pivots.Count == 3) return events;
            //var screenPointB = lastValid ? pivots[pivots.Count - 1] : pivots[pivots.Count - 2];
            //var screenPointA = lastValid ? pivots[pivots.Count - 2] : pivots[pivots.Count - 3];

            var ptB = pivots[pivots.Count - 2];
            var ptA = pivots[pivots.Count - 3];


            // отметить вершину ЗЗ
            if (ShowFiboTurnBars && (markedZigZagPivots.Count == 0 ||
                                     markedZigZagPivots[markedZigZagPivots.Count - 1] < ptA.a))
            {
                markedZigZagPivots.Add(ptA.a);
                events.Add(new RobotHint(ticker, Graphics[0].b.ToString(), "З.З", "З.З", "z", ptA.b)
                {
                    ColorFill     = Color.Olive,
                    Time          = candles[ptA.a].timeOpen,
                    RobotHintType = RobotHint.HintType.Коментарий
                }.ToString());
            }

            // соблюдаются ли условия входа в рынок?
            // - уровень Фибо пройден N-м баром Фибо
            // - с клоза того бара рынок вырос (для продаж)
            var fiboLevel = ptA.b + (ptA.b - ptB.b) * fiboLevels[0];
            //var potentialDealSide = screenPointA.b > screenPointB.b ? -1 : 1;
            var   fiboBreachIndex = -1;
            float fiboBreachPrice = 0;

            foreach (var fiboMember in fiboBars)
            {
                var index = fiboMember + ptB.a - 1;
                if (index >= candles.Count)
                {
                    break;
                }
                // свеча закрылась дальше расширения Фибо?
                var close       = candles[index].close;
                var fiboReached = ptA.b > ptB.b ? close > fiboLevel : close < fiboLevel;
                if (!fiboReached)
                {
                    continue;
                }
                fiboBreachIndex = index;
                fiboBreachPrice = close;
                break;
            }

            // считаем, сколько потенциально могло быть совершено входов
            // с момента пробития Фибо
            if (fiboBreachIndex > 0)
            {
                var countDeals = 1;
                // потенциальные сделки
                for (var i = fiboBreachIndex + 1; i < candles.Count - 1; i++)
                {
                    if ((candles[i].close > fiboBreachPrice && ptA.b > ptB.b) ||
                        (candles[i].close < fiboBreachPrice && ptA.b < ptB.b))
                    {
                        fiboBreachPrice = candles[i].close;
                        countDeals++;
                    }
                }
                var isEnterBetter = (candle.close > fiboBreachPrice && ptA.b > ptB.b) ||
                                    (candle.close < fiboBreachPrice && ptA.b < ptB.b);

                if ((isEnterBetter || fiboBreachIndex == candles.Count - 1) &&
                    countDeals <= maxDealsInSeries)
                {// войти в рынок, закрыв противонаправленные сделки
                    var dealSide = ptA.b > ptB.b ? -1 : 1;

                    List <MarketOrder> orders;
                    robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders);
                    if (orders.Count > 0)
                    {
                        orders = orders.Where(o => o.Magic == Magic && o.Side != dealSide).ToList();
                    }
                    foreach (var order in orders)
                    {
                        robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(),
                                                      robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot);
                    }

                    // открыть сделку
                    OpenDeal(quote.GetCloseQuote(), dealSide);
                    events.Add(new RobotHint(ticker, Graphics[0].b.ToString(),
                                             "Вход", "Вход по З.З", "e", dealSide < 0 ? quote.close : quote.closeAsk)
                    {
                        ColorFill     = dealSide > 0 ? Color.Green : Color.Red,
                        Time          = quote.timeClose,
                        RobotHintType = dealSide > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа
                    }.ToString());
                }
            }

            return(events);
        }
Example #12
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            if (/*formulaResolver == null || */ packer == null)
            {
                return(null);
            }
            curTime = quotes[0].timeClose;

            // обновить табличку цен
            for (var i = 0; i < names.Length; i++)
            {
                if (lastBids.ContainsKey(names[i]))
                {
                    lastBids[names[i]] = (double)quotes[i].close;
                }
                else
                {
                    lastBids.Add(names[i], (double)quotes[i].close);
                }
            }

            CandleDataBidAsk curQuote = null;

            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    curQuote = quotes[i];
                    break;
                }
            }

            if (curQuote == null)
            {
                return(null);                  // нет торгуемой котировки
            }
            // обновить свечки
            var candle = packer.UpdateCandle(curQuote);

            var hints = new List <RobotHint>();

            if (candle != null)
            {
                // закрылась полная свеча, проводим вычисления
                candles.Add(candle);


                countCandles++;
                // обновить очереди (для индекса, переменные вида usdjpy#15)
                if (lastBidLists.Count > 0)
                {
                    foreach (var listTicker in lastBidLists)
                    {
                        double price;
                        if (!lastBids.TryGetValue(listTicker.Key, out price))
                        {
                            price = 0;
                        }
                        listTicker.Value.Add(price);
                    }
                }

                // посчитать индексы
                foreach (var ind in IndexList)
                {
                    ind.CalculateValue(tickerNames, candles, lastBidLists, curTime, randomGener);
                }

                // если это период "разгона" конвейера
                if (isHistoryStartOff)
                {
                    return(null);
                }

                var hintText = new StringBuilder();
                List <MarketOrder> orders;

                #region ТОРГОВЫЙ МОДУЛЬ

                #region проверяем необходимость добавок к открытым позициям

                // проверяем состояние робота, если у нас нет позиций и робот торгует, возвращаем в исходное состояние
                GetMarketOrders(out orders);
                if (orders.Count == 0 && stopsOnPositions == StopPositionsState.ЗащитаУстановлена)
                {
                    RobotTradeState = TradeState.ПоискТочекВхода;
                    TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции закрылись");
                    TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState);
                    stopsOnPositions = StopPositionsState.Незащищены;
                }
                var addPosFlag = 0;
                if (RobotTradeState == TradeState.НаращиваниеПокупок || RobotTradeState == TradeState.НаращиваниеПродаж)
                {
                    var side = RobotTradeState == TradeState.НаращиваниеПокупок ? 1 :
                               RobotTradeState == TradeState.НаращиваниеПродаж ? -1 : 0;
                    if (AddPositionRules == AddPositionRule.НаБареЛучшейЦены)
                    {
                        //GetMarketOrders(out orders);
                        if (orders.Count == 0)
                        {
                            addPosFlag = RobotTradeState == TradeState.НаращиваниеПокупок ? 1 : -1;
                        }
                        else
                        {
                            var averagePrice = GetAveragePrice(orders, side, curQuote.close, ProtectType.ПоЛучшейПозиции);
                            if (side == 1 && curQuote.close < averagePrice)
                            {
                                addPosFlag = 1;
                            }
                            if (side == -1 && curQuote.close > averagePrice)
                            {
                                addPosFlag = -1;
                            }

                            // проверяю достижение актуального фибоуровня
                            if (ActualFiboLevel != null)
                            {
                                // если условие выполнилось, то мы не достигли уровня для открытия позиций
                                if ((addPosFlag == 1 && ActualFiboLevel < curQuote.close) ||
                                    (addPosFlag == -1 && ActualFiboLevel > curQuote.close))
                                {
                                    addPosFlag = 0;
                                }
                            }
                        }
                    }
                }

                if (addPosFlag != 0)
                {
                    GetMarketOrders(out orders);
                    var ordersCount = orders.Count;
                    // проверяем можно ли еще открыть позиции
                    if (ordersCount < CountTrades)
                    {
                        // открыть позу в направлении знака дивера
                        robotContext.SendNewOrderRequest(
                            protectedContext.MakeProtectedContext(),
                            RequestUniqueId.Next(),
                            new MarketOrder
                        {
                            AccountID     = robotContext.AccountInfo.ID,
                            Magic         = Magic,
                            Symbol        = ticker,
                            Volume        = GetTradeLot(),
                            Side          = addPosFlag,
                            ExpertComment = "Atracotes MTS"
                        },
                            OrderType.Market, 0, 0);

                        if (ordersCount > 0)
                        {
                            hintText.AppendLine(string.Format("Добавка к {0}, текущая цена {1}",
                                                              addPosFlag == 1 ? "покупкам" : "продажам", curQuote.close));
                        }
                        else
                        {
                            hintText.AppendLine(string.Format("{0}, текущая цена {1}", addPosFlag == 1 ? "покупка" : "продажа",
                                                              curQuote.close));
                        }
                        TerminalLog.Instance.SaveRobotLog("Atracotes MTS: " + hintText);
                        hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), hintText.ToString(),
                                                addPosFlag > 0 ? "BUY" : "SELL", "e", curQuote.close)
                        {
                            Time          = curQuote.timeClose,
                            ColorFill     = addPosFlag > 0 ? Color.Green : Color.Red,
                            ColorLine     = Color.Black,
                            RobotHintType = addPosFlag > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа
                        });
                        stopsOnPositions = StopPositionsState.Незащищены;
                        if (ordersCount + 1 == CountTrades)
                        {
                            RobotTradeState = TradeState.НабранПолныйОбъем;
                            TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState);
                        }
                    }
                }
                #endregion

                #region считаем зигзагу и уровни расширений

                var quotesList = candles.ToList();
                var pivots     = ZigZag.GetPivots(quotesList, ThresholdPercent, ZigZagSourceType);
                if (pivots.Count > 1)
                {
                    // появились точки, рассчитываем уровни
                    // проверяем процентный порог перешагнули или нет

                    for (var i = pivots.Count; i > 1; i--)
                    {
                        var index0  = i - 1;
                        var index1  = i - 2;
                        var percent = Math.Abs(pivots[index0].b - pivots[index1].b) / pivots[index1].b * 100;
                        if (percent > ThresholdPercent)
                        {
                            // процентный порог пройден, вычисляем уровни
                            // теперь вычисляем уровни расширений
                            var sign  = pivots[index0].b > pivots[index1].b ? -1 : 1;
                            var delta = Math.Abs(pivots[index0].b - pivots[index1].b);

                            // очищаем все предыдущие уровни расширений как устаревшие
                            // extLevels.Clear();

                            foreach (var level in fiboLevels)
                            {
                                var lev = new ExtensionsLevel
                                {
                                    startIndex = countCandles > CandlesInIndexHistory ? countCandles - CandlesInIndexHistory + pivots[index0].a : pivots[index0].a,
                                    length     = BarsCount,
                                    price      = pivots[index0].b + delta * sign * (1 + level),
                                    delta      = DalSpot.Instance.GetAbsValue(ticker, DeltaLevel),
                                    goalFrom   = -sign
                                };
                                extLevels.Add(lev);
                            }
                            break;
                        }
                    }
                }
                #endregion

                #region ищем дивергенции на индексах и курсе валютной пары
                var divergenceSign = 0;

                foreach (var ind in IndexList)
                {
                    var commentOnDivergence = string.Empty;

                    var indiDiverSign = ind.GetDivergenceSign(candles, out commentOnDivergence);
                    if (indiDiverSign != 0)
                    {
                        if (hintText.Length != 0)
                        {
                            hintText.AppendLine();
                        }
                        hintText.AppendLine("Дивергенция на индексе №" + indexList.IndexOf(ind));
                        hintText.AppendLine(commentOnDivergence);
                        hintText.AppendLine("Переменные:");
                        // ReSharper disable PossibleNullReferenceException)
                        foreach (var pair in ind.indexCalculator.varValues)
                        // ReSharper restore PossibleNullReferenceException
                        {
                            hintText.AppendLine(string.Format("{1}{0}{2:f4}", (char)9, pair.Key, pair.Value));
                        }

                        //hints.Add(new RobotHint(hintText.ToString(),
                        //indiDiverSign > 0 ? "BUY" : "SELL", "e", curQuote.Bid)
                        //{
                        //    Time = candle.timeOpen,
                        //    ColorFill = indiDiverSign > 0 ? Color.Green : Color.Red,
                        //    ColorLine = Color.Black
                        //});
                    }


                    divergenceSign += indiDiverSign;
                }
                #endregion


                // теперь получен список дивергенций и уровни расширения.

                #region удаляем старые уровни
                for (var i = 0; i < extLevels.Count; i++)
                {
                    // проверка актуальности уровня по свечам
                    if (countCandles - 1 <= extLevels[i].startIndex + extLevels[i].length)
                    {
                        continue;
                    }
                    // уровень устарел, прошли максимальную длину свечей
                    extLevels.RemoveAt(i);
                    i--;
                }
                #endregion

                // проверяем достижение уровней расширения текущей ценой и если есть - входим в рынок
                divergenceSign = Math.Sign(divergenceSign);



                if (stopsOnPositions == StopPositionsState.Незащищены && divergenceSign != 0)
                {
                    GetMarketOrders(out orders);
                    stopsOnPositions = ProtectPositions(orders, -divergenceSign, curQuote.close);
                    if (stopsOnPositions == StopPositionsState.ЗащитаУстановлена)
                    {
                        TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции защищены ны дивергенции");
                        hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(),
                                                "Защита позиций на дивергенции", "PROTECT", -divergenceSign > 0 ? "PB" : "PS", curQuote.close)
                        {
                            Time          = curQuote.timeClose,
                            ColorFill     = Color.Blue,
                            ColorLine     = Color.Black,
                            RobotHintType = RobotHint.HintType.Поджатие
                        });
                    }
                }

                if (true || RobotTradeState == TradeState.НетПозиций || RobotTradeState == TradeState.ПоискТочекВхода || RobotTradeState == TradeState.НабранПолныйОбъем)
                {
                    foreach (var level in extLevels)
                    {
                        // проверяем попадание цены на уровень
                        //var prevCandle = candles.GetItemByIndex(candles.Count() - 2, true);
                        if ((level.goalFrom == -1 && candles[candles.Count - 1].close >= (level.price - level.delta)) ||
                            (level.goalFrom == 1 && candles[candles.Count - 1].close <= (level.price + level.delta)))
                        {
                            GetMarketOrders(out orders);
                            if (stopsOnPositions == StopPositionsState.Незащищены && divergenceSign == 0)
                            {
                                // надо поджать позиции
                                stopsOnPositions = ProtectPositions(orders, -level.goalFrom, curQuote.close);
                                if (stopsOnPositions == StopPositionsState.ЗащитаУстановлена)
                                {
                                    TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции защищены по достижению уровня расширения");
                                    hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(),
                                                            "Защита позиций по достижению уровня расширения",
                                                            "PROTECT", -level.goalFrom > 0 ? "PB" : "PS", curQuote.close)
                                    {
                                        Time          = curQuote.timeClose,
                                        ColorFill     = Color.Blue,
                                        ColorLine     = Color.Black,
                                        RobotHintType = RobotHint.HintType.Поджатие
                                    });
                                }
                                break;
                            }

                            if (divergenceSign == 0)
                            {
                                continue;
                            }

                            var ordersCount = orders.Count;
                            // цена поднялась до целевого уровня
                            var level1        = level;
                            var ordersToClose = orders.FindAll(o => o.Side != divergenceSign);

                            foreach (var order in ordersToClose)
                            {
                                robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(),
                                                              robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot);
                                ordersCount--;
                            }
                            // закрыли ордера и теперь начинаем открывать позиции в обратную сторону

                            // проверяем можно ли еще открыть позиции
                            if (ordersCount >= CountTrades)
                            {
                                break;
                            }

                            // не добавляем позиции по новому диверу
                            if (RobotTradeState == TradeState.НаращиваниеПокупок && divergenceSign == 1 ||
                                RobotTradeState == TradeState.НаращиваниеПродаж && divergenceSign == -1)
                            {
                                break;
                            }

                            // открыть позу в направлении знака дивера
                            robotContext.SendNewOrderRequest(
                                protectedContext.MakeProtectedContext(),
                                RequestUniqueId.Next(),
                                new MarketOrder
                            {
                                AccountID     = robotContext.AccountInfo.ID,
                                Magic         = Magic,
                                Symbol        = ticker,
                                Volume        = GetTradeLot(),
                                Side          = divergenceSign,
                                ExpertComment = "Atracotes MTS"
                            },
                                OrderType.Market, 0, 0);

                            hintText.AppendLine(string.Format("Пересечение уровня {0} {1}, текущая цена {2}",
                                                              level1.price,
                                                              level1.goalFrom == -1 ? "снизу" : "сверху", curQuote.close));

                            TerminalLog.Instance.SaveRobotLog("Atracotes MTS: " + hintText + ", " + (divergenceSign > 0 ? "покупка" : "продажа"));
                            hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(),
                                                    hintText.ToString(), divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.close)
                            {
                                Time          = curQuote.timeClose,
                                ColorFill     = divergenceSign > 0 ? Color.Green : Color.Red,
                                ColorLine     = Color.Black,
                                RobotHintType = divergenceSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа
                            });

                            RobotTradeState = divergenceSign == 1
                                                  ? TradeState.НаращиваниеПокупок

                                                  : TradeState.НаращиваниеПродаж;
                            TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState);
                            stopsOnPositions = StopPositionsState.Незащищены;
                            break;
                        }
                    }
                }

                #endregion
            }

            var retHint = hints.Select(hint => hint.ToString()).ToList();
            return(retHint.Count > 0 ? retHint : null);
        }