Browse Source

Updated financial calcs and unit tests to deal with NaN return

pull/108/head
Phil 13 years ago
parent
commit
b8f4e66770
  1. 103
      src/Numerics/Financial/AbsoluteReturnMeasures.cs
  2. 46
      src/Numerics/Financial/AbsoluteRiskStatistics.cs
  3. 1
      src/Numerics/Numerics.csproj
  4. 75
      src/UnitTests/FinancialTests/CompoundMonthlyReturnTests.cs
  5. 1
      src/UnitTests/FinancialTests/DownsideDeviationTests.cs
  6. 23
      src/UnitTests/FinancialTests/GainLossRatioTests.cs
  7. 9
      src/UnitTests/FinancialTests/GainMeanTests.cs
  8. 1
      src/UnitTests/FinancialTests/GainStandardDeviationTests.cs
  9. 15
      src/UnitTests/FinancialTests/LossMeanTests.cs
  10. 1
      src/UnitTests/FinancialTests/LossStandardDeviationTests.cs
  11. 1
      src/UnitTests/FinancialTests/SemiDeviationTests.cs
  12. 1
      src/UnitTests/UnitTests.csproj

103
src/Numerics/Financial/AbsoluteReturnMeasures.cs

@ -0,0 +1,103 @@
// <copyright file="AbsoluteReturnMeasures.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Financial
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics.Statistics;
public static class AbsoluteReturnMeasures
{
/// <summary>
/// Compound Monthly Return or Geometric Return or Annualized Return
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static double CompoundMonthlyReturn(this IEnumerable<double> data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var samples = data.Count();
if (samples == 0)
return double.NaN;
double compoundReturn = 1.0;
foreach (var item in data)
{
compoundReturn *= (1 + item);
}
return Math.Pow(compoundReturn, 1.0 / (double)samples) - 1.0;
}
/// <summary>
/// Average Gain or Gain Mean
/// This is a simple average (arithmetic mean) of the periods with a gain. It is calculated by summing the returns for gain periods (return 0)
/// and then dividing the total by the number of gain periods.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
/// <remarks>http://www.offshore-library.com/kb/statistics.php</remarks>
public static double GainMean(this IEnumerable<double> data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var gains = data.Where(x => x >= 0);
return gains.Mean();
}
/// <summary>
/// Average Loss or LossMean
/// This is a simple average (arithmetic mean) of the periods with a loss. It is calculated by summing the returns for loss periods (return < 0)
/// and then dividing the total by the number of loss periods.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
/// <remarks>http://www.offshore-library.com/kb/statistics.php</remarks>
public static double LossMean(this IEnumerable<double> data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var losses = data.Where(x => x < 0);
return losses.Mean();
}
}
}

46
src/Numerics/Financial/AbsoluteRiskStatistics.cs

@ -36,7 +36,7 @@ namespace MathNet.Numerics.Financial
using System.Text;
using MathNet.Numerics.Statistics;
public static class AbsoluteRiskStatistics
public static class AbsoluteRiskMeasures
{
//Note: The following statistics would be condidered an absolute risk statistic in the finance realm as well.
// Standard Deviation
@ -135,44 +135,6 @@ namespace MathNet.Numerics.Financial
return belowMeanData.StandardDeviation();
}
/// <summary>
/// Average Gain or Gain Mean
/// This is a simple average (arithmetic mean) of the periods with a gain. It is calculated by summing the returns for gain periods (return 0)
/// and then dividing the total by the number of gain periods.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
/// <remarks>http://www.offshore-library.com/kb/statistics.php</remarks>
public static double GainMean(this IEnumerable<double> data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var gains = data.Where(x => x >= 0);
return gains.Mean();
}
/// <summary>
/// Average Loss or LossMean
/// This is a simple average (arithmetic mean) of the periods with a loss. It is calculated by summing the returns for loss periods (return < 0)
/// and then dividing the total by the number of loss periods.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
/// <remarks>http://www.offshore-library.com/kb/statistics.php</remarks>
public static double LossMean(this IEnumerable<double> data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var losses = data.Where(x => x < 0);
return losses.Mean();
}
/// <summary>
/// Measures a fund’s average gain in a gain period divided by the fund’s average loss in a losing
/// period. Periods can be monthly or quarterly depending on the data frequency.
@ -190,9 +152,9 @@ namespace MathNet.Numerics.Financial
var losses = data.Where(x => x < 0);
var lossMean = losses.Mean();
if(lossMean != 0.0)
return Math.Abs(gains.Mean() / losses.Mean());
return 0.0;
return Math.Abs(gains.Mean() / losses.Mean());
}
}
}

