Files
TradeBlotter/Model/MGSHPositionModel.cs
2026-02-18 19:42:37 -05:00

602 lines
20 KiB
C#

using MarketData.Generator;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using TradeBlotter.ViewModels;
using TradeBlotter.UIUtils;
using System.Collections.Specialized;
using MarketData;
using MarketData.Generator.Momentum;
using MarketData.DataAccess;
using System.CodeDom;
using MarketData.Generator.MGSHMomentum;
using TradeBlotter.Interface;
namespace TradeBlotter.Model
{
public class MGSHPositionModelCollection : ObservableCollection<MGSHPositionModel>
{
public void Add(MGSHActivePositions activePositions)
{
List<int> slotKeys=new List<int>(activePositions.Keys);
for(int keyIndex=0;keyIndex<slotKeys.Count;keyIndex++)
{
MGSHPositions slotPositions=activePositions[slotKeys[keyIndex]];
foreach (MGSHPosition position in slotPositions) Add(new MGSHPositionModel(position, keyIndex));
}
}
public void Add(MGSHPositions allPositions)
{
foreach (MGSHPosition position in allPositions) Add(new MGSHPositionModel(position));
}
public void Add(MGSHPositions hedgePositions, int slotIndex=-1)
{
if(null == hedgePositions)return;
foreach (MGSHPosition position in hedgePositions) Add(new MGSHPositionModel(position, slotIndex));
}
public void OnCollectionChanged()
{
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset,null));
}
}
public class MGSHPositionModel : ModelBase, IPositionModel
{
private MGSHPosition position = new MGSHPosition();
private int slot;
private int priceChangeDirection=0;
private double prevPrice=double.NaN;
private DateTime lastUpdated=DateTime.Now;
private double currentPriceLow=double.NaN;
private double rsi3=double.NaN;
public MGSHPositionModel()
{
}
public MGSHPositionModel(MGSHPosition position, int slot)
{
Slot=slot;
Symbol=position.Symbol;
PurchaseDate=position.PurchaseDate;
SellDate=position.SellDate;
Shares=position.Shares;
PurchasePrice=position.PurchasePrice;
CurrentPrice=position.CurrentPrice;
Volume=position.Volume;
Return1D=position.Return1D;
CumReturn252=position.CumReturn252;
IDIndicator=position.IDIndicator;
Score=position.Score;
Velocity=position.Velocity;
PE=position.PE;
Beta=position.Beta;
InitialStopLimit=position.InitialStopLimit;
TrailingStopLimit=position.TrailingStopLimit;
LastStopAdjustment=position.LastStopAdjustment;
PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
Comment=position.Comment;
}
public MGSHPositionModel(MGSHPosition position)
{
slot=-1;
Symbol=position.Symbol;
PurchaseDate=position.PurchaseDate;
SellDate=position.SellDate;
Shares=position.Shares;
PurchasePrice=position.PurchasePrice;
CurrentPrice=position.CurrentPrice;
Volume=position.Volume;
Return1D=position.Return1D;
CumReturn252=position.CumReturn252;
IDIndicator=position.IDIndicator;
Score=position.Score;
Velocity=position.Velocity;
PE=position.PE;
Beta=position.Beta;
InitialStopLimit=position.InitialStopLimit;
TrailingStopLimit=position.TrailingStopLimit;
LastStopAdjustment=position.LastStopAdjustment;
PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
Comment=position.Comment;
}
public MGSHPosition Position
{
get{return position;}
set
{
Slot=-1;
Symbol=position.Symbol;
PurchaseDate=position.PurchaseDate;
SellDate=position.SellDate;
Shares=position.Shares;
PurchasePrice=position.PurchasePrice;
CurrentPrice=position.CurrentPrice;
Volume=position.Volume;
Return1D=position.Return1D;
CumReturn252=position.CumReturn252;
IDIndicator=position.IDIndicator;
Score=position.Score;
Velocity=position.Velocity;
PE=position.PE;
Beta=position.Beta;
InitialStopLimit=position.InitialStopLimit;
TrailingStopLimit=position.TrailingStopLimit;
LastStopAdjustment=position.LastStopAdjustment;
PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
Comment=position.Comment;
this.position.R=position.R;
}
}
public double CurrentPriceLow
{
get{return currentPriceLow;}
set
{
if(currentPriceLow==value)return;
currentPriceLow=value;
base.OnPropertyChanged("CurrentPriceLow");
base.OnPropertyChanged("CurrentPriceLowAsString");
base.OnPropertyChanged("TrailingStopLimitColor");
base.OnPropertyChanged("InitialStopLimitColor");
}
}
private void UpdateProperties()
{
base.OnPropertyChanged("CurrentPrice");
base.OnPropertyChanged("MarketValue");
base.OnPropertyChanged("ActiveMarketValue");
base.OnPropertyChanged("GainLoss");
base.OnPropertyChanged("GainLossPcnt");
base.OnPropertyChanged("Comment");
base.OnPropertyChanged("PositionRiskPercentDecimal");
base.OnPropertyChanged("R");
base.OnPropertyChanged("TotalRiskExposure");
base.OnPropertyChanged("RMultiple");
base.OnPropertyChanged("CurrentPriceColor");
base.OnPropertyChanged("TrailingStopLimitColor");
base.OnPropertyChanged("InitialStopLimitColor");
base.OnPropertyChanged("ActiveMarketValueColor");
base.OnPropertyChanged("GainLossColor");
base.OnPropertyChanged("GainLossPcntColor");
base.OnPropertyChanged("RColor");
base.OnPropertyChanged("TotalRiskExposureColor");
base.OnPropertyChanged("RMultipleColor");
}
public String Symbol
{
get{return position.Symbol;}
set{position.Symbol=value;base.OnPropertyChanged("Symbol");}
}
public String Comment
{
get{return position.Comment;}
set{position.Comment=value;base.OnPropertyChanged("Comment");}
}
public DateTime PurchaseDate
{
get{return position.PurchaseDate;}
set{position.PurchaseDate=value;base.OnPropertyChanged("PurchaseDate");}
}
public Brush PurchaseDateColor
{
get
{
DateGenerator dateGenerator=new DateGenerator();
if(!dateGenerator.IsMarketOpen(PurchaseDate)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public Brush SellDateColor
{
get
{
DateGenerator dateGenerator=new DateGenerator();
if(!dateGenerator.IsMarketOpen(SellDate)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public DateTime SellDate
{
get{return position.SellDate;}
set{position.SellDate=value;base.OnPropertyChanged("SellDate");}
}
public int DaysHeld
{
get
{
DateGenerator dateGenerator=new DateGenerator();
if(Utility.IsEpoch(SellDate))return dateGenerator.DaysBetween(PurchaseDate,DateTime.Now.Date);
return dateGenerator.DaysBetween(PurchaseDate,SellDate);
}
}
public int Slot
{
get{return slot;}
set{slot=value;base.OnPropertyChanged("Slot");}
}
public String SlotAsString
{
get
{
if(-1==Slot)return Constants.CONST_DASHES;
return Slot.ToString();
}
}
public double PositionRiskPercentDecimal
{
get
{
return position.PositionRiskPercentDecimal;
}
set
{
position.PositionRiskPercentDecimal=value;
base.OnPropertyChanged("PositionRiskPercentDecimal");
}
}
// ************************************************************************************************************************************
// ******************************************************************** R I S K *******************************************************
// ************************************************************************************************************************************
public double R
{
get
{
if(position.TrailingStopLimit>position.PurchasePrice)return 0.00; // here we are considering the current risk/share which is based on our stop limit
return position.TrailingStopLimit>position.PurchasePrice?0.00:position.PurchasePrice-position.TrailingStopLimit;
}
}
public Brush RColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public String RMultipleAsString
{
get { return Utility.FormatNumber((position.CurrentPrice - position.PurchasePrice) / (position.PurchasePrice - position.InitialStopLimit), 2, false) + "R"; } // always based on original position risk
}
public double RMultiple
{
get{return (position.CurrentPrice-position.PurchasePrice)/(position.PurchasePrice-position.InitialStopLimit);} // always based on original position risk
}
public Brush RMultipleColor
{
get
{
if (!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double TotalRiskExposure
{
get{return R*position.Shares;}
}
public Brush TotalRiskExposureColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
// ************************************************************************************************************************************
public int DaysSinceLastStopAdjustment
{
get
{
if(!IsActivePosition)return int.MinValue;
DateGenerator dateGenerator=new DateGenerator();
DateTime today=DateTime.Now;
int daysSinceLastStopAdjustment=int.MinValue;
if(Utility.IsEpoch(position.LastStopAdjustment)) daysSinceLastStopAdjustment=dateGenerator.DaysBetweenActual(today,position.PurchaseDate);
else daysSinceLastStopAdjustment=dateGenerator.DaysBetweenActual(today,position.LastStopAdjustment);
return daysSinceLastStopAdjustment;
}
}
public Brush DaysSinceLastStopAdjustmentColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
int daysSinceLastStopAdjustment=DaysSinceLastStopAdjustment;
if(int.MinValue.Equals(daysSinceLastStopAdjustment))return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(daysSinceLastStopAdjustment>=90) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
else if(daysSinceLastStopAdjustment>=60) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red); // I made them both red because yellow and purple looked horrible
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
}
}
public double Shares
{
get{return position.Shares;}
set{position.Shares=value;base.OnPropertyChanged("Shares");base.OnPropertyChanged("Exposure");base.OnPropertyChanged("ActiveExposure");base.OnPropertyChanged("MarketValue");base.OnPropertyChanged("ActiveMarketValue");base.OnPropertyChanged("GainLoss");base.OnPropertyChanged("GainLossPcnt");}
}
public double PurchasePrice
{
get{return position.PurchasePrice;}
set{position.PurchasePrice=value;base.OnPropertyChanged("PurchasePrice");base.OnPropertyChanged("Exposure");base.OnPropertyChanged("ActiveExposure");base.OnPropertyChanged("GainLoss");base.OnPropertyChanged("GainLossPcnt");}
}
public double CurrentPrice
{
get{return position.CurrentPrice;}
set
{
if(position.CurrentPrice==value)return;
position.CurrentPrice=value;
if(double.IsNaN(prevPrice)){prevPrice=position.CurrentPrice;priceChangeDirection=0;}
else if(prevPrice>position.CurrentPrice)priceChangeDirection=-1;
else if(prevPrice==position.CurrentPrice)priceChangeDirection=0;
else priceChangeDirection=1;
prevPrice=position.CurrentPrice;
UpdateProperties();
}
}
public double RSI3
{
get{return rsi3;}
set
{
if(rsi3==value)return;
rsi3=value;
base.OnPropertyChanged("RSI3");
base.OnPropertyChanged("RSI3Color");
}
}
public DateTime LastUpdated
{
get{return lastUpdated;}
set{lastUpdated=value;base.OnPropertyChanged("LastUpdated");}
}
public Brush CurrentPriceColor
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(priceChangeDirection>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
else if(priceChangeDirection<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public Brush RSI3Color
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(RSI3<10||RSI3>80)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double Exposure
{
get{return Shares*PurchasePrice;}
}
public double ActiveExposure
{
get{return IsActivePosition?Exposure:0.00;}
}
public Brush ActiveExposureColor
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double MarketValue
{
get{return Shares*CurrentPrice;}
}
public double ActiveMarketValue
{
get{return IsActivePosition?MarketValue:0.00;}
}
public Brush ActiveMarketValueColor
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if (ActiveMarketValue > Exposure) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
else if (ActiveMarketValue < Exposure) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public long Volume
{
get{return position.Volume;}
set{position.Volume=value;base.OnPropertyChanged("Volume");}
}
public double Return1D
{
get{return position.Return1D;}
set{position.Return1D=value;base.OnPropertyChanged("Return1D");}
}
public double GainLoss
{
get{return MarketValue-Exposure;}
}
public Brush GainLossColor
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(GainLoss>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
else if(GainLoss<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double GainLossPcnt
{
get{return (MarketValue-Exposure)/Exposure;}
}
public Brush GainLossPcntColor
{
get
{
if(!IsActivePosition)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(GainLoss>0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Green);
else if(GainLoss<0)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
else return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double CumReturn252
{
get{return position.CumReturn252;}
set{position.CumReturn252=value;base.OnPropertyChanged("CumReturn252");}
}
public double IDIndicator
{
get{return position.IDIndicator;}
set{position.IDIndicator=value;base.OnPropertyChanged("IDIndicator");}
}
public double Score
{
get { return position.Score; }
set { position.Score=value; base.OnPropertyChanged("Score"); }
}
public double Velocity
{
get{return position.Velocity;}
set{position.Velocity=value;base.OnPropertyChanged("Velocity");}
}
public double PE
{
get{return position.PE;}
set{position.PE=value;base.OnPropertyChanged("PE");}
}
public double Beta
{
get{return position.Beta;}
set{position.Beta=value;base.OnPropertyChanged("Beta");}
}
public bool IsActivePosition
{
get{return Utility.IsEpoch(SellDate)?true:false;}
}
public double InitialStopLimit
{
get { return position.InitialStopLimit; }
set
{
position.InitialStopLimit=value;
base.OnPropertyChanged("InitialStopLimit");
base.OnPropertyChanged("InitialStopLimitColor");
}
}
public Brush InitialStopLimitColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(!Utility.IsEpoch(position.LastStopAdjustment)) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); // if we have a trailing stop then we are no longer using the initial stop
StopLimit stopLimit=StopLimitDA.GetStopLimit(position.Symbol,position.Shares);
if(null==stopLimit||!stopLimit.StopPrice.Equals(Math.Round(position.InitialStopLimit,2))) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);
if(currentPriceLow<=position.InitialStopLimit) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
public double TrailingStopLimit
{
get { return position.TrailingStopLimit; }
set
{
position.TrailingStopLimit=value;
base.OnPropertyChanged("TrailingStopLimit");
base.OnPropertyChanged("TrailingStopLimitColor");
}
}
public Brush TrailingStopLimitColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
if(currentPriceLow <= position.TrailingStopLimit)
{
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
}
StopLimit stopLimit=StopLimitDA.GetStopLimit(position.Symbol,position.Shares);
if(null==stopLimit || !stopLimit.StopPrice.Equals(Math.Round(position.TrailingStopLimit,2))) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
// ***
public DateTime LastStopAdjustment
{
get { return position.LastStopAdjustment; }
set { position.LastStopAdjustment=value; base.OnPropertyChanged("LastStopAdjustment"); }
}
public Brush LastStopAdjustmentColor
{
get
{
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
}
}
}
}