Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e0c5f22b6 | |||
| c5008e33d2 |
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 StopLimits internalStopLimits = 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;
|
||||||
@@ -146,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);
|
||||||
|
|
||||||
@@ -289,14 +241,14 @@ 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 != 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();
|
||||||
|
|
||||||
@@ -311,20 +263,20 @@ namespace PortfolioManager.Renderers
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!showTradeLabels)return;
|
if(!showTradeLabels)return;
|
||||||
|
Price latestPrice = prices[0];
|
||||||
|
|
||||||
// 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];
|
|
||||||
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(")");
|
||||||
}
|
}
|
||||||
@@ -340,21 +292,41 @@ 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));
|
||||||
sb.Append(" (").Append(percentOffsetFromLow > 0 ? "+" : "").Append(Utility.FormatPercent(percentOffsetFromLow)).Append(")");
|
if (index == internalStopLimits.Count - 1)
|
||||||
Image image = TextMarkerImageGenerator.GenerateImage(sb.ToString(), FontFactor.FontSize);
|
{
|
||||||
Coordinates coordinates = new Coordinates(latestPrice.Date.ToOADate() - offsets.Offset(OffsetDictionary.OffsetType.HorizontalOffset3PC),
|
double percentOffsetFromLow = ((latestPrice.Low - limit.StopPrice) / limit.StopPrice);
|
||||||
stopLimit.StopPrice - offsets.Offset(OffsetDictionary.OffsetType.VerticalOffset6P5PC));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,11 +545,11 @@ namespace PortfolioManager.Renderers
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return stopLimits;
|
return externalStopLimits;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
stopLimits = value;
|
externalStopLimits = value;
|
||||||
base.OnPropertyChanged("ExternalStopLimits");
|
base.OnPropertyChanged("ExternalStopLimits");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
PortfolioManager/Renderers/MarkerItem.cs
Normal file
16
PortfolioManager/Renderers/MarkerItem.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
43
PortfolioManager/Renderers/TextMarkerManager.cs
Normal file
43
PortfolioManager/Renderers/TextMarkerManager.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user