Files
Avalonia/PortfolioManager/Models/GainLossModel.cs
2026-02-18 22:18:36 -05:00

165 lines
7.5 KiB
C#

using System;
using System.Linq;
using Eremex.AvaloniaUI.Charts;
using MarketData.MarketDataModel;
using MarketData.MarketDataModel.GainLoss;
using MarketData.Numerical;
using MarketData.Utils;
using PortfolioManager.DataSeriesViewModels;
namespace PortfolioManager.Models
{
public class GainLossModel
{
private GainLossModel()
{
}
public static CompositeDataSource Empty()
{
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = new SortedDateTimeDataAdapter()
};
return compositeDataSource;
}
public static CompositeDataSource Price(Price price)
{
if (null == price) return Empty();
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
sortedDateTimeDataAdapter.Add(price.Date, price.Close);
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)
{
if (null == gainLossList) return Empty();
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
foreach (ModelPerformanceItem modelPerformanceItem in gainLossList)
{
sortedDateTimeDataAdapter.Add(modelPerformanceItem.Date, useGainLoss ? modelPerformanceItem.CumulativeGainLoss : modelPerformanceItem.CumProdMinusOne * 100.00);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
// This is the active gain/loss as number or percent.
public static CompositeDataSource GainLoss(GainLossCompoundModelCollection gainLossList, bool useGainLoss)
{
if (null == gainLossList) return Empty();
GainLossCompoundModelCollection sortedCollection = new GainLossCompoundModelCollection(gainLossList.OrderBy(x => x.Date).ToList());
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
foreach (GainLossCompoundModel gainLossCompoundModel in sortedCollection)
{
sortedDateTimeDataAdapter.Add(gainLossCompoundModel.Date, useGainLoss ? gainLossCompoundModel.ActiveGainLoss : gainLossCompoundModel.ActiveGainLossPercent);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
// This is the total gain loss as number or percent
public static CompositeDataSource TotalGainLoss(GainLossCompoundModelCollection gainLossList, bool useGainLoss)
{
if (null == gainLossList) return Empty();
GainLossCompoundModelCollection sortedCollection = new GainLossCompoundModelCollection(gainLossList.OrderBy(x => x.Date).ToList());
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
foreach (GainLossCompoundModel gainLossCompoundModel in sortedCollection)
{
sortedDateTimeDataAdapter.Add(gainLossCompoundModel.Date, useGainLoss ? gainLossCompoundModel.TotalGainLoss : gainLossCompoundModel.TotalGainLossPercent);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
// This is the least squares composite data source based on the active gain/loss
public static CompositeDataSource LeastSquares(GainLossCompoundModelCollection gainLossList, bool useGainLoss)
{
if (null == gainLossList) return Empty();
LeastSquaresResult leastSquaresResult = LeastSquaresFit(gainLossList, useGainLoss);
GainLossCompoundModelCollection sortedCollection = new GainLossCompoundModelCollection(gainLossList.OrderBy(x => x.Date).ToList());
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
for (int index = 0; index < sortedCollection.Count; index++)
{
GainLossCompoundModel gainLossCompoundModel = sortedCollection[index];
int leastSquaresIndex = (leastSquaresResult.LeastSquares.Length - 1) - index;
sortedDateTimeDataAdapter.Add(gainLossCompoundModel.Date, leastSquaresResult.LeastSquares[leastSquaresIndex]);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
// This is the least squares composite data source based on the active gain/loss
public static CompositeDataSource TotalLeastSquares(GainLossCompoundModelCollection gainLossList, bool useGainLoss)
{
if (null == gainLossList) return Empty();
LeastSquaresResult leastSquaresResult = TotalLeastSquaresFit(gainLossList, useGainLoss);
GainLossCompoundModelCollection sortedCollection = new GainLossCompoundModelCollection(gainLossList.OrderBy(x => x.Date).ToList());
SortedDateTimeDataAdapter sortedDateTimeDataAdapter = new SortedDateTimeDataAdapter();
for (int index = 0; index < sortedCollection.Count; index++)
{
GainLossCompoundModel gainLossCompoundModel = sortedCollection[index];
int leastSquaresIndex = (leastSquaresResult.LeastSquares.Length - 1) - index;
sortedDateTimeDataAdapter.Add(gainLossCompoundModel.Date, leastSquaresResult.LeastSquares[leastSquaresIndex]);
}
CompositeDataSource compositeDataSource = new CompositeDataSource()
{
DataAdapter = sortedDateTimeDataAdapter
};
return compositeDataSource;
}
// ***************************************** C A L C U L A T O R S **********************************
// This is the LeastSquares fit based on the active gain/loss
public static LeastSquaresResult LeastSquaresFit(GainLossCompoundModelCollection gainLossList, bool useGainLoss)
{
double[] values = null;
if (useGainLoss) values = (from GainLossCompoundModel gainLoss in gainLossList select gainLoss.ActiveGainLoss).ToList().ToArray();
else values = (from GainLossCompoundModel gainLoss in gainLossList select gainLoss.ActiveGainLossPercent).ToList().ToArray();
LeastSquaresResult leastSquaresResult = Numerics.LeastSquares(values);
return leastSquaresResult;
}
// This is the LeastSquares fit based on the total gain/loss
public static LeastSquaresResult TotalLeastSquaresFit(GainLossCompoundModelCollection gainLossList,bool useGainLoss)
{
double[] values=null;
if(useGainLoss)values=(from GainLossCompoundModel gainLoss in gainLossList select gainLoss.TotalGainLoss).ToList().ToArray();
else values=(from GainLossCompoundModel gainLoss in gainLossList select gainLoss.TotalGainLossPercent).ToList().ToArray();
LeastSquaresResult leastSquaresResult=Numerics.LeastSquares(values);
return leastSquaresResult;
}
}
}