{"id":37971874,"url":"https://github.com/breaded-xyz/alphavec","last_synced_at":"2026-01-16T18:24:56.173Z","repository":{"id":329473200,"uuid":"1115015364","full_name":"breaded-xyz/alphavec","owner":"breaded-xyz","description":"Fast minimalist backtesting for perpetual futures.","archived":false,"fork":false,"pushed_at":"2026-01-10T20:52:03.000Z","size":48796,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-11T06:12:43.869Z","etag":null,"topics":["algorithmic-trading","backtesting","crypto","crypto-bot","quant","quantitative-finance","systematic-trading-strategies"],"latest_commit_sha":null,"homepage":"https://breaded.xyz","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/breaded-xyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-12T08:09:06.000Z","updated_at":"2026-01-10T20:52:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/breaded-xyz/alphavec","commit_stats":null,"previous_names":["breaded-xyz/alphavec"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/breaded-xyz/alphavec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/breaded-xyz%2Falphavec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/breaded-xyz%2Falphavec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/breaded-xyz%2Falphavec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/breaded-xyz%2Falphavec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/breaded-xyz","download_url":"https://codeload.github.com/breaded-xyz/alphavec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/breaded-xyz%2Falphavec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28480709,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["algorithmic-trading","backtesting","crypto","crypto-bot","quant","quantitative-finance","systematic-trading-strategies"],"created_at":"2026-01-16T18:24:56.062Z","updated_at":"2026-01-16T18:24:56.147Z","avatar_url":"https://github.com/breaded-xyz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Alphavec\n\n[![CI](https://github.com/breaded-xyz/alphavec/actions/workflows/ci.yml/badge.svg)](https://github.com/breaded-xyz/alphavec/actions/workflows/ci.yml)\n[![Upload Python Package](https://github.com/breaded-xyz/alphavec/actions/workflows/python-publish.yml/badge.svg)](https://github.com/breaded-xyz/alphavec/actions/workflows/python-publish.yml)\n\n\u003e**Disclaimer**\n\u003e\n\u003eThe content provided in this project is for informational purposes only and does not constitute financial advice. This information should not be construed as professional financial advice, and it is recommended to consult with a qualified financial advisor before making any financial decisions.\n\u003e\n\u003eNo liability is accepted for any losses or damages incurred as a result of acting or refraining from action based on the information provided in this project. Use this information at your own risk.\n\u003e\n\n```\n          $$\\           $$\\                                               \n          $$ |          $$ |                                              \n $$$$$$\\  $$ | $$$$$$\\  $$$$$$$\\   $$$$$$\\ $$\\    $$\\  $$$$$$\\   $$$$$$$\\ \n \\____$$\\ $$ |$$  __$$\\ $$  __$$\\  \\____$$\\\\$$\\  $$  |$$  __$$\\ $$  _____|\n $$$$$$$ |$$ |$$ /  $$ |$$ |  $$ | $$$$$$$ |\\$$\\$$  / $$$$$$$$ |$$ /      \n$$  __$$ |$$ |$$ |  $$ |$$ |  $$ |$$  __$$ | \\$$$  /  $$   ____|$$ |      \n\\$$$$$$$ |$$ |$$$$$$$  |$$ |  $$ |\\$$$$$$$ |  \\$  /   \\$$$$$$$\\ \\$$$$$$$\\ \n \\_______|\\__|$$  ____/ \\__|  \\__| \\_______|   \\_/     \\_______| \\_______|\n              $$ |                                                        \n              $$ |                                                        \n              \\__|                                                                                                         \n```\n\nAlphavec is a lightning fast, minimalist, cost-aware vectorized backtest engine inspired by the guys at RobotWealth.\n\nThe backtest input is the natural output of a typical quant research process - a time series of portfolio weights. You simply provide a dataframe of weights and a dataframe of close prices and order prices, along with some optional cost parameters and the backtest returns a streamlined performance report with insight into the key metrics.\n\n`alphavec` has first-class support for simulating leveraged perptual futures strategies using a small, fast, verifiable simulation core.\n\n## Rationale\n\nAlphavec is an antidote to the various bloated and complex backtest frameworks.\n\nTo validate ideas all you really need is...\n\n```python\n\nweights * returns.shift(-1)\n```\n\nThe goal was to add just enough extra complexity to this basic formula to support sound development of cost-aware systematic trading strategies.\n\n## Install\n\nRequires Python `\u003e=3.10`\n\n`pip install alphavec`\n\n- From source:\n  - `python3 -m venv .venv`\n  - `./.venv/bin/pip install -e .`\n- For development:\n  - `./.venv/bin/pip install -e \".[dev]\"`\n\n## Usage\n\n### Notes\n\n- Simulates cross‑margin (cash pooling) with unlimited leverage and borrowing (no liquidations or margin calls).\n- Orders execute at `exec_prices` plus slippage and fees.\n- Funding applies per period using signed `funding_rates`, +ve rate shorts earn, longs pay, and vice versa for a -ve rate.\n- NaNs in `exec_prices` or `close_prices` imply the asset is not tradable that period.\n- NaNs in `funding_rates` are treated as 0, and funding is always 0 when `close_prices` is NaN.\n- Positions will always be closed if target weight is zero, regardless of minimum notional filter.\n- Use `SimConfig.start_period`/`end_period` to slice inputs before simulating: `str` uses `loc`, `int` uses `iloc`.\n\n### Simulation\n\n`simulate()` runs a cross‑margin perpetual futures backtest from target portfolio weights.\n\nKey inputs:\n- `weights`: pandas `DataFrame` with a `DatetimeIndex` and columns for each asset.\n  Values are decimal percentage target weights (1.0 = 100% equity invested).\n  Positive = long, negative = short. Weights may sum greater than 1 at a time period for leverage.\n- `close_prices`, `exec_prices`, `funding_rates` (optional): same shape/index/columns as `weights`.\n\nReturns:\n- `returns`: period returns as a pandas `Series`.\n- `metrics`: key performance metrics as a pandas `DataFrame` with `Value` and `Note` columns.\n\nExample:\n\nSee `examples/simulate.ipynb`\n\n```python\nimport pandas as pd\nfrom alphavec import MarketData, SimConfig, simulate, tearsheet\n\nweights = pd.DataFrame({\"BTC\": [1, 1, 1]}, index=pd.date_range(\"2024-01-01\", periods=3, freq=\"1D\"))\nclose_prices = pd.DataFrame({\"BTC\": [100, 105, 110]}, index=weights.index)\nexec_prices = close_prices.shift(1).fillna(close_prices.iloc[0])\n\nresult = simulate(\n    weights=weights,\n    market=MarketData(close_prices=close_prices, exec_prices=exec_prices, funding_rates=None),\n    config=SimConfig(\n        benchmark_asset=\"BTC\",\n        order_notional_min=10,\n        fee_rate=0.00025,       # 2.5 bps per trade\n        slippage_rate=0.001,    # 10 bps per trade\n        start_period=\"2023-01-01\",\n        end_period=\"2025-12-06\",\n        init_cash=10_000,\n        freq_rule=\"1D\",\n        trading_days_year=365,\n        risk_free_rate=0.03,\n    ),\n)\nhtml_str = tearsheet(\n    sim_result=result,\n    output_path=\"tearsheet.html\",\n    smooth_periods=30,\n)\n```\n\n### Parameter Search\n\n`grid_search()` wraps `simulate()` and runs grid search over 1D or 2D parameter spaces where the objective is a simulation metric.\n\nSee `examples/search.ipynb`\n\n```python\nfrom alphavec import grid_search, Metrics, MarketData, SimConfig\n\n# Simple 1D search with dict syntax (most concise)\nresults = grid_search(\n    generate_weights=generate_weights,  # def generate_weights(params: Mapping) -\u003e pd.DataFrame\n    objective_metric=Metrics.SHARPE,  # Type-safe metric names\n    param_grid={\"lookback\": [5, 10, 20, 40]},  # Dict syntax - no Grid2D needed!\n    market=MarketData(close_prices=close_prices, exec_prices=exec_prices, funding_rates=None),\n    config=SimConfig(),\n)\n\n# 2D search with multiple grids\nresults = grid_search(\n    generate_weights=generate_weights,\n    param_grids=[\n        {\"lookback\": [5, 10, 20], \"leverage\": [0.5, 1.0, 2.0]},  # 2D dict\n        {\"lookback\": [5, 10, 20], \"smooth_span\": [1, 5, 10]},   # Another 2D search\n    ],\n    market=market,\n    config=config,\n)\n\n# Minimize risk metrics\nresults = grid_search(\n    generate_weights=generate_weights,\n    objective_metric=Metrics.MAX_DRAWDOWN,\n    maximize=False,  # Minimize drawdown instead of maximize\n    param_grid={\"lookback\": [10, 20, 40]},\n    market=market,\n)\n\n# Access results\nresults.table          # Full results DataFrame\nresults.best.params    # Best parameters\nresults.top(5)         # Top 5 parameter combinations\nresults.summary()      # Summary statistics by grid\nresults.plot()         # Smart plot: line for 1D, heatmap for 2D\n\n# Extract metrics (unified API)\nresults.metric_value(MetricKey.ANNUALIZED_SHARPE)\nresults.available_metrics(\"Performance\")\nresults.metrics_dict(\"Risk\")\n```\n\n### Walk-Forward Analysis\n\n`walk_forward()` splits the simulation period into consecutive time-based folds and computes metrics for each fold independently. This helps assess strategy robustness across different market regimes.\n\nSee `examples/walk_forward.ipynb`\n\n```python\nfrom alphavec import walk_forward, FoldConfig, MetricKey, tearsheet\n\nresult = walk_forward(\n    weights=weights,\n    market=MarketData(close_prices=close_prices, exec_prices=exec_prices),\n    config=SimConfig(\n        fee_rate=0.00025,\n        slippage_rate=0.001,\n        trim_warmup=True,  # Skip periods with no valid weights before folding\n    ),\n    fold_config=FoldConfig(\n        fold_period=\"3ME\",   # 3-month (quarterly) folds\n        min_periods=30,      # Minimum observations per fold\n        align_start=True,    # Align to calendar boundaries\n    ),\n)\n\n# Aggregated metrics across folds\nagg = result.metric_aggregation(MetricKey.ANNUALIZED_SHARPE)\nprint(f\"Median Sharpe: {agg.median:.3f}\")\nprint(f\"Mean Sharpe: {agg.mean:.3f}\")\nprint(f\"Std: {agg.std:.3f}\")\n\n# Per-fold values\nfold_sharpes = result.fold_metric_values(MetricKey.ANNUALIZED_SHARPE)\n\n# Summary stats table\nresult.summary_stats([MetricKey.ANNUALIZED_SHARPE, MetricKey.MAX_DRAWDOWN_EQUITY_PCT])\n\n# Per-fold details\nfor fold in result.folds:\n    print(f\"Fold {fold.fold_index}: {fold.start_period} to {fold.end_period}\")\n    print(f\"  Sharpe: {fold.result.metric_value(MetricKey.ANNUALIZED_SHARPE):.2f}\")\n\n# Generate tearsheets\ntearsheet(sim_result=result.full_result, output_path=\"full_tearsheet.html\")\ntearsheet(sim_result=result.folds[0].result, output_path=\"fold_0_tearsheet.html\")\n\n# Extract metrics (unified API)\nresult.metric_value(MetricKey.ANNUALIZED_SHARPE)  # From full_result\nresult.available_metrics(\"Performance\")\nresult.metrics_dict(\"Risk\")\n```\n\n### Extracting Metrics (Unified API)\n\nAll result types (`SimulationResult`, `GridSearchResults`, `WalkForwardResult`) implement the `MetricsAccessor` protocol, providing a consistent interface for extracting metrics:\n\n```python\nfrom alphavec import MetricKey, MetricsAccessor\n\n# Works identically across all result types:\nresult.metric_value(MetricKey.ANNUALIZED_SHARPE)        # Single metric\nresult.metric_value(MetricKey.ALPHA, default=0.0)      # With default for missing\nresult.available_metrics()                              # All metric keys\nresult.available_metrics(\"Performance\")                 # Filter by category\nresult.metrics_dict()                                   # All as dict\nresult.metrics_dict(\"Risk\")                             # Filter by category\n```\n\nThis unified API eliminates the need for nested access patterns:\n\n```python\n# Before (verbose)\ngrid_results.best.result.metric_value(MetricKey.ANNUALIZED_SHARPE)\nwf_result.full_result.metric_value(MetricKey.ANNUALIZED_SHARPE)\n\n# After (concise)\ngrid_results.metric_value(MetricKey.ANNUALIZED_SHARPE)\nwf_result.metric_value(MetricKey.ANNUALIZED_SHARPE)\n```\n\nWrite generic functions that work with any result type:\n\n```python\ndef report_performance(result: MetricsAccessor) -\u003e None:\n    \"\"\"Works with SimulationResult, GridSearchResults, or WalkForwardResult.\"\"\"\n    print(f\"Sharpe: {result.metric_value(MetricKey.ANNUALIZED_SHARPE):.2f}\")\n    print(f\"Max DD: {result.metric_value(MetricKey.MAX_DRAWDOWN_EQUITY_PCT):.2f}%\")\n    for key, value in result.metrics_dict(\"Performance\").items():\n        print(f\"  {key}: {value}\")\n```\n\n**Note**: For `GridSearchResults`, metrics delegate to `best.result`. For `WalkForwardResult`, metrics delegate to `full_result` (requires `include_full_result=True`). For fold-level metrics in walk-forward, use `metric_aggregation()` or `fold_metric_values()`.\n\n## Metrics\n\n`simulate()` returns a `metrics` DataFrame with `Category`, `Value`, and `Note` columns. Metrics are grouped into categories:\n\n### Categories\n\n1. **Meta**: Simulation metadata and configuration\n2. **Performance**: Returns, volatility, Sharpe ratio, drawdowns\n3. **Costs**: Fees, funding, turnover, order statistics\n4. **Exposure**: Gross/net leverage metrics\n5. **Benchmark**: Alpha, beta, tracking error, information ratio (CAPM)\n6. **Distribution**: Win/loss stats, skewness, kurtosis, drawdown duration\n7. **Portfolio**: Holding periods, weights, cost ratios\n8. **Risk**: Sortino, VaR, CVaR, Omega, downside deviation, Ulcer Index\n9. **Signal**: ICs, decile spreads, hit-rates, and selection vs directional decomposition (vs next-period returns)\n\n### Additional Diagnostics (for charting)\n\nSome richer time series / grouped diagnostics are attached as `metrics.attrs[...]` for use in the tearsheet:\n\n- `result.artifacts` exposes typed access to the same artifacts (for autocomplete/discoverability)\n- `metrics_artifacts(result.metrics)` provides the same access when you only have the metrics table\n\nExample:\n\n```python\nart = result.artifacts\nequity = art.equity\ndrawdown = art.drawdown_pct\nrolling_sharpe = art.rolling_sharpe(30)\nsignal_ic = art.signal.weight_forward\n```\n\n- `metrics.attrs[\"returns\"]`: per-period returns (Series)\n- `metrics.attrs[\"returns_pct\"]`: per-period returns in percent (Series)\n- `metrics.attrs[\"equity\"]`: equity curve (Series)\n- `metrics.attrs[\"equity_pct\"]`: equity curve as cumulative return percent (Series)\n- `metrics.attrs[\"drawdown_pct\"]`: drawdown series in percent (Series)\n- `metrics.attrs[\"rolling_sharpe_30\"]`: 30-period rolling Sharpe (annualized, Series)\n- `metrics.attrs[\"init_cash\"]`: initial cash used for the simulation (float)\n- `metrics.attrs[\"benchmark_equity\"]`: benchmark equity curve when `benchmark_asset` is provided (Series)\n- `metrics.attrs[\"benchmark_equity_pct\"]`: benchmark equity as cumulative return percent (Series)\n- `metrics.attrs[\"turnover\"]`: per-period turnover ratio (Series)\n- `metrics.attrs[\"transaction_costs\"]`: per-period transaction costs as a fraction of equity (Series)\n- `metrics.attrs[\"n_positions\"]`: per-period active positions (Series)\n- `metrics.attrs[\"net_exposure\"]`: per-period net exposure ratio (Series)\n- `metrics.attrs[\"gross_exposure\"]`: per-period gross exposure ratio (Series)\n- `metrics.attrs[\"long_exposure\"]`: per-period long exposure ratio (Series)\n- `metrics.attrs[\"short_exposure\"]`: per-period short exposure ratio (Series)\n- `metrics.attrs[\"concentration\"]`: per-period position concentration (Herfindahl index, Series)\n- `metrics.attrs[\"weight_forward\"]`: per-period signal diagnostics vs next returns (DataFrame), including:\n  - `ic`, `rank_ic`\n  - `top_bottom_spread`\n  - selection vs directional attribution (and per-gross variants)\n- `metrics.attrs[\"weight_forward_deciles\"]`: mean next return by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_median\"]`: median next return by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_std\"]`: std dev of next return by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_count\"]`: observation count `n` by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_contrib\"]`: mean contribution by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_contrib_long\"]`: mean long contribution by weight decile (Series)\n- `metrics.attrs[\"weight_forward_deciles_contrib_short\"]`: mean short contribution by weight decile (Series)\n- `metrics.attrs[\"alpha_decay_next_return_by_type\"]`: alpha decay curve as a DataFrame indexed by lag (periods), with mean next return per gross and t-stats for:\n  - `total_per_gross_*`, `selection_per_gross_*`, `directional_per_gross_*`\n\n`n` is the number of (asset, timestamp) observations that fell into that decile with a non-zero weight and a finite next-period return.\n\nSmoothing in the tearsheet is applied at render time only; the underlying per-period series remain available in `metrics.attrs`.\n\nThe rolling Sharpe series used in the tearsheet is stored as `metrics.attrs[\"rolling_sharpe_N\"]` (N defaults to 30 when no smoothing is applied).\n\n### Statistical Methodology\n\nAlphavec follows **industry-standard statistical practices** for backtesting:\n\n- **Sample statistics** (Bessel's correction, `ddof=1`) for all variance/standard deviation calculations\n  - Rationale: Backtests are samples from possible market outcomes, not complete populations\n  - Aligns with quantstats, empyrical, pyfolio, and academic finance literature\n- **Geometric mean** for total returns (compounds properly over time)\n- **Arithmetic mean** for active returns (matches tracking error calculation for Information Ratio)\n- **Sample covariance** for beta calculation (CAPM-consistent)\n- **Excess kurtosis** (normal distribution = 0, not 3)\n\nThis ensures alphavec metrics are directly comparable to industry benchmarks and professional analytics platforms.\n\n## Tearsheet\n\nThe built-in `tearsheet()` renderer produces a self-contained HTML report (static charts + metrics table), including:\n\n- Equity curve (portfolio and optional benchmark)\n- Drawdown\n- Rolling Sharpe (annualized, default 30 periods; uses `smooth_periods` when \u003e 0)\n- Returns distribution\n- Signal diagnostics (when available): directionality and IC/rank-IC vs next-period return scatters with linear fits, alpha decay by lag (total/selection/directional), and decile charts (mean/median, long/short contribution)\n\n## Tearsheet Example\n\n![Tearsheet](examples/tearsheet.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbreaded-xyz%2Falphavec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbreaded-xyz%2Falphavec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbreaded-xyz%2Falphavec/lists"}