Skip to main content

A domain-driven Python module for creating and managing financial indices

Project description

IndexMaker

A domain-driven Python module for creating, managing, and analyzing financial indices. Designed for index professionals.

CI PyPI version Python 3.9+ Code style: black Ruff License: MIT

Features

  • Domain-Driven Design: API uses terminology familiar to index professionals
  • Fluent Interface: Chainable methods for intuitive configuration
  • Type-Safe: Full type hints for IDE support and early error detection
  • Interchangeable Data Sources: Easily swap between free (Yahoo Finance) and proprietary data
  • Production-Ready: Includes validation, backtesting, and comprehensive testing

Installation

From PyPI

pip install indexforge

Using Poetry (Development)

# Clone the repository
git clone https://github.com/reubencapio/indexforge.git
cd indexforge

# Install with Poetry
poetry install

# Activate the virtual environment
poetry shell

From Source

# Install from GitHub
pip install git+https://github.com/reubencapio/indexforge.git

Quick Start

Create a Simple Index

from indexforge import Index, Universe, WeightingMethod, Currency

# Create an index
index = Index.create(
    name="Tech Leaders Index",
    identifier="TECHLDRS",
    currency=Currency.USD,
    base_date="2025-01-01",
    base_value=1000.0
)

# Define the universe
universe = Universe.from_tickers(["AAPL", "MSFT", "GOOGL", "AMZN", "META"])

# Configure
index.set_universe(universe)
index.set_weighting_method(WeightingMethod.equal_weight())

# Get constituents
constituents = index.get_constituents(date="2025-11-15")
for c in constituents:
    print(f"{c.ticker}: {c.name} - {c.weight:.2%}")

Market Cap Weighted Index with Caps

from indexforge import (
    Index, Universe, SelectionCriteria, WeightingMethod,
    RebalancingSchedule, Currency, Factor
)

# Create the index
index = Index.create(
    name="Tech Leaders Index",
    identifier="TECHLDRS",
    currency=Currency.USD,
    base_date="2025-01-01",
    base_value=1000.0
)

# Define universe with criteria
universe = (Universe.builder()
    .asset_class("EQUITIES")
    .sectors(["Technology"])
    .min_market_cap(1_000_000_000)
    .build()
)

# Select top 50 by market cap
selection = (SelectionCriteria.builder()
    .ranking_by(Factor.MARKET_CAP)
    .select_top(50)
    .apply_buffer_rules(add_threshold=45, remove_threshold=60)
    .build()
)

# Market cap weighting with 10% cap
weighting = (WeightingMethod.market_cap()
    .with_cap(max_weight=0.10)
    .build()
)

# Quarterly rebalancing
rebalancing = RebalancingSchedule.quarterly()

# Configure the index
(index
    .set_universe(universe)
    .set_selection_criteria(selection)
    .set_weighting_method(weighting)
    .set_rebalancing_schedule(rebalancing)
)

# Backtest
result = index.backtest(
    start_date="2024-01-01",
    end_date="2024-12-31"
)
print(f"Sharpe Ratio: {result.sharpe_ratio:.2f}")

Using Custom Data Source

from indexmaker import DataConnector, DataProvider, Constituent
import pandas as pd

class MyDataConnector(DataConnector):
    """Your custom data source."""

    def get_prices(self, tickers, start_date, end_date):
        # Fetch from your database/API
        return pd.DataFrame(...)

    def get_constituent_data(self, tickers, as_of_date=None):
        # Return list of Constituent objects
        return [Constituent(ticker=t, ...) for t in tickers]

    def get_market_cap(self, tickers, as_of_date=None):
        return {t: market_cap for t in tickers}

# Use custom data
provider = (DataProvider.builder()
    .add_source("mydata", MyDataConnector())
    .set_default("mydata")
    .build()
)

index.set_data_provider(provider)

Architecture

┌──────────────────────────────────────────────────────────┐
│                    User API Layer                        │
│   Index.create() → set_universe() → calculate()         │
├──────────────────────────────────────────────────────────┤
│                  Domain Model Layer                      │
│   Index │ Universe │ Constituent │ SelectionCriteria    │
├──────────────────────────────────────────────────────────┤
│                   Strategy Layer                         │
│   WeightingMethod │ RebalancingSchedule │ Validation    │
├──────────────────────────────────────────────────────────┤
│                    Data Layer                            │
│   DataProvider → DataConnector (Yahoo, Custom, etc.)    │
└──────────────────────────────────────────────────────────┘

Core Concepts

1. Index

The main entry point. Represents a financial index.

2. Universe

Defines which securities are eligible for inclusion (asset class, region, market cap, etc.)

3. SelectionCriteria

How constituents are chosen from the universe (top N by factor, composite scoring, etc.)

4. WeightingMethod

How constituents are weighted (equal, market cap, factor-based, custom)

5. RebalancingSchedule

When the index is updated (quarterly, monthly, annual)

6. DataProvider

Abstraction for market data - swap between free and proprietary sources

Examples

See the examples/ directory:

  • simple_index.py - Basic equal-weighted index
  • market_cap_index.py - Full-featured market cap weighted index
  • custom_data_source.py - Using your own data source

Run examples:

poetry run python examples/simple_index.py
poetry run python examples/market_cap_index.py
poetry run python examples/custom_data_source.py

Development

# Install dependencies
poetry install

# Run all tests
poetry run pytest

# Run with coverage
poetry run pytest --cov=indexmaker

# Format code
poetry run black src/ tests/ examples/

# Lint code
poetry run ruff check src/ tests/ examples/

# Type check
poetry run mypy src/indexmaker

Or use the Makefile shortcuts:

make test       # Run tests
make coverage   # Tests with coverage
make format     # Format with Black
make lint       # Run Ruff + Mypy
make all        # Format + Lint + Test

Project Structure

indexmaker/
├── src/indexmaker/
│   ├── core/           # Domain models (Index, Universe, Constituent)
│   ├── selection/      # Selection criteria and factors
│   ├── weighting/      # Weighting methods
│   ├── rebalancing/    # Rebalancing schedules
│   ├── data/           # Data providers and connectors
│   └── validation/     # Validation rules
├── tests/              # Unit tests
├── examples/           # Usage examples
└── docs/               # Documentation

Key Design Principles

  1. Domain Language: API uses industry terminology (constituents, rebalancing, weighting)
  2. Data Source Agnostic: Core logic separated from data fetching
  3. Type Safety: Full type hints and validation
  4. Builder Pattern: Fluent configuration for complex objects
  5. Testability: Components can be tested in isolation

Documentation

Requirements

  • Python 3.9+
  • pandas >= 2.0.0
  • numpy >= 1.24.0
  • yfinance >= 0.2.0 (for free data)

License

MIT License - see LICENSE file for details.

Contributing

Contributions welcome! Please read the contributing guidelines first.

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new functionality
  4. Submit a pull request

Acknowledgments

Inspired by industry-standard index methodologies.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

indexforge-0.1.5.tar.gz (57.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

indexforge-0.1.5-py3-none-any.whl (67.4 kB view details)

Uploaded Python 3

File details

Details for the file indexforge-0.1.5.tar.gz.

File metadata

  • Download URL: indexforge-0.1.5.tar.gz
  • Upload date:
  • Size: 57.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for indexforge-0.1.5.tar.gz
Algorithm Hash digest
SHA256 456de8690ba50fe23172857ed5ecc5757a753d7d7b1bb76257fa66eb915d26fc
MD5 6510b442945ccece43b5df20129ada29
BLAKE2b-256 9c0e3eb4c680d9d604618bb4f06da1b9bf00afacb1755fad1d975caaa429031a

See more details on using hashes here.

Provenance

The following attestation bundles were made for indexforge-0.1.5.tar.gz:

Publisher: publish.yml on reubencapio/indexmaker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file indexforge-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: indexforge-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 67.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for indexforge-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 ca78ec7441ecb5601108fdb6bbab63f7d40f894e538178d89a75a5e63fa73411
MD5 87713dafa7382857fcd22c60df3a05bf
BLAKE2b-256 1e14705780c8fbc9f62f7492b768f8cf8861a289915b343c54486d82b5aadca2

See more details on using hashes here.

Provenance

The following attestation bundles were made for indexforge-0.1.5-py3-none-any.whl:

Publisher: publish.yml on reubencapio/indexmaker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page