wi_xirr 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/wi_xirr/extconf.rb +4 -0
- data/ext/wi_xirr/wi_xirr.c +84 -0
- data/lib/wi_xirr.rb +4 -0
- data/lib/wi_xirr/version.rb +3 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2a708d7a6f079f706dfd6cfee92d5e8cc26f72c68750d0d007230a54de6e84ad
|
4
|
+
data.tar.gz: 8326f713285bcaf625d3f42720c17a6546df93279d9832eb209227cbea240533
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bed4a43e9a742bedba1eff69ba81b5b4e335e285dcd76c3a39ef2b0904d63d76dfbfc80be290d8cbd9d2315ab61297eac822156094291bbf8d9cf99b0cffd990
|
7
|
+
data.tar.gz: 99628d325724ca1e5356afba0891bfa0c474926167a5ee15a9e20191431cbecf0c67378e17571b6317afdc95029c17b01c67682241238d4a18c6bff1c7e89fd0
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# include <math.h>
|
2
|
+
# include <time.h>
|
3
|
+
# include <stdio.h>
|
4
|
+
# include <ruby.h>
|
5
|
+
|
6
|
+
VALUE WiXirr = Qnil;
|
7
|
+
|
8
|
+
void Init_wi_xirr();
|
9
|
+
VALUE calculate(VALUE self, VALUE rb_amounts, VALUE rb_dates, VALUE guess, VALUE maximum_iterations);
|
10
|
+
double get_fx(double x, double amounts[], double investmentPreiods[], int numberOfTransactions);
|
11
|
+
double get_derivative_for_x(double x, double amounts[], double investmentPreiods[], int numberOfTransactions);
|
12
|
+
|
13
|
+
void Init_wi_xirr() {
|
14
|
+
WiXirr = rb_const_get(rb_cObject, rb_intern("WiXirr"));
|
15
|
+
rb_define_module_function(WiXirr, "calculate", calculate, 4);
|
16
|
+
}
|
17
|
+
|
18
|
+
VALUE calculate(VALUE self, VALUE rb_amounts, VALUE rb_dates, VALUE guess, VALUE maximum_iterations) {
|
19
|
+
// Fixed variables
|
20
|
+
int max_iterations = NUM2INT(maximum_iterations);
|
21
|
+
int length = (int)RARRAY_LEN(rb_amounts);
|
22
|
+
double delta = 1E-8;
|
23
|
+
double investment_periods[length], amounts[length], dates[length];
|
24
|
+
double min_date = 34028235E38;
|
25
|
+
// Find min and max date and initialize c arrays
|
26
|
+
for(int i = 0; i < length; i++) {
|
27
|
+
amounts[i] = NUM2DBL(rb_ary_entry(rb_amounts, i));
|
28
|
+
// Dates is the array containing the number of days since epoch
|
29
|
+
dates[i] = floor(NUM2DBL(rb_ary_entry(rb_dates, i)) / 86400);
|
30
|
+
if (dates[i] < min_date)
|
31
|
+
min_date = dates[i];
|
32
|
+
}
|
33
|
+
// Find investment_periods
|
34
|
+
for(int i = 0; i < length; i++)
|
35
|
+
investment_periods[i] = (dates[i] - min_date);
|
36
|
+
|
37
|
+
// Solving for 0 npv by Newton's Method
|
38
|
+
double init_guess = NUM2DBL(guess);
|
39
|
+
double irr = init_guess, delta_x = 0.0;
|
40
|
+
int number_of_iterations = 0;
|
41
|
+
do {
|
42
|
+
irr -= delta_x;
|
43
|
+
if (irr == -1.0) {
|
44
|
+
break;
|
45
|
+
}
|
46
|
+
double fx = get_fx(irr, amounts, investment_periods, length);
|
47
|
+
double derivative_at_x = get_derivative_for_x(irr, amounts, investment_periods, length);
|
48
|
+
if (derivative_at_x == 0.0) {
|
49
|
+
irr = -1;
|
50
|
+
break;
|
51
|
+
}
|
52
|
+
delta_x = fx / derivative_at_x;
|
53
|
+
number_of_iterations += 1;
|
54
|
+
} while((fabs(delta_x) > delta) && (number_of_iterations < max_iterations));
|
55
|
+
if (number_of_iterations >= max_iterations) {
|
56
|
+
irr = -1;
|
57
|
+
}
|
58
|
+
return DBL2NUM(pow(1 + irr, 365) - 1);
|
59
|
+
}
|
60
|
+
|
61
|
+
double get_fx(double x, double amounts[], double investmentPreiods[], int numberOfTransactions) {
|
62
|
+
double fx = 0.0;
|
63
|
+
for(int i = 0; i < numberOfTransactions; i++)
|
64
|
+
fx += (amounts[i] / pow(1 + x, investmentPreiods[i]));
|
65
|
+
return fx;
|
66
|
+
}
|
67
|
+
|
68
|
+
double get_derivative_for_x(double x, double amounts[], double investmentPreiods[], int numberOfTransactions) {
|
69
|
+
double f_dash_x = 0.0;
|
70
|
+
for(int i = 0; i < numberOfTransactions; i++)
|
71
|
+
f_dash_x += (amounts[i] * investmentPreiods[i]) / pow(1 + x, investmentPreiods[i]);
|
72
|
+
return -f_dash_x;
|
73
|
+
}
|
74
|
+
|
75
|
+
// Solving for 0 npv by bisection method
|
76
|
+
// double left_guess = -49.99/365.0, right_guess = 49.99/365.0;
|
77
|
+
// while((right_guess - left_guess) > (2 * delta)) {
|
78
|
+
// double mid = (right_guess + left_guess) / 2;
|
79
|
+
// if (get_fx(left_guess, amounts, investment_periods, length) * get_fx(mid, amounts, investment_periods, length) > 0)
|
80
|
+
// left_guess = mid;
|
81
|
+
// else
|
82
|
+
// right_guess = mid;
|
83
|
+
// }
|
84
|
+
// double irr = (left_guess + right_guess) / 2.0;
|
data/lib/wi_xirr.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wi_xirr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mahadevan K, Shaunak Dey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Fast Newtonian method XIRR calculator for Ruby, matches Excel implementation
|
56
|
+
of XIRR formula
|
57
|
+
email:
|
58
|
+
executables: []
|
59
|
+
extensions:
|
60
|
+
- ext/wi_xirr/extconf.rb
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ext/wi_xirr/extconf.rb
|
64
|
+
- ext/wi_xirr/wi_xirr.c
|
65
|
+
- lib/wi_xirr.rb
|
66
|
+
- lib/wi_xirr/version.rb
|
67
|
+
homepage: https://github.com/planarinvestments/wi_xirr
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.1.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Fast Newtonian method XIRR calculator for Ruby
|
90
|
+
test_files: []
|