How do I calculate Excel's XIRR function using C#?
According to XIRR function openoffice documentation (formula is same as in excel) you need to solve for XIRR variable in the following f(xirr) equation:
You can calculate xirr value by:
calculating derivative of above function -> f '(xirr)
after having f(xirr) and f'(xirr) you can solve for xirr value by using iterative Newton's method - famous formula->
EDIT
I've got a bit of time so, here it is - complete C# code for XIRR calculation:
class xirr
{
public const double tol = 0.001;
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) {
fx resf = (double x) => 0.0;
for (int i = 0; i < payments.Length; i++) {
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;
for (int i = 0; i < payments.Length; i++) {
resf = composeFunctions(resf,df_xirr(payments[i],days[i],days[0]));
}
return resf;
}
public static double Newtons_method(double guess, fx f, fx df) {
double x0 = guess;
double x1 = 0.0;
double err = 1e+100;
while (err > tol) {
x1 = x0 - f(x0)/df(x0);
err = Math.Abs(x1-x0);
x0 = x1;
}
return x0;
}
public static void Main (string[] args)
{
double[] payments = {-6800,1000,2000,4000}; // payments
double[] days = {01,08,16,25}; // days of payment (as day of year)
double xirr = Newtons_method(0.1,
total_f_xirr(payments,days),
total_df_xirr(payments,days));
Console.WriteLine("XIRR value is {0}", xirr);
}
}
BTW, keep in mind that not all payments will result in valid XIRR because of restrictions of formula and/or Newton method!
cheers!
I started with 0x69's solution but eventually some new scenarios caused Newton's Method to fail. I created a "smart" version, which uses Bisection Method (slower) when Newton's fails.
Please notice the inline references to multiple sources I used for this solution.
Finally, you are not going to be able to reproduce some of these scenarios in Excel, for Excel itself uses Newton's method. Refer to XIRR, eh? for an interesting discussion about this.
using System;
using System.Collections.Generic;
using System.Linq;
// See the following articles:
// http://blogs.msdn.com/b/lucabol/archive/2007/12/17/bisection-based-xirr-implementation-in-c.aspx
// http://www.codeproject.com/Articles/79541/Three-Methods-for-Root-finding-in-C
// http://www.financialwebring.org/forum/viewtopic.php?t=105243&highlight=xirr
// Default values based on Excel doc
// http://office.microsoft.com/en-us/excel-help/xirr-function-HP010062387.aspx
namespace Xirr
{
public class Program
{
private const Double DaysPerYear = 365.0;
private const int MaxIterations = 100;
private const double DefaultTolerance = 1E-6;
private const double DefaultGuess = 0.1;
private static readonly Func<IEnumerable<CashItem>, Double> NewthonsMethod =
cf => NewtonsMethodImplementation(cf, Xnpv, XnpvPrime);
private static readonly Func<IEnumerable<CashItem>, Double> BisectionMethod =
cf => BisectionMethodImplementation(cf, Xnpv);
public static void Main(string[] args)
{
RunScenario(new[]
{
// this scenario fails with Newton's but succeeds with slower Bisection
new CashItem(new DateTime(2012, 6, 1), 0.01),
new CashItem(new DateTime(2012, 7, 23), 3042626.18),
new CashItem(new DateTime(2012, 11, 7), -491356.62),
new CashItem(new DateTime(2012, 11, 30), 631579.92),
new CashItem(new DateTime(2012, 12, 1), 19769.5),
new CashItem(new DateTime(2013, 1, 16), 1551771.47),
new CashItem(new DateTime(2013, 2, 8), -304595),
new CashItem(new DateTime(2013, 3, 26), 3880609.64),
new CashItem(new DateTime(2013, 3, 31), -4331949.61)
});
RunScenario(new[]
{
new CashItem(new DateTime(2001, 5, 1), 10000),
new CashItem(new DateTime(2002, 3, 1), 2000),
new CashItem(new DateTime(2002, 5, 1), -5500),
new CashItem(new DateTime(2002, 9, 1), 3000),
new CashItem(new DateTime(2003, 2, 1), 3500),
new CashItem(new DateTime(2003, 5, 1), -15000)
});
}
private static void RunScenario(IEnumerable<CashItem> cashFlow)
{
try
{
try
{
var result = CalcXirr(cashFlow, NewthonsMethod);
Console.WriteLine("XIRR [Newton's] value is {0}", result);
}
catch (InvalidOperationException)
{
// Failed: try another algorithm
var result = CalcXirr(cashFlow, BisectionMethod);
Console.WriteLine("XIRR [Bisection] (Newton's failed) value is {0}", result);
}
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
}
catch (InvalidOperationException exception)
{
Console.WriteLine(exception.Message);
}
}
private static double CalcXirr(IEnumerable<CashItem> cashFlow, Func<IEnumerable<CashItem>, double> method)
{
if (cashFlow.Count(cf => cf.Amount > 0) == 0)
throw new ArgumentException("Add at least one positive item");
if (cashFlow.Count(c => c.Amount < 0) == 0)
throw new ArgumentException("Add at least one negative item");
var result = method(cashFlow);
if (Double.IsInfinity(result))
throw new InvalidOperationException("Could not calculate: Infinity");
if (Double.IsNaN(result))
throw new InvalidOperationException("Could not calculate: Not a number");
return result;
}
private static Double NewtonsMethodImplementation(IEnumerable<CashItem> cashFlow,
Func<IEnumerable<CashItem>, Double, Double> f,
Func<IEnumerable<CashItem>, Double, Double> df,
Double guess = DefaultGuess,
Double tolerance = DefaultTolerance,
int maxIterations = MaxIterations)
{
var x0 = guess;
var i = 0;
Double error;
do
{
var dfx0 = df(cashFlow, x0);
if (Math.Abs(dfx0 - 0) < Double.Epsilon)
throw new InvalidOperationException("Could not calculate: No solution found. df(x) = 0");
var fx0 = f(cashFlow, x0);
var x1 = x0 - fx0/dfx0;
error = Math.Abs(x1 - x0);
x0 = x1;
} while (error > tolerance && ++i < maxIterations);
if (i == maxIterations)
throw new InvalidOperationException("Could not calculate: No solution found. Max iterations reached.");
return x0;
}
internal static Double BisectionMethodImplementation(IEnumerable<CashItem> cashFlow,
Func<IEnumerable<CashItem>, Double, Double> f,
Double tolerance = DefaultTolerance,
int maxIterations = MaxIterations)
{
// From "Applied Numerical Analysis" by Gerald
var brackets = Brackets.Find(Xnpv, cashFlow);
if (Math.Abs(brackets.First - brackets.Second) < Double.Epsilon)
throw new ArgumentException("Could not calculate: bracket failed");
Double f3;
Double result;
var x1 = brackets.First;
var x2 = brackets.Second;
var i = 0;
do
{
var f1 = f(cashFlow, x1);
var f2 = f(cashFlow, x2);
if (Math.Abs(f1) < Double.Epsilon && Math.Abs(f2) < Double.Epsilon)
throw new InvalidOperationException("Could not calculate: No solution found");
if (f1*f2 > 0)
throw new ArgumentException("Could not calculate: bracket failed for x1, x2");
result = (x1 + x2)/2;
f3 = f(cashFlow, result);
if (f3*f1 < 0)
x2 = result;
else
x1 = result;
} while (Math.Abs(x1 - x2)/2 > tolerance && Math.Abs(f3) > Double.Epsilon && ++i < maxIterations);
if (i == maxIterations)
throw new InvalidOperationException("Could not calculate: No solution found");
return result;
}
private static Double Xnpv(IEnumerable<CashItem> cashFlow, Double rate)
{
if (rate <= -1)
rate = -1 + 1E-10; // Very funky ... Better check what an IRR <= -100% means
var startDate = cashFlow.OrderBy(i => i.Date).First().Date;
return
(from item in cashFlow
let days = -(item.Date - startDate).Days
select item.Amount*Math.Pow(1 + rate, days/DaysPerYear)).Sum();
}
private static Double XnpvPrime(IEnumerable<CashItem> cashFlow, Double rate)
{
var startDate = cashFlow.OrderBy(i => i.Date).First().Date;
return (from item in cashFlow
let daysRatio = -(item.Date - startDate).Days/DaysPerYear
select item.Amount*daysRatio*Math.Pow(1.0 + rate, daysRatio - 1)).Sum();
}
public struct Brackets
{
public readonly Double First;
public readonly Double Second;
public Brackets(Double first, Double second)
{
First = first;
Second = second;
}
internal static Brackets Find(Func<IEnumerable<CashItem>, Double, Double> f,
IEnumerable<CashItem> cashFlow,
Double guess = DefaultGuess,
int maxIterations = MaxIterations)
{
const Double bracketStep = 0.5;
var leftBracket = guess - bracketStep;
var rightBracket = guess + bracketStep;
var i = 0;
while (f(cashFlow, leftBracket)*f(cashFlow, rightBracket) > 0 && i++ < maxIterations)
{
leftBracket -= bracketStep;
rightBracket += bracketStep;
}
return i >= maxIterations
? new Brackets(0, 0)
: new Brackets(leftBracket, rightBracket);
}
}
public struct CashItem
{
public DateTime Date;
public Double Amount;
public CashItem(DateTime date, Double amount)
{
Date = date;
Amount = amount;
}
}
}
}
Thanks to contributors of the nuget package located at Excel Financial Functions. It supports many financial methods - AccrInt, Irr, Npv, Pv, XIrr, XNpv, etc.,
Install and import the package.
As all the methods are static in Financial class, directly call specific method as Financial.<method_name> with required parameters.
Example:
using Excel.FinancialFunctions;
namespace ExcelXirr
{
class Program
{
static void Main(string[] args)
{
List<double> valList =new List<double>();
valList.Add(4166.67);
valList.Add(-4166.67);
valList.Add(-4166.67);
valList.Add(-4166.67);
List<DateTime> dtList = new List<DateTime>();
dtList.Add(new DateTime(2014, 9, 1));
dtList.Add(new DateTime(2014, 10, 1));
dtList.Add(new DateTime(2014, 11, 1));
dtList.Add(new DateTime(2014, 12, 1));
double result = Financial.XIrr(valList, dtList);
Console.WriteLine(result);
Console.ReadLine();
}
}
}
Result is same as Excel.
The other answers show how to implement XIRR in C#, but if only the calculation result is needed you can call Excel's XIRR function directly in the following way:
First add reference to Microsoft.Office.Interop.Excel and then use the following method:
public static double Xirr(IList<double> values, IList<DateTime> dates)
{
var xlApp = new Application();
var datesAsDoubles = new List<double>();
foreach (var date in dates)
{
var totalDays = (date - DateTime.MinValue).TotalDays;
datesAsDoubles.Add(totalDays);
}
var valuesArray = values.ToArray();
var datesArray = datesAsDoubles.ToArray();
return xlApp.WorksheetFunction.Xirr(valuesArray, datesArray);
}
This repo from GitHub - klearlending/XIRR has sample code on how to calculate XIRR.
The author also provided a blogpost XIRR-demystified, that explains the logic and reasoning.
So far that lib is giving close to accurate results for me. (Still exploring it and forked it for personal use)
Related
I have two lists Schedule(Having Total Hours) And Registered (Having Time Intervals). I want to create a list that is having registered time covered with Schedule list total hours finished.
See the Upper image. The resultant list is covering Registered Times and ENd if it doesn't find any registration for left hours. It will just create further times according to hours left with their types.
Take a look at this sample:
class Task
{
public int duration;
public string type;
public int remaining;
public void Reset()
{
remaining = duration;
}
}
class Span
{
public int from;
public int to;
public int remaining;
public int duration => to - from;
public void Reset()
{
remaining = duration;
}
}
struct Assignment
{
public Span span;
public string type;
}
static IEnumerable<Assignment> AssignTasks(List<Task> tasks, List<Span> spans)
{
// add an infinite span to the end of list
spans.Add(new Span()
{
from = spans.Last().to,
to = int.MaxValue
});
// set remainings of tasks and spans by their total duration
foreach (Task task in tasks) { task.Reset(); }
foreach (Span span in spans) { span.Reset(); }
// set current task and span
int iTask = 0;
int iSpan = 0;
while (iTask < tasks.Count)
{
//find which is smaller: remaining part of current task, or
// remaining part of current span
int assigning =
tasks[iTask].remaining <= spans[iSpan].remaining ?
tasks[iTask].remaining : spans[iSpan].remaining;
// add a new assignment to results
yield return new Assignment()
{
span = new Span()
{
from = spans[iSpan].to - spans[iSpan].remaining,
to = spans[iSpan].to - spans[iSpan].remaining + assigning,
},
type = tasks[iTask].type
};
// update remaining parts of current task and span
tasks[iTask].remaining -= assigning;
spans[iSpan].remaining -= assigning;
// update counters if nothing is left
if (tasks[iTask].remaining == 0)
iTask++;
if (spans[iSpan].remaining == 0)
iSpan++;
}
}
In this piece of code, Task is equivalent to what you call "Scheduled", and Span is equivalent to "Registered". I removed From and To from Task because they seem irrelevant to the problem. I also added a Remaining field to both Task and Span classes, I use these to keep the unassigned part of tasks or spans since a portion of a task can be assigned to a portion of a span.
The key point, to make everything much easier, is adding an infinite span to the end of list of spans. Now there are more registered spans (resources) than our demands and we just need to simply assign them.
You can test it like this:
static void Main(string[] args)
{
List<Task> tasks = new List<Task>()
{
new Task() {duration = 4, type = "A"},
new Task() {duration = 2, type = "B"},
new Task() {duration = 6, type = "C"},
new Task() {duration = 8, type = "D"}
};
List<Span> spans = new List<Span>()
{
new Span() {from = 9, to = 10},
new Span() {from = 11, to = 13},
new Span() {from = 15, to = 20}
};
IEnumerable<Assignment> assignments = AssignTasks(tasks, spans);
Console.WriteLine("Tasks: duration, type");
foreach (Task task in tasks)
{
Console.WriteLine($"{task.duration}, {task.type}");
}
Console.WriteLine("\nSpans: from, to");
foreach (Span span in spans)
{
Console.WriteLine($"{span.from}, {span.to}");
}
Console.WriteLine("\nResults: from, to, type");
foreach (Assignment assignment in assignments)
{
Console.WriteLine($"{assignment.span.from}, {assignment.span.to}, {assignment.type}");
}
Console.ReadLine();
}
The outcome is:
Tasks: duration, type
4, A
2, B
6, C
8, D
Spans: from, to
9, 10
11, 13
15, 20
Results: from, to, type
9, 10, A
11, 13, A
15, 16, A
16, 18, B
18, 20, C
20, 24, C
24, 32, D
Here's my solution:
The following enum and classes represent the input format you requested.
public enum SType
{
A,
B,
C,
D
}
public class Schedule : Register
{
public SType Type { get; set; }
public Schedule(int from, int to, SType type) : base(from, to)
{
Type = type;
}
}
public class Register
{
public int From { get; set; }
public int To { get; set; }
public int TotalHours => To - From;
public Register(int from, int to)
{
From = from;
To = to;
}
}
Then, following your sample input:
var scheduled = new List<Schedule>()
{
new Schedule(0, 4, SType.A),
new Schedule(4, 6, SType.B),
new Schedule(6, 12, SType.C),
new Schedule(12, 20, SType.D)
};
var registered = new List<Register>()
{
new Register(9, 10),
new Register(11, 13),
new Register(15, 20)
};
This will retrieve the requested output:
var result = new List<Schedule>();
int elapsedHours = 0;
foreach (var s in scheduled)
{
int hours = s.TotalHours;
foreach (var r in registered)
{
if (elapsedHours <= r.To)
{
int from = Math.Max(elapsedHours, r.From);
if (r.TotalHours <= hours)
{
elapsedHours = r.To;
result.Add(new Schedule(from, elapsedHours, s.Type));
hours -= (elapsedHours - from);
}
else
{
elapsedHours = from + hours;
result.Add(new Schedule(from, elapsedHours, s.Type));
hours = 0;
}
}
}
if (hours > 0)
{
result.Add(new Schedule(elapsedHours, elapsedHours + hours, s.Type));
elapsedHours += hours;
}
}
Using the following classes to represent your source data:
public class Schedule {
public int From;
public int To;
public int TotalHours => To - From;
public string Type;
public Schedule(int from, int to, string type) {
From = from;
To = to;
Type = type;
}
}
public class Register {
public int From;
public int To;
public Register(int from, int to) {
From = from;
To = to;
}
}
Here is a for loop implementation that spreads each Schedule member across the Registered time intervals and then outputs the rest:
var ans = new List<Schedule>();
int currentRegistered = 0;
var rp = registered[currentRegistered];
var currentFrom = rp.From;
for (int curScheduled = 0; curScheduled < scheduled.Count; ++curScheduled) {
var s = scheduled[curScheduled];
for (var hours = s.TotalHours; hours > 0;) {
if (currentFrom >= rp.To)
rp = (++currentRegistered < registered.Count)
? registered[currentRegistered]
: new Register(currentFrom, int.MaxValue);
if (rp.From > currentFrom)
currentFrom = rp.From;
var newTo = (rp.To - currentFrom > hours) ? currentFrom + hours : rp.To;
ans.Add(new Schedule(currentFrom, newTo, s.Type));
hours -= newTo - currentFrom;
currentFrom = newTo;
}
}
I don't like this code, it is overcomplicated and impractical, so I'm looking to simplify it.
I want it to change a var by a random amount, and I need to put at least 150 variables into this code.
//Variable list
public double price1 = 100;
public double price2 = 100;
public double price3 = 100;
public void DaysEnd(){ //Simplified version of inefficient code
var = price1;
HVariation();
price1 = newvar;
var = price2;
HVariation();
price2 = newvar;
var = price2;
MVariation();
price2 = newvar;
var = price3;
LVariation();
price3 = newvar;
}
public void Hvariation(){
newvar = var + (var * (Random.NextDouble(0 - 0.5, 0.5)));
}
public void Mvariation(){
newvar = var + (var * (Random.NextDouble(0 - 0.25, 0.25)));
}
public void Lvariation(){
newvar = var + (var * (Random.NextDouble(0 - 0.1, 0.5)));
}
This should get you started
List<double> values = new List<double> { 100, 100, 200, 500, ... };
values = values.Select(val => Hvariation(val)).ToList();
// now all values have been altered by Hvariation
...
private readonly Random _rand = new Random();
public double Hvariation(double val) {
return val + (val * (_rand.NextDouble(-0.5, 0.5)));
}
The first thing to do is find repeated code. For example:
var = price3;
LVariation(); //Different variations
price3 = newvar;
This can be turned into a method (that takes the variation as a parameter).
To do this, you will also need to make a default variation that takes the min and max:
public void Variation(double min, double max){
newvar = var + (var * (Random.NextDouble(min, max)));
}
You can then put this together to reduce code to look some thing like this:
public double UpdatePrice(double price, double min, double max)
{
var = price;
Variation(min, max);
return newvar;
}
In general, if I have to copy the code more than once (or even once if the amount copied is significant), I turn the code into a method.
You can simplify this by instead of defining three variation methods, defining a variation level and passing it into a single method. I'm not sure if you would need it to be in arrays or if you can use lists (in which case lists are preferable), but you can store your variable in an array instead of defining a variable name for each one and separate them into logical groupings as you need to. You can then apply the change/transformation to each array using LINQ. An example of this would be
public enum VariationLevel
{
High,
Medium,
Low
};
public double[] HighVariancePrices =
{
100, 100, 100, 100, 100
};
public double[] MediumVariancePrices =
{
100, 100, 100, 100, 100
};
public double[] LowVariancePrices =
{
100, 100, 100, 100, 100
};
public void DaysEnd()
{
HighVariancePrices = HighVariancePrices.Select(price => GetVariation(price, VariationLevel.High)).ToArray();
MediumVariancePrices = MediumVariancePrices.Select(price => GetVariation(price, VariationLevel.Medium)).ToArray();
LowVariancePrices = LowVariancePrices.Select(price => GetVariation(price, VariationLevel.Low)).ToArray();
}
public double GetVariation(double value, VariationLevel variationLevel)
{
switch (variationLevel)
{
case VariationLevel.High:
return value + (value * (Random.NextDouble(0 - 0.5, 0.5)));
case VariationLevel.Medium:
return value + (value * (Random.NextDouble(0 - 0.25, 0.25)));
case VariationLevel.Low:
return value + (value * (Random.NextDouble(0 - 0.1, 0.5)));
}
}
However, the code around Random.NextDouble() doesn't compile (because NextDouble doesn't take arguments) so I'm not certain what you're trying to do there, but that's outside of the scope of "how can I simplify my code?" Hope this helps some.
Heres a fun problem I have.
I have a function that returns a var of items;
var Items = new { sumList = SumList, ratesList = List, sum = List.Sum() };
return Items;
From a function that is dynamic:
public override dynamic GetRates()
and I return it to a function I else where and try to apply it to my code:
dynamic res = cl.mainC.GetRates();
List<double> MashkantaSumList = res.sumList;
Now when I try to apply it, it says the object doesnt exist. But if I look in the debugger the items are happily there as a generic list or what not.
How do I resolve this?
EDIT:
as per request I'll post the full code:
//virtual
public virtual dynamic TotalMashkanta(int i, double sum, double ribit, string[] discount)
{
return 0;
}
//override
public override dynamic TotalMashkanta(int i, double sum, double ribit, string[] discount)
{
double SumTemp = sum;
double monthlyRibit = ribit / 12;
Double permPayPerMont = Financial.Pmt(monthlyRibit, i, sum, 0, DueDate.EndOfPeriod);
List<double> MashkantaList = new List<double>();
List<double> MashkantaSumList = new List<double>();
for (int j = 1; j <= i; j++)
{
MashkantaList.Add(Mashkanta(j, sum, ribit, permPayPerMont) * (1 - CalcDiscount((j / 12) + 1, discount)));
SumTemp = getSum(j, sum, ribit, permPayPerMont * -1); ;
MashkantaSumList.Add(SumTemp);
}
var K_Mashkanta = new { sumList = MashkantaSumList, ratesList = MashkantaList, sum = MashkantaList.Sum() };
return K_Mashkanta;
}
//Function that calls the results
public void GetSilukinTable(string Path, string ClientID, DAL.Client client, string partner_checked, string insurance_Amount, string Premiya_Structure_Mashkanta, string Premiya_Life_Mashkanta, string Discount_Life_Mashkanta, string Loan_Period,string Loan_EndDate, string Bank, string Loan_Interest, string Loan_Amount, string Discount_Loan, string AgentNotes, string ManID)
{
BL.CalculateLogic.Companies t = BL.CalculateLogic.Companies.כלל;
if(ManID == "211") t = BL.CalculateLogic.Companies.הפניקס;
if(ManID == "207") t = BL.CalculateLogic.Companies.הראל;
if(ManID == "206") t = BL.CalculateLogic.Companies.מנורה;
if(ManID == "208") t = BL.CalculateLogic.Companies.הכשרה;
BL.CalculateLogic cl = new BL.CalculateLogic(client, t);
DateTime LoanEnd = DateTime.Now;
int months = 0;
if (DateTime.TryParse(Loan_EndDate, out LoanEnd))
months = BL.Calculating_Companies.Company.GetMonthsBetween(DateTime.Now, LoanEnd);
else
months = Int32.Parse(Loan_Period) * 12;
string[] Discount = Discount_Loan.Split('-');
dynamic res = cl.mainC.TotalMashkanta(months, Double.Parse(Loan_Amount), Double.Parse(Loan_Interest.Trim('%')), Discount);
var MashkantaSumList = res.sumList;
List<double> MashkantaList = res.ratesList;
List<double> MashkantaSumListPartner = new List<double>();
List<double> MashkantaListPartner = new List<double>();
List<double> MashkantaListSum = res.ratesList;
}
The compiler is happy about it because dynamic is compiled and checked at run time. Whatever the problem is, the types don't match. It evaluates this at run time, so you won't see issues at compile time. (Advice: use dynamic only when you really must! Else you will have this kind of problems all the time!)
I tried your code using this and it works fine:
static dynamic GetRates()
{
List<double> SumList = new List<double>();
List<double> List = new List<double>();
var Items = new { sumList = SumList, ratesList = List, sum = List.Sum() };
return Items;
}
static void Main(string[] args)
{
dynamic res = GetRates();
List<double> MashkantaSumList = res.sumList;
}
How can I get the same results of the Excel YearFrac function in my C# application?
Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations to assign to a specific term.
Here is a good snippet.
The algorithm for the YearFrac function is in fact very complex. Maybe this article can provide you with more details.
You can use Excel's functionality directly to calculate YearFrac. Microsoft says you are not supposed to use it, but it works very well. If you need a 100% compatibility with Excel, this solution is hard to beat. You need to add to your project a reference to Microsoft.Office.Interop.Excel in order for this code to compile.
static void Main() {
var excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.WorksheetFunction wsf = excel.WorksheetFunction;
var start = new DateTime(1999, 11, 1);
var end = new DateTime(1999, 1, 11);
for (var basis = 0; basis != 5; basis++) {
Console.WriteLine(wsf.YearFrac(start, end, basis));
}
}
The signature of YEARFRAC is YEARFRAC(Date startDate, Date endDate, int convention). The method to calculate the YEARFRAC depends on the convention.
For convention = 2, YEARFRAC will calculate the YEARFRAC using ACT/360 method. An implementation of the ACT/360 can be found at svn.finmath.net, specifically DayCountConvention_ACT_360.java
For convention = 3, YEARFRAC will calculate the YEARFRAC using ACT/365 method. An implementation of the ACT/365 can be found at svn.finmath.net, specifically
DayCountConvention_ACT_365.java
For convention = 4, YEARFRAC will calculate the YEARFRAC using 30E/360 method. An implementation of the 30E/360 can be found at svn.finmath.net, specifically DayCountConvention_30E_360.java
For convention = 1, the documentation claims that YEARFRAC is calculate using ACT/ACT convention. However, there are a multiple versions of ACT/ACT and I believe the standard for many financial products is ACT/ACT ISDA. I found that YEARFRAC differs by a small amount from the ACT/ACT IDSA convention! An implementation of the ACT/ACT IDSA can be found at DayCountConvention_ACT_ACT_ISDA.java
I haven't checked the other act/act versions yet, but I would not rely on an emulation of YEARFRAC ACT/ACT, when it is not clear what kind of method they implement...
May I suggest:
public static double Yearfrac(DateTime startDate,DateTime endDate,DayCount daycount=DayCount.ActAct)
{
var nbDaysInPeriod = (double)(endDate - startDate).Days;
switch(daycount)
{
case (DayCount.Act360):
return nbDaysInPeriod / (double)360;
case (DayCount.Act365):
return nbDaysInPeriod / (double)365;
case (DayCount.ActAct):
return GetActAct(startDate,endDate);
case (DayCount.Days360):
var result = (endDate.Year - startDate.Year) * 360.0 + (endDate.Month - startDate.Month) * 30.0 + (Math.Min(endDate.Day, 30.0) - Math.Min(startDate.Day, 30.0));
return result/360;
default:
return nbDaysInPeriod / (double)365;
}
}
public static double GetActAct(DateTime startDate, DateTime endDate)
{
// Reproduce Excel Yearfrac as per http://www.dwheeler.com/yearfrac/excel-ooxml-yearfrac.pdf
var nbDaysInPeriod = (double)(endDate - startDate).Days;
if(startDate.Year==endDate.Year || (endDate.Year-1==startDate.Year&&(startDate.Month>endDate.Month||startDate.Month==endDate.Month&&(startDate.Day>=endDate.Day))))
{
var den = 365.0;
if (startDate.Year == endDate.Year && DateTime.IsLeapYear(startDate.Year))
{
den++;
}
else
{
if (endDate.Day == 29 && endDate.Month == 2)
{
den++;
}
else
{
if (DateTime.IsLeapYear(startDate.Year))
{
var feb = new DateTime(startDate.Year, 2, 29);
if (startDate<=feb && feb<=endDate) den++;
}
else
{
if (DateTime.IsLeapYear(endDate.Year))
{
var feb = new DateTime(endDate.Year, 2, 29);
if (startDate <= feb && feb <= endDate) den++;
}
}
}
}
}
else
{
var nbYears = endDate.Year - startDate.Year+1;
var den = nbYears * 365.0;
for (var i=0;i<nbYears;i++)
{
if (DateTime.IsLeapYear(startDate.Year + i)) den++;
}
den /= nbYears;
return nbDaysInPeriod / den;
}
return nbDaysInPeriod / 365.0;
}
If you want an exact YEARFRAC which measures to the day (so no need to specify any day-count convention) and gives a negative for periods in the past try this date extension...
public static double YearFrac(this DateTime startDate, DateTime endDate)
{
//---------------------------------------------------------------------------
startDate = DateTime.Parse(startDate.ToString("dd-MMM-yyyy"));
endDate = DateTime.Parse(endDate.ToString("dd-MMM-yyyy"));
//---------------------------------------------------------------------------
if (startDate == endDate)
return 0.0;
//---------------------------------------------------------------------------
double reverse = 1.0;
//---------------------------------------------------------------------------
if (startDate > endDate)
{
var ed = endDate;
endDate = startDate;
startDate = ed;
reverse = -1.0;
}
//---------------------------------------------------------------------------
int y1 = startDate.Year;
int y2 = endDate.Year;
int m1 = startDate.Month;
int m2 = endDate.Month;
int d1 = startDate.Day;
int d2 = endDate.Day;
int diy = startDate.DaysInYear();
int days = (endDate - startDate).Days;
//---------------------------------------------------------------------------
if (y1 == y2)
{
return (double)days / (double)diy * reverse;
}
//---------------------------------------------------------------------------
int wholeyears = y2 - y1 - 1;
DateTime lastDateA = ValidDate(y2 - 1, m2, d2);
DateTime lastDateB = ValidDate(y2 - 1, m1, d1);
int period1 = (endDate - lastDateA).Days;
int period2 = (endDate - lastDateB).Days;
//---------------------------------------------------------------------------
if (m1 > m2 || (m1 == m2 && d1 > d2))
{
return ((double)wholeyears + (double)period2 / (double)period1) * reverse;
}
//---------------------------------------------------------------------------
DateTime lastDateC = ValidDate(y2, m1, d1);
int period3 = (endDate - lastDateC).Days;
//---------------------------------------------------------------------------
return ((double)wholeyears + 1.0 + (double)period3 / (double)period1) * reverse;
//---------------------------------------------------------------------------
}
public static DateTime ValidDate(int y, int m, int d)
{
try
{
DateTime dt1 = new DateTime(y, m, d);
return dt1;
}
catch (Exception)
{
try
{
if (d == 29 && m == 2)
{
return new DateTime(y, 3, 1);
}
return new DateTime(y, m, d);
}
catch (Exception)
{
throw;
}
}
}
public static int DaysInYear(this DateTime date)
{
int year = date.Year;
DateTime d1 = DateTime.Parse("01-Jan-" + year.ToString());
DateTime d2 = DateTime.Parse("01-Jan-" + (year + 1).ToString());
int diy = (d2 - d1).Days;
return diy;
}
I am writing an app that requires the calculation of the Gamma function.
A code (part of a class) snippet is below:
namespace PB.Utilities.Math
{
// class definition
public class SpecialFunctions
{
// Private Fields
// Instance Constructor
public SpecialFunctions() {}
// Public Method for Gamma Function
// x = input value; x MUST BE > 0
// GammaLn = secondary output value equal to natural log of Gamma Function
public double Gamma(double x, out double GammaLn)
{
try
{
if (x <= 0) throw new System.ArgumentException("arg <= 0 in GammaFunction", "x");
}
catch
{
System.Console.WriteLine("argument <= 0 in GammaFunction");
System.Console.ReadKey();
}
double gammaln;
double _gamma = gamma(x, out gammaln);
GammaLn = gammaln;
return _gamma;
}
// private method for Gamma Function
private double gamma(double xx, out double gammaln)
{
// private constants
int j;
double x,tmp,y,ser;
const double k1 = 5.24218750000000000;
const double k2 = 0.999999999999997092;
const double k3 = 2.5066282746310005;
double[] cof = new double[14]
{
57.1562356658629235, -59.5979603554754912, 14.1360979747417471,
-0.491913816097620199, 0.339946499848118887e-4, 0.465236289270485756e-4,
-0.983744753048795646e-4, 0.158088703224912494e-3, -0.210264441724104883e-3,
0.217439618115212643e-3, -0.164318106536763890e-3, 0.844182239838527433e-4,
-0.261908384015814087e-4, 0.368991826595316234e-5
};
y = x = xx;
tmp = x + k1;
tmp = (x + 0.5) * System.Math.Log(tmp) - tmp;
ser = k2;
for (j = 0; j < 14; j++) ser += cof[j]/++y;
gammaln = tmp + System.Math.Log(k3*ser/x);
return System.Math.Exp(gammaln);
}
}
}
public class BSA
{
static void Main()
{
// Create an object of type PB.Utilities.Math.SpecialFunctions
PB.Utilities.Math.SpecialFunctions Function = new PB.Utilities.Math.SpecialFunctions();
// Call the public method GammaFunction.
double GammaLn1;
double GammaLn2;
double GammaLn3;
double g1 = Function.Gamma(3.5, out GammaLn1);
double g2 = Function.Gamma(1.5, out GammaLn2);
double g3 = Function.Gamma(1/7, out GammaLn3);
System.Console.WriteLine("g(7/2) = "+g1);
System.Console.WriteLine("g(3/2) = "+g2);
System.Console.WriteLine("g(1/7) = "+g3);
}
}
The issue is that at compilation, the parameter x in Gamma (even though x is being assigned the value 3.5 in the calling component) is assigned a value of 0 which triggers the exception. Can anyone please suggest how I can get around this? Thank you.
Seems to be 3.5 in my test cases. Are you sure you haven't excluded some information that might be the issue?
using System;
namespace Doubletesting
{
class Program
{
static void Main(string[] args)
{
double d = Doubletesting.TestDouble(3.5);
Console.WriteLine(d.ToString());
Console.ReadKey();
}
public static double TestDouble(double x)
{
double result;
result = x;
return result;
}
}
}
Result
3.5
UPDATED
The Error is caused by your Function.Gamma(1 / 7, out GammaLn3). This is because both 1 and 7 are INT and dividing (int)1 by (int)7 is zero. Try Function.Gamma(1f / 7f, out GammaLn3).