UNPKG

cfs.js

Version:
646 lines (405 loc) 12.5 kB
/*jshint esversion: 6 */ const cfa = { }; // 0 HELPER FUNCTIONS // 0.0001 Yield cfa.yield = (a,b) => { return b/a - 1; }; // 0.1 Average - average(array) cfa.average = (array) =>{ let sum = 0; array.forEach(element => { sum +=element; }); return sum/array.length; }; // 0.2 Array parse to float cfa.float_array = array => { return array.map(element => { return parseFloat(element); }); }; // 0.3 Sum of array cfa.sum = array => { const reducer = (accumulator, current) =>{ return (accumulator + current); }; return array.reduce(reducer, 0); }; // 0.4 Sort array descending cfa.sort_desc = (array) => { let array_copy = array.slice() return array_copy.sort((a,b) => { return b-a; }); }; // 0.5 Extent cfa.extent = (array) => { let array_sorted = cfa.sort_desc(array); return { min: array_sorted[array_sorted.length-1], max: array_sorted[0] }; }; // 0.5.1 MAX cfa.max = (array) => { return cfa.extent(array).max } // 0.5.2 MIN cfa.min = (array) => { return cfa.extent(array).min } // 0.6 Range cfa.range = (array) => { return cfa.extent(array).max - cfa.extent(array).min; }; // 0.7 k days yield array cfa.yield_array = (array, days) => { let yield_arr = new Array(); for (let i=0; i<array.length-days; i++) { yield_arr[i] = array[i+days]/array[i]-1; } return yield_arr; } // 0.8 Rolling function with callback cfa.rolling = (array, days, callback) =>{ let output = new Array(); for (let i=0; i<array.length-days; i++) { output[i] = callback(array[i], array[i+days]); } return output; } // factorial cfa.factorial = function(num) { if (num < 0) { return -1 } if (num == 0) { return 1 } else { return num * cfa.factorial(num-1) } } // 1. TIME VALUE OF MONEY FUNCTIONS // 1.1 Future value cfa.fv = (pv, r, n, m) => { if (r>1) console.log('Are you sure that the r is sooo high?'); return (pv*Math.pow((1+r/m), n*m)); }; // 1.2 Present value cfa.pv = (fv,r,n,m) => { if (r>1) console.log('Are you sure that the r is sooo high?'); return (fv/Math.pow((1+r/m), n*m)); }; // 1.3 Continous compounding cfa.fv_continous = (pv, r, n) => { if (r>1) console.log('Are you sure that the r is sooo high?') return (pv * Math.pow(Math.E, r*n)); } // CAGR - compounded annual growth rate cfa.cagr = (ending, start, years) => { return Math.pow(ending/start, 1/years) - 1 } // 1.4 Effective Annual Rate cfa.ear = (r,m) => { if (r>1) console.log('Are you sure that the r is sooo high?') return Math.pow(1+(r/m), m)-1 } // 1.5 Continous Effective Annual Rate cfa.ear_continous = (r) => { if (r>1) console.log('Are you sure that the r is sooo high?') return Math.pow(Math.E, r)-1 } // 1.6 Future Value of Ordinary Annuity cfa.fv_annuity_ordinary = (a,r,n) => { if (r>1) console.log('Are you sure that the r is sooo high?') return a*(Math.pow(1+r, n)-1)/r } // 1.7 Present Value of Ordinary Annuity page 319 cfa.pv_annuity_ordinary = (a,r,n) => { if (r>1) console.log('Are you sure that the r is sooo high?') return a/r * (1-Math.pow(1+r, -n)) } // 1.8 Future Value of Unequal Cash Flows cfa.fv_unequal_cf = (array, r) => { for (let i=0; i<array.length; i++) { array[i] = array[i] * Math.pow(1+r, array.length-i-1) } return cfa.sum(array) } // 1.9 Present Value of Unequal Cash Flows cfa.pv_unequal_cf = (array, r) => { for (let i=0; i<array.length; i++) { array[i] = array[i] * Math.pow(1+r, i*(-1)-1) } return cfa.sum(array) } // 1.10 Present Value of Perpetuity cfa.pv_perpetuity = (a, r) => { return a/r } // 1.11 Net Present Value cfa.npv = (array, r) => { for (let i=0; i<array.length; i++) { array[i] = array[i]/Math.pow(1+r, i) } return cfa.sum(array) } cfa.irr = (array) => { function guessRate(array, r) { let discountArray = [] let preSumArray = [] array.forEach((element, index) => { let discountFactor = (1 + (r/100))**index let discountedEl = element/discountFactor discountArray.push({index, discountFactor, discountedEl}) preSumArray.push(discountedEl) }) let sum = cfa.sum(preSumArray) return sum } let irrArray = [] for (let i = 0; i < 100; i = i+0.01) { let rate = i let NPV = guessRate(array, rate) irrArray.push({rate, NPV}) } irrArray = irrArray.filter(element => element.NPV>0) irrArray.sort((a,b) => a.NPV - b.NPV) return irrArray[0] } // 1.14 Median cfa.median = (array) => { if (array.length%2 != 0) { return cfa.sort_desc(array)[Math.floor(array.length/2)] } return (cfa.sort_desc(array)[Math.floor(array.length/2)]+ cfa.sort_desc(array)[Math.floor(array.length/2)-1])/2 } // 1.15 Mode - Single modality so far cfa.mode = (array) => { const element_list = new Set(array); const mode_list = {}; element_list.forEach(e => { mode_list[e] = 0; }); array.forEach(e => { mode_list[e] +=1 }); let max = 0; let max_key; for (i in mode_list) { if (mode_list[i] > max) { max = mode_list[i]; max_key = i; } } let object ={}; object[max_key] = max; return object; } // 1.16 Weighted Mean cfa.weighted_mean = (array) => { let sum = 0; array.forEach(element => { sum += parseFloat(Object.keys(element))*parseFloat(Object.values(element)) }); return sum; } // 1.17 Geometric Mean cfa.geometric_mean = (array) => { let product = array.reduce((a,b) => { return a*b }); return Math.pow(product, 1/array.length); } // 1.18 Harmonic Mean cfa.harmonic_mean = (array) => { let denominator = cfa.sum(array.map(e => { return 1/e })); return array.length/denominator; } // 2. CFA FUNCTIONS // 2.1 Covariance cfa.covariance = (array_X, array_Y) => { if (array_X.length != array_Y.length) { throw 'Arrays have to be the same length'; } let upper = 0; for (let i=0; i < array_X.length; i++) { upper += (array_X[i] - cfa.average(array_X)) * (array_Y[i] - cfa.average(array_Y)); } return(upper/(array_X.length-1)); }; // 2.2 Sample variance cfa.sample_variance = array => { let upper = 0; array.forEach(element => { upper += Math.pow(parseFloat(element) - cfa.average(array), 2); }); return (upper/(array.length-1)); }; // 2.2 Sample standard deviation cfa.standard_deviation = array => { return Math.sqrt(cfa.sample_variance(array)); }; // 2.3 Sample correlation cfa.sample_correlation = (array_X, array_Y) => { if (array_X.length != array_Y.length) { throw 'Arrays have to be the same length'; } return cfa.covariance(array_X, array_Y)/(cfa.standard_deviation(array_X) * cfa.standard_deviation(array_Y)); }; // 2.4 Significance of correlation coefficient cfa.corr_significance = (array_X, array_Y) => { if (array_X.length != array_Y.length) { throw 'Arrays have to be the same length'; } return (cfa.sample_correlation(array_X, array_Y) * Math.sqrt(array_X.length - 2)/Math.sqrt(1 - Math.pow(cfa.sample_correlation(array_X, array_Y),2))); }; // 2.6 Mean Absolute Deviation cfa.mad = (array) => { let average = cfa.average(array); let sum = 0; for (let i=0; i<array.length; i++) { sum = sum + Math.abs(array[i] - average); } return sum/array.length; }; // 2.7 Semivariance cfa.semivariance = (array) => { let average = cfa.average(array); let non_negative = array.filter(e => e<0); let sum = 0; for (let i=0; i<non_negative.length; i++) { sum += Math.pow((non_negative[i] - average), 2); } return sum/(array.length-1); }; // 2.8 Semideviation cfa.semideviation = (array) => { return Math.pow(cfa.semivariance(array), 0.5); }; // 2.9 Target semivariance cfa.target_semivariance = (array, target) => { let below_target = array.filter(e => e<target); let sum = 0; for (let i=0; i<below_target.length; i++) { sum += Math.pow((below_target[i] - target), 2) } return sum/(array.length-1); }; // 2.10 Target Semideviation cfa.target_semideviation = (array, target) => { return Math.pow(cfa.target_semivariance(array, target), 0.5); }; // 2.11 Coefficient of variation cfa.cv = (array) => { return cfa.standard_deviation(array)/cfa.average(array); }; // 2.12 Sharpe Ratio cfa.sharpe = (array_portfolio, array_rf) => { return (cfa.average(array_portfolio) - cfa.average(array_rf))/cfa.standard_deviation(array_portfolio); }; // 2.13 Sample Skewness cfa.sample_skewness = (array) => { return array.length/((array.length-1)*(array.length-2))*cfa.sum(array.map(e => {return Math.pow(e - cfa.average(array), 3)})) / Math.pow(cfa.standard_deviation(array), 3); } // 2.14 Sample Kurtosis cfa.sample_kurtosis = (array) => { return array.length*(array.length+1)/(array.length-1)/(array.length-2)/(array.length-3)*cfa.sum(array.map(e => {return Math.pow(e-cfa.average(array), 4)}))/Math.pow(cfa.standard_deviation(array), 4) - 3*Math.pow(array.length-1, 2)/(array.length-2)/(array.length-3) }; // 3 Probabililty // 3.1 Covariance Matrix - takes array of arrays cfa.covariance_matrix = (array) => { let matrix = new Array(); for (let g=0; g<array.length; g++) { matrix.push([]) } for (let i=0; i<array.length; i ++) { for (let j=0; j<array.length; j++) { matrix[i][j] = cfa.covariance(array[i], array[j]) } } return matrix } // 3.2 Correlation Matrix - takes array of arrays cfa.correlation_matrix = (array) => { let matrix = new Array(); for (let g=0; g<array.length; g++) { matrix.push([]) } for (let i=0; i<array.length; i ++) { for (let j=0; j<array.length; j++) { matrix[i][j] = cfa.sample_correlation(array[i], array[j]) } } return matrix } cfa.callOption = (vol, price, strike, time, rate, dividend) => { let dOne = (vol, price, strike, time, rate, dividend) => { let numerator = Math.log(price/strike) + ((rate - dividend + ((vol**2)/2) ) * time) let denominator = vol*(time**0.5) return numerator/denominator } let dTwo = (vol, price, strike, time, rate, dividend) => { let numerator = Math.log(price/strike) + ((rate - dividend - ((vol**2)/2) ) * time) let denominator = vol*(time**0.5) return numerator/denominator } let left = price * Math.exp(-dividend*time) * cfa.normalCdf(dOne(vol, price, strike, time, rate, dividend)) let right = strike * Math.exp(-rate*time) * cfa.normalCdf(dTwo(vol, price, strike, time, rate, dividend)) let callValue = left - right let d1 = dOne(vol, price, strike, time, rate, dividend) let d2 = dTwo(vol, price, strike, time, rate, dividend) let Nd1 = cfa.normalCdf(d1) let Nd2 = cfa.normalCdf(d2) return {d1, d2, Nd1, Nd2, callValue } } cfa.normal= function(X){ //CDF - HASTINGS. MAX ERROR = .000001 let T=1/(1+.2316419*Math.abs(X)); let D=.3989423*Math.exp(-X*X/2); let Prob=D*T*(.3193815+T*(-.3565638+T*(1.781478+T*(-1.821256+T*1.330274)))); if (X>0) { Prob=1-Prob } let CDF = Prob let pdfNum = Math.exp(X**2 / (-2)) let pdfDen = Math.pow(2*Math.PI, 1/2) let pdf = pdfNum/pdfDen let mean = 0 let variance = 1 return {pdf, CDF, mean, variance} } cfa.nCk = function(n,k) { let numerator = cfa.factorial(n) let denominator = cfa.factorial(k) * cfa.factorial(n - k) return numerator/denominator } cfa.binomial = function(n,x,p) { function binomialPdf(n,x,p) { return cfa.nCk(n,x) * (p**x) * (1-p)**(n-x) } let pdf = binomialPdf(n,x,p) let CDF = 0 for (let i = 0; i < x+1; i++) { CDF = CDF + binomialPdf(n,i,p) } let mean = n * p let variance = mean * (1 - p) return {pdf, CDF, mean, variance} } // cfa.binomialPdf = function(n,x,p) { // return cfa.nCk(n,x) * (p**x) * (1-p)**(n-x) // } // cfa.binomialCDF = function(n,x,p) { // let sum = 0 // for (let i = 0; i < x+1; i++) { // sum = sum + cfa.binomialPdf(n,i,p) // } // return sum // } module.exports = cfa;