448 lines
14 KiB
C#
448 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Input;
|
|
using MarketData;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.Helper;
|
|
using MarketData.DataAccess;
|
|
using MarketData.Utils;
|
|
using TradeBlotter.DataAccess;
|
|
using TradeBlotter.Command;
|
|
using TradeBlotter.Model;
|
|
|
|
namespace TradeBlotter.ViewModels
|
|
{
|
|
public class TradeEntryViewModel : WorkspaceViewModel
|
|
{
|
|
private BlotterTradeModel trade = null;
|
|
private StopLimit stopLimit;
|
|
private readonly TradeRepository tradeRepository;
|
|
private RelayCommand saveCommand;
|
|
private String statusText="";
|
|
|
|
public TradeEntryViewModel(BlotterTradeModel trade,TradeRepository tradeRepository)
|
|
{
|
|
base.DisplayName="TradeEntry";
|
|
this.trade=trade;
|
|
this.tradeRepository=tradeRepository;
|
|
if(PortfolioDA.HasStopLimit(trade.Symbol)) stopLimit=PortfolioDA.GetStopLimit(trade.Symbol);
|
|
PropertyChanged+=OnTradeEntryViewModelPropertyChanged;
|
|
UpdateProperties();
|
|
}
|
|
public override SaveParameters GetSaveParameters()
|
|
{
|
|
return null;
|
|
}
|
|
public override void SetSaveParameters(SaveParameters saveParameters)
|
|
{
|
|
}
|
|
public override bool CanPersist()
|
|
{
|
|
return false;
|
|
}
|
|
public void SetActiveTrade(BlotterTradeModel trade)
|
|
{
|
|
this.trade = trade;
|
|
UpdateProperties();
|
|
}
|
|
private void UpdateProperties()
|
|
{
|
|
base.OnPropertyChanged("Symbol");
|
|
base.OnPropertyChanged("Price");
|
|
base.OnPropertyChanged("CompanyName");
|
|
base.OnPropertyChanged("TradeDate");
|
|
base.OnPropertyChanged("SelectedTradeType");
|
|
base.OnPropertyChanged("SelectedAccount");
|
|
base.OnPropertyChanged("SelectedStatus");
|
|
base.OnPropertyChanged("TradeId");
|
|
base.OnPropertyChanged("Shares");
|
|
base.OnPropertyChanged("Exposure");
|
|
base.OnPropertyChanged("AvailableCash");
|
|
}
|
|
private void OnTradeEntryViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
|
|
{
|
|
if (eventArgs.PropertyName.Equals("Symbol"))
|
|
{
|
|
if(null!=trade && null!=trade.Symbol)
|
|
{
|
|
if(-1==trade.TradeId) // only suggest the price for a new trade (i.e.) a trade that has not yet been assigned a tradeid
|
|
{
|
|
Price price=PricingDA.GetPrice(trade.Symbol,trade.TradeDate);
|
|
if(null==price) price=PricingDA.GetPrice(trade.Symbol);
|
|
if(null!=price)trade.Price=price.Close;
|
|
base.OnPropertyChanged("Price");
|
|
}
|
|
String companyName = PricingDA.GetNameForSymbol(trade.Symbol);
|
|
if (null != companyName)
|
|
{
|
|
trade.CompanyName = companyName;
|
|
base.OnPropertyChanged("CompanyName");
|
|
}
|
|
}
|
|
}
|
|
else if (eventArgs.PropertyName.Equals("TradeDate"))
|
|
{
|
|
base.OnPropertyChanged("Price");
|
|
}
|
|
else if (eventArgs.PropertyName.Equals("SelectedAccount") || eventArgs.PropertyName.Equals("Shares") || eventArgs.PropertyName.Equals("Price") || eventArgs.PropertyName.Equals("SellPrice"))
|
|
{
|
|
base.OnPropertyChanged("AvailableCash");
|
|
}
|
|
}
|
|
public String TradeId
|
|
{
|
|
get { return -1==trade.TradeId?Constants.CONST_DASHES:trade.TradeId.ToString(); }
|
|
set { ;}
|
|
}
|
|
public List<String> TradeTypeOptions
|
|
{
|
|
get { return new List<String>() { "Buy", "Sell" }; }
|
|
}
|
|
// Buy/Sell
|
|
public String SelectedTradeType
|
|
{
|
|
get
|
|
{
|
|
if (null == trade.BuySell) return null;
|
|
else if (trade.BuySell.Equals("S")) return "Sell";
|
|
else if (trade.BuySell.Equals("B")) return "Buy";
|
|
else return null;
|
|
}
|
|
set
|
|
{
|
|
if(String.IsNullOrEmpty(value)) return;
|
|
trade.BuySell = value.Equals("Buy") ? "B" : "S";
|
|
if (trade.BuySell.Equals("B"))
|
|
{
|
|
trade.Status = "OPEN";
|
|
trade.SellPrice = double.NaN;
|
|
trade.SellDate = Utility.Epoch;
|
|
base.OnPropertyChanged("SellPrice");
|
|
base.OnPropertyChanged("SellDate");
|
|
}
|
|
else
|
|
{
|
|
trade.Status = "CLOSED";
|
|
}
|
|
base.OnPropertyChanged("SelectedStatus");
|
|
base.OnPropertyChanged("SelectedTradeType");
|
|
}
|
|
}
|
|
// ***************************************** A C C O U N T ***************************
|
|
public List<String> AccountOptions
|
|
{
|
|
get { return PortfolioDA.GetAccounts(); }
|
|
}
|
|
public String SelectedAccount
|
|
{
|
|
get
|
|
{
|
|
return null==trade.Account||trade.Account.Equals("") ? null : trade.Account;
|
|
}
|
|
set
|
|
{
|
|
trade.Account = value;
|
|
base.OnPropertyChanged("SelectedAccount");
|
|
}
|
|
}
|
|
//************************************************************************************
|
|
public List<String> TradeStatusOptions
|
|
{
|
|
get {return new List<String>(){"OPEN","CLOSED"}; }
|
|
}
|
|
public String SelectedStatus
|
|
{
|
|
get
|
|
{
|
|
return null==trade.Status||trade.Status.Equals("") ? null : trade.Status;
|
|
}
|
|
}
|
|
public DateTime TradeDate
|
|
{
|
|
get { return trade.TradeDate; }
|
|
set
|
|
{
|
|
trade.TradeDate = value;
|
|
Price price = null;
|
|
if (!Utility.IsEpoch(trade.TradeDate) && !trade.TradeDate.Date.Equals(DateTime.Now.Date))
|
|
{
|
|
price = PricingDA.GetPrice(trade.Symbol, trade.TradeDate);
|
|
}
|
|
else
|
|
{
|
|
price = MarketDataHelper.GetLatestPrice(trade.Symbol);
|
|
if (null == price) price = PricingDA.GetPrice(trade.Symbol);
|
|
}
|
|
if (null != price)
|
|
{
|
|
trade.Price = price.Close;
|
|
base.OnPropertyChanged("TradeDate");
|
|
}
|
|
}
|
|
}
|
|
public String Symbol
|
|
{
|
|
get { return trade.Symbol; }
|
|
set
|
|
{
|
|
trade.Symbol = value;
|
|
trade.Symbol = trade.Symbol.ToUpper();
|
|
base.OnPropertyChanged("Symbol");
|
|
}
|
|
}
|
|
public double Shares
|
|
{
|
|
get
|
|
{
|
|
return trade.Shares;
|
|
}
|
|
set
|
|
{
|
|
trade.Shares = value;
|
|
base.OnPropertyChanged("Shares");
|
|
base.OnPropertyChanged("Exposure");
|
|
}
|
|
}
|
|
public String CompanyName
|
|
{
|
|
get { return trade.CompanyName; }
|
|
set
|
|
{
|
|
trade.CompanyName = value;
|
|
base.OnPropertyChanged("CompanyName");
|
|
}
|
|
}
|
|
public String Exposure
|
|
{
|
|
get { return Utility.FormatCurrency(trade.Exposure); }
|
|
set { ;}
|
|
}
|
|
public String Price
|
|
{
|
|
get
|
|
{
|
|
return Utility.FormatPrice(trade.Price);
|
|
}
|
|
set
|
|
{
|
|
trade.Price = Utility.ParseCurrency(value);
|
|
base.OnPropertyChanged("Price");
|
|
base.OnPropertyChanged("Exposure");
|
|
}
|
|
}
|
|
public String StopLimit
|
|
{
|
|
get
|
|
{
|
|
if(null==stopLimit)return Constants.NA;
|
|
return Utility.FormatCurrency(stopLimit.StopPrice,2);
|
|
}
|
|
set
|
|
{
|
|
if(String.IsNullOrEmpty(value))stopLimit=null;
|
|
else
|
|
{
|
|
if(null==stopLimit)
|
|
{
|
|
stopLimit=new StopLimit();
|
|
stopLimit.Symbol=trade.Symbol;
|
|
stopLimit.StopType=StopLimitConstants.STOP_QUOTE;
|
|
}
|
|
stopLimit.StopPrice=Utility.ParseCurrency(value);
|
|
stopLimit.Active=1;
|
|
}
|
|
base.OnPropertyChanged("StopLimit");
|
|
}
|
|
}
|
|
public String SellPrice
|
|
{
|
|
get
|
|
{
|
|
return Utility.FormatPrice(trade.SellPrice);
|
|
}
|
|
set
|
|
{
|
|
if (!trade.Status.Equals("CLOSED")) return;
|
|
trade.SellPrice = Utility.ParseCurrency(value);
|
|
base.OnPropertyChanged("SellPrice");
|
|
}
|
|
}
|
|
public DateTime? SellDate
|
|
{
|
|
get
|
|
{
|
|
if (Utility.IsEpoch(trade.SellDate)) return null;
|
|
return trade.SellDate;
|
|
}
|
|
set
|
|
{
|
|
trade.SellDate = value.Value;
|
|
base.OnPropertyChanged("SellDate");
|
|
}
|
|
}
|
|
public String Commission
|
|
{
|
|
get
|
|
{
|
|
return Utility.FormatCurrency(trade.Commission);
|
|
}
|
|
set
|
|
{
|
|
trade.Commission = Utility.ParseCurrency(value);
|
|
}
|
|
}
|
|
public String Status
|
|
{
|
|
get
|
|
{
|
|
return statusText;
|
|
}
|
|
set
|
|
{
|
|
if(!String.IsNullOrEmpty(value))
|
|
{
|
|
statusText = value;
|
|
base.OnPropertyChanged("Status");
|
|
}
|
|
}
|
|
}
|
|
public String AvailableCash
|
|
{
|
|
get
|
|
{
|
|
double availableCash = CashDA.GetBalance();
|
|
if(null!=SelectedAccount)availableCash=CashDA.GetBalance(SelectedAccount);
|
|
if (null == trade.BuySell) return Utility.FormatCurrency(availableCash);
|
|
if(trade.BuySell.Equals("S") && double.IsNaN(trade.SellPrice) && double.IsNaN(trade.Shares))return Utility.FormatCurrency(availableCash);
|
|
if(trade.BuySell.Equals("B") && double.IsNaN(trade.Price) && double.IsNaN(trade.Shares)) return Utility.FormatCurrency(availableCash);
|
|
if(trade.BuySell.Equals("S")) availableCash += trade.SellPrice * trade.Shares;
|
|
if(trade.BuySell.Equals("B")) availableCash -= trade.Price * trade.Shares;
|
|
if (!double.IsNaN(trade.Commission)) availableCash -= trade.Commission;
|
|
return Utility.FormatCurrency(availableCash);
|
|
}
|
|
}
|
|
// *******************************************************************************************************
|
|
// ****************************************** S A V E C O M M A N D *************************************
|
|
// *******************************************************************************************************
|
|
public ICommand SaveCommand
|
|
{
|
|
get
|
|
{
|
|
if(saveCommand == null)
|
|
{
|
|
saveCommand = new RelayCommand(param => this.Save(),param => this.CanSave);
|
|
}
|
|
return saveCommand;
|
|
}
|
|
}
|
|
public void Save()
|
|
{
|
|
if (!tradeRepository.ContainsTrade(trade))
|
|
{
|
|
tradeRepository.AddTrade(trade);
|
|
WatchListDA.AddToWatchList(trade.Symbol);
|
|
base.OnPropertyChanged("TradeId");
|
|
base.OnPropertyChanged("DisplayName");
|
|
statusText = "Save completed.";
|
|
}
|
|
else
|
|
{
|
|
tradeRepository.UpdateTrade(trade);
|
|
statusText="Update completed.";
|
|
}
|
|
UpdateStopLimit();
|
|
base.OnPropertyChanged("Status");
|
|
}
|
|
private void UpdateStopLimit()
|
|
{
|
|
// if(null==stopLimit && PortfolioDA.HasStopLimit(trade.Symbol))PortfolioDA.DeleteStopLimit(trade.Symbol);
|
|
if(null==stopLimit)PortfolioDA.DeleteStopLimit(trade.Symbol);
|
|
else if(null!=stopLimit)PortfolioDA.InsertUpdateStopLimit(stopLimit);
|
|
}
|
|
public bool CanSave
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
DateGenerator dateGenerator=new DateGenerator();
|
|
if (null == trade.TradeDate || Utility.IsEpoch(trade.TradeDate))
|
|
{
|
|
statusText=String.Format("Invalid Trade Date.");
|
|
return false;
|
|
}
|
|
if (null == trade.BuySell || !(trade.BuySell.ToUpper().Equals("B") || trade.BuySell.ToUpper().Equals("S")))
|
|
{
|
|
statusText=String.Format("BuySell must contain either BUY or SELL.");
|
|
return false;
|
|
}
|
|
if (null == trade.Status || (!trade.Status.Equals("OPEN") && !trade.Status.Equals("CLOSED")))
|
|
{
|
|
statusText=String.Format("Status must contain either OPEN or CLOSED.");
|
|
return false;
|
|
}
|
|
if(null!=trade.Status&&(trade.Status.Equals("CLOSED")||trade.BuySell.ToUpper().Equals("S"))&&double.IsNaN(trade.SellPrice))
|
|
{
|
|
statusText="Close position requires a valid selling price.";
|
|
return false;
|
|
}
|
|
if(null!=trade.Status&&(trade.Status.Equals("CLOSED") || trade.BuySell.ToUpper().Equals("S")) && Utility.IsEpoch(trade.SellDate))
|
|
{
|
|
statusText="Close position requires a valid sell date.";
|
|
return false;
|
|
}
|
|
if(null!=trade.Status&&(trade.Status.Equals("OPEN")||trade.BuySell.ToUpper().Equals("B"))&&!Utility.IsEpoch(trade.SellDate))
|
|
{
|
|
statusText="An open position cannot contain a sell date.";
|
|
return false;
|
|
}
|
|
if(null==trade.Symbol)
|
|
{
|
|
statusText="A trade entry must contain a valid symbol.";
|
|
return false;
|
|
}
|
|
if (0 == trade.Shares)
|
|
{
|
|
statusText="A trade entry must contain a number of shares.";
|
|
return false;
|
|
}
|
|
if (null == trade.Account || "".Equals(trade.Account))
|
|
{
|
|
statusText="A trade entry must contain a valid account.";
|
|
return false;
|
|
}
|
|
if (0 == trade.Price)
|
|
{
|
|
statusText="A trade entry must contain a valid price that is greater than zero.";
|
|
return false;
|
|
}
|
|
if(!Utility.IsEpoch(trade.TradeDate) && !dateGenerator.IsMarketOpen(trade.TradeDate))
|
|
{
|
|
statusText=String.Format("Trade date must be a valid market date. {0} is a holiday or weekend. ",Utility.DateTimeToStringMMSDDSYYYY(trade.TradeDate));
|
|
return false;
|
|
}
|
|
if(!Utility.IsEpoch(trade.SellDate)&&!dateGenerator.IsMarketOpen(trade.SellDate))
|
|
{
|
|
statusText=String.Format("Sell date must be a valid market date. {0} is a holiday or weekend. ",Utility.DateTimeToStringMMSDDSYYYY(trade.SellDate));
|
|
return false;
|
|
}
|
|
statusText="Form is validated.";
|
|
return true;
|
|
}
|
|
catch(Exception exception)
|
|
{
|
|
statusText=exception.ToString();
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
base.OnPropertyChanged("Status");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|