Skip to content

Commit cc88e39

Browse files
committed
Rename unrealized tax to pregnant, add combined after-tax value
Unrealized gains section now labeled "Pregnant STCG/LTCG" and "Total Pregnant Tax". YTD realized section labeled "YTD Realized Tax". After-Tax Value = Portfolio Value - Total Pregnant Tax - YTD Tax Remaining.
1 parent db9d160 commit cc88e39

File tree

3 files changed

+60
-50
lines changed

3 files changed

+60
-50
lines changed

cmd/ibctl/internal/command/holding/holdingoverview/holdingoverview.go

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,12 @@ type overviewJSON struct {
8585
Categories []*ibctlholdings.CategoryOverview `json:"categories"`
8686
// Geos is holdings aggregated by geographic classification.
8787
Geos []*ibctlholdings.GeoOverview `json:"geos"`
88-
// Value is the portfolio value summary with tax impact.
88+
// Value is the portfolio value summary with pregnant (unrealized) tax impact.
8989
Value *valueJSON `json:"value"`
9090
// YTDTax is the YTD realized income tax summary.
9191
YTDTax *ytdTaxJSON `json:"ytd_tax"`
92+
// AfterTaxMicros is the after-tax portfolio value (portfolio - pregnant tax - YTD tax remaining).
93+
AfterTaxMicros int64 `json:"after_tax_micros"`
9294
}
9395

9496
// ytdTaxJSON is the YTD realized income tax summary for JSON output.
@@ -125,22 +127,20 @@ type ytdTaxJSON struct {
125127
TaxRateLTCG float64 `json:"tax_rate_ltcg"`
126128
}
127129

