public static void SetChartViewModelIndicatorPaneData(IList <Candle> candles, ChartViewModel cvm, IIndicator indicator) { indicator.Reset(); var indicatorDataSeries = new XyDataSeries <DateTime, double>(); for (var i = 0; i < candles.Count; i++) { var time = new DateTime(candles[i].CloseTimeTicks, DateTimeKind.Utc).ToLocalTime(); var v = indicator.Process(candles[i]); indicatorDataSeries.Append(time, v.IsFormed ? v.Value : float.NaN); } indicatorDataSeries.SeriesName = indicator.Name; var indicatorPaneVm = cvm.ChartPaneViewModels.Count > 1 ? cvm.ChartPaneViewModels[1] : null; if (indicatorPaneVm == null) { var indicatorPane = new ChartPaneViewModel(cvm, cvm.ViewportManager) { IsFirstChartPane = false, IsLastChartPane = true, YAxisTextFormatting = "0.0000" }; indicatorPane.ChartSeriesViewModels.Add(new ChartSeriesViewModel(indicatorDataSeries, new FastLineRenderableSeries { AntiAliasing = false, SeriesColor = Colors.DarkBlue, StrokeThickness = 2 })); cvm.ChartPaneViewModels.Add(indicatorPane); } else { indicatorPaneVm.ChartSeriesViewModels.Clear(); var fastLineRenderableSeries = new FastLineRenderableSeries { AntiAliasing = false, SeriesColor = Colors.DarkBlue, StrokeThickness = 2 }; indicatorPaneVm.ChartSeriesViewModels.Add(new ChartSeriesViewModel(indicatorDataSeries, fastLineRenderableSeries)); } }
public static void CreateTradeAnnotations(AnnotationCollection annotations, ChartViewModel cvm, TradeAnnotationsToShow annotationsToShow, IList <Candle> candles, Trade trade) { // Setup annotations if (candles.Count == 0) { return; } if (trade.EntryDateTime != null && trade.EntryDateTime > candles[candles.Count - 1].CloseTime()) { return; } if (trade.OrderDateTime != null && trade.OrderDateTime > candles[candles.Count - 1].CloseTime()) { return; } var dataSeries = cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries; var startTime = trade.StartDateTimeLocal; var entryCloseMarketSmaller = annotationsToShow.HasFlag(TradeAnnotationsToShow.MakeEntryCloseMarkerSmaller); if (startTime != null && (trade.OrderPrice != null || trade.EntryPrice != null)) { if (trade.EntryPrice != null && (annotationsToShow.HasFlag(TradeAnnotationsToShow.All) || annotationsToShow.HasFlag(TradeAnnotationsToShow.EntryMarker))) { var profit = trade.NetProfitLoss ?? trade.GrossProfitLoss; var colour = (profit != null && profit < 0) || (trade.RMultiple != null && trade.RMultiple.Value < 0) ? Colors.DarkRed : Colors.Green; AddBuySellMarker(trade.TradeDirection.Value, annotations, trade, trade.EntryDateTimeLocal.Value, trade.EntryPrice.Value, entryCloseMarketSmaller, colour: colour); } if (annotationsToShow.HasFlag(TradeAnnotationsToShow.All) || annotationsToShow.HasFlag(TradeAnnotationsToShow.OrderOrEntryLines)) { if (trade.OrderPrice != null && trade.OrderDateTimeLocal != null) { var orderPrices = trade.OrderPrices.ToList(); if (orderPrices.Count > 0) { orderPrices.Add(new DatePrice( trade.EntryDateTime ?? trade.CloseDateTime ?? new DateTime(candles[candles.Count - 1].CloseTimeTicks, DateTimeKind.Utc), null)); AddLineAnnotations(orderPrices, cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries, annotations, Colors.Gray); } } } } // Add order price line if (trade.OrderPrice != null && trade.CloseDateTime == null && trade.EntryPrice == null) { var brush = new SolidColorBrush(Colors.Gray) { Opacity = 0.3 }; var annotation = new LineAnnotation { X1 = 0, X2 = cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries.Count - 1, Y1 = trade.OrderPrice, Y2 = trade.OrderPrice, Stroke = brush, StrokeDashArray = new DoubleCollection(new[] { 5.0, 3.0 }) }; annotations.Add(annotation); } // Add close price line if (trade.ClosePrice != null) { var oppositeTradeDirection = trade.TradeDirection.Value == TradeDirection.Long ? TradeDirection.Short : TradeDirection.Long; if (annotationsToShow.HasFlag(TradeAnnotationsToShow.All) || annotationsToShow.HasFlag(TradeAnnotationsToShow.CloseMarker)) { var profit = trade.NetProfitLoss ?? trade.GrossProfitLoss; var colour = (profit != null && profit < 0) || (trade.RMultiple != null && trade.RMultiple.Value < 0) ? Colors.DarkRed : Colors.Green; AddBuySellMarker(oppositeTradeDirection, annotations, trade, trade.CloseDateTimeLocal.Value, trade.ClosePrice.Value, entryCloseMarketSmaller, colour: colour); // Add line between buy/sell marker /*var brush = new SolidColorBrush(colour) { Opacity = 0.6 }; * var annotation = new LineAnnotation * { * X1 = dataSeries.FindIndex(trade.EntryDateTimeLocal, SearchMode.Nearest), * X2 = dataSeries.FindIndex(trade.CloseDateTimeLocal, SearchMode.Nearest), * Y1 = trade.EntryPrice.Value, * Y2 = trade.ClosePrice.Value, * Stroke = brush, * StrokeThickness = 3, * StrokeDashArray = new DoubleCollection(new[] { 2.0, 2.0 }) * }; * * annotations.Add(annotation);*/ } } // Add stop prices if (annotationsToShow.HasFlag(TradeAnnotationsToShow.All) || annotationsToShow.HasFlag(TradeAnnotationsToShow.StopsLines)) { var stopPrices = trade.StopPrices.ToList(); if (stopPrices.Count > 0) { stopPrices.Add(new DatePrice(trade.CloseDateTime != null ? trade.CloseDateTime.Value : new DateTime(candles[candles.Count - 1].CloseTimeTicks, DateTimeKind.Utc), null)); AddLineAnnotations(stopPrices, cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries, annotations, Colors.Red); } // Add dummy series just to add stop to legend if (cvm.ChartPaneViewModels[0].ChartSeriesViewModels.All(x => x.DataSeries.SeriesName != "Stop")) { var series = new FastLineRenderableSeries() { AntiAliasing = false, SeriesColor = Colors.Red }; series.SetValue(FilteringLegendModifier.IncludeSeriesProperty, true); var d = new XyDataSeries <DateTime, double>(); d.SeriesName = "Stop"; cvm.ChartPaneViewModels[0].ChartSeriesViewModels.Add(new ChartSeriesViewModel(d, series)); } } // Add current stop price line if (trade.StopPrice != null && trade.CloseDateTime == null) { var brush = new SolidColorBrush(Colors.Red) { Opacity = 0.3 }; var annotation = new LineAnnotation { X1 = 0, X2 = cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries.Count - 1, Y1 = trade.StopPrice.Value, Y2 = trade.StopPrice.Value, Stroke = brush, StrokeDashArray = new DoubleCollection(new[] { 5.0, 3.0 }) }; annotations.Add(annotation); } // Add limit prices if (annotationsToShow.HasFlag(TradeAnnotationsToShow.All) || annotationsToShow.HasFlag(TradeAnnotationsToShow.LimitsLines)) { var limitPrices = trade.LimitPrices.ToList(); if (limitPrices.Count > 0) { limitPrices.Add(new DatePrice(trade.CloseDateTime ?? new DateTime(candles[candles.Count - 1].CloseTimeTicks, DateTimeKind.Utc), null)); AddLineAnnotations(limitPrices, cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries, annotations, Colors.DarkGreen); } } // Add current limit price line if (trade.LimitPrice != null && trade.CloseDateTime == null) { var brush = new SolidColorBrush(Colors.DarkGreen) { Opacity = 0.3 }; var annotation = new LineAnnotation { X1 = 0, X2 = cvm.ChartPaneViewModels[0].ChartSeriesViewModels[0].DataSeries.Count - 1, Y1 = trade.LimitPrice.Value, Y2 = trade.LimitPrice.Value, Stroke = brush, StrokeDashArray = new DoubleCollection(new[] { 5.0, 3.0 }) }; annotations.Add(annotation); } }
public static void SetChartViewModelVisibleRange( Trade trade, ChartViewModel cvm, IList <Candle> candles, Timeframe timeframe) { if (candles.Count == 0) { return; } var startTime = trade.OrderDateTime ?? trade.EntryDateTime.Value; var endTime = trade.CloseDateTime ?? new DateTime(candles.Last().CloseTimeTicks, DateTimeKind.Utc); var startCandle = CandlesHelper.GetFirstCandleThatClosesBeforeDateTime(candles, startTime); var endCandle = CandlesHelper.GetFirstCandleThatClosesBeforeDateTime(candles, endTime) ?? candles.Last(); var candlesBeforeTrade = 0; switch (timeframe) { case Timeframe.M1: candlesBeforeTrade = (1 * 60); break; case Timeframe.M5: candlesBeforeTrade = (6 * 12); break; case Timeframe.M15: candlesBeforeTrade = (2 * 12); break; case Timeframe.M30: candlesBeforeTrade = (2 * 12); break; case Timeframe.H1: candlesBeforeTrade = (2 * 24); break; case Timeframe.H2: candlesBeforeTrade = (5 * 12); break; case Timeframe.H4: candlesBeforeTrade = (10 * 6); break; case Timeframe.H8: candlesBeforeTrade = (20 * 3); break; case Timeframe.D1: candlesBeforeTrade = 30; break; default: throw new ApplicationException(timeframe + " timeframe not found for chart helper vis range"); } var candlesAfterTrade = (int)(candlesBeforeTrade * 0.1); var min = candles.IndexOf(startCandle.Value) - candlesBeforeTrade; var max = candles.IndexOf(endCandle) + candlesAfterTrade; if (min < 0) { min = 0; } SetChartXVisibleRange(cvm, min, max); var miny = double.NaN; var maxy = double.NaN; for (var i = min; i < candles.Count; i++) { if (double.IsNaN(miny) || candles[i].LowBid < miny) { miny = candles[i].LowBid; } if (double.IsNaN(maxy) || candles[i].HighBid > maxy) { maxy = candles[i].HighBid; } } if (trade.LimitPrice != null && trade.LimitPrice < (decimal)miny) { miny = (double)trade.LimitPrice; } if (trade.LimitPrice != null && trade.LimitPrice > (decimal)maxy) { maxy = (double)trade.LimitPrice; } if (trade.StopPrice != null && trade.StopPrice < (decimal)miny) { miny = (double)trade.StopPrice; } if (trade.StopPrice != null && trade.StopPrice > (decimal)maxy) { maxy = (double)trade.StopPrice; } }
public ChartPaneViewModel(ChartViewModel parentChartViewModel, IViewportManager viewportManager) { ViewportManager = viewportManager; ParentViewModel = parentChartViewModel; }