/// <summary> /// планирование покупки или продажи. /// </summary> private int UpdateHigherTimeframesAndGetPlanDirection(CandleDataBidAsk quote, bool calcKijun) { var packers = new[] { dayCandlePacker, hourCandlePacker }; bool[] higherThanKijuns = { false, false }; for (var i = 0; i < subQueue.Length; i++) { var candle = packers[i].UpdateCandle(quote); if (candle != null) { subQueue[i].Add(candle); } if (!calcKijun) { continue; } var candles = candle != null ? subQueue[i].ToList() : subQueue[i].Union(new[] { packers[i].CurrentCandle }).ToList(); var kijun = (candles.Min(c => c.low) + candles.Max(c => c.high)) / 2; higherThanKijuns[i] = quote.close > kijun; } if (!calcKijun || subQueue.Any(q => q.Length < q.MaxQueueLength)) { return(0); } return(higherThanKijuns.Any(x => x != higherThanKijuns[0]) ? 0 : higherThanKijuns[0] ? 1 : -1); }
private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle) { // функция считает и округляет объем входа var volume = CalculateVolume(symbol, base.Leverage); if (volume == 0) { events.Add(string.Format("{0} {1} отменена - объем равен 0", dealSign > 0 ? "покупка" : "продажа", symbol)); return; } var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close; var point = pointCost[symbol]; var stopLoss = enterPrice - dealSign * (float)point * StopLossPoints; var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints; var order = new MarketOrder { Symbol = symbol, // Инструмент по которому совершается сделка Volume = volume, // Объём средств, на который совершается сделка Side = dealSign, // Устанавливаем тип сделки - покупка или продажа StopLoss = stopLoss, // Устанавливаем величину Stop loss для открываемой сделки TakeProfit = takeProfit, // Устанавливаем величину Take profit для открываемой сделки ExpertComment = "TornAssholeRobot" // Комментарий по сделке, оставленный роботом }; var status = NewOrder(order, OrderType.Market, // исполнение по рыночной цене - можно везде выбирать такой вариант 0, 0); // последние 2 параметра для OrderType.Market не имеют значения if (status != RequestStatus.OK) { events.Add(string.Format("Ошибка добавления ордера ({0}): {1}", order.ToStringShort(), status)); } }
private void MakeTrade(string name, CandleDataBidAsk quote) { var option = new Option { Symbol = name, TimeEnter = quote.timeClose, ExpirationMinutes = rand.Next(minStrikeMinutes, maxStrikeMinutes), OptionType = rand.Next(100) < 50 ? OptionType.Call : OptionType.Put, Volume = rand.Next(minVolume, maxVolume), }; option.PriceEnter = (decimal)(option.OptionType == OptionType.Call ? quote.closeAsk : quote.close); var deltaStrikeAbs = DalSpot.Instance.GetAbsValue(name, (decimal)rand.Next(minPoints, maxPoints)); var deltaSide = option.OptionType == OptionType.Call ? 1 : -1; option.PriceStrike = option.PriceEnter + deltaSide * deltaStrikeAbs; CalculatePremium(option); if (option.Premium == 0) { return; } activeOptions.Add(option); }
public void UpdateVolatility(CandleDataBidAsk candle) { deltas.Add(candle.close - candle.open); if (deltas.Count > maxSize) { deltas.RemoveAt(0); } }
public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var events = new List <string>(); if (string.IsNullOrEmpty(ticker)) { return(events); } CandleDataBidAsk quote = null; for (var i = 0; i < names.Length; i++) { if (names[i] != ticker) { continue; } quote = quotes[i]; break; } if (quote == null) { return(events); } // обновить свечку var candle = packer.UpdateCandle(quote); if (candle == null) { return(events); } // получить ордера List <MarketOrder> orders; GetMarketOrders(out orders, false); orders = orders.Where(o => o.Symbol == ticker).ToList(); if (orders.Count == 0 || isHistoryStartOff) { return(events); } // проверить стоп по уровням и по индивидуальным настрофкам сделок if (checkIndividualStop) { DoCheckIndividualStop(candle, orders, events); } // проверить стоп по заданному уровню if (StopLevel != 0) { DoCheckCommonStop(candle, orders, events); } return(events); }
private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle, MovArgRobotTag orderTag) { var volumeMultiplier = (100 + (MartingalePercent * (orderTag.MartinChainNum - 1))) / 100M; var volume = CalculateVolume(symbol, base.Leverage == null ? null : base.Leverage * volumeMultiplier, FixedVolume == null ? null : (int?)(FixedVolume.Value * volumeMultiplier)); if (volume == 0) { events.Add(string.Format("{0} {1} отменена - объем равен 0", dealSign > 0 ? "покупка" : "продажа", symbol)); return; } var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close; var point = pointCost[symbol]; var stopLoss = enterPrice - dealSign * (float)point * StopLossPoints; var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints; var order = new MarketOrder { AccountID = robotContext.AccountInfo.ID, Magic = Magic, Symbol = symbol, Volume = volume, Side = dealSign, StopLoss = stopLoss, TakeProfit = takeProfit, ExpertComment = ExpertComment, Comment = orderTag.MakeComment() }; var status = NewOrder(order, OrderType.Market, 0, 0); if (status != RequestStatus.OK) { events.Add(string.Format("Ошибка добавления ордера {0} {1}: {2}", dealSign > 0 ? "BUY" : "SELL", symbol, status)); } }
public void UpdateVolatility(CandleDataBidAsk candle) { var x = candle.close; if (prevValue == null) { prevValue = x; return; } var delta = x - prevValue.Value; var delta2 = delta * delta; prevValue = x; sum += delta2; items.Add(delta2); if (items.Count > maxLength) { sum -= items[0]; items.RemoveAt(0); volatility = Math.Sqrt(sum / maxLength); } }
private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle) { var volume = CalculateVolume(symbol, base.Leverage); if (volume == 0) { events.Add(string.Format("{0} {1} отменена - объем равен 0", dealSign > 0 ? "покупка" : "продажа", symbol)); return; } var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close; var point = pointCost[symbol]; var stopLoss = enterPrice - dealSign * (float)point * StopLossPoints; var takeProfit = enterPrice + dealSign * (float)point * TakeProfitPoints; var order = new MarketOrder { AccountID = robotContext.AccountInfo.ID, Magic = Magic, Symbol = symbol, Volume = volume, Side = dealSign, StopLoss = stopLoss, TakeProfit = takeProfit, // [A] не забывай уникальный комент ExpertComment = "Bollinger" }; var status = NewOrder(order, OrderType.Market, 0, 0); if (status != RequestStatus.OK) { events.Add(string.Format("Ошибка добавления ордера {0} {1}: {2}", dealSign > 0 ? "BUY" : "SELL", symbol, status)); } }
private void OpenOrder(int dealSign, string symbol, CandleDataBidAsk lastCandle) { var volume = CalculateVolume(symbol, base.Leverage); if (volume == 0) { events.Add(string.Format("{0} {1} отменена - объем равен 0 (L:{2:f3}, #{3})", dealSign > 0 ? "покупка" : "продажа", symbol, base.Leverage, robotContext.AccountInfo.ID)); return; } var enterPrice = dealSign > 0 ? lastCandle.closeAsk : lastCandle.close; var stopLoss = enterPrice - dealSign * DalSpot.Instance.GetAbsValue(symbol, (float)StopLossPoints); var takeProfit = enterPrice + dealSign * DalSpot.Instance.GetAbsValue(symbol, (float)TakeProfitPoints); var order = new MarketOrder { Symbol = symbol, // Инструмент по которому совершается сделка Volume = volume, // Объём средств, на который совершается сделка Side = dealSign, // Устанавливаем тип сделки - покупка или продажа StopLoss = stopLoss, // Устанавливаем величину Stop loss для открываемой сделки TakeProfit = takeProfit, // Устанавливаем величину Take profit для открываемой сделки ExpertComment = "RsiDiverRobot" // Комментарий по сделке, оставленный роботом }; var status = NewOrder(order, OrderType.Market, // исполнение по рыночной цене - можно везде выбирать такой вариант 0, 0); // последние 2 параметра для OrderType.Market не имеют значения if (status != RequestStatus.OK) { events.Add(string.Format("Ошибка добавления ордера ({0}): {1} (#{2} bal: {3})", order, status, robotContext.AccountInfo.ID, robotContext.AccountInfo.Balance.ToStringUniformMoneyFormat(true))); } }
public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { if (/*formulaResolver == null || */ packer == null) { return(null); } curTime = quotes[0].timeClose; // обновить табличку цен for (var i = 0; i < names.Length; i++) { if (lastBids.ContainsKey(names[i])) { lastBids[names[i]] = quotes[i].close; } else { lastBids.Add(names[i], quotes[i].close); } } CandleDataBidAsk curQuote = null; for (var i = 0; i < names.Length; i++) { if (names[i] == ticker) { curQuote = quotes[i]; break; } } // нет торгуемой котировки? if (curQuote == null) { return(null); } // обновить свечки var candle = packer.UpdateCandle(curQuote); if (candle == null) { return(null); } // закрылась полная свеча, проводим вычисления candles.Add(candle); // обновить очереди (для индекса, переменные вида usdjpy#15) if (lastBidLists.Count > 0) { foreach (var listTicker in lastBidLists) { double price; if (!lastBids.TryGetValue(listTicker.Key, out price)) { price = 0; } listTicker.Value.Add(price); } } // посчитать индексы foreach (var ind in IndexList) { ind.CalculateValue(tickerNames, candles, lastBidLists, /*curTime*/ candle.timeOpen, randomGener); } // если это период "разгона" конвейера if (isHistoryStartOff) { return(null); } // если "наращиваем" вход - ищем последнюю сделку и входим в ее направлении, // если закрытие "лучше" List <MarketOrder> orders; GetMarketOrders(out orders, true); var hints = new List <string>(); // следует "нарастить" объем var shouldEnterByChain = false; var lastOrderSide = 0; if (EnterChain == EnterChainCondition.НаЗакрытииЛучше && orders.Count > 0 && orders.Count < CountTrades) { var lastOrder = orders[orders.IndexOfMin(o => - o.TimeEnter.Ticks)]; lastOrderSide = lastOrder.Side; shouldEnterByChain = lastOrderSide > 0 ? (candle.close < lastOrder.PriceEnter) : (candle.close > lastOrder.PriceEnter); } // получить торговый сигнал string comment, expertComment; var dealSign = GetSignalSide(hints, curQuote.GetCloseQuote(), out comment, out expertComment); // сигнала нет if (dealSign == 0) { // ... но есть условие - "нарастить объем" if (shouldEnterByChain) { MakeOrder("", "повторный вход", lastOrderSide, curQuote.GetCloseQuote(), hints); } return(hints); } // от одной проекции не может быть открыто более 1 ордера // описание проекции сохраняем в спец. коменте // закрыть противонаправленные сделки var hasSameOrder = false; var hasSameDealType = false; foreach (var oldOrder in orders) { if (oldOrder.Side == dealSign) { hasSameDealType = true; } if (oldOrder.Side == dealSign && oldOrder.ExpertComment == expertComment) { hasSameOrder = true; continue; } // закрыть ордер другого знака if (oldOrder.Side == dealSign) { continue; } var rst = CloseMarketOrder(oldOrder.ID); if (rst != RequestStatus.OK) { hints.Add("Невозможно закрыть противоположный ордер " + oldOrder.ID); } } if (EnterChain == EnterChainCondition.НаНовойПроекции) { if (hasSameOrder) { return(hints); } MakeOrder(expertComment, comment, dealSign, curQuote.GetCloseQuote(), hints); return(hints); } if (EnterChain == EnterChainCondition.НаЗакрытииЛучше) { if (shouldEnterByChain || !hasSameDealType) { MakeOrder(expertComment, comment, dealSign, curQuote.GetCloseQuote(), hints); } return(hints); } return(hints); }
public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { CandleDataBidAsk quote = null; for (var i = 0; i < names.Length; i++) { if (names[i] == ticker) { quote = quotes[i]; break; } } var events = new List <string>(); if (quote == null) { return(events); } // сопроводить сделки, коли треба... var candle = packer.UpdateCandle(quote); if (candle == null) { return(events); } candles.Add(candle); // получить уровни ЗигЗага var pivots = ZigZag.GetPivots(candles, ZigZagPeriodPercent, ZigZagSourceType); if (pivots.Count < 3) { return(events); } // проверить последнюю вершину ЗЗ - отстоит ли она от предпоследней на ZigZagPeriodPercent //var lastValid = Math.Abs(100*(pivots[pivots.Count - 1].b - pivots[pivots.Count - 2].b)/ // pivots[pivots.Count - 2].b) // >= ZigZagPeriodPercent; //if (!lastValid && pivots.Count == 3) return events; //var screenPointB = lastValid ? pivots[pivots.Count - 1] : pivots[pivots.Count - 2]; //var screenPointA = lastValid ? pivots[pivots.Count - 2] : pivots[pivots.Count - 3]; var ptB = pivots[pivots.Count - 2]; var ptA = pivots[pivots.Count - 3]; // отметить вершину ЗЗ if (ShowFiboTurnBars && (markedZigZagPivots.Count == 0 || markedZigZagPivots[markedZigZagPivots.Count - 1] < ptA.a)) { markedZigZagPivots.Add(ptA.a); events.Add(new RobotHint(ticker, Graphics[0].b.ToString(), "З.З", "З.З", "z", ptA.b) { ColorFill = Color.Olive, Time = candles[ptA.a].timeOpen, RobotHintType = RobotHint.HintType.Коментарий }.ToString()); } // соблюдаются ли условия входа в рынок? // - уровень Фибо пройден N-м баром Фибо // - с клоза того бара рынок вырос (для продаж) var fiboLevel = ptA.b + (ptA.b - ptB.b) * fiboLevels[0]; //var potentialDealSide = screenPointA.b > screenPointB.b ? -1 : 1; var fiboBreachIndex = -1; float fiboBreachPrice = 0; foreach (var fiboMember in fiboBars) { var index = fiboMember + ptB.a - 1; if (index >= candles.Count) { break; } // свеча закрылась дальше расширения Фибо? var close = candles[index].close; var fiboReached = ptA.b > ptB.b ? close > fiboLevel : close < fiboLevel; if (!fiboReached) { continue; } fiboBreachIndex = index; fiboBreachPrice = close; break; } // считаем, сколько потенциально могло быть совершено входов // с момента пробития Фибо if (fiboBreachIndex > 0) { var countDeals = 1; // потенциальные сделки for (var i = fiboBreachIndex + 1; i < candles.Count - 1; i++) { if ((candles[i].close > fiboBreachPrice && ptA.b > ptB.b) || (candles[i].close < fiboBreachPrice && ptA.b < ptB.b)) { fiboBreachPrice = candles[i].close; countDeals++; } } var isEnterBetter = (candle.close > fiboBreachPrice && ptA.b > ptB.b) || (candle.close < fiboBreachPrice && ptA.b < ptB.b); if ((isEnterBetter || fiboBreachIndex == candles.Count - 1) && countDeals <= maxDealsInSeries) {// войти в рынок, закрыв противонаправленные сделки var dealSide = ptA.b > ptB.b ? -1 : 1; List <MarketOrder> orders; robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders); if (orders.Count > 0) { orders = orders.Where(o => o.Magic == Magic && o.Side != dealSide).ToList(); } foreach (var order in orders) { robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(), robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); } // открыть сделку OpenDeal(quote.GetCloseQuote(), dealSide); events.Add(new RobotHint(ticker, Graphics[0].b.ToString(), "Вход", "Вход по З.З", "e", dealSide < 0 ? quote.close : quote.closeAsk) { ColorFill = dealSide > 0 ? Color.Green : Color.Red, Time = quote.timeClose, RobotHintType = dealSide > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }.ToString()); } } return(events); }
public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { if (/*formulaResolver == null || */ packer == null) { return(null); } curTime = quotes[0].timeClose; // обновить табличку цен for (var i = 0; i < names.Length; i++) { if (lastBids.ContainsKey(names[i])) { lastBids[names[i]] = (double)quotes[i].close; } else { lastBids.Add(names[i], (double)quotes[i].close); } } CandleDataBidAsk curQuote = null; for (var i = 0; i < names.Length; i++) { if (names[i] == ticker) { curQuote = quotes[i]; break; } } if (curQuote == null) { return(null); // нет торгуемой котировки } // обновить свечки var candle = packer.UpdateCandle(curQuote); var hints = new List <RobotHint>(); if (candle != null) { // закрылась полная свеча, проводим вычисления candles.Add(candle); countCandles++; // обновить очереди (для индекса, переменные вида usdjpy#15) if (lastBidLists.Count > 0) { foreach (var listTicker in lastBidLists) { double price; if (!lastBids.TryGetValue(listTicker.Key, out price)) { price = 0; } listTicker.Value.Add(price); } } // посчитать индексы foreach (var ind in IndexList) { ind.CalculateValue(tickerNames, candles, lastBidLists, curTime, randomGener); } // если это период "разгона" конвейера if (isHistoryStartOff) { return(null); } var hintText = new StringBuilder(); List <MarketOrder> orders; #region ТОРГОВЫЙ МОДУЛЬ #region проверяем необходимость добавок к открытым позициям // проверяем состояние робота, если у нас нет позиций и робот торгует, возвращаем в исходное состояние GetMarketOrders(out orders); if (orders.Count == 0 && stopsOnPositions == StopPositionsState.ЗащитаУстановлена) { RobotTradeState = TradeState.ПоискТочекВхода; TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции закрылись"); TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState); stopsOnPositions = StopPositionsState.Незащищены; } var addPosFlag = 0; if (RobotTradeState == TradeState.НаращиваниеПокупок || RobotTradeState == TradeState.НаращиваниеПродаж) { var side = RobotTradeState == TradeState.НаращиваниеПокупок ? 1 : RobotTradeState == TradeState.НаращиваниеПродаж ? -1 : 0; if (AddPositionRules == AddPositionRule.НаБареЛучшейЦены) { //GetMarketOrders(out orders); if (orders.Count == 0) { addPosFlag = RobotTradeState == TradeState.НаращиваниеПокупок ? 1 : -1; } else { var averagePrice = GetAveragePrice(orders, side, curQuote.close, ProtectType.ПоЛучшейПозиции); if (side == 1 && curQuote.close < averagePrice) { addPosFlag = 1; } if (side == -1 && curQuote.close > averagePrice) { addPosFlag = -1; } // проверяю достижение актуального фибоуровня if (ActualFiboLevel != null) { // если условие выполнилось, то мы не достигли уровня для открытия позиций if ((addPosFlag == 1 && ActualFiboLevel < curQuote.close) || (addPosFlag == -1 && ActualFiboLevel > curQuote.close)) { addPosFlag = 0; } } } } } if (addPosFlag != 0) { GetMarketOrders(out orders); var ordersCount = orders.Count; // проверяем можно ли еще открыть позиции if (ordersCount < CountTrades) { // открыть позу в направлении знака дивера robotContext.SendNewOrderRequest( protectedContext.MakeProtectedContext(), RequestUniqueId.Next(), new MarketOrder { AccountID = robotContext.AccountInfo.ID, Magic = Magic, Symbol = ticker, Volume = GetTradeLot(), Side = addPosFlag, ExpertComment = "Atracotes MTS" }, OrderType.Market, 0, 0); if (ordersCount > 0) { hintText.AppendLine(string.Format("Добавка к {0}, текущая цена {1}", addPosFlag == 1 ? "покупкам" : "продажам", curQuote.close)); } else { hintText.AppendLine(string.Format("{0}, текущая цена {1}", addPosFlag == 1 ? "покупка" : "продажа", curQuote.close)); } TerminalLog.Instance.SaveRobotLog("Atracotes MTS: " + hintText); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), hintText.ToString(), addPosFlag > 0 ? "BUY" : "SELL", "e", curQuote.close) { Time = curQuote.timeClose, ColorFill = addPosFlag > 0 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = addPosFlag > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }); stopsOnPositions = StopPositionsState.Незащищены; if (ordersCount + 1 == CountTrades) { RobotTradeState = TradeState.НабранПолныйОбъем; TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState); } } } #endregion #region считаем зигзагу и уровни расширений var quotesList = candles.ToList(); var pivots = ZigZag.GetPivots(quotesList, ThresholdPercent, ZigZagSourceType); if (pivots.Count > 1) { // появились точки, рассчитываем уровни // проверяем процентный порог перешагнули или нет for (var i = pivots.Count; i > 1; i--) { var index0 = i - 1; var index1 = i - 2; var percent = Math.Abs(pivots[index0].b - pivots[index1].b) / pivots[index1].b * 100; if (percent > ThresholdPercent) { // процентный порог пройден, вычисляем уровни // теперь вычисляем уровни расширений var sign = pivots[index0].b > pivots[index1].b ? -1 : 1; var delta = Math.Abs(pivots[index0].b - pivots[index1].b); // очищаем все предыдущие уровни расширений как устаревшие // extLevels.Clear(); foreach (var level in fiboLevels) { var lev = new ExtensionsLevel { startIndex = countCandles > CandlesInIndexHistory ? countCandles - CandlesInIndexHistory + pivots[index0].a : pivots[index0].a, length = BarsCount, price = pivots[index0].b + delta * sign * (1 + level), delta = DalSpot.Instance.GetAbsValue(ticker, DeltaLevel), goalFrom = -sign }; extLevels.Add(lev); } break; } } } #endregion #region ищем дивергенции на индексах и курсе валютной пары var divergenceSign = 0; foreach (var ind in IndexList) { var commentOnDivergence = string.Empty; var indiDiverSign = ind.GetDivergenceSign(candles, out commentOnDivergence); if (indiDiverSign != 0) { if (hintText.Length != 0) { hintText.AppendLine(); } hintText.AppendLine("Дивергенция на индексе №" + indexList.IndexOf(ind)); hintText.AppendLine(commentOnDivergence); hintText.AppendLine("Переменные:"); // ReSharper disable PossibleNullReferenceException) foreach (var pair in ind.indexCalculator.varValues) // ReSharper restore PossibleNullReferenceException { hintText.AppendLine(string.Format("{1}{0}{2:f4}", (char)9, pair.Key, pair.Value)); } //hints.Add(new RobotHint(hintText.ToString(), //indiDiverSign > 0 ? "BUY" : "SELL", "e", curQuote.Bid) //{ // Time = candle.timeOpen, // ColorFill = indiDiverSign > 0 ? Color.Green : Color.Red, // ColorLine = Color.Black //}); } divergenceSign += indiDiverSign; } #endregion // теперь получен список дивергенций и уровни расширения. #region удаляем старые уровни for (var i = 0; i < extLevels.Count; i++) { // проверка актуальности уровня по свечам if (countCandles - 1 <= extLevels[i].startIndex + extLevels[i].length) { continue; } // уровень устарел, прошли максимальную длину свечей extLevels.RemoveAt(i); i--; } #endregion // проверяем достижение уровней расширения текущей ценой и если есть - входим в рынок divergenceSign = Math.Sign(divergenceSign); if (stopsOnPositions == StopPositionsState.Незащищены && divergenceSign != 0) { GetMarketOrders(out orders); stopsOnPositions = ProtectPositions(orders, -divergenceSign, curQuote.close); if (stopsOnPositions == StopPositionsState.ЗащитаУстановлена) { TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции защищены ны дивергенции"); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), "Защита позиций на дивергенции", "PROTECT", -divergenceSign > 0 ? "PB" : "PS", curQuote.close) { Time = curQuote.timeClose, ColorFill = Color.Blue, ColorLine = Color.Black, RobotHintType = RobotHint.HintType.Поджатие }); } } if (true || RobotTradeState == TradeState.НетПозиций || RobotTradeState == TradeState.ПоискТочекВхода || RobotTradeState == TradeState.НабранПолныйОбъем) { foreach (var level in extLevels) { // проверяем попадание цены на уровень //var prevCandle = candles.GetItemByIndex(candles.Count() - 2, true); if ((level.goalFrom == -1 && candles[candles.Count - 1].close >= (level.price - level.delta)) || (level.goalFrom == 1 && candles[candles.Count - 1].close <= (level.price + level.delta))) { GetMarketOrders(out orders); if (stopsOnPositions == StopPositionsState.Незащищены && divergenceSign == 0) { // надо поджать позиции stopsOnPositions = ProtectPositions(orders, -level.goalFrom, curQuote.close); if (stopsOnPositions == StopPositionsState.ЗащитаУстановлена) { TerminalLog.Instance.SaveRobotLog("Atracotes MTS: Позиции защищены по достижению уровня расширения"); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), "Защита позиций по достижению уровня расширения", "PROTECT", -level.goalFrom > 0 ? "PB" : "PS", curQuote.close) { Time = curQuote.timeClose, ColorFill = Color.Blue, ColorLine = Color.Black, RobotHintType = RobotHint.HintType.Поджатие }); } break; } if (divergenceSign == 0) { continue; } var ordersCount = orders.Count; // цена поднялась до целевого уровня var level1 = level; var ordersToClose = orders.FindAll(o => o.Side != divergenceSign); foreach (var order in ordersToClose) { robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(), robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); ordersCount--; } // закрыли ордера и теперь начинаем открывать позиции в обратную сторону // проверяем можно ли еще открыть позиции if (ordersCount >= CountTrades) { break; } // не добавляем позиции по новому диверу if (RobotTradeState == TradeState.НаращиваниеПокупок && divergenceSign == 1 || RobotTradeState == TradeState.НаращиваниеПродаж && divergenceSign == -1) { break; } // открыть позу в направлении знака дивера robotContext.SendNewOrderRequest( protectedContext.MakeProtectedContext(), RequestUniqueId.Next(), new MarketOrder { AccountID = robotContext.AccountInfo.ID, Magic = Magic, Symbol = ticker, Volume = GetTradeLot(), Side = divergenceSign, ExpertComment = "Atracotes MTS" }, OrderType.Market, 0, 0); hintText.AppendLine(string.Format("Пересечение уровня {0} {1}, текущая цена {2}", level1.price, level1.goalFrom == -1 ? "снизу" : "сверху", curQuote.close)); TerminalLog.Instance.SaveRobotLog("Atracotes MTS: " + hintText + ", " + (divergenceSign > 0 ? "покупка" : "продажа")); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), hintText.ToString(), divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.close) { Time = curQuote.timeClose, ColorFill = divergenceSign > 0 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = divergenceSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }); RobotTradeState = divergenceSign == 1 ? TradeState.НаращиваниеПокупок : TradeState.НаращиваниеПродаж; TerminalLog.Instance.SaveRobotLog("Atracotes MTS: RobotTradeState = " + RobotTradeState); stopsOnPositions = StopPositionsState.Незащищены; break; } } } #endregion } var retHint = hints.Select(hint => hint.ToString()).ToList(); return(retHint.Count > 0 ? retHint : null); }