using System;
using System.Collections.Generic;
using MarketData.Utils;
using System.Linq;
using MarketData.Generator.Interface;

namespace MarketData.Generator.Momentum
{
  public class Position : IPurePosition
  {
    public Position()
    {
      CurrentPrice=double.NaN;
    }

    public Position(Position position)
    {
      Symbol = position.Symbol;
      PurchaseDate = position.PurchaseDate;
      SellDate = position.SellDate;
      Shares = position.Shares;
      PurchasePrice = position.PurchasePrice;
      CurrentPrice = position.CurrentPrice;
      Volume = position.Volume;
      Return1D = position.Return1D;
      ZacksRank = position.ZacksRank;
      CumReturn252 = position.CumReturn252;
      IDIndicator = position.IDIndicator;
      Score=position.Score;
      MaxDrawdown = position.MaxDrawdown;
      MaxUpside = position.MaxUpside;
      Velocity = position.Velocity;
      PE = position.PE;
      Beta = position.Beta;
      SharpeRatio = position.SharpeRatio;
    }

    public static Position Clone(Position position)
    {
      Position clonedPosition = new Position();
      clonedPosition.Symbol = position.Symbol;
      clonedPosition.PurchaseDate = position.PurchaseDate;
      clonedPosition.SellDate = position.SellDate;
      clonedPosition.Shares = position.Shares;
      clonedPosition.PurchasePrice = position.PurchasePrice;
      clonedPosition.CurrentPrice = position.CurrentPrice;
      clonedPosition.Volume = position.Volume;
      clonedPosition.Return1D = position.Return1D;
      clonedPosition.ZacksRank = position.ZacksRank;
      clonedPosition.CumReturn252 = position.CumReturn252;
      clonedPosition.IDIndicator = position.IDIndicator;
      clonedPosition.Score = position.Score;
      clonedPosition.MaxDrawdown = position.MaxDrawdown;
      clonedPosition.MaxUpside = position.MaxUpside;
      clonedPosition.Velocity = position.Velocity;
      clonedPosition.PE = position.PE;
      clonedPosition.Beta = position.Beta;
      clonedPosition.SharpeRatio = position.SharpeRatio;
      return clonedPosition;
    }

    public String Symbol{get;set;}

    public DateTime PurchaseDate{get;set;}

    public DateTime SellDate{get;set;}

    public double Shares{get;set;}

    public double PurchasePrice{get;set;}

    public double CurrentPrice{get;set;}

    public double Exposure{get{return Shares*PurchasePrice;}}

    public double MarketValue{get{return Shares*CurrentPrice;}}

    public long Volume{get;set;}

    public double Return1D{get;set;}

    public double GainLoss{get{return MarketValue-Exposure;}}

    public double GainLossPcnt{get{return (MarketValue-Exposure)/Exposure;}}

    public String ZacksRank{get;set;}

    public double CumReturn252{get;set;}

    public double IDIndicator{get;set;}

    public double Score{get;set;}

    public double MaxDrawdown{get;set;}

    public double MaxUpside{get;set;}

    public double Velocity{get;set;}

    public double PE{get;set;}

    public double Beta{get;set;}

    public double SharpeRatio { get; set; }

    public virtual NVPCollection ToNVPCollection()
    {
      NVPCollection nvpCollection=new NVPCollection();
      nvpCollection.Add(new NVP("Symbol",Symbol.ToString()));
      nvpCollection.Add(new NVP("PurchaseDate",PurchaseDate.ToString()));
      nvpCollection.Add(new NVP("SellDate",SellDate.ToString()));
      nvpCollection.Add(new NVP("Shares",Shares.ToString()));
      nvpCollection.Add(new NVP("PurchasePrice",PurchasePrice.ToString()));
      nvpCollection.Add(new NVP("CurrentPrice",CurrentPrice.ToString()));
      nvpCollection.Add(new NVP("Volume",Volume.ToString()));
      nvpCollection.Add(new NVP("Return1D",Return1D.ToString()));
      nvpCollection.Add(new NVP("ZacksRank",ZacksRank));
      nvpCollection.Add(new NVP("CumReturn252",CumReturn252.ToString()));
      nvpCollection.Add(new NVP("IDIndicator",IDIndicator.ToString()));
      nvpCollection.Add(new NVP("Score",Score.ToString()));
      nvpCollection.Add(new NVP("MaxDrawdown",MaxDrawdown.ToString()));
      nvpCollection.Add(new NVP("MaxUpside",MaxUpside.ToString()));
      nvpCollection.Add(new NVP("Velocity",Velocity.ToString()));
      nvpCollection.Add(new NVP("PE",PE.ToString()));
      nvpCollection.Add(new NVP("Beta",Beta.ToString()));
      nvpCollection.Add(new NVP("SharpeRatio", SharpeRatio.ToString()));
      return nvpCollection;
    }

    public static Position FromNVPCollection(NVPCollection nvpCollection)
    {
      Position position=new Position();
      NVPDictionary nvpDictionary=nvpCollection.ToDictionary();
      position.Symbol=nvpDictionary["Symbol"].Get<String>();
      position.PurchaseDate=nvpDictionary["PurchaseDate"].Get<DateTime>();
      position.SellDate=nvpDictionary["SellDate"].Get<DateTime>();
      position.Shares=nvpDictionary["Shares"].Get<double>();
      position.PurchasePrice=nvpDictionary["PurchasePrice"].Get<double>();
      position.CurrentPrice=nvpDictionary["CurrentPrice"].Get<double>();
      position.Volume=nvpDictionary["Volume"].Get<long>();
      position.Return1D=nvpDictionary["Return1D"].Get<long>();
      if(nvpDictionary.ContainsKey("ZacksRank"))position.ZacksRank=nvpDictionary["ZacksRank"].Get<String>();
      position.CumReturn252=nvpDictionary["CumReturn252"].Get<long>();
      position.IDIndicator=nvpDictionary["IDIndicator"].Get<double>();
      if(nvpDictionary.ContainsKey("MaxDrawdown"))position.MaxDrawdown=nvpDictionary["MaxDrawdown"].Get<double>();
      if(nvpDictionary.ContainsKey("MaxUpside"))position.MaxUpside=nvpDictionary["MaxUpside"].Get<double>();
      position.Velocity=nvpDictionary["Velocity"].Get<double>();
      position.PE=nvpDictionary["PE"].Get<double>();
      position.Beta=nvpDictionary["Beta"].Get<double>();
      if (nvpDictionary.ContainsKey("SharpeRatio")) position.SharpeRatio = nvpDictionary["SharpeRatio"].Get<double>();
      else position.SharpeRatio = double.NaN;
      if(nvpDictionary.ContainsKey("Score")) position.Score=nvpDictionary["Score"].Get<double>();
      else position.Score=double.NaN;
      return position;
    }

    public static void DisplayHeader()
    {
      MDTrace.WriteLine(LogLevel.DEBUG, "Symbol,Purchase Date,Shares,Purchase Price,Exposure,Volume,Return1D,Sell Date,Sell Price,Market Value,Gain Loss,Gain Loss(%),CumReturn252,IDIndicator,Score,MaxDrawdown,MaxUpside,Velocity,PE,Beta,SharpeRatio");
    }

