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); }