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.Windows.Input;
using MarketData;
using MarketData.Numerical;
using MarketData.Utils;
using MarketData.MarketDataModel;
using MarketData.Generator;
using MarketData.Generator.GainLoss;
using MarketData.DataAccess;
using TradeBlotter.DataAccess;
using TradeBlotter.Command;
using TradeBlotter.Model;
using TradeBlotter.Cache;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using Microsoft.Research.DynamicDataDisplay.PointMarkers;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Forms;
using TradeBlotter.UIUtils;
using TradeBlotter.Extensions;


// Author:Sean Kessler

namespace TradeBlotter.ViewModels
{
  public class BollingerBandViewModel : WorkspaceViewModel
  {
    private static readonly String BAND_MESSAGE="Generating Bollinger Band...";
    private static readonly String DATA_MESSAGE="Loading Pricing Data...";
    private BollingerBands bollingerBands;
    private StopLimit stopLimit;     // This is the stop limit that is looked up in the database and displayed (if there is one)
    private StopLimits stopLimits;   // These stop limits might be passed in with the SaveParams. (i.e.) MMTRend model passes in StopLimits.  If these are passsed in then they are displayed instead of stopLimit.
    private String symbol;
    private String companyName;
    private Prices prices = null;
    private List<String> symbols;
    private List<String> watchLists;
    private String selectedWatchList;
    private RelayCommand refreshCommand;
    private List<Int32> dayCounts;
    private Int32 selectedDayCount;
    private PortfolioTrades portfolioTrades;
    private PortfolioTrades portfolioTradesLots;
    private InsiderTransactionSummaries insiderTransactionSummaries=null;
    private bool syncTradeToBand = true;
    private bool showTradeLabels = true;
    private bool showInsiderTransactions=true;
    private bool showRiskFree=false;
    private bool busyIndicator = false;
    private Price zeroPrice = null;
    private Price riskFreeRatePrice=null;
    private bool isLegendVisible = true;
    private bool useLeastSquaresFit=true; 
    private String busyContent = BAND_MESSAGE;

    private CompositeDataSource compositeDataSourceRiskFreeRatePoint=null;
    private CompositeDataSource compositeDataSourceZeroPoint=null;
    private CompositeDataSource compositeDataSourceStopLimit=null;


		private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedSmall=null;
		private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedMedium=null;
		private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedLarge=null;
    private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredSmall=null;
    private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredMedium=null;
    private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredLarge=null;

    private CompositeDataSource compositeDataSourceK=null;
    private CompositeDataSource compositeDataSourceKL1=null;
    private CompositeDataSource compositeDataSourceL=null;
    private CompositeDataSource compositeDataSourceLP1=null;
    private CompositeDataSource compositeDataSourceHigh=null;
    private CompositeDataSource compositeDataSourceLow=null;
    private CompositeDataSource compositeDataSourceClose=null;
    private CompositeDataSource compositeDataSourceSMAN=null;
    private CompositeDataSource compositeDataSourceVolume=null;
    private CompositeDataSource compositeDataSourceLeastSquares=null;
    private CompositeDataSource compositeDataSourceTradePoints=null;

