2 Commits

Author SHA1 Message Date
9a7b09ef7c Fix symbol cache 2026-02-22 13:36:28 -05:00
7e0c5f22b6 Work on StopLimits 2026-02-18 22:18:36 -05:00
7 changed files with 97 additions and 53 deletions

View File

@@ -36,12 +36,15 @@ namespace PortfolioManager.Cache
symbolCache=new List<string>(); symbolCache=new List<string>();
} }
} }
public void Dispose() public void Dispose()
{ {
lock(thisLock) lock(thisLock)
{ {
if(null==symbolCacheInstance || false==threadRun)return; if(null==symbolCacheInstance || false==threadRun)return;
threadRun=false; threadRun=false;
symbolCacheInstance=null;
}
if(null!=cacheMonitorThread) if(null!=cacheMonitorThread)
{ {
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[SymbolCache:Dispose]Thread state is {0}. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread))); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[SymbolCache:Dispose]Thread state is {0}. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
@@ -49,18 +52,23 @@ namespace PortfolioManager.Cache
cacheMonitorThread=null; cacheMonitorThread=null;
MDTrace.WriteLine(LogLevel.DEBUG,"[SymbolCache:Dispose] End."); MDTrace.WriteLine(LogLevel.DEBUG,"[SymbolCache:Dispose] End.");
} }
symbolCacheInstance=null;
}
} }
public List<String> GetSymbols() public List<String> GetSymbols()
{ {
lock(this) lock(thisLock)
{ {
if(0==symbolCache.Count)symbolCache=PricingDA.GetSymbols(); if(symbolCache.Count>0)return new List<string>(symbolCache);
return symbolCache; }
List<String> symbols = PricingDA.GetSymbols();
lock(thisLock)
{
if(symbolCache.Count>0)return new List<string>(symbolCache);
symbolCache=new List<String>(symbols);
return new List<string>(symbols);
} }
} }
private void ThreadProc() private void ThreadProc()
{ {
int quantums=0; int quantums=0;
@@ -68,13 +76,15 @@ namespace PortfolioManager.Cache
while(threadRun) while(threadRun)
{ {
Thread.Sleep(quantumInterval); Thread.Sleep(quantumInterval);
if(!threadRun)break;
quantums+=quantumInterval; quantums+=quantumInterval;
if(quantums>cacheRefreshAfter) if(quantums>cacheRefreshAfter)
{ {
quantums=0; quantums=0;
List<String> symbols = PricingDA.GetSymbols();
lock(thisLock) lock(thisLock)
{ {
symbolCache=PricingDA.GetSymbols(); symbolCache=new List<string>(symbols);
} }
} }
} }

View File

@@ -270,7 +270,7 @@ namespace PortfolioManager.Models
{ {
if(!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue); 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 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); 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(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); if(currentPriceLow<=position.InitialStopLimit) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
@@ -295,7 +295,7 @@ namespace PortfolioManager.Models
{ {
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
} }
StopLimit stopLimit=StopLimitDA.GetStopLimit(position.Symbol); StopLimit stopLimit=StopLimitDA.GetStopLimit(position.Symbol,position.Shares);
if(null==stopLimit || !stopLimit.StopPrice.Equals(Math.Round(position.TrailingStopLimit,2))) if(null==stopLimit || !stopLimit.StopPrice.Equals(Math.Round(position.TrailingStopLimit,2)))
{ {
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);

View File

@@ -36,17 +36,17 @@ namespace PortfolioManager.Models
return compositeDataSource; return compositeDataSource;
} }
public static CompositeDataSource CreateCompositeDataSource(DateTime xSource, double ySource) // public static CompositeDataSource CreateCompositeDataSource(DateTime xSource, double ySource)
{ // {
if (Utility.IsEpoch(xSource)) return Empty(); // if (Utility.IsEpoch(xSource)) return Empty();
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter(); // SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
sortedDateTimeDataAdapter.Add(xSource, ySource); // sortedDateTimeDataAdapter.Add(xSource, ySource);
CompositeDataSource compositeDataSource = new CompositeDataSource() // CompositeDataSource compositeDataSource = new CompositeDataSource()
{ // {
DataAdapter = sortedDateTimeDataAdapter // DataAdapter = sortedDateTimeDataAdapter
}; // };
return compositeDataSource; // return compositeDataSource;
} // }
// This is the active gain/loss as number or percent. // This is the active gain/loss as number or percent.
public static CompositeDataSource GainLoss(ModelPerformanceSeries gainLossList, bool useGainLoss) public static CompositeDataSource GainLoss(ModelPerformanceSeries gainLossList, bool useGainLoss)

View File

@@ -542,7 +542,7 @@ namespace PortfolioManager.Models
{ {
if (!IsActivePosition) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Blue); 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 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); 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 (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); if (currentPriceLow <= position.InitialStopLimit) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
@@ -569,7 +569,7 @@ namespace PortfolioManager.Models
{ {
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
} }
StopLimit stopLimit = StopLimitDA.GetStopLimit(position.Symbol); 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); if (null == stopLimit || !stopLimit.StopPrice.Equals(Math.Round(position.TrailingStopLimit, 2))) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Purple);
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
} }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Eremex.AvaloniaUI.Charts; using Eremex.AvaloniaUI.Charts;
using MarketData.MarketDataModel; using MarketData.MarketDataModel;
using MarketData.Utils;
using PortfolioManager.DataSeriesViewModels; using PortfolioManager.DataSeriesViewModels;
namespace PortfolioManager.Models namespace PortfolioManager.Models
@@ -37,5 +38,25 @@ namespace PortfolioManager.Models
}; };
return compositeDataSource; return compositeDataSource;
} }
public static CompositeDataSource CreateCompositeDataSource(DateTime xSource,StopLimits stopLimits)
{
if (null == stopLimits || 0 == stopLimits.Count) return Empty();
foreach(StopLimit stopLimit in stopLimits)
{
stopLimit.EffectiveDate = xSource;
}
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
List<StopLimit> sortedStopLimits = stopLimits.OrderBy(x => x.EffectiveDate).ToList();
foreach (StopLimit stopLimit in sortedStopLimits)
{
sortedDateTimeDataAdapter.Add(stopLimit.EffectiveDate, stopLimit.StopPrice);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
} }
} }

