Package Exports
- portfolio-analytics
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (portfolio-analytics) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
PortfolioAnalytics v0.0.4 (Changelog)
In order to track my personal stock market investments performances, as well as to analyse trading strategies on my blog Le Quant 40, I wanted to use portfolio performances measures computed in JavaScript.
Why in JavaScript ? Because I am a fan of Google Sheets, which is easily extensible thanks to Google Apps Script, a JavaScript-based language.
After several fruitless hours of Googling (incomplete codes, incorrect codes, undocumented codes...), I decided to create my own JavaScript library of such portfolio performances measures, hoping that it could be useful to other people...
Features
- Compatible with Google Sheets
- Compatible with any browser supporting ECMAScript 5 (i.e., front-end development)
- Compatible with Node.js (i.e., back-end development)
- (Performances) Automatically uses JavaScript Typed Arrays
- (Accuracy) Internally uses accurate numerical algorithms (e.g., corrected two pass algorithms for mean, variance, skewness and kurtosis, accurate algorithm for error function...)
- Code continuously tested and integrated by Travis CI
- Code heavily documented using JSDoc
Usage
Usage in Google Sheets
If you would like to use PortfolioAnalytics in Google Sheets, you can either:
- (Recommended) Import the external Google Apps Script library with Script ID 1NXwj16pdgcJT-XG5LiWRJyRW604Dj26U4lqgGsJJfOKLum4y9grakXPI into your spreadsheet script
or:
- Import the JavaScript files from the dist/gs directory into your spreadsheet script
In both cases, providing data to the PortfolioAnalytics functions is then accomplished your preferred way:
- Using a wrapper function in your spreadsheet script, directly accessible from your spreadsheet, to which you can provide a standard data range (A1:A99...), e.g.:
function computeUlcerIndexWrapper(iEquityCurveRange) {
// Convert the input range coming from the spreadsheet into an array
var aInternalArray = [];
for (var i=0; i<iEquityCurveRange.length; ++i) {
aInternalArray.push(iEquityCurveRange[i][0]);
}
// Compute the index
var ulcerIndex = PortfolioAnalytics.ulcerIndex(aInternalArray);
// Return it to the spreadsheet
return ulcerIndex;
}- Using pure Google Apps Script functions - typically the getRange(...) familly of functions -, optimized for speed, e.g.:
function computeUlcerIndex() {
// Adapted from https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangerow-column-numrows
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(1, 1, 100); // A1:A100
var values = range.getValues();
// Convert the above range into an array
var aInternalArray = [];
for (var row in values) {
for (var col in values[row]) {
aInternalArray.push(values[row][col]);
}
}
// Compute the index
var ulcerIndex = PortfolioAnalytics.ulcerIndex(aInternalArray);
// Do something with it (use it in a computation, write it back to the spreadsheet, etc.)
...
}You can find examples of PortfolioAnalytics usage in this spreadsheet.
Usage inside a browser
If you would like to use PortfolioAnalytics inside a browser you can download its source code and/or its minified source code.
You then just need to include this code in an HTML page, e.g.:
<script src="portfolio_analytics.dist.min.js" type="text/javascript"></script>To be noted that if the browser is compatible with JavaScript Typed Arrays, you can provide such arrays in input to PortfolioAnalytics for better performances, e.g.:
PortfolioAnalytics.arithmeticReturns(new Float64Array([100.0, 109.75, 111.25]))
// Will output a Float64ArrayUsage with Node.js
If you would like to use PortfolioAnalytics with Node.js, you simply need to declare it as a dependency of your project
in your package.json file.
Then, this is standard Node.js code, e.g.:
var PortfolioAnalytics = require('portfolio-analytics');
...
var ui = PortfolioAnalytics.ulcerIndex([100, 110, 105, 102, 95]);
// ui == 0.07204222820421435Examples
Drawdowns related measures
PortfolioAnalytics.maxDrawdown([1, 2, 1]);
// The maximum drawdown
PortfolioAnalytics.drawdownFunction([1, 2, 1]);
// The drawdown function
PortfolioAnalytics.topDrawdowns([1, 2, 1], 1);
// The top 'n' drawdowns (second largest drawdown, etc.) with their start/end indexes
PortfolioAnalytics.ulcerIndex([1, 2, 1]);
// The Ulcer Index
PortfolioAnalytics.painIndex([1, 2, 1]);
// The Pain Index, also corresponding to the average of the drawdown function
PortfolioAnalytics.conditionalDrawdown([100, 90, 80], 0.5);
// The conditional drawdownReturns related measures
PortfolioAnalytics.cumulativeReturn([1, 2, 1]);
// The cumulative return from first to last period
PortfolioAnalytics.cagr([1, 2, 1], [new Date("2015-12-31"), new Date("2016-12-31"), new Date("2017-12-31")]);
// The compound annual growth rate (CAGR) from first to last date
PortfolioAnalytics.arithmeticReturns([1, 2, 1]);
// The arithmetic returns for all periods
PortfolioAnalytics.valueAtRisk([1, 2, 1], 0.7);
// The (percent) value at riskSharpe ratio related measures
PortfolioAnalytics.sharpeRatio([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100]);
// The Sharpe ratio
PortfolioAnalytics.biasAdjustedSharpeRatio([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100]);
// The Sharpe ratio adjusted for its bias
PortfolioAnalytics.doubleSharpeRatio([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100]);
// The double Sharpe ratio (i.e., the Sharpe ratio, adjusted for its estimation risk)
PortfolioAnalytics.sharpeRatioConfidenceInterval([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100], 0.05);
// The confidence interval for the Sharpe ratio (here, at 5% significance level)
PortfolioAnalytics.probabilisticSharpeRatio([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100], 0);
// The probabilistic Sharpe ratio (i.e., the probability that the Sharpe ratio is greater
// than a reference Sharpe ratio, here 0)
PortfolioAnalytics.minimumTrackRecordLength([100, 110, 105, 107.5, 115], [100, 100, 100, 100, 100], 0.05, 0);
// The minimum track record length (i.e., the minimal length of the track record of the performance
// to have statistical confidence, here at 95%, that the Sharpe ratio is greater than a reference Sharpe ratio, here 0)Returns to variability related measures
PortfolioAnalytics.gainToPainRatio([1, 2, 1]);
// The gain to pain ratioHow to contribute ?
Fork the projet from Github...
Instal the Grunt dependencies
npm installDevelop...
Compile
- The following command generates the files to be used inside a browser or with Node.js in the
distdirectory:
grunt deliver- The following command generates the files to be used in Google Sheets in the
dist\gsdirectory:
grunt deliver-gsTest
Any of the following two commands run the QUnit unit tests contained in the test directory on the generated file dist\portfolio_analytics.dev.min.js:
npm testgrunt test