    public BollingerBandViewModel()
    {
      base.DisplayName = "Bollinger Band";
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      symbols = WatchListDA.GetWatchList(selectedWatchList);
      dayCounts = new List<Int32>();
      dayCounts.Add(60);
      dayCounts.Add(90);
      dayCounts.Add(180);
      dayCounts.Add(360);
      dayCounts.Add(720);
      dayCounts.Add(1440);
      dayCounts.Add(3600);
      selectedDayCount = dayCounts[2];
      PropertyChanged += OnBollingerBandViewModelPropertyChanged;
    }
    public override SaveParameters GetSaveParameters()
    {
      SaveParameters saveParams = new SaveParameters();
      if (null == symbol) return null;
      saveParams.Add(new KeyValuePair<String, String>("Type",GetType().Namespace+"."+GetType().Name));
      saveParams.Add(new KeyValuePair<String, String>("SelectedSymbol", symbol));
      saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", selectedWatchList));
      saveParams.Add(new KeyValuePair<String, String>("SelectedDayCount", selectedDayCount.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("SyncTradeToBand", syncTradeToBand.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("ShowTradeLabels", showTradeLabels.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("ShowRiskFree", showRiskFree.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("IsLegendVisible", isLegendVisible.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("UseLeastSquaresFit", useLeastSquaresFit.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("ShowInsiderTransactions", showInsiderTransactions.ToString()));
      if(null!=stopLimits && 0!=stopLimits.Count)
      {
        saveParams.Add(new KeyValuePair<String,String>("StopHistoryCount",stopLimits.Count.ToString()));
        for(int index=0;index<stopLimits.Count;index++)
        {
          String strItemKey=String.Format("StopHistory_{0}",index);
          StopLimit stopLimit=stopLimits[index];
          NVPCollection nvpCollection=stopLimit.ToNVPCollection();
          String strStopHistoryItem=nvpCollection.ToString();
          saveParams.Add(new KeyValuePair<String,String>(strItemKey,strStopHistoryItem));
        }
      }
      return saveParams;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
      try
      {
        Referer=saveParameters.Referer;
        symbol = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedSymbol") select item).FirstOrDefault().Value;
        selectedWatchList = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedWatchList") select item).FirstOrDefault().Value;
        base.OnPropertyChanged("SelectedWatchList");
        selectedDayCount = Int32.Parse((from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedDayCount") select item).FirstOrDefault().Value);
        try 
        {
          if(saveParameters.ContainsKey("SyncTradeToBand"))syncTradeToBand=Boolean.Parse((from KeyValuePair<String,String> item in saveParameters where item.Key.Equals("SyncTradeToBand") select item).FirstOrDefault().Value);
          else syncTradeToBand=true;
        }
        catch (Exception) { syncTradeToBand = true; }
        try 
        {
          if(saveParameters.ContainsKey("ShowTradeLabels"))showTradeLabels = Boolean.Parse((from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("ShowTradeLabels") select item).FirstOrDefault().Value);
          else showTradeLabels=true;
        }
        catch (Exception) { showTradeLabels = true; }
        try
        {
          if(saveParameters.ContainsKey("IsLegendVisible"))isLegendVisible=Boolean.Parse((from KeyValuePair<String,String> item in saveParameters where item.Key.Equals("IsLegendVisible") select item).FirstOrDefault().Value);
        }
        catch (Exception){;}
        try
        {
          if(saveParameters.ContainsKey("UseLeastSquaresFit"))useLeastSquaresFit=Boolean.Parse((from KeyValuePair<String,String> item in saveParameters where item.Key.Equals("UseLeastSquaresFit") select item).FirstOrDefault().Value);
        }
        catch (Exception){;}
        try
        {
          if(saveParameters.ContainsKey("ShowInsiderTransactions"))showInsiderTransactions=Boolean.Parse((from KeyValuePair<String,String> item in saveParameters where item.Key.Equals("ShowInsiderTransactions") select item).FirstOrDefault().Value);
        }
        catch (Exception){;}
        try{showRiskFree = Boolean.Parse((from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("ShowRiskFree") select item).FirstOrDefault().Value);}
        catch (Exception){;}

        try
        {
          if(saveParameters.ContainsKey("StopHistoryCount"))
          {
            stopLimits = StopLimitsExtensions.FromSaveParams(saveParameters); 
          }
        }
        catch(Exception exception)
        {
          MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
        }
        base.OnPropertyChanged("SelectedSymbol");
      }
      catch (Exception)
      {
      }
    }
    public override bool CanPersist()
    {
      return true;
    }
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    public String BusyContent
    {
      get { return busyContent; }
      set
      {
        busyContent = value;
        base.OnPropertyChanged("BusyContent");
      }
    }
    private void OnBollingerBandViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedSymbol"))
      {
          InitializeDataSources();
          insiderTransactionSummaries=null;
          zeroPrice=null;
          riskFreeRatePrice=null;
          prices=null;
          portfolioTrades=null;
          portfolioTradesLots=null;
          stopLimit=null;
        }

      if (eventArgs.PropertyName.Equals("SyncTradeToBand")||
          eventArgs.PropertyName.Equals("ShowTradeLabels")||
          eventArgs.PropertyName.Equals("SelectedSymbol")||
          eventArgs.PropertyName.Equals("ShowRiskFree")||
					eventArgs.PropertyName.Equals("LeastSquaresFit")||
          (eventArgs.PropertyName.Equals("SelectedDayCount")&&null!=symbol))
      {
      BusyIndicator=true;
      Task workerTask=Task.Factory.StartNew(()=>
      {
        base.DisplayName="Bollinger("+symbol+")";
        base.OnPropertyChanged("DisplayName");
        BusyContent=DATA_MESSAGE;

// DEBUG
        stopLimit=PortfolioDA.GetStopLimit(symbol);
        portfolioTrades = PortfolioDA.GetTradesSymbol(symbol);
        portfolioTradesLots=LotAggregator.CombineLots(portfolioTrades);
        if (null != portfolioTrades && 0 != portfolioTrades.Count)
        {
          DateGenerator dateGenerator = new DateGenerator();
          DateTime earliestTrade = portfolioTrades[0].TradeDate;
          earliestTrade = earliestTrade.AddDays(-30);
          int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now);
          if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(symbol, selectedDayCount);
          else prices = PricingDA.GetPrices(symbol, earliestTrade);

          DateTime earliestInsiderTransactionDate=dateGenerator.GenerateFutureBusinessDate(prices[prices.Count-1].Date,30);
          insiderTransactionSummaries=InsiderTransactionDA.GetInsiderTransactionSummaries(symbol,earliestInsiderTransactionDate);

// calculate the break even price on the open trades for this symbol
          PortfolioTrades openTrades=portfolioTrades.GetOpenTrades();
          DateTime latestPricingDate = PricingDA.GetLatestDate(symbol);
          Price latestPrice = PricingDA.GetPrice(symbol, latestPricingDate);
          zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice);
// calculate the risk free rate price.  This is arrived at by investing each of the amounts in the trades for this symbol at the risk free rate.
// the total is then divided by the number of shares owned.  So this price we be the true break even considering that we could have invested risk
// free instead of owning this security.
          riskFreeRatePrice=RiskFreeRateGenerator.GeneratePriceAtRiskFreeRate(portfolioTrades);
          if (!syncTradeToBand)
          {
            DateTime earliestPricingDate = prices[prices.Count - 1].Date;
            earliestPricingDate = earliestPricingDate.AddDays(30);
            IEnumerable<PortfolioTrade> tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade);
            portfolioTrades = new PortfolioTrades();
            foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade);
            portfolioTradesLots = portfolioTrades;
          }

        }
        else
        {
          prices = PricingDA.GetPrices(symbol, selectedDayCount);
          if (null != prices && 0 != prices.Count)
          {
            DateGenerator dateGenerator = new DateGenerator();
            DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30);
            insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(symbol, earliestInsiderTransactionDate);
          }
        }
        companyName = PricingDA.GetNameForSymbol(symbol);
        BusyContent=BAND_MESSAGE;
        bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
        CreateCompositeDataSources();
      });
      workerTask.ContinueWith((continuation)=>
      {
        BusyIndicator = false;
        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("Volume");
        base.OnPropertyChanged("LeastSquares");
        base.OnPropertyChanged("Title");
        base.OnPropertyChanged("TradePoints");
        base.OnPropertyChanged("Markers");
        base.OnPropertyChanged("ZeroPoint");
        base.OnPropertyChanged("ZeroPointMarkers");
        base.OnPropertyChanged("StopLimit");
        base.OnPropertyChanged("StopLimitMarkers");
        base.OnPropertyChanged("RiskFreeRatePoint");
        base.OnPropertyChanged("RiskFreeRatePointMarkers");

        base.OnPropertyChanged("InsiderTransactionPointDisposedSmall");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall");
        base.OnPropertyChanged("InsiderTransactionPointDisposedMedium");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium");
        base.OnPropertyChanged("InsiderTransactionPointDisposedLarge");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge");

        base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall");
        base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium");
        base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge");
      });
      }
      else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
      {
        BusyIndicator = true;
        BusyContent = DATA_MESSAGE;
        Task workerTask = Task.Factory.StartNew(() =>
        {
//          if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols();
          if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols();
          else symbols = WatchListDA.GetWatchList(selectedWatchList);
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          BusyContent = BAND_MESSAGE;
          base.OnPropertyChanged("Symbols");
        });
      }
    }
// *************************************************************************** C U S T O M  B E H A V I O R **************************************************
    public Boolean LeastSquaresFit
    {
      get
      {
        return useLeastSquaresFit;
      }
      set
      {
        useLeastSquaresFit = value;
        base.OnPropertyChanged("LeastSquaresFit");
      }
    }
    public Boolean CheckBoxLegendVisible
    {
      get
      {
        return isLegendVisible;
      }
      set
      {
        isLegendVisible = value;
        base.OnPropertyChanged("CheckBoxLegendVisible");
        base.OnPropertyChanged("LegendVisible");
      }
    }
    public String LegendVisible
    {
      get
      {
        if (isLegendVisible) return "true";
        return "false";
      }
      set
      {
        isLegendVisible = Boolean.Parse(value);
        base.OnPropertyChanged("LegendVisible");
      }
    }
    public bool ShowRiskFree
    {
      get
      {
        return showRiskFree;
      }
      set
      {
        showRiskFree = value;
        base.OnPropertyChanged("ShowRiskFree");
      }
    }
    public bool ShowTradeLabels
    {
      get
      {
        return showTradeLabels;
      }
      set
      {
        showTradeLabels = value;
        if(showTradeLabels)syncTradeToBand=true;
        base.OnPropertyChanged("ShowTradeLabels");
      }
    }
    public bool SyncTradeToBand
    {
      get
      {
        return syncTradeToBand;
      }
      set
      {
        syncTradeToBand = value;
        if (syncTradeToBand) showTradeLabels = true;
        base.OnPropertyChanged("SyncTradeToBand");
      }
    }
// ************************************************************  C o m p o s i t e   D a t a  S o u r c e s *************************************************
    public void CreateCompositeDataSources()
    {
      if(null==prices||0==prices.Count)return;
      double minClose=(from Price price in prices select price.Close).Min();
// get the maximum date in the bollinger band series
      DateTime maxBollingerDate=(from BollingerBandElement bollingerBandElement in bollingerBands select bollingerBandElement.Date).Max();
// ensure that the insider transactions are clipped to the bollingerband max date.  There are some items in insider transaction summaries (options dated in the future) that will throw the graphic out of proportion
      InsiderTransactionSummaries disposedSummaries=new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed<0 && insiderTransactionSummary.TransactionDate.Date<=maxBollingerDate select insiderTransactionSummary).ToList()); 
      InsiderTransactionSummaries acquiredSummaries=new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed>0 && insiderTransactionSummary.TransactionDate.Date<=maxBollingerDate select insiderTransactionSummary).ToList()); 

