Skip to content

Contributing to Optopsy

Thank you for your interest in contributing to Optopsy! This guide will help you get started.

Development Setup

1. Clone the Repository

git clone https://github.com/michaelchu/optopsy.git
cd optopsy

2. Install Dependencies

uv sync --extra ui

3. Install Pre-commit Hooks

uv run pre-commit install --hook-type pre-push

4. Verify Installation

uv run pytest tests/ -v

Development Workflow

Running Tests

# Run all tests
uv run pytest tests/ -v

# Run specific test file
uv run pytest tests/test_strategies.py -v

# Run tests matching a pattern
uv run pytest tests/ -k "butterfly" -v

Code Formatting and Linting

Optopsy uses Ruff for formatting and linting:

# Check formatting
uv run ruff format --check optopsy/ tests/

# Auto-format code
uv run ruff format optopsy/ tests/

# Lint code
uv run ruff check optopsy/ tests/

# Lint and auto-fix
uv run ruff check --fix optopsy/ tests/

# Type check
uv run ty check optopsy/

Important: All code must pass ruff format, ruff check, and ty check before submitting a PR.

Adding a New Strategy

Follow these steps to add a new options strategy:

1. Define Strategy in strategies.py

Add a public function and helper if needed:

def new_strategy(data: pd.DataFrame, **kwargs: Any) -> pd.DataFrame:
    """
    Generate new strategy statistics.

    A clear description of what this strategy does, including:
    - Leg composition
    - Market outlook
    - Profit/loss characteristics

    Args:
        data: DataFrame containing option chain data
        **kwargs: Optional strategy parameters

    Returns:
        DataFrame with strategy performance statistics
    """
    return _helper(data, leg_def=[...], **kwargs)

2. Add Validation Rules (if needed)

If your strategy has strike constraints, add them to rules.py:

def _rule_new_strategy_strikes(df: pd.DataFrame) -> pd.DataFrame:
    """
    Validate strike ordering for new strategy.

    Rule: [Describe your rule here]
    """
    # Implementation
    return df[mask]

3. Update Column Definitions (if needed)

If your strategy needs new column structures, add them to definitions.py:

new_strategy_internal_cols: List[str] = [
    "underlying_symbol",
    "strike_leg1",
    # ... other columns
]

4. Export in __init__.py

Add your strategy to the exports:

from .strategies import (
    # ... existing strategies
    new_strategy,
)

__all__ = [
    # ... existing strategies
    "new_strategy",
]

5. Add Tests

Create tests in tests/test_strategies.py:

def test_new_strategy(sample_data):
    """Test new strategy returns expected output."""
    results = op.new_strategy(sample_data)

    assert isinstance(results, pd.DataFrame)
    assert len(results) > 0
    assert 'mean' in results.columns
    # Additional assertions

6. Update Documentation

Add documentation to the appropriate strategy category file in docs/strategies/.

Pull Request Guidelines

Before Submitting

  • [ ] All tests pass (uv run pytest tests/ -v)
  • [ ] Code is formatted with Ruff (uv run ruff format optopsy/ tests/)
  • [ ] Linting passes (uv run ruff check optopsy/ tests/)
  • [ ] Type checking passes (uv run ty check optopsy/)
  • [ ] New features have tests
  • [ ] New strategies have documentation
  • [ ] Docstrings follow existing style (Google format)
  • [ ] Type hints are included

PR Description

Include in your PR description: - What changes you made - Why you made them - How to test the changes - Any breaking changes

Example PR Template

## Description
Brief description of changes

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing
How to test these changes

## Checklist
- [ ] Tests pass
- [ ] Code formatted with Ruff
- [ ] Documentation updated
- [ ] Type hints included

Code Style Guidelines

Docstrings

Use Google-style docstrings:

def function_name(param1: str, param2: int) -> bool:
    """
    Brief description of function.

    Longer description if needed, explaining behavior,
    edge cases, or important details.

    Args:
        param1: Description of param1
        param2: Description of param2

    Returns:
        Description of return value

    Raises:
        ValueError: When param1 is invalid
    """
    pass

Type Hints

Always include type hints:

from typing import Any, Dict, List
import pandas as pd

def process_data(
    data: pd.DataFrame,
    params: Dict[str, Any]
) -> List[pd.DataFrame]:
    ...

Function Naming

  • Public functions: snake_case (e.g., long_calls)
  • Private functions: _snake_case (e.g., _process_strategy)
  • Constants: UPPER_CASE (rarely used)

Testing Guidelines

Test Structure

def test_feature_name(sample_data):
    """Test that feature behaves correctly."""
    # Arrange
    expected_result = ...

    # Act
    actual_result = function_under_test(sample_data)

    # Assert
    assert actual_result == expected_result

Fixtures

Use pytest fixtures for common test data:

@pytest.fixture
def sample_data():
    """Generate sample options data for testing."""
    return pd.DataFrame({...})

Coverage

Aim for high test coverage on public APIs. Not every internal function needs tests, but all public strategy functions should be tested.

Documentation

Building Docs Locally

# Install MkDocs and required plugins
pip install mkdocs mkdocs-material "mkdocstrings[python]"

# Serve docs locally
mkdocs serve

# Visit http://127.0.0.1:8000

Documentation Structure

  • docs/index.md - Home page
  • docs/getting-started.md - Installation and quick start
  • docs/strategies/ - Strategy-specific documentation
  • docs/parameters.md - Parameter reference
  • docs/examples.md - Usage examples
  • docs/api-reference.md - Auto-generated API docs

Reporting Issues

Bug Reports

Include: - Python version - Optopsy version - Minimal reproducible example - Expected vs actual behavior - Error messages/tracebacks

Feature Requests

Describe: - The problem you're trying to solve - How you envision the solution - Any alternatives you've considered - Whether you're willing to contribute the feature

Community

  • GitHub Issues: Bug reports and feature requests
  • Discussions: Questions and general discussion
  • Pull Requests: Code contributions

License

By contributing to Optopsy, you agree that your contributions will be licensed under the AGPL-3.0 License.

Questions?

If you have questions about contributing, feel free to: - Open a GitHub Discussion - Create an issue with the "question" label - Check existing issues and documentation

Thank you for contributing to Optopsy!