Skip to main content

ppofolio

tests PyPI license

A PPO seed-ensemble that allocates a portfolio across BTC, ETH and SOL from technical, on-chain and macro features. Classical deep RL (Stable-Baselines3, not LLM-based), inspired by Meta-RL-Crypto (arXiv:2509.09751). This is the public release of a private research project; the history starts at the first public version.

What makes it different from the average "RL trading bot" repo is the evaluation discipline, not the model:

  • a pre-registered evaluation protocol (EVAL_PROTOCOL.md) written before results exist, with decision rules fixed in advance,
  • burned held-out test windows — each is touched once per candidate generation, then never used for selection again,
  • honest baselines (buy-and-hold, rebalanced B&H, MACD, risk parity, 200-day trend filter) evaluated on every window,
  • a model manifest (models/MANIFEST.json) recording every candidate's verdict — including the failures.

Honest results

The current ensemble failed its pre-registered held-out gate: on the burned test window it returned −12.4% against buy-and-hold's −8.25%. On the validation window it returned +16.6% — but that is the selection window, so the number is selection-biased by construction. Simulated under the deployed execution stack (concentration caps, per-trade caps, volatility circuit breaker, kill switch) the validation figure is +11.3%. The system is deployed for forward paper evaluation only and is not qualified for real money by its own rules. The evaluation protocol exists precisely so this paragraph cannot be written any other way.

Architecture

data        ccxt OHLCV · CoinMetrics on-chain · GNews + LLM sentiment (optional) · fear/greed, dominance, funding
  └─ features    per-asset technical indicators + regime features -> one wide panel (ASSET__feature)
       └─ env         Gymnasium env: obs = lookback window + weights + cash, action = target weights
            └─ agents      PPO seed ensemble (Stable-Baselines3), averaged target weights
                 └─ safety chain   volatility circuit breaker -> kill switch (halt + recovery-gated resume) -> hard risk limits
                      └─ broker        paper broker (SQLite or Postgres), FastAPI service + dashboard

The safety-chain ordering (model → breaker → kill switch → limits → broker) is a deliberate design constraint. The multi-objective reward mixes return, rolling Sharpe, drawdown, liquidity and loss asymmetry.

Install

Library (env, rewards, brokers, backtest metrics):

pip install ppofolio --extra-index-url https://download.pytorch.org/whl/cpu

Full research workflow (dataset building, training, backtesting, paper trading):

git clone https://github.com/mohammadi-hadi/ppofolio && cd ppofolio
make install          # pip install -e ".[dev]"
make dataset          # build the feature panel (public APIs, no keys required)
make train            # PPO training
make backtest         # walk-forward eval vs baselines -> reports/
make paper            # paper-trading loop
make serve            # FastAPI service + dashboard

scripts/train_ensemble.sh trains the 3-seed ensemble; scripts/eval_system.py evaluates the full system (policy + circuit breaker + kill switch + risk limits) over an arbitrary window, which is what the protocol gates on.

Layout

path what
ppofolio/data fetchers with cache-on-disk (load_or_fetch) + dataset assembly
ppofolio/features technical indicators, regime features, panel assembly
ppofolio/env Gymnasium trading environment
ppofolio/rewards weighted multi-objective reward
ppofolio/agents training entry points + seed ensemble
ppofolio/backtest walk-forward evaluation + rule-based baselines
ppofolio/live decision loop, circuit breaker, kill switch, risk limits, brokers
ppofolio/serve FastAPI service, scheduler, dashboard
configs/ daily / hourly / smoke configs (--config on every entry point)
EVAL_PROTOCOL.md pre-registered evaluation rules + change log

Caveats

  • News/LLM sentiment is off by default: the shipped configuration was trained with sentiment zeroed, so enabling it at inference is distribution shift. Re-enable only together with a retrain.
  • SOL on-chain data is patchy before 2021 (CoinMetrics community tier); the pipeline forward-fills then zero-fills.
  • Trained model weights are not distributed; train your own with scripts/train_ensemble.sh.
  • Training splits start 2021-08 because 180-day returns and the 200-day MA need warmup.

Disclaimer

Research software for studying RL evaluation methodology on market data. Nothing here is financial advice, and the honest-results section above should make clear that using it to trade real money would be a bad idea.

Cite

@software{mohammadi_ppofolio,
  author  = {Mohammadi, Hadi},
  title   = {ppofolio: PPO ensemble for multi-asset crypto portfolio allocation},
  url     = {https://github.com/mohammadi-hadi/ppofolio},
  version = {0.1.0},
  year    = {2026}
}

See CITATION.cff.

License

MIT © 2026 Hadi Mohammadi

Release files for ppofolio 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ppofolio 0.1.0
File Size Uploaded
ppofolio-0.1.0.tar.gz 74.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ppofolio 0.1.0
File Interpreter ABI Platform
ppofolio-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 145.9 kB

Release files / ppofolio-0.1.0.tar.gz

Download URL ppofolio-0.1.0.tar.gz
Size 74.5 kB
Tags Source
SHA-256 checksum
How to use checksums
22a76c14b44d4815d5277b7cc96c74c30fd5722ba506804a7f63b670e8e62e6a
BLAKE2b-256 checksum
How to use checksums
9eb0996b2994a3468514fdc5a342676f8f84321a4729bcbbae2be36190c145f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / ppofolio-0.1.0-py3-none-any.whl

Download URL ppofolio-0.1.0-py3-none-any.whl
Size 71.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2387229cc0722565a2af22edcb20a30925ae10134706730be41c85a3a36a97a2
BLAKE2b-256 checksum
How to use checksums
e147065b6e5623863b1787c0e117d6fb019d12487061da977398347fd350205f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page