using System; using System.Windows.Input; using System.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Threading.Tasks; using System.Windows.Threading; using System.Windows; using System.Linq; using System.Text; using MarketData; using MarketData.Utils; using MarketData.DataAccess; using TradeBlotter.DataAccess; using TradeBlotter.Command; using TradeBlotter.UIUtils; using TradeBlotter.Cache; using System.Windows.Forms; using MarketData.MarketDataModel; using TradeBlotter.Model; using MarketData.Cache; namespace TradeBlotter.ViewModels { public delegate void EditHandler(int tradeId); // so we can post the event back up to the main window public delegate void DeleteHandler(int tradeId); // so we can post the event back up to the main window public class BlotterViewModel : WorkspaceViewModel { private static readonly String LOADING_TRADES = "Loading Trades..."; private static readonly String REFRESHING_PRICES = "Refreshing Prices..."; private readonly TradeRepository tradeRepository; private PortfolioTrades portfolioTrades; double annualYieldAmt=double.NaN; double annualYieldPcnt=double.NaN; private RelayCommand refreshCommand; private RelayCommand deleteCommand; private RelayCommand editCommand; private EditHandler editHandler; private DeleteHandler deleteHandler; private TradeViewModel selectedItem = null; private bool busyIndicator = false; private String busyContent = LOADING_TRADES; private bool gridChanged = false; public BlotterViewModel(TradeRepository tradeRepository,EditHandler editHandler,DeleteHandler deleteHandler) { this.editHandler = editHandler; this.deleteHandler = deleteHandler; base.DisplayName = "TradeView"; this.tradeRepository = tradeRepository; this.CreateAllTrades(); tradeRepository.TradeAdded += this.OnTradeAddedToRepository; } public override SaveParameters GetSaveParameters() { return null; } public override void SetSaveParameters(SaveParameters saveParameters) { } public override bool CanPersist() { return false; } protected override void OnDispose() { } public ObservableCollection AllTrades { get; private set; } public bool BusyIndicator { get { return busyIndicator; } set { busyIndicator = value; base.OnPropertyChanged("BusyIndicator"); } } public String BusyContent { get { return busyContent; } set { busyContent = value; base.OnPropertyChanged("BusyContent"); } } public TradeViewModel SelectedItem { get { return selectedItem; } set { selectedItem = value; foreach (TradeViewModel tvm in this.AllTrades) { tvm.IsSelected = false; } if (null != selectedItem) selectedItem.IsSelected = true; } } private void CreateAllTrades() { BusyIndicator = true; Task workerTask=Task.Factory.StartNew(() => { LoadPortfolioTrades(); List repositoryTrades=tradeRepository.GetTrades(); repositoryTrades=repositoryTrades.OrderByDescending(x=>x.TradeDate).ThenBy(x=>x.TradeId).ToList(); List all = (from trade in repositoryTrades select new TradeViewModel(trade, tradeRepository)).ToList(); double totalMarketValue = 0; foreach (TradeViewModel tradeViewModel in all) { if (!tradeViewModel.IsOpen) continue; totalMarketValue += Utility.ParseCurrency(tradeViewModel.MarketValue); } foreach (TradeViewModel tradeViewModel in all) { tradeViewModel.Weight = Utility.FormatPercent(Utility.ParseCurrency(tradeViewModel.MarketValue) / totalMarketValue); tradeViewModel.PropertyChanged += this.OnTradeViewModelPropertyChanged; } this.AllTrades = new ObservableCollection(all); this.AllTrades.CollectionChanged += this.OnCollectionChanged; }); workerTask.ContinueWith((continuation) => { BusyIndicator = false; base.OnPropertyChanged("AllTrades"); base.OnPropertyChanged("TotalExposure"); base.OnPropertyChanged("TotalMarketValue"); base.OnPropertyChanged("TotalGainLoss"); base.OnPropertyChanged("TotalReturn"); base.OnPropertyChanged("TotalGainLossAll"); base.OnPropertyChanged("TotalReturnAll"); base.OnPropertyChanged("AnnualDividendYieldAmt"); base.OnPropertyChanged("AnnualDividendYieldPcnt"); }); } public void LoadPortfolioTrades() { portfolioTrades=PortfolioDA.GetOpenTrades(); double weightAdjustedDividendYield=portfolioTrades.GetWeightAdjustedDividendYield(); double exposure=portfolioTrades.Exposure(); annualYieldAmt=weightAdjustedDividendYield*exposure; annualYieldPcnt=weightAdjustedDividendYield; } public String TotalExposure { get { if (null == this.AllTrades) return null; var openTrades = from trade in this.AllTrades where trade.IsOpen select trade; return Utility.FormatCurrency(openTrades.Sum(trade => Utility.ParseCurrency(trade.Exposure))); } } public String TotalMarketValue { get { if (null == this.AllTrades) return null; var openTrades = from trade in this.AllTrades where trade.IsOpen select trade; return Utility.FormatCurrency(openTrades.Sum(trade => Utility.ParseCurrency(trade.MarketValue))); } } public String TotalGainLoss { get { if (null == this.AllTrades) return null; var openTrades = from trade in this.AllTrades where trade.IsOpen select trade; return Utility.FormatCurrency(openTrades.Sum(trade => Utility.ParseCurrency(trade.MarketValue) - Utility.ParseCurrency(trade.Exposure))); } } public String TotalReturn { get { if (null == this.AllTrades) return null; var openTrades = from trade in this.AllTrades where trade.IsOpen select trade; double totalExposure = openTrades.Sum(trade => trade.Price * trade.Shares); double totalMarketValue = openTrades.Sum(trade => Utility.ParseCurrency(trade.CurrentPrice) * trade.Shares); return Utility.FormatPercent((totalMarketValue-totalExposure)/totalExposure); } } public String TotalGainLossAll { get { if (null == this.AllTrades) return null; var allTrades = from trade in this.AllTrades select trade; double totalExposure = allTrades.Sum(trade => trade.Price * trade.Shares); double totalMarketValue = allTrades.Sum(trade => Utility.ParseCurrency((trade.IsOpen ? trade.CurrentPrice : trade.SellPrice)) * trade.Shares); return Utility.FormatCurrency(totalMarketValue - totalExposure); } } public String TotalReturnAll { get { if (null == this.AllTrades) return null; var allTrades = from trade in this.AllTrades select trade; double totalExposure = allTrades.Sum(trade => trade.Price * trade.Shares); double totalMarketValue = allTrades.Sum(trade => Utility.ParseCurrency((trade.IsOpen?trade.CurrentPrice:trade.SellPrice))* trade.Shares); return Utility.FormatPercent((totalMarketValue - totalExposure) / totalExposure); } } public String AnnualDividendYieldPcnt { get { return Utility.FormatPercent(annualYieldPcnt); } } public String AnnualDividendYieldAmt { get { return Utility.FormatCurrency(annualYieldAmt); } } private void OnTradeAddedToRepository(Object sender, TradeAddedEventArgs e) { var viewModel = new TradeViewModel(e.NewTrade, tradeRepository); this.AllTrades.Add(viewModel); } private void OnTradeViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { } private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null && e.NewItems.Count != 0) foreach (TradeViewModel tradeVM in e.NewItems) tradeVM.PropertyChanged += this.OnTradeViewModelPropertyChanged; if (e.OldItems != null && e.OldItems.Count != 0) foreach (TradeViewModel tradeVM in e.OldItems) tradeVM.PropertyChanged -= this.OnTradeViewModelPropertyChanged; } public String CompanyDescription { get { if(null== selectedItem || null==selectedItem.Symbol)return "No row selected."; CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(selectedItem.Symbol); if(null==companyProfile || null==companyProfile.Description)return "No description found."; return companyProfile.Description; } } // ************************************************************************************************************************** // ******************************************************** R E F R E S H *************************************************** // ************************************************************************************************************************** public bool GridChanged { get { return gridChanged; } set { gridChanged = value; base.OnPropertyChanged("GridChanged"); } } private void Refresh() { BusyContent = REFRESHING_PRICES; BusyIndicator = true; Dispatcher uiDispatcher = Dispatcher.CurrentDispatcher; // get the UI dispatcher Task workerTask = Task.Factory.StartNew(() => { GBPriceCache.GetInstance().Clear(); foreach (TradeViewModel tvm in this.AllTrades) { tvm.Invalidate(); } }); workerTask.ContinueWith((continuation) => { BusyIndicator = false; BusyContent = LOADING_TRADES; uiDispatcher.Invoke((MethodInvoker)delegate() { foreach (TradeViewModel tvm in this.AllTrades) { tvm.Validate(); } }); base.OnPropertyChanged("TotalMarketValue"); base.OnPropertyChanged("TotalGainLoss"); base.OnPropertyChanged("TotalReturn"); GridChanged = !GridChanged; }); } private bool CanRefresh { get { return true; } } public ICommand RefreshCommand { get { if (refreshCommand == null) { refreshCommand = new RelayCommand(param => this.Refresh(), param => this.CanRefresh); } return refreshCommand; } } // ************************************************************************************************************************** // ******************************************************** E D I T *************************************************** // ************************************************************************************************************************** private void Edit() { TradeViewModel tvmSelected = null; foreach (TradeViewModel tvm in this.AllTrades) { if (tvm.IsSelected) tvmSelected = tvm; } if (null == tvmSelected || null==editHandler) return; editHandler(tvmSelected.TradeId); } private bool CanEdit { get { return selectedItem == null ? false : true; } } public ICommand EditCommand { get { if (editCommand == null) { editCommand = new RelayCommand(param => this.Edit(), param => this.CanEdit); } return editCommand; } } // ************************************************************************************************************************** // ******************************************************** D E L E T E *************************************************** // ************************************************************************************************************************** private void Delete() { TradeViewModel tvmToRemove=null; foreach (TradeViewModel tvm in this.AllTrades) { if (tvm.IsSelected) { tvmToRemove = tvm; break; } } if (null == tvmToRemove) return; string messageBoxText = "This operation cannot be undone, confirm delete trade_id("+tvmToRemove.TradeId+")"; string caption = "eNavigator"; MessageBoxButton button = MessageBoxButton.YesNoCancel; MessageBoxImage icon = MessageBoxImage.Warning; if(MessageBoxResult.Yes!=System.Windows.MessageBox.Show(messageBoxText, caption, button, icon))return; tradeRepository.Remove(tvmToRemove.TradeId); this.AllTrades.Remove(tvmToRemove); base.OnPropertyChanged("TotalMarketValue"); base.OnPropertyChanged("TotalGainLoss"); base.OnPropertyChanged("TotalReturn"); if (null != deleteHandler) deleteHandler(tvmToRemove.TradeId); } private bool CanDelete { get { return true; } } public ICommand DeleteCommand { get { if (deleteCommand == null) { deleteCommand = new RelayCommand(param => this.Delete(), param => this.CanDelete); } return deleteCommand; } } } }