using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using Avalonia.Media; using MarketData.DataAccess; using MarketData.Generator.MGSHMomentum; using MarketData.MarketDataModel; using MarketData.Utils; using PortfolioManager.Interface; using PortfolioManager.UIUtils; using PortfolioManager.ViewModels; namespace PortfolioManager.Models { public class MGSHPositionModelCollection : ObservableCollection { public void Add(MGSHActivePositions activePositions) { List slotKeys = new List(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("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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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 IBrush 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); 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 IBrush 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); 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 IBrush LastStopAdjustmentColor { get { if (!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); } } } }