mutual fund logic in zfin proper now
Some checks failed
Generic zig build / build (push) Failing after 28s
Generic zig build / deploy (push) Has been skipped

This commit is contained in:
Emil Lerch 2026-03-11 11:47:29 -07:00
parent c596d8c12f
commit 2503f6bc2a
Signed by: lobo
GPG key ID: A7B62D657EF764F8
4 changed files with 16 additions and 21 deletions

View file

@ -61,10 +61,14 @@ XML response format:
Use cron to keep the cache warm for all symbols in your portfolio: Use cron to keep the cache warm for all symbols in your portfolio:
```sh ```sh
# Refresh all portfolio symbols nightly at 5pm ET (after market close) # Refresh all portfolio symbols daily at 5pm ET (after market close)
0 17 * * 1-5 cd /path/to/workdir && ZFIN_PORTFOLIO=portfolio.srf zfin-server refresh 0 17 * * 1-5 cd /path/to/workdir && ZFIN_PORTFOLIO=portfolio.srf zfin-server refresh
``` ```
The candle cache TTL is 23h45m (not a full 24h), providing a 15-minute jitter
buffer so daily cron runs at the same time always see stale data and trigger a
fresh fetch. Dividend and earnings TTLs are 14 and 30 days respectively.
The `refresh` command reads the portfolio SRF file (defaults to `portfolio.srf` The `refresh` command reads the portfolio SRF file (defaults to `portfolio.srf`
in the current directory if `ZFIN_PORTFOLIO` is not set), extracts all stock and in the current directory if `ZFIN_PORTFOLIO` is not set), extracts all stock and
watch symbols, and fetches candles, dividends, and earnings for each. watch symbols, and fetches candles, dividends, and earnings for each.

View file

@ -14,8 +14,8 @@
.hash = "httpz-0.0.0-PNVzrBtMBwAPcQx3mNEgat3Xbsynw-eIC9SmOX5M9XtP", .hash = "httpz-0.0.0-PNVzrBtMBwAPcQx3mNEgat3Xbsynw-eIC9SmOX5M9XtP",
}, },
.zfin = .{ .zfin = .{
.url = "git+https://git.lerch.org/lobo/zfin.git#d25d6acb9b9643e47257f61b489f5fa7fbbac7f3", .url = "git+https://git.lerch.org/lobo/zfin.git#31ae11cec0c16fcc60c5847b256c4b750aa8dd16",
.hash = "zfin-0.0.0-J-B21qPuCgDINNDuVwrUiIyzh1i-H8yv1ySdbCMAishl", .hash = "zfin-0.0.0-J-B21rbwCgALvwhOMCdo0yzEtrD-rF-YuSB8KuEVViI3",
}, },
}, },
} }

View file

@ -2,6 +2,7 @@ FROM scratch
COPY ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY zfin-server /zfin-server COPY zfin-server /zfin-server
ENV HOME=/home/zfin-server ENV HOME=/home/zfin-server
WORKDIR /home/zfin-server
USER 1000:1000 USER 1000:1000
EXPOSE 8080 EXPOSE 8080
ENTRYPOINT ["/zfin-server", "serve"] ENTRYPOINT ["/zfin-server", "serve"]

View file

@ -270,12 +270,6 @@ fn printRateLimitWait(svc: *zfin.DataService, stdout: *std.Io.Writer) !void {
} }
} }
/// Mutual funds typically have 5-letter tickers ending in X.
/// These don't have quarterly earnings on Finnhub.
fn isMutualFund(symbol: []const u8) bool {
return symbol.len == 5 and symbol[4] == 'X';
}
/// Format as percentage (e.g., 0.1234 -> "12.34000"), or "null" if absent. /// Format as percentage (e.g., 0.1234 -> "12.34000"), or "null" if absent.
fn fmtPct(arena: std.mem.Allocator, value: ?f64) []const u8 { fn fmtPct(arena: std.mem.Allocator, value: ?f64) []const u8 {
if (value) |v| return std.fmt.allocPrint(arena, "{d:.5}", .{v * 100.0}) catch "null"; if (value) |v| return std.fmt.allocPrint(arena, "{d:.5}", .{v * 100.0}) catch "null";
@ -417,18 +411,14 @@ fn refresh(allocator: std.mem.Allocator) !void {
sym_ok = false; sym_ok = false;
} }
// Earnings (skip for mutual funds they don't report quarterly earnings) // Earnings
if (!isMutualFund(sym)) { try printRateLimitWait(&svc, stdout);
try printRateLimitWait(&svc, stdout); if (svc.getEarnings(sym)) |result| {
if (svc.getEarnings(sym)) |result| { allocator.free(result.data);
allocator.free(result.data); try stdout.print(", earnings ok", .{});
try stdout.print(", earnings ok", .{}); } else |err| {
} else |err| { try stdout.print(", earnings FAILED ({s})", .{@errorName(err)});
try stdout.print(", earnings FAILED ({s})", .{@errorName(err)}); sym_ok = false;
sym_ok = false;
}
} else {
try stdout.print(", earnings skipped (fund)", .{});
} }
try stdout.print("\n", .{}); try stdout.print("\n", .{});