CoolFace
Datasetpublic

ZipLime/insider-sale-notices

US Insider Sale Notices — SEC Form 144 Every notice a corporate insider files before selling restricted or control stock, normalized into a point-in-time schema and rebuilt daily. 124 886 notices covering 2023-01-04 to 2026-09-04, from 4 237 issuers and 23 871 sellers, with the acceptance timestamp of every filing to the second. The pipeline that produces this dataset lives in recipe/ inside this same repository, at the same revision as the data. See PIPELINE.md for the method… See the full description on the dataset page: https://huggingface.co/datasets/ZipLime/insider-sale-notices.

sourceHugging Faceapache-2.0updated 5h agoView on Hugging Face
0likes926downloads
Dataset Card

US Insider Sale Notices — SEC Form 144

Every notice a corporate insider files before selling restricted or control stock, normalized into a point-in-time schema and rebuilt daily.

124 886 notices covering 2023-01-04 to 2026-09-04, from 4 237 issuers and 23 871 sellers, with the acceptance timestamp of every filing to the second.

The pipeline that produces this dataset lives in `recipe/` inside this same repository, at the same revision as the data. See PIPELINE.md for the method, including what it refuses to do.

What makes this form different from everything else

*A Form 144 is filed before the sale.* Form 4 reports a trade that already happened, within two business days. Form 144 announces a trade that has not happened yet — the insider states how many shares they intend to sell, through which broker, and on approximately what date.

That inverts the usual relationship between the two dates in this dataset:

knowledge_date   the second EDGAR accepted the notice — when you could read it
event_date       the day the seller says the sale may begin — usually later

In 91% of notices the intended sale date falls on or after the day the notice became public. Do not normalise this away. A pipeline that assumes disclosure follows the event will read these rows as broken and repair them into uselessness; the forward-looking date is the entire content of the form.

The join that makes it worth having

issuer_cik and owner_cik are the same identifiers used by ZipLime/insider-trading, the Form 4 dataset. entity_id in the pit config is the issuer CIK in both, so the two point-in-time tables join directly — no ticker dictionary in between, no name matching.

That gives you the pair the market cannot see in either form alone:

Form 144 (this dataset)Form 4 (insider-trading)
what it saysintends to sell N sharessold N shares
filedbefore the salewithin 2 business days after
identifiersissuer_cik, owner_cikissuer_cik, reporting_owner_cik

Follow-through — how much of the announced amount was actually sold, and how fast — is computable from the two datasets and is not shipped precomputed: the answer depends on the window you consider, and baking a window in would be a choice made for you.

python
from datasets import load_dataset

notices = load_dataset("ZipLime/insider-sale-notices", "notices", split="train")
form4  = load_dataset("ZipLime/insider-trading", "transactions", split="train")
# join on (issuer_cik, owner_cik / reporting_owner_cik) and compare
# units_to_be_sold against the shares actually disposed of afterwards

Rule 10b5-1 plan dates

43% of notices disclose the date the seller's Rule 10b5-1 trading plan was adopted (plan_adoption_date), and days_from_plan_to_notice measures the gap. Form 4 carries only a flag saying a plan existed; this form says when it was put in place, which is what separates a sale scheduled months earlier from one arranged the week before a disclosure.

This field exists in no comparable commercial feed.

Coverage, and where it starts

Electronic filing of Form 144 became mandatory on 2023-04-13. Discovery starts on 2023-01-01 and keeps the 843 structured submissions filed voluntarily before the deadline, so the transition is visible in the data rather than cut off at a round date.

Everything earlier is out of reach. Before the mandate the form went in on paper or as free-form HTML — between 83 and 184 submissions a quarter, none of them structured. Parsing those would be an OCR project against a layout that changes per filer agent, for under 1% of the volume; the boundary is stated here rather than papered over.

After the mandate the form runs at roughly 8 749 filings a quarter.

Configs

ConfigRowsGrain
notices124 886one Form 144 notice of proposed sale
acquisitions218 815one lot of the securities to be sold, as it was acquired
past_sales445 642one sale by the same seller in the preceding three months, as disclosed on the form
pit124 886one point-in-time knowledge event, plus a Delta table for ziplime
features90 011one issuer and knowledge-day observation

Schema — notices

