440 lines
17 KiB
C#
440 lines
17 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Media;
|
|
using System.Windows.Input;
|
|
using System.Windows.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Serialization;
|
|
using System.Xml;
|
|
using System.IO;
|
|
using MarketData;
|
|
using MarketData.Numerical;
|
|
using MarketData.Utils;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.Generator;
|
|
using MarketData.DataAccess;
|
|
using TradeBlotter.DataAccess;
|
|
using TradeBlotter.Command;
|
|
using TradeBlotter.Model;
|
|
using TradeBlotter.Cache;
|
|
using Microsoft.Research.DynamicDataDisplay.DataSources;
|
|
|
|
namespace TradeBlotter.ViewModels
|
|
{
|
|
public class OptionsWorksheetViewModel : WorkspaceViewModel
|
|
{
|
|
private const int PRICE_FETCH_INTERVAL_MINS = 2;
|
|
private RelayCommand displayBollingerBandCommand = null;
|
|
private RelayCommand displayMovingAverageCommand = null;
|
|
private Option selectedOption = null;
|
|
private OptionsParams optionsParams = new OptionsParams() { Cashdown = 10000 };
|
|
private String companyName;
|
|
private Price underlierPrice; // this is the price as of the date this record was created.
|
|
private Price currentPrice; // this is the most recent price in the database
|
|
private ObservableCollection<EquityPriceShock> equityPriceShocksCollection = null;
|
|
private bool busyIndicator = false;
|
|
private DispatcherTimer priceTimer = null;
|
|
private Prices prices = null;
|
|
private double transactionGL;
|
|
private bool useRealPrice = false;
|
|
|
|
public OptionsWorksheetViewModel()
|
|
{
|
|
priceTimer = new DispatcherTimer();
|
|
priceTimer.Tick += new EventHandler(TimerHandler);
|
|
priceTimer.Interval = new TimeSpan(0, PRICE_FETCH_INTERVAL_MINS, 0);
|
|
base.DisplayName = "Options Worksheet";
|
|
PropertyChanged += OnViewModelPropertyChanged;
|
|
base.OnPropertyChanged("Title");
|
|
}
|
|
protected override void OnDispose()
|
|
{
|
|
if (null == priceTimer) return;
|
|
priceTimer.Stop();
|
|
}
|
|
private void TimerHandler(Object sender, EventArgs eventArgs)
|
|
{
|
|
if (null == underlierPrice) return;
|
|
Task workerTask = Task.Factory.StartNew(() =>
|
|
{
|
|
currentPrice = PriceCache.GetInstance().GetLatestPrice(underlierPrice.Symbol);
|
|
if (null == currentPrice || null==prices) return;
|
|
if (prices[0].Date.Date.Equals(currentPrice.Date.Date))
|
|
{
|
|
prices[0] = currentPrice;
|
|
}
|
|
else prices.Insert(0, currentPrice);
|
|
});
|
|
workerTask.ContinueWith((continuation) =>
|
|
{
|
|
base.OnPropertyChanged("CurrentPrice");
|
|
base.OnPropertyChanged("CurrentPriceDate");
|
|
base.OnPropertyChanged("Close");
|
|
base.OnPropertyChanged("TransactionGL");
|
|
});
|
|
}
|
|
// ******************************************************************************************** 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();
|
|
|
|
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
|
|
xmlWriterSettings.Indent = false;
|
|
xmlWriterSettings.NewLineHandling = NewLineHandling.None;
|
|
|
|
XmlSerializer optionSerializer = new XmlSerializer(selectedOption.GetType());
|
|
StringBuilder optionString=new StringBuilder();
|
|
XmlWriter optionWriter = XmlWriter.Create(optionString, xmlWriterSettings);
|
|
optionSerializer.Serialize(optionWriter, selectedOption);
|
|
|
|
XmlSerializer underlierPriceSerializer = new XmlSerializer(typeof(Price));
|
|
StringBuilder underlierPriceString = new StringBuilder();
|
|
XmlWriter underlierPriceWriter = XmlWriter.Create(underlierPriceString, xmlWriterSettings);
|
|
underlierPriceSerializer.Serialize(underlierPriceWriter, underlierPrice);
|
|
|
|
saveParams.Add(new KeyValuePair<String, String>("Type", "TradeBlotter.ViewModels.OptionsWorksheetViewModel"));
|
|
saveParams.Add(new KeyValuePair<String, String>("Option", optionString.ToString()));
|
|
saveParams.Add(new KeyValuePair<String, String>("CompanyName", companyName));
|
|
saveParams.Add(new KeyValuePair<String, String>("Price", underlierPriceString.ToString()));
|
|
return saveParams;
|
|
}
|
|
public override void SetSaveParameters(SaveParameters saveParameters)
|
|
{
|
|
try
|
|
{
|
|
String strSelectedOption = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("Option") select item).FirstOrDefault().Value;
|
|
String strLatestPrice = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("Price") select item).FirstOrDefault().Value;
|
|
companyName = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("CompanyName") select item).FirstOrDefault().Value;
|
|
|
|
XmlSerializer optionSerializer = new XmlSerializer(typeof(Option));
|
|
StringReader stringReader = new StringReader(strSelectedOption);
|
|
selectedOption = (Option)optionSerializer.Deserialize(stringReader);
|
|
|
|
XmlSerializer priceSerializer = new XmlSerializer(typeof(Price));
|
|
StringReader priceReader = new StringReader(strLatestPrice);
|
|
underlierPrice = (Price)priceSerializer.Deserialize(priceReader);
|
|
|
|
optionsParams.Symbol = underlierPrice.Symbol;
|
|
optionsParams.Strike = selectedOption.Strike;
|
|
optionsParams.Contracts = (int)Math.Round((optionsParams.Cashdown / underlierPrice.Close) / 100.00, 0);
|
|
optionsParams.Premium = optionsParams.Shares*selectedOption.Bid;
|
|
optionsParams.ExpirationDate = selectedOption.Expiration;
|
|
|
|
// volatility
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
int daysToExpiration = dateGenerator.DaysBetweenActual(optionsParams.ExpirationDate, underlierPrice.Date);
|
|
prices = PricingDA.GetPrices(underlierPrice.Symbol, underlierPrice.Date, daysToExpiration);
|
|
|
|
if(DateTime.Now.Date>=optionsParams.ExpirationDate.Date)currentPrice=PricingDA.GetPrice(underlierPrice.Symbol,optionsParams.ExpirationDate);
|
|
else currentPrice = PriceCache.GetInstance().GetLatestPrice(underlierPrice.Symbol);
|
|
optionsParams.VolatilityDays = daysToExpiration;
|
|
|
|
float[] pricesAr = prices.GetPrices();
|
|
optionsParams.Volatility = Numerics.Volatility(ref pricesAr);
|
|
|
|
if(DateTime.Now.Date>=optionsParams.ExpirationDate.Date)prices=PricingDA.GetPrices(underlierPrice.Symbol,optionsParams.ExpirationDate,daysToExpiration);
|
|
else prices = PricingDA.GetPrices(underlierPrice.Symbol,daysToExpiration);
|
|
|
|
EquityPriceShocks equityPriceShocks = MarketData.MarketDataModel.EquityPriceShocks.CreateEquityPriceShocks(underlierPrice, optionsParams);
|
|
equityPriceShocksCollection = new ObservableCollection<EquityPriceShock>(equityPriceShocks);
|
|
|
|
if (null != underlierPrice) base.DisplayName = "Options Worksheet" + "(" + underlierPrice.Symbol + ")";
|
|
|
|
if (null == optionsParams || null == currentPrice) transactionGL=double.NaN;
|
|
else
|
|
{
|
|
if (optionsParams.Strike < currentPrice.Close)transactionGL=optionsParams.Premium + ((optionsParams.Strike * optionsParams.Shares) - (currentPrice.Close * optionsParams.Shares));
|
|
else transactionGL=optionsParams.Premium + ((currentPrice.Close * optionsParams.Shares) - (underlierPrice.Close * optionsParams.Shares));
|
|
}
|
|
base.OnPropertyChanged("Strike");
|
|
base.OnPropertyChanged("Bid");
|
|
base.OnPropertyChanged("Investment");
|
|
base.OnPropertyChanged("ExpirationDate");
|
|
base.OnPropertyChanged("Shares");
|
|
base.OnPropertyChanged("Contracts");
|
|
base.OnPropertyChanged("Premium");
|
|
base.OnPropertyChanged("EquityPriceShocks");
|
|
base.OnPropertyChanged("UnderlierPrice");
|
|
base.OnPropertyChanged("UnderlierPriceDate");
|
|
base.OnPropertyChanged("CurrentPrice");
|
|
base.OnPropertyChanged("CurrentPriceDate");
|
|
base.OnPropertyChanged("OpenInterest");
|
|
base.OnPropertyChanged("DisplayName");
|
|
base.OnPropertyChanged("Volatility");
|
|
base.OnPropertyChanged("ExpirationDateBackground");
|
|
base.OnPropertyChanged("Close");
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
|
|
}
|
|
}
|
|
// ******************************************************************************************************************************************************
|
|
// *************************************************************** M E N U S U P P O R T **************************************************************
|
|
// ******************************************************************************************************************************************************
|
|
public ObservableCollection<TradeBlotter.Model.MenuItem> MenuItems
|
|
{
|
|
get
|
|
{
|
|
ObservableCollection<TradeBlotter.Model.MenuItem> collection = new ObservableCollection<TradeBlotter.Model.MenuItem>();
|
|
collection.Add(new TradeBlotter.Model.MenuItem() { Text = "Display Moving Average", MenuItemClickedCommand = DisplayMovingAverage, StaysOpenOnClick = false });
|
|
collection.Add(new TradeBlotter.Model.MenuItem() { Text = "Display Bollinger Bands", MenuItemClickedCommand = DisplayBollingerBands, StaysOpenOnClick = false });
|
|
return collection;
|
|
}
|
|
}
|
|
public bool UseRealPrice
|
|
{
|
|
get { return useRealPrice; }
|
|
set { useRealPrice = value; base.OnPropertyChanged("UseRealPrice"); }
|
|
}
|
|
public ICommand DisplayMovingAverage
|
|
{
|
|
get
|
|
{
|
|
if (null == displayMovingAverageCommand)
|
|
{
|
|
displayMovingAverageCommand = new RelayCommand(param =>
|
|
{
|
|
SaveParameters saveParams = new SaveParameters();
|
|
saveParams.Add(new KeyValuePair<String, String>("Type", "TradeBlotter.ViewModels.MovingAverageViewModel"));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedSymbol", underlierPrice.Symbol));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", Constants.CONST_ALL));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedDayCount", "180"));
|
|
saveParams.Add(new KeyValuePair<String, String>("IsLegendVisible", "true"));
|
|
saveParams.Referer=this;
|
|
WorkspaceInstantiator.Invoke(saveParams);
|
|
}, param => { return null == underlierPrice ? false : true; });
|
|
}
|
|
return displayMovingAverageCommand;
|
|
}
|
|
}
|
|
public ICommand DisplayBollingerBands
|
|
{
|
|
get
|
|
{
|
|
if(null==displayBollingerBandCommand)
|
|
{
|
|
displayBollingerBandCommand = new RelayCommand(param =>
|
|
{
|
|
SaveParameters saveParams = new SaveParameters();
|
|
saveParams.Add(new KeyValuePair<String, String>("Type", "TradeBlotter.ViewModels.BollingerBandViewModel"));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedSymbol", underlierPrice.Symbol));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", Constants.CONST_ALL));
|
|
saveParams.Add(new KeyValuePair<String, String>("SelectedDayCount", "90"));
|
|
saveParams.Add(new KeyValuePair<String, String>("SyncTradeToBand", "false"));
|
|
saveParams.Add(new KeyValuePair<String, String>("ShowTradeLabels", "true"));
|
|
saveParams.Add(new KeyValuePair<String, String>("IsLegendVisible", "true"));
|
|
saveParams.Referer=this;
|
|
WorkspaceInstantiator.Invoke(saveParams);
|
|
;
|
|
}, param => { return null == underlierPrice ? false : true; });
|
|
}
|
|
return displayBollingerBandCommand;
|
|
}
|
|
}
|
|
public bool BusyIndicator
|
|
{
|
|
get { return busyIndicator; }
|
|
set
|
|
{
|
|
busyIndicator = value;
|
|
base.OnPropertyChanged("BusyIndicator");
|
|
}
|
|
}
|
|
public CompositeDataSource Close
|
|
{
|
|
get
|
|
{
|
|
if (null == prices) return null;
|
|
CompositeDataSource compositeDataSource = PricesModel.Close(prices);
|
|
return compositeDataSource;
|
|
}
|
|
}
|
|
public ObservableCollection<EquityPriceShock> EquityPriceShocks
|
|
{
|
|
get
|
|
{
|
|
return equityPriceShocksCollection;
|
|
}
|
|
set
|
|
{
|
|
equityPriceShocksCollection = value;
|
|
base.OnPropertyChanged("EquityPriceShocks");
|
|
}
|
|
}
|
|
private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
|
|
{
|
|
if (eventArgs.PropertyName.Equals("UseRealPrice"))
|
|
{
|
|
if (useRealPrice) priceTimer.Start();
|
|
else priceTimer.Stop();
|
|
}
|
|
}
|
|
public String TransactionGL
|
|
{
|
|
get
|
|
{
|
|
if (double.NaN.Equals(transactionGL)) return Constants.CONST_DASHES;
|
|
if (optionsParams.Strike < currentPrice.Close)return Utility.FormatCurrency(transactionGL);
|
|
return Utility.FormatCurrency(transactionGL);
|
|
}
|
|
}
|
|
public String Volatility
|
|
{
|
|
get
|
|
{
|
|
if (null == optionsParams) return Constants.CONST_DASHES;
|
|
return Utility.FormatNumber(optionsParams.Volatility, 2, true);
|
|
}
|
|
}
|
|
public String VolatilityDays
|
|
{
|
|
get
|
|
{
|
|
if (null == optionsParams) return Constants.CONST_DASHES;
|
|
return Utility.FormatNumber(optionsParams.VolatilityDays,0, true);
|
|
}
|
|
}
|
|
public String OpenInterest
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatNumber(selectedOption.OpenInterest,0,true);
|
|
}
|
|
}
|
|
public String CurrentPrice
|
|
{
|
|
get
|
|
{
|
|
if (null == currentPrice) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(currentPrice.Close);
|
|
}
|
|
}
|
|
public String CurrentPriceDate
|
|
{
|
|
get
|
|
{
|
|
if (null == currentPrice) return Constants.CONST_DASHES;
|
|
return Utility.DateTimeToStringMMSDDSYYYYHHMMSS(currentPrice.Date);
|
|
}
|
|
}
|
|
public String LossPoint
|
|
{
|
|
get
|
|
{
|
|
if (null==selectedOption || null == underlierPrice) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(underlierPrice.Close-selectedOption.Bid);
|
|
}
|
|
}
|
|
public String UnderlierPrice
|
|
{
|
|
get
|
|
{
|
|
if (null == underlierPrice) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(underlierPrice.Close);
|
|
}
|
|
}
|
|
public String UnderlierPriceDate
|
|
{
|
|
get
|
|
{
|
|
if (null == underlierPrice) return Constants.CONST_DASHES;
|
|
return Utility.DateTimeToStringMMSDDSYYYY(underlierPrice.Date);
|
|
}
|
|
}
|
|
public String Premium
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(optionsParams.Premium);
|
|
}
|
|
}
|
|
public String Shares
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatNumber(optionsParams.Shares,2,true);
|
|
}
|
|
}
|
|
public String Contracts
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatNumber(optionsParams.Contracts, 0, true);
|
|
}
|
|
}
|
|
public String ExpirationDate
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.DateTimeToStringMMSDDSYYYY(selectedOption.Expiration);
|
|
}
|
|
}
|
|
public Brush TransactionGLBackground
|
|
{
|
|
get
|
|
{
|
|
if (null == underlierPrice) return null;
|
|
return underlierPrice.Date < DateTime.Now ? new SolidColorBrush(Colors.Green) : new SolidColorBrush(Colors.Red);
|
|
}
|
|
}
|
|
public Brush ExpirationDateBackground
|
|
{
|
|
get
|
|
{
|
|
return DateTime.Now.Date>=optionsParams.ExpirationDate.Date?new SolidColorBrush(Colors.Red):new SolidColorBrush(Colors.Green);
|
|
}
|
|
}
|
|
public String Strike
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(selectedOption.Strike);
|
|
}
|
|
}
|
|
public String Bid
|
|
{
|
|
get
|
|
{
|
|
if (null == selectedOption) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(selectedOption.Bid);
|
|
}
|
|
}
|
|
public String Investment
|
|
{
|
|
get
|
|
{
|
|
if (null == optionsParams) return Constants.CONST_DASHES;
|
|
return Utility.FormatCurrency(optionsParams.Cashdown);
|
|
}
|
|
}
|
|
|
|
public void OnErrorItemHandler(String symbol, String message)
|
|
{
|
|
}
|
|
public override String Title
|
|
{
|
|
get
|
|
{
|
|
if (null == companyName || null == optionsParams) return "Options Worksheet";
|
|
return companyName + " (" + optionsParams.Symbol + ")";
|
|
}
|
|
}
|
|
}
|
|
}
|