Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
# Changelog

Versioning: CalVer `YYYY.MMDD.MICRO`, where `MMDD` is the month and day with the
leading zero dropped (PEP 440 form) and `MICRO` increments for multiple releases
on the same day — e.g. `2026.628.0` for 2026-06-28, `2026.105.0` for Jan 5. The
version is auto-bumped by `scripts/bump_version.py`; it is never hand-set.

## [Unreleased]

## [2026.628.0] - 2026-06-28

### Added
- **Consumer platform rework** — retired the Streamlit dashboard in favor of a
Next.js consumer app over a new HTTP/JSON API (`hrp/api/http`, `python -m
hrp.api.http`): conviction list, recommendation dossier, portfolio, track
record, Vault Assistant, settings, plus 8 research screens (momentum, value,
oversold, strong-trend, above-trend, low-volatility, unusual-volume,
dividends) with a price-data continuity guard.
- **Data-freshness status + staleness banner** (`GET /api/status`) so views are
never silently empty; richer `hrp doctor`.
- **Multi-provider LLM layer** (`hrp/llm`) — consult Claude, GPT, or Z.ai GLM via
the Vault Assistant model selector, `POST /api/consult`, or `hrp consult`.
- **Unified `hrp` service CLI**: `start` / `stop` / `restart` / `status` /
`doctor` / `consult`.

### Changed
- Version scheme adopted: CalVer `YYYY.MMDD.MICRO`.
- FastAPI apps report `hrp.__version__`; `hrp.agents` exports lazily (faster CLI).

### Removed
- Streamlit dashboard (`hrp/dashboard/`) and the `streamlit` / `plotly` /
`streamlit-authenticator` dependencies.

### Added (prior, unreleased)
- **Real-Time Data Ingestion** (TASK-007): WebSocket-based intraday data pipeline:
- `PolygonWebSocketClient`: Auto-reconnecting WebSocket with heartbeat monitoring
- `IntradayBarBuffer`: Thread-safe 10K-bar buffer with batch writes
Expand Down
20 changes: 11 additions & 9 deletions hrp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
Personal quantitative research platform for systematic trading strategy development.
"""

# Read the version from pyproject (CalVer YYYY.MMDD.MICRO, e.g. 2026.628.0) so
# __version__ always matches the source in editable/dev installs without a
# reinstall. Fall back to installed metadata for packaged installs without
# pyproject on disk.
try:
from importlib.metadata import version
import tomllib
from pathlib import Path

__version__ = version("hrp")
pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
with open(pyproject_path, "rb") as f:
__version__ = tomllib.load(f)["project"]["version"]
except Exception:
# Fallback: read version from pyproject.toml
try:
import tomllib
from pathlib import Path
from importlib.metadata import version

pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
__version__ = data["project"]["version"]
__version__ = version("hrp")
except Exception:
__version__ = "0.0.0" # Final fallback

Expand Down
3 changes: 2 additions & 1 deletion hrp/api/http/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware

from hrp import __version__
from hrp.api.http.auth import require_token
from hrp.api.http.routers import (
assistant,
Expand All @@ -27,7 +28,7 @@ def create_app() -> FastAPI:
app = FastAPI(
title="HRP API",
description="Advisory HTTP/JSON API for the HRP consumer front-end",
version="1.0.0",
version=__version__,
)

# CORS for the SPA front-end (different origin/port). Configurable via
Expand Down
4 changes: 3 additions & 1 deletion hrp/ops/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
generate_latest,
)

from hrp import __version__

# Define custom metrics
REQUEST_COUNT = Counter(
"hrp_http_requests_total",
Expand Down Expand Up @@ -68,7 +70,7 @@ def create_app() -> FastAPI:
app = FastAPI(
title="HRP Ops",
description="Health and metrics endpoints for HRP",
version="1.0.0",
version=__version__,
)

@app.get("/health")
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "hrp"
version = "1.9.0"
version = "2026.628.0"
description = "Hedgefund Research Platform - Personal quantitative research for systematic trading"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
82 changes: 82 additions & 0 deletions scripts/bump_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""Auto-bump the project version using CalVer ``YYYY.MMDD.MICRO``.

You never specify the number: the date comes from the clock and ``MICRO``
auto-increments when there is already a release for today. Run this as the first
step of a release (the assistant does this automatically when opening a PR).

python scripts/bump_version.py # bump pyproject + stamp CHANGELOG
python scripts/bump_version.py --print # print the next version, no writes
python scripts/bump_version.py --current # print the current version

``MMDD`` drops the leading zero (PEP 440 form): June 28 -> ``628`` (so today is
``2026.628.0``), Jan 5 -> ``105``. The single source of truth is
``pyproject.toml``; ``hrp.__version__`` reads that literal.
"""

from __future__ import annotations

import re
import sys
from datetime import date
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
PYPROJECT = ROOT / "pyproject.toml"
CHANGELOG = ROOT / "CHANGELOG.md"

# Match the version on the first `version = "..."` line of [project].
_VERSION_RE = re.compile(r'^version = "([^"]+)"', re.MULTILINE)


def current_version() -> str:
match = _VERSION_RE.search(PYPROJECT.read_text())
if not match:
raise SystemExit("error: could not find `version` in pyproject.toml")
return match.group(1)


def next_version(today: date | None = None) -> str:
"""Today's CalVer, incrementing MICRO past any existing same-day release."""
today = today or date.today()
# MMDD with no leading zero (PEP 440 form): June 28 -> 628, Jan 5 -> 105.
prefix = f"{today.year}.{today.month * 100 + today.day}"
current = current_version()
micro = 0
if current.startswith(prefix + "."):
try:
micro = int(current.rsplit(".", 1)[1]) + 1
except ValueError:
micro = 0
return f"{prefix}.{micro}"


def _stamp_changelog(version: str) -> None:
if not CHANGELOG.exists():
return
text = CHANGELOG.read_text()
header = f"## [{version}] - {date.today().isoformat()}"
if header in text:
return
marker = "## [Unreleased]"
if marker in text:
# Open a release section right under [Unreleased]; it inherits the
# accumulated unreleased notes, leaving a fresh empty [Unreleased] on top.
text = text.replace(marker, f"{marker}\n\n{header}", 1)
CHANGELOG.write_text(text)


def bump() -> str:
new = next_version()
PYPROJECT.write_text(_VERSION_RE.sub(f'version = "{new}"', PYPROJECT.read_text(), count=1))
_stamp_changelog(new)
return new


if __name__ == "__main__":
if "--current" in sys.argv:
print(current_version())
elif "--print" in sys.argv:
print(next_version())
else:
print(bump())
Loading