accountant
Advanced tools
Comparing version
@@ -10,3 +10,4 @@ /** | ||
, _ = require('underscore') | ||
, request = require('request') | ||
var reports = [] | ||
@@ -51,2 +52,3 @@ | ||
s.industry = s.industry || buy.industry | ||
s.asset_class = s.asset_class || buy.asset_class | ||
@@ -80,6 +82,12 @@ s.chunks = s.chunks || [] | ||
var s = stocks[div.symbol] | ||
, bank = banks[div.account] || {} | ||
, net = bank.positions[div.symbol] * div.amount | ||
, bank = banks[div.account] || {} | ||
, net | ||
if (div.amount){ | ||
net = bank.positions[div.symbol] * div.amount | ||
} else { | ||
net = div.gross | ||
} | ||
s.dividend += net | ||
banks[div.account] = banks[div.account] || {} | ||
@@ -165,4 +173,23 @@ banks[div.account].balance += net | ||
exports.$ = function(v, curr){ | ||
var val = parseInt(v*100)/100 | ||
, dol = parseInt(val) | ||
, cen = exports.pad(Math.round((v % 1) * 100), 2, '0') | ||
, dols = (dol + '').replace(/(\d)(?=(\d\d\d)+$)/, "$1,") | ||
, str = (curr || "$") + dols + "." + cen | ||
str = (val>=0) ? str.green : str.red | ||
return str | ||
} | ||
// Round to 2 decimal places | ||
exports.r2 = function(v){ | ||
if (v == 0){ | ||
return '0' | ||
} | ||
var w = parseInt(v) | ||
, f = exports.pad(Math.abs(parseInt((v % 1) * 100)), 2, '0') | ||
return ((v<0 && w == 0) ? '-' : '') + w + '.' + f | ||
} | ||
exports.pad = function(v, len, ch){ | ||
@@ -186,2 +213,22 @@ var val = v + '' | ||
return stock.quantity * stock.current + stock.dividend - stock.cost_basis | ||
} | ||
} | ||
var FINANCE_URL ='http://www.google.com/finance/info?client=ig&q=' | ||
exports.loadPrices = function(stocks, cb){ | ||
request.get({uri:FINANCE_URL + _(stocks).keys().join(',')}, function(err, resp, body){ | ||
if (!body) throw "Could not get data from API" | ||
var finances = JSON.parse(body.slice(3)) | ||
_.each(finances, function(v, k){ | ||
stocks[v.t].current = v.l_cur | ||
stocks[v.t].change = v.c | ||
stocks[v.t].change_percent = v.cp | ||
}) | ||
cb(stocks) | ||
}) | ||
} | ||
@@ -16,6 +16,6 @@ // This is an accounts.json file - it's just json but you can use comments | ||
// You can also record stocks and ETFs: | ||
, {"date" : "2012-01-04", "typ" : "stock-buy", "symbol" : "MCD", "quantity" : 10, "cost" : 95.94, "commission" : 10, "acct" : "mybank"} | ||
, {"date" : "2012-01-04", "typ" : "etf-buy", "symbol" : "BND", "quantity" : 10, "cost" : 83.73, "commission" : 10, "acct" : "mybank"} | ||
, {"date" : "2012-01-04", "typ" : "stock-buy", "symbol" : "MCD", "quantity" : 10, "cost" : 95.94, "commission" : 10, "acct" : "mybank", "asset_class" : "US Stock"} | ||
, {"date" : "2012-01-04", "typ" : "etf-buy", "symbol" : "BND", "quantity" : 10, "cost" : 83.73, "commission" : 10, "acct" : "mybank", "asset_class" : "Bonds"} | ||
] |
@@ -5,3 +5,3 @@ { | ||
"description": "Double Entry Accounting", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"repository": { | ||
@@ -30,2 +30,4 @@ "url": "" | ||
, "acct-stock" : "./scripts/daily-stock.js" | ||
, "acct-compound" : "./scripts/compound.js" | ||
, "acct-mix" : "./scripts/mix.js" | ||
} | ||
@@ -32,0 +34,0 @@ |
@@ -16,16 +16,16 @@ var request = require('request') | ||
var COLS = { | ||
symbol : {title : "Symbol", ind : 0} | ||
, price : {title : "Price", ind : 1} | ||
, chg : {title : "Δ", ind : 2, desc : "Daily change (price)"} | ||
, chg_p : {title: "Δ%", ind: 3, desc : "Daily change (%)"} | ||
, d_gain : {title: "$Δ", ind: 4, desc : "Day gain (price)"} | ||
, num : {title: "#", ind : 5, desc : "No. Shares owned"} | ||
, age : {title: ">age", ind : 6 , desc: "Age of oldest shares (days)"} | ||
, cb : {title: "Cst Bas.", ind: 7, desc: "Cost basis"} | ||
, mkt : {title: "Mkt Value", ind : 8, desc : "Market value of owned"} | ||
, div : {title: "Div.", ind: 9, desc :"Dividends Paid"} | ||
, gain : {title: "Gain", ind : 10, desc: "Overall gain (price)"} | ||
, sec: {title: "30d%", ind : 11, desc: "30 Day Yield (%)"} | ||
, growth: {title: "Growth", ind : 12, desc: "Growth % (no dividends)"} | ||
, ret: {title: "Return", ind : 13, desc: "Overall return (%)"} | ||
symbol : {title : "Sym", desc: "Symbol", ind : 0} | ||
, price : {title : "Price", ind : 1, align:'right'} | ||
, chg : {title : "Δ", ind : 2, desc : "Daily change (price)", align:'right'} | ||
, chg_p : {title: "Δ%", ind: 3, desc : "Daily change (%)", align:'right'} | ||
, d_gain : {title: "$Δ", ind: 4, desc : "Day gain (price)", align:'right'} | ||
, num : {title: "#", ind : 5, desc : "No. Shares owned", align:'right'} | ||
, age : {title: ">age", ind : 6 , desc: "Age of oldest shares (days)", align:'right'} | ||
, cb : {title: "Cst Bas.", ind: 7, desc: "Cost basis", align:'right'} | ||
, mkt : {title: "Mkt Value", ind : 8, desc : "Market value of owned", align:'right'} | ||
, div : {title: "Div.", ind: 9, desc :"Dividends Paid", align:'right'} | ||
, gain : {title: "Gain", ind : 10, desc: "Overall gain (price)", align:'right'} | ||
, sec: {title: "30d%", ind : 11, desc: "30 Day Yield (%)", align:'right'} | ||
, growth: {title: "Growth", ind : 12, desc: "Growth % (no dividends)", align:'right'} | ||
, ret: {title: "Return", ind : 13, desc: "Overall return (%)", align:'right'} | ||
} | ||
@@ -37,21 +37,7 @@ | ||
onComplete: function(banks, stocks){ | ||
// current values | ||
ac.loadPrices(stocks, function(st){ | ||
render(banks, st, opts) | ||
}) | ||
request.get({uri:FINANCE_URL + _(stocks).keys().join(',')}, function(err, resp, body){ | ||
if (!body) throw "Could not get data from API" | ||
var finances = JSON.parse(body.slice(3)) | ||
_.each(finances, function(v, k){ | ||
stocks[v.t].current = v.l_cur | ||
stocks[v.t].change = v.c | ||
stocks[v.t].change_percent = v.cp | ||
//console.log(v.t, v) | ||
}) | ||
render(banks, stocks, opts) | ||
}) | ||
} | ||
@@ -70,3 +56,3 @@ } | ||
var c = function(v, pre, post){ | ||
var val = '' + parseInt(v*100)/100 | ||
var val = '' + ac.r2(v) | ||
, str = (pre || '') + val + (post || '') | ||
@@ -86,3 +72,3 @@ | ||
if (opts.color != false) | ||
str = (val>=0) ? str.green : ((val <= bord) ? str.red : str.yellow) | ||
str = (val>=0) ? ((val>= -bord) ? str.blue : str.green) : ((val <= bord) ? str.red : str.yellow) | ||
@@ -95,5 +81,6 @@ return str | ||
head : _.map(COLS, function(v, k){return v.title}) | ||
, style : {compact: true, 'padding-left':1, head: ['cyan']} | ||
, style : {compact: true, 'padding-left':1, 'padding-right':1 , head: ['cyan']} | ||
, colAligns: _.map(COLS, function(v, k){return v.align || 'left'}) | ||
}) | ||
var MKT_RET = _.find(stocks, function(v,k){ | ||
@@ -131,3 +118,3 @@ return (k =='VTI')} )|| {quantity : 1, current : 0, dividend : 0, cost_basis: 0} | ||
, num: c(v.quantity) | ||
, age: v.chunks && ((age + '')[(age < 360) ? 'yellow' : 'green']) || '' | ||
, age: v.chunks && ((age + '')[(age < 365) ? 'yellow' : 'green']) || '' | ||
, cb: c(v.cost_basis) | ||
@@ -134,0 +121,0 @@ , mkt: c(v.quantity * v.current) |
@@ -8,4 +8,6 @@ var Table = require('cli-table') | ||
, cbval : {title : "CB Val", ind : 1} | ||
, cbprop: {title : "CB % Equity", ind: 2} | ||
, val : {title: "Curr Val", ind: 2} | ||
//, cbprop: {title : "CB % Equity", ind: 2} | ||
, cbpropnet: {title : "CB % Net", ind: 3} | ||
, valpropnet: {title : "Val % Net", ind: 4} | ||
} | ||
@@ -16,4 +18,3 @@ | ||
onComplete: function(banks, stocks){ | ||
var cols = ["Asset", "CB Val"] | ||
ac.loadPrices(stocks, function(stocks){ | ||
@@ -30,2 +31,3 @@ var t = new Table({ | ||
, cash = 0 | ||
, total_worth = 0 | ||
@@ -37,2 +39,3 @@ _.each(banks, function(b, k){ | ||
net_worth += b.balance | ||
total_worth += b.balance | ||
}) | ||
@@ -42,3 +45,5 @@ | ||
symbol: "Cash".yellow | ||
, current: 1 | ||
, cost_basis: cash | ||
, quantity: cash | ||
}) | ||
@@ -52,2 +57,3 @@ | ||
net_equity += s.cost_basis | ||
total_worth += s.current * s.quantity | ||
@@ -57,3 +63,3 @@ }) | ||
assets.sort(function(a, b){ | ||
return b.cost_basis - a.cost_basis | ||
return (b.current*b.quantity) - (a.current*a.quantity) | ||
}) | ||
@@ -64,4 +70,7 @@ | ||
, ac.c(x.cost_basis) | ||
, x.equity ? ac.c(x.cost_basis/net_equity*100) : '-' | ||
, ac.c(x.cost_basis/net_worth*100)]) | ||
//, x.equity ? ac.c(x.cost_basis/net_equity*100) : '-' | ||
, ac.c(x.current * x.quantity) | ||
, ac.c(x.cost_basis/net_worth*100) | ||
, ac.c(x.current*x.quantity/total_worth*100) | ||
]) | ||
}) | ||
@@ -71,4 +80,5 @@ | ||
}) | ||
} | ||
} | ||
} |
@@ -20,8 +20,13 @@ var ac = require('../accountant') | ||
, onDividend : function(acct, banks, stocks){ | ||
var s = stocks[acct.symbol] | ||
var s = stocks[acct.symbol] | ||
, positions = banks[acct.account].positions | ||
, net = parseInt(positions[acct.symbol] * acct.amount * 100) / 100 | ||
, net = parseInt(positions[acct.symbol] * acct.amount * 100) / 100 | ||
if (SHOW_DIVIDENDS) | ||
if (acct.gross){ | ||
acct.amount = parseInt(acct.gross/s.quantity * 100)/100 | ||
net = acct.gross | ||
} | ||
if (SHOW_DIVIDENDS){ | ||
console.log(ac.pad(acct.symbol, 5), "Div".blue, acct.date, s.quantity, acct.amount, ": $", net) | ||
} | ||
} | ||
@@ -28,0 +33,0 @@ |
@@ -7,3 +7,4 @@ var request = require('request') | ||
, c = ac.c | ||
, $$ = ac.$ | ||
var EXCHANGE_RATES = { | ||
@@ -26,4 +27,5 @@ USD : 1 // To USD | ||
return; | ||
var dollar_balance = v.balance | ||
var age = parseInt((new Date().getTime() - new Date(v.last_statement).getTime())/(1000*3600*24)) | ||
, dollar_balance = v.balance | ||
, liquid = v.balance | ||
@@ -41,2 +43,8 @@ | ||
if (age > 60){ | ||
k = k.red | ||
} else if (age > 30){ | ||
k = k.yellow | ||
} | ||
vals.push([k, dollar_balance, liquid]) | ||
@@ -50,6 +58,6 @@ }) | ||
_.each(vals, function(v){ | ||
t.push([v[0], c(v[1]), c(v[2]), c(v[1]/tot_val * 100)]) | ||
t.push([v[0], $$(v[1]), $$(v[2]), c(v[1]/tot_val * 100)]) | ||
}) | ||
t.push([]); | ||
t.push(['Total', c(tot_val), c(tot_liq), '']); | ||
t.push(['Total', $$(tot_val), $$(tot_liq), '']); | ||
@@ -56,0 +64,0 @@ console.log(t.toString()) |
26497
19.94%18
20%714
22.68%