    public void Display()
    {
      if (Utility.IsEpoch(SellDate) && double.IsNaN(CurrentPrice))
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},N/A,N/A,N/A,N/A,N/A,{7},{8},{9},{10},{11},{12},{13},{14},{15}",
          Symbol,
          Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
          Shares,
          Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
          Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
          Volume,
          Utility.AddQuotes(Utility.FormatPercent(Return1D)),
          Utility.AddQuotes(Utility.FormatPercent(CumReturn252)),
          Utility.AddQuotes(Utility.FormatNumber(IDIndicator)),
          Utility.AddQuotes(Utility.FormatNumber(Score)),
          Utility.AddQuotes(Utility.FormatPercent(MaxDrawdown)),
          Utility.AddQuotes(Utility.FormatPercent(MaxUpside)),
          Utility.AddQuotes(Utility.FormatPercent(Velocity)),
          Utility.AddQuotes(Utility.FormatNumber(PE)),
          Utility.AddQuotes(Utility.FormatNumber(Beta)),
          Utility.AddQuotes(Utility.FormatNumber(SharpeRatio))
          ));
      }
      else
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}",
        Symbol,
        Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
        Shares,
        Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
        Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
        Volume,
        Utility.AddQuotes(Utility.FormatPercent(Return1D)),
        Utility.DateTimeToStringMMHDDHYYYY(SellDate),
        Utility.AddQuotes(Utility.FormatCurrency(CurrentPrice)),
        Utility.AddQuotes(Utility.FormatCurrency(MarketValue)),
        Utility.AddQuotes(Utility.FormatCurrency(GainLoss)),
        Utility.FormatPercent(GainLossPcnt),
        Utility.AddQuotes(Utility.FormatPercent(CumReturn252)),
        Utility.AddQuotes(Utility.FormatNumber(IDIndicator)),
        Utility.AddQuotes(Utility.FormatNumber(Score)),
        Utility.AddQuotes(Utility.FormatPercent(MaxDrawdown)),
        Utility.AddQuotes(Utility.FormatPercent(MaxUpside)),
        Utility.AddQuotes(Utility.FormatPercent(Velocity)),
        Utility.AddQuotes(Utility.FormatNumber(PE)),
        Utility.AddQuotes(Utility.FormatNumber(Beta)),
        Utility.AddQuotes(Utility.FormatNumber(SharpeRatio))
        ));
      }
    }
  }
// ****************************************************************************************************************************************************************
  public class Positions : List<Position>
  {
    public Positions()
    {
    }
    public Positions(Positions positions)
    {
      foreach(Position position in positions)Add(position);
    }
    public Positions(List<Position> positions)
    {
      foreach(Position position in positions)Add(position);
    }
    public Positions(Position position)
    {
      Add(position);
    }
    public void Add(Positions positions)
    {
      foreach(Position position in positions)Add(position);
    }
    public double Exposure
    {
      get
      {
        return (from Position position in this select position.PurchasePrice*position.Shares).Sum();
      }
    }
    public double MarketValue
    {
      get
      {
        return (from Position position in this select position.CurrentPrice*position.Shares).Sum();
      }
    }
    public NVPCollections ToNVPCollections()
    {
      NVPCollections nvpCollections=new NVPCollections();
      foreach(Position position in this)
      {
        nvpCollections.Add(position.ToNVPCollection());
      }
      return nvpCollections;
    }
    public static Positions FromNVPCollections(NVPCollections nvpCollections)
    {
      Positions positions=new Positions();
      foreach(NVPCollection nvpCollection in nvpCollections)
      {
        positions.Add(Position.FromNVPCollection(nvpCollection)); 
      }
      return positions;
    }
    public void DisplayTopFive()
    {
      Positions positions = new Positions(this.OrderByDescending(x => x.GainLossPcnt).Take(5).ToList());
      Position.DisplayHeader();
      for (int index = 0; index < positions.Count; index++)
      {
        Position position = positions[index];
        position.Display();
      }
    }
    public void DisplayBottomFive()
    {
      Positions positions = new Positions(this.OrderBy(x => x.GainLossPcnt).Take(5).ToList());
      Position.DisplayHeader();
      for (int index = 0; index < positions.Count; index++)
      {
        Position position = positions[index];
        position.Display();
      }
    }
    public void Display()
    {
      Position.DisplayHeader();
      for(int index=0;index<Count;index++)
      {
        Position position=this[index];
        position.Display();
      }
      if(this.Any(x=>Utility.IsEpoch(x.SellDate)||double.IsNaN(x.CurrentPrice)))
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("EXPOSURE:{0}", Utility.FormatCurrency(this.Exposure)));
      }
      else
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("GAIN/LOSS {0}", Utility.FormatCurrency(this.Sum(x => x.GainLoss)))); 
      }
      MDTrace.WriteLine(LogLevel.DEBUG,"****************************************************************************************************************************");      
    }
  }
}
