add unit tests for account valuation
This commit is contained in:
parent
3171be6f70
commit
5b0af2486c
1 changed files with 95 additions and 0 deletions
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue