Skip to content

feat(research,risk): OpenBB sidecar Sources and an earnings blackout (#141) - #153

Merged
sudoTomas merged 3 commits into
mainfrom
feat/openbb-sources
Nov 4, 2026
Merged

sudoTomas merged 3 commits into
mainfrom
feat/openbb-sources

Conversation

@sudoTomas

Copy link
Copy Markdown
Owner

What changed

  • Sidecar (not deployed): infra/openbb/ (pinned requirements.txt: openbb-core 2.0.1, openbb-platform-api 2.0.1, equity/derivatives/news routers, nasdaq/cboe/sec/finra providers, all 2.0.0; Dockerfile), a profile-gated openbb compose service on 127.0.0.1:6900, and infra/systemd/openbb-api.service (own venv). The trader never imports OpenBB; src/trader/data/openbb.py is a thin HTTP client.
  • Producer src/trader/research/openbb.py: refresh_openbb (service, POST /research/openbb/refresh, trader openbb refresh, MCP refresh_openbb), run by trader-openbb-refresh.timer at 11:30 and 21:30 UTC. By default it covers every Bot's US stocks. It appends one compact dated row per (kind, symbol) to openbb_snapshots (migration 0016). Each provider has a breaker: 3 failures in a row skip that provider for 6 h. A failed fetch writes nothing. An unreachable sidecar returns unavailable and charges no breaker.
  • Sources earnings, options, fundamentals in loop/sources.py: each reads the newest row at or before as_of and renders its own prompt lane. Rows older than 3 d / 2 d / 10 d are flagged STALE. The Source version is openbb_snapshots.id. Bots can subscribe to them and none does by default. Blind replay drops them because they are not in BLIND_SOURCES.
  • RiskGuard check 5b earnings_blackout (src/trader/risk/earnings.py): it denies opens and adds on a US stock from TRADER_RISK_EARNINGS_BLACKOUT_DAYS sessions before its report through the report session (default 1; 0 turns it off). Sessions are counted on the NYSE calendar. Exits return before this check, so closes, trims and the stop always pass. If the calendar row is missing or stale (>3 d), the check fails open: it logs a warning and the allow verdict says "blackout not applied", which is journaled with the decision. The replay crude book applies the same check at each step's point in time (earnings_blackout_denied).
  • Read door openbb (GET /research/openbb, trader openbb show, MCP get_openbb).
  • Docs: deploy runbook section "OpenBB sidecar", configuration.md / .env.example (regenerated), CONTEXT.md ("Earnings blackout", Source), architecture.md, decide-change-gate.md.

Acceptance criteria

  • Producer tests with recorded fixtures, no network: done. tests/golden/openbb_aapl.json holds OBBject bodies, served by httpx.MockTransport. Tests cover the summaries, the 204 "no data" response, Cboe failing over to Nasdaq, the breaker tripping and then closing, and the sidecar being unreachable.
  • Source rendering tests: done. They cover the dated note for each kind, the pinned read (a row fetched after as_of is not visible), the stale flag, a report date that has already passed, the prompt lanes, and journaled source_versions.
  • RiskGuard blackout tests: done. They cover the session before and the report session, adds, the window counting sessions rather than calendar days (Friday before a Monday report), exits always passing, failing open on a missing or stale calendar, 0 turning it off, crypto not being affected, the guard reading the database row point in time, and replay.
  • Live check on the box (earnings dates for the 6 large caps match Nasdaq's site): NOT done. Nothing was deployed and there was no SSH access. It is an operator step in the runbook.
  • Docs: deploy runbook, configuration.md, CONTEXT.md: done.

How to switch it on

  1. Start the sidecar: docker compose -f infra/docker-compose.yml --profile openbb up -d --build openbb, or the systemd unit.
  2. Set TRADER_OPENBB_BASE_URL (http://openbb:6900 in compose, http://127.0.0.1:6900 for systemd) and restart the trader.
  3. Run trader openbb refresh once, then enable trader-openbb-refresh.timer.
  4. Check trader openbb show --kind earnings against nasdaq.com.
  5. Subscribe Bot Walk first live-paper acceptance (was EAI-176 / epic EAI-164) #2 with trader bot version bot-2-largecap --source … --source earnings --source options --source fundamentals. This goes through the decide-change gate.

The blackout is on by default but stays inert until the producer has written calendar rows. Until then it fails open with a warning.

Tests

29 new tests in tests/test_openbb.py. The full suite passes (960). test_supervisor.py::test_the_semaphore_caps_concurrent_decide_calls[4] failed once under machine load and passed on 3 reruns; it is timing-based and unrelated to this change.

Closes #141

https://claude.ai/code/session_01UDNLNu854ULHbHSL59UJKu

OpenBB (Apache-2.0) runs as its own openbb-api sidecar, pinned, in its own
venv (infra/systemd/openbb-api.service) or container (compose service
`openbb`, profile-gated). The trader only calls its REST routes
(data/openbb.py); it never imports OpenBB.

A producer (research/openbb.py, `refresh_openbb` on every door,
trader-openbb-refresh.timer twice a day) asks keyless providers for every
Bot's US stocks and appends one compact dated row per kind to
openbb_snapshots (migration 0016): the next earnings report, its time and
consensus EPS plus the last surprise (Nasdaq); ATM IV, implied move and
put/call skew at the next expiry (Cboe, Nasdaq fallback); price targets,
ratios, insider trades and short interest (Nasdaq, SEC, FINRA). Each
provider has a breaker (3 failures in a row skip it for 6 h); a failed
fetch writes nothing, and an unreachable sidecar charges no provider.

New Sources `earnings`, `options`, `fundamentals` (off unless a Bot
subscribes) render the newest row at or before as_of, flagged STALE past
3 d / 2 d / 10 d; the row id is the Source version. Blind replays drop them.

RiskGuard gains check 5b, earnings_blackout: no opens or adds on a US stock
from TRADER_RISK_EARNINGS_BLACKOUT_DAYS (default 1, 0 = off) sessions
before its report through the report session. Exits never reach it. With
no calendar row or a stale one it fails open, logs a warning, and its
allow verdict (journaled with the decision) says so. Replay's crude book
runs it point in time (earnings_blackout_denied).

Closes #141.

Claude-Session: https://claude.ai/code/session_01UDNLNu854ULHbHSL59UJKu
OpenBB Sources carry available_at = the row's fetch time (no older vintage)
and have look-ahead cases in tests/test_point_in_time.py. Migration 0016
stays: the migrator applies any unapplied name, so it lands after 0017.

Claude-Session: https://claude.ai/code/session_01UDNLNu854ULHbHSL59UJKu
@sudoTomas
sudoTomas merged commit bee3a14 into main Nov 4, 2026
1 check passed
@sudoTomas
sudoTomas deleted the feat/openbb-sources branch November 4, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenBB sidecar: earnings, options and fundamentals Sources + earnings blackout

1 participant