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 @@
+