A Node.js module that helps with calculations concerning stocks and portfolios.
Financier is a simple, object-oriented way of managing a portfolio. Please feel free to request any features. Code contributions are always welcome!
$ npm install financier
Financier uses the Sylvester matrix math library for calculations. NPM will automatically install Sylvester as a dependency.
var financier = require('financier');
var Stock = financier.Stock;
var Portfolio = financier.Portfolio;
Here is an example featuring comprehensive usage of Financier.
// Load financier.
var financier = require('financier');
var Stock = financier.Stock;
var Portfolio = financier.Portfolio;
var stocks = {};
// A bit of pseudo-code to load return data from a CSV.
var stockData = CSV.load('nasdaq-historical-returns.csv');
// Initialize the stocks.
for (var stock in stockData) {
stocks[stock] = new Stock(stock);
for (var tick in stockData[stock]) {
stocks[stock].push(tick.open, tick.close, true);
}
stocks[stock].calculateAverage();
}
// Gather the securities for the portfolio.
var securities = [
{
stock: stocks.AAPL,
value: 10234.34
},
{
stock: stocks.GOOG,
value: 63464.53
},
{
stock: stocks.MSFT,
value: 4352.2
},
{
stock: stocks.AIG,
value: 630.99,
},
{
stock: stocks.C,
value: 902.11
}
];
// Build the portfolio.
var clientPortfolio = new Portfolio();
for (var i = 0; i < securities.length; i++) {
var security = securities[i];
clientPortfolio.addStock(security.stock, security.value, true);
}
// Spit out the risk.
console.log(clientPortfolio.calculateRisk());
Used to calculate returns and averages for individual stocks. The parameter
ticker
determines the stock symbol for the stock.
var AAPL = new Stock('AAPL');
- ticker -
String
The stock symbol. - returns -
Array
The array of tick returns for the stock. - average -
Float
The average of all the tick returns. - value -
Float
The market value of the stock. (Initialized when added to a portfolio.) - weight -
Float
The weight of the stock in comparison to the total portfolio market value. (Initialized when added to a portfolio.)
Add a tick of data to the stock history. This new return is stored in
Stock.returns
. Default behaviour immediately recalculates the overall average on
returns.
The parameters open
and close
are floats
representing the price of the stock.
If wait
is true
, the average is not calculated.
// Push a return of 5.8 to the list of returns. The overall average return will
// be automagically calculated.
AAPL.push(106.5, 112.3);
Calculate the average of all the returns. This new average is both returned and
stored in Stock.average
.
It is only necessary to call this function if you are adding returns in bulk.
function randomValue() {
return 100 + Math.random() * 30;
}
// Simulate adding thousands of returns to a stock.
for (var i = 0; i < 10000; i++) {
// Push the data, but hold off on calculating the average.
AAPL.push(randomValue(), randomValue(), true);
}
// Now calculate the overall average.
AAPL.calculateAverage();
Keeps data on a portfolio, and has methods to calculate its attributes.
var clientPortfolio = new Portfolio();
- stocks -
Object
Stocks included in the portfolio. - value -
Float
Total market value for the stock. - risk -
Float
Risk for the entire portfolio. - cache -
Cache
Cache of portfolio securities.
Add a stock to the portfolio. This stock is stored in the Portfolio.stocks
.
Stock.weight
for all securities are automagically recalculated.
The parameter stock
is the Stock
object being added. value
represents the
market value for the security as a float
. Currency should be kept consistent.
If clone
is true
, a new Stock
is created with identical Stock.ticker
,
Stock.return
, and Stock.average
properties.
IMPORTANT: If stocks are reused in multiple portfolios, or need to be kept independent of the portfolio, they MUST be cloned to prevent discrepencies with how JavaScript passes objects by reference.
// Add AAPL to multiple client portfolios:
clientPortfolio.addStock(AAPL, 100323.33, true);
otherClientPortfolio.addStock(AAPL, 1483.63, true);
var open = 135.3;
var close = 123.53;
// If new return history needs to be added, it must be done individually.
AAPL.push(open, close);
clientPortfolio.stocks.AAPL.push(open, close);
otherClientPortfolio.stocks.AAPL.push(open, close);
Remove a stock from the portfolio. Portfolio.stocks
is updated. Additionally,
Stock.weight
for all stocks are recalculated.
// Both of these are valid:
clientPortfolio.removeStock('AAPL');
clientPortfolio.removeStock(AAPL);
Update a stock with a new market value. Weights for all the stocks are recalculated. However, the new value is not validated. Stocks are not deleted if the value is 0 or negative.
Get the tickers for all the stocks in the portfolio.
Checks if the stock is currently in the portfolio.
Calculate the total market value of the portfolio. Portfolio.value
is updated, as
well as returned. This function is called everytime Portfolio.calculateWeights()
is called.
Calculate and update Stock.weight
for all securities in the portfolio. This
function is called whenever securities in the portfolio are altered.
Calculate the covariance between two stocks. If stockA
and stockB
are the same
instance of Stock
the function returns 1 by definition.
While it is better to create a Portfolio
to calculate covariance, this function can
be called to examine individual stocks.
var GOOG = new Stock('GOOG');
var AAPL = new Stock('AAPL');
// Pretend that we have filled out the stocks with tick history...
GOOG.push(...);
AAPL.push(...);
// Find the covariance between Google and Apple.
var covariance = Portfolio.calculateCovariance(GOOG, AAPL);
Create the matrix of security weights. We do not use Sylvestor.Vector
because it does
not have a transpose method. Portfolio.calculateRisk()
calls this function.
Create the covariance matrix of all securities. Portfolio.caulcateCovariance()
is called
for every possible pair of securities. Portfolio.calculateRisk()
calls this function.
Calculate risk for the entire portfolio. We first check against Portfolio.cache
to prevent any
unnecessary work (i.e. securities have not been altered since last time the risk was calculated).
Portfolio.cache
and Portfolio.risk
are then updated.