300 lines
9.0 KiB
TOML
300 lines
9.0 KiB
TOML
[project]
|
|
name = "ml4t"
|
|
version = "3.0.0"
|
|
description = "Machine Learning for Algorithmic Trading — 3rd Edition"
|
|
readme = "README.md"
|
|
requires-python = ">=3.14"
|
|
license = "MIT"
|
|
authors = [{ name = "Stefan Jansen" }]
|
|
|
|
dependencies = [
|
|
# ===================
|
|
# Core Data Science
|
|
# ===================
|
|
"numpy>=1.26",
|
|
# scipy<1.18: 1.18 removed the private scipy.cluster.hierarchy._LINKAGE_METHODS
|
|
# that PyPortfolioOpt 1.6.0 (latest) still references for HRP linkage validation
|
|
# (Ch17 08_library_comparison). Lift once pypfopt ships a scipy>=1.18 fix.
|
|
"scipy>=1.12,<1.18",
|
|
"pandas>=2.2",
|
|
"polars>=1.0",
|
|
"pyarrow>=15.0",
|
|
# ===================
|
|
# Visualization
|
|
# ===================
|
|
"plotly>=5.20",
|
|
"matplotlib>=3.8",
|
|
"seaborn>=0.13",
|
|
"kaleido==0.2.1",
|
|
# ===================
|
|
# Machine Learning
|
|
# ===================
|
|
"scikit-learn>=1.4",
|
|
"xgboost>=3.1",
|
|
"lightgbm>=4.6",
|
|
"catboost>=1.2.8",
|
|
"optuna>=3.6",
|
|
"optuna-integration[lightgbm]>=4.8",
|
|
"shap>=0.45",
|
|
"tabpfn>=2.0",
|
|
"gymnasium>=1.2",
|
|
"stable-baselines3>=2.7",
|
|
# ===================
|
|
# ML4T Libraries (PyPI, pre-release)
|
|
# ===================
|
|
"ml4t-data>=0.1.0b15",
|
|
"ml4t-diagnostic>=0.1.0b21",
|
|
"ml4t-engineer>=0.1.0b8",
|
|
"ml4t-backtest>=0.1.0b20",
|
|
"ml4t-live>=0.1.0b3",
|
|
# ===================
|
|
# Deep Learning
|
|
# ===================
|
|
"torch>=2.2",
|
|
"pytorch-lightning>=2.2",
|
|
"torchdiffeq>=0.2",
|
|
# torchode (Lienen & Günnemann 2022) would offer per-sample adaptive
|
|
# integration in Ch5 NB04 but its torchtyping dependency is incompatible
|
|
# with torch>=2.10, so the notebook uses torchdiffeq instead.
|
|
"transformers>=4.40,<5",
|
|
"sentencepiece>=0.2",
|
|
"sentence-transformers>=2.6",
|
|
"einops>=0.7",
|
|
"granite-tsfm>=0.3",
|
|
"chronos-forecasting>=1.4",
|
|
# ===================
|
|
# Time Series
|
|
# ===================
|
|
"statsmodels>=0.14",
|
|
"arch>=8.0",
|
|
"pmdarima>=2.0",
|
|
"sktime>=0.30",
|
|
"darts>=0.28",
|
|
"statsforecast>=1.7",
|
|
"hmmlearn>=0.3",
|
|
"filterpy>=1.4",
|
|
"pykalman>=0.11",
|
|
"pywavelets>=1.6",
|
|
"ruptures>=1.1",
|
|
# ===================
|
|
# Causal Inference
|
|
# ===================
|
|
"dowhy>=0.11",
|
|
"econml>=0.15",
|
|
"causalml>=0.15",
|
|
"tigramite>=5.2",
|
|
# tfcausalimpact (BSTS, Ch15 NB06): py312 image only — requires Python <3.13.
|
|
# See envs/py312/pyproject.toml; pycausalimpact (ARIMA, 2020-dead) removed.
|
|
"causal-learn>=0.1",
|
|
"linearmodels>=6.0",
|
|
# ===================
|
|
# NLP / Text
|
|
# ===================
|
|
# gensim: word2vec/Doc2Vec only (Ch10 NB01-02). No Python 3.14 support.
|
|
# Use Docker: docker compose --profile word2vec run --rm word2vec python ...
|
|
"datasets>=2.19",
|
|
"evaluate>=0.4",
|
|
# ===================
|
|
# Portfolio / Finance
|
|
# ===================
|
|
"PyPortfolioOpt>=1.5",
|
|
"riskfolio-lib>=6.0",
|
|
"skfolio>=0.3",
|
|
"vectorbt>=0.26",
|
|
# ===================
|
|
# Data Sources
|
|
# ===================
|
|
"yfinance>=0.2",
|
|
"edgartools>=5.9",
|
|
# sec-edgar-api: removed — no notebook imports it (they use edgartools).
|
|
# sec-edgar-api 1.1.0 is broken with pyrate-limiter 4.x anyway.
|
|
"secedgar>=0.6",
|
|
"iex-parser>=1.7",
|
|
"beautifulsoup4>=4.12",
|
|
"cot-reports>=0.1",
|
|
"databento>=0.47.0",
|
|
"gdown>=5.1",
|
|
"oandapyV20>=0.7",
|
|
# ===================
|
|
# Technical Analysis
|
|
# ===================
|
|
"ta-lib>=0.6.8",
|
|
"ta>=0.11",
|
|
# ===================
|
|
# Synthetic Data
|
|
# ===================
|
|
"be-great>=0.0.5",
|
|
"opacus>=1.4",
|
|
# signatory/esig: separate env (envs/py312/). Only Ch5 NB03, Ch9 NB06/12.
|
|
# ===================
|
|
# Strategy
|
|
# ===================
|
|
"exchange-calendars>=4.5",
|
|
# ===================
|
|
# Utilities
|
|
# ===================
|
|
"python-dotenv>=1.0",
|
|
"pyyaml>=6.0",
|
|
"tqdm>=4.66",
|
|
"rich>=13.7",
|
|
"requests>=2.31",
|
|
"nest-asyncio>=1.6",
|
|
"neo4j>=5.28",
|
|
"thefuzz>=0.22",
|
|
"rapidfuzz>=3.6",
|
|
"psutil>=5.9",
|
|
"sympy>=1.12",
|
|
"openpyxl>=3.1",
|
|
"numba>=0.59",
|
|
"papermill>=2.6",
|
|
# ===================
|
|
# Jupyter
|
|
# ===================
|
|
"jupyter>=1.0",
|
|
"notebook>=7.0",
|
|
"jupytext>=1.16",
|
|
"jupyterlab>=4.1",
|
|
"ipython>=8.22",
|
|
"anywidget>=0.9",
|
|
"nbconvert>=7.16",
|
|
"nbformat>=5.10",
|
|
# ===================
|
|
# File Formats
|
|
# ===================
|
|
"tables>=3.10",
|
|
"duckdb>=1.0",
|
|
"mlflow>=3.10.1",
|
|
"arviz>=0.23.4,<1.0",
|
|
"feast>=0.61",
|
|
"pymc>=5.25.1",
|
|
"pyvis>=0.3.2",
|
|
"llama-index-core>=0.14.20",
|
|
"llama-index-embeddings-huggingface>=0.7.0",
|
|
"chromadb>=1.5.5",
|
|
"pfhedge>=0.22.0",
|
|
"ml4t-models>=0.1.0a4",
|
|
"llama-index-vector-stores-chroma>=0.5.5",
|
|
"llama-index-llms-openai>=0.7.7",
|
|
# Ch24 Autonomous Agents (required at notebook runtime; Docker installs
|
|
# main deps only, so these must not live in an optional-dependencies group)
|
|
"crewai>=0.86",
|
|
# litellm enters transitively via crewai. Pin the security floor directly:
|
|
# crewai's newest 0.x (0.118) caps litellm <1.83, which carries proxy-server
|
|
# CVEs (GHSA OIDC bypass / proxy-config priv-esc). The book only uses litellm
|
|
# as a client lib, but we keep the patched line anyway; this floor holds
|
|
# crewai at 0.95 (last 0.x allowing litellm>=1.83). crewai 1.x needs
|
|
# chromadb<1.2, which conflicts with the Ch22 RAG stack.
|
|
"litellm>=1.83.0",
|
|
"langgraph>=0.2",
|
|
"google-genai>=0.3",
|
|
# Anthropic is the first provider in the Ch24 agent auto-detect cascade
|
|
# (agent_providers.create_llm_client). It is a runtime dependency, not a
|
|
# dev tool — readers with ANTHROPIC_API_KEY set need it in the Docker image.
|
|
"anthropic>=0.89.0",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
# Database benchmark extras (requires Docker for servers)
|
|
db-benchmark = [
|
|
"arcticdb>=4.5",
|
|
"clickhouse-connect>=0.7",
|
|
"psycopg2-binary>=2.9",
|
|
"influxdb-client>=1.45",
|
|
"questdb>=2.0",
|
|
]
|
|
# Bayesian modeling
|
|
bayesian = [
|
|
"pymc>=5.14",
|
|
"arviz>=0.18,<1.0",
|
|
]
|
|
# MLOps (Ch26)
|
|
mlops = [
|
|
"feast>=0.61",
|
|
"mlflow>=2.16",
|
|
]
|
|
# Live Trading (Ch25)
|
|
live = [
|
|
"ib_insync>=0.9",
|
|
"python-okx>=0.3",
|
|
"alpaca-py>=0.33",
|
|
]
|
|
# Development tools
|
|
dev = [
|
|
"pytest>=8.0",
|
|
"pytest-rerunfailures>=15.0",
|
|
"jupytext>=1.16",
|
|
"pre-commit>=3.6",
|
|
"ruff>=0.8",
|
|
]
|
|
|
|
[tool.uv]
|
|
# ml4t-engineer only has pre-release versions on PyPI
|
|
prerelease = "if-necessary-or-explicit"
|
|
|
|
# Force protobuf >= 5.0 for Python 3.14 compatibility.
|
|
# protobuf 4.x has a C extension metaclass bug on Python 3.14.
|
|
# opentelemetry-proto 1.27.0 pins protobuf<5; override until it upgrades.
|
|
override-dependencies = [
|
|
"protobuf>=5.0",
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["setuptools>=77", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"httpx>=0.28.1",
|
|
]
|
|
|
|
[tool.setuptools.packages.find]
|
|
include = ["utils", "data", "case_studies"]
|
|
namespaces = false
|
|
|
|
# Auto-loaded at interpreter startup to put numbered chapter dirs on sys.path
|
|
# (see sitecustomize.py). Shipped as a top-level module so both the editable
|
|
# install (local) and a wheel install resolve it.
|
|
[tool.setuptools]
|
|
py-modules = ["sitecustomize"]
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
# Vendored upstream code (MIT-licensed PatchTST reference) — don't lint/modify.
|
|
extend-exclude = ["**/_reference/**"]
|
|
# Keep at py312 even though requires-python is >=3.14. With
|
|
# target-version = "py314", ruff/pyupgrade rewrites `except (A, B):`
|
|
# to PEP 758's unparenthesized `except A | B:` form. Until our minimum
|
|
# runtime support and reader tooling catches up to py314, we pin py312
|
|
# so ruff preserves the parenthesized tuple-catch form.
|
|
target-version = "py312"
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
ignore = [
|
|
"E501", # Line length handled by formatter
|
|
"E402", # Module level import not at top - OK for notebooks
|
|
"F401", # Imported but unused - OK for conditional imports in notebooks
|
|
"F811", # Redefinition of unused variable - OK in notebook cells
|
|
"B006", # Mutable argument defaults - common pattern in notebooks
|
|
"B007", # Loop variable not used - intentional in some cases
|
|
"B018", # Useless expression - intentional in notebooks to display output
|
|
"B905", # zip without strict= - bare zip reads cleaner in teaching code
|
|
"F822", # Undefined in __all__ - forward declarations
|
|
"E741", # Ambiguous variable names (l, I, O) - common in math/ML code
|
|
"F841", # Local variable assigned but never used - common in exploratory notebooks
|
|
"SIM102", # Use single if statement - readability preference
|
|
"SIM105", # contextlib.suppress over try/except/pass - explicit form clearer
|
|
"SIM108", # Use ternary operator - readability preference
|
|
"SIM113", # Use enumerate - readability preference
|
|
"SIM118", # Use `key in dict` - both forms acceptable
|
|
]
|
|
|
|
[tool.jupytext]
|
|
formats = "ipynb,py:percent"
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
python_functions = ["test_*"]
|
|
addopts = "-v --tb=short -p no:torchtyping"
|