clean up history/enrich
This commit is contained in:
parent
1cdf228fc1
commit
be42f9e15a
2 changed files with 36 additions and 42 deletions
|
|
@ -3,6 +3,36 @@ const zfin = @import("../root.zig");
|
||||||
const cli = @import("common.zig");
|
const cli = @import("common.zig");
|
||||||
const isCusipLike = @import("../models/portfolio.zig").isCusipLike;
|
const isCusipLike = @import("../models/portfolio.zig").isCusipLike;
|
||||||
|
|
||||||
|
const OverviewMeta = struct {
|
||||||
|
sector: []const u8,
|
||||||
|
geo: []const u8,
|
||||||
|
asset_class: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Derive sector, geo, and asset_class from an Alpha Vantage company overview.
|
||||||
|
fn deriveMetadata(overview: zfin.CompanyOverview, sector_buf: []u8) OverviewMeta {
|
||||||
|
const sector_raw = overview.sector orelse "Unknown";
|
||||||
|
const sector_str = cli.fmt.toTitleCase(sector_buf, sector_raw);
|
||||||
|
const country_str = overview.country orelse "US";
|
||||||
|
const geo_str = if (std.mem.eql(u8, country_str, "USA")) "US" else country_str;
|
||||||
|
|
||||||
|
const asset_class_str = blk: {
|
||||||
|
if (overview.asset_type) |at| {
|
||||||
|
if (std.mem.eql(u8, at, "ETF")) break :blk "ETF";
|
||||||
|
if (std.mem.eql(u8, at, "Mutual Fund")) break :blk "Mutual Fund";
|
||||||
|
}
|
||||||
|
if (overview.market_cap) |mc_str| {
|
||||||
|
const mc = std.fmt.parseInt(u64, mc_str, 10) catch 0;
|
||||||
|
if (mc >= 10_000_000_000) break :blk "US Large Cap";
|
||||||
|
if (mc >= 2_000_000_000) break :blk "US Mid Cap";
|
||||||
|
break :blk "US Small Cap";
|
||||||
|
}
|
||||||
|
break :blk "US Large Cap";
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{ .sector = sector_str, .geo = geo_str, .asset_class = asset_class_str };
|
||||||
|
}
|
||||||
|
|
||||||
/// CLI `enrich` command: bootstrap a metadata.srf file from Alpha Vantage OVERVIEW data.
|
/// CLI `enrich` command: bootstrap a metadata.srf file from Alpha Vantage OVERVIEW data.
|
||||||
/// Reads the portfolio, extracts stock symbols, fetches sector/industry/country for each,
|
/// Reads the portfolio, extracts stock symbols, fetches sector/industry/country for each,
|
||||||
/// and outputs a metadata SRF file to stdout.
|
/// and outputs a metadata SRF file to stdout.
|
||||||
|
|
@ -50,31 +80,14 @@ fn enrichSymbol(allocator: std.mem.Allocator, svc: *zfin.DataService, sym: []con
|
||||||
if (overview.asset_type) |at| allocator.free(at);
|
if (overview.asset_type) |at| allocator.free(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sector_raw = overview.sector orelse "Unknown";
|
|
||||||
var sector_buf: [64]u8 = undefined;
|
var sector_buf: [64]u8 = undefined;
|
||||||
const sector_str = cli.fmt.toTitleCase(§or_buf, sector_raw);
|
const meta = deriveMetadata(overview, §or_buf);
|
||||||
const country_str = overview.country orelse "US";
|
|
||||||
const geo_str = if (std.mem.eql(u8, country_str, "USA")) "US" else country_str;
|
|
||||||
|
|
||||||
const asset_class_str = blk: {
|
|
||||||
if (overview.asset_type) |at| {
|
|
||||||
if (std.mem.eql(u8, at, "ETF")) break :blk "ETF";
|
|
||||||
if (std.mem.eql(u8, at, "Mutual Fund")) break :blk "Mutual Fund";
|
|
||||||
}
|
|
||||||
if (overview.market_cap) |mc_str| {
|
|
||||||
const mc = std.fmt.parseInt(u64, mc_str, 10) catch 0;
|
|
||||||
if (mc >= 10_000_000_000) break :blk "US Large Cap";
|
|
||||||
if (mc >= 2_000_000_000) break :blk "US Mid Cap";
|
|
||||||
break :blk "US Small Cap";
|
|
||||||
}
|
|
||||||
break :blk "US Large Cap";
|
|
||||||
};
|
|
||||||
|
|
||||||
if (overview.name) |name| {
|
if (overview.name) |name| {
|
||||||
try out.print("# {s}\n", .{name});
|
try out.print("# {s}\n", .{name});
|
||||||
}
|
}
|
||||||
try out.print("symbol::{s},sector::{s},geo::{s},asset_class::{s}\n", .{
|
try out.print("symbol::{s},sector::{s},geo::{s},asset_class::{s}\n", .{
|
||||||
sym, sector_str, geo_str, asset_class_str,
|
sym, meta.sector, meta.geo, meta.asset_class,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,34 +172,15 @@ fn enrichPortfolio(allocator: std.mem.Allocator, svc: *zfin.DataService, file_pa
|
||||||
if (overview.asset_type) |at| allocator.free(at);
|
if (overview.asset_type) |at| allocator.free(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sector_raw = overview.sector orelse "Unknown";
|
|
||||||
var sector_buf: [64]u8 = undefined;
|
var sector_buf: [64]u8 = undefined;
|
||||||
const sector_str = cli.fmt.toTitleCase(§or_buf, sector_raw);
|
const meta = deriveMetadata(overview, §or_buf);
|
||||||
const country_str = overview.country orelse "US";
|
|
||||||
const geo_str = if (std.mem.eql(u8, country_str, "USA")) "US" else country_str;
|
|
||||||
|
|
||||||
// Determine asset_class from asset type + market cap
|
|
||||||
const asset_class_str = blk: {
|
|
||||||
if (overview.asset_type) |at| {
|
|
||||||
if (std.mem.eql(u8, at, "ETF")) break :blk "ETF";
|
|
||||||
if (std.mem.eql(u8, at, "Mutual Fund")) break :blk "Mutual Fund";
|
|
||||||
}
|
|
||||||
// For common stocks, infer from market cap
|
|
||||||
if (overview.market_cap) |mc_str| {
|
|
||||||
const mc = std.fmt.parseInt(u64, mc_str, 10) catch 0;
|
|
||||||
if (mc >= 10_000_000_000) break :blk "US Large Cap";
|
|
||||||
if (mc >= 2_000_000_000) break :blk "US Mid Cap";
|
|
||||||
break :blk "US Small Cap";
|
|
||||||
}
|
|
||||||
break :blk "US Large Cap";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Comment with the name for readability
|
// Comment with the name for readability
|
||||||
if (overview.name) |name| {
|
if (overview.name) |name| {
|
||||||
try out.print("# {s}\n", .{name});
|
try out.print("# {s}\n", .{name});
|
||||||
}
|
}
|
||||||
try out.print("symbol::{s},sector::{s},geo::{s},asset_class::{s}\n\n", .{
|
try out.print("symbol::{s},sector::{s},geo::{s},asset_class::{s}\n\n", .{
|
||||||
sym, sector_str, geo_str, asset_class_str,
|
sym, meta.sector, meta.geo, meta.asset_class,
|
||||||
});
|
});
|
||||||
success += 1;
|
success += 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ const fmt = cli.fmt;
|
||||||
pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, symbol: []const u8, color: bool, out: *std.Io.Writer) !void {
|
pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, symbol: []const u8, color: bool, out: *std.Io.Writer) !void {
|
||||||
const result = svc.getCandles(symbol) catch |err| switch (err) {
|
const result = svc.getCandles(symbol) catch |err| switch (err) {
|
||||||
zfin.DataError.NoApiKey => {
|
zfin.DataError.NoApiKey => {
|
||||||
try cli.stderrPrint("Error: TWELVEDATA_API_KEY not set.\n");
|
try cli.stderrPrint("Error: No API key configured for candle data.\n");
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
|
|
@ -46,7 +46,7 @@ pub fn display(candles: []const zfin.Candle, symbol: []const u8, color: bool, ou
|
||||||
for (candles) |candle| {
|
for (candles) |candle| {
|
||||||
var db: [10]u8 = undefined;
|
var db: [10]u8 = undefined;
|
||||||
var vb: [32]u8 = undefined;
|
var vb: [32]u8 = undefined;
|
||||||
try cli.setGainLoss(out, color, if (candle.close >= candle.open) @as(f64, 1) else @as(f64, -1));
|
try cli.setGainLoss(out, color, if (candle.close >= candle.open) 1.0 else -1.0);
|
||||||
try out.print("{s:>12} {d:>10.2} {d:>10.2} {d:>10.2} {d:>10.2} {s:>12}\n", .{
|
try out.print("{s:>12} {d:>10.2} {d:>10.2} {d:>10.2} {d:>10.2} {s:>12}\n", .{
|
||||||
candle.date.format(&db), candle.open, candle.high, candle.low, candle.close, fmt.fmtIntCommas(&vb, candle.volume),
|
candle.date.format(&db), candle.open, candle.high, candle.low, candle.close, fmt.fmtIntCommas(&vb, candle.volume),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue