Skip to content

Portfolio Management Toolkit - Implemented Architecture

Status:Fully Implemented (October 18, 2025)

This document describes the current production-ready modular monolith architecture that has been implemented and validated through all 9 refactoring phases.

Implemented Modular Monolith Architecture

The portfolio management toolkit now follows a clean layered modular architecture with clear separation of concerns and explicit dependencies.

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Portfolio Management Toolkit                             │
│                                                                             │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │                      Layer 6: Reporting                               │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  reporting/                                                      │ │ │
│  │  │  • visualization/ (charts, graphs)                               │ │ │
│  │  │  • reports/ (summary, comparison, trade analysis)                │ │ │
│  │  │  • exporters/ (CSV, JSON, HTML)                                  │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │                    Layer 5: Backtesting                               │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  backtesting/                                                    │ │ │
│  │  │  • engine/ (backtest execution, simulation)                      │ │ │
│  │  │  • transactions/ (costs, execution)                              │ │ │
│  │  │  • rebalancing/ (triggers, events)                               │ │ │
│  │  │  • performance/ (metrics, analytics)                             │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │               Layer 4: Portfolio Construction                         │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  portfolio/                                                      │ │ │
│  │  │  • strategies/ (equal-weight, risk-parity, mean-variance)        │ │ │
│  │  │  • constraints/ (models, validators)                             │ │ │
│  │  │  • rebalancing/ (config, logic)                                  │ │ │
│  │  │  • builder (orchestration)                                       │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │              Layer 3: Financial Analytics                             │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  analytics/                                                      │ │ │
│  │  │  • returns/ (calculator, config, loaders)                        │ │ │
│  │  │  • metrics/ (performance, risk)                                  │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │                  Layer 2: Asset Universe                              │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  assets/                                                         │ │ │
│  │  │  • selection/ (criteria, selector, filters)                      │ │ │
│  │  │  • classification/ (classifier, taxonomy, overrides)             │ │ │
│  │  │  • universes/ (definition, loader, manager)                      │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │                   Layer 1: Data Management                            │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  data/                                                           │ │ │
│  │  │  • ingestion/ (stooq indexing, loaders)                          │ │ │
│  │  │  • io/ (readers, writers, exporters)                             │ │ │
│  │  │  • matching/ (symbol matchers, strategies)                       │ │ │
│  │  │  • analysis/ (quality, currency)                                 │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                    ▲                                        │
│                                    │                                        │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │                    Layer 0: Core Foundation                           │ │
│  │  ┌─────────────────────────────────────────────────────────────────┐ │ │
│  │  │  core/                                                           │ │ │
│  │  │  • exceptions (hierarchy)                                        │ │ │
│  │  │  • config (constants)                                            │ │ │
│  │  │  • utils (parallel processing, timing)                           │ │ │
│  │  │  • types (protocols, interfaces)                                 │ │ │
│  │  └─────────────────────────────────────────────────────────────────┘ │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│  Legend:  ▲ = Dependency Flow (upward only)                                │
└─────────────────────────────────────────────────────────────────────────────┘

Detailed Package Dependencies

reporting ──────────┐
              ┌──────────┐
              │backtesting│
              └──────────┘
                    ├─────────────┐
                    ▼             ▼
              ┌─────────┐   ┌──────────┐
              │portfolio│   │analytics │
              └─────────┘   └──────────┘
                    │             │
                    │             ▼
                    │       ┌──────────┐
                    └──────▶│  assets  │
                            └──────────┘
                            ┌──────────┐
                            │   data   │
                            └──────────┘
                            ┌──────────┐
                            │   core   │
                            └──────────┘

Package Interactions - Data Flow

