Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Frends.Community.ExcelFinancialFunctions.Tests/XIrr.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ public void ThreeXIrrToolss()

var options = new Options
{
Tolerance = 0.00000001,
MaxIterations = 100
Guess = 0.1
};

var ret = XIrrTools.CalculateXIrr(input, options, new System.Threading.CancellationToken());

Assert.That(ret.Value, Is.EqualTo("77.4425237947709"));
Assert.That(ret.Value, Is.EqualTo("77.4425237947701"));
}
}
}
23 changes: 16 additions & 7 deletions Frends.Community.ExcelFinancialFunctions/Definition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Frends.Community.ExcelFinancialFunctions
public class Parameters
{
/// <summary>
/// JArray string with value and date
/// JArray string with value and date Dates should be sorted in ascending order.
/// </summary>
/// <example>
/// [{value: 1.234, date: "2021-05-25"}, {value: 2.345, date: "2022-05-25"}]
Expand All @@ -26,16 +26,25 @@ public class Parameters
public class Options
{
/// <summary>
/// Tolerance that will be used in calculations.
/// Guess is a number that you guess is close to the result of XIRR.
/// </summary>
[DefaultValue(0.00000001)]
public double Tolerance { get; set; }
[DefaultValue(0.1)]
public double Guess { get; set; }

/// <summary>
/// Max number of iterations(to prevent infinite looping).
/// If set, allows you to ignore errors and return specified value.
/// If not set, error will be thrown normally.
/// </summary>
[DefaultValue(100)]
public int MaxIterations { get; set; }
[DefaultValue(false)]
public bool ReturnValueOnError { get; set; }

/// <summary>
/// What task should return on failure (string)
/// </summary>
[UIHint(nameof(ReturnValueOnError), "", true)]
[DisplayFormat(DataFormatString = "Text")]
[DefaultValue("NM")]
public string ReturnValue { get; set; }
}

public class Result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net471</TargetFrameworks>
<description>Tasks for financial calculations using Excel Functions</description>
<authors>HiQ Finland</authors>
<copyright>HiQ Finland</copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/CommunityHiQ/Frends.Community.ExcelFinancialFunctions</PackageProjectUrl>
<IncludeSource>true</IncludeSource>
<PackageTags>Frends</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Version>0.1.6</Version>
<Version>0.1.13</Version>
</PropertyGroup>

<ItemGroup>
Expand All @@ -19,6 +20,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="ExcelFinancialFunctions" Version="3.2.0" />
<PackageReference Include="FSharp.Core" Version="6.0.5" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
Expand Down
82 changes: 18 additions & 64 deletions Frends.Community.ExcelFinancialFunctions/Methods.cs
Original file line number Diff line number Diff line change
@@ -1,90 +1,44 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Frends.Community.ExcelFinancialFunctions
{
internal class Methods
{
public delegate double fx(double x);

public static fx composeFunctions(fx f1, fx f2)
{
return (double x) => f1(x) + f2(x);
}

public static fx f_xirr(double p, double dt, double dt0)
{
return (double x) => p * Math.Pow((1.0 + x), ((dt0 - dt) / 365.0));
}

public static fx df_xirr(double p, double dt, double dt0)
{
return (double x) => (1.0 / 365.0) * (dt0 - dt) * p * Math.Pow((x + 1.0), (((dt0 - dt) / 365.0) - 1.0));
}

public static fx total_f_xirr(double[] payments, double[] days)
/// <summary>
/// Calculates XIrr using ExcelFinancialFunctions .NET Standard library
/// </summary>
/// <param name="cancellationToken"></param>
public static List<double> getPaymentsFromJArray(JArray jarray, CancellationToken cancellationToken)
{
fx resf = (double x) => 0.0;
var values = new List<double>();

for (int i = 0; i < payments.Length; i++)
foreach (var item in jarray)
{
resf = composeFunctions(resf, f_xirr(payments[i], days[i], days[0]));
}

return resf;
}

public static fx total_df_xirr(double[] payments, double[] days)
{
fx resf = (double x) => 0.0;
cancellationToken.ThrowIfCancellationRequested();

for (int i = 0; i < payments.Length; i++)
{
resf = composeFunctions(resf, df_xirr(payments[i], days[i], days[0]));
double value = double.Parse(item["value"].ToString());
values.Add(value);
}

return resf;
return values;
}


/// <summary>
/// Calculates XIrr using Newton's method
/// </summary>
/// <param name="cancellationToken"></param>
public static double Newtons_method(double guess, fx f, fx df, double tol, int maxIterations, CancellationToken cancellationToken)
public static List<DateTime> getDatesFromJArray(JArray jarray, CancellationToken cancellationToken)
{
int i = 0;
double x0 = guess;
double x1 = 0.0;
double err = 1e+100;
var dates = new List<DateTime>();

while (err > tol && ++i < maxIterations)
foreach (var item in jarray)
{
cancellationToken.ThrowIfCancellationRequested();
x1 = x0 - f(x0) / df(x0);
err = Math.Abs(x1 - x0);
x0 = x1;
}
if (i == maxIterations)
{
throw new InvalidOperationException("Could not calculate: No solution found. Max iterations reached.");
}

return x0;
}

public static double[] getPaymentsFromJArray(JArray jarray)
{
return jarray.Select(x => double.Parse(x["value"].ToString())).ToList().ToArray();
}
DateTime date = DateTime.Parse(item["date"].ToString());
dates.Add(date);
}

public static double[] getDaysFromJArray(JArray jarray)
{
return jarray.Select(x => (double)DateTime.Parse(x["date"].ToString()).DayOfYear).ToList().ToArray();
return dates;
}
}
}
36 changes: 24 additions & 12 deletions Frends.Community.ExcelFinancialFunctions/XIrrTools.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.ComponentModel;
using System.Threading;
using Microsoft.CSharp; // You can remove this if you don't need dynamic type in .NET Standard frends Tasks
using Newtonsoft.Json.Linq;
using Excel.FinancialFunctions;
using System.Collections.Generic;
using System;

#pragma warning disable 1591

Expand All @@ -14,26 +16,36 @@ public static class XIrrTools
/// Documentation: https://github.com/CommunityHiQ/Frends.Community.ExcelFinancialFunctions
/// </summary>
/// <param name="input">Values and dates for calculations</param>
/// <param name="options">Define tollerance and max iterations.</param>
/// <param name="options">Define guess and error value.</param>
/// <param name="cancellationToken"></param>
/// <returns>Object {string Value} </returns>
public static Result CalculateXIrr([PropertyTab] Parameters input, [PropertyTab] Options options, CancellationToken cancellationToken)
{
JArray jarray = JArray.Parse(input.Input);

int maxIter = options.MaxIterations;
double tol = options.Tolerance;
double guess = options.Guess;

double[] payments = Methods.getPaymentsFromJArray(jarray); // payments
double[] days = Methods.getDaysFromJArray(jarray); // days of payment (as day of year)
double xirr = Methods.Newtons_method(0.1,
Methods.total_f_xirr(payments, days),
Methods.total_df_xirr(payments, days),
tol,
maxIter,
cancellationToken);
List<double> payments = Methods.getPaymentsFromJArray(jarray, cancellationToken); // payments
List<DateTime> dates = Methods.getDatesFromJArray(jarray, cancellationToken); // dates of payment

string xirr;

if (options.ReturnValueOnError)
{
try
{
xirr = Financial.XIrr(payments, dates, guess).ToString();
}
catch (Exception)
{
xirr = options.ReturnValue.ToString();
}
}
else
{
xirr = Financial.XIrr(payments, dates, guess).ToString();
}

var output = new Result
{
Value = xirr.ToString()
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,27 @@ https://www.myget.org/F/frends-community/api/v3/index.json and in Gallery view i

## XIrrTools

Task calculates XIrr value using Newtons method
Task calculates XIrr value using Excel Financial Functions from .NET library

### Properties

| Property | Type | Description | Example |
| -------- | -------- | -------- | -------- |
| Input | `string` | JArray string with values and dates. | `[{value: 1.234, date: "2021-05-25"}, {value: 2.345, date: "2022-05-25"}]` |
| Input | `string` | JArray string with values and dates. Dates should be sorted in ascending order.| `[{value: 1.234, date: "2021-05-25"}, {value: 2.345, date: "2022-05-25"}]` |

### Options

| Property | Type | Description | Example |
| -------- | -------- | -------- | -------- |
| Tolerance | `double` | Tolerance used in calculations. | `0.00000001` |
| MaxIterations | `int` | Max. number of iterations while calculating Xirr value. | `100` |
| Guess | `double` | Guess is a number that you guess is close to the result of XIRR. | `0.1` |

### Returns

A result object with parameters.

| Property | Type | Description | Example |
| -------- | -------- | -------- | -------- |
| Value | `string` | Calculated XIrr value. | `77.4425237947709` |
| Value | `string` | Calculated XIrr value. | `77.4425237947701` |

Usage:
To fetch result use syntax:
Expand Down Expand Up @@ -87,3 +86,10 @@ NOTE: Be sure to merge the latest from "upstream" before making a pull request!
| 0.1.4 | Test case created, README updated |
| 0.1.5 | Fixed input tab |
| 0.1.6 | Minor changes to descriptions |
| 0.1.7 | Add description to .csproj file |
| 0.1.8 | Calculate Xirr using .NET Excel library |
| 0.1.9 | Add FSharp.Core to the task |
| 0.1.10 | Remove unnecessary comments and namespaces |
| 0.1.11 | Update README |
| 0.1.12 | Add option to return value on error |
| 0.1.13 | Update Properties description |