def compute_returns_table(pricer: returnslib.Pricer, target_currency: Currency, account_data: List[AccountData], intervals: List[Interval]): """Compute a table of sequential returns.""" header = ["Return"] rows = [["Total"], ["Ex-div"], ["Div"]] for intname, date1, date2 in intervals: header.append(intname) cash_flows = returnslib.truncate_and_merge_cash_flows( pricer, account_data, date1, date2) returns = returnslib.compute_returns(cash_flows, pricer, target_currency, date2) rows[0].append(returns.total) rows[1].append(returns.exdiv) rows[2].append(returns.div) return Table(header, rows)
def write_returns_html( dirname: str, pricer: returnslib.Pricer, account_data: List[AccountData], title: str, end_date: Date, target_currency: Optional[Currency] = None) -> subprocess.Popen: """Write out returns report to a directory with files in it.""" logging.info("Writing returns dir for %s: %s", title, dirname) os.makedirs(dirname, exist_ok=True) with open(path.join(dirname, "index.html"), "w") as indexfile: fprint = partial(print, file=indexfile) fprint(RETURNS_TEMPLATE_PRE.format(style=STYLE, title=title)) if not target_currency: cost_currencies = set(r.cost_currency for r in account_data) target_currency = cost_currencies.pop() assert not cost_currencies, ( "Incompatible cost currencies {} for accounts {}".format( cost_currencies, ",".join([r.account for r in account_data]))) # TOOD(blais): Prices should be plot separately, by currency. # fprint("<h2>Prices</h2>") # pairs = set((r.currency, r.cost_currency) for r in account_data) # plots = plot_prices(dirname, pricer.price_map, pairs) # for _, filename in sorted(plots.items()): # fprint('<img src={} style="width: 100%"/>'.format(filename)) fprint("<h2>Cash Flows</h2>") cash_flows = returnslib.truncate_and_merge_cash_flows( pricer, account_data, None, end_date) returns = returnslib.compute_returns(cash_flows, pricer, target_currency, end_date) transactions = data.sorted( [txn for ad in account_data for txn in ad.transactions]) # Note: This is where the vast majority of the time is spent. plots = plot_flows(dirname, pricer.price_map, cash_flows, transactions, returns.total) fprint('<img src={} style="width: 100%"/>'.format(plots["flows"])) fprint('<img src={} style="width: 100%"/>'.format(plots["cumvalue"])) fprint("<h2>Returns</h2>") fprint( render_table(Table(["Total", "Ex-Div", "Div"], [[returns.total, returns.exdiv, returns.div]]), floatfmt="{:.2%}")) # Compute table of returns over intervals. table = compute_returns_table(pricer, target_currency, account_data, get_calendar_intervals(TODAY)) fprint("<p>", render_table(table, floatfmt="{:.1%}", classes=["full"]), "</p>") table = compute_returns_table(pricer, target_currency, account_data, get_cumulative_intervals(TODAY)) fprint("<p>", render_table(table, floatfmt="{:.1%}", classes=["full"]), "</p>") fprint('<h2 class="new-page">Accounts</h2>') fprint("<p>Cost Currency: {}</p>".format(target_currency)) accounts_df = get_accounts_table(account_data) fprint(accounts_df.to_html()) fprint('<h2 class="new-page">Cash Flows</h2>') df = investments.cash_flows_to_table(cash_flows) fprint(df.to_html()) fprint(RETURNS_TEMPLATE_POST) return indexfile.name