315 lines
16 KiB
C#
315 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.DataAccess;
|
|
using MarketData.Utils;
|
|
using System.Linq;
|
|
using MarketData.Helper;
|
|
using MarketData.Numerical;
|
|
using System.Reflection;
|
|
|
|
namespace MarketData.Generator.CMTrend
|
|
{
|
|
public class Position
|
|
{
|
|
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;
|
|
R=position.R;
|
|
C=position.C;
|
|
PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
|
|
InitialStopLimit=position.InitialStopLimit;
|
|
TrailingStopLimit=position.TrailingStopLimit;
|
|
Volume=position.Volume;
|
|
Volatility=position.Volatility;
|
|
LastStopAdjustment=position.LastStopAdjustment;
|
|
Comment=position.Comment;
|
|
}
|
|
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.R=position.R;
|
|
clonedPosition.C=position.C;
|
|
clonedPosition.PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
|
|
clonedPosition.InitialStopLimit=position.InitialStopLimit;
|
|
clonedPosition.TrailingStopLimit=position.TrailingStopLimit;
|
|
clonedPosition.Volume=position.Volume;
|
|
clonedPosition.Volatility=position.Volatility;
|
|
clonedPosition.LastStopAdjustment=position.LastStopAdjustment;
|
|
clonedPosition.Comment=position.Comment;
|
|
return clonedPosition;
|
|
}
|
|
public String Symbol { get; set; }
|
|
public DateTime PurchaseDate { get; set; }
|
|
public DateTime SellDate { get; set; }
|
|
public double Shares { get; set; } // This is actual shares (round down P to the nearest whole number)
|
|
public double PurchasePrice { get; set; }
|
|
public double CurrentPrice { get; set; } // When the position is sold the current price will hold the sell price
|
|
public double Exposure { get { return Shares*PurchasePrice; } } // Derived
|
|
public double MarketValue { get { return Shares*CurrentPrice; } } // Derived
|
|
public double GainLoss { get { return MarketValue-Exposure; } } // Derived
|
|
public double GetGainLoss(Price currentPrice) { return (Shares*currentPrice.Close)-Exposure; } // get the gain loss based upon the given price
|
|
public double GainLossPcnt { get { return (MarketValue-Exposure)/Exposure; } } // Derived
|
|
public double PositionRiskPercentDecimal { get; set; } // (i.e.) .06 = 6%
|
|
public double R { get; set; } // PositionRiskPercentDecimal*PurchasePrice
|
|
public double C { get; set; } // AvailableCash * TotalRiskPercentDecimal
|
|
public double P { get { return C/R; } } // Derived. This is the number of shares to buy according to risk limits
|
|
public double TrailingStopLimit { get; set; } // This is the trailing stop limit.
|
|
public double InitialStopLimit { get; set; } // This is the initial stop limit.
|
|
public DateTime LastStopAdjustment { get; set; }
|
|
public double TotalRiskExposure { get { return R*Shares; } } // This is the total risk in dollars that we are exposed to
|
|
public double RMultiple { get { return (CurrentPrice-PurchasePrice)/R; } } // Derived.
|
|
public String RMultipleAsString
|
|
{
|
|
get
|
|
{
|
|
return Utility.FormatNumber(RMultiple,2,false)+"R";
|
|
}
|
|
} // Derived.
|
|
public double Volatility { get; set; }
|
|
public long Volume { get; set; }
|
|
public String Comment { 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()));
|
|
if(!double.IsNaN(CurrentPrice)) nvpCollection.Add(new NVP("CurrentPrice",CurrentPrice.ToString()));
|
|
if(!double.IsNaN(Exposure)) nvpCollection.Add(new NVP("Exposure",Exposure.ToString()));
|
|
if(!double.IsNaN(MarketValue)) nvpCollection.Add(new NVP("MarketValue",MarketValue.ToString()));
|
|
if(!double.IsNaN(GainLoss)) nvpCollection.Add(new NVP("GainLoss",GainLoss.ToString()));
|
|
if(!double.IsNaN(GainLossPcnt)) nvpCollection.Add(new NVP("GainLossPcnt",GainLossPcnt.ToString()));
|
|
if(!double.IsNaN(PositionRiskPercentDecimal)) nvpCollection.Add(new NVP("PositionRiskDecimal",PositionRiskPercentDecimal.ToString()));
|
|
if(!double.IsNaN(R)) nvpCollection.Add(new NVP("R",R.ToString()));
|
|
if(!double.IsNaN(C)) nvpCollection.Add(new NVP("C",C.ToString()));
|
|
if(!double.IsNaN(C)) nvpCollection.Add(new NVP("P",P.ToString()));
|
|
if(!double.IsNaN(InitialStopLimit)) nvpCollection.Add(new NVP("InitialStopLimit",InitialStopLimit.ToString()));
|
|
if(!double.IsNaN(TrailingStopLimit)) nvpCollection.Add(new NVP("TrailingStopLimit",TrailingStopLimit.ToString()));
|
|
if(!double.IsNaN(TotalRiskExposure)) nvpCollection.Add(new NVP("TotalRiskExposure",TotalRiskExposure.ToString()));
|
|
if(!double.IsNaN(RMultiple)) nvpCollection.Add(new NVP("RMultiple",RMultipleAsString));
|
|
if(!double.IsNaN(Volatility)) nvpCollection.Add(new NVP("Volatility",Volatility.ToString()));
|
|
nvpCollection.Add(new NVP("Volume",Volume.ToString()));
|
|
nvpCollection.Add(new NVP("LastStopAdjustment",LastStopAdjustment.ToString()));
|
|
if(null!=Comment) nvpCollection.Add(new NVP("Comment",Comment));
|
|
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>();
|
|
if(nvpDictionary.ContainsKey("CurrentPrice")) position.CurrentPrice=nvpDictionary["CurrentPrice"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("R")) position.R=nvpDictionary["R"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("C")) position.C=nvpDictionary["C"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("PositionRiskDecimal")) position.PositionRiskPercentDecimal=nvpDictionary["PositionRiskDecimal"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("InitialStopLimit")) position.InitialStopLimit=nvpDictionary["InitialStopLimit"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("TrailingStopLimit")) position.TrailingStopLimit=nvpDictionary["TrailingStopLimit"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("Volatility")) position.Volatility=nvpDictionary["Volatility"].Get<double>();
|
|
if(nvpDictionary.ContainsKey("Volume")) position.Volume=nvpDictionary["Volume"].Get<int>();
|
|
if(nvpDictionary.ContainsKey("LastStopAdjustment")) position.LastStopAdjustment=nvpDictionary["LastStopAdjustment"].Get<DateTime>();
|
|
if(nvpDictionary.ContainsKey("Comment")) position.Comment=nvpDictionary["Comment"].Get<String>();
|
|
return position;
|
|
}
|
|
public void Display()
|
|
{
|
|
if(Utility.IsEpoch(SellDate)&&double.IsNaN(CurrentPrice))
|
|
{
|
|
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},{21}",
|
|
Symbol,
|
|
Shares,
|
|
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
|
|
Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(InitialStopLimit)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(TrailingStopLimit)),
|
|
Utility.AddQuotes(Utility.DateTimeToStringMMHDDHYYYY(LastStopAdjustment)),
|
|
Utility.AddQuotes(Utility.FormatNumber(Volatility,2)),
|
|
Utility.AddQuotes(Utility.FormatNumber(Volume,0)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(R)),
|
|
Utility.AddQuotes(Utility.FormatNumber(PositionRiskPercentDecimal,3)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(C)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(TotalRiskExposure)),
|
|
Utility.AddQuotes(Utility.FormatNumber(RMultiple,3)),
|
|
Utility.AddQuotes(RMultipleAsString),
|
|
Utility.IsEpoch(SellDate)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(SellDate),
|
|
"N/A",
|
|
Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
|
|
"N/A",
|
|
"N/A",
|
|
"N/A",
|
|
null==Comment?"":Comment
|
|
));
|
|
}
|
|
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},{21}",
|
|
Symbol,
|
|
Shares,
|
|
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
|
|
Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(InitialStopLimit)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(TrailingStopLimit)),
|
|
Utility.IsEpoch(LastStopAdjustment)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(LastStopAdjustment),
|
|
Utility.AddQuotes(Utility.FormatNumber(Volatility,2)),
|
|
Utility.AddQuotes(Utility.FormatNumber(Volume,0)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(R)),
|
|
Utility.AddQuotes(Utility.FormatNumber(PositionRiskPercentDecimal,3)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(C)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(TotalRiskExposure)),
|
|
Utility.AddQuotes(Utility.FormatNumber(RMultiple,3)),
|
|
Utility.AddQuotes(RMultipleAsString),
|
|
Utility.IsEpoch(SellDate)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(SellDate),
|
|
Utility.AddQuotes(Utility.FormatCurrency(CurrentPrice)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(MarketValue)),
|
|
Utility.AddQuotes(Utility.FormatCurrency(GainLoss)),
|
|
Utility.FormatPercent(GainLossPcnt),
|
|
null==Comment?"":Comment
|
|
));
|
|
}
|
|
}
|
|
public static void DisplayHeader()
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,"Symbol,Shares,Purchase Date,Purchase Price,Initial Stop Limit,Trailing Stop Limit,Last Stop Adjustment,Volatility,Volume,R,PositionRiskPercentDecimal,C,TotalRiskExposure,RMultiple,RMultipleString,Sell Date,Sell Price,Exposure,Market Value,Gain Loss,Gain Loss(%),Comment");
|
|
}
|
|
}
|
|
// ****************************************************************************************************************************************************************
|
|
public class Positions:List<Position>
|
|
{
|
|
public Positions()
|
|
{
|
|
}
|
|
public Positions(Positions positions)
|
|
{
|
|
if(null==positions) return;
|
|
foreach(Position position in positions) Add(position);
|
|
}
|
|
public Positions(List<Position> positions)
|
|
{
|
|
if(null==positions) return;
|
|
foreach(Position position in positions) Add(position);
|
|
}
|
|
public Positions(Position position)
|
|
{
|
|
if(null==position) return;
|
|
Add(position);
|
|
}
|
|
public void Add(Positions positions)
|
|
{
|
|
if(null==positions) return;
|
|
foreach(Position position in positions) Add(position);
|
|
}
|
|
public int PositionsOn(DateTime purchaseDate)
|
|
{
|
|
return this.Count(x => x.PurchaseDate.Equals(purchaseDate));
|
|
}
|
|
public double GetExposure()
|
|
{
|
|
Positions openPositions=new Positions(this.Where(x => Utility.IsEpoch(x.SellDate)).ToList());
|
|
return (from Position position in openPositions select position.PurchasePrice*position.Shares).Sum();
|
|
}
|
|
public double GetMarketValue()
|
|
{
|
|
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
|
|
if(null==closedPositions||0==closedPositions.Count) return 0.00;
|
|
return closedPositions.Select(x => x.CurrentPrice*x.Shares).Sum();
|
|
}
|
|
public List<String> GetSymbols()
|
|
{
|
|
return (from Position position in this select position.Symbol).Distinct().ToList();
|
|
}
|
|
public double GetGainLoss()
|
|
{
|
|
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
|
|
if(null==closedPositions||0==closedPositions.Count) return 0.00;
|
|
double totalMarketValue=closedPositions.Select(x => x.Shares*x.CurrentPrice).Sum();
|
|
double totalExposure=closedPositions.Select(x => x.Shares*x.PurchasePrice).Sum();
|
|
return totalMarketValue-totalExposure;
|
|
}
|
|
public double GetGainLossPercent()
|
|
{
|
|
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
|
|
if(null==closedPositions||0==closedPositions.Count) return 0.00;
|
|
double totalMarketValue=closedPositions.Select(x => x.Shares*x.CurrentPrice).Sum();
|
|
double totalExposure=closedPositions.Select(x => x.Shares*x.PurchasePrice).Sum();
|
|
return (totalMarketValue-totalExposure)/totalExposure;
|
|
}
|
|
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 AddFromNVPCollection(NVPCollection nvpCollection)
|
|
{
|
|
Add(Position.FromNVPCollection(nvpCollection));
|
|
}
|
|
public void DisplayTop(int count=10)
|
|
{
|
|
Positions positions=new Positions(this.OrderByDescending(x => x.GainLossPcnt).Take(count).ToList());
|
|
Position.DisplayHeader();
|
|
for(int index=0;index<positions.Count;index++)
|
|
{
|
|
Position position=positions[index];
|
|
position.Display();
|
|
}
|
|
}
|
|
public void DisplayBottom(int count=10)
|
|
{
|
|
Positions positions=new Positions(this.OrderBy(x => x.GainLossPcnt).Take(count).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();
|
|
}
|
|
MDTrace.WriteLine(LogLevel.DEBUG,"****************************************************************************************************************************");
|
|
}
|
|
}
|
|
}
|
|
|