1
src/Numerics/Numerics.csproj

@ -105,6 +105,7 @@
<Compile Include="Constants.cs" />
<Compile Include="Control.cs" />
<Compile Include="Complex32.cs" />
<Compile Include="Financial\AbsoluteReturnMeasures.cs" />
<Compile Include="Financial\AbsoluteRiskStatistics.cs" />
<Compile Include="LinearAlgebra\Generic\Matrix.BCL.cs" />
<Compile Include="LinearAlgebra\Generic\Vector.BCL.cs" />

75
src/UnitTests/FinancialTests/CompoundMonthlyReturnTests.cs

@ -0,0 +1,75 @@
// <copyright file="CompoundMonthlyReturnTests.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
// Copyright (c) 2009-2010 Math.NET
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.UnitTests.FinancialTests
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics.Financial;
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class CompoundMonthlyReturnTests
{
[Test]
[ExpectedException(typeof(ArgumentNullException))] //assert
public void throws_when_input_data_is_null()
{
//arrange
List<double> inputData = null;
//act
inputData.CompoundMonthlyReturn();
}
[Test]
public void returns_undefined_with_empty_input_data()
{
//arrange
List<double> inputData = new List<double>();
//act
var cmpdReturn = inputData.CompoundMonthlyReturn();
//assert
Assert.AreEqual(double.NaN, cmpdReturn);
}
[Test]
public void calculates_the_compound_monthly_return()
{
//arrange
var inputData = new[] { 0.2, 0.06, 0.01 };
//act
var cmpdReturn = inputData.CompoundMonthlyReturn();
//assert
AssertHelpers.AlmostEqual(0.0870999982199265, cmpdReturn, 15);
}
//Definitly need more tests here. Would love to find test data for these stats similar to the .dat files used for other tests.
}
}

1
src/UnitTests/FinancialTests/DownsideDeviationTests.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class DownsideDeviationTests
{
[Test]

23
src/UnitTests/FinancialTests/GainLossRatioTests.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class GainLossRatioTests
{
[Test]
@ -48,61 +49,61 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
[Test]
//Not sure this is correct. Undefined may be more correct.
public void returns_zero_for_a_single_positive_input()
public void returns_NaN_for_a_single_positive_input()
{
//arrange
var inputData = new[] { 1.0 };
//act
var gainLossRatio = inputData.GainLossRatio();
//assert
Assert.AreEqual(0.0, gainLossRatio);
Assert.AreEqual(double.NaN, gainLossRatio);
}
[Test]
//Not sure this is correct. Undefined may be more correct.
public void returns_zero_for_a_single_negative_input()
public void returns_NaN_for_a_single_negative_input()
{
//arrange
var inputData = new[] { -1.0 };
//act
var gainLossRatio = inputData.GainLossRatio();
//assert
Assert.AreEqual(0.0, gainLossRatio);
Assert.AreEqual(double.NaN, gainLossRatio);
}
[Test]
//Not sure this is correct. Undefined may be more correct.
public void returns_zero_for_a_set_of_all_positive_numbers()
public void returns_NaN_for_a_set_of_all_positive_numbers()
{
//arrange
var inputData = new[] { 1.0, 2.0, 3.0 };
//act
var gainLossRatio = inputData.GainLossRatio();
//assert
Assert.AreEqual(0.0, gainLossRatio);
Assert.AreEqual(double.NaN, gainLossRatio);
}
[Test]
//Not sure this is correct. Undefined may be more correct.
public void returns_zero_for_a_set_of_all_negative_numbers()
public void returns_NaN_for_a_set_of_all_negative_numbers()
{
//arrange
var inputData = new[] { -1.0, -2.0, -3.0 };
//act
var gainLossRatio = inputData.GainLossRatio();
//assert
Assert.AreEqual(0.0, gainLossRatio);
Assert.AreEqual(double.NaN, gainLossRatio);
}
[Test]
public void handles_a_value_of_zero_as_a_positive()
{
//arrange
var inputData = new[] { 0.0, 1.0, 2.0 };
var inputData = new[] { 0.0, -1.0 };
//act
var gainLossRatio = inputData.GainLossRatio();
var gainLossRatio = inputData.GainLossRatio();
//assert
Assert.AreEqual(0.0, gainLossRatio);
Assert.AreEqual(0.0, gainLossRatio); //0.0 / -1.0 => 0.0
}
[Test]

9
src/UnitTests/FinancialTests/GainMeanTests.cs

@ -33,6 +33,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class GainMeanTests
{
[Test]
@ -46,14 +47,14 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
Assert.AreEqual(0.0, gainMean);
}
[Test]
public void returns_zero_when_all_input_is_negative()
public void returns_NaN_when_all_input_is_negative()
{
//arrange
var inputData = new[] { -1.0, -2.0, -3.0 };
//act
var gainMean = inputData.GainMean();
//assert
Assert.AreEqual(0.0, gainMean);
Assert.AreEqual(double.NaN, gainMean);
}
[Test]
@ -91,14 +92,14 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
}
[Test]
public void returns_zero_with_no_input_data()
public void returns_NaN_with_no_input_data()
{
//arrange
var inputData = new List<double>();
//act
var gainMean = inputData.GainMean();
//assert
Assert.AreEqual(0.0, gainMean);
Assert.AreEqual(double.NaN, gainMean);
}
}

