Skip to content

[Audit] Form-4 insider ingestion + conviction net-direction annotation (edgartools) #1461

Description

@stranske

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 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.

Non-Goals

Tasks

  • 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 insider_transactions table (dialect-aware DDL + Alembic migration + schema.sql, mirroring conviction_scores; add to parity gate [Audit] Add schema.sql<->Alembic parity gate; close gin-index/embedding/nullability drift #1308).
  • 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".
  • Dialect parity: insider_transactions present 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).
  • 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_scores schema.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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

agent:codexAssign to Codex agentagents:formattedIssue has been formatted to AGENT_ISSUE_TEMPLATEenhancementNew feature or requestpriority:normalNormal-priority weekly repo-review workstatus: readyReady for Orchestrator opener pickuptestingTests or coverage work

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions