clean up earnings
This commit is contained in:
parent
8ae9089975
commit
2bcb84dafa
3 changed files with 22 additions and 50 deletions
|
|
@ -16,6 +16,15 @@ pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, symbol: []const
|
||||||
};
|
};
|
||||||
defer allocator.free(result.data);
|
defer allocator.free(result.data);
|
||||||
|
|
||||||
|
// Sort chronologically (oldest first) — providers may return in any order
|
||||||
|
if (result.data.len > 1) {
|
||||||
|
std.mem.sort(zfin.EarningsEvent, result.data, {}, struct {
|
||||||
|
fn f(_: void, a: zfin.EarningsEvent, b: zfin.EarningsEvent) bool {
|
||||||
|
return a.date.days < b.date.days;
|
||||||
|
}
|
||||||
|
}.f);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.source == .cached) try cli.stderrPrint("(using cached earnings data)\n");
|
if (result.source == .cached) try cli.stderrPrint("(using cached earnings data)\n");
|
||||||
|
|
||||||
try display(result.data, symbol, color, out);
|
try display(result.data, symbol, color, out);
|
||||||
|
|
@ -64,32 +73,8 @@ pub fn display(events: []const zfin.EarningsEvent, symbol: []const u8, color: bo
|
||||||
try out.print("\n{d} earnings event(s)\n\n", .{events.len});
|
try out.print("\n{d} earnings event(s)\n\n", .{events.len});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fmtEps(val: f64) [12]u8 {
|
|
||||||
var buf: [12]u8 = .{' '} ** 12;
|
|
||||||
_ = std.fmt.bufPrint(&buf, "${d:.2}", .{val}) catch {};
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Tests ────────────────────────────────────────────────────
|
// ── Tests ────────────────────────────────────────────────────
|
||||||
|
|
||||||
test "fmtEps formats positive value" {
|
|
||||||
const result = fmtEps(1.25);
|
|
||||||
const trimmed = std.mem.trimRight(u8, &result, &.{' '});
|
|
||||||
try std.testing.expectEqualStrings("$1.25", trimmed);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "fmtEps formats negative value" {
|
|
||||||
const result = fmtEps(-0.50);
|
|
||||||
const trimmed = std.mem.trimRight(u8, &result, &.{' '});
|
|
||||||
try std.testing.expect(std.mem.indexOf(u8, trimmed, "0.5") != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "fmtEps formats zero" {
|
|
||||||
const result = fmtEps(0.0);
|
|
||||||
const trimmed = std.mem.trimRight(u8, &result, &.{' '});
|
|
||||||
try std.testing.expectEqualStrings("$0.00", trimmed);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "display shows earnings with beat" {
|
test "display shows earnings with beat" {
|
||||||
var buf: [4096]u8 = undefined;
|
var buf: [4096]u8 = undefined;
|
||||||
var w: std.Io.Writer = .fixed(&buf);
|
var w: std.Io.Writer = .fixed(&buf);
|
||||||
|
|
|
||||||
24
src/tui.zig
24
src/tui.zig
|
|
@ -1117,29 +1117,7 @@ pub const App = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadEarningsData(self: *App) void {
|
fn loadEarningsData(self: *App) void {
|
||||||
self.earnings_loaded = true;
|
earnings_tab.loadData(self);
|
||||||
self.freeEarnings();
|
|
||||||
|
|
||||||
const result = self.svc.getEarnings(self.symbol) catch |err| {
|
|
||||||
switch (err) {
|
|
||||||
zfin.DataError.NoApiKey => self.setStatus("No API key. Set FINNHUB_API_KEY"),
|
|
||||||
zfin.DataError.FetchFailed => {
|
|
||||||
self.earnings_disabled = true;
|
|
||||||
self.setStatus("No earnings data (ETF/index?)");
|
|
||||||
},
|
|
||||||
else => self.setStatus("Error loading earnings"),
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.earnings_data = result.data;
|
|
||||||
self.earnings_timestamp = result.timestamp;
|
|
||||||
|
|
||||||
if (result.data.len == 0) {
|
|
||||||
self.earnings_disabled = true;
|
|
||||||
self.setStatus("No earnings data available (ETF/index?)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.setStatus(if (result.source == .cached) "r/F5 to refresh" else "Fetched | r/F5 to refresh");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadOptionsData(self: *App) void {
|
fn loadOptionsData(self: *App) void {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,15 @@ pub fn loadData(self: *App) void {
|
||||||
self.earnings_data = result.data;
|
self.earnings_data = result.data;
|
||||||
self.earnings_timestamp = result.timestamp;
|
self.earnings_timestamp = result.timestamp;
|
||||||
|
|
||||||
|
// Sort chronologically (oldest first) — providers may return in any order
|
||||||
|
if (result.data.len > 1) {
|
||||||
|
std.mem.sort(zfin.EarningsEvent, result.data, {}, struct {
|
||||||
|
fn f(_: void, a: zfin.EarningsEvent, b: zfin.EarningsEvent) bool {
|
||||||
|
return a.date.days < b.date.days;
|
||||||
|
}
|
||||||
|
}.f);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.data.len == 0) {
|
if (result.data.len == 0) {
|
||||||
self.earnings_disabled = true;
|
self.earnings_disabled = true;
|
||||||
self.setStatus("No earnings data available (ETF/index?)");
|
self.setStatus("No earnings data available (ETF/index?)");
|
||||||
|
|
@ -81,15 +90,15 @@ pub fn renderEarningsLines(
|
||||||
return lines.toOwnedSlice(arena);
|
return lines.toOwnedSlice(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
try lines.append(arena, .{ .text = try std.fmt.allocPrint(arena, " {s:>12} {s:>4} {s:>12} {s:>12} {s:>12} {s:>10}", .{
|
try lines.append(arena, .{ .text = try std.fmt.allocPrint(arena, " {s:>12} {s:>4} {s:>12} {s:>12} {s:>12} {s:>10} {s:>5}", .{
|
||||||
"Date", "Q", "EPS Est", "EPS Act", "Surprise", "Surprise %",
|
"Date", "Q", "EPS Est", "EPS Act", "Surprise", "Surprise %", "When",
|
||||||
}), .style = th.mutedStyle() });
|
}), .style = th.mutedStyle() });
|
||||||
|
|
||||||
for (ev) |e| {
|
for (ev) |e| {
|
||||||
var row_buf: [128]u8 = undefined;
|
var row_buf: [128]u8 = undefined;
|
||||||
const row = fmt.fmtEarningsRow(&row_buf, e);
|
const row = fmt.fmtEarningsRow(&row_buf, e);
|
||||||
|
|
||||||
const text = try std.fmt.allocPrint(arena, " {s}", .{row.text});
|
const text = try std.fmt.allocPrint(arena, " {s} {s:>5}", .{ row.text, @tagName(e.report_time) });
|
||||||
const row_style = if (row.is_future) th.mutedStyle() else if (row.is_positive) th.positiveStyle() else th.negativeStyle();
|
const row_style = if (row.is_future) th.mutedStyle() else if (row.is_positive) th.positiveStyle() else th.negativeStyle();
|
||||||
|
|
||||||
try lines.append(arena, .{ .text = text, .style = row_style });
|
try lines.append(arena, .{ .text = text, .style = row_style });
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue