SEC Form 4 Insider-Filing AgentΒΆ

SEC Form 4 insider-filing AI trading team workflow

This example analyzes public SEC Form 4 filings. It does not use material non-public information. Records first become visible at the SEC acceptance/publication time (normalized as published_at), never merely on their earlier transaction date.

The parser preserves transaction codes, direct versus indirect ownership, derivative status, amendments, quantities, prices, and computed values. The default strategy considers only open-market transactions; grants, gifts, option exercises, derivatives, and amendments must not be treated as ordinary open-market buying or selling.

form4_researcher builds the evidence packet without trading permission. trading_risk_manager independently verifies account state and price and is the only agent allowed to submit an order.

The live source is the SEC Form 4 Atom feed at https://www.sec.gov/cgi-bin/browse-edgar?action=getcurrent&type=4&output=atom. The strategy may act only on entries whose published time is already visible at the backtest clock. A January 23, 2026 clock fetched 40 current entries and hid all 40 as future. A live feed item such as Mark W. Webb, accession 0001193125-26-397981, is the kind of row live mode can see when it is still in the latest feed.

This example does not ship sample trades. Pass official EDGAR filings in transactions or a JSON file of those filings in transactions_path. Running the module with neither argument stops instead of inventing trades. A backtest on this page is real only after those filings and market prices are supplied.

 1"""SEC Form 4 public-insider-filings strategy.
 2
 3Python creates the agents and runs them. It does not download the feed or place orders.
 4The research agent fetches the public Atom feed. The trading agent places the orders.
 5"""
 6
 7from lumibot.example_strategies.agent_cycle import add_agent, run_cycle, trader_prompt
 8from lumibot.strategies import Strategy
 9
10_FEED_URL = "https://www.sec.gov/cgi-bin/browse-edgar?action=getcurrent&type=4&output=atom"
11
12
13class AISECInsiderFilingsStrategy(Strategy):
14    parameters = {
15        "feed_url": _FEED_URL,
16    }
17
18    def initialize(self):
19        self.sleeptime = "1D"
20        add_agent(
21            self,
22            "insider_trade_researcher",
23            (
24                "Use rss_fetch on the supplied SEC Form 4 feed. Ignore any entry whose published time "
25                "is after as_of. Ignore grants, gifts, option exercises, automatic plans, and amendments. "
26                "Keep open-market purchases and sales only. Report the ticker, the side, and the published time. "
27                "Do not submit orders."
28            ),
29            allow_trading=False,
30        )
31        add_agent(
32            self,
33            "bull",
34            "Argue for copying the open-market insider buys. Do not submit orders.",
35            allow_trading=False,
36        )
37        add_agent(
38            self,
39            "bear",
40            "Argue the risks: grants, amendments, thin names, and sales. Do not submit orders.",
41            allow_trading=False,
42        )
43        add_agent(
44            self,
45            "interpreter",
46            "Read both cases. Assign account weights for the open-market tickers only. Do not submit orders.",
47            allow_trading=False,
48        )
49        add_agent(
50            self,
51            "trading_risk_manager",
52            trader_prompt(
53                book_rule=(
54                    "Trade only exact tickers from open-market Form 4 rows already public on as_of. "
55                    "Never short. Never treat a grant, gift, or option exercise as an open-market purchase."
56                ),
57                exit_rule=(
58                    "Sell a name with the order tool when a later visible filing is a sale. "
59                    "Otherwise stay invested, with cash near 0% to 5%."
60                ),
61            ),
62            allow_trading=True,
63        )
64
65    def on_trading_iteration(self):
66        as_of = self.get_datetime()
67        context = {
68            "as_of": as_of.isoformat(),
69            "feed_url": self.parameters["feed_url"],
70            "clock_rule": "Ignore any feed entry published after as_of.",
71            "risk_policy": {
72                "cash_target": "0% to 5%",
73                "sizing": "scale the open-market filings to account value",
74                "never_short": True,
75            },
76        }
77        run_cycle(
78            self,
79            context,
80            researcher="insider_trade_researcher",
81            bull="bull",
82            bear="bear",
83            interpreter="interpreter",
84            trader="trading_risk_manager",
85            research_task="Fetch the Form 4 feed and report only open-market rows already public on as_of.",
86            bull_task="Make the bull case for the open-market buys.",
87            bear_task="Make the bear case against copying the filings.",
88            interpret_task="Assign account weights for the open-market tickers.",
89            trade_task="Scale the visible open-market book to this account. Sell names the filings sold.",
90        )