Source code for portfolio_toolkit.position.compare_open_positions

from typing import List

import pandas as pd

from portfolio_toolkit.portfolio.portfolio import Portfolio
from portfolio_toolkit.utils.period import Period

from .get_open_positions import get_open_positions


[docs] def compare_open_positions( portfolio: Portfolio, periods: List[Period], display="value" ) -> pd.DataFrame: """ Compare open positions across multiple periods. Creates a DataFrame showing position values or returns at the end of each period. Rows represent assets, columns represent periods. Args: portfolio: Portfolio object containing assets periods: List of Period objects to compare display: 'value' shows position values, 'return' shows percentage returns Returns: pd.DataFrame: DataFrame with assets as rows and periods as columns. For 'value': Values show position market value, "-" for missing positions. For 'return': Values show percentage return vs previous period, "-" for missing/first period. Example: # Show values df = compare_open_positions(portfolio, periods, display='value') Result: Q1 2025 Q2 2025 AAPL 1500.00 1650.00 GOOGL 2000.00 - # Show returns df = compare_open_positions(portfolio, periods, display='return') Result: Q1 2025 Q2 2025 AAPL - 10.00% GOOGL - - """ if display not in ["value", "return"]: raise ValueError("display must be 'value' or 'return'") # Get positions for each period end date period_positions = {} all_assets = set() for period in periods: end_date_str = period.end_date.strftime("%Y-%m-%d") positions = get_open_positions(portfolio.assets, end_date_str) period_positions[period.label] = {pos.ticker: pos for pos in positions} all_assets.update(pos.ticker for pos in positions) # Create comparison data comparison_data = {} for asset in sorted(all_assets): if display == "value": asset_values = [] for period in periods: if asset in period_positions[period.label]: position = period_positions[period.label][asset] asset_values.append(f"{position.value:.2f}") else: asset_values.append("-") elif display == "return": asset_values = [] for i, period in enumerate(periods): if i == 0: # First period has no comparison asset_values.append("-") else: prev_period = periods[i - 1] current_period = period # Check if asset exists in both periods if ( asset in period_positions[prev_period.label] and asset in period_positions[current_period.label] ): prev_value = period_positions[prev_period.label][asset].value current_value = period_positions[current_period.label][ asset ].value if prev_value > 0: return_pct = ( (current_value - prev_value) / prev_value ) * 100 asset_values.append(f"{return_pct:.2f}%") else: asset_values.append("-") else: asset_values.append("-") comparison_data[asset] = asset_values # Create DataFrame period_labels = [period.label for period in periods] df = pd.DataFrame(comparison_data, index=period_labels).T return df