			BinCollection<InsiderTransactionSummary> disposedSummariesBin=BinHelper<InsiderTransactionSummary>.CreateBins(new BinItems<InsiderTransactionSummary>(disposedSummaries),3);
			BinCollection<InsiderTransactionSummary> acquiredSummariesBin=BinHelper<InsiderTransactionSummary>.CreateBins(new BinItems<InsiderTransactionSummary>(acquiredSummaries),3);

      compositeDataSourceRiskFreeRatePoint=GainLossModel.Price(riskFreeRatePrice);
      compositeDataSourceZeroPoint= GainLossModel.Price(zeroPrice);

      if(null!=stopLimits)
      {
        compositeDataSourceStopLimit=StopLimitCompositeModel.CreateCompositeDataSource(stopLimits);
      }
      else if(null!=stopLimit && null!=zeroPrice)
      {
        compositeDataSourceStopLimit=GainLossModel.CreateCompositeDataSource(zeroPrice.Date,stopLimit.StopPrice);
      }

		  compositeDataSourceInsiderTransactionPointDisposedSmall=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[2]),minClose);
		  compositeDataSourceInsiderTransactionPointDisposedMedium=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[1]),minClose);
		  compositeDataSourceInsiderTransactionPointDisposedLarge=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[0]),minClose);
      compositeDataSourceInsiderTransactionPointAcquiredSmall=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[0]),minClose);
      compositeDataSourceInsiderTransactionPointAcquiredMedium=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[1]),minClose);
      compositeDataSourceInsiderTransactionPointAcquiredLarge=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[2]),minClose);

      compositeDataSourceK =BollingerBandModel.K(bollingerBands);
      compositeDataSourceKL1 =BollingerBandModel.KL1(bollingerBands);
      compositeDataSourceL =BollingerBandModel.L(bollingerBands);
      compositeDataSourceLP1 =BollingerBandModel.LP1(bollingerBands);
      compositeDataSourceHigh =BollingerBandModel.High(bollingerBands);
      compositeDataSourceLow =BollingerBandModel.Low(bollingerBands);
      compositeDataSourceClose =BollingerBandModel.Close(bollingerBands);
      compositeDataSourceSMAN =BollingerBandModel.SMAN(bollingerBands);
      compositeDataSourceVolume =BollingerBandModel.Volume(bollingerBands);

      compositeDataSourceLeastSquares = BollingerBandModel.LeastSquares(bollingerBands);

      compositeDataSourceTradePoints = PortfolioTradeModel.PortfolioTrades(portfolioTradesLots);
    }
    public void InitializeDataSources()
    {
      if(compositeDataSourceStopLimit!=null)compositeDataSourceStopLimit.Clear();
      if(compositeDataSourceRiskFreeRatePoint!=null)compositeDataSourceRiskFreeRatePoint.Clear();
      if(compositeDataSourceZeroPoint!=null)compositeDataSourceZeroPoint.Clear();

      if(compositeDataSourceInsiderTransactionPointDisposedSmall!=null)compositeDataSourceInsiderTransactionPointDisposedSmall.Clear();
      if(compositeDataSourceInsiderTransactionPointDisposedMedium!=null)compositeDataSourceInsiderTransactionPointDisposedMedium.Clear();
      if(compositeDataSourceInsiderTransactionPointDisposedLarge!=null)compositeDataSourceInsiderTransactionPointDisposedLarge.Clear();

      if(compositeDataSourceInsiderTransactionPointAcquiredSmall!=null)compositeDataSourceInsiderTransactionPointAcquiredSmall.Clear();
      if(compositeDataSourceInsiderTransactionPointAcquiredMedium!=null)compositeDataSourceInsiderTransactionPointAcquiredMedium.Clear();
      if(compositeDataSourceInsiderTransactionPointAcquiredLarge!=null)compositeDataSourceInsiderTransactionPointAcquiredLarge.Clear();

      if(compositeDataSourceK!=null)compositeDataSourceK.Clear();
      if(compositeDataSourceKL1!=null)compositeDataSourceKL1.Clear();
      if(compositeDataSourceL!=null)compositeDataSourceL.Clear();
      if(compositeDataSourceLP1!=null)compositeDataSourceLP1.Clear();
      if(compositeDataSourceHigh!=null)compositeDataSourceHigh.Clear();
      if(compositeDataSourceLow!=null)compositeDataSourceLow.Clear();
      if(compositeDataSourceClose!=null)compositeDataSourceClose.Clear();
      if(compositeDataSourceSMAN!=null)compositeDataSourceSMAN.Clear();
      if(compositeDataSourceVolume!=null)compositeDataSourceVolume.Clear();
      if(compositeDataSourceLeastSquares!=null)compositeDataSourceLeastSquares.Clear();
      if (compositeDataSourceTradePoints != null) compositeDataSourceTradePoints.Clear();
    }
    public CompositeDataSource RiskFreeRatePoint         
    {
      get
      {
        if(!showRiskFree)return null;
        return compositeDataSourceRiskFreeRatePoint;
      }
    }

    public CompositeDataSource ZeroPoint
    {
      get
      {
         return compositeDataSourceZeroPoint;
      }       
    }
    public CompositeDataSource StopLimit
    {
      get
      {
        return compositeDataSourceStopLimit;
      }
    }
