Form 4 Transaction Codes Explained: P, S, A, M, and What They Mean
A field guide to every Form 4 transaction code with signal-value ratings. Know which codes to trade on, which to filter, and which to ignore entirely.
A Form 4 filing without transaction-code context is a spreadsheet of numbers with no meaning. The two-letter code determines whether a filing is a discretionary market vote or a compensation-plumbing artifact. Here is the complete field guide.
Open-market codes (highest signal)
- P — Open-market or private purchase of non-derivative securities. High signal. This is the code that carries almost all documented insider buy alpha.
- S — Open-market or private sale of non-derivative securities. Medium-low signal after filtering 10b5-1 plans and diversification sales.
Compensation codes (filter out)
- A — Grant, award, or other acquisition. Compensation, not conviction.
- M — Exercise or conversion of derivative. Mechanical option event; the actual signal (if any) is a same-day P or S.
- F — Payment of exercise price or tax by delivery of shares. Tax withholding; ignore.
- D — Disposition to the issuer. Buybacks in kind; ignore.
Other codes (context-dependent)
- G — Gift. Not a market vote but useful for concentration analysis.
- I — Discretionary transaction. Rare, worth reading the footnote.
- V — Voluntary early report. Modifier on another code, not a code itself.
- W — Acquisition or disposition by will or laws of descent. Estate event; ignore.
- X — Exercise of in-the-money or at-the-money derivative security. Similar to M.
Derivative-security codes
Codes J, K, L, O, U, and Z appear on the derivative table. For a discretionary-buy signal, these are almost always noise; for options-flow analysis they can be useful. Most systematic Form 4 strategies filter the derivative table entirely.
A practical starting filter
def is_signal_trade(txn):
return (
txn["txn_code"] == "P"
and txn["value_usd"] >= 25_000
and not txn.get("is_10b5_1", False)
)The NexusForm4 API pre-filters administrative codes from its /signals/ endpoints, so you only see codes that carry information. If you want the raw feed, use /trades/latest and apply your own filter.