diff --git a/PortfolioManager/UIUtils/CartesianPointSeriesViewII.cs b/PortfolioManager/UIUtils/CartesianPointSeriesViewII.cs new file mode 100644 index 0000000..48681be --- /dev/null +++ b/PortfolioManager/UIUtils/CartesianPointSeriesViewII.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Media; +using Eremex.AvaloniaUI.Charts; +using Eremex.AvaloniaUI.Charts.Native; + +namespace Eremex.AvaloniaUI.Charts +{ + public class CartesianPointSeriesViewII : CartesianPointSeriesView + { + public CartesianPointSeriesViewII() + { + } + + protected override SeriesViewPainter CreatePainter() + { + return new MarkerPainter(); + } + } +} \ No newline at end of file diff --git a/PortfolioManager/ViewModels/BollingerBandViewModel.cs b/PortfolioManager/ViewModels/BollingerBandViewModel.cs index 01fa7ef..dd4c0bd 100644 --- a/PortfolioManager/ViewModels/BollingerBandViewModel.cs +++ b/PortfolioManager/ViewModels/BollingerBandViewModel.cs @@ -10,6 +10,7 @@ using CommunityToolkit.Mvvm.Input; using DynamicData; using Eremex.AvaloniaUI.Charts; using MarketData; +using MarketData.CNNProcessing; using MarketData.DataAccess; using MarketData.Generator; using MarketData.MarketDataModel; @@ -20,505 +21,291 @@ using PortfolioManager.DataSeriesViewModels; using PortfolioManager.Extensions; using PortfolioManager.Models; using PortfolioManager.UIUtils; +using SkiaSharp; namespace PortfolioManager.ViewModels { - public partial class BollingerBandViewModel : WorkspaceViewModel + public static class TextMarkerImageGenerator { - private bool isBusy = false; - private List watchListNames; - private String selectedWatchList; - private List dayCounts = new int[] { 60, 90, 180, 360, 720, 1440, 3600 }.ToList(); - private int selectedDayCount = 90; - private ObservableCollection symbols = new ObservableCollection(); - private String selectedSymbol = default; - private bool showMarkers = false; - - private InsiderTransactionSummaries insiderTransactionSummaries = null; - private Price zeroPrice = null; - private PortfolioTrades portfolioTrades; - private PortfolioTrades portfolioTradesLots; - private StopLimit stopLimit; // This is the stop limit that is looked up in the database and displayed (if there is one) - private StopLimits stopLimits; // These stop limits might be passed in with the SaveParams. (i.e.) MMTRend model passes in StopLimits. If these are passsed in then they are displayed instead of stopLimit. - private Prices prices = null; - - private bool syncTradeToBand = true; - private String companyName = default; - private bool showTradeLabels = true; - - private bool useLeastSquaresFit = true; - private bool showInsiderTransactions = true; - - private CompositeDataSource compositeDataSourceZeroPoint = null; - private CompositeDataSource compositeDataSourceStopLimit = null; - - private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedSmall = null; - private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedMedium = null; - private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedLarge = null; - private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredSmall = null; - private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredMedium = null; - private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredLarge = null; - - private CompositeDataSource compositeDataSourceK = null; - private CompositeDataSource compositeDataSourceKL1 = null; - private CompositeDataSource compositeDataSourceL = null; - private CompositeDataSource compositeDataSourceLP1 = null; - private CompositeDataSource compositeDataSourceHigh = null; - private CompositeDataSource compositeDataSourceLow = null; - private CompositeDataSource compositeDataSourceClose = null; - private CompositeDataSource compositeDataSourceSMAN = null; - private CompositeDataSource compositeDataSourceVolume = null; - private CompositeDataSource compositeDataSourceLeastSquares = null; - private CompositeDataSource compositeDataSourceTradePoints = null; - - private BollingerBands bollingerBands; - - public BollingerBandViewModel(bool loadedFromParams = false) + public static IImage GenerateImage(String text) { - InitializeDataSources(); - PropertyChanged += OnViewModelPropertyChanged; - DisplayName = "Bollinger"; - Initialize(loadedFromParams ? false : true); + ImageHelper imageHelper = new ImageHelper(); + int fontSize = 36; + int width = 640; + imageHelper.CreateImage(width, fontSize); + imageHelper.Fill(SKColors.White); + SKTextAlign align = SKTextAlign.Center; + SKFont font = new SKFont(SKTypeface.FromFamilyName("Helvetica"), fontSize); + imageHelper.DrawText(text, new SKPoint(width / 2, fontSize - 2), SKColors.Black, align, font); + Avalonia.Media.Imaging.Bitmap avBitmap = new Avalonia.Media.Imaging.Bitmap(imageHelper.ToStream()); + return avBitmap; + // avBitmap.Save("c:\\3\\mybitmap.jpg"); } } - protected override void OnDispose() + public static IImage GenerateImage(int width, int height,SKColor color) { - MDTrace.WriteLine(LogLevel.DEBUG,$"Dispose BollingerBandViewModel"); - base.OnDispose(); - } - - private void Initialize(bool executePropertyChanged=true) - { - Task workerTask = Task.Factory.StartNew(() => - { - MDTrace.WriteLine(LogLevel.DEBUG, $"BollingerBandViewModel::Initialize()"); - watchListNames = WatchListDA.GetWatchLists(); - watchListNames.Insert(0, UIConstants.CONST_ALL); - selectedWatchList = watchListNames.Find(x => x.Equals("Valuations")); - symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList)); - }); - workerTask.ContinueWith((continuation) => - { - if (executePropertyChanged) - { - base.OnPropertyChanged("Symbols"); - base.OnPropertyChanged("WatchListNames"); - base.OnPropertyChanged("SelectedWatchList"); - } - }); + ImageHelper imageHelper = new ImageHelper(); + imageHelper.CreateImage(width, height); + imageHelper.Fill(color); + Avalonia.Media.Imaging.Bitmap avBitmap = new Avalonia.Media.Imaging.Bitmap(imageHelper.ToStream()); + return avBitmap; + // avBitmap.Save("c:\\3\\mybitmap.jpg"); } } + } - public bool IsBusy + public partial class BollingerBandViewModel : WorkspaceViewModel { - get - { - return isBusy; - } - set - { - isBusy = value; - base.OnPropertyChanged("IsBusy"); - } - } + private bool isBusy = false; + private List watchListNames; + private String selectedWatchList; + private List dayCounts = new int[] { 60, 90, 180, 360, 720, 1440, 3600 }.ToList(); + private int selectedDayCount = 90; + private ObservableCollection symbols = new ObservableCollection(); + private String selectedSymbol = default; + private bool showMarkers = false; - public override String Title - { - get - { - if (null == selectedSymbol) return DisplayName; - return "Bollinger " + "("+selectedSymbol+")"; - } - } + private InsiderTransactionSummaries insiderTransactionSummaries = null; + private Price zeroPrice = null; + private PortfolioTrades portfolioTrades; + private PortfolioTrades portfolioTradesLots; + private StopLimit stopLimit; // This is the stop limit that is looked up in the database and displayed (if there is one) + private StopLimits stopLimits; // These stop limits might be passed in with the SaveParams. (i.e.) MMTRend model passes in StopLimits. If these are passsed in then they are displayed instead of stopLimit. + private Prices prices = null; - public String GraphTitle - { - get - { - if (null == companyName || null == prices || 0 == prices.Count) return ""; - String displayCompanyName=companyName; - if(displayCompanyName.Length>40)displayCompanyName=displayCompanyName.Substring(0,40)+"..."; - StringBuilder sb=new StringBuilder(); - float change=float.NaN; - Prices prices2day=new Prices(prices.Take(2).ToList()); - if(2==prices2day.Count)change=prices2day.GetReturns()[0]; - sb.Append(displayCompanyName); - sb.Append(" (").Append(selectedSymbol).Append(") "); - sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[prices.Count-1].Date)); - sb.Append(" Thru "); - sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[0].Date)); - sb.Append(" (").Append(Utility.FormatCurrency(prices[0].Close)); - sb.Append("/").Append(Utility.FormatCurrency(prices[0].Low)); - if(!float.IsNaN(change)) - { - sb.Append(","); - sb.Append(change>=0.00?"+":"").Append(Utility.FormatPercent((double)change)); - } - sb.Append(")"); - return sb.ToString(); - } - } + private bool syncTradeToBand = true; + private String companyName = default; + private bool showTradeLabels = true; - public override String DisplayName - { - get - { - return "Bollinger Band"; - } - } + private bool useLeastSquaresFit = true; + private bool showInsiderTransactions = true; - public bool ShowMarkers - { - get - { - return showMarkers; - } - set - { - showMarkers = value; - base.OnPropertyChanged("ShowMarkers"); - } - } + private CompositeDataSource compositeDataSourceZeroPoint = null; + private CompositeDataSource compositeDataSourceStopLimit = null; - public ObservableCollection Symbols - { - get - { - return symbols; - } - } + private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedSmall = null; + private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedMedium = null; + private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedLarge = null; + private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredSmall = null; + private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredMedium = null; + private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredLarge = null; - public String SelectedSymbol - { - get - { - return selectedSymbol; - } - set - { - if (String.IsNullOrEmpty(selectedSymbol)) - { - return; - } - selectedSymbol = value; - base.OnPropertyChanged("SelectedSymbol"); - } - } + private CompositeDataSource compositeDataSourceK = null; + private CompositeDataSource compositeDataSourceKL1 = null; + private CompositeDataSource compositeDataSourceL = null; + private CompositeDataSource compositeDataSourceLP1 = null; + private CompositeDataSource compositeDataSourceHigh = null; + private CompositeDataSource compositeDataSourceLow = null; + private CompositeDataSource compositeDataSourceClose = null; + private CompositeDataSource compositeDataSourceSMAN = null; + private CompositeDataSource compositeDataSourceVolume = null; + private CompositeDataSource compositeDataSourceLeastSquares = null; + private CompositeDataSource compositeDataSourceTradePoints = null; - public int SelectedDayCount - { - get - { - return selectedDayCount; - } - set - { - selectedDayCount = value; - base.OnPropertyChanged("SelectedDayCount"); - } - } + private BollingerBands bollingerBands; - public List DayCounts - { - get + public BollingerBandViewModel(bool loadedFromParams = false) { - return dayCounts; - } - } - - public bool SyncTradeToBand - { - get - { - return syncTradeToBand; - } - set - { - syncTradeToBand = value; - if (syncTradeToBand) showTradeLabels = true; - base.OnPropertyChanged("SyncTradeToBand"); - base.OnPropertyChanged("TradePoints"); - base.OnPropertyChanged("ZeroPoint"); - base.OnPropertyChanged("StopLimits"); - base.OnPropertyChanged("TradePointMarkers"); - base.OnPropertyChanged("ZeroPointMarkers"); - base.OnPropertyChanged("StopLimitMarkers"); - } - } - - public bool ShowTradeLabels - { - get - { - return showTradeLabels; - } - set - { - showTradeLabels = value; - base.OnPropertyChanged("ShowTradeLabels"); - } - } - - public Boolean CheckBoxShowInsiderTransactions - { - get - { - return showInsiderTransactions; - } - set - { - showInsiderTransactions = value; - base.OnPropertyChanged("CheckBoxShowInsiderTransactions"); - base.OnPropertyChanged("InsiderTransactionPointDisposedSmall"); - base.OnPropertyChanged("InsiderTransactionPointDisposedMedium"); - base.OnPropertyChanged("InsiderTransactionPointDisposedLarge"); - base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall"); - base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium"); - base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge"); - - base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall"); - base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium"); - base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge"); - base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall"); - base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium"); - base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge"); - } - } +// CartesianLineSeriesView ch = new CartesianLineSeriesView(); + CartesianPointSeriesView ch = new CartesianPointSeriesView(); - // ****************************************************** P R O P E R T I E S ************************************************ - - public List WatchListNames - { - get - { - return watchListNames; - } - } - - public String SelectedWatchList - { - get - { - return selectedWatchList; - } - set - { - selectedWatchList = value; - base.OnPropertyChanged("SelectedWatchList"); - } - } - - /// - /// See the XAML and also OSValueConverter in UIUtils for an explanation. - /// - public int MarkerSize - { - get - { - return 0; - } - } - - // ********************************************************************************************************************************************* - - - // ******************************************************************* P E R S I S T E N C E *************************************************** - - public override bool CanPersist() - { - return true; - } - - public override SaveParameters GetSaveParameters() - { - SaveParameters saveParams = new SaveParameters(); - if (String.IsNullOrEmpty(selectedSymbol)) return null; - saveParams.Add(new KeyValuePair("Type",GetType().Namespace+"."+GetType().Name)); - saveParams.Add(new KeyValuePair("SelectedSymbol", selectedSymbol)); - saveParams.Add(new KeyValuePair("SelectedWatchList", selectedWatchList)); - saveParams.Add(new KeyValuePair("SelectedDayCount", selectedDayCount.ToString())); - saveParams.Add(new KeyValuePair("SyncTradeToBand", syncTradeToBand.ToString())); - saveParams.Add(new KeyValuePair("ShowTradeLabels", showTradeLabels.ToString())); - saveParams.Add(new KeyValuePair("UseLeastSquaresFit", useLeastSquaresFit.ToString())); - saveParams.Add(new KeyValuePair("ShowInsiderTransactions", showInsiderTransactions.ToString())); - if(null!=stopLimits && 0!=stopLimits.Count) - { - saveParams.Add(new KeyValuePair("StopHistoryCount",stopLimits.Count.ToString())); - for(int index=0;index(strItemKey,strStopHistoryItem)); - } - } - return saveParams; - } - - public override void SetSaveParameters(SaveParameters saveParameters) - { - try - { - - Task workerTask = Task.Factory.StartNew(() => - { - - Referer = saveParameters.Referer; - selectedSymbol = (from KeyValuePair item in saveParameters where item.Key.Equals("SelectedSymbol") select item).FirstOrDefault().Value; - selectedWatchList = (from KeyValuePair item in saveParameters where item.Key.Equals("SelectedWatchList") select item).FirstOrDefault().Value; - selectedDayCount = Int32.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("SelectedDayCount") select item).FirstOrDefault().Value); - MDTrace.WriteLine(LogLevel.DEBUG, $"BollingerBandViewModel::SetSaveParameters('{selectedSymbol}','{selectedWatchList}','{selectedDayCount}')"); - try - { - if (saveParameters.ContainsKey("SyncTradeToBand")) syncTradeToBand = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("SyncTradeToBand") select item).FirstOrDefault().Value); - else syncTradeToBand = true; - } - catch (Exception) { syncTradeToBand = true; } - try - { - if (saveParameters.ContainsKey("ShowTradeLabels")) showTradeLabels = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("ShowTradeLabels") select item).FirstOrDefault().Value); - else showTradeLabels = true; - } - catch (Exception) { showTradeLabels = true; } - try - { - if (saveParameters.ContainsKey("UseLeastSquaresFit")) useLeastSquaresFit = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("UseLeastSquaresFit") select item).FirstOrDefault().Value); - } - catch (Exception) {; } - try - { - if (saveParameters.ContainsKey("ShowInsiderTransactions")) showInsiderTransactions = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("ShowInsiderTransactions") select item).FirstOrDefault().Value); - } - catch (Exception) {; } - try - { - if (saveParameters.ContainsKey("StopHistoryCount")) - { - stopLimits = StopLimitsExtensions.FromSaveParams(saveParameters); - } - } - catch (Exception exception) - { - MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Exception:{0}", exception.ToString())); - } - // base.OnPropertyChanged("SelectedWatchList"); - // base.OnPropertyChanged("SelectedSymbol"); - }); - workerTask.ContinueWith((continuation) => - { - base.OnPropertyChanged("SelectedWatchList"); - base.OnPropertyChanged("SelectedSymbol"); - }); - } - catch (Exception) - { - } - } - - // ****************************************************** R E L A Y S ******************************************************** - [RelayCommand] - public async Task Refresh() - { - base.OnPropertyChanged("SelectedSymbol"); - await Task.FromResult(true); - } - - // ************************************************************************************************************************************* - private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) - { - if (eventArgs.PropertyName.Equals("SelectedSymbol") && !String.IsNullOrEmpty(selectedSymbol)) - { InitializeDataSources(); - InitializeData(); + PropertyChanged += OnViewModelPropertyChanged; + DisplayName = "Bollinger"; + Initialize(loadedFromParams ? false : true); } - if ((eventArgs.PropertyName.Equals("SyncTradeToBand") || - eventArgs.PropertyName.Equals("ShowTradeLabels") || - eventArgs.PropertyName.Equals("SelectedSymbol") || - eventArgs.PropertyName.Equals("ShowRiskFree") || - eventArgs.PropertyName.Equals("LeastSquaresFit") || - eventArgs.PropertyName.Equals("SelectedDayCount")) - && !String.IsNullOrEmpty(selectedSymbol)) + protected override void OnDispose() + { + MDTrace.WriteLine(LogLevel.DEBUG, $"Dispose BollingerBandViewModel"); + base.OnDispose(); + } + + private void Initialize(bool executePropertyChanged = true) { - IsBusy = true; Task workerTask = Task.Factory.StartNew(() => { - MDTrace.WriteLine(LogLevel.DEBUG,$"OnViewModelPropertyChanged({eventArgs.PropertyName}). Selected symbol '{selectedSymbol}'"); - base.DisplayName = "Bollinger(" + selectedSymbol + ")"; - base.OnPropertyChanged("DisplayName"); - stopLimit = PortfolioDA.GetStopLimit(selectedSymbol); - portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol); - portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades); - if (null != portfolioTrades && 0 != portfolioTrades.Count) - { - DateGenerator dateGenerator = new DateGenerator(); - DateTime earliestTrade = portfolioTrades[0].TradeDate; - earliestTrade = earliestTrade.AddDays(-30); - int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now); - if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount); - else prices = PricingDA.GetPrices(selectedSymbol, earliestTrade); - - DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30); - insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate); - - // calculate the break even price on the open trades for this symbol - PortfolioTrades openTrades = portfolioTrades.GetOpenTrades(); - DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol); - Price latestPrice = PricingDA.GetPrice(selectedSymbol, latestPricingDate); - zeroPrice = ParityGenerator.GenerateGainLossValue(openTrades, latestPrice); - - if (!syncTradeToBand) - { - DateTime earliestPricingDate = prices[prices.Count - 1].Date; - earliestPricingDate = earliestPricingDate.AddDays(30); - IEnumerable tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade); - portfolioTrades = new PortfolioTrades(); - foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade); - portfolioTradesLots = portfolioTrades; - } - } - else - { - prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount); - if (null != prices && 0 != prices.Count) - { - DateGenerator dateGenerator = new DateGenerator(); - DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30); - insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate); - } - } - companyName = PricingDA.GetNameForSymbol(selectedSymbol); - bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices); - CreateCompositeDataSources(); + MDTrace.WriteLine(LogLevel.DEBUG, $"BollingerBandViewModel::Initialize()"); + watchListNames = WatchListDA.GetWatchLists(); + watchListNames.Insert(0, UIConstants.CONST_ALL); + selectedWatchList = watchListNames.Find(x => x.Equals("Valuations")); + symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList)); }); workerTask.ContinueWith((continuation) => { - base.OnPropertyChanged("K"); - base.OnPropertyChanged("KL1"); - base.OnPropertyChanged("L"); - base.OnPropertyChanged("LP1"); - base.OnPropertyChanged("High"); - base.OnPropertyChanged("Low"); - base.OnPropertyChanged("Close"); - base.OnPropertyChanged("SMAN"); - base.OnPropertyChanged("Volume"); - base.OnPropertyChanged("LeastSquares"); - base.OnPropertyChanged("GraphTitle"); - base.OnPropertyChanged("Title"); + if (executePropertyChanged) + { + base.OnPropertyChanged("Symbols"); + base.OnPropertyChanged("WatchListNames"); + base.OnPropertyChanged("SelectedWatchList"); + } + }); + } + public bool IsBusy + { + get + { + return isBusy; + } + set + { + isBusy = value; + base.OnPropertyChanged("IsBusy"); + } + } + + public override String Title + { + get + { + if (null == selectedSymbol) return DisplayName; + return "Bollinger " + "(" + selectedSymbol + ")"; + } + } + + public String GraphTitle + { + get + { + if (null == companyName || null == prices || 0 == prices.Count) return ""; + String displayCompanyName = companyName; + if (displayCompanyName.Length > 40) displayCompanyName = displayCompanyName.Substring(0, 40) + "..."; + StringBuilder sb = new StringBuilder(); + float change = float.NaN; + Prices prices2day = new Prices(prices.Take(2).ToList()); + if (2 == prices2day.Count) change = prices2day.GetReturns()[0]; + sb.Append(displayCompanyName); + sb.Append(" (").Append(selectedSymbol).Append(") "); + sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[prices.Count - 1].Date)); + sb.Append(" Thru "); + sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[0].Date)); + sb.Append(" (").Append(Utility.FormatCurrency(prices[0].Close)); + sb.Append("/").Append(Utility.FormatCurrency(prices[0].Low)); + if (!float.IsNaN(change)) + { + sb.Append(","); + sb.Append(change >= 0.00 ? "+" : "").Append(Utility.FormatPercent((double)change)); + } + sb.Append(")"); + return sb.ToString(); + } + } + + public override String DisplayName + { + get + { + return "Bollinger Band"; + } + } + + public bool ShowMarkers + { + get + { + return showMarkers; + } + set + { + showMarkers = value; + base.OnPropertyChanged("ShowMarkers"); + } + } + + public ObservableCollection Symbols + { + get + { + return symbols; + } + } + + public String SelectedSymbol + { + get + { + return selectedSymbol; + } + set + { + if (String.IsNullOrEmpty(selectedSymbol)) + { + return; + } + selectedSymbol = value; + base.OnPropertyChanged("SelectedSymbol"); + } + } + + public int SelectedDayCount + { + get + { + return selectedDayCount; + } + set + { + selectedDayCount = value; + base.OnPropertyChanged("SelectedDayCount"); + } + } + + public List DayCounts + { + get + { + return dayCounts; + } + } + + public bool SyncTradeToBand + { + get + { + return syncTradeToBand; + } + set + { + syncTradeToBand = value; + if (syncTradeToBand) showTradeLabels = true; + base.OnPropertyChanged("SyncTradeToBand"); base.OnPropertyChanged("TradePoints"); base.OnPropertyChanged("ZeroPoint"); base.OnPropertyChanged("StopLimits"); - base.OnPropertyChanged("TradePointMarkers"); base.OnPropertyChanged("ZeroPointMarkers"); base.OnPropertyChanged("StopLimitMarkers"); +// base.OnPropertyChanged("ZeroPointMarkersTextMarkers"); + } + } + public bool ShowTradeLabels + { + get + { + return showTradeLabels; + } + set + { + showTradeLabels = value; + base.OnPropertyChanged("ShowTradeLabels"); + } + } + + public Boolean CheckBoxShowInsiderTransactions + { + get + { + return showInsiderTransactions; + } + set + { + showInsiderTransactions = value; + base.OnPropertyChanged("CheckBoxShowInsiderTransactions"); base.OnPropertyChanged("InsiderTransactionPointDisposedSmall"); base.OnPropertyChanged("InsiderTransactionPointDisposedMedium"); base.OnPropertyChanged("InsiderTransactionPointDisposedLarge"); - base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall"); base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium"); base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge"); @@ -526,380 +313,660 @@ namespace PortfolioManager.ViewModels base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall"); base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium"); base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge"); - base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall"); base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium"); base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge"); - IsBusy = false; - }); + } } - else if (eventArgs.PropertyName.Equals("SelectedWatchList")) + + + // ****************************************************** P R O P E R T I E S ************************************************ + + public List WatchListNames { - IsBusy = true; - Task workerTask = Task.Factory.StartNew(() => + get { - if (selectedWatchList.Equals(Constants.CONST_ALL)) - { - symbols.Clear(); - symbols.AddRange(SymbolCache.GetInstance().GetSymbols()); - } - else - { - symbols.Clear(); - symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList)); - } - }); - workerTask.ContinueWith((continuation) => + return watchListNames; + } + } + + public String SelectedWatchList + { + get { - IsBusy = false; - base.OnPropertyChanged("Symbols"); - }); + return selectedWatchList; + } + set + { + selectedWatchList = value; + base.OnPropertyChanged("SelectedWatchList"); + } } - } -// ************************************************* C O M P O S I T E D A T A S O U R C E S ******************************************** + /// + /// See the XAML and also OSValueConverter in UIUtils for an explanation. + /// + public int MarkerSize + { + get + { + return 0; + } + } - public CompositeDataSource K - { - get - { - return compositeDataSourceK; - } - } - public CompositeDataSource KL1 - { - get - { - return compositeDataSourceKL1; - } - } + // ********************************************************************************************************************************************* - public CompositeDataSource L - { - get - { - return compositeDataSourceL; - } - } - public CompositeDataSource LP1 - { - get - { - return compositeDataSourceLP1; - } - } - public CompositeDataSource High - { - get - { - return compositeDataSourceHigh; - } - } - public CompositeDataSource Low - { - get - { - return compositeDataSourceLow; - } - } - public CompositeDataSource Close - { - get - { - return compositeDataSourceClose; - } - } - public CompositeDataSource SMAN - { - get - { - return compositeDataSourceSMAN; - } - } - public CompositeDataSource Volume - { - get - { - return compositeDataSourceVolume; - } - } - public CompositeDataSource LeastSquares - { - get - { - if(!useLeastSquaresFit||null==bollingerBands)return Empty(); - return compositeDataSourceLeastSquares; - } - } + // ******************************************************************* P E R S I S T E N C E *************************************************** - public CompositeDataSource TradePoints - { - get + public override bool CanPersist() { - if (!showTradeLabels) return Empty(); - return compositeDataSourceTradePoints; + return true; } - } - public CompositeDataSource ZeroPoint - { - get + public override SaveParameters GetSaveParameters() { - if (!showTradeLabels) return Empty(); - return compositeDataSourceZeroPoint; + SaveParameters saveParams = new SaveParameters(); + if (String.IsNullOrEmpty(selectedSymbol)) return null; + saveParams.Add(new KeyValuePair("Type", GetType().Namespace + "." + GetType().Name)); + saveParams.Add(new KeyValuePair("SelectedSymbol", selectedSymbol)); + saveParams.Add(new KeyValuePair("SelectedWatchList", selectedWatchList)); + saveParams.Add(new KeyValuePair("SelectedDayCount", selectedDayCount.ToString())); + saveParams.Add(new KeyValuePair("SyncTradeToBand", syncTradeToBand.ToString())); + saveParams.Add(new KeyValuePair("ShowTradeLabels", showTradeLabels.ToString())); + saveParams.Add(new KeyValuePair("UseLeastSquaresFit", useLeastSquaresFit.ToString())); + saveParams.Add(new KeyValuePair("ShowInsiderTransactions", showInsiderTransactions.ToString())); + if (null != stopLimits && 0 != stopLimits.Count) + { + saveParams.Add(new KeyValuePair("StopHistoryCount", stopLimits.Count.ToString())); + for (int index = 0; index < stopLimits.Count; index++) + { + String strItemKey = String.Format("StopHistory_{0}", index); + StopLimit stopLimit = stopLimits[index]; + NVPCollection nvpCollection = stopLimit.ToNVPCollection(); + String strStopHistoryItem = nvpCollection.ToString(); + saveParams.Add(new KeyValuePair(strItemKey, strStopHistoryItem)); + } + } + return saveParams; } - } - public CompositeDataSource StopLimits - { - get + public override void SetSaveParameters(SaveParameters saveParameters) { - if (!showTradeLabels) return Empty(); - return compositeDataSourceStopLimit; - } - } + try + { - public CompositeDataSource InsiderTransactionPointDisposedSmall - { - get - { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointDisposedSmall; - } - } + Task workerTask = Task.Factory.StartNew(() => + { - public CompositeDataSource InsiderTransactionPointDisposedMedium - { - get - { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointDisposedMedium; + Referer = saveParameters.Referer; + selectedSymbol = (from KeyValuePair item in saveParameters where item.Key.Equals("SelectedSymbol") select item).FirstOrDefault().Value; + selectedWatchList = (from KeyValuePair item in saveParameters where item.Key.Equals("SelectedWatchList") select item).FirstOrDefault().Value; + selectedDayCount = Int32.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("SelectedDayCount") select item).FirstOrDefault().Value); + MDTrace.WriteLine(LogLevel.DEBUG, $"BollingerBandViewModel::SetSaveParameters('{selectedSymbol}','{selectedWatchList}','{selectedDayCount}')"); + try + { + if (saveParameters.ContainsKey("SyncTradeToBand")) syncTradeToBand = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("SyncTradeToBand") select item).FirstOrDefault().Value); + else syncTradeToBand = true; + } + catch (Exception) { syncTradeToBand = true; } + try + { + if (saveParameters.ContainsKey("ShowTradeLabels")) showTradeLabels = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("ShowTradeLabels") select item).FirstOrDefault().Value); + else showTradeLabels = true; + } + catch (Exception) { showTradeLabels = true; } + try + { + if (saveParameters.ContainsKey("UseLeastSquaresFit")) useLeastSquaresFit = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("UseLeastSquaresFit") select item).FirstOrDefault().Value); + } + catch (Exception) {; } + try + { + if (saveParameters.ContainsKey("ShowInsiderTransactions")) showInsiderTransactions = Boolean.Parse((from KeyValuePair item in saveParameters where item.Key.Equals("ShowInsiderTransactions") select item).FirstOrDefault().Value); + } + catch (Exception) {; } + try + { + if (saveParameters.ContainsKey("StopHistoryCount")) + { + stopLimits = StopLimitsExtensions.FromSaveParams(saveParameters); + } + } + catch (Exception exception) + { + MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Exception:{0}", exception.ToString())); + } + // base.OnPropertyChanged("SelectedWatchList"); + // base.OnPropertyChanged("SelectedSymbol"); + }); + workerTask.ContinueWith((continuation) => + { + base.OnPropertyChanged("SelectedWatchList"); + base.OnPropertyChanged("SelectedSymbol"); + }); + } + catch (Exception) + { + } } - } - public CompositeDataSource InsiderTransactionPointDisposedLarge - { - get + // ****************************************************** R E L A Y S ******************************************************** + [RelayCommand] + public async Task Refresh() { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointDisposedLarge; + base.OnPropertyChanged("SelectedSymbol"); + await Task.FromResult(true); } - } - public CompositeDataSource InsiderTransactionPointAcquiredSmall - { - get + // ************************************************************************************************************************************* + private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointAcquiredSmall; - } - } + if (eventArgs.PropertyName.Equals("SelectedSymbol") && !String.IsNullOrEmpty(selectedSymbol)) + { + InitializeDataSources(); + InitializeData(); + } - public CompositeDataSource InsiderTransactionPointAcquiredMedium - { - get - { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointAcquiredMedium; - } - } + if ((eventArgs.PropertyName.Equals("SyncTradeToBand") || + eventArgs.PropertyName.Equals("ShowTradeLabels") || + eventArgs.PropertyName.Equals("SelectedSymbol") || + eventArgs.PropertyName.Equals("ShowRiskFree") || + eventArgs.PropertyName.Equals("LeastSquaresFit") || + eventArgs.PropertyName.Equals("SelectedDayCount")) + && !String.IsNullOrEmpty(selectedSymbol)) + { + IsBusy = true; + Task workerTask = Task.Factory.StartNew(() => + { + MDTrace.WriteLine(LogLevel.DEBUG, $"OnViewModelPropertyChanged({eventArgs.PropertyName}). Selected symbol '{selectedSymbol}'"); + base.DisplayName = "Bollinger(" + selectedSymbol + ")"; + base.OnPropertyChanged("DisplayName"); + stopLimit = PortfolioDA.GetStopLimit(selectedSymbol); + portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol); + portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades); + if (null != portfolioTrades && 0 != portfolioTrades.Count) + { + DateGenerator dateGenerator = new DateGenerator(); + DateTime earliestTrade = portfolioTrades[0].TradeDate; + earliestTrade = earliestTrade.AddDays(-30); + int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now); + if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount); + else prices = PricingDA.GetPrices(selectedSymbol, earliestTrade); - public CompositeDataSource InsiderTransactionPointAcquiredLarge - { - get - { - if (!showInsiderTransactions) return Empty(); - return compositeDataSourceInsiderTransactionPointAcquiredLarge; - } - } + DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30); + insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate); - // ******************************************************** M A R K E R S ************************************************** - - public IImage StopLimitMarkers - { - get - { - if (!showTradeLabels) return null; - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleUp); - } - } + // calculate the break even price on the open trades for this symbol + PortfolioTrades openTrades = portfolioTrades.GetOpenTrades(); + DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol); + Price latestPrice = PricingDA.GetPrice(selectedSymbol, latestPricingDate); + zeroPrice = ParityGenerator.GenerateGainLossValue(openTrades, latestPrice); - public IImage ZeroPointMarkers - { - get - { - if (!showTradeLabels) return null; - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.BlueTriangleUp); + if (!syncTradeToBand) + { + DateTime earliestPricingDate = prices[prices.Count - 1].Date; + earliestPricingDate = earliestPricingDate.AddDays(30); + IEnumerable tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade); + portfolioTrades = new PortfolioTrades(); + foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade); + portfolioTradesLots = portfolioTrades; + } + } + else + { + prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount); + if (null != prices && 0 != prices.Count) + { + DateGenerator dateGenerator = new DateGenerator(); + DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30); + insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate); + } + } + companyName = PricingDA.GetNameForSymbol(selectedSymbol); + bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices); + CreateCompositeDataSources(); + }); + workerTask.ContinueWith((continuation) => + { + base.OnPropertyChanged("K"); + base.OnPropertyChanged("KL1"); + base.OnPropertyChanged("L"); + base.OnPropertyChanged("LP1"); + base.OnPropertyChanged("High"); + base.OnPropertyChanged("Low"); + base.OnPropertyChanged("Close"); + base.OnPropertyChanged("SMAN"); + base.OnPropertyChanged("Volume"); + base.OnPropertyChanged("LeastSquares"); + base.OnPropertyChanged("GraphTitle"); + base.OnPropertyChanged("Title"); + + base.OnPropertyChanged("TradePoints"); + base.OnPropertyChanged("ZeroPoint"); + base.OnPropertyChanged("StopLimits"); + + base.OnPropertyChanged("TradePointMarkers"); + base.OnPropertyChanged("ZeroPointMarkers"); + base.OnPropertyChanged("StopLimitMarkers"); + +// base.OnPropertyChanged("ZeroPointMarkersTextMarkers"); + + + base.OnPropertyChanged("InsiderTransactionPointDisposedSmall"); + base.OnPropertyChanged("InsiderTransactionPointDisposedMedium"); + base.OnPropertyChanged("InsiderTransactionPointDisposedLarge"); + + base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall"); + base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium"); + base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge"); + + base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall"); + base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium"); + base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge"); + + base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall"); + base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium"); + base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge"); + IsBusy = false; + }); + } + else if (eventArgs.PropertyName.Equals("SelectedWatchList")) + { + IsBusy = true; + Task workerTask = Task.Factory.StartNew(() => + { + if (selectedWatchList.Equals(Constants.CONST_ALL)) + { + symbols.Clear(); + symbols.AddRange(SymbolCache.GetInstance().GetSymbols()); + } + else + { + symbols.Clear(); + symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList)); + } + }); + workerTask.ContinueWith((continuation) => + { + IsBusy = false; + base.OnPropertyChanged("Symbols"); + }); + } } - } + + // ************************************************* C O M P O S I T E D A T A S O U R C E S ******************************************** + + public CompositeDataSource K + { + get + { + return compositeDataSourceK; + } + } + public CompositeDataSource KL1 + { + get + { + return compositeDataSourceKL1; + } + } + + public CompositeDataSource L + { + get + { + return compositeDataSourceL; + } + } + public CompositeDataSource LP1 + { + get + { + return compositeDataSourceLP1; + } + } + public CompositeDataSource High + { + get + { + return compositeDataSourceHigh; + } + } + public CompositeDataSource Low + { + get + { + return compositeDataSourceLow; + } + } + public CompositeDataSource Close + { + get + { + return compositeDataSourceClose; + } + } + public CompositeDataSource SMAN + { + get + { + return compositeDataSourceSMAN; + } + } + public CompositeDataSource Volume + { + get + { + return compositeDataSourceVolume; + } + } + + public CompositeDataSource LeastSquares + { + get + { + if (!useLeastSquaresFit || null == bollingerBands) return Empty(); + return compositeDataSourceLeastSquares; + } + } + + public CompositeDataSource TradePoints + { + get + { + if (!showTradeLabels) return Empty(); + return compositeDataSourceTradePoints; + } + } + + public CompositeDataSource ZeroPoint + { + get + { + if (!showTradeLabels) return Empty(); + return compositeDataSourceZeroPoint; + } + } + + public CompositeDataSource StopLimits + { + get + { + if (!showTradeLabels) return Empty(); + return compositeDataSourceStopLimit; + } + } + + public CompositeDataSource InsiderTransactionPointDisposedSmall + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointDisposedSmall; + } + } + + public CompositeDataSource InsiderTransactionPointDisposedMedium + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointDisposedMedium; + } + } + + public CompositeDataSource InsiderTransactionPointDisposedLarge + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointDisposedLarge; + } + } + + public CompositeDataSource InsiderTransactionPointAcquiredSmall + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointAcquiredSmall; + } + } + + public CompositeDataSource InsiderTransactionPointAcquiredMedium + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointAcquiredMedium; + } + } + + public CompositeDataSource InsiderTransactionPointAcquiredLarge + { + get + { + if (!showInsiderTransactions) return Empty(); + return compositeDataSourceInsiderTransactionPointAcquiredLarge; + } + } + + // ******************************************************** M A R K E R S ************************************************** + + public IImage StopLimitMarkers + { + get + { + if (!showTradeLabels) return null; + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleUp); + } + } + + /// + /// This is just a single marker + /// + public IImage ZeroPointMarkers + { + get + { + if (!showTradeLabels) return null; + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.BlueTriangleUp); + } + } + + // public IImage ZeroPointMarkersTextMarkers + // { + // get + // { + // return TextMarkerImageGenerator.GenerateImage(64,64,SKColors.Red); + // } + // } + + /// + /// This is just a single marker + /// + // public IImage ZeroPointMarkersTextMarkers + // { + // get + // { + // if (null == zeroPrice || !showTradeLabels) return null; + // StringBuilder sb = new StringBuilder(); + // sb.Append("Even "); + // sb.Append(Utility.FormatCurrency(zeroPrice.Close)); + // Price latestPrice = prices[0]; + // double parityOffsetPercent = (latestPrice.Close - zeroPrice.Close) / zeroPrice.Close; + // sb.Append("(").Append(parityOffsetPercent < 0 ? "" : "+").Append(Utility.FormatPercent(parityOffsetPercent)).Append(")"); + // return TextMarkerImageGenerator.GenerateImage(sb.ToString()); + // } + // } public IImage TradePointMarkers { get { if (!showTradeLabels) return null; - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.DarkBlueTriangleUp); - } - } - - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersDisposedSmall - { - get - { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.YellowTriangleUp); } } - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersDisposedMedium - { - get + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersDisposedSmall { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); - } - } - - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersDisposedLarge - { - get - { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); - } - } - - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersAcquiredSmall - { - get - { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); - } - } - - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersAcquiredMedium - { - get - { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); - } - } - - /// - /// This size is controlled in the XAML - /// - public IImage InsiderTransactionPointMarkersAcquiredLarge - { - get - { - return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); - } - } - - // ********************************************************************************************************************************************* - public void CreateCompositeDataSources() - { - if (null == prices || 0 == prices.Count) return; - double minClose = (from Price price in prices select price.Close).Min(); - - // get the maximum date in the bollinger band series - DateTime maxBollingerDate = (from BollingerBandElement bollingerBandElement in bollingerBands select bollingerBandElement.Date).Max(); - // ensure that the insider transactions are clipped to the bollingerband max date. There are some items in insider transaction summaries (options dated in the future) that will throw the graphic out of proportion - InsiderTransactionSummaries disposedSummaries = new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed < 0 && insiderTransactionSummary.TransactionDate.Date <= maxBollingerDate select insiderTransactionSummary).ToList()); - InsiderTransactionSummaries acquiredSummaries = new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed > 0 && insiderTransactionSummary.TransactionDate.Date <= maxBollingerDate select insiderTransactionSummary).ToList()); - - BinCollection disposedSummariesBin = BinHelper.CreateBins(new BinItems(disposedSummaries), 3); - BinCollection acquiredSummariesBin = BinHelper.CreateBins(new BinItems(acquiredSummaries), 3); - - compositeDataSourceZeroPoint = GainLossModel.Price(zeroPrice); - - if (null != stopLimits) - { - compositeDataSourceStopLimit = StopLimitCompositeModel.CreateCompositeDataSource(stopLimits); - } - else if (null != stopLimit && null != zeroPrice) - { - compositeDataSourceStopLimit = GainLossModel.CreateCompositeDataSource(zeroPrice.Date, stopLimit.StopPrice); + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); + } } - compositeDataSourceInsiderTransactionPointDisposedSmall = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[2]), minClose); - compositeDataSourceInsiderTransactionPointDisposedMedium = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[1]), minClose); - compositeDataSourceInsiderTransactionPointDisposedLarge = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[0]), minClose); - compositeDataSourceInsiderTransactionPointAcquiredSmall = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[0]), minClose); - compositeDataSourceInsiderTransactionPointAcquiredMedium = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[1]), minClose); - compositeDataSourceInsiderTransactionPointAcquiredLarge = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[2]), minClose); - - compositeDataSourceK = BollingerBandModel.K(bollingerBands); - compositeDataSourceKL1 = BollingerBandModel.KL1(bollingerBands); - compositeDataSourceL = BollingerBandModel.L(bollingerBands); - compositeDataSourceLP1 = BollingerBandModel.LP1(bollingerBands); - compositeDataSourceHigh = BollingerBandModel.High(bollingerBands); - compositeDataSourceLow = BollingerBandModel.Low(bollingerBands); - compositeDataSourceClose = BollingerBandModel.Close(bollingerBands); - compositeDataSourceSMAN = BollingerBandModel.SMAN(bollingerBands); - compositeDataSourceVolume = BollingerBandModel.Volume(bollingerBands); - - compositeDataSourceLeastSquares = BollingerBandModel.LeastSquares(bollingerBands); - - compositeDataSourceTradePoints = PortfolioTradeModel.PortfolioTrades(portfolioTradesLots); - } - - private void InitializeData() - { - - insiderTransactionSummaries = null; - zeroPrice = null; - prices = null; - portfolioTrades = null; - portfolioTradesLots = null; - stopLimit = null; - } - - private void InitializeDataSources() - { - compositeDataSourceStopLimit = Empty(); - compositeDataSourceZeroPoint = Empty(); - - compositeDataSourceInsiderTransactionPointDisposedSmall = Empty(); - compositeDataSourceInsiderTransactionPointDisposedMedium = Empty(); - compositeDataSourceInsiderTransactionPointDisposedLarge = Empty(); - - compositeDataSourceInsiderTransactionPointAcquiredSmall = Empty(); - compositeDataSourceInsiderTransactionPointAcquiredMedium = Empty(); - compositeDataSourceInsiderTransactionPointAcquiredLarge = Empty(); - - compositeDataSourceK = Empty(); - compositeDataSourceKL1 = Empty(); - compositeDataSourceL = Empty(); - compositeDataSourceLP1 = Empty(); - compositeDataSourceHigh = Empty(); - compositeDataSourceLow = Empty(); - compositeDataSourceClose = Empty(); - compositeDataSourceSMAN = Empty(); - compositeDataSourceVolume = Empty(); - compositeDataSourceLeastSquares = Empty(); - compositeDataSourceTradePoints = Empty(); - } - - private static CompositeDataSource Empty() - { - return new CompositeDataSource() + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersDisposedMedium { - DataAdapter = new SortedDateTimeDataAdapter() - }; + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); + } + } + + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersDisposedLarge + { + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.RedTriangleDown); + } + } + + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersAcquiredSmall + { + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); + } + } + + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersAcquiredMedium + { + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); + } + } + + /// + /// This size is controlled in the XAML + /// + public IImage InsiderTransactionPointMarkersAcquiredLarge + { + get + { + return ImageCache.GetInstance().GetImage(ImageCache.ImageType.GreenTriangleUp); + } + } + + // ********************************************************************************************************************************************* + public void CreateCompositeDataSources() + { + if (null == prices || 0 == prices.Count) return; + double minClose = (from Price price in prices select price.Close).Min(); + + // get the maximum date in the bollinger band series + DateTime maxBollingerDate = (from BollingerBandElement bollingerBandElement in bollingerBands select bollingerBandElement.Date).Max(); + // ensure that the insider transactions are clipped to the bollingerband max date. There are some items in insider transaction summaries (options dated in the future) that will throw the graphic out of proportion + InsiderTransactionSummaries disposedSummaries = new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed < 0 && insiderTransactionSummary.TransactionDate.Date <= maxBollingerDate select insiderTransactionSummary).ToList()); + InsiderTransactionSummaries acquiredSummaries = new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed > 0 && insiderTransactionSummary.TransactionDate.Date <= maxBollingerDate select insiderTransactionSummary).ToList()); + + BinCollection disposedSummariesBin = BinHelper.CreateBins(new BinItems(disposedSummaries), 3); + BinCollection acquiredSummariesBin = BinHelper.CreateBins(new BinItems(acquiredSummaries), 3); + + compositeDataSourceZeroPoint = GainLossModel.Price(zeroPrice); + + if (null != stopLimits) + { + compositeDataSourceStopLimit = StopLimitCompositeModel.CreateCompositeDataSource(stopLimits); + } + else if (null != stopLimit && null != zeroPrice) + { + compositeDataSourceStopLimit = GainLossModel.CreateCompositeDataSource(zeroPrice.Date, stopLimit.StopPrice); + } + + compositeDataSourceInsiderTransactionPointDisposedSmall = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[2]), minClose); + compositeDataSourceInsiderTransactionPointDisposedMedium = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[1]), minClose); + compositeDataSourceInsiderTransactionPointDisposedLarge = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[0]), minClose); + compositeDataSourceInsiderTransactionPointAcquiredSmall = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[0]), minClose); + compositeDataSourceInsiderTransactionPointAcquiredMedium = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[1]), minClose); + compositeDataSourceInsiderTransactionPointAcquiredLarge = InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[2]), minClose); + + compositeDataSourceK = BollingerBandModel.K(bollingerBands); + compositeDataSourceKL1 = BollingerBandModel.KL1(bollingerBands); + compositeDataSourceL = BollingerBandModel.L(bollingerBands); + compositeDataSourceLP1 = BollingerBandModel.LP1(bollingerBands); + compositeDataSourceHigh = BollingerBandModel.High(bollingerBands); + compositeDataSourceLow = BollingerBandModel.Low(bollingerBands); + compositeDataSourceClose = BollingerBandModel.Close(bollingerBands); + compositeDataSourceSMAN = BollingerBandModel.SMAN(bollingerBands); + compositeDataSourceVolume = BollingerBandModel.Volume(bollingerBands); + + compositeDataSourceLeastSquares = BollingerBandModel.LeastSquares(bollingerBands); + + compositeDataSourceTradePoints = PortfolioTradeModel.PortfolioTrades(portfolioTradesLots); + } + + private void InitializeData() + { + + insiderTransactionSummaries = null; + zeroPrice = null; + prices = null; + portfolioTrades = null; + portfolioTradesLots = null; + stopLimit = null; + } + + private void InitializeDataSources() + { + compositeDataSourceStopLimit = Empty(); + compositeDataSourceZeroPoint = Empty(); + + compositeDataSourceInsiderTransactionPointDisposedSmall = Empty(); + compositeDataSourceInsiderTransactionPointDisposedMedium = Empty(); + compositeDataSourceInsiderTransactionPointDisposedLarge = Empty(); + + compositeDataSourceInsiderTransactionPointAcquiredSmall = Empty(); + compositeDataSourceInsiderTransactionPointAcquiredMedium = Empty(); + compositeDataSourceInsiderTransactionPointAcquiredLarge = Empty(); + + compositeDataSourceK = Empty(); + compositeDataSourceKL1 = Empty(); + compositeDataSourceL = Empty(); + compositeDataSourceLP1 = Empty(); + compositeDataSourceHigh = Empty(); + compositeDataSourceLow = Empty(); + compositeDataSourceClose = Empty(); + compositeDataSourceSMAN = Empty(); + compositeDataSourceVolume = Empty(); + compositeDataSourceLeastSquares = Empty(); + compositeDataSourceTradePoints = Empty(); + } + + private static CompositeDataSource Empty() + { + return new CompositeDataSource() + { + DataAdapter = new SortedDateTimeDataAdapter() + }; + } } - } } diff --git a/PortfolioManager/Views/BollingerBandView.axaml b/PortfolioManager/Views/BollingerBandView.axaml index fd1f3df..222f879 100644 --- a/PortfolioManager/Views/BollingerBandView.axaml +++ b/PortfolioManager/Views/BollingerBandView.axaml @@ -6,6 +6,7 @@ xmlns:vw="using:PortfolioManager.Views" xmlns:md="using:PortfolioManager.Models" xmlns:local="using:PortfolioManager.UIUtils" + xmlns:localmxc="using:Eremex.AvaloniaUI.Charts" xmlns:li="using:LoadingIndicators.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" xmlns:mxc="https://schemas.eremexcontrols.net/avalonia/charts" @@ -82,7 +83,8 @@ - + + @@ -156,10 +158,17 @@ - + + + + @@ -203,6 +212,7 @@ + diff --git a/PortfolioManager/Views/CMMomentumView.axaml b/PortfolioManager/Views/CMMomentumView.axaml index 9ed8d3a..64c18f5 100644 --- a/PortfolioManager/Views/CMMomentumView.axaml +++ b/PortfolioManager/Views/CMMomentumView.axaml @@ -84,6 +84,17 @@ + + + + + + + + + + + diff --git a/PortfolioManager/Views/CMTrendView.axaml b/PortfolioManager/Views/CMTrendView.axaml index 1640544..0e616eb 100644 --- a/PortfolioManager/Views/CMTrendView.axaml +++ b/PortfolioManager/Views/CMTrendView.axaml @@ -84,6 +84,17 @@ + + + + + + + + + + + diff --git a/PortfolioManager/Views/MGSHMomentumView.axaml b/PortfolioManager/Views/MGSHMomentumView.axaml index 4b9618d..0c155a8 100644 --- a/PortfolioManager/Views/MGSHMomentumView.axaml +++ b/PortfolioManager/Views/MGSHMomentumView.axaml @@ -100,6 +100,17 @@ + + + + + + + + + + + diff --git a/PortfolioManager/Views/MainWindow.axaml b/PortfolioManager/Views/MainWindow.axaml index 00da1d8..bb4263b 100644 --- a/PortfolioManager/Views/MainWindow.axaml +++ b/PortfolioManager/Views/MainWindow.axaml @@ -6,6 +6,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:HyperText.Avalonia.Controls;assembly=HyperText.Avalonia" xmlns:mxc="https://schemas.eremexcontrols.net/avalonia/charts" + xmlns:mx="clr-namespace:Eremex.AvaloniaUI.Controls;assembly=Eremex.Avalonia.Controls" + xmlns:mxe="clr-namespace:Eremex.AvaloniaUI.Controls.Editors;assembly=Eremex.Avalonia.Controls" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="PortfolioManager.Views.MainWindow" x:DataType="vm:MainWindowViewModel" @@ -130,7 +132,7 @@ - + @@ -153,7 +155,7 @@ - + diff --git a/PortfolioManager/Views/MomentumView.axaml b/PortfolioManager/Views/MomentumView.axaml index 9490238..4ddee9b 100644 --- a/PortfolioManager/Views/MomentumView.axaml +++ b/PortfolioManager/Views/MomentumView.axaml @@ -69,8 +69,6 @@ - - @@ -84,6 +82,17 @@ + + + + + + + + + + +