381 lines
13 KiB
C#
381 lines
13 KiB
C#
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<TradeViewModel> 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<BlotterTradeModel> repositoryTrades=tradeRepository.GetTrades();
|
|
repositoryTrades=repositoryTrades.OrderByDescending(x=>x.TradeDate).ThenBy(x=>x.TradeId).ToList();
|
|
List<TradeViewModel> 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<TradeViewModel>(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;
|
|
}
|
|
}
|
|
}
|
|
}
|