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.Threading.Tasks;
using System.Threading;
using System.Windows.Input;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Windows.Media;
using MarketData;
using MarketData.Utils;
using MarketData.MarketDataModel;
using MarketData.Generator;
using MarketData.DataAccess;
using MarketData.Helper;
using MarketData.Numerical;
using TradeBlotter.DataAccess;
using TradeBlotter.Command;
using TradeBlotter.Model;
using TradeBlotter.Cache;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using System.IO;

namespace TradeBlotter.ViewModels
{
  public class OptionsViewModel : WorkspaceViewModel
  {
    private enum Tasks{SelectedSymbol,SelectedItem,CheckBoxFullHistory,CheckBoxCallPutRatio,SelectedExpirationDate,SelectedOptionType,SelectedWatchList,SelectedRiskFreeRateType,SelectedVolatilityDays};
    private Dictionary<Tasks,Semaphore> semaphorePool=new Dictionary<Tasks,Semaphore>();
    private RelayCommand launchOptionsWorksheetCommand = null;
    private BollingerBands bollingerBands;
    private Prices prices;
    private String symbol;
    private double volatility;
    private List<String> symbols;
    private List<String> watchLists;
    private String selectedWatchList;
    private RelayCommand updateCommand;
    private List<String> optionTypes;
    private String selectedOptionType;
    private ObservableCollection<Option> optionModels = new ObservableCollection<Option>();
    private ObservableCollection<Item> expirationDates=new ObservableCollection<Item>();
    private Options options = null;
    private List<String> riskFreeRateTypes;
    private String selectedRiskFreeRateType;
    private double selectedRiskFreeRate;
    private DateTime selectedRiskFreeRateDate=DateTime.MinValue;
    private List<Int32> volatilityDays =null;
    private Int32 selectedVolatilityDays;
    private String companyName;
    private Option selectedItem = null;
    private bool busyIndicator = false;
    private Item selectedExpirationDate = null;
    private bool checkBoxFullHistory = false;
    private bool checkBoxFullHistoryEnabled=false;
    private bool checkBoxCallPutRatio=true;
    private bool checkBoxCallPutRatioEnabled=true;
    private bool useLeastSquaresFit=false;
//    private bool showOnlyCallPutRatio=true;

