Skip to main content

Investments domain plugin for the OakQuant timber substrate (watchlist capability migrated from grove core; more to follow).

Project description

oak-domain-investments

The investments domain plugin for OakQuant's Timber substrate — discoverable, 3-layer, migrating in one capability at a time.

License: Apache-2.0 Python

What it is

Investment logic is moving out of OakQuant's grove/timber core and into this package, deliberately one capability at a time so each move is small, isolated, and low-risk. This README documents the current state and is expected to grow as more capabilities land.

The package is a discoverable plugin: it advertises itself through entry points and registers into the host's shared registries (Timber's model/service registries, grove's app, acorn's tool registry) — never by editing the core libraries. See the oak-domain-plugins skill for the wider plugin shape.

First migrated capability: the watchlist (capability #1). It exercises all three layers of the plugin system end to end.

The 3-layer shape

A single installed package plugs into three OakQuant layers, one entry point per group. Each host discovers only its own group and imports only that entry point's module, so the timber layer never pulls in grove/FastAPI or acorn.

Layer Entry-point group Class Contributes
timber timber.domains InvestmentsDomain WatchlistItem ORM model + WatchlistService, registered at init (Step 8.5) into Timber's model/service registries
grove grove.domains InvestmentsGroveDomain The watchlist HTTP router, mounted on grove's app at startup
acorn acorn.domains InvestmentsAcornDomain A get_watchlist agent tool, registered into acorn's Oracle at startup

The grove and acorn plugins delegate to the same WatchlistService that the timber layer registers (reached through Timber's service_registry.domain("investments")), so there is one implementation behind all three surfaces.

Capability #1: the watchlist

Symbols a user tracks without necessarily owning them.

Model — WatchlistItem (oak_domain_investments/models.py)

A common.models.base.Base model (TimestampMixin) for table watchlist_items, migrated field-for-field from grove's config/models/watchlist_models.yaml so existing rows keep working:

  • id (UUID str PK), user_id (FK → users.id), symbol (uppercase ticker), name, notes
  • alert_above / alert_below (price alert thresholds)
  • statusactive | removed (the service soft-deletes via status)
  • Unique index on (user_id, symbol); index on (user_id, status)

Exported as DOMAIN_MODELS and registered before Step 9 create_all, so the table exists.

Service — WatchlistService (oak_domain_investments/services/watchlist_service.py)

Takes its DB from the injected ctx.db; enriches with Timber's stock_data_service on a best-effort basis. The per-tier max_watchlist limit is not here — it's a grove-billing concern enforced by the grove router.

  • get_watchlist(user_id, include_prices=True) — active items, with optional current prices + alert_triggered state
  • add_to_watchlist(user_id, symbol, name=None, notes=None) — idempotent on active (user, symbol); resolves company name best-effort
  • remove_from_watchlist(item_id) — soft-delete (status="removed")
  • update_alerts(item_id, alert_above=None, alert_below=None) — set/clear alerts (a non-positive value clears)

Grove HTTP surface (oak_domain_investments/grove_plugin.py)

InvestmentsGroveDomain mounts a router that delegates to WatchlistService and applies the best-effort max_watchlist tier gate on add:

  • GET {prefix} — list the user's watchlist
  • POST {prefix} — add a symbol
  • DELETE {prefix}/{item_id} — remove (soft-delete)
  • PUT {prefix}/{item_id}/alerts — set/clear price alerts

Phase 1 mounts at /investments/watchlist (a non-conflicting path while grove core's /api/v3/watchlist still exists). Phase 2 — after the core route is removed — repoints this to the canonical /api/v3/watchlist.

Acorn agent tool (oak_domain_investments/acorn_plugin.py)

InvestmentsAcornDomain contributes a get_watchlist(user_id) tool (RiskTier.READ) to acorn's Oracle. It reads WatchlistItem directly through Timber's db_service (a synchronous, user-scoped read, no HTTP round-trip) and returns the active watchlist as markdown.

Migration status

InvestmentsInfoService (services/info_service.py) reports what has migrated: MIGRATED_CAPABILITIES = ["watchlist"]. This list grows as portfolio, thresholds, and other capabilities move in. Investment logic that hasn't migrated yet still lives in timber core (common/services/data_fetcher/, data_processor/portfolio_metrics.py, vendors/plaid_service.py).

How discovery works

Each host loads only its own entry-point group:

  • timber.domainsoak_domain_investments:InvestmentsDomain
  • grove.domainsoak_domain_investments.grove_plugin:InvestmentsGroveDomain
  • acorn.domainsoak_domain_investments.acorn_plugin:InvestmentsAcornDomain

Once the package is installed, discovery is automatic via these entry points. For local development against checkouts, each host also honors an env-var fallback (e.g. TIMBER_DOMAIN_PLUGINS=oak_domain_investments:InvestmentsDomain) so the plugin loads without a reinstall.

Install

pip install oak-domain-investments

Requires Python 3.11+ and timber-common>=0.6.16. The import package is oak_domain_investments.

Develop / test against a sibling timber checkout:

# from the repo root, with ../timber on the path
PYTHONPATH=../timber:. TIMBER_DOMAIN_PLUGINS=oak_domain_investments:InvestmentsDomain \
  python3 -m pytest tests/ -q

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oak_domain_investments-0.7.0.tar.gz (34.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oak_domain_investments-0.7.0-py3-none-any.whl (34.7 kB view details)

Uploaded Python 3

File details

Details for the file oak_domain_investments-0.7.0.tar.gz.

File metadata

  • Download URL: oak_domain_investments-0.7.0.tar.gz
  • Upload date:
  • Size: 34.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for oak_domain_investments-0.7.0.tar.gz
Algorithm Hash digest
SHA256 59a8a06b76bd4a882c51e6997de1bb2478b5437c9fa709837ceafaac9a445a5f
MD5 568165ba5c36e991fbadf6d8d260ae22
BLAKE2b-256 4597cba6a197b7383a2a99f70bc1b8ce9cebb83dbfb4bb2efe7d3ca7da64444d

See more details on using hashes here.

Provenance

The following attestation bundles were made for oak_domain_investments-0.7.0.tar.gz:

Publisher: release.yml on oakquant-ai/oak-domain-investments

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oak_domain_investments-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for oak_domain_investments-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a81da600aa4175255cfd947726ea809decdb973dfca74287bd92d683e805083d
MD5 731f5f7fa18ce3d61be2c1f2520c5d00
BLAKE2b-256 c7e23ddcafe735a176e5b0f8d86d6e29b5c84959069bdcdbae4c1204a2906160

See more details on using hashes here.

Provenance

The following attestation bundles were made for oak_domain_investments-0.7.0-py3-none-any.whl:

Publisher: release.yml on oakquant-ai/oak-domain-investments

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page