add total value to equity/fixed income display
All checks were successful
Generic zig build / build (push) Successful in 1m51s
Generic zig build / deploy (push) Successful in 15s

This commit is contained in:
Emil Lerch 2026-04-28 12:30:16 -07:00
parent 6ea0a58949
commit 7014c326d1
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 21 additions and 8 deletions

View file

@ -79,10 +79,10 @@ pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, file_path: []co
portfolio.totalCdFaceValue(),
);
try display(result, split.stock_pct, split.bond_pct, file_path, color, out);
try display(result, split.stock_pct, split.bond_pct, pf_data.summary.total_value, file_path, color, out);
}
pub fn display(result: zfin.analysis.AnalysisResult, stock_pct: f64, bond_pct: f64, file_path: []const u8, color: bool, out: *std.Io.Writer) !void {
pub fn display(result: zfin.analysis.AnalysisResult, stock_pct: f64, bond_pct: f64, total_value: f64, file_path: []const u8, color: bool, out: *std.Io.Writer) !void {
const label_width = fmt.analysis_label_width;
const bar_width = fmt.analysis_bar_width;
@ -93,8 +93,12 @@ pub fn display(result: zfin.analysis.AnalysisResult, stock_pct: f64, bond_pct: f
// Equities vs Fixed Income summary
{
var eq_buf: [24]u8 = undefined;
var fi_buf: [24]u8 = undefined;
const eq_dollars = fmt.fmtMoneyAbs(&eq_buf, stock_pct * total_value);
const fi_dollars = fmt.fmtMoneyAbs(&fi_buf, bond_pct * total_value);
try cli.setFg(out, color, cli.CLR_MUTED);
try out.print(" Equities {d:.1}% / Fixed Income {d:.1}%\n\n", .{ stock_pct * 100, bond_pct * 100 });
try out.print(" Equities {d:.1}% ({s}) / Fixed Income {d:.1}% ({s})\n\n", .{ stock_pct * 100, eq_dollars, bond_pct * 100, fi_dollars });
try cli.reset(out, color);
}
@ -237,7 +241,7 @@ test "display shows all sections" {
.unclassified = @constCast(&unclassified),
.total_value = 100000.0,
};
try display(result, 0.80, 0.20, "test.srf", false, &w);
try display(result, 0.80, 0.20, 100000.0, "test.srf", false, &w);
const out = w.buffered();
try std.testing.expect(std.mem.indexOf(u8, out, "Portfolio Analysis") != null);
try std.testing.expect(std.mem.indexOf(u8, out, "Asset Class") != null);

View file

@ -74,7 +74,9 @@ pub fn buildStyledLines(app: *App, arena: std.mem.Allocator) ![]const StyledLine
// Compute equity/fixed split from classification + portfolio
var stock_pct: f64 = 0;
var bond_pct: f64 = 0;
var total_value: f64 = 0;
if (app.portfolio_summary) |summary| {
total_value = summary.total_value;
if (app.portfolio) |pf| {
const benchmark = @import("../analytics/benchmark.zig");
const cm_entries = if (app.classification_map) |cm| cm.entries else &.{};
@ -89,7 +91,7 @@ pub fn buildStyledLines(app: *App, arena: std.mem.Allocator) ![]const StyledLine
bond_pct = split.bond_pct;
}
}
return renderAnalysisLines(arena, app.theme, app.analysis_result, stock_pct, bond_pct);
return renderAnalysisLines(arena, app.theme, app.analysis_result, stock_pct, bond_pct, total_value);
}
/// Render analysis tab content. Pure function no App dependency.
@ -99,6 +101,7 @@ pub fn renderAnalysisLines(
analysis_result: ?zfin.analysis.AnalysisResult,
stock_pct: f64,
bond_pct: f64,
total_value: f64,
) ![]const StyledLine {
var lines: std.ArrayList(StyledLine) = .empty;
@ -114,8 +117,14 @@ pub fn renderAnalysisLines(
// Equities vs Fixed Income summary
if (stock_pct > 0 or bond_pct > 0) {
var eq_buf: [24]u8 = undefined;
var fi_buf: [24]u8 = undefined;
const eq_dollars = fmt.fmtMoneyAbs(&eq_buf, stock_pct * total_value);
const fi_dollars = fmt.fmtMoneyAbs(&fi_buf, bond_pct * total_value);
try lines.append(arena, .{
.text = try std.fmt.allocPrint(arena, " Equities {d:.1}% / Fixed Income {d:.1}%", .{ stock_pct * 100, bond_pct * 100 }),
.text = try std.fmt.allocPrint(arena, " Equities {d:.1}% ({s}) / Fixed Income {d:.1}% ({s})", .{
stock_pct * 100, eq_dollars, bond_pct * 100, fi_dollars,
}),
.style = th.mutedStyle(),
});
try lines.append(arena, .{ .text = "", .style = th.contentStyle() });
@ -243,7 +252,7 @@ test "renderAnalysisLines with data" {
.unclassified = &.{},
.total_value = 200000,
};
const lines = try renderAnalysisLines(arena, th, result, 0.80, 0.20);
const lines = try renderAnalysisLines(arena, th, result, 0.80, 0.20, 200000);
// Should have header section + asset class items
try testing.expect(lines.len >= 5);
// Find "Portfolio Analysis" header
@ -266,7 +275,7 @@ test "renderAnalysisLines no data" {
const arena = arena_state.allocator();
const th = theme.default_theme;
const lines = try renderAnalysisLines(arena, th, null, 0, 0);
const lines = try renderAnalysisLines(arena, th, null, 0, 0, 0);
try testing.expectEqual(@as(usize, 5), lines.len);
try testing.expect(std.mem.indexOf(u8, lines[3].text, "No analysis data") != null);
}