示例#1
0
        private void OpenOrder(Cortege3 <string, int, DateTime> order)
        {
            var ticker = order.a;
            var side   = order.b;

            var dealVolumeDepo = CalculateVolume(ticker);

            if (dealVolumeDepo == 0)
            {
                return;
            }

            float?sl = null;

            if (CheckDice(probStopLoss))
            {
                var quote = QuoteStorage.Instance.ReceiveValue(ticker);
                if (quote != null)
                {
                    var points = minStopPoints;
                    if (CheckDice(propRandomStopStep))
                    {
                        points = points + rnd.Next(maxStopPoints - minStopPoints + 1);
                    }
                    else
                    {
                        points = points + rnd.Next((maxStopPoints - minStopPoints) / stepStopPoints + 1) * stepStopPoints;
                    }
                    sl  = side > 0 ? quote.ask : quote.bid;
                    sl -= side * DalSpot.Instance.GetAbsValue(ticker, (float)points);
                }
            }

            robotContext.SendNewOrderRequest(
                protectedContext.MakeProtectedContext(),
                RequestUniqueId.Next(),
                new MarketOrder
            {
                Symbol        = ticker,
                Side          = side,
                AccountID     = robotContext.AccountInfo.ID,
                Magic         = Magic,
                Volume        = dealVolumeDepo,
                ExpertComment = "RandomRobot",
                Comment       = "",
                StopLoss      = sl,
                TakeProfit    = null
            },
                OrderType.Market, 0, 0);
        }
示例#2
0
        private void WorkerWalletOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs ea)
        {
            ShowHideProgress(false);

            if (ea.Result == null)
            {
                return;
            }

            walletExplicitDetail = (WalletExplicitResponse)ea.Result;

            // байндинг
            walletCurrency = walletExplicitDetail.wallet.Currency;
            lblWallet.Text = walletExplicitDetail.wallet.Balance.ToStringUniformMoneyFormat() + " " + walletExplicitDetail.wallet.Currency;

            var summaryData = new List <Cortege3 <string, int, decimal> >();

            foreach (var transfersByType in walletExplicitDetail.transfersSummary.TransfersByType)
            {
                var row = new Cortege3 <string, int, decimal>
                {
                    a = EnumFriendlyName <TransfersByAccountSummary.AccountTransferType> .GetString(transfersByType.Key),
                    b = transfersByType.Value.a,
                    c = transfersByType.Value.b
                };
                summaryData.Add(row);
            }
            summaryTransfersFastGrid.DataBind(summaryData);

            gridSubscription.DataBind(walletExplicitDetail.subscriptions ?? new List <Contract.Entity.Subscription>());

            gridAccount.DataBind(walletExplicitDetail.realAccounts ?? new List <AccountShared>());

            if (!transfersWorker.IsBusy)
            {
                transfersWorker.RunWorkerAsync();
            }
        }
示例#3
0
        private void OpenOrder(Cortege3<string, int, DateTime> order)
        {
            var ticker = order.a;
            var side = order.b;

            var dealVolumeDepo = CalculateVolume(ticker);
            if (dealVolumeDepo == 0) return;

            float? sl = null;
            if (CheckDice(probStopLoss))
            {
                var quote = QuoteStorage.Instance.ReceiveValue(ticker);
                if (quote != null)
                {
                    var points = minStopPoints;
                    if (CheckDice(propRandomStopStep))
                        points = points + rnd.Next(maxStopPoints - minStopPoints + 1);
                    else
                        points = points + rnd.Next((maxStopPoints - minStopPoints)/stepStopPoints + 1)*stepStopPoints;
                    sl = side > 0 ? quote.ask : quote.bid;
                    sl -= side * DalSpot.Instance.GetAbsValue(ticker, (float)points);
                }
            }

            robotContext.SendNewOrderRequest(
                protectedContext.MakeProtectedContext(),
                RequestUniqueId.Next(),
                new MarketOrder
                    {
                        Symbol = ticker,
                        Side = side,
                        AccountID = robotContext.AccountInfo.ID,
                        Magic = Magic,
                        Volume = dealVolumeDepo,
                        ExpertComment = "RandomRobot",
                        Comment = "",
                        StopLoss = sl,
                        TakeProfit = null
                    },
                OrderType.Market, 0, 0);
        }
        private void BuildChannel(List <CandleData> candles, int from)
        {
            var channel = new Cortege3 <PointD, PointD, PointD> {
            };
            var state   = ChannelStateInfo.НетКанала;

            switch (ChannelState)
            {
            case ChannelStateInfo.НетКанала:
                // канала еще нет, ищем сначала по верхним точкам, если не находим, пробуем по нижним найти
                var channelhigh = GetHighLineChannel(candles, from);
                var channellow  = GetLowLineChannel(candles, from);
                if ((channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0)) &&
                    (channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                {
                    break;
                }

                if (channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0))
                {
                    state   = ChannelStateInfo.ПостроенПоМинимумам;
                    channel = channellow;
                    break;
                }
                if ((channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                {
                    state   = ChannelStateInfo.ПостроенПоМаксимумам;
                    channel = channelhigh;
                    break;
                }

                if (channelhigh.b.X > channellow.b.X || (channelhigh.b.X == channellow.b.X && channelhigh.a.X > channellow.a.X))
                {
                    state   = ChannelStateInfo.ПостроенПоМаксимумам;
                    channel = channelhigh;
                    break;
                }
                state   = ChannelStateInfo.ПостроенПоМинимумам;
                channel = channellow;
                break;

            case ChannelStateInfo.ПостроенПоМаксимумам:
                channel = GetLowLineChannel(candles, from);
                if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                {
                    return;
                }
                state = ChannelStateInfo.ПостроенПоМинимумам;
                break;

            case ChannelStateInfo.ПостроенПоМинимумам:
                channel = GetHighLineChannel(candles, from);
                if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                {
                    return;
                }
                state = ChannelStateInfo.ПостроенПоМаксимумам;
                break;
            }



            if (lastIndexB == 0 && lastIndexA == 0)
            {
                lastIndexA = channel.a.X;
                lastIndexB = channel.b.X;
            }

            if (lastIndexB == channel.b.X && lastIndexA < channel.a.X)
            {
                // найденный канал старше текущего, игнорируем
                return;
            }

            if (!ShowAllChannels && lastIndexB > channel.b.X)
            {
                // найденный канал уже старый, игнорируем его
                channel = currChannel;
            }
            var a = channel.a;
            var b = channel.b;
            var k = (b.Y - a.Y) / (b.X - a.X);

            // стираем старый канал
            if (!ShowAllChannels)
            {
                series.data.Clear();
            }

            // находим точку на текущей свече + 1, туда и продлим канал
            var bx = 0;

            if (series.data.Count == 0)
            {
                bx = candles.Count;
            }
            else
            {
                bx = (int)b.X + CountAfter + CountForward;
            }

            if (TradePoints)
            {
                // просто покажем точки входа и все
                // посчитаем точки входа если они есть
                for (var i = (int)b.X + CountAfter + 1; i < b.X + CountAfter + CountForward; i++)
                {
                    if (candles.Count <= i)
                    {
                        break;
                    }
                    var highY = b.Y + k * (i - b.X);
                    var lowY  = channel.c.Y + k * (i - channel.c.X);
                    if (highY <= candles[i].high && highY >= candles[i].low)
                    {
                        var detailed = string.Format("S {0}", highY);
                        var tip      = new AsteriskTooltip(detailed, detailed)
                        {
                            Price       = (float)highY,
                            CandleIndex = i,
                            DateStart   = candles[i].timeOpen,
                            Sign        = "e",
                            Shape       = AsteriskTooltip.ShapeType.СтрелкаВниз,
                            ColorFill   = Color.Pink,
                            ColorLine   = Color.Black,
                            ColorText   = Color.Black
                        };
                        commentSeries.data.Add(tip);
                        break;
                    }
                    if (lowY >= candles[i].low && lowY <= candles[i].high)
                    {
                        var detailed = string.Format("B {0}", lowY);
                        var tip      = new AsteriskTooltip(detailed, detailed)
                        {
                            Price       = (float)lowY,
                            CandleIndex = i,
                            DateStart   = candles[i].timeOpen,
                            Sign        = "e",
                            Shape       = AsteriskTooltip.ShapeType.СтрелкаВверх,
                            ColorFill   = Color.Green,
                            ColorLine   = Color.Black,
                            ColorText   = Color.Black
                        };
                        commentSeries.data.Add(tip);
                        break;
                    }
                }
            }
            else
            {
                var line = new TrendLine
                {
                    LineColor = state == ChannelStateInfo.ПостроенПоМаксимумам ? ClUpLine : ClDownLine,
                    LineStyle = TrendLine.TrendLineStyle.Отрезок
                };
                // линия по двум экстремумам
                line.linePoints.Add(new PointD(a.X - countBefore, b.Y + k * (a.X - countBefore - b.X)));
                line.linePoints.Add(new PointD(bx, b.Y + k * (bx - b.X)));
                series.data.Add(line);


                line = new TrendLine
                {
                    LineColor = state == ChannelStateInfo.ПостроенПоМаксимумам ? ClUpLine : ClDownLine,
                    LineStyle = TrendLine.TrendLineStyle.Отрезок
                };
                var c = channel.c;
                // линия по одному экстремуму
                line.linePoints.Add(new PointD(a.X - countBefore, c.Y + k * (a.X - countBefore - c.X)));
                line.linePoints.Add(new PointD(bx, c.Y + k * (bx - c.X)));
                series.data.Add(line);
            }
            ChannelState = state;
            currChannel  = channel;
            lastIndexA   = currChannel.a.X;
            lastIndexB   = currChannel.b.X;
        }
示例#5
0
        private void WorkerWalletOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs ea)
        {
            ShowHideProgress(false);

            if (ea.Result == null)
                return;

            walletExplicitDetail = (WalletExplicitResponse) ea.Result;

            // байндинг
            walletCurrency = walletExplicitDetail.wallet.Currency;
            lblWallet.Text = walletExplicitDetail.wallet.Balance.ToStringUniformMoneyFormat() + " " + walletExplicitDetail.wallet.Currency;

            var summaryData = new List<Cortege3<string, int, decimal>>();
            foreach (var transfersByType in walletExplicitDetail.transfersSummary.TransfersByType)
            {
                var row = new Cortege3<string, int, decimal>
                    {
                        a = EnumFriendlyName<TransfersByAccountSummary.AccountTransferType>.GetString(transfersByType.Key),
                        b = transfersByType.Value.a,
                        c = transfersByType.Value.b
                    };
                summaryData.Add(row);
            }
            summaryTransfersFastGrid.DataBind(summaryData);

            gridSubscription.DataBind(walletExplicitDetail.subscriptions ?? new List<Contract.Entity.Subscription>());

            gridAccount.DataBind(walletExplicitDetail.realAccounts ?? new List<AccountShared>());

            if (!transfersWorker.IsBusy)
                transfersWorker.RunWorkerAsync();
        }
        private void BuildChannel(List<CandleData> candles, int from)
        {
            var channel = new Cortege3<PointD, PointD, PointD> { };
            var state = ChannelStateInfo.НетКанала;
            switch (ChannelState)
            {
                case ChannelStateInfo.НетКанала:
                    // канала еще нет, ищем сначала по верхним точкам, если не находим, пробуем по нижним найти
                    var channelhigh = GetHighLineChannel(candles, from);
                    var channellow = GetLowLineChannel(candles, from);
                    if ((channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0))
                        && (channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                        break;

                    if (channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0))
                    {
                        state = ChannelStateInfo.ПостроенПоМинимумам;
                        channel = channellow;
                        break;
                    }
                    if ((channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                    {
                        state = ChannelStateInfo.ПостроенПоМаксимумам;
                        channel = channelhigh;
                        break;
                    }

                    if (channelhigh.b.X > channellow.b.X || (channelhigh.b.X == channellow.b.X && channelhigh.a.X > channellow.a.X))
                    {
                        state = ChannelStateInfo.ПостроенПоМаксимумам;
                        channel = channelhigh;
                        break;
                    }
                    state = ChannelStateInfo.ПостроенПоМинимумам;
                    channel = channellow;
                    break;

                case ChannelStateInfo.ПостроенПоМаксимумам:
                    channel = GetLowLineChannel(candles, from);
                    if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                        return;
                    state = ChannelStateInfo.ПостроенПоМинимумам;
                    break;
                case ChannelStateInfo.ПостроенПоМинимумам:
                    channel = GetHighLineChannel(candles, from);
                    if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                        return;
                    state = ChannelStateInfo.ПостроенПоМаксимумам;
                    break;
            }

            if (lastIndexB == 0 && lastIndexA == 0)
            {
                lastIndexA = channel.a.X;
                lastIndexB = channel.b.X;
            }

            if (lastIndexB == channel.b.X && lastIndexA < channel.a.X)
            {
                // найденный канал старше текущего, игнорируем
                return;
            }

            if (!ShowAllChannels && lastIndexB > channel.b.X)
            {
                // найденный канал уже старый, игнорируем его
                channel = currChannel;
            }
            var a = channel.a;
            var b = channel.b;
            var k = (b.Y - a.Y) / (b.X - a.X);
            // стираем старый канал
            if (!ShowAllChannels)
                series.data.Clear();

            // находим точку на текущей свече + 1, туда и продлим канал
            var bx = 0;
            if (series.data.Count == 0)
                bx = candles.Count;
            else
                bx = (int)b.X + CountAfter + CountForward;

            if (TradePoints)
            {
                // просто покажем точки входа и все
                // посчитаем точки входа если они есть
                for (var i = (int)b.X + CountAfter + 1; i < b.X + CountAfter + CountForward; i++)
                {
                    if (candles.Count <= i) break;
                    var highY = b.Y + k*(i - b.X);
                    var lowY = channel.c.Y + k*(i - channel.c.X);
                    if (highY <= candles[i].high && highY >= candles[i].low)
                    {
                        var detailed = string.Format("S {0}", highY);
                        var tip = new AsteriskTooltip(detailed, detailed)
                        {
                            Price = (float)highY,
                            CandleIndex = i,
                            DateStart = candles[i].timeOpen,
                            Sign = "e",
                            Shape = AsteriskTooltip.ShapeType.СтрелкаВниз,
                            ColorFill = Color.Pink,
                            ColorLine = Color.Black,
                            ColorText = Color.Black
                        };
                        commentSeries.data.Add(tip);
                        break;
                    }
                    if (lowY >= candles[i].low && lowY <= candles[i].high)
                    {
                        var detailed = string.Format("B {0}", lowY);
                        var tip = new AsteriskTooltip(detailed, detailed)
                        {
                            Price = (float)lowY,
                            CandleIndex = i,
                            DateStart = candles[i].timeOpen,
                            Sign = "e",
                            Shape = AsteriskTooltip.ShapeType.СтрелкаВверх,
                            ColorFill = Color.Green,
                            ColorLine = Color.Black,
                            ColorText = Color.Black
                        };
                        commentSeries.data.Add(tip);
                        break;
                    }
                }
            }
            else
            {
                var line = new TrendLine
                               {
                                   LineColor = state == ChannelStateInfo.ПостроенПоМаксимумам ? ClUpLine : ClDownLine,
                                   LineStyle = TrendLine.TrendLineStyle.Отрезок
                               };
                // линия по двум экстремумам
                line.linePoints.Add(new PointD(a.X - countBefore, b.Y + k*(a.X - countBefore - b.X)));
                line.linePoints.Add(new PointD(bx, b.Y + k*(bx - b.X)));
                series.data.Add(line);

                line = new TrendLine
                           {
                               LineColor = state == ChannelStateInfo.ПостроенПоМаксимумам ? ClUpLine : ClDownLine,
                               LineStyle = TrendLine.TrendLineStyle.Отрезок
                           };
                var c = channel.c;
                // линия по одному экстремуму
                line.linePoints.Add(new PointD(a.X - countBefore, c.Y + k*(a.X - countBefore - c.X)));
                line.linePoints.Add(new PointD(bx, c.Y + k*(bx - c.X)));
                series.data.Add(line);
            }
            ChannelState = state;
            currChannel = channel;
            lastIndexA = currChannel.a.X;
            lastIndexB = currChannel.b.X;
        }
        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) continue;
                quote = quotes[i];
                break;
            }
            if (quote == null) return null;
            var candle = packer.UpdateCandle(quote);

            //if (candles.Count == 0) return null;

            if (candle == null)
            {
                // тут надо производить текущие действия с открытыми позициям
                // сопроводить сделки, коли треба... еще как треба
            }
            else
            {
                candles.Add(candle);
                waitNextQuoteFlag = false;
            }

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

            if (candles.Count < CandlesInHistory)
                return null; // не достаточно накоплено свечек
            List<MarketOrder> positions;
            List<PendingOrder> pendingOrders;
            GetMarketOrders(out positions);
            GetPendingOrders(out pendingOrders);
            var events = new List<string>();

            if (positions.Count != 0)
            {
                //Logger.InfoFormat("OnQuotesReceived: сопровождаем позицию,  данные quote bid={0} ask={1} time={2}", quote.bid, quote.ask, quote.time);
                ManageOpenPositions(positions, pendingOrders, quote.GetCloseQuote(), ref events);
            }

            if (candle == null)
            {
                if (waitNextQuoteFlag)
                {
                    //Logger.InfoFormat("OnQuotesReceived: данные quote bid={0} ask={1} time={2}", quote.bid, quote.ask, quote.time);
                    //Logger.InfoFormat("OnQuotesReceived: ждем следующую свечу... ");
                    return events;
                    // цена за границей канала
                }

                if (currHighChannelPrice != 0 && currLowChannelPrice != 0 && (pendingOrders.Count != 0 || positions.Count != 0) )
                    return events;
            }
            else
            {
                // появилась новая свечка
                if (noTradeDays < candle.timeOpen)
                    noTradeDays = candle.timeOpen;

            }
            if (positions.Count == 0)
            {
                if (CountLosses >= MaxLossSeries - 1)
                {
                    CountLosses = 0; // сбрасываем счетчик после убытков
                    // включаем режим "тишина"
                    //noTradeDays = candle.timeOpen.AddDays(SilenceDays);
                    ChannelState = ChannelStateInfo.НетКанала;
                    currChannel = new Cortege3<PointD, PointD, PointD>();
                }
            }

            if (noTradeDays > quote.timeClose)
            {
                return null; // включен режим тишина, ждем когда можно будет торговать
            }

            // --------------------------------------------------------------
            // вот тут нужно делать только действия при появлении новой свечи
            // --------------------------------------------------------------
            // строить только на новой свече
            if (candle != null)
            {
                //var s = string.Format("OnQuotesReceived: сформировалась свеча OHLC {0} {1} {2} {3},   timeopen={4} timeclose={5}",
                //        candle.open, candle.high, candle.low, candle.close, candle.timeOpen, candle.timeClose);
                //Logger.Info(s);
                //events.Add(s);
            }
            //else
                //Logger.InfoFormat("OnQuotesReceived: полный проход при несформированной свечке");

            //Logger.InfoFormat("OnQuotesReceived: данные quote bid={0} ask={1} time={2}", quote.bid, quote.ask, quote.time);

            if (positions.Count != 0 && positions[0].TakeProfit == null)
            {
                // позиция разворотная последняя, трейлингуем ее и больше ничего не делаем
                ChannelState = ChannelStateInfo.НетКанала;
                currChannel = new Cortege3<PointD, PointD, PointD>();
                currLowChannelPrice = 0;
                currHighChannelPrice = 0;
                RemoveAllOrders(pendingOrders, PendingOrderType.Limit);
                if (candle != null)
                    Logger.InfoFormat("Трейлингуется разворотная позиция id={0}", positions[0].ID);
                return events;
            }

            Logger.InfoFormat("ChannelState = {0}", ChannelState.ToString());
            Logger.InfoFormat("highPrice={0}, lowPrice={1}", currHighChannelPrice, currLowChannelPrice);

            ChannelStateInfo state;
            var channel = TryToFindChannel(ChannelState, out state);

            var a = channel.a;
            var b = channel.b;
            var k = (b.Y - a.Y) / (b.X - a.X);

            if (lastIndexB == 0 && lastIndexA == 0)
            {
                lastIndexA = a.X;
                lastIndexB = b.X;
            }

            if (lastIndexB > b.X || (lastIndexB == channel.b.X && lastIndexA > channel.a.X))
            {
                // найденный канал уже старый, игнорируем его
                channel = currChannel;
            }
            else
                ChannelState = state;
            currChannel = channel;
            lastIndexA = currChannel.a.X;
            lastIndexB = currChannel.b.X;
            // теперь определяем текущие точки границ канала
            // по двум экстремумам
            a = currChannel.a;
            b = currChannel.b;
            k = (b.Y - a.Y) / (b.X - a.X);

            var price1 = b.Y + k*(candles.Count - b.X);
            // по одному экстремуму
            var c = channel.c;
            var price2 = c.Y + k*(candles.Count - c.X);

            if (price1 > price2)
            {
                currHighChannelPrice = price1;
                currLowChannelPrice = price2;
            }
            else
            {
                currHighChannelPrice = price2;
                currLowChannelPrice = price1;
            }

            SaveLog(string.Format("текущий канал - верхняя цена {0}, нижняя цена {1}, ChannelState={2}", currHighChannelPrice, currLowChannelPrice, ChannelState));
            if (quote.close < currLowChannelPrice || quote.close > currHighChannelPrice)
            {
                waitNextQuoteFlag = true;
                // редкая ситуация - цена находится вне канала, возможно после разворотов и сработанного стопа
                SaveLog(string.Format("цена {0} находится вне канала - не торгуем", quote.close));
                return events;
            }

            if (ChannelState == ChannelStateInfo.НетКанала)
            {
                SaveLog(RemoveAllOrders(pendingOrders, null)
                            ? "нет текущего канала, все отложенные ордеры сняты"
                            : "возникла ошибка при удалении ордеров");
                return events;
            }
            // надо переставить ордера
            // выбираем sell limit
            var ord = pendingOrders.FirstOrDefault(o => o.PriceSide == PendingOrderType.Limit && o.Side == -1);
            var pos = positions.FirstOrDefault(p => p.Side == -1);
            if (ord != null)
            {
                // меняем цену ордера
                var res = EditOrder(ord, (decimal)currHighChannelPrice, (decimal)currLowChannelPrice);
                if (res != RequestStatus.OK)
                {
                    Logger.ErrorFormat("SlideChannelRobot: Не могу изменить ордер №{0}, вход по цене {1}", ord.ID, ord.PriceFrom);
                }
            }
            else
                if (pos == null)
                {
                    // проверка есть ли разворотная позиция на покупку, тогда не будем ставить ордер
                    //pos = positions.FirstOrDefault(p => p.Side == 1);
                    //if (pos == null || pos.TakeProfit.HasValue)
                        InstallOrder(ticker, (decimal) currHighChannelPrice, (decimal) currLowChannelPrice,
                                 PendingOrderType.Limit, -1, RoundMinVolume);
                }

            // ордер может ставить только если нет открытой позиции в этом направлении либо он ставится за стопом открытой позиции
            if (pos != null)
            {
                //if (pos.TakeProfit != null && pos.TakeProfit != 0) // позиция не разворотная
                //{
                    pos.TakeProfit = (float) currLowChannelPrice;
                    var res = robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), pos);
                    if (res != RequestStatus.OK)
                    {
                        Logger.ErrorFormat(
                            "SlideChannelRobot: Не могу выставить tp={0} на позицию №{1}, вход по цене {2}",
                            pos.TakeProfit, pos.ID, pos.PriceEnter);
                    }
                //}
                if (ord == null && pos.StopLoss < currHighChannelPrice)
                {
                    res = InstallOrder(ticker, (decimal) currHighChannelPrice, (decimal) currLowChannelPrice,
                                    PendingOrderType.Limit, -1, RoundMinVolume);
                    if (res != RequestStatus.OK)
                    {
                        Logger.ErrorFormat("SlideChannelRobot: Не могу выставить ордер по цене {0} за поджатой позицией №{1}", currHighChannelPrice, pos.ID);
                    }
                }
            }

            // выбираем buy limit
            ord = pendingOrders.FirstOrDefault(o => o.PriceSide == PendingOrderType.Limit && o.Side == 1);
            pos = positions.FirstOrDefault(p => p.Side == 1);
            if (ord != null)
            {
                // меняем цену ордера
                var res = EditOrder(ord, (decimal)currLowChannelPrice, (decimal)currHighChannelPrice);
                if (res != RequestStatus.OK)
                {
                    Logger.ErrorFormat("SlideChannelRobot: Не могу изменить ордер №{0}, вход по цене {1}", ord.ID, ord.PriceFrom);
                }
            }
            else
                if (pos == null)
                {
                    // проверка есть ли разворотная позиция на покупку, тогда не будем ставить ордер
                    //pos = positions.FirstOrDefault(p => p.Side == -1);
                    //if (pos == null || pos.TakeProfit.HasValue)
                        InstallOrder(ticker, (decimal) currLowChannelPrice, (decimal) currHighChannelPrice,
                                 PendingOrderType.Limit, 1, RoundMinVolume);
                }

            if (pos != null)
            {
                //if (pos.TakeProfit != null && pos.TakeProfit != 0) // позиция не разворотная
                //{
                    pos.TakeProfit = (float) currHighChannelPrice;
                    var res = robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), pos);
                    if (res != RequestStatus.OK)
                    {
                        Logger.ErrorFormat(
                            "SlideChannelRobot: Не могу выставить tp={0} на позицию №{1}, вход по цене {2}",
                            pos.TakeProfit, pos.ID, pos.PriceEnter);
                    }
                //}
                if (ord == null && pos.StopLoss > currLowChannelPrice)
                {
                    res = InstallOrder(ticker, (decimal) currLowChannelPrice, (decimal) currHighChannelPrice,
                                    PendingOrderType.Limit, 1, RoundMinVolume);
                    if (res != RequestStatus.OK)
                    {
                        Logger.ErrorFormat("SlideChannelRobot: Не могу выставить ордер по цене {0} за поджатой позицией №{1}", currLowChannelPrice, pos.ID);
                    }
                }
            }
            return events;
        }
        /// <summary>
        /// Поиск каналов
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        private Cortege3<PointD, PointD, PointD> TryToFindChannel(ChannelStateInfo currState, out ChannelStateInfo state)
        {
            state = ChannelStateInfo.НетКанала;
            var channel = new Cortege3<PointD, PointD, PointD> { };
            switch (currState)
            {
                case ChannelStateInfo.НетКанала:
                    // канала еще нет, ищем сначала по верхним точкам, если не находим, пробуем по нижним найти
                    var channelhigh = GetHighLineChannel(candles, candles.Count - 1);
                    var channellow = GetLowLineChannel(candles, candles.Count - 1);
                    if ((channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0))
                        && (channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                    {
                        return currChannel;
                    }

                    if (channelhigh.a == new PointD(0, 0) || channelhigh.b == new PointD(0, 0))
                    {
                        state = ChannelStateInfo.ПостроенПоМинимумам;
                        return channellow;
                    }

                    if ((channellow.a == new PointD(0, 0) || channellow.b == new PointD(0, 0)))
                    {
                        state = ChannelStateInfo.ПостроенПоМаксимумам;
                        return channelhigh;
                    }
                    if (channelhigh.b.X > channellow.b.X || (channelhigh.b.X == channellow.b.X && channelhigh.a.X > channellow.a.X))
                    {
                        state = ChannelStateInfo.ПостроенПоМаксимумам;
                        return channelhigh;
                    }
                    state = ChannelStateInfo.ПостроенПоМинимумам;
                    return channellow;

                case ChannelStateInfo.ПостроенПоМаксимумам:
                    channel = GetLowLineChannel(candles, candles.Count - 1);
                    if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                        channel = currChannel;
                    else
                        state = ChannelStateInfo.ПостроенПоМинимумам;
                    break;
                case ChannelStateInfo.ПостроенПоМинимумам:
                    channel = GetHighLineChannel(candles, candles.Count - 1);
                    if (channel.a == new PointD(0, 0) || channel.b == new PointD(0, 0))
                        channel = currChannel;
                    else
                        state = ChannelStateInfo.ПостроенПоМаксимумам;
                    break;
            }
            return channel;
        }