You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implementation of the Form-4 (insider) slice of design issue #1404 (options/short/Form-4 cross-reference). 13F shows only long equity, so the conviction signal is structurally biased. Insider (Form 3/4/5) activity on the issuers managers hold is the cheapest de-bias signal and needs no new vendor: edgartools (pinned edgartools==5.43.0, requirements.txt:6) is already adopted for 13F (adapters/edgar.py:_parse_13f_with_edgartools, uses edgar.thirteenf) and provides Form 3/4/5 parsing. Verified absent at main @ 705e427: no form.?4/insider anywhere in adapters/, etl/, api/, chains/, schema.sql.
Decision resolved (was open in #1404): do the Form-4/insider slice first (edgartools, no new data feed); short-interest + options are deferred to #1404.
Scope
Ingest recent insider (Form 4) transactions for the issuers of securities managers hold, persist them, and annotate conviction/signals with an insider net-direction. Phase 1 = ingest + store + annotate; do NOT re-derive conviction scoring.
Add adapters/insider.py: fetch + normalize Form 4 insider transactions for an issuer (by CIK/ticker) via edgartools' ownership/Form-4 API (confirm the exact entry point, e.g. edgar ownership module, mirroring how adapters/edgar.py wraps edgar.thirteenf). Preserve a stable row contract (issuer_cik, ticker, insider_name, txn_code, shares, txn_date, acquired_disposed).
Add etl/insider_flow.py: resolve held securities → issuer (via holdings.resolved_ticker/resolved_figi from OpenFIGI Add OpenFIGI CUSIP resolution layer #1374, or edgartools company lookup); pull recent Form-4 for those issuers respecting the SEC fair-use governor (adapters/edgar.py_request_with_retry); upsert into insider_transactions.
Expose an insider net-direction annotation: a derived per-(manager,cusip) "insiders net buying/selling over last N days" available to api/signals.py (routes at api/signals.py:313+) and/or as a field joined to conviction output. Read-only; no conviction recompute.
Acceptance Criteria
New test (stubbed edgartools): a fake issuer returning 2 insider buys + 1 sell → insider_transactions gets 3 rows and the net-direction annotation for that issuer is "net buy".
Robustness test: an issuer whose insider fetch raises → conviction rows for that manager are unaffected (no drop, no exception escaping the flow) and the annotation is null/"unknown".
Deliberate-break demonstration: removing the graceful-failure guard makes the robustness test fail (exception escapes / rows dropped); restoring passes.
Implementation Notes
Audit baseline main @ 705e427. Anchors: edgartools adopted (adapters/edgar.py:192_parse_13f_with_edgartools), governor adapters/edgar.py:_request_with_retry, conviction_scoresschema.sql:315 + etl/conviction_flow.py:compute_conviction_scores, resolved identifiers holdings.resolved_ticker/figi (schema.sql:135-137), signals API api/signals.py. First slice of #1404 / epic #1320; short-interest + options remain in #1404.
Why
Implementation of the Form-4 (insider) slice of design issue #1404 (options/short/Form-4 cross-reference). 13F shows only long equity, so the
convictionsignal is structurally biased. Insider (Form 3/4/5) activity on the issuers managers hold is the cheapest de-bias signal and needs no new vendor:edgartools(pinnededgartools==5.43.0,requirements.txt:6) is already adopted for 13F (adapters/edgar.py:_parse_13f_with_edgartools, usesedgar.thirteenf) and provides Form 3/4/5 parsing. Verified absent atmain@705e427: noform.?4/insideranywhere inadapters/,etl/,api/,chains/,schema.sql.Decision resolved (was open in #1404): do the Form-4/insider slice first (edgartools, no new data feed); short-interest + options are deferred to #1404.
Scope
Ingest recent insider (Form 4) transactions for the issuers of securities managers hold, persist them, and annotate conviction/signals with an insider net-direction. Phase 1 = ingest + store + annotate; do NOT re-derive conviction scoring.
Non-Goals
conviction_scorescomputation (etl/conviction_flow.py:compute_conviction_scores) — annotate/join, don't recompute.Tasks
adapters/insider.py: fetch + normalize Form 4 insider transactions for an issuer (by CIK/ticker) via edgartools' ownership/Form-4 API (confirm the exact entry point, e.g.edgarownership module, mirroring howadapters/edgar.pywrapsedgar.thirteenf). Preserve a stable row contract (issuer_cik,ticker,insider_name,txn_code,shares,txn_date,acquired_disposed).insider_transactionstable (dialect-aware DDL + Alembic migration +schema.sql, mirroringconviction_scores; add to parity gate [Audit] Add schema.sql<->Alembic parity gate; close gin-index/embedding/nullability drift #1308).etl/insider_flow.py: resolve held securities → issuer (viaholdings.resolved_ticker/resolved_figifrom OpenFIGI Add OpenFIGI CUSIP resolution layer #1374, or edgartools company lookup); pull recent Form-4 for those issuers respecting the SEC fair-use governor (adapters/edgar.py_request_with_retry); upsert intoinsider_transactions.api/signals.py(routes atapi/signals.py:313+) and/or as a field joined to conviction output. Read-only; no conviction recompute.Acceptance Criteria
insider_transactionsgets 3 rows and the net-direction annotation for that issuer is "net buy".insider_transactionspresent on both SQLite (Alembic) and Postgres (schema.sql) paths (gate [Audit] Add schema.sql<->Alembic parity gate; close gin-index/embedding/nullability drift #1308 green).Implementation Notes
Audit baseline
main@705e427. Anchors: edgartools adopted (adapters/edgar.py:192_parse_13f_with_edgartools), governoradapters/edgar.py:_request_with_retry,conviction_scoresschema.sql:315+etl/conviction_flow.py:compute_conviction_scores, resolved identifiersholdings.resolved_ticker/figi(schema.sql:135-137), signals APIapi/signals.py. First slice of #1404 / epic #1320; short-interest + options remain in #1404.