Beispiel #1
0
        private List<string> UpdateOrders(DateTime now, List<MarketOrder> orders)
        {
            var result = new List<string>();
            foreach (var order in orders.Where(o => o.Magic == Magic))
            {
                var sign = order.Side > 0 ? 1 : -1;
                var updateOrder = false;

                // sl
                var slPointsDecrease = InitialSlPoints - (int)((now - order.TimeEnter).TotalMinutes / SlTpPeriodMinutes) * SlTpPointsDecrease;
                var slDecrease = DalSpot.Instance.GetAbsValue(order.Symbol, (float)slPointsDecrease);
                var slValue = order.PriceEnter - sign * slDecrease;
                var slPointsDeviation = GetPointsDeviation(order, slValue, true);
                if (Math.Abs((int)slPointsDeviation) >= 1)
                    updateOrder = true;

                // tp
                var tpPointsDecrease = InitialTpPoints - (int)((now - order.TimeEnter).TotalMinutes / SlTpPeriodMinutes) * SlTpPointsDecrease;
                var tpDecrease = DalSpot.Instance.GetAbsValue(order.Symbol, (float)tpPointsDecrease);
                var tpValue = order.PriceEnter + sign * tpDecrease;
                var tpPointsDeviation = GetPointsDeviation(order, tpValue, false);
                if (Math.Abs((int)tpPointsDeviation) >= 1)
                    updateOrder = true;

                // update
                if (!updateOrder) // sl/tp changes are < 1 points - not updating
                    continue;
                order.StopLoss = slValue;
                order.TakeProfit = tpValue;
                var status = robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), order);
                if (status != RequestStatus.OK)
                {
                    var hint = new RobotHint(order.Symbol, "",
                                                "SendEditMarketRequest error: " +
                                                EnumFriendlyName<RequestStatus>.GetString(status),
                                                order.Side > 0 ? "BUY SL" : "SELL SL", "e", order.StopLoss.Value)
                    {
                        Time = now,
                        RobotHintType = RobotHint.HintType.Поджатие,
                        ColorFill = Color.Red
                    };
                    result.Add(hint.ToString());
                    hint = new RobotHint(order.Symbol, "",
                                         "SendEditMarketRequest error: " +
                                         EnumFriendlyName<RequestStatus>.GetString(status),
                                         order.Side > 0 ? "BUY TP" : "SELL TP", "e", order.TakeProfit.Value)
                    {
                        Time = now,
                        RobotHintType = RobotHint.HintType.Поджатие,
                        ColorFill = Color.Red
                    };
                    result.Add(hint.ToString());
                }
                /*else
                {
                    // 4 debug
                    var hint = new RobotHint(order.Symbol, "", "SendEditMarketRequest Ok",
                                             order.Side > 0 ? "BUY SL" : "SELL SL", "i", order.StopLoss.Value)
                                   {
                                       Time = now,
                                       RobotHintType = RobotHint.HintType.Поджатие,
                                   };
                    result.Add(hint.ToString());
                    hint = new RobotHint(order.Symbol, "", "SendEditMarketRequest Ok",
                                         order.Side > 0 ? "BUY TP" : "SELL TP", "i", order.TakeProfit.Value)
                               {
                                   Time = now,
                                   RobotHintType = RobotHint.HintType.Поджатие,
                               };
                    result.Add(hint.ToString());
                }*/
            }
            return result;
        }
        private bool CheckEnterCondition(CandleData candle, List<MarketOrder> openedOrders, List<string> events, bool isHistoryStartOff)
        {
            if (side == 0) return false;

            // проверить количество сделок
            var ownOrders = FiboRobotPosition.GetRobotPositions(ticker, openedOrders, timeframe, PriceA, null);
            var ordersCount = ownOrders.Count;
            if (ordersCount >= MaxDealsInSeries) return false;

            // обновить цену B?
            var bWasUpdated = false;
            if ((side > 0 && candle.close > (float)PriceB) ||
                (side < 0 && candle.close < (float)PriceB))
            {
                // удалить старую отметку - цена В обновлена
                events.Add(new RobotMarkClear(ticker, timeframe, HintPriceBIsUpdated)
                {
                    RobotHintType = RobotMark.HintType.Тейк
                }.ToString());

                // и добавить новую
                var msg = string.Format("Цена \"B\" обновлена с {0} на {1}",
                                        PriceB.ToStringUniformPriceFormat(), candle.close.ToStringUniformPriceFormat());
                var hint = MakeRobotComment(
                    candle.close, msg,
                    candle.timeClose, Color.Crimson,
                    RobotMark.HintType.Тейк);
                hint.HintCode = HintPriceBIsUpdated;
                events.Add(hint.ToString());
                events.Add(msg);

                PriceB = (decimal)candle.close;
                bWasUpdated = true;
                priceBwasUpdated = true;
            }

            if (isHistoryStartOff) return false;

            // проверить, преодолен ли уровень входа
            var levelBroken =
                IsPriceInsideTargetLevels(candle.close, PriceA, PriceB, false);
            if (!levelBroken) return false;

            var level = PriceB + KoefEnter * (PriceA - PriceB);
            var msgLevelBroken = string.Format("Уровень {0} преодолен, направление - {1}",
                                    level.ToStringUniformPriceFormat(), Side);

            // получить закрытые ордера
            var closedOrders = GetLastClosedOrders();
            var orders = openedOrders.Union(closedOrders).OrderByDescending(o => o.TimeEnter).ToList();
            var openedAndClosedFiboOrders = FiboRobotPosition.GetRobotPositions(ticker, orders, timeframe, PriceA, null);

            // если цена B не была обновлена свечкой, проверить, нет ли сделок
            // по данному расширению A-B, открытых "лучше" этой цены
            if (!bWasUpdated)
            {
                if (openedAndClosedFiboOrders.Count > 0)
                {
                    if ((side > 0 && openedAndClosedFiboOrders.Any(d => d.order.PriceEnter < candle.close)) ||
                        (side < 0 && openedAndClosedFiboOrders.Any(d => d.order.PriceEnter > candle.close)))
                    {
                        msgLevelBroken += ", есть сделки по \"лучшей\" цене";
                        events.Add(msgLevelBroken);
                        return false;
                    }
                }
            }

            // второй уровень Фибо преодолен?
            if (!CheckEnterThenFiboCondition(candle, side, openedAndClosedFiboOrders.Select(o => o.order).ToList()))
            {
                // создать отметку на графике и выйти
                var hint = new RobotHint(ticker, timeframe.ToString(),
                    "Уровень ФБ-II не преодолен", "ФБ-II", "Ф", candle.close)
                {
                    Time = candle.timeClose,
                    ColorFill = Color.Coral,
                    ColorLine = Color.DarkRed,
                    RobotHintType = RobotHint.HintType.Коментарий,
                    Timeframe = BarSettingsStorage.Instance.GetBarSettingsFriendlyName(timeframe)
                };
                events.Add(hint.ToString());

                return false;
            }

            if (CloseOtherSides)
                CloseOtherSideDeals(ownOrders.Select(o => o.order).ToList());

            msgLevelBroken += ", вход в рынок";
            events.Add(msgLevelBroken);
            // таки войти в рынок
            var enterIsOk = OpenDeal(orders);
            if (enterIsOk && (ordersCount >= maxDealsInSeries - 1))
                events.Add(string.Format("Робот \"FX\" {0} осуществил {1} входов в рынок",
                    HumanRTickers, maxDealsInSeries));
            return true;
        }
