Skip to content

fix: gross_exposure() uses abs(asset_value) for grouped portfolios#837

Merged
polakowo merged 1 commit intopolakowo:masterfrom
coryvirok:fix/gross-exposure-abs-grouped
Mar 26, 2026
Merged

fix: gross_exposure() uses abs(asset_value) for grouped portfolios#837
polakowo merged 1 commit intopolakowo:masterfrom
coryvirok:fix/gross-exposure-abs-grouped

Conversation

@coryvirok
Copy link
Copy Markdown
Contributor

Summary

  • gross_exposure() was computing net signed exposure instead of gross exposure for grouped portfolios with short positions
  • For short-only positions it returned negative values; for mixed long/short it could return wildly inflated values (e.g. 6000%+ when actual gross exposure was ~50%)
  • Root cause: grouped asset_value is the net sum across columns (longs - shorts), but gross exposure requires sum(abs(per_column_values))

Fix

In Portfolio.gross_exposure(), when group_by is active, compute abs() on per-column asset values before group aggregation, rather than using the net grouped asset value.

Test plan

  • Updated test_gross_exposure — all gross exposure values are now non-negative
  • Updated test_stats — hardcoded Max Gross Exposure [%] values corrected
  • test_net_exposure passes unchanged — net_exposure() correctly computes long_exposure - short_exposure
  • Full test suite: 930 passed, 0 failed

Fixes #836.

🤖 Generated with Claude Code

…with short positions

gross_exposure() was computing net signed exposure instead of gross
exposure for grouped portfolios. For short-only positions, it returned
negative values; for mixed long/short, it could return wildly inflated
values (e.g. 6000%+ when actual gross exposure was ~50%).

Root cause: when group_by is active, asset_value is the net sum of
per-column values (longs - shorts). For gross exposure, we need the
sum of absolute per-column values. The fix computes
abs(per-column asset values) before group aggregation.

The existing net_exposure() method is unaffected — it correctly
computes long_exposure - short_exposure from direction-filtered
gross_exposure calls.

Fixes polakowo#836.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Portfolio.gross_exposure() so grouped portfolios compute true gross exposure (sum of absolute per-column position values) rather than netting longs and shorts within each group, which previously produced negative and/or extreme values for mixed long/short groupings.

Changes:

  • Updated Portfolio.gross_exposure() to aggregate abs(asset_value) at the per-column level before grouping.
  • Updated test_gross_exposure expected outputs to ensure gross exposure is non-negative and matches the corrected computation.
  • Updated test_stats hardcoded Max Gross Exposure [%] values to reflect the corrected metric.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
vectorbt/portfolio/base.py Fixes grouped gross exposure by summing per-column absolute asset values before group aggregation.
tests/test_portfolio.py Updates expected outputs for gross exposure and derived stats to match corrected behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread vectorbt/portfolio/base.py
@polakowo polakowo self-requested a review March 26, 2026 21:14
@polakowo polakowo merged commit e4490cc into polakowo:master Mar 26, 2026
17 checks passed
@coryvirok
Copy link
Copy Markdown
Contributor Author

Great job, AIs! 👏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gross_exposure() uses signed asset_value instead of abs() for grouped portfolios with short positions

3 participants