// **************************************************************** I N S I D E R   T R A N S A C T I O N S  *************************************************
    public CompositeDataSource InsiderTransactionPointDisposedSmall
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return  compositeDataSourceInsiderTransactionPointDisposedSmall;
      }
    }
 
    public CenteredTextMarker[] InsiderTransactionPointMarkersDisposedSmall                                                                                  
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for disposed shares yet
      }
    }
    public CompositeDataSource InsiderTransactionPointDisposedMedium
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return  compositeDataSourceInsiderTransactionPointDisposedMedium;
      }
    }
 
    public CenteredTextMarker[] InsiderTransactionPointMarkersDisposedMedium                                                                                 
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for disposed shares yet
      }
    }
    public CompositeDataSource InsiderTransactionPointDisposedLarge
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return  compositeDataSourceInsiderTransactionPointDisposedLarge;
      }
    }
 
    public CenteredTextMarker[] InsiderTransactionPointMarkersDisposedLarge                                                                                  
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for disposed shares yet
      }
    }
// *****************************************************************************************************************************************************
    public CompositeDataSource InsiderTransactionPointAcquiredSmall
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return compositeDataSourceInsiderTransactionPointAcquiredSmall;
      }
    }
    public CenteredTextMarker[] InsiderTransactionPointMarkersAcquiredSmall
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for acquired shares yet.
      }
    }
    public CompositeDataSource InsiderTransactionPointAcquiredMedium
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return compositeDataSourceInsiderTransactionPointAcquiredMedium;
      }
    }
    public CenteredTextMarker[] InsiderTransactionPointMarkersAcquiredMedium
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for acquired shares yet.
      }
    }
    public CompositeDataSource InsiderTransactionPointAcquiredLarge
    {
      get
      {
        if (!showInsiderTransactions || null == insiderTransactionSummaries || null==prices) return null;
        return compositeDataSourceInsiderTransactionPointAcquiredLarge;
      }
    }
    public CenteredTextMarker[] InsiderTransactionPointMarkersAcquiredLarge
    {
      get
      {                                                                    
        return null;  // not displaying any text markers for acquired shares yet.
      }
    }
// *********************************************************************************************************************************************************************
    public CompositeDataSource K
    {
      get
      {
        return  compositeDataSourceK;
      }
    }
    public CompositeDataSource KL1
    {
      get
      {
        return  compositeDataSourceKL1;
      }
    }

    public CompositeDataSource L
    {
      get
      {
        return  compositeDataSourceL;
      }
    }
    public CompositeDataSource LP1
    {
      get
      {
        return  compositeDataSourceLP1;
      }
    }
    public CompositeDataSource High
    {
      get
      {
        return  compositeDataSourceHigh;
      }
    }
    public CompositeDataSource Low
    {
      get
      {
        return  compositeDataSourceLow;
      }
    }
    public CompositeDataSource Close
    {
      get
      {
        return  compositeDataSourceClose;
      }
    }
    public CompositeDataSource SMAN
    {
      get
      {
        return  compositeDataSourceSMAN;
      }
    }
    public CompositeDataSource Volume
    {
      get
      {
        return  compositeDataSourceVolume;
      }
    }
// ********************************************************************* L E A S T  S Q U A R E S  *************************************************************
    public CompositeDataSource LeastSquares
    {
      get
      {
        if(!useLeastSquaresFit||null==bollingerBands)return null;
        return compositeDataSourceLeastSquares;
      }
    }
