/// <summary> /// распаковать если необходимо /// </summary> public List <QuoteData> GetQuotes() { if (!packed) { return(unpacked); } var result = new List <QuoteData>(count); var unpackedStream = method == PackedMethod.FastGZip ? UnpackBytesGZip(quoteStream) : CompressionHelper.DecompressBytes(quoteStream); const int quoteSz = SizeofTime + SizeofPrice + SizeofPrice; var size = count * quoteSz; for (var offset = 0; offset < size; offset += quoteSz) { var q = new QuoteData { time = new DateTime(BitConverter.ToInt64(unpackedStream, offset)), ask = BitConverter.ToSingle(unpackedStream, offset + SizeofTime), bid = BitConverter.ToSingle(unpackedStream, offset + SizeofTime + SizeofPrice) }; result.Add(q); } return(result); }
public bool IsValid(string symbol, QuoteData quote) { var logMsgCode = symbol.GetHashCode(); var price = (quote.ask + quote.bid) * 0.5f; if (price < MinValue) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, logMsgCode, 1000 * 60 * 120, "Котировка {0} ({1}) меньше допустимого значения {2}", symbol, price, MinValue); return false; } float val; if (!quoteByTicker.TryGetValue(symbol, out val)) return true; var delta = Math.Abs(price - val) / val; if (delta > MaxDeltaRel) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, logMsgCode, 1000 * 60 * 120, "Котировка {0} ({1}): последнее сохраненное значение {2}", symbol, price, val); return false; } return true; }
/// <summary> /// Читает котировки из файла. Строки вида: EURUSD 1.371825 09.12.2013 16:09:35 /// </summary> private static Dictionary<string, QuoteData> ReadFromFile() { var result = new Dictionary<string, QuoteData>(); var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DAL\\last_quotes.txt"); string[] lines; try { lines = File.ReadAllLines(filePath); } catch (Exception ex) { Logger.Error("ReadFromFile", ex); return result; } if (lines.Length == 0) return result; foreach (var quoteItemes in lines.Select(line => line.Split('\t'))) { float bid; if (Single.TryParse(quoteItemes[1].Trim(), out bid)) continue; var ticker = quoteItemes[0].Trim(); if (!result.Keys.Contains(ticker)) continue; var quote = new QuoteData(bid, DalSpot.Instance.GetAskPriceWithDefaultSpread(ticker, bid), DateTime.Now); result.Add(ticker, quote); } return result; }
public bool PricesAreSame(QuoteData q) { if (q == null) { return(false); } return(bid == q.bid && ask == q.ask); }
public static QuoteData ParseQuoteStringNewFormat(string line, DateTime date) { // 0000 1.3570 1.3572 var parts = line.Split(' '); if (parts.Length != 3) return null; var quote = new QuoteData(); var timeNum = int.Parse(parts[0]); int hour = timeNum / 100; int minute = timeNum - 100 * hour; quote.time = date.AddMinutes(minute + hour * 60); quote.bid = parts[1].ToFloatUniform(); quote.ask = parts[2].ToFloatUniform(); return quote; }
public static QuoteData ParseQuoteStringNewFormat(string line, DateTime date) { // 0000 1.3570 1.3572 var parts = line.Split(' '); if (parts.Length != 3) { return(null); } var quote = new QuoteData(); var timeNum = int.Parse(parts[0]); int hour = timeNum / 100; int minute = timeNum - 100 * hour; quote.time = date.AddMinutes(minute + hour * 60); quote.bid = parts[1].ToFloatUniform(); quote.ask = parts[2].ToFloatUniform(); return(quote); }
/// <summary> /// Расчитать объем сделки в валюте депозита /// </summary> public void CalculateDealVolumeInDepoCurrency(MarketOrder deal, QuoteData dealQuote, string depoCurrency, QuoteArchive arc, DateTime date) { var volumeInCounter = deal.Volume * dealQuote.GetPrice(QuoteType.NonSpecified); // перевести из контрвалюты в валюту депо bool inverse, pairsAreEqual; var smb = DalSpot.Instance.FindSymbol(deal.Symbol, false, depoCurrency, out inverse, out pairsAreEqual); if (pairsAreEqual) { deal.VolumeInDepoCurrency = volumeInCounter; return; } if (string.IsNullOrEmpty(smb)) return; var quoteCtDepo = arc.GetQuoteOnDateSeq(smb, date); if (quoteCtDepo == null) return; var priceCtDepo = quoteCtDepo.GetPrice(QuoteType.NonSpecified); if (priceCtDepo == 0) return; deal.VolumeInDepoCurrency = inverse ? volumeInCounter / priceCtDepo : volumeInCounter * priceCtDepo; }
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; }
/// <summary> /// распаковать если необходимо /// </summary> public List<QuoteData> GetQuotes() { if (!packed) return unpacked; var result = new List<QuoteData>(count); var unpackedStream = method == PackedMethod.FastGZip ? UnpackBytesGZip(quoteStream) : CompressionHelper.DecompressBytes(quoteStream); const int quoteSz = SizeofTime + SizeofPrice + SizeofPrice; var size = count * quoteSz; for (var offset = 0; offset < size; offset += quoteSz) { var q = new QuoteData { time = new DateTime(BitConverter.ToInt64(unpackedStream, offset)), ask = BitConverter.ToSingle(unpackedStream, offset + SizeofTime), bid = BitConverter.ToSingle(unpackedStream, offset + SizeofTime + SizeofPrice) }; result.Add(q); } return result; }
private int CheckProtectByDivers(QuoteData curQuote, bool isHistoryStartOff, StringBuilder diverKinds) { if (diversToProtect.Count == 0) return 0; var diverSign = 0; foreach (var diverSet in diversToProtect) { var candle = packerDiverProtect[diverSet].UpdateCandle(curQuote.bid, curQuote.time); if (candle == null) continue; var candleQueue = candles4Protect[diverSet]; candleQueue.Add(candle); // сформировалась новая свеча - проверить дивергенции с индексами); foreach (var diver in diverSet.IndexList) { diver.CalculateValue(tickerNames, candleQueue, lastBidLists, curTime, randomGener); if (isHistoryStartOff) continue; string divergenceText; var indiDiverSign = diver.GetDivergenceSign(candleQueue, out divergenceText); //if (!string.IsNullOrEmpty(divergenceText)) // Logger.InfoFormat("CheckProtectTrigger[{0}]: {1}", // BarSettingsStorage.Instance.GetBarSettingsFriendlyName(diverSet.Timeframe), // divergenceText); diverSign += indiDiverSign; if (indiDiverSign != 0 && ShowProtectEventMarker) { diverKinds.Append(BarSettingsStorage.Instance.GetBarSettingsFriendlyName(diverSet.timeframe)); diverKinds.Append(indiDiverSign > 0 ? ":Б " : ":М "); } } } return -diverSign; }
/// <param name="newQuotes">обновленные котировки</param> /// <returns>нужна перерисовка</returns> public bool ProcessQuotes(QuoteData[] newQuotes) { if (newQuotes == null) return false; // выдерживание минимального интервала между обновлениями var deltaMills = (DateTime.Now - timeOfLastUpdate).TotalMilliseconds; if (deltaMills < MinIntervalBetweenUpdates) return false; timeOfLastUpdate = DateTime.Now; // доукомплектовать свечки if (newQuotes.Length == 0) return false; if (candlePacker == null) return false; var candles = chart.StockSeries.Data.Candles; // обновленная свечка и список добавленных свечек CandleData updatedCandle = null; var newCandles = new List<CandleData>(); foreach (var q in newQuotes) { if (q.bid == 0 || q.ask == 0) { Logger.ErrorFormat("Nil quote: {0} at {1}", Symbol, q.time, q.bid == 0 && q.ask == 0 ? " both" : ""); continue; } var candle = candlePacker.UpdateCandle(q.bid, q.time); if (candle == null) continue; // либо завершена старая свечка, либо слеплена новая if (candles.Count > 0) if (candles[candles.Count - 1].timeOpen == candle.timeOpen) { candles[candles.Count - 1] = new CandleData(candle); // заменить обновленную // запомнить обновленную свечку updatedCandle = candles[candles.Count - 1]; continue; } candles.Add(new CandleData(candle)); // запомнить добавленную свечку newCandles.Add(candles[candles.Count - 1]); } // если сформировалась, но не закончена новая свеча... if (candlePacker.CurrentCandle != null) { var candleUpdated = false; if (candles.Count > 0) if (candles[candles.Count - 1].timeOpen == candlePacker.CurrentCandle.timeOpen) { candles[candles.Count - 1] = new CandleData(candlePacker.CurrentCandle); // заменить обновленную // запомнить обновленную свечку updatedCandle = candles[candles.Count - 1]; candleUpdated = true; } if (!candleUpdated) { candles.Add(new CandleData(candlePacker.CurrentCandle)); // запомнить добавленную свечку newCandles.Add(candles[candles.Count - 1]); } } // обновить границу интервала if (newQuotes.Length > 0) chart.EndTime = newQuotes[newQuotes.Length - 1].time; // обработать котировки в индикаторах ProcessQuotesByIndicators(updatedCandle, newCandles); if (chart.StockSeries.ShowLastQuote) { float? price = newCandles.Count > 0 ? newCandles[newCandles.Count - 1].close : updatedCandle != null ? (float?)updatedCandle.close : null; if (price.HasValue) chart.Panes.StockPane.YAxis.CurrentPrice = price; } if (chart.StockSeries.AutoScroll) chart.ScrollToEnd(); return true; }
private void MakeOrder(string expertComment, string comment, int dealSign, QuoteData curQuote, List<string> hints) { var tradeVolume = GetEnterVolume(); if (tradeVolume == 0) { hints.Add(comment + ", объем входа 0"); return; } var order = new MarketOrder { ExpertComment = expertComment, // описание проекции Comment = comment, Symbol = ticker, Volume = tradeVolume, Side = dealSign, //StopLoss = }; // запрос входа на сервере var status = NewOrder(order, OrderType.Market, (decimal) (dealSign > 0 ? curQuote.ask : curQuote.bid), 0); if (status != RequestStatus.OK) hints.Add(comment + ", вход неуспешен: " + status); }
private void UpdateQuote(News[] news, QuoteData[] quotes) { if (!startupFinished) return; if (!updateCompleted.WaitOne(UpdateQuoteTimeout)) return; updateCompleted.Reset(); try { // график обрабатывает новые котировки и перерисовывается var flagRedrawQuotes = false; var flagRedrawNews = false; if (quotes != null) flagRedrawQuotes = chart.ProcessQuotes(quotes); if (news != null) flagRedrawNews = chart.ProcessNews(news); if (flagRedrawNews || flagRedrawQuotes) // перерисовать { chart.RedrawChartSafe(); } } finally { updateCompleted.Set(); } }
/// <summary> /// асинхронно обновить график /// </summary> public void UpdateBaseNewsAsynch(News[] news, QuoteData[] quotes) { if (!updateCompleted.WaitOne(WaitFormUpdateInterval)) return; var del = new UpdateQuoteDel(UpdateQuote); try { BeginInvoke(del, (object)news, (object)quotes); } catch (InvalidOperationException) { } }
private AccountStatistics BuildEquityCurve( List<MarketOrder> orders, List<MarketOrder> openOrders, List<BalanceChange> balanceChanges) { var stat = new AccountStatistics { Statistics = new PerformerStat { DealsCount = orders.Count + openOrders.Count, }, DealsStillOpened = openOrders.Count, listEquity = new List<EquityOnTime>() }; if (worker.CancellationPending) return stat; SetProgressValueSafe(40, Localizer.GetString("MessageActualizingQuoteHistory") + "..."); if (balanceChanges.Count == 0) { MessageBox.Show(Localizer.GetString("MessageNoTransfersData")); return stat; } var curxDepo = AccountStatus.Instance.AccountData.Currency; // запросить котировки, если стоит соотв. флаг var quotesDic = UpdateQuotesForStats(orders, openOrders, curxDepo); // построить кривую эквити // отсчет от первого движения на счете либо от стартовой даты balanceChanges = balanceChanges.OrderBy(bc => bc.ValueDate).ToList(); var startDate = cbStartFrom.Checked ? dpStart.Value : balanceChanges[0].ValueDate; // начальный баланс var initialBalance = !cbStartFrom.Checked ? balanceChanges[0].SignedAmountDepo : balanceChanges.Where(bc => bc.ValueDate <= startDate).Sum(bc => bc.SignedAmountDepo); // движения от начального баланса с заданным интервалом дискретизации var dueBalances = balanceChanges.Where(bc => bc.ValueDate > startDate).ToList(); var dueDeals = orders.Union(openOrders).OrderBy(o => o.TimeEnter).ToList(); var endDate = DateTime.Now; var balance = initialBalance; var cursor = new BacktestTickerCursor(); var path = ExecutablePath.ExecPath + TerminalEnvironment.QuoteCacheFolder; if (!cursor.SetupCursor(path, quotesDic.Keys.ToList(), quotesDic.Min(t => t.Value))) { MessageBox.Show(Localizer.GetString("MessageErrorGettingQuotesFromFiles")); return stat; } var currentQuotes = new Dictionary<string, QuoteData>(); var timeframeMinutes = Timeframe; SetProgressValueSafe(60, Localizer.GetString("MessageCalculationInProcess") + "..."); try { for (var time = startDate; time < endDate; time = time.AddMinutes(timeframeMinutes)) { if (worker.CancellationPending) return stat; // получить баланс на дату for (var i = 0; i < dueBalances.Count; i++) { if (dueBalances[i].ValueDate > time) break; balance += dueBalances[i].SignedAmountDepo; dueBalances.RemoveAt(i); i--; } var equity = balance; // получить текущие котировки var candles = cursor.MoveToTime(time); foreach (var candle in candles) { var quote = new QuoteData(candle.Value.open, DalSpot.Instance.GetAskPriceWithDefaultSpread(candle.Key, candle.Value.open), candle.Value.timeOpen); if (currentQuotes.ContainsKey(candle.Key)) currentQuotes[candle.Key] = quote; else currentQuotes.Add(candle.Key, quote); } // уточнить результат по открытым позициям for (var i = 0; i < dueDeals.Count; i++) { if (worker.CancellationPending) return stat; if (dueDeals[i].TimeExit.HasValue) if (dueDeals[i].TimeExit.Value <= time) { dueDeals.RemoveAt(i); i--; continue; } var deal = dueDeals[i]; if (deal.TimeEnter <= time) { // посчитать текущий результат сделки // в контрвалюте if (!currentQuotes.ContainsKey(deal.Symbol)) continue; var dealTickerQuote = currentQuotes[deal.Symbol]; var dealTickerPrice = deal.Side > 0 ? dealTickerQuote.bid : dealTickerQuote.ask; var dealResult = deal.Volume * deal.Side * (dealTickerPrice - deal.PriceEnter); // перевод прибыли в валюту депо bool inverse, areSame; var dealTransferSymbol = DalSpot.Instance.FindSymbol(deal.Symbol, false, curxDepo, out inverse, out areSame); float? baseDepoRate = null; if (areSame) baseDepoRate = 1f; else { if (!string.IsNullOrEmpty(dealTransferSymbol)) if (currentQuotes.ContainsKey(dealTransferSymbol)) { var quote = currentQuotes[dealTransferSymbol]; if (quote.time >= time) baseDepoRate = !inverse ? (deal.Side > 0 ? quote.bid : quote.ask) : (deal.Side > 0 ? 1 / quote.ask : 1 / quote.bid); } } if (!baseDepoRate.HasValue) continue; dealResult *= baseDepoRate.Value; equity += (decimal)dealResult; } } // for (deal ... // сохранить отметку - время/доходность stat.listEquity.Add(new EquityOnTime((float)equity, time)); } // for (time ... += Timeframe } finally { cursor.Close(); } // если история начинается с пустого депо - изъять эти строки из истории var firstNotEmpty = stat.listEquity.FindIndex(e => e.equity > 0); if (firstNotEmpty == stat.listEquity.Count - 1) stat.listEquity.Clear(); else if (firstNotEmpty > 0) stat.listEquity.RemoveRange(0, firstNotEmpty); SetProgressValueSafe(70, Localizer.GetString("MessageBuildingEquityChart") + "..."); stat.Calculate(balanceChanges, openOrders, startDate); return stat; }
public Mt4Quote(string symbol, QuoteData quote) { Symbol = symbol; Bid = quote.bid; Ask = quote.ask; }
/// <summary> /// считаемтся суммарный ордер /// текущая котировка берется из curQuote, если таковая null - из /// avgPrice /// </summary> public MarketOrder CalculateSummaryOrder(List<MarketOrder> orders, QuoteData curQuote, float? avgPrice) { if (orders.Count == 0) return null; if (orders.Count == 1) return orders[0].MakeCopy(); var symbol = orders[0].Symbol; float sumBuys = 0, sumSells = 0; var sumVolume = 0; var totalProfit = 0f; foreach (var order in orders) { sumVolume += order.Side * order.Volume; if (order.Side > 0) sumBuys += order.Volume * order.PriceEnter; else sumSells += order.Volume * order.PriceEnter; totalProfit += order.ResultDepo; } var miniPipCost = GetAbsValue(symbol, 1/10f); if (sumVolume != 0) { var averagePrice = (sumBuys - sumSells) / sumVolume; var avgOrder = new MarketOrder { Symbol = orders[0].Symbol, PriceEnter = averagePrice, ResultDepo = totalProfit, Side = Math.Sign(sumVolume), Volume = Math.Abs(sumVolume), StopLoss = GetDefaultSample(orders.Select(o => o.StopLoss), true, miniPipCost), TakeProfit = GetDefaultSample(orders.Select(o => o.TakeProfit), true, miniPipCost), }; var price = avgPrice; if (curQuote != null) price = avgOrder.Side > 0 ? curQuote.bid : curQuote.ask; avgOrder.ResultPoints = price.HasValue ? (int)Math.Round(GetPointsValue(symbol, avgOrder.Side * (price.Value - avgOrder.PriceEnter))) : 0; return avgOrder; } return null; }
private static void OnQuotesReceived(string[] names, QuoteData[] quotes) { ModuleStatusController.Instance.lastQuoteTime.Value = DateTime.Now; }
/// <summary> /// Вызывается с приходом новой котировки /// </summary> public override List<string> OnQuotesReceived(string[] names, QuoteData[] quotes, bool isHistoryStartOff) { if (isHistoryStartOff) return null; List<MarketOrder> orders; robotContext.GetMarketOrders(robotContext.accountInfo.ID, out orders); if (orders == null || orders.Count == 0) StateRobot = StateInfo.NoTrade; if (quotes[0] == null) return null; for (var i = 0; i < names.Count(); i++) { // пробегаемся по тикерам и ищем те на которые подписан робот foreach (var ticker in Graphics) { if (ticker.a == names[i]) { //BarSettings set = ticker.b; //var dt = set.GetDistanceTime(15, -1, quotes[i].Time); // валютная пара совпадает if (StateRobot == StateInfo.NoTrade) { // надо открыть позицию допустим buy var sl = quotes[i].ask - DalSpot.Instance.GetAbsValue(ticker.a, (float) (StopLoss ?? 0)); var tp = quotes[i].ask + DalSpot.Instance.GetAbsValue(ticker.a, (float) (TakeProfit ?? 0)); if (NewOrder(Magic, ticker.a, 10000, 1, OrderType.Market, 0, 0, (decimal?)sl, (decimal?)tp, null, null, string.Empty, "simple_robot") == RequestStatus.OK) { StateRobot = StateInfo.OpenBuy; } } } } } return null; }
public void CheckOrderTrailing(MarketOrder pos, QuoteData price) { const int minPipsToMoveStop = 1; if (!pos.TrailLevel1.HasValue) return; var resultAbs = pos.Side > 0 ? price.bid - pos.PriceEnter : pos.PriceEnter - price.ask; var resultPoints = DalSpot.Instance.GetPointsValue(pos.Symbol, resultAbs); for (var i = pos.trailingLevels.Length - 1; i >= 0; i--) { if ((pos.trailingLevels[i] == null) || (pos.trailingTargets[i] == null)) continue; if (resultPoints >= pos.trailingLevels[i].Value) { // перетащить стоп var targetStop = pos.PriceEnter + pos.Side * DalSpot.Instance.GetAbsValue(pos.Symbol, pos.trailingTargets[i].Value); if ((pos.StopLoss == null || (targetStop > pos.StopLoss && pos.Side > 0) || (targetStop < pos.StopLoss && pos.Side < 0))) { // проверить расстояние между целевым стопом и текущим стопом var deltaSlPips = Math.Abs(DalSpot.Instance.GetPointsValue(pos.Symbol, targetStop - (pos.StopLoss ?? 0))); if (deltaSlPips >= minPipsToMoveStop) { // вот тут уж точно перетащить стоп Logger.InfoFormat("Установка SL для позиции #{0} с {1:f5} на {2:f5}", pos.ID, pos.StopLoss ?? 0, targetStop); MoveStop(pos, targetStop); break; } } } } }
private void CheckScriptTriggerQuote(string[] quoteNames, QuoteData[] quoteArray) { // сформировать список скриптов (по котировке и по формуле) для срабатывания var scriptsToFire = new List<TerminalScript>(); var scripts = ScriptManager.Instance.GetScripts().ToList(); foreach (var script in scripts.Where(s => s.Trigger != null && (s.Trigger is ScriptTriggerNewQuote || s.Trigger is ScriptTriggerPriceFormula) /*&& s.ScriptTarget != TerminalScript.TerminalScriptTarget.График*/)) { if (script.Trigger is ScriptTriggerNewQuote) { var trigger = (ScriptTriggerNewQuote) script.Trigger; if (trigger.quotesToCheck.Count == 0 || trigger.quotesToCheck.Any(q => quoteNames.Any(n => n.Equals(q, StringComparison.OrdinalIgnoreCase)))) { scriptsToFire.Add(script); } continue; } if (script.Trigger is ScriptTriggerPriceFormula) { var trigger = (ScriptTriggerPriceFormula) script.Trigger; trigger.CheckCondition(); if (trigger.IsTriggered) scriptsToFire.Add(script); } } // запустить скрипты на выполнение if (scriptsToFire.Count > 0) ThreadPool.QueueUserWorkItem(ExecuteScriptsRoutine, scriptsToFire); }
/// <summary> /// получена котировка - одна или несколько /// обновить графики /// </summary> private void OnQuotesReceived(string[] names, QuoteData[] quotes) { // определить, сколько времени прошло с момента получения последней котировки // предложить заполнить дырки var lastQuoteTime = lastQuoteReceived.GetLastHitIfHitted() ?? timeStarted; var deltaMinutes = (DateTime.Now - lastQuoteTime).TotalMinutes; if (deltaMinutes > MinutesOfGapInQuoteStream) ReportOnGapFound(lastQuoteTime); // обновить время последней котировки lastQuoteReceived.Touch(); robotFarm.OnQuotesReceived(names, quotes); try { for (var i = 0; i < names.Length; i++) { var name = names[i]; var charts = Charts; for (var j = 0; j < charts.Count; j++) { var child = charts[j]; if (child.chart.Symbol != name) continue; // обновить асинхронно child.UpdateQuoteAsynch(new[] {quotes[i]}); } } } // ReSharper disable EmptyGeneralCatchClause catch // ReSharper restore EmptyGeneralCatchClause {// окно может быть еще не сформировано, когда в него попадет котировка } // обработать котировки в скриптах CheckScriptTriggerQuote(names, quotes); }
/// <summary> /// проверить условия защиты либо по диверам, либо - по Фибоначчи /// прошерстить все таймфреймы, на каждом ТФ - все диверы /// проверить, выполняется ли условие на защиту покупок или продаж /// </summary> private void CheckProtectTrigger( List<MarketOrder> orders, QuoteData curQuote, List<RobotHint> hints, bool isHistoryStartOff, CandleData newCandle) { if (diversToProtect.Count == 0 && fibonacciProtect.Count == 0) return; var protectConditions = new StringBuilder(); int diverSign = CheckProtectByDivers(curQuote, isHistoryStartOff, protectConditions); if (diverSign == 0) diverSign = CheckProtectByFibos(protectConditions, orders, newCandle); if (diverSign == 0) return; // защищаем сделки с указанным знаком var protectSide = (DealType) diverSign; // создать новый список защиты // старый либо актуализируется, либо игнорируется orders = orders.Where(o => o.Side == (int)protectSide).ToList(); if (orders.Count == 0) return; var newProtectList = new ProtectList { orderIds = orders.Select(o => o.ID).ToList(), side = protectSide }; if (protectList != null) if (newProtectList.AreEqual(protectList)) return; protectList = newProtectList; // добавить маркер на график if (ShowProtectEventMarker) { var eventTitle = protectSide == DealType.Buy ? string.Format("Защита {0} покупок", orders.Count) : string.Format("Защита {0} продаж", orders.Count); var eventText = "Условия: " + protectConditions; hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), eventText, eventTitle, "p", curQuote.bid) { Time = curQuote.time, ColorFill = Color.Yellow, ColorLine = Color.Black, RobotHintType = RobotHint.HintType.Коментарий //diverSign > 0 // ? RobotHint.HintType.Покупка // : RobotHint.HintType.Продажа }); } //Logger.InfoFormat("CheckProtectTrigger: защита сделок [{0}] типа {1}", // string.Join(", ", protectList.orderIds), protectList.side); }
/// <summary> /// проверить и осуществить трейлинг /// </summary> private void CheckUnconditionalProtect(List<MarketOrder> orders, QuoteData curQuote, List<RobotHint> hints) { foreach (var order in orders) { var result = order.Side > 0 ? curQuote.bid - order.PriceEnter : order.PriceEnter - curQuote.ask; var resultPoints = DalSpot.Instance.GetPointsValue(order.Symbol, result); if (resultPoints < unconditionalProtectPips) continue; var stop = order.PriceEnter + order.Side * DalSpot.Instance.GetAbsValue(order.Symbol, (float)protectTarget); var deltaPips = DalSpot.Instance.GetPointsValue(order.Symbol, Math.Abs(stop - (order.StopLoss ?? 0))); if (deltaPips <= protectSensitivity) continue; // передвинуть стоп order.StopLoss = stop; robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), order); if (ShowProtectMarker) { var title = "Безусловная защита сделки " + order.ID; hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), title, title, "p", curQuote.bid) { RobotHintType = RobotHint.HintType.Коментарий, Time = curQuote.time, ColorFill = Color.White, ColorLine = Color.DarkBlue, ColorText = Color.Black }); } } }
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 QuoteData(QuoteData q) { bid = q.bid; ask = q.ask; time = q.time; }
public float CalculateProfit(QuoteData q) { var priceExit = Side > 0 ? q.bid : q.ask; return(CalculateProfit(priceExit)); }
private void OnQuotesReceived(string[] names, QuoteData[] quotes) { var nowTime = DateTime.Now.AddDays(offsetHours); // лок на запись в словарь свечей if (!lockCandles.TryEnterWriteLock(LockTimeout)) { Logger.Error("OnQuotesReceived - таймаут записи"); return; } try { if (!lockCandlesM1.TryEnterWriteLock(LockTimeout)) { Logger.Error("OnQuotesReceived - таймаут записи (m1)"); return; } try { // обновить свечи foreach (var packerDic in packers) { var timeframeCode = packerDic.Key; var isM1 = timeframeCode == barSettingsCodeM1; for (var i = 0; i < names.Length; i++) { var name = names[i]; CandlePacker packer; packerDic.Value.TryGetValue(name, out packer); if (packer == null) continue; var newCandle = packer.UpdateCandle(quotes[i].bid, nowTime); if (newCandle != null) { candles[timeframeCode][name].Add(newCandle); if (isM1) candlesM1[name].Add(newCandle); } } } } finally { lockCandlesM1.ExitWriteLock(); } } finally { lockCandles.ExitWriteLock(); } // если пришло время выгрузить m1 в файл... выгрузить var timeSaved = lastTimeCandlesSaved.GetLastHitIfHitted(); if (timeSaved.HasValue) { if ((DateTime.Now - timeSaved.Value).TotalSeconds > flushCandlesIntervalSec) { FlushCandlesInFiles(); // таки выгрузить lastTimeCandlesSaved.Touch(); } } else lastTimeCandlesSaved.Touch(); }
public CandleDataBidAsk UpdateCandle(QuoteData q) { var candleBid = packerBid.UpdateCandle(q.bid, q.time) ?? packerBid.CurrentCandle; var candleAsk = packerAsk.UpdateCandle(q.ask, q.time) ?? packerAsk.CurrentCandle; return new CandleDataBidAsk(candleBid, candleAsk) { timeClose = q.time }; }
/// <summary> /// асинхронно обновить график /// </summary> public void UpdateQuoteAsynch(QuoteData[] quotes) { UpdateBaseNewsAsynch(null, quotes); }
private void TryEnterTheMarket(int divergenceSign, QuoteData curQuote, List<RobotHint> hints, string divergenceHint) { // проверить фильтры foreach (var filter in filters) { if (filter.IsEnterProhibided((DealType)divergenceSign)) return; // запрет входа фильтром } // фильтр Фибоначчпхи if (FiboEnabled) if (!IsFiboFilterPassed(divergenceSign)) return; List<MarketOrder> orders; GetMarketOrders(out orders); var ordersCount = orders.Count; // закрыть противоположные ордера var ordersToClose = orders.FindAll(o => o.Side != divergenceSign); foreach (var order in ordersToClose) { var requestRst = robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(), robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot); // добавить объект - коментарий на график if (ShowExitMarker) { var orderResult = order.Side == 1 ? curQuote.bid - order.PriceEnter : order.PriceEnter - curQuote.ask; orderResult = DalSpot.Instance.GetPointsValue(order.Symbol, orderResult); var dealInfo = new StringBuilder(); dealInfo.AppendLine(string.Format( "{0} №{1}. {2}, р-т {3}", requestRst == RequestStatus.OK ? "Закрытие" : "[" + requestRst + "]", order.ID, order.Side == 1 ? "BUY" : "SELL", (int) orderResult)); dealInfo.Append(string.Format("Открыта {0:dd.MM.yyyy HH:mm} по {1:f4}", order.TimeEnter, order.PriceEnter)); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), divergenceHint, dealInfo.ToString(), "q", curQuote.bid) { Time = curQuote.time, ColorFill = order.Side == 1 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = RobotHint.HintType.Коментарий }); } ordersCount--; } // открыть позу в направлении знака дивера if (!OpenDeal(divergenceSign, orders)) return; if (ShowEnterMarker) hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), divergenceHint, divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.bid) { Time = curQuote.time, ColorFill = divergenceSign > 0 ? Color.Green : Color.Red, ColorLine = Color.Black, RobotHintType = divergenceSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }); }
private int GetSignalSide(List<string> hints, QuoteData curQuote, out string comment, out string expertComment) { comment = string.Empty; expertComment = string.Empty; // есть ли "пробитая" проекция? string projString; var projSign = GetLastProjectionSide(out projString); if (projSign == 0) return 0; // есть ли дивер? var diverSpan = GetDivergence(); var lastSign = diverSpan == null ? 0 : diverSpan.sign; if (lastSign == 0) return 0; // знаки не совпали - входа нет if (lastSign != projSign) { if (ExtendedMarks) hints.Add(new RobotHint(ticker, BarSettingsStorage.Instance.GetBarSettingsFriendlyName(timeframe), string.Format("Знаки расширения {0} и дивергенции [{1}:{2}] не совпали", projString, diverSpan.sign > 0 ? "бычья" : "медвежья", candles[diverSpan.end].timeClose.ToStringUniform()), "Нет входа", "", curQuote.bid ) { Time = curQuote.time, ColorFill = Color.LightGreen, ColorLine = Color.Black, RobotHintType = lastSign > 0 ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа }.ToString()); return 0; } if (diverSpan != null) { expertComment = projString; comment = string.Format("Ф: {0}, дивер: [{1}:{2}]", projString, diverSpan.sign > 0 ? "бычья" : "медвежья", candles[diverSpan.end].timeOpen.ToStringUniform()); } // вернуть знак предполагаемого входа в рынок return lastSign; }
/// <summary> /// собственно защита /// </summary> private void CheckProtect(List<MarketOrder> orders, QuoteData curQuote, List<RobotHint> hints) { if (protectList == null) return; if (protectList.orderIds.Count == 0) { protectList = null; return; } var ordersToProtect = (from order in orders let orderId = order.ID where protectList.orderIds.Contains(orderId) select order).ToList(); if (ordersToProtect.Count == 0) return; var pointCost = DalSpot.Instance.GetAbsValue(ordersToProtect[0].Symbol, 1f); // индивидуальная "защита" if (ProtectPosType == ProtectType.Индивидуально) { foreach (var order in ordersToProtect) { var targetStop = order.PriceEnter + order.Side*ProtectTarget*pointCost; // проверка - не пытаться переставить стоп на 0.4 пп например var delta = Math.Abs(targetStop - (order.StopLoss ?? 0)); delta = delta/pointCost; if (delta < ProtectSensitivity) continue; // проверка контрольной отметки var orderProtectLevel = order.PriceEnter + order.Side*ProtectLevel*pointCost; var shouldProtect = order.Side == 1 ? curQuote.bid > orderProtectLevel : curQuote.bid < orderProtectLevel; if (!shouldProtect) continue; order.StopLoss = targetStop; robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), order); if (ShowProtectMarker) { var title = "Защита сделки " + order.ID; hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), title, title, "p", curQuote.bid) { RobotHintType = RobotHint.HintType.Коментарий, Time = curQuote.time, ColorFill = Color.White, ColorLine = Color.DarkBlue, ColorText = Color.Black }); } protectList.orderIds.Remove(order.ID); } if (protectList.orderIds.Count == 0) protectList = null; return; } // защита по "медианнной цене" или по "худшей цене" // найти ту самую медианную цену float medPrice = 0; if (ProtectPosType == ProtectType.ПоСреднейЦене) { // средняя цена... var sumPrice = ordersToProtect.Sum(o => o.PriceEnter * o.Volume); var sumVolume = ordersToProtect.Sum(o => o.Volume); medPrice = sumPrice/sumVolume; } if (ProtectPosType == ProtectType.ПоХудшейЦене) { var date = ordersToProtect[0].TimeEnter; medPrice = ordersToProtect[0].PriceEnter; for (var i = 1; i < ordersToProtect.Count; i++) { if (ordersToProtect[i].TimeEnter >= date) continue; date = ordersToProtect[i].TimeEnter; medPrice = ordersToProtect[i].PriceEnter; } } var stopPrice = medPrice + ordersToProtect[0].Side * ProtectTarget * pointCost; // проверить все ордера var dealProtected = false; foreach (var order in ordersToProtect) { var delta = Math.Abs(stopPrice - (order.StopLoss ?? 0)); delta = delta / pointCost; if (delta < ProtectSensitivity) continue; // цена прошла рубеж? var shouldProtect = order.Side == 1 ? curQuote.bid > medPrice : curQuote.bid < medPrice; if (!shouldProtect) continue; dealProtected = true; order.StopLoss = stopPrice; protectList.orderIds.Remove(order.ID); } if (ShowProtectMarker && dealProtected) { var text = new StringBuilder(); text.AppendLine("Защита сделок " + string.Join(", ", ordersToProtect.Select(o => o.ID))); text.AppendFormat("Средневзвеш. цена: {0:f4}", medPrice); hints.Add(new RobotHint(Graphics[0].a, Graphics[0].b.ToString(), "Защита сделок", text.ToString(), "p", curQuote.bid) { RobotHintType = RobotHint.HintType.Коментарий, Time = curQuote.time, ColorFill = Color.White, ColorLine = Color.DarkBlue, ColorText = Color.Black }); } if (protectList.orderIds.Count == 0) protectList = null; return; }
protected int CalculateVolumeInBaseCurrency(decimal volumeDepo, string tradeTicker, VolumeRoundType roundType, QuoteData quoteByTicker = null) { var volumeBase = volumeDepo; var depoCurx = robotContext.AccountInfo.Currency; var quotes = QuoteStorage.Instance.ReceiveAllData(); bool inverse, pairsEqual; var tickerTrans = DalSpot.Instance.FindSymbol(tradeTicker, true, depoCurx, out inverse, out pairsEqual); if (!pairsEqual) { QuoteData quote; if (tickerTrans == tradeTicker && quoteByTicker != null) quote = quoteByTicker; else quotes.TryGetValue(tickerTrans, out quote); if (quote == null) { var msgError = string.Format( "Невозможно рассчитать объем - отсутствует котировка \"{0}\"", tickerTrans); Logger.Info(msgError); return 0; } var priceTrans = inverse ? 1 / quote.bid : quote.ask; volumeBase /= (decimal)priceTrans; } return MarketOrder.RoundDealVolume((int)volumeBase, roundType, RoundMinVolume, RoundVolumeStep); }
public void OnQuotesReceived(string[] names, QuoteData[] quotes) { if (State != FarmState.Started) return; // if (RobotFarmOffTime.IsTimeOff()) return; var candles = packerPool.MakeCandles(quotes, ref names); foreach (var account in Accounts) { try { account.OnQuotesReceived(names, candles, false); } catch (Exception ex) { Logger.Error("Ошибка обработки котировок по счету " + account.AccountId + ": " + ex.Message); } } }