{"id":29260114,"url":"https://github.com/zillionare/moonshot","last_synced_at":"2025-07-04T07:08:23.122Z","repository":{"id":301862142,"uuid":"1009596094","full_name":"zillionare/moonshot","owner":"zillionare","description":"Alphalens lacks accurate monthly factor testing; this library delivers it.","archived":false,"fork":false,"pushed_at":"2025-06-29T08:29:39.000Z","size":421,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-29T09:31:46.098Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zillionare.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-27T11:44:11.000Z","updated_at":"2025-06-29T08:29:42.000Z","dependencies_parsed_at":"2025-06-29T09:31:51.837Z","dependency_job_id":"25c16552-21a9-4547-a6d8-4bc613ea4a3c","html_url":"https://github.com/zillionare/moonshot","commit_stats":null,"previous_names":["zillionare/moonshot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zillionare/moonshot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zillionare%2Fmoonshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zillionare%2Fmoonshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zillionare%2Fmoonshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zillionare%2Fmoonshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zillionare","download_url":"https://codeload.github.com/zillionare/moonshot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zillionare%2Fmoonshot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263464234,"owners_count":23470477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-04T07:08:21.509Z","updated_at":"2025-07-04T07:08:23.107Z","avatar_url":"https://github.com/zillionare.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# moonshot\n\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://pypi.python.org/pypi/moonshot\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/moonshot.svg\"\n        alt = \"Release Status\"\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://github.com/zillionare/moonshot/actions\"\u003e\n    \u003cimg src=\"https://github.com/zillionare/moonshot/actions/workflows/main.yml/badge.svg?branch=release\" alt=\"CI Status\"\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://zillionare.github.io/moonshot/\"\u003e\n    \u003cimg src=\"https://img.shields.io/website/https/zillionare.github.io/moonshot/index.html.svg?label=docs\u0026down_message=unavailable\u0026up_message=available\" alt=\"Documentation Status\"\u003e\n\u003c/a\u003e\n\n\u003c/p\u003e\n\n\nAlphalens lacks accurate monthly factor testing; our library delivers it.\n\n## Overview\n\nMoonshot is a lightweight, efficient Python package designed specifically for monthly factor-based investment strategy backtesting. **Unlike existing tools such as Alphalens, which has limitations in monthly factor analysis**, Moonshot provides a clean, intuitive API for evaluating factor performance through monthly portfolio rebalancing, making it ideal for quantitative researchers and portfolio managers working with factor investing strategies.\n\n### Why Moonshot?\n\n**Addressing Alphalens Limitations**: While Alphalens is a popular choice for factor analysis, it has known issues with monthly factor evaluation, particularly in handling monthly rebalancing logic and date alignment. Moonshot was specifically designed to address these shortcomings.\n\nUnlike general-purpose backtesting frameworks, Moonshot is specifically crafted for monthly factor strategies. It eliminates the complexity of configuring generic backtesting engines while providing the precision needed for factor research. **Most importantly, it ensures accurate monthly factor analysis where other tools fall short.**\n\nThe name \"Moonshot\" reflects our ambition to help researchers and practitioners aim high in their factor investing endeavors - taking calculated risks for potentially significant returns, with the confidence that comes from accurate analysis.\n\n* Free software: MIT\n* Documentation: \u003chttps://zillionare.github.io/moonshot/\u003e\n\n\n## Installation\n\n### From PyPI (Recommended)\n\n```bash\npip install moonshot\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/zillionare/moonshot.git\ncd moonshot\npip install -e .\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport pandas as pd\nimport numpy as np\nfrom moonshot import monthly_factor_backtest, calculate_group_statistics, plot_cumulative_returns\n\n# Create simple synthetic data for demonstration\n# Factor data: higher factor values should lead to higher returns\nfactor_data = pd.Series([\n    1.0, 2.0, 3.0,  # January 31st: A=1.0, B=2.0, C=3.0\n    1.5, 2.5, 3.5   # February 28th: A=1.5, B=2.5, C=3.5\n], index=pd.MultiIndex.from_tuples([\n    ('2023-01-31', 'A'), ('2023-01-31', 'B'), ('2023-01-31', 'C'),\n    ('2023-02-28', 'A'), ('2023-02-28', 'B'), ('2023-02-28', 'C')\n], names=['date', 'asset']), name='factor')\n\n# Price data: Include both month-end (for factor calculation) and next month start (for trading)\nprice_data = pd.DataFrame([\n    # January month-end data (factor calculation date)\n    {'date': '2023-01-31', 'asset': 'A', 'open': 100, 'close': 100},\n    {'date': '2023-01-31', 'asset': 'B', 'open': 100, 'close': 100},\n    {'date': '2023-01-31', 'asset': 'C', 'open': 100, 'close': 100},\n    # February start data (trading execution date)\n    {'date': '2023-02-01', 'asset': 'A', 'open': 100, 'close': 100},\n    {'date': '2023-02-01', 'asset': 'B', 'open': 100, 'close': 100},\n    {'date': '2023-02-01', 'asset': 'C', 'open': 100, 'close': 100},\n    # February month-end data (factor calculation date)\n    {'date': '2023-02-28', 'asset': 'A', 'open': 100, 'close': 100},  # 0% return\n    {'date': '2023-02-28', 'asset': 'B', 'open': 100, 'close': 110},  # 10% return\n    {'date': '2023-02-28', 'asset': 'C', 'open': 100, 'close': 120},  # 20% return\n    # March start data (trading execution date)\n    {'date': '2023-03-01', 'asset': 'A', 'open': 100, 'close': 100},\n    {'date': '2023-03-01', 'asset': 'B', 'open': 110, 'close': 110},\n    {'date': '2023-03-01', 'asset': 'C', 'open': 120, 'close': 120},\n]).set_index(['date', 'asset'])\n\n# Run backtest with 3 quantiles\nstrategy_returns, benchmark_returns = monthly_factor_backtest(\n    factor_data, price_data, quantiles=3\n)\n\nprint(\"Strategy Returns by Quantile:\")\nprint(strategy_returns)\n# Expected output: Q3 (highest factor) should have ~20% return\n# Q2 (medium factor) should have ~10% return\n# Q1 (lowest factor) should have ~0% return\n\nprint(\"\\nBenchmark Returns (Equal-weighted):\")\nprint(benchmark_returns)\n# Expected output: ~10% (average of 0%, 10%, 20%)\n```\n\n### Advanced Analysis\n\n```python\n# Calculate performance statistics\nstats = calculate_group_statistics(strategy_returns)\nprint(\"\\nPerformance Statistics:\")\nprint(stats)\n\n# Plot cumulative returns\nplot_cumulative_returns(strategy_returns, benchmark_returns)\n\n# Analyze long-short spread\nfrom moonshot import analyze_long_short_spread\nspread = analyze_long_short_spread(strategy_returns)\nprint(\"\\nLong-Short Spread:\")\nprint(spread)\n```\n\n### Custom Binning\n\n```python\n# Use custom bins instead of quantiles\nstrategy_returns, benchmark_returns = monthly_factor_backtest(\n    factor_data, price_data, bins=[0, 1.5, 2.5, 4.0]\n)\n```\n\n## Examples\n\nFor more comprehensive examples and tutorials, see the [`examples/`](examples/) directory:\n\n- **[`basic_example.py`](examples/basic_example.py)**: Introduction to core functionality\n- **[`advanced_analysis.py`](examples/advanced_analysis.py)**: Performance analysis and visualization\n- **[`custom_binning.py`](examples/custom_binning.py)**: Quantiles vs custom bins comparison\n- **[`data_preprocessing.py`](examples/data_preprocessing.py)**: Handling real-world data challenges\n\nRun any example with:\n```bash\npython examples/basic_example.py\n```\n\n## Important Data Requirements\n\n### ⚠️ Critical: Date Alignment\n\n**Moonshot assumes your data is properly aligned to month-end dates.** The library does not automatically handle missing dates or irregular time series. If your data has gaps or misaligned dates, you **must** preprocess it before using Moonshot.\n\n### Data Preprocessing for Missing Dates\n\nIf you need to trade even when some dates are missing, align your data to month-end dates first:\n\n```python\n# Method 1: Forward fill with complete date range\ndef align_to_month_end(data, start_date, end_date):\n    \"\"\"\n    Align data to month-end dates using forward fill\n    \"\"\"\n    # Generate complete month-end date range\n    complete_dates = pd.date_range(start_date, end_date, freq='ME')\n\n    if isinstance(data, pd.Series):\n        # For factor data (MultiIndex with date, asset)\n        assets = data.index.get_level_values('asset').unique()\n        complete_index = pd.MultiIndex.from_product(\n            [complete_dates, assets], names=['date', 'asset']\n        )\n        aligned_data = data.reindex(complete_index).groupby('asset').ffill()\n    else:\n        # For price data (DataFrame with MultiIndex)\n        assets = data.index.get_level_values('asset').unique()\n        complete_index = pd.MultiIndex.from_product(\n            [complete_dates, assets], names=['date', 'asset']\n        )\n        aligned_data = data.reindex(complete_index).groupby('asset').ffill()\n\n    return aligned_data.dropna()\n\n# Example usage\naligned_factor = align_to_month_end(factor_data, '2023-01-31', '2023-12-31')\naligned_prices = align_to_month_end(price_data, '2023-01-31', '2023-12-31')\n\n# Method 2: Resample to month-end and forward fill\ndef resample_to_month_end(data):\n    \"\"\"\n    Resample daily data to month-end\n    \"\"\"\n    if isinstance(data, pd.Series):\n        return data.groupby('asset').resample('ME', level='date').last().ffill()\n    else:\n        return data.groupby('asset').resample('ME', level='date').last().ffill()\n```\n\n### Data Format Requirements\n\n1. **Factor Data**: Must be a pandas Series with MultiIndex (date, asset)\n2. **Price Data**: Must be a pandas DataFrame with MultiIndex (date, asset) and columns ['open', 'close']\n3. **Dates**: Must be pandas datetime objects, preferably month-end dates\n4. **No Missing Values**: Ensure no NaN values in critical periods\n\n## API Reference\n\n### Core Functions\n\n- `monthly_factor_backtest(factor_data, bars_data, quantiles=None, bins=None)`: Main backtesting function\n- `calculate_group_statistics(monthly_returns)`: Calculate performance metrics\n- `plot_cumulative_returns(strategy_returns, benchmark_returns)`: Visualize results\n- `analyze_long_short_spread(monthly_returns)`: Analyze long-short strategy\n\nFor detailed API documentation, visit: \u003chttps://zillionare.github.io/moonshot/\u003e\n\n## Features\n\n* **Accurate Monthly Factor Analysis**: Specifically designed to handle monthly rebalancing correctly\n* **Simple API**: Clean, intuitive interface for factor backtesting\n* **Flexible Grouping**: Support both quantile-based and custom bin-based grouping\n* **Performance Analytics**: Built-in calculation of key performance metrics\n* **Visualization**: Easy plotting of cumulative returns and performance\n* **Long-Short Analysis**: Dedicated tools for long-short strategy evaluation\n* **Type Safety**: Full type hints for better development experience\n\n## Credits\n\nThis package was created with the [ppw](https://zillionare.github.io/python-project-wizard) tool. For more information, please visit the [project page](https://zillionare.github.io/python-project-wizard/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzillionare%2Fmoonshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzillionare%2Fmoonshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzillionare%2Fmoonshot/lists"}