1
src/UnitTests/FinancialTests/GainStandardDeviationTests.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class GainStandardDeviationTests
{
[Test]

15
src/UnitTests/FinancialTests/LossMeanTests.cs

@ -33,28 +33,29 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class LossMeanTests
{
[Test]
public void returns_zero_when_zero_is_the_only_input()
public void returns_NaN_when_zero_is_the_only_input()
{
//arrange
var inputData = new[] { 0.0 };
//act
var lossMean = inputData.LossMean();
//assert
Assert.AreEqual(0.0, lossMean);
Assert.AreEqual(double.NaN, lossMean);
}
[Test]
public void returns_zero_when_all_input_is_positive()
public void returns_NaN_when_all_input_is_positive()
{
//arrange
var inputData = new[] { 1.0 };
var inputData = new[] { 0.0, 1.0 };
//act
var lossMean = inputData.LossMean();
//assert
Assert.AreEqual(0.0, lossMean);
Assert.AreEqual(double.NaN, lossMean);
}
[Test]
@ -92,14 +93,14 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
}
[Test]
public void returns_zero_with_no_input_data()
public void returns_NaN_with_no_input_data()
{
//arrange
var inputData = new List<double>();
//act
var lossMean = inputData.LossMean();
//assert
Assert.AreEqual(0.0, lossMean);
Assert.AreEqual(double.NaN, lossMean);
}
}
}

1
src/UnitTests/FinancialTests/LossStandardDeviationTests.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class LossStandardDeviationTests
{
[Test]

1
src/UnitTests/FinancialTests/SemiDeviationTests.cs

@ -34,6 +34,7 @@ namespace MathNet.Numerics.UnitTests.FinancialTests
using NUnit.Framework;
[TestFixture]
[Category("FinancialTests")]
public class SemiDeviationTests
{
[Test]

1
src/UnitTests/UnitTests.csproj

@ -122,6 +122,7 @@
<Compile Include="DistributionTests\Multivariate\MultinomialTests.cs" />
<Compile Include="DistributionTests\Multivariate\NormalGammaTests.cs" />
<Compile Include="DistributionTests\Multivariate\WishartTests.cs" />
<Compile Include="FinancialTests\CompoundMonthlyReturnTests.cs" />
<Compile Include="FinancialTests\DownsideDeviationTests.cs" />
<Compile Include="FinancialTests\GainLossRatioTests.cs" />
<Compile Include="FinancialTests\GainStandardDeviationTests.cs" />

Loading…
Cancel
Save