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.3.0.tar.gz (22.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.3.0-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: oak_domain_investments-0.3.0.tar.gz
  • Upload date:
  • Size: 22.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.3.0.tar.gz
Algorithm Hash digest
SHA256 4eabfa875fa46495d29317d0cf0e115afde6714ac9df2c7513946d377ce35e12
MD5 0da785ac0ed489f670be28771adfb03e
BLAKE2b-256 b9ad1041095994f18bb842574013496e64a7f3ae9802a9c197f563c8a81d532d

See more details on using hashes here.

Provenance

The following attestation bundles were made for oak_domain_investments-0.3.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.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for oak_domain_investments-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5cc9d25642b2a0170c96f4d3cfcf20300ed27cc950f5644d0e04b87151283c45
MD5 5347585a425ea1e393be2499629c7e54
BLAKE2b-256 6850b312b19b2583770ebf8324b4c7699ab5b234f4c6a381303e63c820028406

See more details on using hashes here.

Provenance

The following attestation bundles were made for oak_domain_investments-0.3.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