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.
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 indexmarket_cap_index.py- Full-featured market cap weighted indexcustom_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
- Domain Language: API uses industry terminology (constituents, rebalancing, weighting)
- Data Source Agnostic: Core logic separated from data fetching
- Type Safety: Full type hints and validation
- Builder Pattern: Fluent configuration for complex objects
- Testability: Components can be tested in isolation
Documentation
- API Design Proposal - Complete API specification
- Quick Reference - Common patterns cheat sheet
- Free Data Sources - Using Yahoo Finance and other free data
- Design Rationale - Why the API is designed this way
- Module Structure - Architecture details
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.
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
456de8690ba50fe23172857ed5ecc5757a753d7d7b1bb76257fa66eb915d26fc
|
|
| MD5 |
6510b442945ccece43b5df20129ada29
|
|
| BLAKE2b-256 |
9c0e3eb4c680d9d604618bb4f06da1b9bf00afacb1755fad1d975caaa429031a
|
Provenance
The following attestation bundles were made for indexforge-0.1.5.tar.gz:
Publisher:
publish.yml on reubencapio/indexmaker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
indexforge-0.1.5.tar.gz -
Subject digest:
456de8690ba50fe23172857ed5ecc5757a753d7d7b1bb76257fa66eb915d26fc - Sigstore transparency entry: 849954234
- Sigstore integration time:
-
Permalink:
reubencapio/indexmaker@3f7e004393d404e6fe2b4ac4ac30867383705da8 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/reubencapio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3f7e004393d404e6fe2b4ac4ac30867383705da8 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca78ec7441ecb5601108fdb6bbab63f7d40f894e538178d89a75a5e63fa73411
|
|
| MD5 |
87713dafa7382857fcd22c60df3a05bf
|
|
| BLAKE2b-256 |
1e14705780c8fbc9f62f7492b768f8cf8861a289915b343c54486d82b5aadca2
|
Provenance
The following attestation bundles were made for indexforge-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on reubencapio/indexmaker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
indexforge-0.1.5-py3-none-any.whl -
Subject digest:
ca78ec7441ecb5601108fdb6bbab63f7d40f894e538178d89a75a5e63fa73411 - Sigstore transparency entry: 849954236
- Sigstore integration time:
-
Permalink:
reubencapio/indexmaker@3f7e004393d404e6fe2b4ac4ac30867383705da8 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/reubencapio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3f7e004393d404e6fe2b4ac4ac30867383705da8 -
Trigger Event:
release
-
Statement type: