private void AddRobotHintLineOnChart(RobotHint hint, ChartForm chart) { var pivotIndex = chart.chart.chart.StockSeries.GetIndexByCandleOpen( hint.Time.Value); var line = new TrendLine { Comment = hint.Text, DateStart = hint.Time.Value, LineColor = hint.ColorLine ?? chart.chart.chart.visualSettings.SeriesForeColor, ShapeFillColor = hint.ColorFill ?? chart.chart.chart.visualSettings.SeriesBackColor, LineStyle = TrendLine.TrendLineStyle.Отрезок, Owner = chart.chart.seriesTrendLine }; if (!string.IsNullOrEmpty(hint.HintCode)) line.Name = hint.HintCode; line.AddPoint(pivotIndex, hint.Price.Value); // точку конца отрезка сместить вправо на N свечек line.AddPoint(pivotIndex + 10, hint.Price.Value); chart.chart.seriesTrendLine.data.Add(line); }
public override List <string> OnQuotesReceived(string[] names, QuoteData[] quotes, bool isHistoryStartOff) { if (formulaResolver == null || packer == null) { return(null); } curTime = quotes[0].time; // обновить табличку цен for (var i = 0; i < names.Length; i++) { if (lastBids.ContainsKey(names[i])) { lastBids[names[i]] = quotes[i].bid; } else { lastBids.Add(names[i], quotes[i].bid); } } QuoteData 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.bid, curQuote.time); Dictionary <string, double> varValues = null; if (candle != null) { candles.Add(candle); countCandles++; // обновить очереди (для индекса, переменные вида usdjpy#15) if (lastBidLists.Count > 0) { foreach (var listTicker in lastBidLists) { float price; if (!lastBids.TryGetValue(listTicker.Key, out price)) { price = 0; } listTicker.Value.Add(price); } } // посчитать индекс double index; varValues = GetVariableValues(); if (formulaResolver.Calculate(varValues, out index)) { lastIndexValue = double.IsNaN(index) ? 0 : (float)index; } lastIndicies.Add(lastIndexValue ?? 0); } // если это период "разгона" конвейера if (isHistoryStartOff) { return(null); } RobotHint hint = null; // получить знак дивергенции if (candle != null) { string commentOnDivergence = string.Empty; var divergenceSign = GetDivergenceSign(out commentOnDivergence); List <MarketOrder> orders; robotContext.GetMarketOrders(robotContext.accountInfo.ID, out orders); if (divergenceSign != 0) { var hintText = new StringBuilder(); hintText.AppendLine(commentOnDivergence); hintText.AppendLine("Переменные:"); // ReSharper disable PossibleNullReferenceException) foreach (var pair in varValues) // ReSharper restore PossibleNullReferenceException { hintText.AppendLine(string.Format("{1}{0}{2:f4}", (char)9, pair.Key, pair.Value)); } hint = new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), hintText.ToString(), divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.bid) { Time = candle.timeOpen, //curTime ColorFill = divergenceSign > 0 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = divergenceSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }; // если получен сигнал на покупку - купить, закрыв продажи // наоборот, если получен сигнал на продажу - продать, закрыв покупки var ordersToClose = orders.FindAll(o => o.Side != divergenceSign); foreach (var order in ordersToClose) { robotContext.SendCloseRequest(CurrentProtectedContext.Instance.MakeProtectedContext(), robotContext.accountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); } // открыть позу в направлении знака дивера decimal?stop = StopLossPoints == 0 ? (decimal?)null : (decimal)curQuote.bid - divergenceSign * DalSpot.Instance.GetAbsValue(ticker, (decimal)StopLossPoints); decimal?take = TakeProfitPoints == 0 ? (decimal?)null : (decimal)curQuote.bid + divergenceSign * DalSpot.Instance.GetAbsValue(ticker, (decimal)TakeProfitPoints); robotContext.SendNewOrderRequest(CurrentProtectedContext.Instance.MakeProtectedContext(), RequestUniqueId.Next(), robotContext.accountInfo.ID, Magic, ticker, Volume, divergenceSign, OrderType.Market, 0, 0, stop, take, null, null, string.Empty, "OscillatorBasedRobot"); } } return(hint != null ? new List <string> { hint.ToString() } : null); }
public override List<string> OnQuotesReceived(string[] names, QuoteData[] quotes, bool isHistoryStartOff) { if (formulaResolver == null || packer == null) return null; curTime = quotes[0].time; // обновить табличку цен for (var i = 0; i < names.Length; i++) { if (lastBids.ContainsKey(names[i])) lastBids[names[i]] = quotes[i].bid; else lastBids.Add(names[i], quotes[i].bid); } QuoteData 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.bid, curQuote.time); Dictionary<string, double> varValues = null; if (candle != null) { candles.Add(candle); countCandles++; // обновить очереди (для индекса, переменные вида usdjpy#15) if (lastBidLists.Count > 0) { foreach (var listTicker in lastBidLists) { float price; if (!lastBids.TryGetValue(listTicker.Key, out price)) price = 0; listTicker.Value.Add(price); } } // посчитать индекс double index; varValues = GetVariableValues(); if (formulaResolver.Calculate(varValues, out index)) lastIndexValue = double.IsNaN(index) ? 0 : (float)index; lastIndicies.Add(lastIndexValue ?? 0); } // если это период "разгона" конвейера if (isHistoryStartOff) return null; RobotHint hint = null; // получить знак дивергенции if (candle != null) { string commentOnDivergence = string.Empty; var divergenceSign = GetDivergenceSign(out commentOnDivergence); List<MarketOrder> orders; robotContext.GetMarketOrders(robotContext.accountInfo.ID, out orders); if (divergenceSign != 0) { var hintText = new StringBuilder(); hintText.AppendLine(commentOnDivergence); hintText.AppendLine("Переменные:"); // ReSharper disable PossibleNullReferenceException) foreach (var pair in varValues) // ReSharper restore PossibleNullReferenceException { hintText.AppendLine(string.Format("{1}{0}{2:f4}", (char) 9, pair.Key, pair.Value)); } hint = new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), hintText.ToString(), divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.bid) { Time = candle.timeOpen, //curTime ColorFill = divergenceSign > 0 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = divergenceSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }; // если получен сигнал на покупку - купить, закрыв продажи // наоборот, если получен сигнал на продажу - продать, закрыв покупки var ordersToClose = orders.FindAll(o => o.Side != divergenceSign); foreach (var order in ordersToClose) { robotContext.SendCloseRequest(CurrentProtectedContext.Instance.MakeProtectedContext(), robotContext.accountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); } // открыть позу в направлении знака дивера decimal? stop = StopLossPoints == 0 ? (decimal?) null : (decimal)curQuote.bid - divergenceSign*DalSpot.Instance.GetAbsValue(ticker, (decimal)StopLossPoints); decimal? take = TakeProfitPoints == 0 ? (decimal?) null : (decimal)curQuote.bid + divergenceSign*DalSpot.Instance.GetAbsValue(ticker, (decimal)TakeProfitPoints); robotContext.SendNewOrderRequest(CurrentProtectedContext.Instance.MakeProtectedContext(), RequestUniqueId.Next(), robotContext.accountInfo.ID, Magic, ticker, Volume, divergenceSign, OrderType.Market, 0, 0, stop, take, null, null, string.Empty, "OscillatorBasedRobot"); } } return hint != null ? new List<string> {hint.ToString()} : null; }
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 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; }
private void AddRobotHintOnChart(RobotHint hint, ChartForm chart) { // добавить отрезочек с комментарием if (hint.RobotHintType == RobotMark.HintType.Линия) { AddRobotHintLineOnChart(hint, chart); return; } // добавить звездочку var toolTip = new AsteriskTooltip(hint.Title, hint.Text) { Owner = chart.chart.seriesAsteriks, Price = hint.Price.Value, CandleIndex = chart.chart.chart.StockSeries.GetIndexByCandleOpen( hint.Time.Value), DateStart = hint.Time.Value, Sign = hint.Sign, Radius = 5, Shape = hint.RobotHintType == RobotMark.HintType.Стоп ? AsteriskTooltip.ShapeType.Квадрат : hint.RobotHintType == RobotMark.HintType.Тейк ? AsteriskTooltip.ShapeType.Квадрат : hint.RobotHintType == RobotMark.HintType.Покупка ? AsteriskTooltip.ShapeType.СтрелкаВверх : hint.RobotHintType == RobotMark.HintType.Продажа ? AsteriskTooltip.ShapeType.СтрелкаВниз : hint.RobotHintType == RobotMark.HintType.Поджатие ? AsteriskTooltip.ShapeType.Звезда : AsteriskTooltip.ShapeType.Круг }; if (!string.IsNullOrEmpty(hint.HintCode)) toolTip.Name = hint.HintCode; if (hint.ColorFill.HasValue) toolTip.ColorFill = hint.ColorFill.Value; if (hint.ColorLine.HasValue) toolTip.ColorLine = hint.ColorLine.Value; if (hint.ColorText.HasValue) toolTip.ColorText = hint.ColorText.Value; chart.chart.seriesAsteriks.data.Add(toolTip); }
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; }
private void AddRobotHintOnPriceUpdated(string pricePreffix, decimal priceOld, decimal priceNew, DateTime eventTime) { if (eventTime == default(DateTime)) eventTime = DateTime.Now; var hint = new RobotHint(ticker, timeframe.ToString(), "Цена " + pricePreffix + " обновлена с " + priceOld.ToStringUniformPriceFormat() + " на " + priceNew.ToStringUniformPriceFormat(), "цена " + pricePreffix, pricePreffix, (float)priceNew) { Time = eventTime, ColorFill = Color.Moccasin, ColorLine = Color.DarkGoldenrod, RobotHintType = RobotHint.HintType.Тейк, Timeframe = BarSettingsStorage.Instance.GetBarSettingsFriendlyName(timeframe) }; recentRobotHints.Add(hint); }
private RobotHint MakeRobotComment(float price, string text, DateTime time, Color? colorLine = null, RobotMark.HintType hintType = RobotMark.HintType.Линия) { var hint = new RobotHint(ticker, BarSettingsStorage.Instance.GetBarSettingsFriendlyName(timeframe), text, GetUniqueName(), "*", price) { Time = time, ColorFill = Color.LightGray, ColorLine = colorLine ?? Color.DarkBlue, RobotHintType = hintType }; return hint; }
/// <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); }