commit
message
Simplifying Formulas.ts
author
Ben Vogt <[email protected]>
date
2017-01-15 18:10:11
stats
1 file(s) changed,
0 insertions(+),
200 deletions(-)
files
src/Formulas.ts
1diff --git a/src/Formulas.ts b/src/Formulas.ts
2index 59561de..82a5211 100644
3--- a/src/Formulas.ts
4+++ b/src/Formulas.ts
5@@ -1,5 +1,3 @@
6-/// <reference path="../node_modules/moment/moment.d.ts"/>
7-import * as moment from "moment";
8 import * as Formula from "formulajs"
9 import * as RawFormulas from "./RawFormulas";
10
11@@ -22,209 +20,21 @@ const SUPPORTED_FORMULAS = [
12 'XOR'
13 ];
14
15-const CustomFormulas = {
16- "F.DIST": Formula["FDIST"],
17- "F.INV": Formula["FINV"],
18- ATAN2: function (x, y) {
19- return Math.atan2(y, x);
20- },
21- DATEVALUE: function (dateString: string) : Date {
22- return new Date(dateString);
23- },
24- EDATE: function (start_date: Date, months) {
25- return moment(start_date).add(months, 'months').toDate();
26- },
27- EOMONTH: function (start_date, months) {
28- var edate = moment(start_date).add(months, 'months');
29- return new Date(edate.year(), edate.month(), edate.daysInMonth());
30- },
31- SIN: function (rad) {
32- return rad === Math.PI ? 0 : Math.sin(rad);
33- },
34- TAN: function (rad) {
35- return rad === Math.PI ? 0 : Math.tan(rad);
36- },
37- ACCRINT: function (issue, first, settlement, rate, par, frequency, basis) {
38- // Return error if either date is invalid
39- if (!moment(issue).isValid() || !moment(first).isValid() || !moment(settlement).isValid()) {
40- return '#VALUE!';
41- }
42-
43- // Set default values
44- par = (typeof par === 'undefined') ? 0 : par;
45- basis = (typeof basis === 'undefined') ? 0 : basis;
46-
47- // Return error if either rate or par are lower than or equal to zero
48- if (rate <= 0 || par <= 0) {
49- return '#NUM!';
50- }
51-
52- // Return error if frequency is neither 1, 2, or 4
53- if ([1, 2, 4].indexOf(frequency) === -1) {
54- return '#NUM!';
55- }
56-
57- // Return error if basis is neither 0, 1, 2, 3, or 4
58- if ([0, 1, 2, 3, 4].indexOf(basis) === -1) {
59- return '#NUM!';
60- }
61-
62- // Return error if issue greater than or equal to settlement
63- if (moment(issue).diff(moment(settlement)) >= 0) {
64- return '#NUM!';
65- }
66-
67- // Compute accrued interest
68- var factor : any = 0;
69- switch (basis) {
70- case 0:
71- // US (NASD) 30/360
72- factor = CustomFormulas.YEARFRAC(issue, settlement, basis);
73- break;
74- case 1:
75- // Actual/actual
76- factor = CustomFormulas.YEARFRAC(issue, settlement, basis);
77- break;
78- case 2:
79- // Actual/360
80- factor = CustomFormulas.YEARFRAC(issue, settlement, basis);
81- break;
82- case 3:
83- // Actual/365
84- factor = CustomFormulas.YEARFRAC(issue, settlement, basis);
85- break;
86- case 4:
87- // European 30/360
88- factor = CustomFormulas.YEARFRAC(issue, settlement, basis);
89- break;
90- }
91- return par * rate * factor;
92- },
93- YEARFRAC: function (start_date, end_date, basis) : any {
94- basis = (typeof basis === 'undefined') ? 0 : basis;
95- var sdate = moment(new Date(start_date));
96- var edate = moment(new Date(end_date));
97-
98- // Return error if either date is invalid
99- if (!sdate.isValid() || !edate.isValid()) {
100- return '#VALUE!';
101- }
102-
103- // Return error if basis is neither 0, 1, 2, 3, or 4
104- if ([0, 1, 2, 3, 4].indexOf(basis) === -1) {
105- return '#NUM!';
106- }
107-
108- // Return zero if start_date and end_date are the same
109- if (sdate === edate) {
110- return 0;
111- }
112-
113- // Swap dates if start_date is later than end_date
114- if (sdate.diff(edate) > 0) {
115- edate = moment(new Date(start_date));
116- sdate = moment(new Date(end_date));
117- }
118-
119- // Lookup years, months, and days
120- var syear = sdate.year();
121- var smonth = sdate.month();
122- var sday = sdate.date();
123- var eyear = edate.year();
124- var emonth = edate.month();
125- var eday = edate.date();
126-
127- switch (basis) {
128- case 0:
129- // US (NASD) 30/360
130- // Note: if eday == 31, it stays 31 if sday < 30
131- if (sday === 31 && eday === 31) {
132- sday = 30;
133- eday = 30;
134- } else if (sday === 31) {
135- sday = 30;
136- } else if (sday === 30 && eday === 31) {
137- eday = 30;
138- } else if (smonth === 1 && emonth === 1 && sdate.daysInMonth() === sday && edate.daysInMonth() === eday) {
139- sday = 30;
140- eday = 30;
141- } else if (smonth === 1 && sdate.daysInMonth() === sday) {
142- sday = 30;
143- }
144- return ((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360;
145-
146- case 1:
147- // Actual/actual
148- var feb29Between = function (date1, date2) {
149- // Requires year2 == (year1 + 1) or year2 == year1
150- // Returns TRUE if February 29 is between the two dates (date1 may be February 29), with two possibilities:
151- // year1 is a leap year and date1 <= Februay 29 of year1
152- // year2 is a leap year and date2 > Februay 29 of year2
153-
154- var mar1year1 = moment(new Date(date1.year(), 2, 1));
155- if (moment([date1.year()]).isLeapYear() && date1.diff(mar1year1) < 0 && date2.diff(mar1year1) >= 0) {
156- return true;
157- }
158- var mar1year2 = moment(new Date(date2.year(), 2, 1));
159- if (moment([date2.year()]).isLeapYear() && date2.diff(mar1year2) >= 0 && date1.diff(mar1year2) < 0) {
160- return true;
161- }
162- return false;
163- };
164- var ylength = 365;
165- if (syear === eyear || ((syear + 1) === eyear) && ((smonth > emonth) || ((smonth === emonth) && (sday >= eday)))) {
166- if (syear === eyear && moment([syear]).isLeapYear()) {
167- ylength = 366;
168- } else if (feb29Between(sdate, edate) || (emonth === 1 && eday === 29)) {
169- ylength = 366;
170- }
171- return edate.diff(sdate, 'days') / ylength;
172- } else {
173- var years = (eyear - syear) + 1;
174- var days = moment(new Date(eyear + 1, 0, 1)).diff(moment(new Date(syear, 0, 1)), 'days');
175- var average = days / years;
176- return edate.diff(sdate, 'days') / average;
177- }
178-
179- case 2:
180- // Actual/360
181- return edate.diff(sdate, 'days') / 360;
182-
183- case 3:
184- // Actual/365
185- return edate.diff(sdate, 'days') / 365;
186-
187- case 4:
188- // European 30/360
189- if (sday === 31) {
190- sday = 30;
191- }
192-
193- if (eday === 31) {
194- eday = 30;
195- }
196- // Remarkably, do NOT change February 28 or February 29 at ALL
197- return ((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360;
198- }
199- }
200-};
201-
202 var Formulas = {
203 exists: function(fn: string) {
204- return ((fn in CustomFormulas) || SUPPORTED_FORMULAS.indexOf(fn) > -1 || (fn in RawFormulas));
205+ return (SUPPORTED_FORMULAS.indexOf(fn) > -1 || (fn in RawFormulas) || (fn in RawFormulas.__COMPLEX));
206 },
207 get: function(fn: string) {
208 if (fn in RawFormulas) {
209 return RawFormulas[fn];
210 }
211- if (fn in CustomFormulas) {
212- return CustomFormulas[fn];
213+ if (fn in RawFormulas.__COMPLEX) {
214+ return RawFormulas.__COMPLEX[fn];
215 }
216 return Formula[fn];
217 }
218 };
219
220 export {
221- Formulas,
222- CustomFormulas
223+ Formulas
224 }
225\ No newline at end of file