// ***************************************************************************************************************************************************************
    public CompositeDataSource TradePoints
    {
      get
      {
        return  compositeDataSourceTradePoints;
      }
    }
    public CenteredTextMarker[] Markers
    {
      get
      {
        if (null == portfolioTradesLots || 0 == portfolioTradesLots.Count || !showTradeLabels) return null;
        TextMarkerOffsets textMarkerOffsets = new TextMarkerOffsets(35, 18);
        List<CenteredTextMarker> centeredTextMarkers = new List<CenteredTextMarker>();
        for (int index = 0; index < portfolioTradesLots.Count; index++)
        {
          CenteredTextMarker centerTextMarker = new CenteredTextMarker();
          PortfolioTrade portfolioTrade = portfolioTradesLots[index];
          StringBuilder sb = new StringBuilder();
          sb.Append(portfolioTrade.BuySell.Equals("B") ? "Buy " : "Sell ");
          sb.Append(Utility.FormatNumber(portfolioTrade.Shares));
          sb.Append("@");
          sb.Append(Utility.FormatCurrency(portfolioTrade.Price));
          centerTextMarker.Text = sb.ToString();
          centerTextMarker.HorizontalShift = "0";
          centerTextMarker.VerticalShift = textMarkerOffsets.GetOffset(portfolioTrade).ToString();
          centeredTextMarkers.Add(centerTextMarker);
        }
        return centeredTextMarkers.ToArray();
      }
    }
    public CenteredTextMarker[] RiskFreeRatePointMarkers
    {
      get
      {
        List<CenteredTextMarker> centeredTextMarkers = new List<CenteredTextMarker>();
        if (null == riskFreeRatePrice || !showTradeLabels ||!showRiskFree) return null;  
        CenteredTextMarker centerTextMarker = new CenteredTextMarker();
        StringBuilder sb = new StringBuilder();                                                       
        sb.Append("1yTsy ");
        sb.Append(Utility.FormatCurrency(riskFreeRatePrice.Close));
        centerTextMarker.Text = sb.ToString();
        centeredTextMarkers.Add(centerTextMarker);
        return centeredTextMarkers.ToArray();
      }
    }
    public CenteredTextMarker[] ZeroPointMarkers
    {
      get
      {
        if (null == zeroPrice || !showTradeLabels) return null;
        List<CenteredTextMarker> centeredTextMarkers = new List<CenteredTextMarker>();
        CenteredTextMarker centerTextMarker = new CenteredTextMarker();
        StringBuilder sb = new StringBuilder();
        sb.Append("Even ");
        sb.Append(Utility.FormatCurrency(zeroPrice.Close));
        Price latestPrice=prices[0];
        double parityOffsetPercent=(latestPrice.Close-zeroPrice.Close)/zeroPrice.Close;
        sb.Append("(").Append(parityOffsetPercent<0?"":"+").Append(Utility.FormatPercent(parityOffsetPercent)).Append(")");
        centerTextMarker.Text = sb.ToString();
        centeredTextMarkers.Add(centerTextMarker);
        centerTextMarker.VerticalShift="40";
        centerTextMarker.HorizontalShift="32";
        return centeredTextMarkers.ToArray();
      }
    }
    public CenteredTextMarker[] StopLimitMarkers
    {
      get
      {
        List<CenteredTextMarker> centeredTextMarkers=new List<CenteredTextMarker>();
        if(!showTradeLabels) return null;
        if(null!=stopLimits)
        {
          for(int index=0;index<stopLimits.Count;index++)
          {
            StopLimit limit=stopLimits[index];
            CenteredTextMarker centerTextMarker=new CenteredTextMarker();

            StringBuilder sb=new StringBuilder();
            sb.Append(limit.StopType).Append(" ");
            sb.Append(Utility.FormatCurrency(limit.StopPrice));
            if(index==stopLimits.Count-1)
            {
              Price latestPrice=prices[0];      // always use the most recent price when calculating the spread (in percent) from the active stop limit.
              double percentOffsetFromLow=((latestPrice.Low-limit.StopPrice)/limit.StopPrice);
              sb.Append(" (").Append(percentOffsetFromLow>0?"+":"").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
            }
            centerTextMarker.Text=sb.ToString();
            if(0==index&&stopLimits.Count>1) centerTextMarker.VerticalShift="25";
            else centerTextMarker.VerticalShift="40";
            centerTextMarker.HorizontalShift="32";
            centeredTextMarkers.Add(centerTextMarker);
          }
        }
        else
        {
          if(null==zeroPrice)return null;
          if(null==stopLimit||null==zeroPrice||!showTradeLabels) return null;
          CenteredTextMarker centerTextMarker=new CenteredTextMarker();
          Price latestPrice=prices[0];
          double percentOffsetFromLow=((latestPrice.Low-stopLimit.StopPrice)/stopLimit.StopPrice);
          StringBuilder sb=new StringBuilder();
          sb.Append(stopLimit.StopType).Append(" ");
          sb.Append(Utility.FormatCurrency(stopLimit.StopPrice));
          sb.Append(" (").Append(percentOffsetFromLow>0?"+":"").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
          centerTextMarker.Text=sb.ToString();
          centeredTextMarkers.Add(centerTextMarker);
          centerTextMarker.VerticalShift="40";
          centerTextMarker.HorizontalShift="32";
        }
        return centeredTextMarkers.ToArray();
      }
    }

