I have implemented mathematical functions using a C# library. I basically need to output data by the RiskMatrixByFunds
in the following format.
Key will contain Id and value will contain collection of string, double, double
For example:
Id 1
value
{'ArithmeticMean', 12.34, 3.44},
{'AverageGain', 12.35, 3.45},
{'AverageLoss', 12.36, 3.46},
I have used a Dictionary structure that will contain the int and list of tuple collection.
Let me know if it can be enhanced, any ideas on magic strings used, a better way to implement it.
public class RiskMatrix : IRiskMatrix
{
public (double Monthly, double Annual) ArithmeticMean(IEnumerable<double> ReturnsList)
{
double returnList = ReturnsList.Mean();
return (Monthly: returnList, Annual: returnList * Math.Pow(12, 0.5));
}
public (double Monthly, double Annual) AverageGain(IEnumerable<double> ReturnsList)
{
double returnList = ReturnsList.GainMean();
return (Monthly: returnList, Annual: returnList * Math.Pow(12, 0.5));
}
public (double Monthly, double Annual) AverageLoss(IEnumerable<double> ReturnsList)
{
double returnList = ReturnsList.LossMean();
return (Monthly: returnList, Annual: returnList * Math.Pow(12, 0.5));
}
public Dictionary<int, List<Tuple<string,double, double>>> RiskMatrixByFunds(Dictionary<int, IEnumerable<double>> ReturnsList)
{
Dictionary<int, List<Tuple<string ,double, double>>> returnsList = new Dictionary<int, List<Tuple<string,double, double>>>();
List <Tuple<string, double, double>> list = null;
foreach (KeyValuePair<int, IEnumerable<double>> entry in ReturnsList)
{
list = new List<Tuple<string, double, double>>();
(double Monthly, double Annual) arithmeticMeanResult = ArithmeticMean(entry.Value);
list.Add(new Tuple<string, double, double>("ArithmeticMean", arithmeticMeanResult.Monthly, arithmeticMeanResult.Annual));
(double Monthly, double Annual) averageGainResult = AverageGain(entry.Value);
list.Add(new Tuple<string, double, double>("AverageGain", averageGainResult.Monthly, averageGainResult.Annual));
(double Monthly, double Annual) averageLossResult = AverageLoss(entry.Value);
list.Add(new Tuple<string, double, double>("AverageLoss", averageLossResult.Monthly, averageLossResult.Annual));
(double Monthly, double Annual) betaCorrelationresult = BetaCorrelation(entry.Value);
returnsList.Add(entry.Key, list);
}
return returnsList;
}
}
1 Answer 1
There might be a reason why you used a List<Tuple<string ,double, double>>
. E.g. if you need to pass the data to an existing library or your UI needs to bind to a list. Otherwise I would recommend to create a dedicated class
public class RiskStatistics
{
public double ArithmeticMeanMonthly { get; set; }
public double ArithmeticMeanAnnual { get; set; }
public double AverageGainMonthly { get; set; }
public double AverageGainAnnual { get; set; }
public double AverageLossMonthly { get; set; }
public double AverageLossAnnual { get; set; }
}
Since the properties are named, there's no need for magic strings. This makes the creation and usage of the risk matrix less convoluted:
public Dictionary<int, RiskStatistics> RiskMatrixByFunds(
Dictionary<int, IEnumerable<double>> returnsLists)
{
var riskMatrixDict = new Dictionary<int, RiskStatistics>();
foreach (KeyValuePair<int, IEnumerable<double>> entry in returnsLists) {
var risk = new RiskStatistics();
(risk.ArithmeticMeanMonthly, risk.ArithmeticMeanAnnual) = ArithmeticMean(entry.Value);
(risk.AverageGainMonthly, risk.AverageGainAnnual) = AverageGain(entry.Value);
(risk.AverageLossMonthly, risk.AverageLossAnnual) = AverageLoss(entry.Value);
riskMatrixDict.Add(entry.Key, risk);
}
return riskMatrixDict;
}
You could also calculate the annual values on the fly. This would make the creation even easier. Here the adapted average gain properties as an example:
private static readonly double Sqrt12 = Math.Pow(12, 0.5);
public double ArithmeticMeanMonthly { get; set; }
public double ArithmeticMeanAnnual => ArithmeticMeanMonthly * Sqrt12;
With this adapted RiskStatistics
class, you could directly assign from the extension methods and skip the methods returning tuples.
var risk = new RiskStatistics {
ArithmeticMeanMonthly = entry.Value.Mean(),
AverageGainMonthly = entry.Value.GainMean(),
AverageLossMonthly = entry.Value.LossMean()
};
riskMatrixDict.Add(entry.Key, risk);
The annual values are read-only and need not to be assigned.
-
\$\begingroup\$ Good idea. Integrated it in my answer. Multiplication is fast and should have no noticeable impact on speed. \$\endgroup\$Olivier Jacot-Descombes– Olivier Jacot-Descombes2019年04月08日 12:04:44 +00:00Commented Apr 8, 2019 at 12:04