Back to use cases

    Use case / X DATA / Python 3 / Published

    Build a daily stock Twitter board for your watchlist

    Build a daily board of stock Twitter posts for a small watchlist. Search each cashtag on X, merge Latest and Top posts and drop spam and off-topic posts.

    Cashtags flowing through Desearch X search into a filtered daily ticker board

    This stock Twitter ticker pulse builds a daily Markdown and CSV board for a small stock watchlist from public X posts. It searches each cashtag, merges the latest and top posts, and drops spam and off-topic posts. This page shows a stored sample; there is no hosted demo.

    The problem

    Cashtag searches on X mix useful posts with invite-link spam, paid group pitches and long watchlist posts that tag a dozen tickers. Reading every ticker by hand each morning takes time, and it is hard to compare tickers when the noise level differs. You need one board with counts per ticker, the posts worth opening and a clear note on what was dropped.

    What the app does

    • Searches X once for the latest posts and once for the top posts of each ticker.
    • Merges duplicate posts and sorts each one into kept, spam or off-topic.
    • Reports per ticker the returned, spam, off-topic and kept counts, the most-liked and most-viewed post and co-mentioned cashtags.
    • Adds a rough count of bullish and bearish words, labelled as a word count, not a signal.
    • Writes a Markdown board, board and posts CSV files, a cost CSV and the raw responses.

    The board is a sample of recent posts, not total volume. It is not investment advice.

    How it works

    1. Normalize the watchlist. Tickers come from the command line or a file. They are uppercased, deduplicated and limited to 1 to 6 letters, with up to 10 tickers per run.
    2. Plan the calls. Each ticker gets a Latest call and a Top call to GET /twitter with the query $TICKER. The Top call adds a start date (3 days back by default) and a minimum of 50 likes.
    3. Merge and filter. Posts are deduplicated by ID. Invite links, group pitches and posts with 5 or more distinct cashtags count as spam. A post without the searched cashtag counts as off-topic. Spam wins when both apply.
    4. Build the board. Kept posts feed the counts, the Latest time span, the Top window and the word tilt. Every unique post, with its drop reasons, goes to the posts CSV.
    5. Record cost. Each call reads X-Desearch-Cost-Usd. Calls are not retried automatically, because a retry could be billed again.

    The code

    This verbatim excerpt from ticker_pulse.py applies the spam and off-topic rules to one post:

    PYTHON
    def spam_reasons(post, ticker, max_cashtags=5):
        """List matching spam rules and the off-topic rule."""
        text = (post.get('text') or '').lower()
        urls = (post.get('entities') or {}).get('urls') or []
        searchable = text + ' ' + ' '.join((str(u.get('expanded_url') or '').lower() for u in urls))
        tags = cashtags(post)
        reasons = []
        if any((link in searchable for link in INVITE_LINKS)):
            reasons.append('invite_link')
        if any((phrase in text for phrase in GROUP_PHRASES)):
            reasons.append('group_pitch')
        if len(tags) >= max_cashtags:
            reasons.append('watchlist_spam')
        if ticker.upper() not in tags:
            reasons.append('off_topic')
        return reasons
    
    
    def filter_group(reasons):
        """Assign one group, with spam taking precedence over off-topic."""
        if any(reason in ('invite_link', 'group_pitch', 'watchlist_spam') for reason in reasons):
            return 'spam'
        return 'off_topic' if 'off_topic' in reasons else 'kept'

    View the code

    Endpoints

    • GET /twitter

    Example output

    From sample-output.md in the source folder. It was re-rendered offline with account names anonymized from the raw file of a live run on 2026-10-28.

    | Ticker | Returned | Spam | Off-topic | Kept | Latest span (h) | Top post likes | Tilt |
    | --- | --- | --- | --- | --- | --- | --- | --- |
    | NVDA | Latest: 20; Top: 20 | 7 (17.5%) | 0 (0.0%) | 33 | 0.7 | 1184 | more bullish words |
    | TSLA | Latest: 20; Top: 20 | 1 (2.5%) | 10 (25.0%) | 29 | 5.6 | 347 | more bullish words |
    | SOFI | Latest: 20; Top: 20 | 0 (0.0%) | 0 (0.0%) | 40 | 5.5 | 1732 | more bullish words |

    Counts come from the latest 20 public X posts returned per ticker and sort, not all mentions. The tilt column is a rough word count.

    Run it yourself

    Get the Python examples and open the ticker pulse folder. Use Python 3.10 or newer; there are no packages to install. Create an API key in the console and set DESEARCH_API_KEY, or pass a private key file with --key-file PATH.

    BASH
    git clone https://github.com/Desearch-ai/desearch-py-examples
    cd desearch-py-examples/stock-twitter-ticker-pulse

    These commands are copied from the source README. The dry run prints the planned calls without a key or API calls.

    SH
    python3 ticker_pulse.py NVDA TSLA AMD
    python3 ticker_pulse.py '$NVDA' --watchlist watchlist.txt --count 30 --out output
    python3 ticker_pulse.py NVDA --dry-run
    python3 ticker_pulse.py NVDA --top-only --key-file /path/to/private-key

    Use --watchlist FILE for a longer list, --max-cashtags to tune the watchlist spam rule and --anonymize to replace account names in the Markdown and CSV files.

    What it costs

    On 2026-10-28, every X search call with count=20 cost $0.003, read from the X-Desearch-Cost-Usd header. One ticker (Latest and Top) cost $0.006. A 3-ticker run made 6 calls, cost $0.018 and took about 55 seconds. Use --latest-only or --top-only to halve the calls. These are dated measurements, not current price quotes. Check pricing before a larger run.

    Ideas to extend it

    • Run the board every morning and keep each day's CSV to compare spam and off-topic shares over time.
    • Add a column that links the most-liked post for each ticker in a team digest.
    • Tune --max-cashtags for watchlists where list posts are useful.
    • Combine the board with a news search for the same tickers.

    Use with AI agents

    Point an MCP client at the hosted Desearch server. Replace the placeholder with a key from the console. Do not commit the key.

    JSON
    {
      "mcpServers": {
        "desearch": {
          "url": "https://mcp.desearch.ai/mcp",
          "headers": {
            "Authorization": "Bearer <key>"
          }
        }
      }
    }

    Prompt you can paste for this example:

    Build a Python CLI that makes a daily Markdown and CSV board for a stock watchlist using Desearch. For each ticker call GET /twitter twice with query $TICKER: once with sort Latest and once with sort Top, start_date and min_likes. Merge duplicate posts by ID. Drop spam (invite links, group pitches, posts with 5 or more distinct cashtags) and off-topic posts that lack the searched cashtag. Report returned, spam, off-topic and kept counts, the most-liked and most-viewed post and a rough bullish versus bearish word count per ticker. Read the API key from DESEARCH_API_KEY or a key file. Record X-Desearch-Cost-Usd per call and do not retry billed calls. Say clearly that the board is a sample and not investment advice.

    Build your own example.

    Give your agents access to web and social search. Get an API key to start building, or talk to us about your integration.

    Read docs