Commit Latest

This commit is contained in:
2025-07-16 18:34:00 -04:00
parent 78964a53d3
commit f0025a97b4
5 changed files with 281 additions and 133 deletions

View File

@@ -20,69 +20,136 @@ using MarketData.Numerical;
using MarketData;
using Avalonia.Controls.Platform;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace PortfolioManager.Renderers
{
// ********************************************************************************************************************************
public class TextPlot
// public class TextPlot
// {
// public TextPlot()
// {
// }
// public TextPlot(String markerText,SKRect boundingRect,Pixel screenCoordinates)
// {
// BoundingRect = boundingRect;
// ScreenCoordinates = screenCoordinates;
// MarkerText = markerText;
// }
// public Pixel ScreenCoordinates { get; set; }
// public SKRect BoundingRect { get; set; }
// public String MarkerText { get; set; }
// }
// public class TextPlots : List<TextPlot>
// {
// public TextPlots()
// {
// }
// /// <summary>
// /// The coordinate system is based on (0,0) in the upper left
// /// </summary>
// /// <param name="coordinates"></param>
// /// <returns></returns>
// public bool PointInRects(String markerText,Pixel screenCoordinates,ref Pixel adjustedScreenCoordinates,float factor)
// {
// MDTrace.WriteLine(LogLevel.DEBUG,$"Searching for rectangles in X:{screenCoordinates.X}Y:{screenCoordinates.Y}");
// foreach(TextPlot textPlot in this)
// {
// if(Math.Round(screenCoordinates.X,2) >= Math.Round(textPlot.BoundingRect.Left,2) &&
// Math.Round(screenCoordinates.X,2) <= Math.Round(textPlot.BoundingRect.Right,2) &&
// Math.Round(screenCoordinates.Y,2) >= Math.Round(textPlot.BoundingRect.Top,2) &&
// Math.Round(screenCoordinates.Y,2) <= Math.Round(textPlot.BoundingRect.Bottom,2))
// {
// MDTrace.WriteLine(LogLevel.DEBUG,$"The text {markerText} at Point:X:{screenCoordinates.X}:Y:{screenCoordinates.Y} is within Rect:L({textPlot.BoundingRect.Left}),T({textPlot.BoundingRect.Top}),R({textPlot.BoundingRect.Right}),B({textPlot.BoundingRect.Bottom}) with text {textPlot.MarkerText} which is plotted at Coordinates:X:{textPlot.ScreenCoordinates.X} Y:{textPlot.ScreenCoordinates.Y}");
// SKRect lowestRect = FindLowestAdjacentRect(textPlot.BoundingRect);
// adjustedScreenCoordinates.Y = textPlot.ScreenCoordinates.Y - factor;
// adjustedScreenCoordinates.X = screenCoordinates.X;
// return true;
// }
// }
// return false;
// }
// public void Summary()
// {
// MDTrace.WriteLine(LogLevel.DEBUG,$"TextPlots:{Count}");
// foreach(TextPlot textPlot in this)
// {
// MDTrace.WriteLine(LogLevel.DEBUG,$"Rect:L({textPlot.BoundingRect.Left}),T({textPlot.BoundingRect.Top}),R({textPlot.BoundingRect.Right}),B({textPlot.BoundingRect.Bottom}) with text {textPlot.MarkerText} is plotted at Coordinates:X:{textPlot.ScreenCoordinates.X} Y:{textPlot.ScreenCoordinates.Y}");
// }
// }
// /// <summary>
// /// Find the Rectangle with the highest Bottom that lies within the X-plane
// /// </summary>
// /// <returns></returns>
// private SKRect FindLowestAdjacentRect(SKRect rect)
// {
// List<SKRect> adjacentRects = this.Where(x=> rect.Left >= x.BoundingRect.Left && rect.Right <= x.BoundingRect.Right).Select(x=>x.BoundingRect).ToList();
// if(null == adjacentRects || 0==adjacentRects.Count)return new SKRect(){Left=0,Top=0,Right=0,Bottom=0};
// adjacentRects = adjacentRects.OrderByDescending(x=>x.Bottom).ToList();
// return adjacentRects[0];
// }
// }
public class MarkerItem
{
public TextPlot()
public MarkerItem(double markerDate, double markerPrice)
{
MarkerDate = markerDate;
MarkerPrice = markerPrice;
}
public TextPlot(String markerText,SKRect boundingRect,Pixel screenCoordinates)
{
BoundingRect = boundingRect;
ScreenCoordinates = screenCoordinates;
MarkerText = markerText;
}
public Pixel ScreenCoordinates { get; set; }
public SKRect BoundingRect { get; set; }
public String MarkerText { get; set; }
public double MarkerDate { get; set; }
public double MarkerPrice { get; set; }
}
public class TextPlots : List<TextPlot>
public class TextMarkerManager : List<MarkerItem>
{
public TextPlots()
private DateGenerator dateGenerator = new DateGenerator();
private const double DATE_SPREAD_PCNT = 2.0; // PERCENT
private const double PRICE_SPREAD_PCNT = 2.0; // PERCENT
public Coordinates GetBestMarkerLocation(double markerDate, double markerPrice,OffsetDictionary offsetDictionary,double verticalAdjustmentFactor)
{
}
/// <summary>
/// The coordinate system is based on (0,0) in the upper left
/// </summary>
/// <param name="coordinates"></param>
/// <returns></returns>
public bool PointInRects(String markerText,Pixel screenCoordinates,ref Pixel adjustedScreenCoordinates,float factor)
{
foreach(TextPlot textPlot in this)
if(!IsOverlapped(markerDate,markerPrice,offsetDictionary))
{
if(Math.Round(screenCoordinates.X,2) >= Math.Round(textPlot.BoundingRect.Left,2) &&
Math.Round(screenCoordinates.X,2) <= Math.Round(textPlot.BoundingRect.Right,2) &&
Math.Round(screenCoordinates.Y,2) >= Math.Round(textPlot.BoundingRect.Top,2) &&
Math.Round(screenCoordinates.Y,2) <= Math.Round(textPlot.BoundingRect.Bottom,2))
{
MDTrace.WriteLine(LogLevel.DEBUG,$"The text {markerText} at Point:X:{screenCoordinates.X}:Y:{screenCoordinates.Y} is within Rect:L({textPlot.BoundingRect.Left}),T({textPlot.BoundingRect.Top}),R({textPlot.BoundingRect.Right}),B({textPlot.BoundingRect.Bottom}) with text {textPlot.MarkerText} which is plotted at Coordinates:X:{textPlot.ScreenCoordinates.X} Y:{textPlot.ScreenCoordinates.Y}");
SKRect lowestRect = FindLowestAdjacentRect(textPlot.BoundingRect);
adjustedScreenCoordinates.Y = textPlot.ScreenCoordinates.Y - factor;
adjustedScreenCoordinates.X = screenCoordinates.X;
return true;
}
Add(new MarkerItem(markerDate, markerPrice));
return new Coordinates(){X=markerDate,Y=markerPrice};
}
Add(new MarkerItem(markerDate, markerPrice));
return new Coordinates(){X=markerDate,Y=markerPrice-verticalAdjustmentFactor};
}
private bool IsOverlapped(double markerDate, double markerPrice,OffsetDictionary offsetDictionary)
{
foreach(MarkerItem markerItem in this)
{
double markerItemDate = markerItem.MarkerDate;
double markerItemPrice = markerItem.MarkerPrice;
// double minDate = markerItemDate/(1.00+DATE_SPREAD_PCNT/100.0);
// double maxDate = markerItemDate*(1.00+DATE_SPREAD_PCNT/100.0);
// double minPrice = markerItemPrice/(1.00+PRICE_SPREAD_PCNT/100.0);
// double maxPrice = markerItemPrice*(1.00+PRICE_SPREAD_PCNT/100.0);
double minDate = markerItemDate - offsetDictionary.HorizontalSpread*(DATE_SPREAD_PCNT/100.0);
double maxDate = markerItemDate + offsetDictionary.HorizontalSpread*(DATE_SPREAD_PCNT/100.0);
double minPrice = markerItemPrice - offsetDictionary.VerticalSpread*(PRICE_SPREAD_PCNT/100.0);
double maxPrice = markerItemPrice + offsetDictionary.VerticalSpread*(PRICE_SPREAD_PCNT/100.0);
if(markerDate>=minDate && markerDate<=maxDate && markerPrice >=minPrice && markerPrice<=maxPrice)
{
return true;
}
}
return false;
}
/// <summary>
/// Find the Rectangle with the highest Bottom that lies within the X-plane
/// </summary>
/// <returns></returns>
private SKRect FindLowestAdjacentRect(SKRect rect)
{
List<SKRect> adjacentRects = this.Where(x=> rect.Left >= x.BoundingRect.Left && rect.Right <= x.BoundingRect.Right).Select(x=>x.BoundingRect).ToList();
if(null == adjacentRects || 0==adjacentRects.Count)return new SKRect(){Left=0,Top=0,Right=0,Bottom=0};
adjacentRects = adjacentRects.OrderByDescending(x=>x.Bottom).ToList();
return adjacentRects[0];
}
}
// *********************************************************************************************************************************************
@@ -105,7 +172,8 @@ namespace PortfolioManager.Renderers
private Prices prices = default;
private BollingerBands bollingerBands;
private InsiderTransactionSummaries insiderTransactionSummaries = null;
// private TextPlots textPlots = new TextPlots();
// private TextPlots textPlots = new TextPlots();
private TextMarkerManager textMarkerManager = new TextMarkerManager();
private OffsetDictionary offsets = new OffsetDictionary();
@@ -131,78 +199,87 @@ namespace PortfolioManager.Renderers
public void Render()
{
MDTrace.WriteLine(LogLevel.DEBUG,$"[Render] ENTER");
Plotter.Plot.Axes.Left.TickGenerator = new ScottPlot.TickGenerators.NumericAutomatic()
lock(Plotter.Plot.Sync)
{
LabelFormatter = (double value) => value.ToString("C") // "C" format specifier formats as currency
};
Plotter.Plot.Axes.DateTimeTicksBottom();
Plotter.Plot.Axes.AutoScale();
Plotter.Plot.XLabel("Date");
Plotter.Plot.YLabel("Price");
Plotter.Refresh();
base.OnPropertyChanged("ShowLegend");
MDTrace.WriteLine(LogLevel.DEBUG,$"[Render] LEAVE");
MDTrace.WriteLine(LogLevel.DEBUG,$"[Render] ENTER");
Plotter.Plot.Axes.Left.TickGenerator = new ScottPlot.TickGenerators.NumericAutomatic()
{
LabelFormatter = (double value) => value.ToString("C") // "C" format specifier formats as currency
};
Plotter.Plot.Axes.DateTimeTicksBottom();
Plotter.Plot.Axes.AutoScale();
Plotter.Plot.XLabel("Date");
Plotter.Plot.YLabel("Price");
if (!ShowLegend) Plotter.Plot.HideLegend();
else Plotter.Plot.ShowLegend();
Plotter.Refresh();
MDTrace.WriteLine(LogLevel.DEBUG,$"[Render] LEAVE");
}
}
public void SetData(String selectedSymbol, int selectedDayCount)
{
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] ENTER");
this.selectedSymbol = selectedSymbol;
this.selectedDayCount = selectedDayCount;
stopLimit = PortfolioDA.GetStopLimit(selectedSymbol);
portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol);
portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades);
Plotter.Plot.Clear();
if (null != portfolioTrades && 0 != portfolioTrades.Count)
lock(Plotter.Plot.Sync)
{
DateGenerator dateGenerator = new DateGenerator();
DateTime earliestTrade = portfolioTrades[0].TradeDate;
earliestTrade = earliestTrade.AddDays(-30);
int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now);
if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
else prices = PricingDA.GetPrices(selectedSymbol, earliestTrade);
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] ENTER");
this.selectedSymbol = selectedSymbol;
this.selectedDayCount = selectedDayCount;
stopLimit = PortfolioDA.GetStopLimit(selectedSymbol);
portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol);
portfolioTradesLots = LotAggregator.CombineLots(portfolioTrades);
DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30);
insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate);
// calculate the break even price on the open trades for this symbol
PortfolioTrades openTrades = portfolioTrades.GetOpenTrades();
DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol);
latestPrice = PricingDA.GetPrice(selectedSymbol, latestPricingDate);
zeroPrice = ParityGenerator.GenerateGainLossValue(openTrades, latestPrice);
if (!syncTradeToBand)
{
DateTime earliestPricingDate = prices[prices.Count - 1].Date;
earliestPricingDate = earliestPricingDate.AddDays(30);
IEnumerable<PortfolioTrade> tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade);
portfolioTrades = new PortfolioTrades();
foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade);
portfolioTradesLots = portfolioTrades;
}
}
else
{
prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
if (null != prices && 0 != prices.Count)
Plotter.Plot.Clear();
if (null != portfolioTrades && 0 != portfolioTrades.Count)
{
DateGenerator dateGenerator = new DateGenerator();
DateTime earliestTrade = portfolioTrades[0].TradeDate;
earliestTrade = earliestTrade.AddDays(-30);
int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now);
if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
else prices = PricingDA.GetPrices(selectedSymbol, earliestTrade);
DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30);
insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate);
// calculate the break even price on the open trades for this symbol
PortfolioTrades openTrades = portfolioTrades.GetOpenTrades();
DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol);
latestPrice = PricingDA.GetPrice(selectedSymbol, latestPricingDate);
zeroPrice = ParityGenerator.GenerateGainLossValue(openTrades, latestPrice);
if (!syncTradeToBand)
{
DateTime earliestPricingDate = prices[prices.Count - 1].Date;
earliestPricingDate = earliestPricingDate.AddDays(30);
IEnumerable<PortfolioTrade> tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade);
portfolioTrades = new PortfolioTrades();
foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade);
portfolioTradesLots = portfolioTrades;
}
}
else
{
prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
if (null != prices && 0 != prices.Count)
{
DateGenerator dateGenerator = new DateGenerator();
DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30);
insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate);
}
}
bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
// textPlots.Clear();
textMarkerManager.Clear();
CalculateOffsets();
GenerateBollingerBands();
GenerateLeastSquares();
GenerateInsiderTransactions();
GenerateStopLimits();
GenerateTradePoints();
GenerateZeroPoint(zeroPrice);
// textPlots.Summary();
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] LEAVE");
}
bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
// textPlots.Clear();
CalculateOffsets();
GenerateBollingerBands();
GenerateLeastSquares();
GenerateInsiderTransactions();
GenerateStopLimits();
GenerateTradePoints();
GenerateZeroPoint(zeroPrice);
MDTrace.WriteLine(LogLevel.DEBUG,$"[SetData] LEAVE");
}
/// <summary>
@@ -210,29 +287,29 @@ namespace PortfolioManager.Renderers
/// </summary>
private void CalculateOffsets()
{
double maxBollingerDate = bollingerBands.Max(x => x.Date).ToOADate();
double minBollingerDate = bollingerBands.Min(x => x.Date).ToOADate();
double maxBollingerValue = bollingerBands.Max(x => x.K);
double minBollingerValue = bollingerBands.Min(x => x.L);
offsets.MaxBollingerDate = bollingerBands.Max(x => x.Date).ToOADate();
offsets.MinBollingerDate = bollingerBands.Min(x => x.Date).ToOADate();
offsets.MaxBollingerValue = bollingerBands.Max(x => x.K);
offsets.MinBollingerValue = bollingerBands.Min(x => x.L);
offsets.Add(OffsetDictionary.OffsetType.MaxBollingerDate,maxBollingerDate);
offsets.Add(OffsetDictionary.OffsetType.MinBollingerDate,minBollingerDate);
offsets.Add(OffsetDictionary.OffsetType.MaxBollingerValue,maxBollingerValue);
offsets.Add(OffsetDictionary.OffsetType.MinBollingerValue,minBollingerValue);
offsets.Add(OffsetDictionary.OffsetType.MaxBollingerDate,offsets.MaxBollingerDate);
offsets.Add(OffsetDictionary.OffsetType.MinBollingerDate,offsets.MinBollingerDate);
offsets.Add(OffsetDictionary.OffsetType.MaxBollingerValue,offsets.MaxBollingerValue);
offsets.Add(OffsetDictionary.OffsetType.MinBollingerValue,offsets.MinBollingerValue);
double spreadHorz = (maxBollingerDate - minBollingerDate);
double spreadVert = (maxBollingerValue - minBollingerValue);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset1PC,spreadHorz * .01);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset3PC,spreadHorz * .03);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset5PC,spreadHorz * .05);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset1PC,spreadVert * .01);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset3PC,spreadVert *.03);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset5PC,spreadVert * .05);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset6PC,spreadVert * .06);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset6P5PC,spreadVert * .065);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset7PC,spreadVert * .07);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset10PC,spreadVert * .10);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset15PC,spreadVert * .15);
offsets.HorizontalSpread = (offsets.MaxBollingerDate - offsets.MinBollingerDate);
offsets.VerticalSpread = (offsets.MaxBollingerValue - offsets.MinBollingerValue);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset1PC,offsets.HorizontalSpread * .01);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset3PC,offsets.HorizontalSpread * .03);
offsets.Add(OffsetDictionary.OffsetType.HorizontalOffset5PC,offsets.HorizontalSpread * .05);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset1PC,offsets.VerticalSpread * .01);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset3PC,offsets.VerticalSpread *.03);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset5PC,offsets.VerticalSpread * .05);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset6PC,offsets.VerticalSpread * .06);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset6P5PC,offsets.VerticalSpread * .065);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset7PC,offsets.VerticalSpread * .07);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset10PC,offsets.VerticalSpread * .10);
offsets.Add(OffsetDictionary.OffsetType.VerticalOffset15PC,offsets.VerticalSpread * .15);
}
/// <summary>
@@ -280,6 +357,9 @@ namespace PortfolioManager.Renderers
image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize);
coordinates = new Coordinates(dates[0].ToOADate() - offsets.Offset(OffsetDictionary.OffsetType.HorizontalOffset3PC),
values[0] - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
coordinates = textMarkerManager.GetBestMarkerLocation(coordinates.X, coordinates.Y, offsets, offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
// Pixel screenCoordinates = Plotter.Plot.GetPixel(coordinates);
// Pixel adjScreenCoordinates = Plotter.Plot.GetPixel(coordinates);
@@ -342,6 +422,7 @@ namespace PortfolioManager.Renderers
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));
// Pixel screenCoordinates = Plotter.Plot.GetPixel(coordinates);
// Pixel adjScreenCoordinates = Plotter.Plot.GetPixel(coordinates);
// if(textPlots.PointInRects(sb.ToString(),screenCoordinates,ref adjScreenCoordinates,(float)offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC)))
@@ -370,7 +451,7 @@ namespace PortfolioManager.Renderers
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));
// Pixel screenCoordinates = Plotter.Plot.GetPixel(coordinates);
// Pixel adjScreenCoordinates = Plotter.Plot.GetPixel(coordinates);
// if(textPlots.PointInRects(sb.ToString(),screenCoordinates,ref adjScreenCoordinates,(float)offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC)))
@@ -416,6 +497,7 @@ namespace PortfolioManager.Renderers
Coordinates coordinates = new Coordinates(portfolioTrade.TradeDate.ToOADate(),
portfolioTrade.Price - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
coordinates = textMarkerManager.GetBestMarkerLocation(coordinates.X, coordinates.Y,offsets, offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
// Pixel screenCoordinates = Plotter.Plot.GetPixel(coordinates);
// Pixel adjScreenCoordinates = Plotter.Plot.GetPixel(coordinates);
// if(textPlots.PointInRects(sb.ToString(),screenCoordinates,ref adjScreenCoordinates,(float)offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC)))

View File

@@ -12,6 +12,42 @@ namespace PortfolioManager.Renderers
private Dictionary<OffsetType, double> offsetDictionary = new Dictionary<OffsetType, double>();
/// <summary>
/// Gets/Sets the Maximum bollinger date in AODate form
/// </summary>
public double MaxBollingerDate { get; set; }
/// <summary>
/// Gets/Sets the Minumum bollinger date in AODate form
/// </summary>
public double MinBollingerDate { get; set; }
/// <summary>
/// Gets/Sets the Maximum bollinger value
/// </summary>
public double MaxBollingerValue { get; set; }
/// <summary>
/// Gets/Sets the Minimum bollinger value
/// </summary>
public double MinBollingerValue { get; set; }
/// <summary>
/// Gets/Sets the Horizontal Spread (max-min)
/// </summary>
public double HorizontalSpread { get; set; }
/// <summary>
/// Gets/Sets the Vertical Spread (max-min)
/// </summary>
public double VerticalSpread { get; set; }
/// <summary>
/// Add an offset and it's offset type
/// </summary>
/// <param name="offsetType"></param>
/// <param name="value"></param>
public void Add(OffsetType offsetType, double value)
{
if (offsetDictionary.ContainsKey(offsetType))
@@ -24,6 +60,11 @@ namespace PortfolioManager.Renderers
}
}
/// <summary>
/// Get the offset specified by offsetType
/// </summary>
/// <param name="offsetType"></param>
/// <returns></returns>
public double Offset(OffsetType offsetType)
{
return offsetDictionary[offsetType];

View File

@@ -104,8 +104,29 @@ namespace PortfolioManager.ViewModels
private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
if ((eventArgs.PropertyName.Equals("SyncTradeToBand") ||
if(eventArgs.PropertyName.Equals("SelectedWatchList"))
{
IsBusy=true;
Task workerTask = Task.Factory.StartNew(()=>
{
symbols.Clear();
if(UIConstants.CONST_ALL.Equals(selectedWatchList))
{
symbols.AddRange(PricingDA.GetSymbols());
}
else
{
symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList));
}
});
workerTask.ContinueWith((continuation)=>
{
IsBusy=false;
base.OnPropertyChanged("Symbols");
});
}
else if ((eventArgs.PropertyName.Equals("SyncTradeToBand") ||
eventArgs.PropertyName.Equals("ShowTradeLabels") ||
eventArgs.PropertyName.Equals("SelectedSymbol") ||
eventArgs.PropertyName.Equals("ShowRiskFree") ||
@@ -127,6 +148,8 @@ namespace PortfolioManager.ViewModels
bollingerBandRenderer.ExternalStopLimits = stopLimits;
bollingerBandRenderer.SetData(selectedSymbol, selectedDayCount);
bollingerBandRenderer.Render();
// bollingerBandRenderer.SetData(selectedSymbol, selectedDayCount); // do it twice. The second render will figure out the text image overlaps
// bollingerBandRenderer.Render();
});
workerTask.ContinueWith((continuation) =>
{

View File

@@ -7,11 +7,11 @@ namespace PortfolioManager.ViewModels
{
public AvaPlot AvaPlot { get; set; } = default;
}
public abstract class PlotterWorkspaceViewModel : WorkspaceViewModel
{
public AvaPlot Plotter { get; set; }
public EventHandler<PlotterLoadedEventArgs> OnPlotterLoadedEventHandler;
public void OnPlotterLoaded(AvaPlot avaPlot)

View File

@@ -5,6 +5,7 @@ using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Eremex.AvaloniaUI.Controls.Utils;
using MarketData;
using PortfolioManager.ViewModels;
using ScottPlot;
using ScottPlot.Avalonia;
@@ -29,6 +30,7 @@ public partial class BollingerBandView : UserControl
PlotterWorkspaceViewModel viewModel = (DataContext as PlotterWorkspaceViewModel);
if (null!=viewModel && default == viewModel.Plotter)
{
MDTrace.WriteLine(LogLevel.DEBUG,$"Create new plot.");
viewModel.Plotter = new AvaPlot();
viewModel.OnPlotterLoaded(viewModel.Plotter);
}