Congressional Disclosure Agent¶
This example reads the public House Clerk periodic transaction report. It downloads the yearly index at the House financial-pdfs ZIP, then the member PDF. The bot trades only after that filing is public. It is a disclosure-following example, not a claim that the member traded on the publication date or that copying the trade is profitable. Amounts on the report are ranges, and the report can be up to 45 days late.
Availability¶
The source TransactionDate describes when the reported transaction
occurred. ReportDate (normalized as published_at) is when the example
first makes the record visible. Federal disclosure rules may permit a report
as late as 45 days after the transaction, so this is not a low-latency
signal and the example must never backdate availability to TransactionDate.
House and Senate periodic transaction reports are public filings. The House source is the Clerk’s yearly index ZIP and the PTR PDF named in that index. Official instructions say an option row should name the underlying security, put or call, strike, and expiration. Real filings are PDFs, and some rows leave the contract fields incomplete. Stock mode needs the ticker and the buy or sell. Option mode also needs call or put, strike, and expiration. A row without strike and expiration is skipped. Gifts, spinoffs, private companies, and money-market funds are skipped.
This example does not ship sample trades. Pass parsed official filings in
disclosures or a JSON file of those filings in disclosures_path.
Running the module with neither argument stops instead of inventing a
portfolio. A backtest on this page is real only after those filings and
market prices are supplied. Amounts on the filings are ranges, not exact
share counts.
Architecture¶
disclosure_researcher cannot trade. trading_risk_manager is the only
agent with trading tools and caps a new position at the configured percentage.
Already processed disclosure IDs are ignored and old records are rejected by
the configured age limit. Records stay hidden until ReportDate.
1"""Nancy Pelosi congressional-disclosure strategy.
2
3Python creates the agents and runs them. It does not download filings or place orders.
4The research agent fetches the public House reports. 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_FILING_URLS = (
11 "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20033725.pdf",
12 "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20034836.pdf",
13 "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20035143.pdf",
14)
15_BOOK = (
16 "Use filings whose report date is on or before the session date. "
17 "Each filing line has a ticker in parentheses and an asset code in square brackets. "
18 "Count [ST] and [AB]. Skip [OP]. "
19 "P is a buy. S, including S (partial), is a sell. "
20 "A line with transaction E, or a description that says gift, spinoff, or donor-advised, is not a trade. "
21 "Each amount is a dollar range. The midpoint is dollars, never a share count. "
22 "A sell is not a buy. For each ticker, net_dollars = buy midpoint minus sell midpoint. "
23 "Keep every counted sell. A ticker that has both a buy and a sell uses both. "
24 "If net_dollars is zero or negative, the weight is zero and you do not buy it, even if another agent calls it a buy. "
25 "Example: AAA has only a buy of $3,000,000, so it can be bought. BBB has only a $15,000,000 sale, so it is not bought. "
26 "CCC has a $375,000 buy and a $3,000,000 sell, so the net is a sale and it is not bought. "
27 "DDD is a units line whose bracket code is AB and whose only trade is a buy, so it can be bought. "
28 "Weights are each positive net divided by the sum of positive nets, and those weights sum to 100% of account value. "
29 "Do not calculate shares yourself. For each positive-net ticker, call risk_calculate_stock_quantity with "
30 "maximum_notional equal to account value times that weight and available_cash equal to cash still unspent. "
31 "Submit exactly the quantity that tool returns. After each fill, the next order uses the cash that is left. Never short."
32)
33_EXIT = (
34 "Sell a name with the order tool when a later visible filing is a sale or its scaled "
35 "weight fell. Otherwise keep the replica invested, with cash near 0% to 5%."
36)
37
38
39class AICongressDisclosuresStrategy(Strategy):
40 parameters = {
41 "member": "Nancy Pelosi",
42 "filing_urls": list(_FILING_URLS),
43 }
44
45 def initialize(self):
46 self.sleeptime = "1D"
47 add_agent(
48 self,
49 "congress_researcher",
50 (
51 "Research public House periodic transaction reports for the named member. "
52 "Use http_request to fetch each filing URL. Each transaction is already one line. "
53 "Read the report date in the filing text. Ignore any filing whose report date is after as_of. "
54 "A transaction date is not the public date. "
55 "The ticker is the symbol in parentheses. The code in square brackets is the asset type. "
56 "Count [ST] and [AB]. Skip [OP]. "
57 "P is a buy. S, including S (partial), is a sell. "
58 "Skip a line whose transaction is E, or whose description says gift, spinoff, or donor-advised. "
59 "For each ticker write one line: TICKER buy_dollars sell_dollars net_dollars. "
60 "Add every counted buy into buy_dollars and every counted sell into sell_dollars. "
61 "Do not drop a sell because the same ticker also has a buy. "
62 "buy_dollars and sell_dollars are range midpoints in dollars. "
63 "net_dollars = buy_dollars - sell_dollars. A sale is not a buy. Do not submit orders."
64 ),
65 allow_trading=False,
66 )
67 add_agent(
68 self,
69 "bull",
70 "Argue for copying the visible buys, using range midpoints. Do not submit orders.",
71 allow_trading=False,
72 )
73 add_agent(
74 self,
75 "bear",
76 "Argue the risks: stale filings, wide ranges, and names that should be sold. Do not submit orders.",
77 allow_trading=False,
78 )
79 add_agent(
80 self,
81 "interpreter",
82 "Weight only [ST] and [AB] lines whose net_dollars is positive. Name every zero or negative net as do not buy. Do not submit orders.",
83 allow_trading=False,
84 )
85 add_agent(
86 self,
87 "trading_risk_manager",
88 trader_prompt(book_rule=_BOOK, exit_rule=_EXIT),
89 allow_trading=True,
90 )
91
92 def on_trading_iteration(self):
93 as_of = self.get_datetime()
94 context = {
95 "as_of": as_of.isoformat(),
96 "member": self.parameters["member"],
97 "filing_urls": list(self.parameters["filing_urls"]),
98 "clock_rule": (
99 "Ignore any filing whose report date is after as_of. "
100 "Transaction date is not the public date."
101 ),
102 "risk_policy": {
103 "cash_target": "0% to 5%",
104 "sizing": "scale visible filing range midpoints to account value",
105 "never_short": True,
106 },
107 }
108 run_cycle(
109 self,
110 context,
111 researcher="congress_researcher",
112 bull="bull",
113 bear="bear",
114 interpreter="interpreter",
115 trader="trading_risk_manager",
116 research_task="Fetch the filings and report only the rows already public on as_of.",
117 bull_task="Make the bull case for copying the visible book.",
118 bear_task="Make the bear case against copying the visible book.",
119 interpret_task="Assign account weights from the filing range midpoints.",
120 trade_task=(
121 "Buy only tickers whose research line has positive net_dollars. "
122 "Call risk_calculate_stock_quantity for each of those tickers and submit that quantity. "
123 "Do not buy a ticker another agent likes if its net_dollars is zero or negative."
124 ),
125 )