128-
// valueJSON is the portfolio value summary for JSON output.
130+
// valueJSON is the portfolio value summary with pregnant (unrealized) tax for JSON output.
129131
type valueJSON struct {
130132
// PortfolioValueMicros is the total portfolio market value in micros.
131133
PortfolioValueMicros int64 `json:"portfolio_value_micros"`
132-
// STCGMicros is the total short-term capital gains in micros.
133-
STCGMicros int64 `json:"stcg_micros"`
134-
// STCGTaxMicros is the estimated short-term capital gains tax in micros.
135-
STCGTaxMicros int64 `json:"stcg_tax_micros"`
136-
// LTCGMicros is the total long-term capital gains in micros.
137-
LTCGMicros int64 `json:"ltcg_micros"`
138-
// LTCGTaxMicros is the estimated long-term capital gains tax in micros.
139-
LTCGTaxMicros int64 `json:"ltcg_tax_micros"`
140-
// TotalTaxMicros is the total estimated tax in micros.
141-
TotalTaxMicros int64 `json:"total_tax_micros"`
142-
// AfterTaxMicros is the after-tax portfolio value in micros.
143-
AfterTaxMicros int64 `json:"after_tax_micros"`
134+
// PregnantSTCGMicros is the total pregnant (unrealized) short-term capital gains in micros.
135+
PregnantSTCGMicros int64 `json:"pregnant_stcg_micros"`
136+
// PregnantSTCGTaxMicros is the estimated pregnant short-term capital gains tax in micros.
137+
PregnantSTCGTaxMicros int64 `json:"pregnant_stcg_tax_micros"`
138+
// PregnantLTCGMicros is the total pregnant (unrealized) long-term capital gains in micros.
139+
PregnantLTCGMicros int64 `json:"pregnant_ltcg_micros"`
140+
// PregnantLTCGTaxMicros is the estimated pregnant long-term capital gains tax in micros.
141+
PregnantLTCGTaxMicros int64 `json:"pregnant_ltcg_tax_micros"`
142+
// TotalPregnantTaxMicros is the total estimated pregnant (unrealized) tax in micros.
143+
TotalPregnantTaxMicros int64 `json:"total_pregnant_tax_micros"`
144144
// TaxRateSTCG is the short-term capital gains tax rate from config.
145145
TaxRateSTCG float64 `json:"tax_rate_stcg"`
146146
// TaxRateLTCG is the long-term capital gains tax rate from config.
@@ -200,6 +200,9 @@ func run(ctx context.Context, container appext.Container, flags *flags) error {
200200
fmt.Fprintln(writer)
201201
// Section 5: YTD realized income tax summary.
202202
ibctlcmd.WriteYTDTaxSummary(writer, ytdSummary, data.Config, formatBaseMicros)
203+
fmt.Fprintln(writer)
204+
// Section 6: combined after-tax value.
205+
ibctlcmd.WriteAfterTaxValue(writer, summary, ytdSummary, formatBaseMicros)
203206
return nil
204207
case cliio.FormatCSV:
205208
// Section 1: holding list CSV.
@@ -222,23 +225,27 @@ func run(ctx context.Context, container appext.Container, flags *flags) error {
222225
fmt.Fprintln(writer)
223226
// Section 5: YTD realized income tax summary.
224227
ibctlcmd.WriteYTDTaxSummary(writer, ytdSummary, data.Config, formatBaseMicros)
228+
fmt.Fprintln(writer)
229+
// Section 6: combined after-tax value.
230+
ibctlcmd.WriteAfterTaxValue(writer, summary, ytdSummary, formatBaseMicros)
225231
return nil
226232
case cliio.FormatJSON:
227233
// Combined JSON object with all five sections.
234+
// Compute combined after-tax value for JSON output.
235+
afterTaxMicros := summary.TotalValueMicros - summary.TotalTaxMicros - ytdSummary.TaxRemainingMicros
228236
overview := &overviewJSON{
229237
Holdings: result.Holdings,
230238
Categories: categories,
231239
Geos: geos,
232240
Value: &valueJSON{
233-
PortfolioValueMicros: summary.TotalValueMicros,
234-
STCGMicros: summary.TotalSTCGMicros,
235-
STCGTaxMicros: summary.STCGTaxMicros,
236-
LTCGMicros: summary.TotalLTCGMicros,
237-
LTCGTaxMicros: summary.LTCGTaxMicros,
238-
TotalTaxMicros: summary.TotalTaxMicros,
239-
AfterTaxMicros: summary.AfterTaxMicros,
240-
TaxRateSTCG: data.Config.TaxRateSTCG,
241-
TaxRateLTCG: data.Config.TaxRateLTCG,
241+
PortfolioValueMicros: summary.TotalValueMicros,
242+
PregnantSTCGMicros: summary.TotalSTCGMicros,
243+
PregnantSTCGTaxMicros: summary.STCGTaxMicros,
244+
PregnantLTCGMicros: summary.TotalLTCGMicros,
245+
PregnantLTCGTaxMicros: summary.LTCGTaxMicros,
246+
TotalPregnantTaxMicros: summary.TotalTaxMicros,
247+
TaxRateSTCG: data.Config.TaxRateSTCG,
248+
TaxRateLTCG: data.Config.TaxRateLTCG,
242249
},
243250
YTDTax: &ytdTaxJSON{
244251
DividendMicros: ytdSummary.DividendMicros,
@@ -257,6 +264,7 @@ func run(ctx context.Context, container appext.Container, flags *flags) error {
257264
TaxRateSTCG: data.Config.TaxRateSTCG,
258265
TaxRateLTCG: data.Config.TaxRateLTCG,
259266
},
267+
AfterTaxMicros: afterTaxMicros,
260268
}
261269
jsonData, err := json.Marshal(overview)
262270
if err != nil {

cmd/ibctl/internal/command/holding/holdingvalue/holdingvalue.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,7 @@ func run(ctx context.Context, container appext.Container, flags *flags) error {
103103
}
104104
fmt.Fprintln(os.Stdout)
105105
ibctlcmd.WriteYTDTaxSummary(os.Stdout, ytdSummary, data.Config, formatBaseMicros)
106+
fmt.Fprintln(os.Stdout)
107+
ibctlcmd.WriteAfterTaxValue(os.Stdout, summary, ytdSummary, formatBaseMicros)
106108
return nil
107109
}

cmd/ibctl/internal/ibctlcmd/holdingsdata.go

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,8 @@ type ValueSummary struct {
191191
TotalLTCGMicros int64
192192
// LTCGTaxMicros is the estimated long-term capital gains tax in micros.
193193
LTCGTaxMicros int64
194-
// TotalTaxMicros is the total estimated tax in micros.
194+
// TotalTaxMicros is the total estimated pregnant (unrealized) tax in micros.
195195
TotalTaxMicros int64
196-
// AfterTaxMicros is the after-tax portfolio value in micros.
197-
AfterTaxMicros int64
198196
}
199197

200198
// YTDTaxSummary holds computed YTD realized income and capital gains tax amounts.
@@ -236,16 +234,13 @@ func ComputeValueSummary(holdings []*ibctlholdings.HoldingOverview, config *ibct
236234
stcgTaxMicros := int64(math.Round(float64(totalSTCGMicros) * config.TaxRateSTCG))
237235
ltcgTaxMicros := int64(math.Round(float64(totalLTCGMicros) * config.TaxRateLTCG))
238236
totalTaxMicros := stcgTaxMicros + ltcgTaxMicros
239-
// After-tax value = portfolio value - total taxes.
240-
afterTaxMicros := totalValueMicros - totalTaxMicros
241237
return &ValueSummary{
242238
TotalValueMicros: totalValueMicros,
243239
TotalSTCGMicros: totalSTCGMicros,
244240
STCGTaxMicros: stcgTaxMicros,
245241
TotalLTCGMicros: totalLTCGMicros,
246242
LTCGTaxMicros: ltcgTaxMicros,
247243
TotalTaxMicros: totalTaxMicros,
248-
AfterTaxMicros: afterTaxMicros,
249244
}
250245
}
251246

@@ -306,35 +301,40 @@ func ComputeYTDTaxSummary(
306301
}, nil
307302
}
308303

309-
// WriteValueSummary writes the portfolio value summary as formatted text.
304+
// WriteValueSummary writes the portfolio value summary with pregnant (unrealized) tax as formatted text.
310305
func WriteValueSummary(writer io.Writer, summary *ValueSummary, config *ibctlconfig.Config, formatBaseMicros func(int64) string) {
311-
fmt.Fprintf(writer, "Portfolio Value: %s\n", formatBaseMicros(summary.TotalValueMicros))
306+
fmt.Fprintf(writer, "Portfolio Value: %s\n", formatBaseMicros(summary.TotalValueMicros))
312307
fmt.Fprintf(writer, "\n")
313-
fmt.Fprintf(writer, "STCG: %s\n", formatBaseMicros(summary.TotalSTCGMicros))
314-
fmt.Fprintf(writer, "STCG Tax (%.1f%%): %s\n", config.TaxRateSTCG*100, formatBaseMicros(summary.STCGTaxMicros))
315-
fmt.Fprintf(writer, "LTCG: %s\n", formatBaseMicros(summary.TotalLTCGMicros))
316-
fmt.Fprintf(writer, "LTCG Tax (%.1f%%): %s\n", config.TaxRateLTCG*100, formatBaseMicros(summary.LTCGTaxMicros))
317-
fmt.Fprintf(writer, "Total Tax: %s\n", formatBaseMicros(summary.TotalTaxMicros))
318-
fmt.Fprintf(writer, "\n")
319-
fmt.Fprintf(writer, "After-Tax Value: %s\n", formatBaseMicros(summary.AfterTaxMicros))
308+
fmt.Fprintf(writer, "Pregnant STCG: %s\n", formatBaseMicros(summary.TotalSTCGMicros))
309+
fmt.Fprintf(writer, "Pregnant STCG Tax (%.1f%%): %s\n", config.TaxRateSTCG*100, formatBaseMicros(summary.STCGTaxMicros))
310+
fmt.Fprintf(writer, "Pregnant LTCG: %s\n", formatBaseMicros(summary.TotalLTCGMicros))
311+
fmt.Fprintf(writer, "Pregnant LTCG Tax (%.1f%%): %s\n", config.TaxRateLTCG*100, formatBaseMicros(summary.LTCGTaxMicros))
312+
fmt.Fprintf(writer, "Total Pregnant Tax: %s\n", formatBaseMicros(summary.TotalTaxMicros))
320313
}
321314

322315
// WriteYTDTaxSummary writes the YTD realized income tax summary as formatted text.
323316
func WriteYTDTaxSummary(writer io.Writer, summary *YTDTaxSummary, config *ibctlconfig.Config, formatBaseMicros func(int64) string) {
324-
fmt.Fprintf(writer, "YTD Realized Income Tax:\n")
317+
fmt.Fprintf(writer, "YTD Realized Tax:\n")
325318
fmt.Fprintf(writer, "\n")
326-
fmt.Fprintf(writer, "Dividends: %s\n", formatBaseMicros(summary.DividendMicros))
327-
fmt.Fprintf(writer, "Dividend Tax (%.1f%%): %s\n", config.TaxRateDividend*100, formatBaseMicros(summary.DividendTaxMicros))
328-
fmt.Fprintf(writer, "Interest: %s\n", formatBaseMicros(summary.InterestMicros))
329-
fmt.Fprintf(writer, "Interest Tax (%.1f%%): %s\n", config.TaxRateInterest*100, formatBaseMicros(summary.InterestTaxMicros))
330-
fmt.Fprintf(writer, "Realized STCG: %s\n", formatBaseMicros(summary.STCGMicros))
331-
fmt.Fprintf(writer, "STCG Tax (%.1f%%): %s\n", config.TaxRateSTCG*100, formatBaseMicros(summary.STCGTaxMicros))
332-
fmt.Fprintf(writer, "Realized LTCG: %s\n", formatBaseMicros(summary.LTCGMicros))
333-
fmt.Fprintf(writer, "LTCG Tax (%.1f%%): %s\n", config.TaxRateLTCG*100, formatBaseMicros(summary.LTCGTaxMicros))
319+
fmt.Fprintf(writer, "Dividends: %s\n", formatBaseMicros(summary.DividendMicros))
320+
fmt.Fprintf(writer, "Dividend Tax (%.1f%%): %s\n", config.TaxRateDividend*100, formatBaseMicros(summary.DividendTaxMicros))
321+
fmt.Fprintf(writer, "Interest: %s\n", formatBaseMicros(summary.InterestMicros))
322+
fmt.Fprintf(writer, "Interest Tax (%.1f%%): %s\n", config.TaxRateInterest*100, formatBaseMicros(summary.InterestTaxMicros))
323+
fmt.Fprintf(writer, "Realized STCG: %s\n", formatBaseMicros(summary.STCGMicros))
324+
fmt.Fprintf(writer, "STCG Tax (%.1f%%): %s\n", config.TaxRateSTCG*100, formatBaseMicros(summary.STCGTaxMicros))
325+
fmt.Fprintf(writer, "Realized LTCG: %s\n", formatBaseMicros(summary.LTCGMicros))
326+
fmt.Fprintf(writer, "LTCG Tax (%.1f%%): %s\n", config.TaxRateLTCG*100, formatBaseMicros(summary.LTCGTaxMicros))
334327
fmt.Fprintf(writer, "\n")
335-
fmt.Fprintf(writer, "Total Tax Owed: %s\n", formatBaseMicros(summary.TotalTaxOwedMicros))
336-
fmt.Fprintf(writer, "Tax Paid: %s\n", formatBaseMicros(summary.TaxPaidMicros))
337-
fmt.Fprintf(writer, "Tax Remaining: %s\n", formatBaseMicros(summary.TaxRemainingMicros))
328+
fmt.Fprintf(writer, "YTD Tax Owed: %s\n", formatBaseMicros(summary.TotalTaxOwedMicros))
329+
fmt.Fprintf(writer, "YTD Tax Paid: %s\n", formatBaseMicros(summary.TaxPaidMicros))
330+
fmt.Fprintf(writer, "YTD Tax Remaining: %s\n", formatBaseMicros(summary.TaxRemainingMicros))
331+
}
332+
333+
// WriteAfterTaxValue writes the combined after-tax portfolio value.
334+
// After-tax value = portfolio value - pregnant tax - YTD tax remaining.
335+
func WriteAfterTaxValue(writer io.Writer, valueSummary *ValueSummary, ytdSummary *YTDTaxSummary, formatBaseMicros func(int64) string) {
336+
afterTaxMicros := valueSummary.TotalValueMicros - valueSummary.TotalTaxMicros - ytdSummary.TaxRemainingMicros
337+
fmt.Fprintf(writer, "After-Tax Value: %s\n", formatBaseMicros(afterTaxMicros))
338338
}
339339

340340
// WriteHoldingListTable writes the holding list as a table with securities,

0 commit comments

Comments
 (0)