public bool Step(out string[] names, out CandleDataBidAsk[] currentQuotes) { var lstNames = new List<string>(); var lstQuotes = new List<CandleDataBidAsk>(); var nextTimes = new List<DateTime>(); foreach (var pair in quotes) { var symbol = pair.Key; var quotesList = pair.Value; var index = currentIndex[symbol]; if (index < 0) continue; var quote = quotesList[index]; if (quote.timeClose == timeNow) { lstQuotes.Add(quote); lstNames.Add(pair.Key); index++; if (index >= quotesList.Count) index = -1; currentIndex[symbol] = index; } if (index >= 0) nextTimes.Add(quotesList[index].timeClose); } if (nextTimes.Count > 0) timeNow = nextTimes.Min(); names = lstNames.ToArray(); currentQuotes = lstQuotes.ToArray(); return names.Length > 0; }
public CandleDataBidAsk[] MakeCandles(QuoteData[] quotes, ref string[] names) { var candles = new CandleDataBidAsk[quotes.Length]; List <int> indexesLacked = null; for (var i = 0; i < quotes.Length; i++) { CandlePackerBidAsk packer; if (!packers.TryGetValue(names[i], out packer)) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgPackerForTickerMissed, 1000 * 60 * 5, "CandlePackerPool - не найден пакер для тикера {0}, всего {1} пакеров", names[i], packers.Count); if (indexesLacked == null) { indexesLacked = new List <int> { i } } ; else { indexesLacked.Add(i); } continue; } var candle = packer.UpdateCandle(quotes[i]); candles[i] = candle; } if (indexesLacked != null) { if (indexesLacked.Count == quotes.Length) { names = new string[0]; return(new CandleDataBidAsk[0]); } names = names.Where((n, i) => !indexesLacked.Contains(i)).ToArray(); candles = candles.Where((n, i) => !indexesLacked.Contains(i)).ToArray(); } return(candles); }
public CandleDataBidAsk[] MakeCandles(QuoteData[] quotes, ref string[] names) { var candles = new CandleDataBidAsk[quotes.Length]; List<int> indexesLacked = null; for (var i = 0; i < quotes.Length; i++) { CandlePackerBidAsk packer; if (!packers.TryGetValue(names[i], out packer)) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgPackerForTickerMissed, 1000 * 60 * 5, "CandlePackerPool - не найден пакер для тикера {0}, всего {1} пакеров", names[i], packers.Count); if (indexesLacked == null) indexesLacked = new List<int> {i}; else indexesLacked.Add(i); continue; } var candle = packer.UpdateCandle(quotes[i]); candles[i] = candle; } if (indexesLacked != null) { if (indexesLacked.Count == quotes.Length) { names = new string[0]; return new CandleDataBidAsk[0]; } names = names.Where((n, i) => !indexesLacked.Contains(i)).ToArray(); candles = candles.Where((n, i) => !indexesLacked.Contains(i)).ToArray(); } return candles; }
public void MakeCandles(List<Cortege2<string, QuoteData>> quotes, out string[] names, out CandleDataBidAsk[] candles) { var namesList = new List<string>(); var candlesList = new List<CandleDataBidAsk>(); foreach (var quote in quotes) { CandlePackerBidAsk packer; if (!packers.TryGetValue(quote.a, out packer)) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgPackerForTickerMissed, 1000 * 60 * 5, "CandlePackerPool - не найден пакер для тикера {0}, всего {1} пакеров", quote.a, packers.Count); continue; } var candle = packer.UpdateCandle(quote.b); namesList.Add(quote.a); candlesList.Add(candle); } names = namesList.ToArray(); candles = candlesList.ToArray(); }
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); } }
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>(); #region получить candle из quote if (string.IsNullOrEmpty(ticker)) return events; var tickerIndex = -1; for (var i = 0; i < names.Length; i++) if (names[i] == ticker) { tickerIndex = i; break; } if (tickerIndex < 0) return events; var quote = quotes[tickerIndex]; var candle = packer.UpdateCandle(quote); if (candle == null) return events; #endregion extremumRangeQueue.Add(candle); if (extremumRangeQueue.Length != extremumRangeQueue.MaxQueueLength) return events; // Если очередь заполнена полностью, значит можно проверять её среднее значение на локальный экстремум CheckExtremum(extremumRangeQueue); // Все ли 4 экстремума сейчас имеются для анализа if (extremumQueue.Length != extremumQueue.MaxQueueLength) return events; var extrArray = extremumQueue.ToArray(); // Теперь можно проверить - чередуются ли экстремумы. var boofSign = !extrArray[0].b; foreach (var extremum in extrArray) { if (extremum.b == boofSign) return events; // Это значит что два максимума или два минимума идут друг за другом boofSign = !boofSign; } // Экстремумы чередуются друг за другом. // Теперь проверяем, больше ли по модулю "а", чем "b", "с" и "d" и close. var priceA = extrArray[0].a; var currentSide = extrArray[0].b ? 1 : -1; for (var i = 1; i < extrArray.Length; i++) { if (currentSide != Math.Sign(priceA - extrArray[i].a)) return events; } if (currentSide != Math.Sign(priceA - candle.close)) return events; // соотнесение "плеч" var ab = Math.Abs(extrArray[0].a - extrArray[1].a); var bc = Math.Abs(extrArray[1].a - extrArray[2].a); var cd = Math.Abs(extrArray[2].a - extrArray[3].a); var dClose = Math.Abs(extrArray[3].a - candle.close); var bcCd = cd == 0 ? float.MaxValue : bc / cd; if (bcCd < MinShoulder || bcCd > MaxShoulder) return events; if (ab <= bc || ab <= cd || ab <= dClose) return events; // Первый экстремум является большим по модулю, чем остальные - можно совершать сделку if (!isHistoryStartOff) // линии скользящих средних пересеклись причём не на истории. Значит пора торговать!!! { // коментарий var extrNames = new [] {"A", "B", "C", "D"}; var nameIndex = 0; // ReSharper disable LoopCanBeConvertedToQuery foreach (var extr in extrArray) // ReSharper restore LoopCanBeConvertedToQuery { events.Add(new RobotHint(ticker, Graphics[0].b.ToString(), extrNames[nameIndex], extrNames[nameIndex], extrNames[nameIndex++], extr.a) { Time = extr.c, RobotHintType = RobotHint.HintType.Линия //extr.b ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }.ToString()); } // закрыть противонаправленные, если автозакрытие включено пользователем if (CloseDeal) { List<MarketOrder> orders; robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders); foreach ( var order in orders.Where(o => o.Side != currentSide && o.Magic == Magic && o.Symbol == ticker).ToList()) robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(), robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); } OpenDeal(candle.close, currentSide); } return events; }
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); }
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)); }
/// <summary> /// Вызывается с приходом новой котировки /// </summary> public abstract List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff);
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { throw new NotImplementedException(); }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { events = new List<string>(); if (packers == null) return events; for (var i = 0; i < quotes.Length; i++) { CandlePacker packer; if (!packers.TryGetValue(names[i], out packer)) continue; var candle = packer.UpdateCandle(quotes[i]); if (candle == null) continue; var candlesList = lastCandles[names[i]]; candlesList.Add(candle); if (candlesList.Count > patternLength) candlesList.RemoveAt(0); if (candlesList.Count < patternLength) continue; if (isHistoryStartOff) continue; List<PendingOrder> orders; GetPendingOrders(out orders); orders = orders.Where(o => o.Symbol == names[i]).ToList(); PlaceNewOrder(candlesList, names[i], orders); CheckOrders(candlesList, names[i]); } return events; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var events = new List<string>(); if (tickers.Length == 0 || isHistoryStartOff) return events; if (lastTrade == null) { lastTrade = new ThreadSafeTimeStamp(); lastTrade.Touch(); } // секунд с последнего трейда... var timeSince = (DateTime.Now - lastTrade.GetLastHit()).TotalSeconds; if (timeSince < tradeIntervalSec) return events; lastTrade.Touch(); // затребовать все сделки со своим magic List<MarketOrder> orders; GetMarketOrders(out orders, true); var sides = tickers.ToDictionary(t => t, t => 1); if (orders != null) foreach (var order in orders) { if (sides.ContainsKey(order.Symbol)) sides[order.Symbol] = -order.Side; // закрыть старую сделку CloseMarketOrder(order.ID); } // открыть новые сделки foreach (var tickerSide in sides) { var newOrd = new MarketOrder { Symbol = tickerSide.Key, Side = tickerSide.Value, AccountID = robotContext.AccountInfo.ID, Magic = Magic, Volume = FixedVolume, ExpertComment = "SimpleTradeMachine" }; var rst = robotContext.SendNewOrderRequest(protectedContext.MakeProtectedContext(), RequestUniqueId.Next(), newOrd, OrderType.Market, 0, 0); } return events; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { if (isHistoryStartOff) return new List<string>(); if (!string.IsNullOrEmpty(errorMessage)) { var evts = new List<string> { errorMessage }; errorMessage = string.Empty; return evts; } var evsList = spamMessage.GetMessages().Select(m => m.b).ToList(); if (TradeSharpAccount > 0) { var account = robotContext.AccountInfo; if (account != null && account.ID != TradeSharpAccount) { spamMessage.PutMessage(SpamMessage.MessageCategory.AccountMismatch, "Открыт счет #" + account.ID + ", ожидается счет #" + TradeSharpAccount); return evsList; } } if (!initMessageWasSent) { // сообщить - привет, я торговый робот, делаю то-то и то-то initMessageWasSent = true; evsList.Add(string.Format("MT4 робот, слушает порт {0}, отправляет на порт {1}", portOwn, portMt4)); } // проверить время с последней проверки ордеров var lastTime = timeSinceUpdate.GetLastHit(); var nowTime = DateTime.Now; var milsPassed = (nowTime - lastTime).TotalMilliseconds; if (milsPassed < MilsBetweenChecks) return evsList; timeSinceUpdate.Touch(); // транслировать сделки в МТ4 if (Mode == RobotMode.УправлятьМТ4) { List<MarketOrder> orders; // проверить имеющиеся ордера GetMarketOrders(out orders, false); TranslateOrdersToMt4(orders); return evsList; } // копировать сделки из МТ4 if (Mode == RobotMode.КопироватьОрдераМТ4) { CopyOrdersFromMt4(evsList); return evsList; } return evsList; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var evtList = new List<string>(); var deltaMils = lastCheckTime.HasValue ? (DateTime.Now - lastCheckTime.Value).TotalMilliseconds : int.MaxValue; if (deltaMils >= IntervalCheckMils) { lastState = CheckDeposit(); lastCheckTime = DateTime.Now; } if (lastState == StateCode.OK) return evtList; // осуществить стопаут? var countStopout = new Cortege2<int, int>(0, 0); if (lastState == StateCode.Stopout) countStopout = PerformStopout(); // разослать сообщение PerformDelivery(countStopout); if (countStopout.a > 0) { Logger.InfoFormat("DrawDownStopoutChecker: закрыто {0} сделок из {1}", countStopout.a, countStopout.a + countStopout.b); } return evtList; }
public void OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryTakeOff) { var realOrModelTime = quotes[0].timeClose; foreach (var robot in listRobots) { var robotMessages = robot.OnQuotesReceived(names, quotes, isHistoryTakeOff); if (robotMessages != null && robotMessages.Count > 0 && onRobotMessage != null) onRobotMessage(robot, realOrModelTime, robotMessages); } }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var events = new List<string>(); if (isHistoryStartOff) return events; // сформировать свечи for (var i = 0; i < names.Length; i++) { CandlePacker packer; var ticker = names[i]; if (!packers.TryGetValue(ticker, out packer)) continue; var candle = packer.UpdateCandle(quotes[i]); if (candle == null) continue; // проверить условия для входа в рынок string comment; var side = CheckTradeCondition(candle, ticker, out comment); if (side == 0) continue; // закрыть сделки противоположного знака if (CloseOpposite) { List<MarketOrder> orders; GetMarketOrders(out orders, true); foreach (var order in orders.Where(o => o.Symbol == ticker && o.Side != side)) CloseMarketOrder(order.ID); } // создать ордер OpenDeal(quotes[i].close, side, ticker, comment); } return events; }
/// <summary> /// дать роботам котировки в работу /// </summary> public void OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryQuotes) { if (context == null) return; try { context.OnQuotesReceived(names, quotes, isHistoryQuotes); } catch (Exception ex) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgQuoteRecvError, 1000 * 60 * 5, "Ошибка в OnQuotesReceived (счет {0}): {1}", AccountId, ex); } }
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) { 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; }
/// <summary> /// Этот метод вызывается каждый раз при новых данных котировки. Метод реализует основную логику торговли робота. /// Здесь принимается решение о открытии нового ордера и закрытии открытых сделок /// Совершение сделок будет поисходить на закрытии свечи. При закрытии свечки метод UpdateCandle объекта packer вернёт эту свечу, иначе Null. /// В случае если свеча закрылась, тогда методом CalculateMA расчитываем значение скользящей средней для текущей котировки. /// Если быстрая и медленная скользящие седние пересекаются, а так же если текущая котировка не является "исторической", тогда можно /// принимать решение об открытии новой сделки. /// </summary> /// <param name="quotes"></param> /// <param name="isHistoryStartOff">Флаг, показывающий, является текущая котировка взятой из истории, или это значение катировки на текущий момент на рынке</param> /// <param name="names"></param> public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { events = lastMessages.ToList(); lastMessages.Clear(); #region Получение текущей свечи // Массивы "names" и "quotes" всегда содержат одинаковое количество элементов (по одному). Фактически это пары ключ/значение if (string.IsNullOrEmpty(ticker)) { Logger.ErrorFormat("Название текущего инструмента (ticker) для робота {0} задано не корректно", TypeName); return events; } var tickerIndex = -1; for (var i = 0; i < names.Length; i++) if (names[i] == ticker) { tickerIndex = i; break; } if (tickerIndex < 0) { //Logger.InfoFormat("Не удалось получить котировку для робота {0}", TypeName); return events; } //Выбираем из всего массива текущих катировкок, катировку для того инструмента, которым торгует робот var quote = quotes[tickerIndex]; var candle = packer.UpdateCandle(quote); #endregion // Если свеча закрылась, тогда candle != null (сделки соверши) if (candle == null) return events; queueSlow.Add(candle.close); queueFast.Add(candle.close); if (queueSlow.Length < queueSlow.MaxQueueLength) return events; CandlesAnalysisAndTrade(candle, isHistoryStartOff); return events; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var hints = new List<RobotHint>(); if (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) { // закрылась полная свеча, проводим вычисления candles.Add(candle); countCandles++; } List<MarketOrder> orders = null; if (ProtectPosType != ProtectType.НеЗащищать) { GetMarketOrders(out orders); if (orders.Count > 0) { if (unconditionalProtectPips > 0) CheckUnconditionalProtect(orders, curQuote.GetCloseQuote(), hints); // проверить множество индексов на нескольких ТФ - условия защиты CheckProtectTrigger(orders, curQuote.GetCloseQuote(), hints, isHistoryStartOff, candle); // проверить собственно защиту CheckProtect(orders, curQuote.GetCloseQuote(), hints); } } if (CalcDealChainStat) { if (orders == null) GetMarketOrders(out orders); UpdateChainStatistics(orders); } if (candle != null) { // закрылась полная свеча, проводим вычисления // обновить очереди (для индекса, переменные вида 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 DiversToEnter) ind.CalculateValue(tickerNames, candles, lastBidLists, curTime, randomGener); // индексы для фильтров foreach (var filter in filters) filter.indexCalculator.CalculateValue(tickerNames, candles, lastBidLists, curTime, randomGener); // если это период "разгона" конвейера if (isHistoryStartOff) return null; // получить суммарный знак диверов на текущей свече var divergenceSign = 0; var commentBuilder = new StringBuilder(); foreach (var ind in DiversToEnter) { string commentOnDivergence; var indiDiverSign = ind.GetDivergenceSign(candles, out commentOnDivergence); divergenceSign += indiDiverSign; if (!string.IsNullOrEmpty(commentOnDivergence)) commentBuilder.AppendLine(commentOnDivergence); } divergenceSign = Math.Sign(divergenceSign); // есть дивер? if (divergenceSign != 0) TryEnterTheMarket(divergenceSign, curQuote.GetCloseQuote(), hints, commentBuilder.ToString()); } var retHint = hints.Select(hint => hint.ToString()).ToList(); return retHint.Count > 0 ? retHint : null; }
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; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { events = lastMessages.ToList(); lastMessages.Clear(); if (packers == null) return events; for (var i = 0; i < quotes.Length; i++) { CandlePacker packer; if (!packers.TryGetValue(names[i], out packer)) continue; var candle = packer.UpdateCandle(quotes[i]); if (candle == null) continue; var enterSign = CheckEnterCondition(names[i], candle.close); if (enterSign == 0) continue; if (isHistoryStartOff) continue; if (CloseOpposite) CloseCounterOrders(enterSign, names[i]); OpenOrder(enterSign, names[i], quotes[i]); } return events; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { if (isProcessing) return new List<string>(); try { isProcessing = true; return ProcessQuotes(names, quotes, isHistoryStartOff); } finally { isProcessing = false; } }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { events = new List<string>(); if (packers == null) return events; for (var i = 0; i < quotes.Length; i++) { CandlePacker packer; if (!packers.TryGetValue(names[i], out packer)) continue; var candle = packer.UpdateCandle(quotes[i]); if (candle == null) continue; var enterSign = CheckEnterCondition(names[i], candle); if (isHistoryStartOff || enterSign == 0) continue; // если есть открытые сделки против текущего направления - закрыть их if (CloseOpposite) CloseCounterOrders(enterSign, names[i]); // открыть сделку OpenOrder(enterSign, names[i], quotes[i]); } return events; }
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; }
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) { var messages = new List<string>(); var nowTime = quotes[0].timeClose; var minutesFromLastDeal = timeOfLastDeal.HasValue ? (nowTime - timeOfLastDeal.Value).TotalMinutes : int.MaxValue; for (var i = 0; i < names.Length; i++) { if (!tickers.Contains(names[i])) continue; tickerVolatility[names[i]].UpdateVolatility(quotes[i]); } if (minutesFromLastDeal >= intervalBetweenTradesMinutes) { for (var i = 0; i < names.Length; i++) { if (!tickers.Contains(names[i])) continue; MakeTrade(names[i], quotes[i]); } timeOfLastDeal = nowTime; } CheckOptions(names, quotes); return messages; }
public override List<string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { if (packers.Count == 0) return new List<string>(); if (isHistoryStartOff) return new List<string>(); var time = quotes[0].timeClose; // подготовить события входа for (var i = 0; i < names.Length; i++) { var ticker = names[i]; foreach (var packer in packers) { if (packer.Key.a != ticker) continue; var candle = packer.Value.UpdateCandle(quotes[i]); if (candle == null) continue; // закрыть сделку / сделки? if (CheckDice(probClose)) TryCloseDeal(ticker); // войти в рынок или закрыть сделку или забить? if (!CheckDice(probTrade)) continue; // в рабочий час...? var isWorkingHour = workHours.Any(hr => hr.a >= time.Hour && hr.b <= time.Hour); if (!isWorkingHour && !CheckDice(probNonWorkTrade)) continue; List<MarketOrder> orders; GetMarketOrders(out orders, true); orders = orders.Where(o => o.Symbol == ticker).ToList(); // повторный вход? if (orders.Count > 0) if (!CheckDice(probSecondOrder)) continue; var side = CheckDice(50) ? 1 : -1; // противоположный вход? if (orders.Count > 0 && orders[orders.Count - 1].Side != side) if (!CheckDice(probOpposOrder)) continue; // время входа var timeEnter = time; if (!CheckDice(probStrictOnCandleCloseOrder)) { var deltaMinutes = rnd.Next((int) (packer.Key.b.Intervals.Sum()/1.5)); timeEnter = timeEnter.AddMinutes(deltaMinutes); } plannedOrders.Add(new Cortege3<string, int, DateTime>(ticker, side, timeEnter)); } } // если есть события для входа - войти в рынок for (var i = 0; i < plannedOrders.Count; i++) { if (time > plannedOrders[i].c) continue; OpenOrder(plannedOrders[i]); plannedOrders.RemoveAt(i); i--; } return null; }
private void CheckOptions(string[] names, CandleDataBidAsk[] quotes) { var nowTime = quotes.Max(q => q.timeClose); for (var i = 0; i < activeOptions.Count; i++) { var option = activeOptions[i]; // опцион проэкспарился if (option.ExpireTime < nowTime) { activeOptions.RemoveAt(i); i--; histOptions.Add(option); continue; } // опцион сработал var nameIndex = names.IndexOf(option.Symbol); if (nameIndex < 0) continue; var quote = quotes[nameIndex]; if ((option.OptionType == OptionType.Call && quote.high >= (float) option.PriceStrike) || (option.OptionType == OptionType.Put && quote.low <= (float) option.PriceStrike)) { option.Profit = option.Volume * (option.PriceStrike - option.PriceEnter) * (int) option.OptionType; activeOptions.RemoveAt(i); i--; histOptions.Add(option); } } }