// ************************************************************************************************************************************************************************
    public override String Title
    {
      get 
      {
        if (null == companyName || null == prices || 0 == prices.Count) return "";
        String displayCompanyName=companyName;
        if(displayCompanyName.Length>40)displayCompanyName=displayCompanyName.Substring(0,40)+"...";
        StringBuilder sb=new StringBuilder();
        float change=float.NaN;
        Prices prices2day=new Prices(prices.Take(2).ToList());
        if(2==prices2day.Count)change=prices2day.GetReturns()[0];
        sb.Append(displayCompanyName);
        sb.Append(" (").Append(symbol).Append(") ");
        sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[prices.Count-1].Date));
        sb.Append(" Thru ");
        sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[0].Date));
        sb.Append(" (").Append(Utility.FormatCurrency(prices[0].Close));
        sb.Append("/").Append(Utility.FormatCurrency(prices[0].Low));
        if(!float.IsNaN(change))
        {
          sb.Append(",");
          sb.Append(change>=0.00?"+":"").Append(Utility.FormatPercent((double)change));
        }
        sb.Append(")");
        return sb.ToString();
      }
    }
    public Boolean Visibility
    {
      get { return false; }
    }
    public List<Int32> DayCounts
    {
      get{return dayCounts;}
    }
    public Int32 SelectedDayCount
    {
      get { return selectedDayCount; }
      set { selectedDayCount = value; base.OnPropertyChanged("SelectedDayCount"); }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get { return symbol; }
      set
      {
        if (value == symbol || String.IsNullOrEmpty(value)) return;
        symbol = value;
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public List<String> WatchListNames
    {
      get 
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }
    private void Refresh()
    {
      base.OnPropertyChanged("SelectedSymbol");
    }
    private bool CanRefresh
    {
      get { return true; }
    }
    public ICommand RefreshCommand
    {
      get
      {
        if (refreshCommand == null)
        {
          refreshCommand = new RelayCommand(param => this.Refresh(),param=>this.CanRefresh);
        }
        return refreshCommand;
      }
    }

    public Boolean CheckBoxShowInsiderTransactions
    {
      get
      {
        return showInsiderTransactions;
      }
      set
      {
        showInsiderTransactions = value;
        base.OnPropertyChanged("CheckBoxShowInsiderTransactions");
        base.OnPropertyChanged("InsiderTransactionPointDisposedSmall");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall");
        base.OnPropertyChanged("InsiderTransactionPointDisposedMedium");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium");
        base.OnPropertyChanged("InsiderTransactionPointDisposedLarge");
        base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge");

        base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall");
        base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium");
				base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge");
        base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge");
				base.OnPropertyChanged("LeastSquares");
      }
    }
  }
}
