clean up analysis
This commit is contained in:
parent
b718c1ae39
commit
ce72985054
2 changed files with 28 additions and 57 deletions
|
|
@ -4,9 +4,7 @@ const cli = @import("common.zig");
|
|||
const fmt = cli.fmt;
|
||||
|
||||
/// CLI `analysis` command: show portfolio analysis breakdowns.
|
||||
pub fn run(allocator: std.mem.Allocator, config: zfin.Config, svc: *zfin.DataService, file_path: []const u8, color: bool, out: *std.Io.Writer) !void {
|
||||
_ = config;
|
||||
|
||||
pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, file_path: []const u8, color: bool, out: *std.Io.Writer) !void {
|
||||
// Load portfolio
|
||||
const file_data = std.fs.cwd().readFileAlloc(allocator, file_path, 10 * 1024 * 1024) catch {
|
||||
try cli.stderrPrint("Error: Cannot read portfolio file\n");
|
||||
|
|
@ -23,11 +21,12 @@ pub fn run(allocator: std.mem.Allocator, config: zfin.Config, svc: *zfin.DataSer
|
|||
const positions = try portfolio.positions(allocator);
|
||||
defer allocator.free(positions);
|
||||
|
||||
// Build prices map from cache
|
||||
const syms = try portfolio.stockSymbols(allocator);
|
||||
defer allocator.free(syms);
|
||||
|
||||
// Build prices from cache
|
||||
var prices = std.StringHashMap(f64).init(allocator);
|
||||
defer prices.deinit();
|
||||
|
||||
// First pass: try cached candle prices
|
||||
for (positions) |pos| {
|
||||
if (pos.shares <= 0) continue;
|
||||
if (svc.getCachedCandles(pos.symbol)) |cs| {
|
||||
|
|
@ -37,15 +36,16 @@ pub fn run(allocator: std.mem.Allocator, config: zfin.Config, svc: *zfin.DataSer
|
|||
}
|
||||
}
|
||||
}
|
||||
// Build fallback prices for symbols without cached candle data
|
||||
var manual_price_set = try zfin.valuation.buildFallbackPrices(allocator, portfolio.lots, positions, &prices);
|
||||
defer manual_price_set.deinit();
|
||||
|
||||
var summary = zfin.valuation.portfolioSummary(allocator, portfolio, positions, prices, manual_price_set) catch {
|
||||
try cli.stderrPrint("Error computing portfolio summary.\n");
|
||||
return;
|
||||
// Build summary via shared pipeline
|
||||
var pf_data = cli.buildPortfolioData(allocator, portfolio, positions, syms, &prices, svc) catch |err| switch (err) {
|
||||
error.NoAllocations, error.SummaryFailed => {
|
||||
try cli.stderrPrint("Error computing portfolio summary.\n");
|
||||
return;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
defer summary.deinit(allocator);
|
||||
defer pf_data.deinit(allocator);
|
||||
|
||||
// Load classification metadata
|
||||
const dir_end = if (std.mem.lastIndexOfScalar(u8, file_path, '/')) |idx| idx + 1 else 0;
|
||||
|
|
@ -78,10 +78,10 @@ pub fn run(allocator: std.mem.Allocator, config: zfin.Config, svc: *zfin.DataSer
|
|||
|
||||
var result = zfin.analysis.analyzePortfolio(
|
||||
allocator,
|
||||
summary.allocations,
|
||||
pf_data.summary.allocations,
|
||||
cm,
|
||||
portfolio,
|
||||
summary.total_value,
|
||||
pf_data.summary.total_value,
|
||||
acct_map_opt,
|
||||
) catch {
|
||||
try cli.stderrPrint("Error computing analysis.\n");
|
||||
|
|
@ -101,51 +101,22 @@ pub fn display(result: zfin.analysis.AnalysisResult, file_path: []const u8, colo
|
|||
try cli.reset(out, color);
|
||||
try out.print("========================================\n\n", .{});
|
||||
|
||||
// Asset Class
|
||||
try cli.setBold(out, color);
|
||||
try cli.setFg(out, color, cli.CLR_HEADER);
|
||||
try out.print(" Asset Class\n", .{});
|
||||
try cli.reset(out, color);
|
||||
try printBreakdownSection(out, result.asset_class, label_width, bar_width, color);
|
||||
const sections = [_]struct { items: []const zfin.analysis.BreakdownItem, title: []const u8 }{
|
||||
.{ .items = result.asset_class, .title = " Asset Class" },
|
||||
.{ .items = result.sector, .title = " Sector (Equities)" },
|
||||
.{ .items = result.geo, .title = " Geographic" },
|
||||
.{ .items = result.account, .title = " By Account" },
|
||||
.{ .items = result.tax_type, .title = " By Tax Type" },
|
||||
};
|
||||
|
||||
// Sector
|
||||
if (result.sector.len > 0) {
|
||||
try out.print("\n", .{});
|
||||
for (sections, 0..) |sec, si| {
|
||||
if (si > 0 and sec.items.len == 0) continue;
|
||||
if (si > 0) try out.print("\n", .{});
|
||||
try cli.setBold(out, color);
|
||||
try cli.setFg(out, color, cli.CLR_HEADER);
|
||||
try out.print(" Sector (Equities)\n", .{});
|
||||
try out.print("{s}\n", .{sec.title});
|
||||
try cli.reset(out, color);
|
||||
try printBreakdownSection(out, result.sector, label_width, bar_width, color);
|
||||
}
|
||||
|
||||
// Geographic
|
||||
if (result.geo.len > 0) {
|
||||
try out.print("\n", .{});
|
||||
try cli.setBold(out, color);
|
||||
try cli.setFg(out, color, cli.CLR_HEADER);
|
||||
try out.print(" Geographic\n", .{});
|
||||
try cli.reset(out, color);
|
||||
try printBreakdownSection(out, result.geo, label_width, bar_width, color);
|
||||
}
|
||||
|
||||
// By Account
|
||||
if (result.account.len > 0) {
|
||||
try out.print("\n", .{});
|
||||
try cli.setBold(out, color);
|
||||
try cli.setFg(out, color, cli.CLR_HEADER);
|
||||
try out.print(" By Account\n", .{});
|
||||
try cli.reset(out, color);
|
||||
try printBreakdownSection(out, result.account, label_width, bar_width, color);
|
||||
}
|
||||
|
||||
// Tax Type
|
||||
if (result.tax_type.len > 0) {
|
||||
try out.print("\n", .{});
|
||||
try cli.setBold(out, color);
|
||||
try cli.setFg(out, color, cli.CLR_HEADER);
|
||||
try out.print(" By Tax Type\n", .{});
|
||||
try cli.reset(out, color);
|
||||
try printBreakdownSection(out, result.tax_type, label_width, bar_width, color);
|
||||
try printBreakdownSection(out, sec.items, label_width, bar_width, color);
|
||||
}
|
||||
|
||||
// Unclassified
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ pub fn main() !u8 {
|
|||
break;
|
||||
}
|
||||
}
|
||||
try commands.analysis.run(allocator, config, &svc, analysis_file, color, out);
|
||||
try commands.analysis.run(allocator, &svc, analysis_file, color, out);
|
||||
} else {
|
||||
try cli.stderrPrint("Unknown command. Run 'zfin help' for usage.\n");
|
||||
return 1;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue