Code cleanup

This commit is contained in:
2026-01-25 11:50:38 -05:00
parent c4d2da2522
commit c5008e33d2
5 changed files with 95 additions and 69 deletions

View File

@@ -3,7 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="using:PortfolioManager.Dialogs" xmlns:vm="using:PortfolioManager.Dialogs"
x:Class="PortfolioManager.Dialogs.EditPositionDialog" x:Class="PortfolioManager.Dialogs.EditPositionDialog"
x:DataType="vm:EditPositionDialogViewModel" x:DataType="vm:EditPositionDialogViewModel"
Title="Edit Position Dialog" Title="Edit Position Dialog"
@@ -42,13 +42,15 @@
<TextBox Margin="0,4,0,4" Grid.Row="2" Grid.Column="2" IsReadOnly="true" MinWidth="35" Text="{Binding Path=Symbol, Mode=OneWay}"/> <TextBox Margin="0,4,0,4" Grid.Row="2" Grid.Column="2" IsReadOnly="true" MinWidth="35" Text="{Binding Path=Symbol, Mode=OneWay}"/>
<Label Grid.Row="3" Grid.Column="0" MinWidth="35">Purchase Date</Label> <Label Grid.Row="3" Grid.Column="0" MinWidth="35">Purchase Date</Label>
<TextBox Margin="0,4,0,4" IsReadOnly="true" Grid.Row="3" Grid.Column="2" Text="{Binding Path=PurchaseDate, Mode=OneWay}"/> <TextBox Margin="0,4,0,4" IsReadOnly="true" Grid.Row="3" Grid.Column="2" Text="{Binding Path=PurchaseDate, Mode=OneWay}"/>
<Label Grid.Row="4" Grid.Column="0" MinWidth="75">Purchase Price</Label> <Label Grid.Row="4" Grid.Column="0" MinWidth="75">Purchase Price</Label>
<TextBox Margin="0,4,0,4" Grid.Row="4" Grid.Column="2" IsReadOnly="false" Text="{Binding Path=PurchasePrice, UpdateSourceTrigger=LostFocus, Mode=TwoWay}" /> <TextBox Margin="0,4,0,4" Grid.Row="4" Grid.Column="2" IsReadOnly="false" Text="{Binding Path=PurchasePrice, UpdateSourceTrigger=LostFocus, Mode=TwoWay}" />
<Label Grid.Row="5" Grid.Column="0">Initial Stop Limit</Label> <Label Grid.Row="5" Grid.Column="0">Initial Stop Limit</Label>
<TextBox Margin="0,4,0,4" Grid.Row="5" Grid.Column="2" MinWidth="35" Text="{Binding Path=InitialStopLimit, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/> <TextBox Margin="0,4,0,4" Grid.Row="5" Grid.Column="2" MinWidth="35"
Text="{Binding Path=InitialStopLimit, UpdateSourceTrigger=LostFocus, Mode=TwoWay}">
</TextBox>
<CheckBox Grid.Row="6" Grid.Column="0" IsChecked="{Binding Path=SyncTrailingStop, UpdateSourceTrigger=LostFocus, Mode=TwoWay}">Sync Trailing Stop</CheckBox> <CheckBox Grid.Row="6" Grid.Column="0" IsChecked="{Binding Path=SyncTrailingStop, UpdateSourceTrigger=LostFocus, Mode=TwoWay}">Sync Trailing Stop</CheckBox>
<Label Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="3" FontWeight="Bold" Content="{Binding Path=InitialStopRecommendation, Mode=OneWay}" /> <Label Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="3" FontWeight="Bold" Content="{Binding Path=InitialStopRecommendation, Mode=OneWay}" />
@@ -56,7 +58,7 @@
<Label Grid.Row="8" Grid.Column="0">Trailing Stop</Label> <Label Grid.Row="8" Grid.Column="0">Trailing Stop</Label>
<TextBox Grid.Row="8" Grid.Column="2" MinWidth="35" Text="{Binding Path=TrailingStopLimit, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/> <TextBox Grid.Row="8" Grid.Column="2" MinWidth="35" Text="{Binding Path=TrailingStopLimit, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
<Button Command="{Binding Path=OkButtonClickCommand}" Content="_Ok" MinWidth="70" IsDefault="False" Margin="2" Grid.Row="9" Grid.RowSpan="2" Grid.Column="0"/> <Button Command="{Binding Path=OkButtonClickCommand}" Content="_Ok" MinWidth="70" IsDefault="False" Margin="2" Grid.Row="9" Grid.RowSpan="2" Grid.Column="0"/>
<Button Command="{Binding Path=CancelButtonClick}" Content="_Cancel" MinWidth="70" IsCancel="True" Margin="2" Grid.Row="11" Grid.RowSpan="2" Grid.Column="0"/> <Button Command="{Binding Path=CancelButtonClick}" Content="_Cancel" MinWidth="70" IsCancel="True" Margin="2" Grid.Row="11" Grid.RowSpan="2" Grid.Column="0"/>
</Grid> </Grid>

View File

@@ -1,10 +1,12 @@
using System; using System;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using MarketData.DataAccess; using MarketData.DataAccess;
using MarketData.Generator.Interface; using MarketData.Generator.Interface;
using MarketData.MarketDataModel; using MarketData.MarketDataModel;
using MarketData.Numerical;
using MarketData.Utils; using MarketData.Utils;
using PortfolioManager.ViewModels; using PortfolioManager.ViewModels;
@@ -92,9 +94,21 @@ namespace PortfolioManager.Dialogs
{ {
get get
{ {
return "Recommended Initial Stop: " + Utility.FormatCurrency(sourcePosition.PurchasePrice * (1.00 - sourcePosition.PositionRiskPercentDecimal), 2); StringBuilder sb = new StringBuilder();
sb.Append("Recommended Initial Stop: ").Append(Utility.FormatCurrency(Numerics.Discount(sourcePosition.PurchasePrice,sourcePosition.PositionRiskPercentDecimal), 2));
sb.Append(" = Discount(").Append(Utility.FormatCurrency(sourcePosition.PurchasePrice,2)).Append(",").Append(Utility.FormatPercent(sourcePosition.PositionRiskPercentDecimal,2)).Append(")");
return sb.ToString();
} }
} }
public String InitialStopRecommendationDescription
{
get
{
return "InitialStopRecommendationDescription";
}
}
public String TrailingStopLimit public String TrailingStopLimit
{ {

View File

@@ -24,59 +24,10 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace PortfolioManager.Renderers namespace PortfolioManager.Renderers
{ {
public class MarkerItem /// <summary>
{ /// BollingerBandRenderer - Renders the ScottPlot for the Bollinger Bands
public MarkerItem(double markerDate, double markerPrice) /// If external stop limits are provided then the renderer will use those otherwise the renderer will look up using StopLimitDA
{ /// </summary>
MarkerDate = markerDate;
MarkerPrice = markerPrice;
}
public double MarkerDate { get; set; }
public double MarkerPrice { get; set; }
}
public class TextMarkerManager : List<MarkerItem>
{
private DateGenerator dateGenerator = new DateGenerator();
private const double DATE_SPREAD_PCNT = 10.0; // PERCENT
private const double PRICE_SPREAD_PCNT = 10.0; // PERCENT
public Coordinates GetBestMarkerLocation(double markerDate, double markerPrice,OffsetDictionary offsetDictionary,double verticalAdjustmentFactor)
{
if(!IsOverlapped(markerDate,markerPrice,offsetDictionary))
{
Add(new MarkerItem(markerDate, markerPrice));
return new Coordinates(){X=markerDate,Y=markerPrice};
}
Add(new MarkerItem(markerDate, markerPrice-verticalAdjustmentFactor));
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 - 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;
}
}
// *********************************************************************************************************************************************
public class BollingerBandRenderer : ModelBase public class BollingerBandRenderer : ModelBase
{ {
private String selectedSymbol = default; private String selectedSymbol = default;
@@ -89,8 +40,8 @@ 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; private StopLimit stopLimit = default; // StopLimits that the renderer has located using StopLimitDA
private StopLimits stopLimits = default; 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;
private Prices prices = default; private Prices prices = default;
@@ -289,10 +240,10 @@ namespace PortfolioManager.Renderers
/// </summary> /// </summary>
private void GenerateStopLimits() private void GenerateStopLimits()
{ {
if (null == stopLimits && null == zeroPrice) return; if (null == externalStopLimits && null == zeroPrice) return;
if (null != stopLimits) if (null != externalStopLimits)
{ {
StopLimits = StopLimitCompositeModel.CreateCompositeDataSource(stopLimits); StopLimits = StopLimitCompositeModel.CreateCompositeDataSource(externalStopLimits);
} }
else if (null != stopLimit && null != zeroPrice) else if (null != stopLimit && null != zeroPrice)
{ {
@@ -313,16 +264,16 @@ namespace PortfolioManager.Renderers
if(!showTradeLabels)return; if(!showTradeLabels)return;
// Add the text marker // Add the text marker
if (null != stopLimits) if (null != externalStopLimits)
{ {
for (int index = 0; index < stopLimits.Count; index++) for (int index = 0; index < externalStopLimits.Count; index++)
{ {
StopLimit limit = stopLimits[index]; StopLimit limit = externalStopLimits[index];
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append(limit.StopType).Append(" "); sb.Append(limit.StopType).Append(" ");
sb.Append(Utility.FormatCurrency(limit.StopPrice)); sb.Append(Utility.FormatCurrency(limit.StopPrice));
if (index == stopLimits.Count - 1) if (index == externalStopLimits.Count - 1)
{ {
Price latestPrice = prices[0]; Price latestPrice = prices[0];
double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice); double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice);
@@ -573,11 +524,11 @@ namespace PortfolioManager.Renderers
{ {
get get
{ {
return stopLimits; return externalStopLimits;
} }
set set
{ {
stopLimits = value; externalStopLimits = value;
base.OnPropertyChanged("ExternalStopLimits"); base.OnPropertyChanged("ExternalStopLimits");
} }
} }

View File

@@ -0,0 +1,16 @@
namespace PortfolioManager.Renderers
{
public class MarkerItem
{
public MarkerItem(double markerDate, double markerPrice)
{
MarkerDate = markerDate;
MarkerPrice = markerPrice;
}
public double MarkerDate { get; set; }
public double MarkerPrice { get; set; }
}
}

View File

@@ -0,0 +1,43 @@
using System.Collections.Generic;
using MarketData.Utils;
using ScottPlot;
namespace PortfolioManager.Renderers
{
public class TextMarkerManager : List<MarkerItem>
{
private DateGenerator dateGenerator = new DateGenerator();
private const double DATE_SPREAD_PCNT = 10.0; // PERCENT
private const double PRICE_SPREAD_PCNT = 10.0; // PERCENT
public Coordinates GetBestMarkerLocation(double markerDate, double markerPrice,OffsetDictionary offsetDictionary,double verticalAdjustmentFactor)
{
if(!IsOverlapped(markerDate,markerPrice,offsetDictionary))
{
Add(new MarkerItem(markerDate, markerPrice));
return new Coordinates(){X=markerDate,Y=markerPrice};
}
Add(new MarkerItem(markerDate, markerPrice-verticalAdjustmentFactor));
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 - 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;
}
}
}