ignore option mark to market in schwab

This commit is contained in:
Emil Lerch 2026-04-25 09:07:13 -07:00
parent 74fa8d91fa
commit fb1178b5ca
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -710,6 +710,7 @@ pub const SymbolComparison = struct {
shares_delta: ?f64,
value_delta: ?f64,
is_cash: bool,
is_option: bool,
only_in_brokerage: bool,
only_in_portfolio: bool,
};
@ -723,6 +724,7 @@ pub const AccountComparison = struct {
portfolio_total: f64,
brokerage_total: f64,
total_delta: f64,
option_value_delta: f64,
has_discrepancies: bool,
};
@ -769,6 +771,7 @@ pub fn compareAccounts(
var portfolio_total: f64 = 0;
var brokerage_total: f64 = 0;
var option_value_delta: f64 = 0;
var has_discrepancies = false;
// Track which portfolio symbols we've matched
@ -793,6 +796,7 @@ pub fn compareAccounts(
.shares_delta = if (bp.quantity) |q| q else null,
.value_delta = bp.current_value,
.is_cash = bp.is_cash,
.is_option = false,
.only_in_brokerage = true,
.only_in_portfolio = false,
});
@ -804,6 +808,7 @@ pub fn compareAccounts(
var pf_shares: f64 = 0;
var pf_value: f64 = 0;
var pf_price: ?f64 = null;
var is_option = false;
if (bp.is_cash) {
pf_shares = portfolio.cashForAccount(portfolio_acct_name.?);
@ -842,6 +847,7 @@ pub fn compareAccounts(
pf_shares += lot.shares;
pf_value += @abs(lot.shares) * lot.open_price * lot.multiplier;
pf_price = lot.open_price * lot.multiplier;
is_option = true;
},
else => {},
}
@ -859,7 +865,14 @@ pub fn compareAccounts(
const shares_match = if (shares_delta) |d| @abs(d) < 0.01 else true;
const value_match = if (value_delta) |d| @abs(d) < 1.0 else true;
if (!shares_match or !value_match) has_discrepancies = true;
// Option value deltas are expected (cost basis vs mark-to-market)
// track them separately rather than flagging as discrepancies
if (is_option) {
if (value_delta) |d| option_value_delta += d;
if (!shares_match) has_discrepancies = true;
} else {
if (!shares_match or !value_match) has_discrepancies = true;
}
const br_price: ?f64 = if (bp.quantity) |q| if (bp.current_value) |v| if (q != 0) v / q else null else null else null;
@ -874,6 +887,7 @@ pub fn compareAccounts(
.shares_delta = shares_delta,
.value_delta = value_delta,
.is_cash = bp.is_cash,
.is_option = is_option,
.only_in_brokerage = pf_shares == 0 and pf_value == 0,
.only_in_portfolio = false,
});
@ -906,6 +920,7 @@ pub fn compareAccounts(
.shares_delta = null,
.value_delta = null,
.is_cash = false,
.is_option = false,
.only_in_brokerage = false,
.only_in_portfolio = true,
});
@ -962,6 +977,7 @@ pub fn compareAccounts(
.shares_delta = null,
.value_delta = null,
.is_cash = is_cd,
.is_option = !is_cd,
.only_in_brokerage = false,
.only_in_portfolio = true,
});
@ -977,6 +993,7 @@ pub fn compareAccounts(
.portfolio_total = portfolio_total,
.brokerage_total = brokerage_total,
.total_delta = brokerage_total - portfolio_total,
.option_value_delta = option_value_delta,
.has_discrepancies = has_discrepancies,
});
}
@ -997,6 +1014,7 @@ fn displayResults(results: []const AccountComparison, color: bool, out: *std.Io.
var total_portfolio: f64 = 0;
var total_brokerage: f64 = 0;
var total_option_delta: f64 = 0;
var discrepancy_count: usize = 0;
for (results) |acct| {
@ -1096,6 +1114,10 @@ fn displayResults(results: []const AccountComparison, color: bool, out: *std.Io.
}
}
// Options: shares match is sufficient value delta is expected
// (cost basis vs mark-to-market) and not actionable
if (cmp.is_option) break :blk "Option";
// Shares match show value delta (stale price) if any, muted
if (cmp.value_delta) |d| {
if (@abs(d) >= 1.0) {
@ -1151,23 +1173,32 @@ fn displayResults(results: []const AccountComparison, color: bool, out: *std.Io.
});
try cli.reset(out, color);
const delta = acct.total_delta;
if (@abs(delta) < 1.0) {
try out.print("\n", .{});
const adj_delta = acct.total_delta - acct.option_value_delta;
if (@abs(adj_delta) < 1.0) {
// no delta text needed
} else {
const sign: []const u8 = if (delta >= 0) "+" else "-";
if (delta >= 0) {
const sign: []const u8 = if (adj_delta >= 0) "+" else "-";
if (adj_delta >= 0) {
try cli.setFg(out, color, cli.CLR_NEGATIVE);
} else {
try cli.setFg(out, color, cli.CLR_POSITIVE);
}
try out.print("Delta {s}{s}\n", .{ sign, fmt.fmtMoneyAbs(&delta_buf, @abs(delta)) });
try out.print("Delta {s}{s}", .{ sign, fmt.fmtMoneyAbs(&delta_buf, @abs(adj_delta)) });
try cli.reset(out, color);
}
try out.print("\n", .{});
if (@abs(acct.option_value_delta) >= 1.0) {
var opt_delta_buf: [24]u8 = undefined;
const opt_sign: []const u8 = if (acct.option_value_delta >= 0) "+" else "-";
try cli.setFg(out, color, cli.CLR_MUTED);
try out.print(" (options {s}{s})", .{ opt_sign, fmt.fmtMoneyAbs(&opt_delta_buf, @abs(acct.option_value_delta)) });
try cli.reset(out, color);
}
try out.print("\n\n", .{});
total_portfolio += acct.portfolio_total;
total_brokerage += acct.brokerage_total;
total_option_delta += acct.option_value_delta;
}
// Grand totals
@ -1175,6 +1206,7 @@ fn displayResults(results: []const AccountComparison, color: bool, out: *std.Io.
var br_grand_buf: [24]u8 = undefined;
var grand_delta_buf: [24]u8 = undefined;
const grand_delta = total_brokerage - total_portfolio;
const grand_adj_delta = grand_delta - total_option_delta;
try cli.setBold(out, color);
try out.print(" Total: portfolio {s} brokerage {s}", .{
@ -1183,16 +1215,24 @@ fn displayResults(results: []const AccountComparison, color: bool, out: *std.Io.
});
try cli.reset(out, color);
if (@abs(grand_delta) < 1.0) {
if (@abs(grand_adj_delta) < 1.0) {
// no delta text needed
} else {
const sign: []const u8 = if (grand_delta >= 0) "+" else "-";
if (grand_delta >= 0) {
const sign: []const u8 = if (grand_adj_delta >= 0) "+" else "-";
if (grand_adj_delta >= 0) {
try cli.setFg(out, color, cli.CLR_NEGATIVE);
} else {
try cli.setFg(out, color, cli.CLR_POSITIVE);
}
try out.print(" delta {s}{s}", .{ sign, fmt.fmtMoneyAbs(&grand_delta_buf, @abs(grand_delta)) });
try out.print(" delta {s}{s}", .{ sign, fmt.fmtMoneyAbs(&grand_delta_buf, @abs(grand_adj_delta)) });
try cli.reset(out, color);
}
if (@abs(total_option_delta) >= 1.0) {
var opt_grand_buf: [24]u8 = undefined;
const opt_sign: []const u8 = if (total_option_delta >= 0) "+" else "-";
try cli.setFg(out, color, cli.CLR_MUTED);
try out.print(" (options {s}{s})", .{ opt_sign, fmt.fmtMoneyAbs(&opt_grand_buf, @abs(total_option_delta)) });
try cli.reset(out, color);
}
try out.print("\n", .{});