diff --git a/PortfolioManager/Renderers/BollingerBandRenderer.cs b/PortfolioManager/Renderers/BollingerBandRenderer.cs index a0c7bd9..1ba9475 100644 --- a/PortfolioManager/Renderers/BollingerBandRenderer.cs +++ b/PortfolioManager/Renderers/BollingerBandRenderer.cs @@ -70,6 +70,7 @@ namespace PortfolioManager.Renderers private bool showLegend = false; private bool showTradeLabels = true; private bool showInsiderTransactions = true; + private bool showLeastSquares = true; private bool syncTradeToBand = true; private StopLimit stopLimit = default; private StopLimits stopLimits = default; @@ -103,7 +104,14 @@ namespace PortfolioManager.Renderers public void Render() { + Plotter.Plot.Axes.Left.TickGenerator = new ScottPlot.TickGenerators.NumericAutomatic() + { + LabelFormatter = (double value) => value.ToString("C") // "C" format specifier formats as currency + }; + Plotter.Plot.Axes.DateTimeTicksBottom(); Plotter.Plot.Axes.AutoScale(); + Plotter.Plot.XLabel("Date"); + Plotter.Plot.YLabel("Price"); Plotter.Refresh(); base.OnPropertyChanged("ShowLegend"); } @@ -162,6 +170,7 @@ namespace PortfolioManager.Renderers GenerateStopLimits(); GenerateTradePoints(); GenerateZeroPoint(zeroPrice); + GenerateLeastSquares(); } /// @@ -189,6 +198,23 @@ namespace PortfolioManager.Renderers offsets.Add(OffsetDictionary.OffsetType.VerticalOffset5PC,spreadVert * .05); } + /// + /// Generate LeastSquares line + /// + private void GenerateLeastSquares() + { + if (null == bollingerBands || !showLeastSquares) return; + LeastSquares = BollingerBandModel.LeastSquares(bollingerBands); + + Scatter scatter = default; + { + (DateTime[] dates, double[] values) = LeastSquares.ToXYData(); + scatter = Plotter.Plot.Add.ScatterLine(dates, values, ScottPlot.Color.FromSKColor(SKColors.Orange)); + scatter.LegendText = "LeastSquares"; + scatter.LineWidth = 3; + } + } + /// /// Generate the ZeroPoint marker and text /// @@ -202,12 +228,12 @@ namespace PortfolioManager.Renderers ZeroPoint = GainLossModel.Price(zeroPrice); (DateTime[] dates, double[] values) = ZeroPoint.ToXYData(); // There is only a single value in this collection -// Place the triangle marker + // Place the triangle marker image = TextMarkerImageGenerator.ToSPImage(ImageCache.GetInstance().GetImage(ImageCache.ImageType.BlueTriangleUp)); coordinates = new Coordinates(dates[0].ToOADate(), values[0]); imageMarker = Plotter.Plot.Add.ImageMarker(coordinates, image, SizeFactor.Normal); -// Place the text marker + // Place the text marker StringBuilder sb = new StringBuilder(); sb.Append("Even "); sb.Append(Utility.FormatCurrency(zeroPrice.Close)); @@ -571,6 +597,19 @@ namespace PortfolioManager.Renderers } } + public bool ShowLeastSquares + { + get + { + return showLeastSquares; + } + set + { + showLeastSquares = value; + base.OnPropertyChanged("ShowLeastSquares"); + } + } + public AvaPlot Plotter { get; private set; } private CompositeDataSource InsiderTransactionPointDisposedSmall { get; set; } = Empty(); @@ -590,9 +629,7 @@ namespace PortfolioManager.Renderers private CompositeDataSource SMAN { get; set; } = Empty(); private CompositeDataSource Volume { get; set; } = Empty(); private CompositeDataSource LeastSquares { get; set; } = Empty(); - private CompositeDataSource ZeroPoint { get; set; } = Empty(); - private CompositeDataSource StopLimits { get; set; } = Empty(); private static CompositeDataSource Empty() diff --git a/PortfolioManager/ViewModels/ScottPlotViewModel.cs b/PortfolioManager/ViewModels/ScottPlotViewModel.cs index 524dd55..5d8d97b 100644 --- a/PortfolioManager/ViewModels/ScottPlotViewModel.cs +++ b/PortfolioManager/ViewModels/ScottPlotViewModel.cs @@ -30,14 +30,15 @@ namespace PortfolioManager.ViewModels private bool showInsiderTransactions = true; private bool showTradeLabels = true; private bool syncTradeToBand = true; + private bool useLeastSquaresFit = true; public ScottPlotViewModel() - { - DisplayName = "Bollinger"; - OnPlotterLoadedEventHandler += PlotterLoadedEvent; - PropertyChanged += OnViewModelPropertyChanged; - Initialize(); - } + { + DisplayName = "Bollinger"; + OnPlotterLoadedEventHandler += PlotterLoadedEvent; + PropertyChanged += OnViewModelPropertyChanged; + Initialize(); + } protected override void OnDispose() { @@ -102,7 +103,7 @@ namespace PortfolioManager.ViewModels eventArgs.PropertyName.Equals("ShowTradeLabels") || eventArgs.PropertyName.Equals("SelectedSymbol") || eventArgs.PropertyName.Equals("ShowRiskFree") || - eventArgs.PropertyName.Equals("LeastSquaresFit") || + eventArgs.PropertyName.Equals("UseLeastSquaresFit") || eventArgs.PropertyName.Equals("CheckBoxShowInsiderTransactions") || eventArgs.PropertyName.Equals("SelectedDayCount")) && !String.IsNullOrEmpty(selectedSymbol) @@ -113,6 +114,7 @@ namespace PortfolioManager.ViewModels { companyName = PricingDA.GetNameForSymbol(selectedSymbol); bollingerBandRenderer = new BollingerBandRenderer(Plotter); + bollingerBandRenderer.ShowLeastSquares = useLeastSquaresFit; bollingerBandRenderer.SyncTradeToBand = syncTradeToBand; bollingerBandRenderer.ShowInsiderTransactions = showInsiderTransactions; bollingerBandRenderer.ShowTradeLabels = showTradeLabels; @@ -303,6 +305,19 @@ namespace PortfolioManager.ViewModels } } + public bool UseLeastSquaresFit + { + get + { + return useLeastSquaresFit; + } + set + { + useLeastSquaresFit = value; + base.OnPropertyChanged("UseLeastSquaresFit"); + } + } + public Boolean CheckBoxShowInsiderTransactions { get diff --git a/PortfolioManager/Views/ScottPlotView.axaml b/PortfolioManager/Views/ScottPlotView.axaml index 1c66d3d..1a180cb 100644 --- a/PortfolioManager/Views/ScottPlotView.axaml +++ b/PortfolioManager/Views/ScottPlotView.axaml @@ -62,6 +62,7 @@ +