add unit tests for account valuation

This commit is contained in:
Emil Lerch 2026-04-11 10:22:03 -07:00
parent 3171be6f70
commit 5b0af2486c
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -711,3 +711,98 @@ test "positionsForAccount excludes closed-only symbols" {
try std.testing.expectEqualStrings("XLV", pos_b[0].symbol); try std.testing.expectEqualStrings("XLV", pos_b[0].symbol);
try std.testing.expectApproxEqAbs(@as(f64, 50.0), pos_b[0].shares, 0.01); try std.testing.expectApproxEqAbs(@as(f64, 50.0), pos_b[0].shares, 0.01);
} }
test "isOpen respects maturity_date" {
const past = Date.fromYmd(2024, 1, 1);
const future = Date.fromYmd(2099, 12, 31);
const expired_option = Lot{
.symbol = "AAPL 01/01/2024 150 C",
.shares = -1,
.open_date = Date.fromYmd(2023, 6, 1),
.open_price = 5.0,
.security_type = .option,
.maturity_date = past,
};
try std.testing.expect(!expired_option.isOpen());
const active_option = Lot{
.symbol = "AAPL 12/31/2099 150 C",
.shares = -1,
.open_date = Date.fromYmd(2023, 6, 1),
.open_price = 5.0,
.security_type = .option,
.maturity_date = future,
};
try std.testing.expect(active_option.isOpen());
const closed_option = Lot{
.symbol = "AAPL 12/31/2099 150 C",
.shares = -1,
.open_date = Date.fromYmd(2023, 6, 1),
.open_price = 5.0,
.security_type = .option,
.maturity_date = future,
.close_date = Date.fromYmd(2024, 6, 1),
};
try std.testing.expect(!closed_option.isOpen());
const stock = Lot{
.symbol = "AAPL",
.shares = 100,
.open_date = Date.fromYmd(2023, 1, 1),
.open_price = 150.0,
};
try std.testing.expect(stock.isOpen());
}
test "nonStockValueForAccount" {
const allocator = std.testing.allocator;
const future = Date.fromYmd(2099, 12, 31);
const past = Date.fromYmd(2024, 1, 1);
var lots = [_]Lot{
.{ .symbol = "AAPL", .shares = 100, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 150.0, .account = "IRA" },
.{ .symbol = "", .shares = 5000, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 1.0, .security_type = .cash, .account = "IRA" },
.{ .symbol = "CD123", .shares = 50000, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 1.0, .security_type = .cd, .account = "IRA", .maturity_date = future },
.{ .symbol = "AAPL 12/31/2099 200 C", .shares = -2, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 3.50, .security_type = .option, .account = "IRA", .maturity_date = future, .multiplier = 100 },
.{ .symbol = "AAPL 01/01/2024 180 C", .shares = -1, .open_date = Date.fromYmd(2023, 6, 1), .open_price = 4.0, .security_type = .option, .account = "IRA", .maturity_date = past, .multiplier = 100 },
.{ .symbol = "", .shares = 1000, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 1.0, .security_type = .cash, .account = "Other" },
};
const portfolio = Portfolio{ .lots = &lots, .allocator = allocator };
// cash(5000) + cd(50000) + open option(2*3.50*100=700) = 55700
// expired option excluded
const ns = portfolio.nonStockValueForAccount("IRA");
try std.testing.expectApproxEqAbs(@as(f64, 55700.0), ns, 0.01);
const ns_other = portfolio.nonStockValueForAccount("Other");
try std.testing.expectApproxEqAbs(@as(f64, 1000.0), ns_other, 0.01);
}
test "totalForAccount" {
const allocator = std.testing.allocator;
const future = Date.fromYmd(2099, 12, 31);
var lots = [_]Lot{
.{ .symbol = "AAPL", .shares = 100, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 150.0, .account = "IRA" },
.{ .symbol = "MSFT", .shares = 50, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 300.0, .account = "IRA" },
.{ .symbol = "", .shares = 2000, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 1.0, .security_type = .cash, .account = "IRA" },
.{ .symbol = "CD456", .shares = 10000, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 1.0, .security_type = .cd, .account = "IRA", .maturity_date = future },
.{ .symbol = "AAPL C", .shares = -1, .open_date = Date.fromYmd(2024, 1, 1), .open_price = 5.0, .security_type = .option, .account = "IRA", .maturity_date = future, .multiplier = 100 },
};
const portfolio = Portfolio{ .lots = &lots, .allocator = allocator };
var prices = std.StringHashMap(f64).init(allocator);
defer prices.deinit();
try prices.put("AAPL", 170.0);
// MSFT not in prices should fall back to avg_cost (300.0)
// stocks: AAPL(100*170=17000) + MSFT(50*300=15000) = 32000
// non-stock: cash(2000) + cd(10000) + option(1*5*100=500) = 12500
// total = 44500
const total = portfolio.totalForAccount(allocator, "IRA", prices);
try std.testing.expectApproxEqAbs(@as(f64, 44500.0), total, 0.01);
}