Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01c2516eaa | |||
| 9a7b09ef7c | |||
| 7e0c5f22b6 |
@@ -57,6 +57,7 @@ namespace PortfolioManager.Cache
|
||||
{
|
||||
lock (thisLock)
|
||||
{
|
||||
DisposeBitmaps();
|
||||
imageCache = new Dictionary<ImageType, Bitmap>();
|
||||
}
|
||||
}
|
||||
@@ -66,22 +67,30 @@ namespace PortfolioManager.Cache
|
||||
lock (thisLock)
|
||||
{
|
||||
if (null == imageCacheInstance) return;
|
||||
List<Bitmap> bitmaps = imageCache.Values.ToList();
|
||||
foreach (Bitmap bitmap in bitmaps)
|
||||
{
|
||||
bitmap.Dispose();
|
||||
}
|
||||
DisposeBitmaps();
|
||||
imageCache = null;
|
||||
imageCacheInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IImage GetImage(ImageCache.ImageType imageType)
|
||||
|
||||
private void DisposeBitmaps()
|
||||
{
|
||||
lock(this)
|
||||
if(null == imageCache)return;
|
||||
List<Bitmap> bitmaps = imageCache.Values.ToList();
|
||||
foreach (Bitmap bitmap in bitmaps)
|
||||
{
|
||||
return imageCache[imageType];
|
||||
bitmap.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public IImage GetImage(ImageType imageType)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
if (imageCache == null)throw new ObjectDisposedException(nameof(ImageCache));
|
||||
if (!imageCache.TryGetValue(imageType, out var bitmap))throw new KeyNotFoundException($"Image {imageType} not found in cache.");
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace PortfolioManager.Cache
|
||||
public class SymbolCache : IDisposable
|
||||
{
|
||||
private List<String> symbolCache=new List<String>();
|
||||
private Object thisLock=new Object();
|
||||
private readonly Object thisLock=new Object();
|
||||
private readonly Object fetchLock = new Object();
|
||||
private Thread cacheMonitorThread=null;
|
||||
private volatile bool threadRun=true;
|
||||
private int cacheRefreshAfter=60000; // Invalidate cache after
|
||||
@@ -36,31 +37,42 @@ namespace PortfolioManager.Cache
|
||||
symbolCache=new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
if(null==symbolCacheInstance || false==threadRun)return;
|
||||
if(null==symbolCacheInstance || false==threadRun)return;
|
||||
threadRun=false;
|
||||
if(null!=cacheMonitorThread)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[SymbolCache:Dispose]Thread state is {0}. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
|
||||
cacheMonitorThread.Join(5000);
|
||||
cacheMonitorThread=null;
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"[SymbolCache:Dispose] End.");
|
||||
}
|
||||
symbolCacheInstance=null;
|
||||
}
|
||||
if(null!=cacheMonitorThread)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[SymbolCache:Dispose]Thread state is {0}. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
|
||||
cacheMonitorThread.Join(5000);
|
||||
cacheMonitorThread=null;
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"[SymbolCache:Dispose] End.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> GetSymbols()
|
||||
{
|
||||
lock(this)
|
||||
lock(thisLock)
|
||||
{
|
||||
if(0==symbolCache.Count)symbolCache=PricingDA.GetSymbols();
|
||||
return symbolCache;
|
||||
if(symbolCache.Count>0)return new List<string>(symbolCache);
|
||||
}
|
||||
lock(fetchLock)
|
||||
{
|
||||
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()
|
||||
{
|
||||
int quantums=0;
|
||||
@@ -68,16 +80,18 @@ namespace PortfolioManager.Cache
|
||||
while(threadRun)
|
||||
{
|
||||
Thread.Sleep(quantumInterval);
|
||||
if(!threadRun)break;
|
||||
quantums+=quantumInterval;
|
||||
if(quantums>cacheRefreshAfter)
|
||||
{
|
||||
quantums=0;
|
||||
List<String> symbols = PricingDA.GetSymbols();
|
||||
lock(thisLock)
|
||||
{
|
||||
symbolCache=PricingDA.GetSymbols();
|
||||
symbolCache=new List<string>(symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ namespace PortfolioManager.Models
|
||||
{
|
||||
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);
|
||||
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);
|
||||
@@ -295,7 +295,7 @@ namespace PortfolioManager.Models
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -36,17 +36,17 @@ namespace PortfolioManager.Models
|
||||
return compositeDataSource;
|
||||
}
|
||||
|
||||
public static CompositeDataSource CreateCompositeDataSource(DateTime xSource, double ySource)
|
||||
{
|
||||
if (Utility.IsEpoch(xSource)) return Empty();
|
||||
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
|
||||
sortedDateTimeDataAdapter.Add(xSource, ySource);
|
||||
CompositeDataSource compositeDataSource = new CompositeDataSource()
|
||||
{
|
||||
DataAdapter = sortedDateTimeDataAdapter
|
||||
};
|
||||
return compositeDataSource;
|
||||
}
|
||||
// public static CompositeDataSource CreateCompositeDataSource(DateTime xSource, double ySource)
|
||||
// {
|
||||
// if (Utility.IsEpoch(xSource)) return Empty();
|
||||
// SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
|
||||
// sortedDateTimeDataAdapter.Add(xSource, ySource);
|
||||
// CompositeDataSource compositeDataSource = new CompositeDataSource()
|
||||
// {
|
||||
// DataAdapter = sortedDateTimeDataAdapter
|
||||
// };
|
||||
// return compositeDataSource;
|
||||
// }
|
||||
|
||||
// This is the active gain/loss as number or percent.
|
||||
public static CompositeDataSource GainLoss(ModelPerformanceSeries gainLossList, bool useGainLoss)
|
||||
|
||||
@@ -542,7 +542,7 @@ namespace PortfolioManager.Models
|
||||
{
|
||||
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);
|
||||
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);
|
||||
@@ -569,7 +569,7 @@ namespace PortfolioManager.Models
|
||||
{
|
||||
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);
|
||||
return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eremex.AvaloniaUI.Charts;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Utils;
|
||||
using PortfolioManager.DataSeriesViewModels;
|
||||
|
||||
namespace PortfolioManager.Models
|
||||
@@ -37,5 +38,25 @@ namespace PortfolioManager.Models
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace PortfolioManager.Renderers
|
||||
private bool showInsiderTransactions = true;
|
||||
private bool showLeastSquares = 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 PortfolioTrades portfolioTrades = default;
|
||||
private PortfolioTrades portfolioTradesLots = default;
|
||||
@@ -97,7 +97,8 @@ namespace PortfolioManager.Renderers
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] ENTER");
|
||||
this.selectedSymbol = selectedSymbol;
|
||||
this.selectedDayCount = selectedDayCount;
|
||||
stopLimit = StopLimitDA.GetStopLimit(selectedSymbol);
|
||||
|
||||
internalStopLimits = StopLimitDA.GetStopLimits(selectedSymbol);
|
||||
portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol);
|
||||
portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades);
|
||||
|
||||
@@ -245,9 +246,9 @@ namespace PortfolioManager.Renderers
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -262,6 +263,7 @@ namespace PortfolioManager.Renderers
|
||||
}
|
||||
|
||||
if(!showTradeLabels)return;
|
||||
Price latestPrice = prices[0];
|
||||
|
||||
// Add the text marker
|
||||
if (null != externalStopLimits)
|
||||
@@ -275,7 +277,6 @@ namespace PortfolioManager.Renderers
|
||||
sb.Append(Utility.FormatCurrency(limit.StopPrice));
|
||||
if (index == externalStopLimits.Count - 1)
|
||||
{
|
||||
Price latestPrice = prices[0];
|
||||
double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice);
|
||||
sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
|
||||
}
|
||||
@@ -291,21 +292,41 @@ namespace PortfolioManager.Renderers
|
||||
else
|
||||
{
|
||||
if (null == zeroPrice) return;
|
||||
if (null == stopLimit || null == zeroPrice) return;
|
||||
Price latestPrice = prices[0];
|
||||
double percentOffsetFromLow = ((latestPrice.Low - stopLimit.StopPrice) / stopLimit.StopPrice);
|
||||
if (null == internalStopLimits || null == zeroPrice) return;
|
||||
for (int index = 0; index < internalStopLimits.Count; index++)
|
||||
{
|
||||
StopLimit limit = internalStopLimits[index];
|
||||
|
||||
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));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(limit.StopType).Append(" ");
|
||||
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(")");
|
||||
}
|
||||
Image image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize);
|
||||
Coordinates coordinates = new Coordinates(limit.EffectiveDate.ToOADate(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
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.CMMomentumViewModel,PathFileName,C:\boneyard\marketdata\Sessions\CM20191031.TXT
|
||||
Type,PortfolioManager.ViewModels.CMTrendViewModel,PathFileName,C:\boneyard\marketdata\Sessions\CMT20200817.TXT
|
||||
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
|
||||
Type,PortfolioManager.ViewModels.BollingerBandViewModel,SelectedSymbol,ALHC,SelectedWatchList,{ALL},SelectedDayCount,90,SyncTradeToBand,False,ShowTradeLabels,True,UseLeastSquaresFit,True,ShowInsiderTransactions,True
|
||||
|
||||
Reference in New Issue
Block a user