Last active
September 20, 2021 03:21
-
-
Save pauloromeira/147624af7922876de29eae4a042ab66f to your computer and use it in GitHub Desktop.
Apps Script (Google Sheets) - Balance Portfolio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ---------- General Helpers ---------- */ | |
function _sort_idxs(items) { | |
return items.map((item, idx) => [item, idx]).sort().map(i => i[1]); | |
} | |
function _sort_apply(idxs, items) { | |
return idxs.map(idx => items[idx]); | |
} | |
function _sort_restore(idxs, items) { | |
var restored = new Array(idxs.length); | |
items.map((item, i) => { restored[idxs[i]] = item; }); | |
return restored; | |
} | |
/* ---------- Specific Helpers ---------- */ | |
function _heights(widths, areas) { | |
return widths.map((width, i) => areas[i]/width); | |
} | |
function _max_height(widths, heights, amount, count) { | |
var curr_amount = 0; | |
var curr_width = 0; | |
for (var i = 0; i < (count - 1); i++) { | |
let next_width = curr_width + widths[i]; | |
let next_amount = curr_amount + next_width * (heights[i + 1] - heights[i]); | |
if (next_amount >= amount) | |
break; | |
curr_width = next_width; | |
curr_amount = next_amount; | |
} | |
return heights[i] + (amount - curr_amount) / (curr_width + widths[i]); | |
} | |
/* ---------- Main ---------- */ | |
function balance_portfolio(weights, balances, amount, title, count) { | |
var widths = weights.flat(); | |
var heights = _heights(widths, balances.flat()); | |
count = count && typeof(count) === "number" ? Math.min(count, heights.length) : heights.length; | |
// Apply: sort by heights | |
var idxs = _sort_idxs(heights); | |
widths = _sort_apply(idxs, widths); | |
heights = _sort_apply(idxs, heights); | |
// Calculate max_height | |
var max_height = heights[heights.length - 1]; | |
if (typeof(amount) === "number") | |
max_height = _max_height(widths, heights, amount, count); | |
// Calculate results | |
var results = heights.map((h, i) => i < count ? Math.max(max_height - h, 0) * widths[i]: 0); | |
// Restore: sort by heights | |
results = _sort_restore(idxs, results); | |
if (title) | |
results.unshift(title); | |
return results; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment