Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions tests/test_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6630,11 +6630,11 @@ def test_gross_exposure(self):
)
result = pd.DataFrame(
np.array([
[0.0, -0.010214494162927312, 0.010012024441354066],
[0.00200208256628545, -0.022821548354919067, 0.021830620581035857],
[0.0, -0.022821548354919067, 0.002949383274126105],
[0.0, -0.04241418126633477, 0.0],
[0.050155728521486365, -0.12017991413866216, 0.0]
[0.0, 0.01000999998999, 0.010012024441354066],
[0.00200208256628545, 0.021825370842812494, 0.021830620581035857],
[0.0, 0.021825370842812494, 0.002949383274126105],
[0.0, 0.03909759620159034, 0.0],
[0.050155728521486365, 0.09689116931945001, 0.0]
]),
index=price_na.index,
columns=price_na.columns
Expand All @@ -6651,23 +6651,23 @@ def test_gross_exposure(self):
pf_shared.gross_exposure(group_by=False),
pd.DataFrame(
np.array([
[0.0, -0.00505305454620791, 0.010012024441354066],
[0.0010005203706447724, -0.011201622483733716, 0.021830620581035857],
[0.0, -0.011201622483733716, 0.002949383274126105],
[0.0, -0.020585865497718882, 0.0],
[0.025038871596209537, -0.0545825965137659, 0.0]
[0.0, 0.0050024987481246875, 0.010012024441354066],
[0.0010005203706447724, 0.010956168751293576, 0.021830620581035857],
[0.0, 0.010956168751293576, 0.002949383274126105],
[0.0, 0.019771825228137207, 0.0],
[0.025038871596209537, 0.049210520540028384, 0.0]
]),
index=price_na.index,
columns=price_na.columns
)
)
result = pd.DataFrame(
np.array([
[-0.00505305454620791, 0.010012024441354066],
[-0.010188689433972452, 0.021830620581035857],
[-0.0112078992458765, 0.002949383274126105],
[-0.02059752492931316, 0.0],
[-0.027337628293439265, 0.0]
[0.0050024987481246875, 0.010012024441354066],
[0.011958382893456152, 0.021830620581035857],
[0.010962173376438594, 0.002949383274126105],
[0.019782580537729116, 0.0],
[0.07392874356988736, 0.0]
]),
index=price_na.index,
columns=pd.Index(['first', 'second'], dtype='object', name='group')
Expand Down Expand Up @@ -7268,7 +7268,7 @@ def test_stats(self):
np.array([
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
pd.Timedelta('5 days 00:00:00'), 100.0, 98.88877000000001, -1.11123, 283.3333333333333,
2.05906183131983, 0.42223000000000005, 1.6451238489727062, pd.Timedelta('3 days 08:00:00'),
5.629250614065742, 0.42223000000000005, 1.6451238489727062, pd.Timedelta('3 days 08:00:00'),
2.0, 1.3333333333333333, 0.6666666666666666, -1.5042060606060605, 33.333333333333336,
-98.38058805880588, -100.8038553855386, 143.91625412541256, -221.34645964596464,
pd.Timedelta('2 days 12:00:00'), pd.Timedelta('2 days 00:00:00'), np.inf, 0.10827272727272726,
Expand Down Expand Up @@ -7376,7 +7376,7 @@ def test_stats(self):
pd.Series(
np.array([
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
pd.Timedelta('5 days 00:00:00'), 200.0, 194.95809, -2.520955, 275.0, -0.505305454620791,
pd.Timedelta('5 days 00:00:00'), 200.0, 194.95809, -2.520955, 275.0, 7.392873929961589,
0.82091, 2.46248125751388, pd.Timedelta('4 days 00:00:00'), 4, 2, 2, -4.512618181818182,
0.0, -54.450495049504966, -388.2424242424243, np.nan, -221.34645964596461, pd.NaT,
pd.Timedelta('2 days 00:00:00'), 0.0, -0.2646459090909091, -20.095906945591288,
Expand Down
17 changes: 14 additions & 3 deletions vectorbt/portfolio/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4296,10 +4296,21 @@ def asset_value(self, direction: str = 'both', group_by: tp.GroupByLike = None,
@cached_method
def gross_exposure(self, direction: str = 'both', group_by: tp.GroupByLike = None,
wrap_kwargs: tp.KwargsLike = None) -> tp.SeriesFrame:
"""Get gross exposure."""
asset_value = to_2d_array(self.asset_value(group_by=group_by, direction=direction))
"""Get gross exposure.

Gross exposure is the sum of absolute position values divided by portfolio value.
For grouped portfolios with mixed long/short positions, per-column absolute values
are summed before dividing by group portfolio value."""
Comment thread
polakowo marked this conversation as resolved.
if self.wrapper.grouper.is_grouped(group_by=group_by):
# For grouped portfolios, we need sum(abs(per_column)) per group,
# not abs(sum(per_column)). The latter gives net exposure, not gross.
asset_value_ungrouped = to_2d_array(self.asset_value(group_by=False, direction=direction))
group_lens = self.wrapper.grouper.get_group_lens(group_by=group_by)
abs_asset_value = nb.asset_value_grouped_nb(np.abs(asset_value_ungrouped), group_lens)
else:
abs_asset_value = np.abs(to_2d_array(self.asset_value(group_by=group_by, direction=direction)))
cash = to_2d_array(self.cash(group_by=group_by, free=True))
gross_exposure = nb.gross_exposure_nb(asset_value, cash)
gross_exposure = nb.gross_exposure_nb(abs_asset_value, cash)
return self.wrapper.wrap(gross_exposure, group_by=group_by, **merge_dicts({}, wrap_kwargs))

@cached_method
Expand Down
Loading