    public OptionsViewModel()
    {
      semaphorePool.Add(Tasks.SelectedSymbol,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedItem,new Semaphore(1,1));
      semaphorePool.Add(Tasks.CheckBoxFullHistory,new Semaphore(1,1));
      semaphorePool.Add(Tasks.CheckBoxCallPutRatio,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedExpirationDate,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedOptionType,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedWatchList,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedRiskFreeRateType,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedVolatilityDays,new Semaphore(1,1));

      base.DisplayName = "Options";
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      symbols = WatchListDA.GetWatchList(selectedWatchList);
      symbols = OptionsDA.GetOptionsSymbolIn(symbols);
      volatilityDays = new List<Int32>();
      volatilityDays.Add(15);
      volatilityDays.Add(30);
      volatilityDays.Add(60);
      volatilityDays.Add(90);
      volatilityDays.Add(120);
      volatilityDays.Add(180);
      volatilityDays.Add(360);
      selectedVolatilityDays = volatilityDays[0];
      optionTypes = new List<String>();
      optionTypes.Add("Put");
      optionTypes.Add("Call");
      selectedOptionType = optionTypes[0];
      riskFreeRateTypes = YieldCurveData.GetRateTypesString();
      selectedRiskFreeRateType = riskFreeRateTypes[3];
      YieldCurve yieldCurve=YieldCurveDA.GetYieldCurve(1);
      selectedRiskFreeRateDate = yieldCurve[0].Date;
      selectedRiskFreeRate = yieldCurve[0].GetRate(selectedRiskFreeRateType);
      base.OnPropertyChanged("RiskFreeRateTypes");
      base.OnPropertyChanged("SelectedRiskFreeRateType");
      base.OnPropertyChanged("SelectedRiskFreeRate");
      base.OnPropertyChanged("SelectedRiskFreeRateDate");
      base.OnPropertyChanged("VolatilityDays");
      base.OnPropertyChanged("SelectedVolatilityDays");
      PropertyChanged += OnOptionsViewModelPropertyChanged;
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    public ObservableCollection<TradeBlotter.Model.MenuItem> MenuItems
    {
      get
      {
        ObservableCollection<TradeBlotter.Model.MenuItem> collection = new ObservableCollection<TradeBlotter.Model.MenuItem>();
        collection.Add(new TradeBlotter.Model.MenuItem() { Text = "Launch Options Worksheet", MenuItemClickedCommand = LaunchOptionsWorksheet, StaysOpenOnClick = false });
        return collection;
      }
    }
    public ICommand LaunchOptionsWorksheet
    {
      get
      {
        if (null == launchOptionsWorksheetCommand)
        {
          launchOptionsWorksheetCommand = new RelayCommand(param =>
          {
            Price latestPrice=PriceCache.GetInstance().GetLatestPrice(selectedItem.Symbol);
            if(null==latestPrice)latestPrice=PricingDA.GetPrice(selectedItem.Symbol);
            SaveParameters saveParams = new SaveParameters();
            XmlSerializer optionSerializer = new XmlSerializer(selectedItem.GetType());
            StringWriter optionStringWriter = new StringWriter();
            optionSerializer.Serialize(optionStringWriter, selectedItem);

            XmlSerializer priceSerializer = new XmlSerializer(typeof(Price));
            StringWriter priceWriter = new StringWriter();
            priceSerializer.Serialize(priceWriter, latestPrice);

            saveParams.Add(new KeyValuePair<String, String>("Type", "TradeBlotter.ViewModels.OptionsWorksheetViewModel"));
            saveParams.Add(new KeyValuePair<String, String>("Option",optionStringWriter.ToString()));
            saveParams.Add(new KeyValuePair<String, String>("CompanyName", companyName));
            saveParams.Add(new KeyValuePair<String, String>("Price", priceWriter.ToString()));
            saveParams.Referer=this;
            WorkspaceInstantiator.Invoke(saveParams);
          }, param => { return true; });
        }
        return launchOptionsWorksheetCommand;
      }
    }
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set { busyIndicator = value; base.OnPropertyChanged("BusyIndicator"); }
    }
// ***************************************************************************************************************************************************************
// *************************************************************** M A I N   E V E N T   H A N D L E R ***********************************************************
// ***************************************************************************************************************************************************************
    private void OnOptionsViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      try
      {
        if(eventArgs.PropertyName.Equals("CheckBoxCallPutRatio"))
        {
          HandleCheckBoxCallPutRatio();
        }
        if (eventArgs.PropertyName.Equals("CheckBoxFullHistory"))
        {
          HandleCheckBoxFullHistory();
        }
        if (eventArgs.PropertyName.Equals("SelectedSymbol") && null != symbol)
        {
          HandleSelectedSymbol();
        }
        else if (eventArgs.PropertyName.Equals("SelectedExpirationDate"))
        {
          HandleSelectedExpirationDate();
        }
        else if (eventArgs.PropertyName.Equals("SelectedOptionType") && null != symbol)
        {
          HandleSelectedOptionType();
        }
        else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
        {
          HandleSelectedWatchList();
        }
        else if (eventArgs.PropertyName.Equals("SelectedRiskFreeRateType"))
        {
          HandleSelectedRiskFreeRateType();
        }
        else if (eventArgs.PropertyName.Equals("SelectedVolatilityDays"))
        {
          HandleSelectedVolatilityDays();
        }
        else if (eventArgs.PropertyName.Equals("SelectedItem"))
        {
          HandleSelectedItem();
        }
        else if(eventArgs.PropertyName.Equals("LeastSquaresFit"))
        {
          base.OnPropertyChanged("LeastSquares");
        }
      }
      catch(Exception /*e*/)
      {
      }
      finally
      {
      }
    }
    private void HandleCheckBoxCallPutRatio()
    {
      try
      {
        semaphorePool[Tasks.CheckBoxCallPutRatio].WaitOne();
        if(!checkBoxCallPutRatioEnabled)return;
        SelectedItem=null;
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("OnOptionsViewModelPropertyChanged:CheckBoxCallPutRatio:{0}", symbol));
        base.OnPropertyChanged("SelectedSymbol");
      }
      finally
      {
        semaphorePool[Tasks.CheckBoxCallPutRatio].Release();
      }
    }
    private void HandleCheckBoxFullHistory()
    {
      try
      {
        semaphorePool[Tasks.CheckBoxFullHistory].WaitOne();
        if(!checkBoxFullHistoryEnabled)return;
        SelectedItem=null;
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("OnOptionsViewModelPropertyChanged:CheckBoxFullHistory:{0}", symbol));
        base.OnPropertyChanged("SelectedSymbol");
      }
      finally
      {
        semaphorePool[Tasks.CheckBoxFullHistory].Release();
      }
    }
    private void HandleSelectedSymbol()
    {
      try
      {
        semaphorePool[Tasks.SelectedSymbol].WaitOne();
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("OnOptionsViewModelPropertyChanged:SelectedSymbol:{0}", symbol));
        checkBoxFullHistoryEnabled=true;
        SelectedItem=null;
        BusyIndicator = true;
        base.DisplayName="Options"+"("+symbol+")";
        Task workerTask = Task.Factory.StartNew(() =>
        {
          companyName = PricingDA.GetNameForSymbol(SelectedSymbol);
          if(checkBoxFullHistory)options=OptionsDA.GetOptions(symbol);
          else options = OptionsDA.GetOptions(symbol,DateTime.Now);
          if (null == options || 0 == options.Count)
          {
            App.Current.Dispatcher.Invoke((Action)delegate
            {
              optionModels.Clear();
              expirationDates.Clear();
            });          
            base.OnPropertyChanged("AllOptions");
            base.OnPropertyChanged("ExpirationDates");
            return;
          }
          PutCallRatioHelper.CalculatePutCallRatios(options);
          if(checkBoxCallPutRatio)options=new Options((from Option option in options where (option.Type.Equals(OptionTypeEnum.CallOption) && !option.CallPutRatio.Equals(double.NaN))||(option.Type.Equals(OptionTypeEnum.PutOption) && !option.PutCallRatio.Equals(double.NaN)) select option).ToList());
          IEnumerable<Option> selectedOptions = null;
          OptionTypeEnum optionType = selectedOptionType.Equals("Call") ? OptionTypeEnum.CallOption : OptionTypeEnum.PutOption;
          selectedOptions = from option in options where option.Type.Equals(optionType) select option;
          if(!selectedOptions.Any())
          {
            App.Current.Dispatcher.Invoke((Action)delegate
            {
              optionModels.Clear();
              expirationDates.Clear();
            });          
            base.OnPropertyChanged("AllOptions");
            base.OnPropertyChanged("ExpirationDates");
            return;
          }
          var selection = from option in selectedOptions select option.Expiration;
          IEnumerable<DateTime> distinctDates = selection.Distinct();
          App.Current.Dispatcher.Invoke((Action)delegate
          {
            expirationDates.Clear();
            for (int index = 0; index < distinctDates.Count<DateTime>(); index++)
            {
              expirationDates.Add(new Item(Utility.DateTimeToStringMMHDDHYYYY(distinctDates.ElementAt(index))));
            }
            selectedExpirationDate=expirationDates[0];
          });          
          UpdateOptionValues();
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          UpdateGraphs();
          base.OnPropertyChanged("DisplayName");
          base.OnPropertyChanged("ExpirationDates");
          base.OnPropertyChanged("SelectedExpirationDate");
          base.OnPropertyChanged("UnderlyingPrice");
          base.OnPropertyChanged("PricingDate");
          base.OnPropertyChanged("Title");
          base.OnPropertyChanged("CheckBoxFullHistoryEnabled");
          base.OnPropertyChanged("CheckBoxCallPutRatioEnabled");
        });
      }
      finally
      {
        semaphorePool[Tasks.SelectedSymbol].Release();
      }
    }
    private void HandleSelectedExpirationDate()
    {
      try
      {
        semaphorePool[Tasks.SelectedExpirationDate].WaitOne();
        MDTrace.WriteLine(String.Format("OnOptionsViewModelPropertyChanged:SelectedExpirationDate:{0}", symbol));
        selectedItem = null;
        IEnumerable<Option> selectedOptions = null;
        if (null == options || null == selectedExpirationDate)
        {
          MDTrace.WriteLine("null == options || null==selectedExpirationDate");
          bollingerBands = null;
          UpdateGraphs();
          return;
        }
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Selected Expiration Date:{0}", selectedExpirationDate.Value));
        selectedOptions = from option in options where option.Expiration.Date.Equals(DateTime.Parse(selectedExpirationDate.Value).Date) select option;
        if (null != selectedOptionType)
        {
          OptionTypeEnum optionType = selectedOptionType.Equals("Call") ? OptionTypeEnum.CallOption : OptionTypeEnum.PutOption;
          selectedOptions = from option in selectedOptions where option.Type.Equals(optionType) select option;
        }
        optionModels = new ObservableCollection<Option>(selectedOptions);
        Option topItem = optionModels.FirstOrDefault();
        if (topItem.Expiration < DateTime.Now) prices = PricingDA.GetPrices(symbol, topItem.Expiration, selectedVolatilityDays);
        else prices = PricingDA.GetPrices(symbol, selectedVolatilityDays);
        if (selectedVolatilityDays < 40)
        {
          Prices bollingerBandPrices = null;
          if (topItem.Expiration < DateTime.Now) bollingerBandPrices = PricingDA.GetPrices(symbol, topItem.Expiration, 40);
          else bollingerBandPrices = PricingDA.GetPrices(symbol, 40);
          bollingerBands = BollingerBandGenerator.GenerateBollingerBands(bollingerBandPrices);
          if (null != bollingerBandPrices) MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Bollinger Band Prices(<40) - {0} Min:{1} Max:{2}", symbol, bollingerBandPrices[0].Date, bollingerBandPrices[bollingerBandPrices.Count - 1].Date));
          else MDTrace.WriteLine(LogLevel.DEBUG,String.Format("No price for {0}",symbol));
        }
        else
        {
          if(null!=prices)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Bollinger Band Prices - {0} Min:{1} Max:{2}", symbol, prices[0].Date, prices[prices.Count - 1].Date));
          else MDTrace.WriteLine(LogLevel.DEBUG,String.Format("No prices for symbol {0}", symbol));
          bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
        }
        if (null != prices && 0 != prices.Count)
        {
          float[] closingPrices = prices.GetPrices();
          volatility = Numerics.Volatility(ref closingPrices);
          base.OnPropertyChanged("Volatility");
        }
        UpdateOptionValues();
        UpdateGraphs();
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
      }
      finally
      {
        semaphorePool[Tasks.SelectedExpirationDate].Release();
      }
    }
    private void HandleSelectedOptionType()
    {
      try
      {
        semaphorePool[Tasks.SelectedOptionType].WaitOne();
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("OnOptionsViewModelPropertyChanged:SelectedOptionType:{0}", selectedOptionType));
        SelectedItem=null;
        BusyIndicator = true;
        Task workerTask = Task.Factory.StartNew(() =>
        {
          IEnumerable<Option> selectedOptions = null;
          OptionTypeEnum optionType = selectedOptionType.Equals("Call") ? OptionTypeEnum.CallOption : OptionTypeEnum.PutOption;
          if (null == options || 0 == options.Count) return;
          selectedOptions = from option in options where option.Type.Equals(optionType) select option;
          selectedOptions = from option in selectedOptions where option.Expiration.Date.Equals(DateTime.Parse(selectedExpirationDate.Value).Date) select option;
          Option newSelection=selectedOptions.FirstOrDefault();
          optionModels = new ObservableCollection<Option>(selectedOptions);
          UpdateOptionValues();
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          base.OnPropertyChanged("SelectedItem");
          UpdateGraphs();
        });
      }
      finally
      {
        semaphorePool[Tasks.SelectedOptionType].Release();
      }
    }
    private void HandleSelectedWatchList()
    {
      try
      {
        semaphorePool[Tasks.SelectedWatchList].WaitOne();
        MDTrace.WriteLine(LogLevel.DEBUG, "OnOptionsViewModelPropertyChanged:SelectedWatchList");
//        if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols();
        if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols();
        else symbols = WatchListDA.GetWatchList(selectedWatchList);
        symbols = OptionsDA.GetOptionsSymbolIn(symbols);
        base.OnPropertyChanged("Symbols");
      }
      finally
      {
        semaphorePool[Tasks.SelectedWatchList].Release();
      }
    }
    private void HandleSelectedRiskFreeRateType()
    {
      try
      {
        semaphorePool[Tasks.SelectedRiskFreeRateType].WaitOne();
        MDTrace.WriteLine(LogLevel.DEBUG, "OnOptionsViewModelPropertyChanged:SelectedRiskFreeRateType");
        YieldCurve yieldCurve = YieldCurveDA.GetYieldCurve(1);
        selectedRiskFreeRate = yieldCurve[0].GetRate(selectedRiskFreeRateType);
        selectedRiskFreeRateDate = yieldCurve[0].Date;
        UpdateOptionValues();
        base.OnPropertyChanged("SelectedRiskFreeRate");
        base.OnPropertyChanged("SelectedRiskFreeRateDate");
      }
      finally
      {
        semaphorePool[Tasks.SelectedRiskFreeRateType].Release();
      }
    }
    public void HandleSelectedVolatilityDays()
    {
      try
      {
        semaphorePool[Tasks.SelectedVolatilityDays].WaitOne();
        MDTrace.WriteLine(LogLevel.DEBUG, "OnOptionsViewModelPropertyChanged:SelectedVolatilityDays");
        DateTime expirationDate=DateTime.Parse(selectedExpirationDate.Value);
        if(expirationDate<DateTime.Now)prices=PricingDA.GetPrices(symbol,expirationDate,selectedVolatilityDays);
        else prices = PricingDA.GetPrices(symbol, selectedVolatilityDays);
        if (null != prices && 0 != prices.Count)
        {
          float[] closingPrices = prices.GetPrices();
          volatility = Numerics.Volatility(ref closingPrices);
          base.OnPropertyChanged("Volatility");
        }
        if (selectedVolatilityDays < 40)
        {
          Prices bollingerBandPrices=null;
          if(expirationDate<DateTime.Now)bollingerBandPrices=PricingDA.GetPrices(symbol,expirationDate,40);
          else bollingerBandPrices = PricingDA.GetPrices(symbol, 40);
          bollingerBands = BollingerBandGenerator.GenerateBollingerBands(bollingerBandPrices);
        }
        else bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
        UpdateOptionValues();
        UpdateGraphs();
      }
      finally
      {
        semaphorePool[Tasks.SelectedVolatilityDays].Release();
      }
    }
    private void HandleSelectedItem()
    {
      try
      {
        semaphorePool[Tasks.SelectedItem].WaitOne();
        if(null==selectedItem)return;
        MDTrace.WriteLine(LogLevel.DEBUG, "OnOptionsViewModelPropertyChanged:SelectedItem");
        base.OnPropertyChanged("SelectedOptionStrikePoints");
      }
      finally
      {
        semaphorePool[Tasks.SelectedItem].Release();
      }
    }
    public Boolean LeastSquaresFit
    {
      get
      {
        return useLeastSquaresFit;
      }
      set
      {
        useLeastSquaresFit = value;
        base.OnPropertyChanged("LeastSquaresFit");
      }
    }