┌──────────────┐
│ CLI Scripts  │  (Entry Points)
└──────────────┘
┌─────────────────────────────────────────────────────────────┐
│                     WORKFLOW EXAMPLE                        │
│                                                             │
│  1. Data Preparation (scripts/prepare_tradeable_data.py)   │
│     ┌─────────────────────────────────────────────────┐    │
│     │  data.ingestion → data.matching → data.io       │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  2. Asset Selection (scripts/select_assets.py)             │
│     ┌─────────────────────────────────────────────────┐    │
│     │  data.io → assets.selection                     │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  3. Classification (scripts/classify_assets.py)            │
│     ┌─────────────────────────────────────────────────┐    │
│     │  assets.selection → assets.classification       │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  4. Returns Calculation (scripts/calculate_returns.py)     │
│     ┌─────────────────────────────────────────────────┐    │
│     │  data.io → analytics.returns                    │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  5. Universe Management (scripts/manage_universes.py)      │
│     ┌─────────────────────────────────────────────────┐    │
│     │  assets.universes → analytics.returns           │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  6. Portfolio Construction (scripts/construct_portfolio.py)│
│     ┌─────────────────────────────────────────────────┐    │
│     │  analytics.returns → portfolio.strategies       │    │
│     └─────────────────────────────────────────────────┘    │
│           │                                                 │
│           ▼                                                 │
│  7. Backtesting (scripts/run_backtest.py)                  │
│     ┌─────────────────────────────────────────────────┐    │
│     │  portfolio.strategies → backtesting.engine      │    │
│     │  → backtesting.performance → reporting          │    │
│     └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

Package Responsibility Matrix

Package Primary Responsibility Key Classes/Functions Dependencies
core Foundation utilities, exceptions, config Exception hierarchy, parallel processing, constants None
data Data ingestion, I/O, symbol matching StooqIndexer, TradeableLoader, SymbolMatcher core
assets Asset selection, classification, universes AssetSelector, AssetClassifier, UniverseLoader core, data
analytics Financial calculations, returns, metrics ReturnCalculator, PerformanceMetrics core, assets
portfolio Portfolio construction, strategies PortfolioBuilder, EqualWeight, RiskParity core, analytics
backtesting Historical simulation, performance BacktestEngine, TransactionCostModel core, portfolio, analytics
reporting Visualization, report generation ChartPreparation, ReportGenerator core, backtesting, portfolio

Module Split Examples

Before: Monolithic portfolio.py (821 lines)

portfolio.py
├── StrategyType (enum)
├── PortfolioConstraints (dataclass)
├── RebalanceConfig (dataclass)
├── Portfolio (dataclass)
├── PortfolioStrategy (ABC)
├── EqualWeightStrategy (class)
├── RiskParityStrategy (class)
├── MeanVarianceStrategy (class)
├── Constraint validation logic
└── Various utility functions

After: Organized portfolio/ package

portfolio/
├── __init__.py (public API)
├── models.py
│   ├── Portfolio
│   └── StrategyType
├── builder.py
│   └── PortfolioBuilder (orchestration)
├── strategies/
│   ├── __init__.py
│   ├── base.py
│   │   └── PortfolioStrategy (ABC)
│   ├── equal_weight.py
│   │   └── EqualWeightStrategy
│   ├── risk_parity.py
│   │   └── RiskParityStrategy
│   └── mean_variance.py
│       └── MeanVarianceStrategy
├── constraints/
│   ├── __init__.py
│   ├── models.py
│   │   └── PortfolioConstraints
│   └── validators.py
│       └── Constraint validation logic
└── rebalancing/
    ├── __init__.py
    ├── config.py
    │   └── RebalanceConfig
    └── logic.py
        └── Rebalancing algorithms

Benefits of Split

  • ✅ Each file < 200 lines (easier to understand)
  • ✅ Related code grouped logically
  • ✅ Easy to add new strategies (just add a file)
  • ✅ Clear separation of concerns
  • ✅ Better testability (test each component)

Import Pattern Evolution

Current Pattern (Flat)

# Script imports
from src.portfolio_management.selection import FilterCriteria, AssetSelector
from src.portfolio_management.classification import AssetClassifier, AssetClass
from src.portfolio_management.returns import ReturnCalculator, ReturnConfig
from src.portfolio_management.portfolio import Portfolio, PortfolioStrategy
from src.portfolio_management.backtest import BacktestEngine, BacktestConfig
from src.portfolio_management.visualization import prepare_equity_curve
from src.portfolio_management.exceptions import PortfolioConstructionError
from src.portfolio_management.utils import _run_in_parallel

New Pattern (Modular)

# Script imports - cleaner and organized by domain
from portfolio_management.assets import (
    FilterCriteria, AssetSelector, AssetClassifier, AssetClass
)
from portfolio_management.analytics import ReturnCalculator, ReturnConfig
from portfolio_management.portfolio import Portfolio, PortfolioStrategy
from portfolio_management.backtesting import BacktestEngine, BacktestConfig
from portfolio_management.reporting import prepare_equity_curve
from portfolio_management.core import PortfolioConstructionError, run_in_parallel

Benefits

  • ✅ Grouped by logical domain
  • ✅ Shorter import lines
  • ✅ Clear which layer you're using
  • ✅ IDE autocomplete works better

Testing Structure Evolution

Current (Mixed)

tests/
├── test_selection.py
├── test_classification.py
├── test_returns.py
├── test_portfolio.py
├── test_backtest.py
├── test_visualization.py
├── test_utils.py
├── test_universes.py
├── integration/
│   └── ...
└── scripts/
    └── ...

New (Organized by Package)

tests/
├── unit/
│   ├── core/
│   │   ├── test_exceptions.py
│   │   ├── test_config.py
│   │   └── test_utils.py
│   ├── data/
│   │   ├── test_ingestion.py
│   │   ├── test_io.py
│   │   └── test_matching.py
│   ├── assets/
│   │   ├── test_selection.py
│   │   ├── test_classification.py
│   │   └── test_universes.py
│   ├── analytics/
│   │   └── test_returns.py
│   ├── portfolio/
│   │   ├── test_strategies.py
│   │   └── test_constraints.py
│   ├── backtesting/
│   │   └── test_engine.py
│   └── reporting/
│       └── test_visualization.py
├── integration/
│   └── ...
└── scripts/
    └── ...

Architecture Principles Applied

1. Separation of Concerns

  • Each package has a single, well-defined purpose
  • No mixing of data access with business logic
  • Clear boundaries between layers

2. Dependency Inversion

  • Higher layers depend on abstractions (interfaces/protocols)
  • Lower layers provide implementations
  • Core defines contracts, packages implement them

3. Single Responsibility

  • Each package responsible for one aspect of the system
  • Each module within package has focused responsibility
  • Easy to change without affecting others

4. Open/Closed Principle

  • New strategies added by creating new files
  • Existing code doesn't need modification
  • Extension through composition

5. Don't Repeat Yourself (DRY)

  • Shared code in appropriate layer
  • Core utilities accessible to all
  • No duplication across packages

Package Communication Patterns

Pattern 1: Direct Import (Same Layer)

# Within assets package
from .selection import FilterCriteria
from .classification import AssetClassifier

Pattern 2: Public API Import (Cross-Layer)

# From higher layer to lower layer
from portfolio_management.analytics import ReturnCalculator
from portfolio_management.assets import AssetClassifier
# Pass dependencies explicitly
class PortfolioBuilder:
    def __init__(
        self,
        return_calculator: ReturnCalculator,
        strategy: PortfolioStrategy
    ):
        self.return_calculator = return_calculator
        self.strategy = strategy

Pattern 4: Protocol/Interface (For Flexibility)

# In core/types.py
from typing import Protocol

class IReturnCalculator(Protocol):
    def calculate(self, prices: pd.DataFrame) -> pd.DataFrame:
        ...

# In portfolio/builder.py
from portfolio_management.core.types import IReturnCalculator

class PortfolioBuilder:
    def __init__(self, calculator: IReturnCalculator):
        self.calculator = calculator

Success Metrics

Code Quality Metrics

Metric Before After (Target) Improvement
Avg Module Size ~500 lines \<200 lines 60% reduction
Max Module Size 821 lines \<400 lines 51% reduction
Packages 1 7 7x organization
Circular Dependencies Unknown 0 Eliminated
Import Depth Flat 3 levels Clear hierarchy
Public APIs Unclear Explicit 100% clarity

Developer Experience Metrics

Metric Before After (Target)
Time to find code High Low
Onboarding time 2-3 days 1 day
Change impact Unclear Predictable
Test isolation Hard Easy
Add new feature Complex Straightforward

Prepared By: GitHub Copilot Date: October 18, 2025 Related Document: MODULAR_MONOLITH_REFACTORING_PLAN.md