ColumnTypeNotes
notice_id, accession_numberstrEDGAR accession; the primary key.
form_type, is_amendment, amends_accession_numbermixed144 or 144/A; an amendment names the notice it restates.
filed_datedateFiling day.
accepted_attimestamp UTCThe point-in-time key. EDGAR's acceptance stamp, converted from US Eastern.
issuer_cik, issuer_name, issuer_ticker, ticker_source, exchangestrTicker comes from SEC's company_tickers.json — a current mapping, not point-in-time. issuer_cik is the key that does not drift.
owner_cik, owner_namestrThe seller. Joins to reporting_owner_cik in the Form 4 dataset.
relationships, relationship_rawlist[str], strAs filed — free text: Officer, COB & CEO, 10% Stockholder, Member of immediate family…
is_officer, is_director, is_ten_percent_owner, is_other_affiliateboolDerived from that free text; the raw value is kept.
security_class_raw, security_classstr42 spellings collapse to common, class_a, preferred, depositary_receipt, …
broker_namestrThe broker who will execute.
units_to_be_soldi64Shares the seller intends to sell.
aggregate_market_value_usdf64Their stated market value.
units_outstanding, pct_of_units_outstandingmixedShares outstanding as stated, and the sale as a share of it.
implied_price_usdf64Value ÷ units. A sanity check on both.
approx_sale_datedateThe event date — when the sale may begin.
notice_date, signaturemixedFrom the signature block.
plan_adoption_date, plan_adoption_dates, has_10b5_1_plan, days_from_plan_to_noticemixedRule 10b5-1 plan, where disclosed.
nothing_to_report_past_3m, past_3m_sale_count, past_3m_units_sold, past_3m_gross_proceeds_usdmixedThe seller's own three-month history, rolled up from past_sales.
acquisition_count, remarksmixed
value_qualitystrok \units_missing \value_missing \implied_price_below_cent \implied_price_implausible
date_qualitystrok \sale_before_filing \sale_date_missing \out_of_range
parser_version, inserted_atmixedProvenance.

Schema — pit

system   pit_event_id, logical_notice_id, revision, operation,
         entity_id, event_date, knowledge_date, knowledge_estimated
values   issuer_cik, issuer_name, issuer_ticker, owner_cik, owner_name,
         relationship, is_officer, is_director, is_ten_percent_owner,
         security_class, units_to_be_sold, aggregate_market_value_usd,
         pct_of_units_outstanding, has_10b5_1_plan, plan_adoption_date,
         days_from_plan_to_notice, past_3m_units_sold, broker_name,
         is_amendment

entity_id is the issuer CIK. A 144/A is stored as a second revision of the same logical_notice_id; both stay in the table, and a point-in-time read returns whichever was current at the moment you ask:

python
import polars as pl
from datetime import datetime, UTC

pit = pl.read_parquet("data/pit/knowledge_year=*/*.parquet")
visible = pit.filter(pl.col("knowledge_date") <= datetime(2025, 6, 30, tzinfo=UTC))
current = (visible.sort(["logical_notice_id", "revision", "knowledge_date"])
                  .unique(subset=["logical_notice_id"], keep="last"))

The table is append-only: a rebuild adds what it has not seen and never rewrites what is there. Changing what counted as known, after the fact, would make any backtest built on it unreproducible.

Schema — features

Daily per-issuer aggregates keyed on knowledge_day, never on the intended sale date: n_notices, n_sellers, units_to_be_sold, notice_value_usd, pct_of_units_outstanding, max_single_notice_value_usd, share_under_10b5_1_plan, n_officer_notices, n_director_notices, n_ten_percent_owner_notices, median_days_to_sale, plus 30- and 90-day rolling sums. An amended notice is counted once, at its latest revision.

Using it with ziplime

manifest.json describes the bundle; the Delta table it points at is data/pit/insider_sale_notices.delta.

python
bundle = "data/pit/insider_sale_notices.delta"   # bundle_storage_data.table_uri

Known gaps

  • —No pre-2023 history. See Coverage above.
  • —A notice is intent, not execution. Insiders file and then sell less, or later, or not at all. Treat units_to_be_sold as an upper bound announced by an interested party, and use the Form 4 dataset for what actually happened.
  • —Tickers are a current mapping. An issuer that changed symbol carries today's symbol on its whole history. Join on issuer_cik when this matters.
  • —Relationship is free text. The boolean flags are pattern-derived and the raw string is published beside them; a seller who wrote SAME is is_other_affiliate.
  • —Amendments are rare (1.1% of filings) but real. Deduplicate on logical_notice_id before summing.

Provenance and updates

Source: SEC EDGAR, Form 144 — Notice of Proposed Sale of Securities under Rule 144. US Government work, public domain. Requests are made under SEC Fair Access with a declared User-Agent, below the published rate threshold.

Rebuilt daily at 06:35 UTC by a Hugging Face Job whose script (`jobs/run.py`) lints, tests, ingests, verifies, and only then publishes. A failed gate leaves the previous revision standing.