diff --git a/MarketDataLib/Generator/Interface/IPosition.cs b/MarketDataLib/Generator/Interface/IPosition.cs new file mode 100644 index 0000000..37915fe --- /dev/null +++ b/MarketDataLib/Generator/Interface/IPosition.cs @@ -0,0 +1,13 @@ +using System; + +namespace MarketData.Generator.Interface +{ + public interface IPosition : IPurePosition + { + double TrailingStopLimit {get; set;} + + double InitialStopLimit {get; set;} + + double PositionRiskPercentDecimal {get; set;} + } +} diff --git a/MarketDataLib/Generator/Interface/IPurePosition.cs b/MarketDataLib/Generator/Interface/IPurePosition.cs new file mode 100644 index 0000000..1af1a89 --- /dev/null +++ b/MarketDataLib/Generator/Interface/IPurePosition.cs @@ -0,0 +1,19 @@ +using System; + +namespace MarketData.Generator.Interface +{ + public interface IPurePosition + { + String Symbol {get; set;} + + DateTime PurchaseDate {get; set;} + + DateTime SellDate {get; set;} + + double CurrentPrice {get; set;} + + double PurchasePrice {get; set;} + + double Shares {get; set;} + } +} diff --git a/MarketDataLib/Generator/MGSHMomentum/MGSHPositions.cs b/MarketDataLib/Generator/MGSHMomentum/MGSHPositions.cs index a084870..b863dd0 100644 --- a/MarketDataLib/Generator/MGSHMomentum/MGSHPositions.cs +++ b/MarketDataLib/Generator/MGSHMomentum/MGSHPositions.cs @@ -74,7 +74,6 @@ namespace MarketData.Generator.MGSHMomentum 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;} diff --git a/MarketDataLib/Generator/Momentum/Backtest.cs b/MarketDataLib/Generator/Momentum/Backtest.cs index f0d04b9..6e5a94d 100644 --- a/MarketDataLib/Generator/Momentum/Backtest.cs +++ b/MarketDataLib/Generator/Momentum/Backtest.cs @@ -341,6 +341,90 @@ namespace MarketData.Generator.Momentum GBPriceCache.GetInstance().Dispose(); SaveSession(); } + + // ****************************************************************************************************************************************************** + // ****************************************************************** C L O S E ********************************************************************** + // ****************************************************************************************************************************************************** + public bool ClosePosition(String symbol,DateTime purchaseDate,DateTime sellDate,double sellPrice,String pathSessionFile) + { + if(null==pathSessionFile) return false; + MGSessionParams sessionParams=null; + + PathSessionFileName=pathSessionFile; + if(null==(sessionParams=RestoreSession())) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Error loading session file {0}",pathSessionFile)); + return false; + } + if(!BackupSession()) return false; + Positions activePositions = ActivePositions.GetPositions(); + Position position=activePositions.Where(x => x.Symbol.Equals(symbol) && x.PurchaseDate.Equals(purchaseDate)).FirstOrDefault(); + if(null==position) // if it is not in the active positions then the position is already closed and we are modifying either the sell date or the sell price + { + position=AllPositions.Where(x => x.Symbol.Equals(symbol) && x.PurchaseDate.Equals(purchaseDate)).FirstOrDefault(); + if(null==position) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Cannot locate position for symbol '{0}' purchased on {1}.",symbol,purchaseDate.ToShortDateString())); + return false; + } + position.SellDate = sellDate; + CashBalance -= position.MarketValue; + position.CurrentPrice = sellPrice; + CashBalance += position.MarketValue; + SaveSession(); + return true; + } + position.SellDate = sellDate; + position.CurrentPrice = sellPrice; + CashBalance += position.MarketValue; + ActivePositions.Remove(position); + AllPositions.Add(position); + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Position for symbol '{0}' purchased on {1} is now closed.",symbol,purchaseDate.ToShortDateString())); + SaveSession(); + return true; + } + + + // ****************************************************************************************************************************************************** + // *************************************************************************** E D I T ****************************************************************** + // ****************************************************************************************************************************************************** + public bool EditPosition(String symbol,DateTime purchaseDate,double purchasePrice,String pathSessionFile) + { + if(null==pathSessionFile) return false; + MGSessionParams sessionParams=null; + + PathSessionFileName=pathSessionFile; + if(null==(sessionParams=RestoreSession())) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Error loading session file {0}",pathSessionFile)); + return false; + } + if(!BackupSession()) return false; + + Positions activePositions = ActivePositions.GetPositions(); + + Position position=activePositions.Where(x => x.Symbol.Equals(symbol) && x.PurchaseDate.Equals(purchaseDate)).FirstOrDefault(); + if(null==position) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Cannot locate position for symbol '{0}' purchased on {1}.",symbol,purchaseDate.ToShortDateString())); + return false; + } + if(!position.PurchaseDate.Equals(purchaseDate)) position.PurchaseDate=purchaseDate; + if(!position.PurchasePrice.Equals(purchasePrice)) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Adjusting Cash for Position for symbol '{0}' purchased on {1}. Original Price: {2} New Price: {3} Change in Cash: {4}", + symbol,purchaseDate.ToShortDateString(), + Utility.FormatCurrency(position.PurchasePrice), + Utility.FormatCurrency(purchasePrice), + Utility.FormatCurrency((position.PurchasePrice-purchasePrice)*position.Shares))); + CashBalance+=(position.PurchasePrice-purchasePrice)*position.Shares; + position.PurchasePrice=purchasePrice; + } + SaveSession(); + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Position for symbol '{0}' purchased on {1} has been modified and saved.",symbol,purchaseDate.ToShortDateString())); + return true; + } + // ****************************************************************************************************************************************************** // ****************************************************************** B A C K T E S T ***************************************************************** // ****************************************************************************************************************************************************** @@ -702,5 +786,26 @@ namespace MarketData.Generator.Momentum sessionParams.NonTradeableCash=NonTradeableCash; sessionManager.SaveSession(sessionParams,PathSessionFileName); } + + public bool BackupSession() + { + String[] parts=PathSessionFileName.Split('.'); + String backupFileName=parts[0]+"_"+Utility.DateTimeToStringYYYYMMDDMMSSTT(DateTime.Now)+".bak"; + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Saving session to '{0}'",backupFileName)); + MGSessionParams sessionParams=new MGSessionParams(); + MGSessionManager sessionManager=new MGSessionManager(); + sessionParams.LastUpdated=Today(); + sessionParams.TradeDate=TradeDate; + sessionParams.StartDate=StartDate; + sessionParams.AnalysisDate=AnalysisDate; + sessionParams.Configuration=Configuration; + sessionParams.ActivePositions=ActivePositions; + sessionParams.AllPositions=AllPositions; + sessionParams.Cycle=Cycle; + sessionParams.CashBalance=CashBalance; + sessionParams.NonTradeableCash=NonTradeableCash; + sessionManager.SaveSession(sessionParams,backupFileName); + return true; + } } } diff --git a/MarketDataLib/Generator/Momentum/Positions.cs b/MarketDataLib/Generator/Momentum/Positions.cs index 699779c..a6fc6e9 100644 --- a/MarketDataLib/Generator/Momentum/Positions.cs +++ b/MarketDataLib/Generator/Momentum/Positions.cs @@ -1,21 +1,18 @@ 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 MarketData.Generator.Interface; namespace MarketData.Generator.Momentum { - public class Position + public class Position : IPurePosition { public Position() { CurrentPrice=double.NaN; } + public Position(Position position) { Symbol = position.Symbol; @@ -37,27 +34,73 @@ namespace MarketData.Generator.Momentum 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() @@ -83,6 +126,7 @@ namespace MarketData.Generator.Momentum nvpCollection.Add(new NVP("SharpeRatio", SharpeRatio.ToString())); return nvpCollection; } + public static Position FromNVPCollection(NVPCollection nvpCollection) { Position position=new Position(); @@ -109,10 +153,12 @@ namespace MarketData.Generator.Momentum 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)) diff --git a/MarketDataLib/MarketDataLib.csproj b/MarketDataLib/MarketDataLib.csproj index a6c19c4..a731ad4 100644 --- a/MarketDataLib/MarketDataLib.csproj +++ b/MarketDataLib/MarketDataLib.csproj @@ -141,6 +141,7 @@ +