View File

@@ -40,7 +40,7 @@ namespace PortfolioManager.Renderers
private bool showInsiderTransactions = true; private bool showInsiderTransactions = true;
private bool showLeastSquares = true; private bool showLeastSquares = true;
private bool syncTradeToBand = true; private bool syncTradeToBand = true;
private StopLimit stopLimit = default; // StopLimits that the renderer has located using StopLimitDA private StopLimits internalStopLimits = default; // StopLimits that the renderer has located using StopLimitDA
private StopLimits externalStopLimits = default; // StopLimits that are provided to the renderer externally by a model private StopLimits externalStopLimits = default; // StopLimits that are provided to the renderer externally by a model
private PortfolioTrades portfolioTrades = default; private PortfolioTrades portfolioTrades = default;
private PortfolioTrades portfolioTradesLots = default; private PortfolioTrades portfolioTradesLots = default;
@@ -97,7 +97,8 @@ namespace PortfolioManager.Renderers
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] ENTER"); MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] ENTER");
this.selectedSymbol = selectedSymbol; this.selectedSymbol = selectedSymbol;
this.selectedDayCount = selectedDayCount; this.selectedDayCount = selectedDayCount;
stopLimit = StopLimitDA.GetStopLimit(selectedSymbol);
internalStopLimits = StopLimitDA.GetStopLimits(selectedSymbol);
portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol); portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol);
portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades); portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades);
@@ -245,9 +246,9 @@ namespace PortfolioManager.Renderers
{ {
StopLimits = StopLimitCompositeModel.CreateCompositeDataSource(externalStopLimits); StopLimits = StopLimitCompositeModel.CreateCompositeDataSource(externalStopLimits);
} }
else if (null != stopLimit && null != zeroPrice) else if (null != internalStopLimits && null != zeroPrice)
{ {
StopLimits = GainLossModel.CreateCompositeDataSource(zeroPrice.Date, stopLimit.StopPrice); StopLimits = StopLimitCompositeModel.CreateCompositeDataSource(zeroPrice.Date, internalStopLimits);
} }
(DateTime[] dates, double[] values) = StopLimits.ToXYData(); (DateTime[] dates, double[] values) = StopLimits.ToXYData();
@@ -262,6 +263,7 @@ namespace PortfolioManager.Renderers
} }
if(!showTradeLabels)return; if(!showTradeLabels)return;
Price latestPrice = prices[0];
// Add the text marker // Add the text marker
if (null != externalStopLimits) if (null != externalStopLimits)
@@ -275,7 +277,6 @@ namespace PortfolioManager.Renderers
sb.Append(Utility.FormatCurrency(limit.StopPrice)); sb.Append(Utility.FormatCurrency(limit.StopPrice));
if (index == externalStopLimits.Count - 1) if (index == externalStopLimits.Count - 1)
{ {
Price latestPrice = prices[0];
double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice); double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice);
sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")"); sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
} }
@@ -291,22 +292,42 @@ namespace PortfolioManager.Renderers
else else
{ {
if (null == zeroPrice) return; if (null == zeroPrice) return;
if (null == stopLimit || null == zeroPrice) return; if (null == internalStopLimits || null == zeroPrice) return;
Price latestPrice = prices[0]; for (int index = 0; index < internalStopLimits.Count; index++)
double percentOffsetFromLow = ((latestPrice.Low - stopLimit.StopPrice) / stopLimit.StopPrice); {
StopLimit limit = internalStopLimits[index];
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append(stopLimit.StopType).Append(" "); sb.Append(limit.StopType).Append(" ");
sb.Append(Utility.FormatCurrency(stopLimit.StopPrice)); sb.Append(Utility.FormatCurrency(limit.StopPrice));
if (index == internalStopLimits.Count - 1)
{
double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice);
sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")"); sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
}
Image image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize); Image image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize);
Coordinates coordinates = new Coordinates(latestPrice.Date.ToOADate() - offsets.Offset(OffsetDictionary.OffsetType.HorizontalOffset3PC), Coordinates coordinates = new Coordinates(limit.EffectiveDate.ToOADate(),
stopLimit.StopPrice - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC)); limit.StopPrice - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
coordinates = textMarkerManager.GetBestMarkerLocation(coordinates.X, coordinates.Y,offsets, offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC)); coordinates = textMarkerManager.GetBestMarkerLocation(coordinates.X, coordinates.Y,offsets, offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
ImageMarker imageMarker = Plotter.Plot.Add.ImageMarker(coordinates, image); ImageMarker imageMarker = Plotter.Plot.Add.ImageMarker(coordinates, image);
} }
// double percentOffsetFromLow = ((latestPrice.Low - stopLimit.StopPrice) / stopLimit.StopPrice);
// StringBuilder sb = new StringBuilder();
// sb.Append(stopLimit.StopType).Append(" ");
// sb.Append(Utility.FormatCurrency(stopLimit.StopPrice));
// sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
// Image image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize);
// Coordinates coordinates = new Coordinates(latestPrice.Date.ToOADate() - offsets.Offset(OffsetDictionary.OffsetType.HorizontalOffset3PC),
// stopLimit.StopPrice - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
// coordinates = textMarkerManager.GetBestMarkerLocation(coordinates.X, coordinates.Y,offsets, offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
// ImageMarker imageMarker = Plotter.Plot.Add.ImageMarker(coordinates, image);
}
} }
/// <summary> /// <summary>

View File

@@ -1,12 +1,4 @@
Type,PortfolioManager.ViewModels.MGSHMomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\MGSH20250331.TXT Type,PortfolioManager.ViewModels.MGSHMomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\MGSH20250331.TXT
Type,PortfolioManager.ViewModels.MomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\MG20180131.TXT Type,PortfolioManager.ViewModels.MomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\MG20180131.TXT
Type,PortfolioManager.ViewModels.CMMomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\CM20191031.TXT Type,PortfolioManager.ViewModels.CMMomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\CM20191031.TXT
Type,PortfolioManager.ViewModels.CMTrendViewModel,PathFileName,C:\boneyard\marketdata\Sessions\CMT20200817.TXT Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,ALHC,SelectedWatchList,{ALL},SelectedDayCount,90,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,SPOT,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,GWRE,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,True,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,CRS,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,True,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,T,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,True,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,NRG,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,PSO,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,True,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,PARR,SelectedWatchList,Valuations,SelectedDayCount,180,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,SH,SelectedWatchList,Valuations,SelectedDayCount,90,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True