Drinniol
A personal pipeline that finds publicly reachable equity-research documents, extracts ratings and price targets for each ticker, and shows them in a dashboard with alerts. It’s under construction, the code is private, and its output has never been used to place a trade.
- Python
- TypeScript
- FastAPI
- PostgreSQL
- Next.js
How it works
It runs in six stages: discovery → fetch → parse → extraction → storage → API and dashboard.
- Discovery: a web-search API with per-ticker query rules.
- Fetch and parse: public URLs only, with no logins. PDFs are parsed to text.
- Extraction: rules first, then an LLM with a fixed output schema.
- Storage: Postgres plus file storage.
- Surface: a FastAPI service with 11 endpoints, a Next.js dashboard with 7 views, and Telegram alerts.
The project has 124 automated tests. I designed and specified it and checked its results; the code was written with Claude Code.
Search quality
The first version of search returned mostly news and aggregator pages. I added a host blocklist and rules that stop bare-ticker queries for tickers that are common words (such as NOW), then measured the effect on a labeled sample.
| Relevant results | 95% interval | |
|---|---|---|
| Before | 39 of 100 (39%) | 30% to 49% |
| After | 39 of 61 (64%) | 51% to 75% |
- The change removed 39 of the 100 sampled results, and none of the 39 was relevant.
- Both groups improved: ambiguous tickers from 34% to 55%, the rest from 42% to 69%.
- “Relevant” means a research document (broker, fund, consulting, industry or academic report) that is substantively about the ticker or its sector. News, aggregator pages and marketing don’t count.
Handling confidential material
Documents are checked for confidentiality, draft and embargo markers after download. A flagged document is quarantined: it’s stored, but its text is never sent to the LLM, it produces no signals or alerts, and it’s hidden from the API and dashboard except on a review page. A reviewer can release a document with a written note.
Prompt caching
Caching had been silently off because the system prompt was below the model’s minimum cacheable length. After the fix, a cache hit cuts the system-prompt cost by 73% and the input cost per document by 5% to 24%. The saving applies only to back-to-back batch runs.
Limitations
- The end-to-end corpus is 5 documents.
- Filing and earnings-transcript sources, and OCR, are not built.
- The quarantine patterns haven’t met a real confidential document. Their one match so far was a false positive on a legal disclaimer, which led me to narrow the pattern.
- The accuracy of LLM extraction hasn’t been measured.
- The search sample is 100 results from 10 tickers on one day. A first labeling pass was done by AI and I reviewed it, and the query text partly reveals which version a result came from.




