Portfolio API Reference¶
The portfolio package handles portfolio construction, strategies, and constraints.
Overview¶
The portfolio package contains:
- Strategies - Portfolio allocation strategies
- Constraints - Portfolio constraints and limits
- Membership - Membership policy for turnover control
- Cardinality - Cardinality constraint interfaces
Portfolio Package¶
portfolio_management.portfolio
¶
A comprehensive suite for systematic portfolio construction and management.
This package provides a modular framework for building, optimizing, and analyzing investment portfolios. It includes a variety of weighting strategies, constraint management, and rebalancing logic, designed for both research and production environments.
Key Components
- PortfolioConstructor: The main entry point for building portfolios. It acts as a factory for different portfolio strategies.
- PortfolioStrategy: An interface for all portfolio construction strategies,
with concrete implementations like
EqualWeightStrategy,MeanVarianceStrategy, andRiskParityStrategy. - PortfolioConstraints: A data class to define investment constraints such as min/max weights, asset class exposure limits, and more.
- CardinalityConstraints: A data class for advanced constraints on the number of assets in a portfolio.
- RebalanceConfig: Configuration for defining rebalancing frequency and tolerance.
Usage Example
import pandas as pd from portfolio_management.portfolio import PortfolioConstructor, PortfolioConstraints
import numpy as np
1. Define returns data¶
np.random.seed(42) returns = pd.DataFrame({ ... "asset1": np.random.normal(0, 0.01, 30), ... "asset2": np.random.normal(0, 0.02, 30), ... "asset3": np.random.normal(0, 0.03, 30), ... })
2. Define constraints¶
constraints = PortfolioConstraints(max_weight=0.5, require_full_investment=True)
3. Initialize the constructor and build a portfolio¶
from portfolio_management.portfolio.strategies.mean_variance import MeanVarianceStrategy constructor = PortfolioConstructor(constraints=constraints)
The default min_periods for MeanVarianceStrategy is 252. We override it for the example.¶
constructor.register_strategy( ... "mean_variance_min_vol", ... MeanVarianceStrategy(objective="min_volatility", min_periods=30) ... ) portfolio = constructor.construct( ... strategy_name="mean_variance_min_vol", ... returns=returns ... )
4. View the resulting weights (exact values depend on random data)¶
print(portfolio.weights.sum().round(2)) 1.0
PortfolioConstructor
¶
Coordinates portfolio strategy selection and construction.
This class acts as a factory for portfolio construction, allowing users to
register different PortfolioStrategy implementations and then construct
portfolios by referencing their registered names. It simplifies the process
of comparing different strategies under the same constraints.
It comes with several common strategies pre-registered, such as equal weight, minimum volatility, and maximum Sharpe ratio.
Attributes:
| Name | Type | Description |
|---|---|---|
_default_constraints |
PortfolioConstraints
|
Default constraints to apply if none are provided during construction. |
_strategies |
dict[str, PortfolioStrategy]
|
A registry of available portfolio construction strategies. |
Example
import pandas as pd from portfolio_management.portfolio import ( ... PortfolioConstructor, PortfolioConstraints ... )
import numpy as np np.random.seed(42) returns = pd.DataFrame({ ... 'ASSET_A': np.random.normal(0, 0.01, 30), ... 'ASSET_B': np.random.normal(0, 0.02, 30), ... })
Initialize with default constraints¶
constraints = PortfolioConstraints(max_weight=0.7) from portfolio_management.portfolio.strategies.mean_variance import MeanVarianceStrategy constructor = PortfolioConstructor(constraints=constraints)
The default min_periods for MeanVarianceStrategy is 252. We override it for the example.¶
constructor.register_strategy( ... "mean_variance_min_vol", ... MeanVarianceStrategy(objective="min_volatility", min_periods=30) ... )
Construct a minimum volatility portfolio¶
portfolio = constructor.construct("mean_variance_min_vol", returns)
The exact weights will vary, but the sum should be 1.0¶
print(portfolio.weights.sum().round(2)) 1.0
Compare multiple strategies¶
comparison = constructor.compare_strategies( ... ["equal_weight", "mean_variance_min_vol"], ... returns ... )
The exact weights will vary, but the sums should be 1.0¶
print(comparison.sum().round(2)) equal_weight 1.0 mean_variance_min_vol 1.0 dtype: float64
Source code in src/portfolio_management/portfolio/builder.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
register_strategy(name, strategy)
¶
Register a strategy implementation under the provided name.
list_strategies()
¶
construct(strategy_name, returns, constraints=None, asset_classes=None)
¶
Construct a portfolio using the requested strategy.
Source code in src/portfolio_management/portfolio/builder.py
compare_strategies(strategy_names, returns, constraints=None, asset_classes=None)
¶
Construct and compare multiple strategies.
Source code in src/portfolio_management/portfolio/builder.py
CardinalityNotImplementedError
¶
Bases: NotImplementedError
Raised when attempting to use unimplemented cardinality methods.
This exception is raised when a cardinality constraint method other than PRESELECTION is specified but not yet implemented. This is expected behavior for design stubs.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
The cardinality method that was attempted |
|
message |
Descriptive error message with implementation guidance |
Source code in src/portfolio_management/portfolio/cardinality.py
CardinalityConstraints
dataclass
¶
Defines constraints on the number of assets in a portfolio.
Cardinality constraints limit the number of non-zero positions, which is critical for managing transaction costs, improving liquidity, and adhering to fund mandates that limit the number of holdings.
Mathematical Formulation
Let w ∈ ℝⁿ be the portfolio weights and z ∈ {0,1}ⁿ be binary indicators where zᵢ = 1 if asset i is included in the portfolio, and 0 otherwise.
-
Position Limit: min_assets ≤ Σᵢ zᵢ ≤ max_assets
-
Linking weights and indicators: min_position_size * zᵢ ≤ wᵢ ≤ max_weight * zᵢ
This formulation requires a Mixed-Integer Programming (MIP) solver.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether cardinality constraints are active. |
method |
CardinalityMethod
|
The method for enforcing cardinality. 'preselection' is the default and filters assets before optimization. Other methods like 'miqp' integrate constraints into the optimizer. |
max_assets |
int | None
|
Maximum number of non-zero positions. |
min_position_size |
float
|
The minimum weight for any non-zero position. |
group_limits |
dict[str, int] | None
|
A dictionary mapping asset groups to the maximum number of positions allowed in that group. |
enforce_in_optimizer |
bool
|
If True, integrates the constraints directly into the optimization problem, which requires a MIP-capable solver. Defaults to False, relying on pre-selection. |
Configuration Example (YAML):
cardinality:
enabled: true
method: preselection
max_assets: 50
min_position_size: 0.015
group_limits:
equity: 40
alternatives: 5
Performance Notes
preselection: Very fast, suitable for all optimizers. Sub-optimal as it doesn't consider correlations during selection.miqp: Provides the optimal solution but is computationally expensive (NP-hard) and requires a specialized solver (e.g., Gurobi, CBC). Complexity scales exponentially with the number of assets.
Source code in src/portfolio_management/portfolio/constraints/models.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
CardinalityMethod
¶
Bases: str, Enum
Methods for handling cardinality constraints in optimization.
Attributes:
| Name | Type | Description |
|---|---|---|
PRESELECTION |
Use factor-based preselection before optimization (current default) |
|
MIQP |
Mixed-Integer Quadratic Programming (future: requires commercial solver) |
|
HEURISTIC |
Iterative heuristic approach (future: custom implementation) |
|
RELAXATION |
Continuous relaxation with post-processing (future) |
Source code in src/portfolio_management/portfolio/constraints/models.py
PortfolioConstraints
dataclass
¶
Defines basic investment constraints and guardrails for a portfolio.
This data class holds common constraints that can be applied during the optimization process to ensure the portfolio meets diversification and exposure mandates.
Attributes:
| Name | Type | Description |
|---|---|---|
max_weight |
float
|
Maximum weight for any single asset. |
min_weight |
float
|
Minimum weight for any single asset. |
max_equity_exposure |
float
|
Maximum total allocation to equity assets. |
min_bond_exposure |
float
|
Minimum total allocation to bond/cash assets. |
sector_limits |
dict[str, float] | None
|
A dictionary mapping sector names to their maximum allowed weight in the portfolio. |
require_full_investment |
bool
|
If True, forces the sum of all asset weights to equal 1.0. |
Configuration Example (YAML):
constraints:
max_weight: 0.15
min_weight: 0.01
max_equity_exposure: 0.80
sector_limits:
Technology: 0.30
Healthcare: 0.25
require_full_investment: true
Source code in src/portfolio_management/portfolio/constraints/models.py
MembershipPolicy
dataclass
¶
Configuration for membership policy rules.
This dataclass defines the rules that control how asset membership changes during portfolio rebalancing. Policies are applied in a specific order to ensure stability while respecting selection criteria.
Application order
- Min holding period: protect assets from premature exit
- Rank buffer: keep existing holdings unless they fall far out of favor
- Max changes: limit the number of additions/removals per rebalance
- Turnover cap: limit the fraction of portfolio value that can change
Attributes:
| Name | Type | Description |
|---|---|---|
buffer_rank |
int | None
|
Assets currently held are kept if their rank is better than this threshold, even if they fall outside top_k. For example, if top_k=30 and buffer_rank=50, existing holdings ranked 31-50 will be retained. Set to None to disable buffer. Default: None. |
min_holding_periods |
int | None
|
Minimum number of rebalance periods an asset must be held before it can be removed. Set to None or 0 to disable. Default: None. |
max_turnover |
float | None
|
Maximum fraction of portfolio value that can change in a single rebalance (0.0 to 1.0). Calculated as sum of absolute weight changes. Set to None to disable. Default: None. |
max_new_assets |
int | None
|
Maximum number of new assets that can be added in a single rebalance. Set to None to disable. Default: None. |
max_removed_assets |
int | None
|
Maximum number of assets that can be removed in a single rebalance. Set to None to disable. Default: None. |
enabled |
bool
|
Master switch to enable/disable all policy rules. Default: True. |
Example
Conservative policy: limit churn¶
policy = MembershipPolicy( ... buffer_rank=50, ... min_holding_periods=3, ... max_new_assets=5, ... max_removed_assets=5 ... )
Aggressive policy: more freedom to rebalance¶
policy = MembershipPolicy( ... buffer_rank=35, ... min_holding_periods=1, ... max_turnover=0.50, ... max_new_assets=10, ... max_removed_assets=10 ... )
Disabled policy¶
policy = MembershipPolicy(enabled=False)
Source code in src/portfolio_management/portfolio/membership.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | |
validate()
¶
Validate policy parameters.
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If any parameter is invalid. |
Source code in src/portfolio_management/portfolio/membership.py
default()
classmethod
¶
Create a default membership policy suitable for most portfolios.
Returns:
| Type | Description |
|---|---|
MembershipPolicy
|
MembershipPolicy with moderate defaults: |
MembershipPolicy
|
|
MembershipPolicy
|
|
MembershipPolicy
|
|
MembershipPolicy
|
|
MembershipPolicy
|
|
Example
policy = MembershipPolicy.default() policy.min_holding_periods 3
Source code in src/portfolio_management/portfolio/membership.py
disabled()
classmethod
¶
Create a disabled membership policy (no restrictions).
Returns:
| Type | Description |
|---|---|
MembershipPolicy
|
MembershipPolicy with enabled=False. |
Example
policy = MembershipPolicy.disabled() policy.enabled False
Source code in src/portfolio_management/portfolio/membership.py
Portfolio
dataclass
¶
Represents a constructed portfolio with weights and metadata.
Attributes:
| Name | Type | Description |
|---|---|---|
weights |
Series
|
Series mapping ticker symbols to portfolio weights |
strategy |
str
|
Name of the strategy used to construct the portfolio |
timestamp |
Timestamp
|
When the portfolio was constructed |
metadata |
dict[str, object] | None
|
Optional dict with strategy-specific information |
Source code in src/portfolio_management/portfolio/models.py
StrategyType
¶
Bases: str, Enum
Supported portfolio construction strategies.
Source code in src/portfolio_management/portfolio/models.py
Preselection
¶
Factor-based asset preselection engine.
Computes momentum and/or low-volatility factors from historical returns and selects top-K assets deterministically without lookahead bias.
Supports optional caching to avoid recomputing factor scores across runs.
Source code in src/portfolio_management/portfolio/preselection.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | |
select_assets(returns, rebalance_date=None)
¶
Select top-K assets based on configured factors.
Uses only data available up to (but not including) rebalance_date. If rebalance_date is None, uses all available data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame with returns (assets as columns, dates as index) |
required |
rebalance_date
|
date | None
|
Date of rebalancing (uses data strictly before this) |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of selected asset tickers (sorted alphabetically for determinism) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If returns DataFrame is invalid |
InsufficientDataError
|
If insufficient data for factor calculation |
Examples:
>>> from datetime import date
>>> import pandas as pd
>>> import numpy as np
>>> np.random.seed(42)
>>> returns = pd.DataFrame({
... 'ASSET1': np.random.normal(0, 0.01, 60),
... 'ASSET2': np.random.normal(0, 0.02, 60),
... 'ASSET3': np.random.normal(0, 0.03, 60)
... }, index=pd.date_range(end='2022-12-30', periods=60))
>>> config = PreselectionConfig(method=PreselectionMethod.MOMENTUM, top_k=2, min_periods=30)
>>> preselect = Preselection(config)
>>> selected = preselect.select_assets(returns, rebalance_date=date(2022, 12, 30))
Source code in src/portfolio_management/portfolio/preselection.py
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | |
PreselectionConfig
dataclass
¶
Configuration for asset preselection.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
PreselectionMethod
|
Preselection method to use |
top_k |
int | None
|
Number of assets to select (if None or 0, no preselection) |
lookback |
int
|
Number of periods to look back for factor calculation |
skip |
int
|
Number of most recent periods to skip (for momentum) |
momentum_weight |
float
|
Weight for momentum factor (when using combined) |
low_vol_weight |
float
|
Weight for low-volatility factor (when using combined) |
min_periods |
int
|
Minimum number of periods required for valid calculation |
Source code in src/portfolio_management/portfolio/preselection.py
PreselectionMethod
¶
RebalanceConfig
dataclass
¶
Specifies the rules and costs for portfolio rebalancing.
This data class defines the parameters that govern when and how a portfolio should be rebalanced. It supports both calendar-based (frequency) and drift-based (tolerance bands) rebalancing triggers.
Attributes:
| Name | Type | Description |
|---|---|---|
frequency |
int
|
The calendar-based rebalance frequency in days (e.g., 30 for monthly, 90 for quarterly). |
tolerance_bands |
float
|
The maximum allowed drift for a position's weight (as a percentage of target weight) before triggering a rebalance. For example, 0.20 means a 20% drift is allowed. |
min_trade_size |
float
|
The minimum trade size as a fraction of the total portfolio value. Trades smaller than this will be suppressed to avoid incurring excessive transaction costs for minor adjustments. |
cost_per_trade |
float
|
The estimated transaction cost as a percentage of the trade value (e.g., 0.001 for 10 basis points). |
Configuration Example (YAML):
rebalancing:
frequency: 90 # Quarterly rebalance
tolerance_bands: 0.15 # 15% drift tolerance
min_trade_size: 0.005 # 0.5% of portfolio
cost_per_trade: 0.0005 # 5 bps
Source code in src/portfolio_management/portfolio/rebalancing/config.py
StatisticsCache
¶
Caches covariance matrices and expected returns.
This class maintains cached covariance matrices and expected returns that can be incrementally updated when new data is added, significantly improving performance for large universes with overlapping data windows (e.g., monthly rebalances).
The cache is automatically invalidated when: - The asset set changes (different tickers) - The lookback window changes - The data window shifts beyond the cache validity
Attributes:
| Name | Type | Description |
|---|---|---|
window_size |
Number of periods for the rolling window (default: 252) |
|
annualization_factor |
Factor to annualize statistics (default: 252) |
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | |
get_covariance_matrix(returns, annualize=True)
¶
Compute or retrieve cached covariance matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame of returns (dates as index, tickers as columns) |
required |
annualize
|
bool
|
Whether to annualize the covariance matrix |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Covariance matrix as DataFrame |
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
get_expected_returns(returns, annualize=True)
¶
Compute or retrieve cached expected returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame of returns (dates as index, tickers as columns) |
required |
annualize
|
bool
|
Whether to annualize the expected returns |
True
|
Returns:
| Type | Description |
|---|---|
Series
|
Expected returns as Series |
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
get_statistics(returns, annualize=True)
¶
Compute or retrieve both expected returns and covariance matrix.
This is more efficient than calling get_expected_returns and get_covariance_matrix separately as it computes both in one pass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame of returns (dates as index, tickers as columns) |
required |
annualize
|
bool
|
Whether to annualize the statistics |
True
|
Returns:
| Type | Description |
|---|---|
tuple[Series, DataFrame]
|
Tuple of (expected_returns, covariance_matrix) |
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
clear_cache()
¶
Clear all cached statistics.
Primarily for testing to ensure test isolation.
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
get_cache_stats()
¶
Get cache statistics.
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
Dictionary with covariance_entries and returns_entries. |
Source code in src/portfolio_management/portfolio/statistics/rolling_statistics.py
EqualWeightStrategy
¶
Bases: PortfolioStrategy
Implements the equal-weight (1/N) portfolio construction strategy.
This strategy assigns an equal weight to every asset in the investment universe. It is a simple, transparent, and computationally inexpensive approach that serves as a common benchmark.
The main assumption is that there is no information available to suggest that any single asset will outperform another.
Mathematical Formulation
Given N assets in the portfolio, the weight for each asset i is: wᵢ = 1 / N
This strategy does not perform any optimization and only considers the number
of available assets. It will, however, validate the resulting portfolio
against basic constraints (e.g., max_weight).
Example
import pandas as pd from portfolio_management.portfolio.strategies import EqualWeightStrategy from portfolio_management.portfolio.constraints import PortfolioConstraints
returns = pd.DataFrame({ ... 'ASSET_A': [0.01, 0.02], ... 'ASSET_B': [0.03, -0.01], ... 'ASSET_C': [0.02, 0.01], ... 'ASSET_D': [-0.01, 0.01], ... })
strategy = EqualWeightStrategy() constraints = PortfolioConstraints(max_weight=0.3) portfolio = strategy.construct(returns, constraints)
print(portfolio.weights) ASSET_A 0.25 ASSET_B 0.25 ASSET_C 0.25 ASSET_D 0.25 dtype: float64
Source code in src/portfolio_management/portfolio/strategies/equal_weight.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |
name
property
¶
Return the strategy name.
min_history_periods
property
¶
Return minimum number of return periods required.
construct(returns, constraints, asset_classes=None)
¶
Construct an equal-weight portfolio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame with returns (assets as columns, dates as index) |
required |
constraints
|
PortfolioConstraints
|
Portfolio constraints to enforce |
required |
asset_classes
|
Series | None
|
Optional Series mapping tickers to asset classes |
None
|
Returns:
| Type | Description |
|---|---|
Portfolio
|
Portfolio with equal weights, adjusted for constraints |
Raises:
| Type | Description |
|---|---|
InsufficientDataError
|
If returns DataFrame is empty |
ConstraintViolationError
|
If equal weighting violates constraints |
Source code in src/portfolio_management/portfolio/strategies/equal_weight.py
MeanVarianceStrategy
¶
Bases: PortfolioStrategy
Constructs a portfolio using mean-variance optimization (MVO).
This strategy leverages the PyPortfolioOpt library to find the optimal asset allocation that balances risk (variance) and return. It is a cornerstone of modern portfolio theory.
Mathematical Formulation
The core of MVO is a quadratic optimization problem. For an objective like 'max_sharpe', the optimizer solves:
maximize: (w.T * μ - r_f) / sqrt(w.T * Σ * w) subject to: Σw = 1 (or other constraints) w_i >= 0 (long-only)
where: - w: portfolio weights vector - μ: expected returns vector - Σ: covariance matrix of asset returns - r_f: risk-free rate
Supported Objectives
max_sharpe: Finds the tangency portfolio with the highest Sharpe ratio.min_volatility: Finds the portfolio with the minimum possible risk.efficient_risk: Finds the portfolio on the efficient frontier for a given target risk level.
Example
import pandas as pd from portfolio_management.portfolio.strategies import MeanVarianceStrategy from portfolio_management.portfolio.constraints import PortfolioConstraints
import numpy as np returns = pd.DataFrame({ ... 'STABLE_ASSET': np.random.normal(0.001, 0.01, 252), ... 'GROWTH_ASSET': np.random.normal(0.005, 0.05, 252), ... })
Find the portfolio that minimizes volatility¶
strategy = MeanVarianceStrategy(objective="min_volatility", min_periods=30) constraints = PortfolioConstraints(min_weight=0.1, max_weight=0.9) portfolio = strategy.construct(returns, constraints)
The exact weights will vary, but the stable asset should have a high weight¶
print(portfolio.weights['STABLE_ASSET'] > 0.5) True
Source code in src/portfolio_management/portfolio/strategies/mean_variance.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | |
name
property
¶
Return the registered strategy name.
min_history_periods
property
¶
Return the minimum number of periods needed for estimation.
construct(returns, constraints, asset_classes=None)
¶
Construct a mean-variance optimised portfolio.
Source code in src/portfolio_management/portfolio/strategies/mean_variance.py
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | |
PortfolioStrategy
¶
Bases: ABC
Abstract base class for all portfolio construction strategies.
This class defines the common interface for all strategies. Concrete implementations must provide the logic for constructing a portfolio, which involves calculating asset weights based on return data and a set of constraints.
The interface is designed to be flexible, accommodating strategies ranging from simple heuristics (like equal weight) to complex optimizations (like mean-variance or risk parity).
Source code in src/portfolio_management/portfolio/strategies/base.py
name
abstractmethod
property
¶
Return the strategy name.
min_history_periods
abstractmethod
property
¶
Return minimum number of return periods required.
construct(returns, constraints, asset_classes=None)
abstractmethod
¶
Construct a portfolio based on the strategy's logic.
This is the core method of the strategy. It takes historical or expected returns, a set of investment constraints, and optional asset-level metadata to calculate and return the target portfolio weights.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
A DataFrame of asset returns, with assets as columns and dates as the index. |
required |
constraints
|
PortfolioConstraints
|
An object defining the investment rules, such as weight limits and exposure constraints. |
required |
asset_classes
|
Series | None
|
An optional Series that maps asset tickers to their respective asset classes (e.g., 'EQUITY', 'BOND'). This is used for applying group-level constraints. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Portfolio |
Portfolio
|
A |
Portfolio
|
and other relevant metadata about the constructed portfolio. |
Raises:
| Type | Description |
|---|---|
InsufficientDataError
|
If the provided |
OptimizationError
|
If a numerical optimization fails to converge to a valid solution. |
InfeasibleError
|
If the optimization problem is determined to be infeasible under the given constraints. |
Source code in src/portfolio_management/portfolio/strategies/base.py
RiskParityStrategy
¶
Bases: PortfolioStrategy
Constructs a portfolio where each asset contributes equally to total risk.
This strategy, often called "risk parity," seeks to build a more balanced portfolio by ensuring that the contribution of each asset to the overall portfolio volatility is the same. It is considered a more robust approach to diversification than traditional capital allocation strategies.
Mathematical Formulation
The objective is to find the portfolio weights w such that the risk
contribution of each asset is equal. The risk contribution of asset i is:
RCᵢ = wᵢ * ∂σ(w) / ∂wᵢ = wᵢ * (Σw)ᵢ / σ(w)
where: - w: portfolio weights vector - Σ: covariance matrix of asset returns - σ(w): portfolio volatility, sqrt(w.T * Σ * w)
The optimizer solves for w such that RCᵢ = RCⱼ for all assets i, j.
Example
import pandas as pd import numpy as np from portfolio_management.portfolio.strategies import RiskParityStrategy from portfolio_management.portfolio.constraints import PortfolioConstraints
Create returns with different volatilities¶
np.random.seed(42) returns = pd.DataFrame({ ... 'LOW_VOL': np.random.normal(0, 0.05, 252), ... 'HIGH_VOL': np.random.normal(0, 0.20, 252), ... })
strategy = RiskParityStrategy() print(strategy.name) risk_parity
Source code in src/portfolio_management/portfolio/strategies/risk_parity.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | |
name
property
¶
Return the strategy name.
min_history_periods
property
¶
Return minimum number of return periods required.
construct(returns, constraints, asset_classes=None)
¶
Construct a risk parity portfolio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
DataFrame with returns (assets as columns, dates as index) |
required |
constraints
|
PortfolioConstraints
|
Portfolio constraints to enforce |
required |
asset_classes
|
Series | None
|
Optional Series mapping tickers to asset classes |
None
|
Returns:
| Type | Description |
|---|---|
Portfolio
|
Portfolio with risk-parity weights |
Raises:
| Type | Description |
|---|---|
InsufficientDataError
|
If insufficient data for covariance estimation |
OptimizationError
|
If optimization fails to converge |
DependencyError
|
If riskparityportfolio library is not installed |
Source code in src/portfolio_management/portfolio/strategies/risk_parity.py
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | |
validate_constraints(weights, constraints, asset_classes)
staticmethod
¶
Validate portfolio constraints.
Source code in src/portfolio_management/portfolio/strategies/risk_parity.py
get_cardinality_optimizer(method)
¶
Get optimizer function for specified cardinality method (stub).
Factory function to retrieve the appropriate optimizer implementation based on the cardinality method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
Cardinality method name ('miqp', 'heuristic', 'relaxation') |
required |
Returns:
| Type | Description |
|---|---|
Any
|
Optimizer function for the specified method |
Raises:
| Type | Description |
|---|---|
CardinalityNotImplementedError
|
If method not implemented |
ValueError
|
If method is unknown |
Source code in src/portfolio_management/portfolio/cardinality.py
optimize_with_cardinality_heuristic(returns, constraints, cardinality, asset_classes=None)
¶
Optimize portfolio with cardinality via heuristics (design stub).
This is a design stub for future heuristic-based cardinality optimization. When implemented, this will use iterative algorithms to find good (not necessarily optimal) sparse portfolios.
Potential Algorithms
- Greedy forward selection: Start with empty portfolio, add assets one-by-one
- Greedy backward elimination: Start with full portfolio, remove assets one-by-one
- Local search: Start with initial solution, iteratively swap assets
- Threshold-based: Optimize without cardinality, then threshold small weights
Expected Performance
- Fast: Minutes even for large universes (>500 assets)
- Near-optimal: Typically within 5-10% of MIQP solution
- No special solver required
Implementation Considerations
- Greedy algorithms may get stuck in local optima
- Multiple random restarts can improve solution quality
- Warm-start from preselection results often helps
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
Historical returns DataFrame |
required |
constraints
|
PortfolioConstraints
|
Portfolio constraints |
required |
cardinality
|
CardinalityConstraints
|
Cardinality constraints |
required |
asset_classes
|
Series | None
|
Optional asset class mapping |
None
|
Returns:
| Type | Description |
|---|---|
Portfolio
|
Portfolio with good approximate sparse weights |
Raises:
| Type | Description |
|---|---|
CardinalityNotImplementedError
|
Always (not yet implemented) |
Source code in src/portfolio_management/portfolio/cardinality.py
optimize_with_cardinality_miqp(returns, constraints, cardinality, asset_classes=None)
¶
Optimize portfolio with cardinality via MIQP (design stub).
This is a design stub for future MIQP-based cardinality optimization. When implemented, this will use Mixed-Integer Quadratic Programming to find the optimal sparse portfolio subject to cardinality constraints.
Implementation Requirements
- Commercial solver: Gurobi or CPLEX with Python bindings
- Binary variable z_i for each asset (z_i=1 if w_i > 0)
- Constraint: sum(z_i) <= max_assets
- Constraint: w_i <= z_i (big-M formulation)
- Objective: Minimize risk or maximize Sharpe ratio
Expected Performance
- Small universes (<50 assets): Seconds to optimal solution
- Medium universes (50-200 assets): Minutes to optimal solution
- Large universes (>200 assets): May not converge in reasonable time
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
Historical returns DataFrame |
required |
constraints
|
PortfolioConstraints
|
Portfolio constraints |
required |
cardinality
|
CardinalityConstraints
|
Cardinality constraints |
required |
asset_classes
|
Series | None
|
Optional asset class mapping |
None
|
Returns:
| Type | Description |
|---|---|
Portfolio
|
Portfolio with optimal sparse weights |
Raises:
| Type | Description |
|---|---|
CardinalityNotImplementedError
|
Always (not yet implemented) |
Source code in src/portfolio_management/portfolio/cardinality.py
optimize_with_cardinality_relaxation(returns, constraints, cardinality, asset_classes=None)
¶
Optimize portfolio with cardinality via relaxation (design stub).
This is a design stub for future relaxation-based cardinality optimization. When implemented, this will use continuous relaxation followed by post-processing to enforce cardinality.
Approach
- Solve continuous (non-integer) relaxation with penalty on number of assets
- Use L1 or elastic-net regularization to encourage sparsity
- Post-process: threshold or round weights to satisfy exact cardinality
- Optional: local refinement after rounding
Trade-offs
✓ Fast: Similar to standard continuous optimization ✓ No special solver required ✓ Smooth optimization landscape ✗ Two-stage process (optimize, then round) ✗ Rounding may degrade solution quality ✗ Hard cardinality constraint approximated by penalty
Implementation Considerations
- L1 penalty: λ * sum(|w_i|) encourages sparsity but doesn't control exact count
- Regularization strength (λ) requires tuning
- Rounding strategy: sort by weight magnitude, keep top-K
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
Historical returns DataFrame |
required |
constraints
|
PortfolioConstraints
|
Portfolio constraints |
required |
cardinality
|
CardinalityConstraints
|
Cardinality constraints |
required |
asset_classes
|
Series | None
|
Optional asset class mapping |
None
|
Returns:
| Type | Description |
|---|---|
Portfolio
|
Portfolio with approximate sparse weights |
Raises:
| Type | Description |
|---|---|
CardinalityNotImplementedError
|
Always (not yet implemented) |
Source code in src/portfolio_management/portfolio/cardinality.py
validate_cardinality_constraints(constraints, portfolio_constraints, num_assets)
¶
Validate cardinality constraints for feasibility.
Checks that cardinality constraints are internally consistent and compatible with portfolio constraints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
constraints
|
CardinalityConstraints
|
Cardinality constraints to validate |
required |
portfolio_constraints
|
PortfolioConstraints
|
Portfolio-level constraints |
required |
num_assets
|
int
|
Number of assets in the universe |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If constraints are infeasible or inconsistent |
CardinalityNotImplementedError
|
If non-preselection method specified |
Source code in src/portfolio_management/portfolio/cardinality.py
apply_membership_policy(current_holdings, preselected_ranks, policy, holding_periods=None, top_k=30, current_weights=None, candidate_weights=None)
¶
Apply membership policy to determine final candidate set.
This function takes the preselected candidates (typically from a ranking/scoring step) and current portfolio holdings, then applies policy rules to determine the final set of assets that should be passed to the optimizer.
Policy application order
- Start with top_k from preselected_ranks
- Apply min_holding_periods: keep assets that haven't been held long enough
- Apply buffer_rank: keep existing holdings within buffer
- Apply max_new_assets: limit additions
- Apply max_removed_assets: limit removals
- Check max_turnover: if violated, reduce changes (future enhancement)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_holdings
|
list[str]
|
List of asset IDs currently in the portfolio. |
required |
preselected_ranks
|
Series
|
Series mapping asset IDs to their rank (1=best). Lower rank is better. Must include all current_holdings if they are still in the universe. |
required |
policy
|
MembershipPolicy
|
MembershipPolicy configuration. |
required |
holding_periods
|
dict[str, int] | None
|
Dict mapping asset ID to number of periods held. Required if policy.min_holding_periods is set. Default: None. |
None
|
top_k
|
int
|
Number of top-ranked assets to target. Default: 30. |
30
|
current_weights
|
dict[str, float] | None
|
Dict mapping current holdings to their portfolio weights. Required if policy.max_turnover is set. Default: None. |
None
|
candidate_weights
|
dict[str, float] | None
|
Dict mapping candidate assets to their expected weights after rebalance. Required if policy.max_turnover is set. Default: None. |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of asset IDs that should be passed to the optimizer, respecting all |
list[str]
|
policy constraints. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If required data is missing or invalid. |
Example
current_holdings = ["AAPL", "MSFT", "GOOGL"] ranks = pd.Series({"AAPL": 1, "MSFT": 2, "AMZN": 3, "GOOGL": 45}) holding_periods = {"AAPL": 5, "MSFT": 2, "GOOGL": 1} policy = MembershipPolicy( ... buffer_rank=50, ... min_holding_periods=3, ... max_new_assets=2 ... )
final = apply_membership_policy( ... current_holdings=current_holdings, ... preselected_ranks=ranks, ... policy=policy, ... holding_periods=holding_periods, ... top_k=30 ... )
GOOGL kept despite rank=45 (within buffer) and min_holding_periods¶
Only 2 new assets added due to max_new_assets¶
Source code in src/portfolio_management/portfolio/membership.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | |
create_preselection_from_dict(config_dict)
¶
Create Preselection instance from dictionary configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_dict
|
PreselectionConfigDict | None
|
Dictionary with preselection configuration |
required |
Returns:
| Type | Description |
|---|---|
Preselection | None
|
Preselection instance or None if preselection disabled |
Source code in src/portfolio_management/portfolio/preselection.py
options: show_root_heading: true show_source: false members_order: source group_by_category: true show_category_heading: true