clean up performance.zig
This commit is contained in:
parent
0cb3b2948b
commit
fbe8320399
2 changed files with 30 additions and 9 deletions
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
const Date = @import("../models/date.zig").Date;
|
||||
const Candle = @import("../models/candle.zig").Candle;
|
||||
const Dividend = @import("../models/dividend.zig").Dividend;
|
||||
const portfolio = @import("../models/portfolio.zig");
|
||||
|
||||
/// Minimum holding period (in years) before annualizing returns.
|
||||
/// Set below 1.0 to handle trading-day snap (e.g. a "1-year" lookback
|
||||
|
|
@ -89,11 +90,14 @@ fn totalReturnWithDividendsSnap(
|
|||
to: Date,
|
||||
start_dir: SearchDirection,
|
||||
) ?PerformanceResult {
|
||||
// When `from` predates all cached candles, the only safe shortcut is
|
||||
// for stable-NAV funds: if the earliest candle we have is at $1, we
|
||||
// can extrapolate backward and synthesize a $1 candle at `from`.
|
||||
// Reuse `stableNavCandle` so the synthesized candle has the same
|
||||
// shape as the one used elsewhere.
|
||||
const start = findNearestCandle(candles, from, start_dir) orelse
|
||||
// Stable-NAV fund (e.g. money market): synthesize start candle at $1
|
||||
// when candle history doesn't reach back far enough.
|
||||
if (candles.len > 0 and from.lessThan(candles[0].date) and candles[0].close == 1.0)
|
||||
stableNavCandle(from)
|
||||
portfolio.stableNavCandle(from)
|
||||
else
|
||||
return null;
|
||||
const end = findNearestCandle(candles, to, .backward) orelse return null;
|
||||
|
|
@ -111,7 +115,7 @@ fn totalReturnWithDividendsSnap(
|
|||
// For stable-NAV funds, dividends before candle history use $1.
|
||||
const price_candle = findNearestCandle(candles, div.ex_date, .backward) orelse
|
||||
if (start.close == 1.0)
|
||||
stableNavCandle(div.ex_date)
|
||||
portfolio.stableNavCandle(div.ex_date)
|
||||
else
|
||||
continue;
|
||||
if (price_candle.close > 0) {
|
||||
|
|
@ -131,11 +135,9 @@ fn totalReturnWithDividendsSnap(
|
|||
};
|
||||
}
|
||||
|
||||
/// Synthesize a candle with stable $1 NAV for a given date.
|
||||
/// Used for money market funds whose NAV is always $1.
|
||||
fn stableNavCandle(date: Date) Candle {
|
||||
return .{ .date = date, .open = 1, .high = 1, .low = 1, .close = 1, .adj_close = 1, .volume = 0 };
|
||||
}
|
||||
// Stable-NAV candle synthesis lives in src/models/portfolio.zig
|
||||
// (`portfolio.stableNavCandle`) so every caller agrees on the shape
|
||||
// of a synthesized $1 candle. Performance-only heuristics stay here.
|
||||
|
||||
/// Convenience: compute 1yr, 3yr, 5yr, 10yr trailing returns from adjusted close.
|
||||
/// Uses the last available date as the endpoint.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
const std = @import("std");
|
||||
const Date = @import("date.zig").Date;
|
||||
const Candle = @import("candle.zig").Candle;
|
||||
|
||||
/// Synthesize a stable-NAV (= $1) candle for a given date. Used when
|
||||
/// historical price data for a money-market fund doesn't reach back as
|
||||
/// far as the period under analysis — the close is known to be $1 by
|
||||
/// construction, so we can extrapolate backward without inventing data.
|
||||
pub fn stableNavCandle(date: Date) Candle {
|
||||
return .{ .date = date, .open = 1, .high = 1, .low = 1, .close = 1, .adj_close = 1, .volume = 0 };
|
||||
}
|
||||
|
||||
/// Type of holding in a portfolio lot.
|
||||
pub const LotType = enum {
|
||||
|
|
@ -806,3 +815,13 @@ test "totalForAccount" {
|
|||
const total = portfolio.totalForAccount(allocator, "IRA", prices);
|
||||
try std.testing.expectApproxEqAbs(@as(f64, 44500.0), total, 0.01);
|
||||
}
|
||||
|
||||
test "stableNavCandle: fills all fields at $1" {
|
||||
const c = stableNavCandle(Date.fromYmd(2026, 4, 1));
|
||||
try std.testing.expectEqual(@as(f64, 1), c.close);
|
||||
try std.testing.expectEqual(@as(f64, 1), c.open);
|
||||
try std.testing.expectEqual(@as(f64, 1), c.high);
|
||||
try std.testing.expectEqual(@as(f64, 1), c.low);
|
||||
try std.testing.expectEqual(@as(f64, 1), c.adj_close);
|
||||
try std.testing.expectEqual(@as(u64, 0), c.volume);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue