Repository navigation
feat(research,risk): OpenBB sidecar Sources and an earnings blackout (#141) - #153
Merged
Merged
Conversation
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
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
infra/openbb/(pinnedrequirements.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-gatedopenbbcompose service on127.0.0.1:6900, andinfra/systemd/openbb-api.service(own venv). The trader never imports OpenBB;src/trader/data/openbb.pyis a thin HTTP client.src/trader/research/openbb.py:refresh_openbb(service,POST /research/openbb/refresh,trader openbb refresh, MCPrefresh_openbb), run bytrader-openbb-refresh.timerat 11:30 and 21:30 UTC. By default it covers every Bot's US stocks. It appends one compact dated row per (kind, symbol) toopenbb_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 returnsunavailableand charges no breaker.earnings,options,fundamentalsinloop/sources.py: each reads the newest row at or beforeas_ofand renders its own prompt lane. Rows older than 3 d / 2 d / 10 d are flaggedSTALE. The Source version isopenbb_snapshots.id. Bots can subscribe to them and none does by default. Blind replay drops them because they are not inBLIND_SOURCES.earnings_blackout(src/trader/risk/earnings.py): it denies opens and adds on a US stock fromTRADER_RISK_EARNINGS_BLACKOUT_DAYSsessions before its report through the report session (default 1;0turns 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).openbb(GET /research/openbb,trader openbb show, MCPget_openbb).configuration.md/.env.example(regenerated), CONTEXT.md ("Earnings blackout", Source), architecture.md, decide-change-gate.md.Acceptance criteria
tests/golden/openbb_aapl.jsonholds OBBject bodies, served byhttpx.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.as_ofis not visible), the stale flag, a report date that has already passed, the prompt lanes, and journaledsource_versions.0turning it off, crypto not being affected, the guard reading the database row point in time, and replay.How to switch it on
docker compose -f infra/docker-compose.yml --profile openbb up -d --build openbb, or the systemd unit.TRADER_OPENBB_BASE_URL(http://openbb:6900in compose,http://127.0.0.1:6900for systemd) and restart the trader.trader openbb refreshonce, then enabletrader-openbb-refresh.timer.trader openbb show --kind earningsagainst nasdaq.com.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