// ************************************************************************************************************************************************************
// ***************************************************************************************************************************************************************
// ***************************************************************************************************************************************************************
    public String RatioDescription
    {
      get
      {
        if(null== selectedItem || null==selectedItem.Symbol)return "No row selected.";
        StringBuilder sb=new StringBuilder();
        sb.Append("The contrarian viewpoint is to trade against the positions of option traders.  \nA high put/call ratio may indicate a buying opportunity while a low put/call ration may indicate a pullback.\n");
        if(selectedOptionType.Equals("Put"))
        {
          Option option=optionModels.OrderByDescending(x=>x.PutCallRatio).First();
          sb.Append(String.Format("The highest put/call ratio for {0} {1} expiry is the {2} strike.",selectedItem.Symbol,Utility.DateTimeToStringMMHDDHYYYY(selectedItem.Expiration),Utility.FormatCurrency(option.Strike)));
        }
        else
        {
          Option option=optionModels.OrderByDescending(x=>x.CallPutRatio).First();
          sb.Append(String.Format("The highest call/put ratio for {0} {1} expiry is the {2} strike.",selectedItem.Symbol,Utility.DateTimeToStringMMHDDHYYYY(selectedItem.Expiration),Utility.FormatCurrency(option.Strike)));
        }
        return sb.ToString();
      }
    }
    public ObservableCollection<Option> AllOptions
    {
      get { return optionModels; }
    }
    public List<String> OptionTypes
    {
      get
      {
        return optionTypes;
      }
    }
    public String SelectedOptionType
    {
      get { return selectedOptionType; }
      set{selectedOptionType=value;base.OnPropertyChanged("SelectedOptionType");}
    }
    public ObservableCollection<Item> ExpirationDates
    {
      get
      {
        return expirationDates;
      }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get { return symbol; }
      set
      {
        if (value == symbol || String.IsNullOrEmpty(value)) return;
        symbol = value;
        checkBoxFullHistory=false;
        base.OnPropertyChanged("CheckBoxFullHistory");
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public override String Title
    {
      get
      {
        if (null == companyName || null == SelectedSymbol) return null;
        return companyName+" ("+SelectedSymbol+")";
      }
    }
    public List<String> WatchListNames
    {
      get
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }

    public List<String> RiskFreeRateTypes
    {
      get
      {
        return riskFreeRateTypes;
      }
    }
    public String SelectedRiskFreeRateType
    {
      get
      {
        return selectedRiskFreeRateType;
      }
      set
      {
        selectedRiskFreeRateType = value;
        base.OnPropertyChanged("SelectedRiskFreeRateType");
      }
    } 
    public double SelectedRiskFreeRate
    {
      get
      {
        return selectedRiskFreeRate;
      }
      set
      {
        selectedRiskFreeRate = value;
        base.OnPropertyChanged("SelectedRiskFreeRate");
      }
    }
    public DateTime SelectedRiskFreeRateDate
    {
      get
      {
        return selectedRiskFreeRateDate;
      }
      set
      {
        selectedRiskFreeRateDate = value;
        base.OnPropertyChanged("SelectedRiskFreeRateDate");
      }
    }
    public List<Int32> VolatilityDays
    {
      get
      {
        return volatilityDays;
      }      
    }
    public Int32 SelectedVolatilityDays
    {
      get
      {
        return selectedVolatilityDays;
      }
      set
      {
        selectedVolatilityDays = value;
        base.OnPropertyChanged("SelectedVolatilityDays");
      }
    }
    public String UnderlyingPrice
    {
      get
      {
        if (null == prices || 0 == prices.Count) return Constants.CONST_DASHES;
        return Utility.FormatCurrency(prices[0].Close);
      }
    }
    public String PricingDate
    {
      get
      {
        if (null == prices || 0 == prices.Count) return Constants.CONST_DASHES;
        return Utility.DateTimeToStringMMSDDSYYYY(prices[0].Date);
      }
    }
    public String Volatility
    {
      get
      {
        if (double.IsNaN(volatility)) return Constants.CONST_DASHES;
        return Utility.FormatNumber(volatility);
      }
    }
    private void Update()
    {
      try
      {
        BusyIndicator = true;
        Task workerTask=Task.Factory.StartNew(()=>
        {
          if (null == symbol) return;
          Options options = MarketDataHelper.GetOptions(symbol);
          if (null == options || 0 == options.Count) return;
          if (OptionsDA.AddOptions(options)) MessageBox.Show(String.Format("Added {0} records for {1}", options.Count, symbol));
          else MessageBox.Show(String.Format("Failed to add options chain for {0}", symbol));
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          base.OnPropertyChanged("SelectedSymbol");
        });
      }
      catch (Exception exception)
      {
        BusyIndicator = false;
        MessageBox.Show(exception.ToString());
      }
    }
    private bool CanUpdate
    {
      get { return true; }
    }
    public ICommand UpdateCommand
    {
      get
      {
        if (updateCommand == null)
        {
          updateCommand = new RelayCommand(param => this.Update(), param => this.CanUpdate);
        }
        return updateCommand;
      }
    }
    private void UpdateOptionValues()
    {
      if (null == optionModels) return;
      DateGenerator dateGenerator = new DateGenerator();
      foreach(Option option in optionModels)
      {
        int days = dateGenerator.DaysBetween(option.Expiration, prices[0].Date);
        double fractionOfYear = days / 360.00;
        double optionValue = BlackScholesOptionPricingModel.GetPrice(option.Type, prices[0].Close, option.Strike, fractionOfYear, selectedRiskFreeRate/100.00, volatility);
        option.OptionValue = optionValue;
        option.MoneyType.SetMoney(prices[0].Close, option.Strike);
      }        
      if(checkBoxCallPutRatio)optionModels = new ObservableCollection<Option>(optionModels.OrderByDescending(x=>x.Ratio));
      else optionModels = new ObservableCollection<Option>(optionModels.OrderByDescending(x=>x.Strike));
      base.OnPropertyChanged("AllOptions");
    }
// BollingerBands
    private void UpdateGraphs()
    {
      base.OnPropertyChanged("SelectedOptionStrikePoints");
      base.OnPropertyChanged("OptionStrikePoints");
      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("LeastSquares");
    }
    public CompositeDataSource K
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.K(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource KL1
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.KL1(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource L
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.L(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource LP1
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.LP1(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource High
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.High(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource Low
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.Low(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource Close
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.Close(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource SMAN
    {
      get
      {
        CompositeDataSource compositeDataSource = BollingerBandModel.SMAN(bollingerBands);
        return compositeDataSource;
      }
    }
    public CompositeDataSource LeastSquares
    {
      get
      {
        if(!useLeastSquaresFit||null==bollingerBands||null==selectedExpirationDate||null==selectedExpirationDate.Value)return null;
        CompositeDataSource compositeDataSourceLeastSquares=null;
        compositeDataSourceLeastSquares=BollingerBandModel.LeastSquaresExtend(bollingerBands,DateTime.Parse(selectedExpirationDate.Value));
        return compositeDataSourceLeastSquares;
      }
    }
// ***************************************************************************************************
    public CompositeDataSource OptionStrikePoints
    {
      get
      {
        if(null==selectedExpirationDate || null==selectedOptionType)return new CompositeDataSource();
        OptionTypeEnum optionType = selectedOptionType.Equals("Call") ? OptionTypeEnum.CallOption : OptionTypeEnum.PutOption;
        List<Option> optionsList = (from option in options where option.Expiration.Date.Equals(DateTime.Parse(selectedExpirationDate.Value).Date)  &&  option.Type.Equals(optionType) select option).ToList();
        OptionStrikes optionStrikes = new OptionStrikes();
        foreach (Option option in optionsList) optionStrikes.Add(new OptionStrike(option.Expiration,option.Strike));
        CompositeDataSource compositeDataSource = OptionStrikeModel.OptionStrikes(optionStrikes);
        return compositeDataSource;
      }
    }
    public CompositeDataSource SelectedOptionStrikePoints
    {
      get
      {
        if (null == selectedItem)return new CompositeDataSource();
        MDTrace.WriteLine(LogLevel.DEBUG, "SelectedOptionStrikePoints:returning composite");
        OptionStrikes optionStrikes = new OptionStrikes();
        optionStrikes.Add(new OptionStrike(selectedItem.Expiration, selectedItem.Strike));
        CompositeDataSource compositeDataSource = OptionStrikeModel.OptionStrikes(optionStrikes);
        return compositeDataSource;
      }
    }
    //***********************************************************
    public Option SelectedItem
    {
      get
      {
        return selectedItem;
      }
      set
      {
        selectedItem = value;
        base.OnPropertyChanged("SelectedItem");
      }
    }
    public Item SelectedExpirationDate
    {
      get
      {
        return selectedExpirationDate;
      }
      set
      {
        selectedExpirationDate = value;
        base.OnPropertyChanged("SelectedExpirationDate");
      }
    }

    public bool CheckBoxCallPutRatioEnabled
    {
      get{return checkBoxCallPutRatioEnabled;}
    }
    public bool CheckBoxCallPutRatio
    {
      get
      {
        return checkBoxCallPutRatio;
      }
      set
      {
        checkBoxCallPutRatio=value;
        base.OnPropertyChanged("CheckBoxCallPutRatio");
      }
    }
//  ************************************************
    public bool CheckBoxFullHistoryEnabled
    {
      get{return checkBoxFullHistoryEnabled;}
    }
    public bool CheckBoxFullHistory
    {
      get
      {
        return checkBoxFullHistory;
      }
      set
      {
        checkBoxFullHistory=value;
        base.OnPropertyChanged("CheckBoxFullHistory");
      }
    }
//  ************************************************
  }
}