Beispiel #3
0
        private List<string> ProcessQuotes(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            var result = new List<string>();

            // дописываем лог
            foreach (var m in pendingLogMessages.Where(e => !logMessages.Contains(e)))
            {
                logMessages.Add(m);
                result.Add(MakeLog(m));
            }

            // проверяем инициализацию
            var message = "не инициализирован, остановлен";
            if (newsSettings == null || currencySettings == null)
            {
                if (!logMessages.Contains(message))
                {
                    logMessages.Add(message);
                    result.Add(MakeLog(message));
                }
                return result;
            }

            // all ok inform
            // информируем о начале работы
            message = "запущен";
            if (!logMessages.Contains(message))
            {
                logMessages.Add(message);
                result.Add(MakeLog(message));
            }

            // saving to cache
            // сохраняем кэш котировок
            for (var i = 0; i < names.Length; i++)
            {
                var name = names[i];
                if(!quoteStorage.ContainsKey(name))
                    quoteStorage.Add(name, new List<QuoteData>());
                quoteStorage[name].Add(quotes[i].GetCloseQuote());
            }

            // if this call is used for caching quotes - exiting
            // если мы в режиме наполнения кэша - выходим
            if (isHistoryStartOff)
                return result;

            // detemining model time
            // определение модельного времени
            if (quotes.Length == 0)
                return result;
            var now = quotes[0].timeClose;

            // update orders' SL & TP
            // обновляем сделки
            List<MarketOrder> orders;
            robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders);
            result.AddRange(UpdateOrders(now, orders));

            // working with news
            // make GrabNews calls unfrequent
            // сокращаем частоту вызовов GrabNews
            if ((now - lastGrabNewsCall.GetLastHit()).TotalSeconds < PauseForNewsReadingSeconds)
                return result;
            var grab = true; // in present - grab each PauseForNewsReadingSeconds
            if (now.Date < DateTime.Today) // working in the past (testing)
                if (now.Date == lastGrabNewsCall.GetLastHit().Date) // grabbing only once in day
                    grab = false;
            // grabbing
            // извлечение с Alpari
            if (grab)
            {
                List<string> parseErrors;
                var news = GrabNews(new DateTime(now.Year, now.Month, now.Day), out parseErrors);
                foreach (var m in parseErrors.Where(e => !logMessages.Contains(e)))
                {
                    logMessages.Add(m);
                    result.Add(MakeLog(m));
                }
                if (news.Count == 0)
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error,
                                                          LogMsgNoNewsParsed, 1000 * 60 * 5, "Прочитано 0 новостей");
                else
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                          LogMsgNewsParsed, 1000 * 60 * 5, "Прочитано {0} новостей",
                                                          news.Count);
                freshNews.AddRange(news);
                lastGrabNewsCall.SetTime(now);
            }
            // processing
            // обработка новостей (внешний цикл)
            foreach (var curNews in freshNews)
            {
                var currentNews = curNews;

                // сверяем время
                if (oldNews.Contains(currentNews)) // news already processed
                    continue;
                // news obsolete
                // новость устарела
                if ((now - currentNews.Time - new TimeSpan(0, NewsProcessingDelayMinutes, 0)).TotalMinutes > NewsObsolescenceTimeMinutes)
                {
                    oldNews.Add(currentNews);
                    continue;
                }
                // news in future; skip processing
                // придержим новость на будущее
                if (currentNews.Time + new TimeSpan(0, NewsProcessingDelayMinutes, 0) > now)
                    continue;

                var timeNear = currentNews.Time.AddMinutes(TimeNearMinutes);
                var timeFar = currentNews.Time.AddMinutes(-TimeFarMinutes);

                result.Add(MakeLog("обрабатывается " + currentNews));
                var chatMessage = "\n"; // здесь формируется сообщение в чат
                chatMessage += string.Format("Обрабатывается новость: [{0}] {1}\nВремя: {2}, прогноз: {3}, фактическое: {4}\n",
                                  currentNews.CountryCode, currentNews.Title, currentNews.Time,
                                  currentNews.ProjectedValue, currentNews.Value);

                // calc weights
                // вычисляем веса, определяем знак
                int valueWeight;
                if(currentNews.ProjectedValue > currentNews.Value)
                    valueWeight = -1;
                else if((currentNews.ProjectedValue < currentNews.Value))
                    valueWeight = 1;
                else
                    valueWeight = 0;
                var delta = currentNews.ProjectedValue == 0
                                ? 100
                                : (int)Math.Abs((currentNews.Value - currentNews.ProjectedValue) / currentNews.ProjectedValue * 100);
                var newsWeight = GetWeight(currentNews.CountryCode, currentNews.Title, delta);
                // 4 debug
                /*if (newsWeight == 0)
                {
                    message = string.Format("Valuable news not processed: [{0}] {1}", currentNews.CountryCode,
                                                currentNews.Title);
                    if (!logMessages.Contains(message))
                    {
                        logMessages.Add(message);
                        result.AddRange(MakeLog(message));
                    }
                }*/
                var sign = valueWeight * newsWeight;
                if(sign == 0)
                {
                    oldNews.Add(currentNews);
                    chatMessage += "Результат: нет входа в рынок\n";
                    chatMessage += "Причина: " +
                                   (newsWeight == 0
                                        ? "вес новости равен 0\n"
                                        : "отклонение экономического показателя равно 0\n");
                    if (SendMessageInRoom != null)
                        SendMessageInRoom(chatMessage, chatRoom);
                    continue;
                }

                // gathering tickers for affected currecncies
                // определяем затронутые новостью валютные пары и их знак новостного сигнала
                var tickersAndSigns = new List<Cortege2<string, int>>();
                var currencies = currencySettings.Where(c => c.CountryCode == currentNews.CountryCode).Select(c => c.CurrencyCode);
                foreach (var currency in currencies)
                {
                    var cur = currency;
                    var tickersWithBaseCur = Graphics.Where(g => g.a.StartsWith(cur)).Select(g => g.a);
                    tickersAndSigns.AddRange(tickersWithBaseCur.Select(t => new Cortege2<string, int>(t, sign)).ToList());
                    var tickersWithQuoteCur = Graphics.Where(g => g.a.EndsWith(cur)).Select(g => g.a);
                    tickersAndSigns.AddRange(
                        tickersWithQuoteCur.Select(t => new Cortege2<string, int>(t, -sign)).ToList());
                }

                // processing tickers
                // работаем с выбранными валютными парами (внутренний цикл)
                foreach (var tickerAndSign in tickersAndSigns)
                {
                    var ticker = tickerAndSign.a;
                    var curSign = tickerAndSign.b;

                    // определение действующей на этот момент котировки
                    var data = GetDataFromStorage(ticker, currentNews.Time, currentNews.Time.AddMinutes(5));
                    if(data.Count == 0)
                    {
                        chatMessage += "Результат: нет входа в рынок с " + ticker + "\n";
                        chatMessage += "Причина: нет котировки для " + ticker + " в диапазоне от " +
                                       currentNews.Time + " до " + currentNews.Time.AddMinutes(5) + "\n";
                        if (SendMessageInRoom != null)
                            SendMessageInRoom(chatMessage, chatRoom);
                        continue;
                    }

                    // опорное значение для определения трендов и величины сделки - цена спроса
                    var value = data[0].bid;

                    // определение тренда
                    int signNear = 0, signFar = 0;
                    data = GetDataFromStorage(ticker, timeNear, timeNear.AddMinutes(5));
                    if (data.Count == 0)
                    {
                        // 4 debug
                        var hint = new RobotHint(ticker, "", "insufficient data for near-trend",
                                                    curSign > 0 ? "BUY no near-data" : "SELL no near-data", "e", value)
                                        {Time = now, ColorFill = Color.Red};
                        result.Add(hint.ToString());
                        chatMessage += "Результат: нет входа в рынок с " + ticker + "\n";
                        chatMessage += "Причина: недостаточно данных для определения тренда после выхода новости\n";
                        if (SendMessageInRoom != null)
                            SendMessageInRoom(chatMessage, chatRoom);
                        continue;
                    }
                    var valueNear = data[0].bid;
                    if (value > valueNear)
                        signNear = 1;
                    else if (value < valueNear)
                        signNear = -1;
                    data = GetDataFromStorage(ticker, timeFar, timeFar.AddMinutes(5));
                    if (data.Count == 0)
                    {
                        // 4 debug
                        var hint = new RobotHint(ticker, "", "insufficient data for far-trend",
                                                    curSign > 0 ? "BUY no far-data" : "SELL no far-data", "e", value)
                                        {Time = now, ColorFill = Color.Red};
                        result.Add(hint.ToString());
                        chatMessage += "Результат: нет входа в рынок с " + ticker + "\n";
                        chatMessage += "Причина: недостаточно данных для определения тренда до выхода новости\n";
                        if (SendMessageInRoom != null)
                            SendMessageInRoom(chatMessage, chatRoom);
                        continue;
                    }
                    var valueFar = data[0].bid;
                    if (value > valueFar)
                        signFar = 1;
                    else if (value < valueFar)
                        signFar = -1;

                    // определяем необходимость входа в рынок
                    var values = new Dictionary<string, double>();
                    values.Add("tn", curSign);
                    values.Add("tba", signFar);
                    values.Add("tcb", signNear);
                    double formulaResult;
                    var resultFlag = expressionResolver.Calculate(values, out formulaResult);
                    if (!resultFlag)
                    {
                        result.Add(MakeLog("Ошибка в расчете по формуле для входа в рынок"));
                        chatMessage += "Результат: нет входа в рынок с " + ticker + "\n";
                        chatMessage += "Причина: ошибка в расчете по формуле для входа в рынок\n";
                        if(SendMessageInRoom != null)
                            SendMessageInRoom(chatMessage, chatRoom);
                        continue;
                    }

                    // вход в рынок
                    var tradeSign = 0;
                    switch (EnterSign)
                    {
                        case EnterSignEnum.Tn:
                            tradeSign = curSign;
                            break;
                        case EnterSignEnum.NotTn:
                            tradeSign = -curSign;
                            break;
                        case EnterSignEnum.Tba:
                            tradeSign = signFar;
                            break;
                        case EnterSignEnum.NotTba:
                            tradeSign = -signFar;
                            break;
                        case EnterSignEnum.Tcb:
                            tradeSign = signNear;
                            break;
                        case EnterSignEnum.NotTcb:
                            tradeSign = -signNear;
                            break;
                    }
                    if (formulaResult != 0)
                    {
                        // если получен сигнал на покупку - купить, закрыв продажи
                        // наоборот, если получен сигнал на продажу - продать, закрыв покупки
                        robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders);
                        var ordersToClose = orders.Where(o => o.Symbol == ticker && o.Side != tradeSign).ToList();
                        foreach (var order in ordersToClose)
                        {
                            robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(),
                                robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot);
                        }
                        // создаем ордер
                        var decreaseSl = DalSpot.Instance.GetAbsValue(ticker, (float)InitialSlPoints);
                        var slValue = value - tradeSign * decreaseSl;
                        var decreaseTp = DalSpot.Instance.GetAbsValue(ticker, (float)InitialTpPoints);
                        var tpValue = value + tradeSign * decreaseTp;
                        var newOrder = new MarketOrder
                            {
                                AccountID = robotContext.AccountInfo.ID,
                                Magic = Magic,
                                Symbol = ticker,
                                Volume = Volume,
                                Side = tradeSign,
                                StopLoss = slValue,
                                TakeProfit = tpValue,
                                ExpertComment = currentNews.Title
                            };

                        var status = robotContext.SendNewOrderRequest(protectedContext.MakeProtectedContext(),
                                                            RequestUniqueId.Next(),
                                                            newOrder,
                                                            OrderType.Market, (decimal)value, 0);
                        if (status != RequestStatus.OK)
                        {
                            var hint = new RobotHint(ticker, "",
                                                     "SendNewOrderRequest error: " +
                                                     EnumFriendlyName<RequestStatus>.GetString(status) + " news: " +
                                                     currentNews,
                                                     tradeSign > 0 ? "BUY error" : "SELL error", "e", value)
                                {
                                    Time = now,
                                    ColorFill = Color.Red
                                };
                            result.Add(hint.ToString());
                        }
                        else
                        {
                            var hint = new RobotHint(ticker, "", "SendNewOrderRequest Ok, news: " + currentNews,
                                                        tradeSign > 0 ? "BUY" : "SELL", "i", value) { Time = now, ColorFill = Color.Red };
                            result.Add(MakeLog("вход в рынок по новости " + currentNews));
                            result.Add(hint.ToString());
                            chatMessage += "Результат: вход в рынок: " + (tradeSign > 0 ? "покупка " : "продажа ") + ticker + "\n";
                        }
                    }
                    else
                    {
                        var hint = new RobotHint(ticker, "", "Market condition fulfill failed, news: " + currentNews,
                                                    tradeSign > 0 ? "BUY no condition" : "SELL no condition", "e", value)
                                        {
                                            Time = now, RobotHintType = RobotHint.HintType.Стоп
                                        };
                        result.Add(hint.ToString());
                        chatMessage += "Результат: нет входа в рынок с " + ticker + "\n";
                        chatMessage += "Причина: не выполнено условие входа\n";
                    }
                    if (SendMessageInRoom != null)
                        SendMessageInRoom(chatMessage, chatRoom);
                }
                oldNews.Add(currentNews);
            }
            return result;
        }
        /// <summary>
        /// проверить условия повторного входа (в другом направлении)
        /// </summary>
        private void CheckVersaEnterCondition(CandleData candle, List<MarketOrder> orders, List<string> events)
        {
            List<FiboRobotPosition> allOrders;
            FiboRobotPosition lastOrder;
            decimal a;
            decimal b;

            if (!GetVersaEnterAandB(orders, out allOrders, out lastOrder, out a, out b)) return;
            var doubleSide = a < b ? DealType.Buy : DealType.Sell;

            var shouldEnter = IsPriceInsideTargetLevels(candle.close, a, b, true);
            if (!shouldEnter) return;

            // проверить - нет ли повторных ("второй серии") входов по "лучшей" цене?
            // не слишком ли много повторных входов?
            var doubledDeals = allOrders.Where(d => d.Sequence > 1).ToList();
            if (doubledDeals.Count(d => d.order.IsOpened) >= MaxDealsInSeries) return;
            var hasBetterDoubledDeal = doubleSide > 0
                                           ? doubledDeals.Any(d => d.order.PriceEnter < candle.close)
                                           : doubledDeals.Any(d => d.order.PriceEnter > candle.close);
            if (hasBetterDoubledDeal) return;

            // проверить - есть ли N свечек и M пунктов с момента последней сделки?
            var deltaPoints = DalSpot.Instance.GetPointsValue(ticker, Math.Abs((decimal)candle.close - b));
            if (deltaPoints < MinPointsForDoubleEnter)
            {
                if (VerboseLogging)
                    Logger.InfoFormat(RobotNamePreffix + ": повторный вход ({0} {1}) невозможен - расстояние [C, D] слишком мало",
                        doubleSide, ticker);
                return;
            }

            // добавить отметку - повторный вход в рынок
            var hint = new RobotHint(ticker, timeframe.ToString(),
                "Повторный вход, цена A: " + a.ToStringUniformPriceFormat() + ", цена B: " + b.ToStringUniformPriceFormat() +
                " (из сделки #" + lastOrder.order.ID + ")",
                "повторный " + doubleSide, "d", candle.close)
            {
                Time = candle.timeClose,
                ColorFill = Color.LawnGreen,
                ColorLine = Color.MediumSeaGreen,
                RobotHintType = RobotHint.HintType.Коментарий,
                Timeframe = BarSettingsStorage.Instance.GetBarSettingsFriendlyName(timeframe)
            };
            events.Add(hint.ToString());

            // войти в рынок повторно
            OpenDeal(orders, a, b, 2, (int)doubleSide);
        }