<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Forecite</title>
    <description>The latest articles on DEV Community by Forecite (@forecite).</description>
    <link>https://dev.to/forecite</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092815%2F10476223-7421-4ba2-8c62-71320aef902d.png</url>
      <title>DEV Community: Forecite</title>
      <link>https://dev.to/forecite</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/forecite"/>
    <language>en</language>
    <item>
      <title>Which SEC Filings Actually Move Stock Prices — and How to Get the 8-Ks That Matter in Real Time</title>
      <dc:creator>Forecite</dc:creator>
      <pubDate>Mon, 24 Aug 2026 20:09:44 +0000</pubDate>
      <link>https://dev.to/forecite/which-sec-filings-actually-move-stock-prices-and-how-to-get-the-8-ks-that-matter-in-real-time-3e1m</link>
      <guid>https://dev.to/forecite/which-sec-filings-actually-move-stock-prices-and-how-to-get-the-8-ks-that-matter-in-real-time-3e1m</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical ranking of SEC filing types by short-term price impact, and how to get 8-K filing alerts in real time, scored for actionability instead of raw EDGAR noise.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The SEC receives thousands of filings on a normal trading day. A small fraction of them precede a meaningful price move within the next hour. The rest are routine filings such as prospectus supplements and ownership housekeeping, or amendments that restate what the market already knew. If you want to know which SEC filings move stock prices, the useful answer has two parts: a ranking by filing type, and a warning that the type alone is a weak filter, because the highest-impact form is also the noisiest one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filing types ranked by short-term price impact
&lt;/h2&gt;

&lt;p&gt;A rough ordering, from most likely to move a stock in the near term to least:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8-K (current reports).&lt;/strong&gt; This is where material events appear first: earnings results under Item 2.02, entry into or termination of material agreements under Item 1.01, executive departures under Item 5.02, bankruptcy under Item 1.03, delisting notices, impairments. When a stock gaps on news, an 8-K is very often the source document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Schedule 13D and amendments.&lt;/strong&gt; A 13D discloses that someone has crossed 5% ownership with activist intent. New 13Ds from known activists routinely reprice a stock within minutes. Schedule 13G, the passive equivalent, matters far less.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Form 4 (insider transactions).&lt;/strong&gt; Open-market purchases by a CEO or a cluster of officers can move a small-cap. Routine option exercises and scheduled 10b5-1 sales generally do nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S-1s, S-3s, and 424B prospectuses.&lt;/strong&gt; These signal dilution or an upcoming offering. The reaction is usually negative and often fast, especially for smaller issuers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10-K and 10-Q (annual and quarterly reports).&lt;/strong&gt; The headline numbers are typically pre-announced in an 8-K, so the periodic report itself moves prices less than people expect. The exceptions are in the text itself: going-concern language, newly disclosed litigation, and changes to the risk factors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amendments, 13F holdings reports, and administrative filings.&lt;/strong&gt; 13Fs arrive up to 45 days after quarter end. A 10-Q/A correcting a typo is noise. This bottom tier makes up much of EDGAR's daily volume.&lt;/p&gt;

&lt;p&gt;The complication is that the ranking holds only on average. Most 8-Ks are Item 7.01 or 8.01 disclosures, press-release attachments, and other boilerplate filings that no one trades on. The form type with nearly all of the short-horizon signal also produces the most non-events, so an alert on every 8-K will quickly train you to ignore your own alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems with polling EDGAR directly
&lt;/h2&gt;

&lt;p&gt;The obvious build is to poll EDGAR's public feeds and push everything matching your watchlist. Teams that try this hit the same problems. Polling intervals add latency on top of dissemination time, and by the time your parser has fetched the document, extracted the item codes, and run whatever filtering logic you wrote, faster participants have already read the filing. Then there is classification. An Item 1.01 tag indicates that a material agreement exists, but not whether it is a transformative licensing deal or a routine credit-facility extension. You end up writing keyword rules, and those rules stop working well over time.&lt;/p&gt;

&lt;p&gt;A SEC EDGAR real-time API fixes the delivery mechanics but does not decide which filings matter. You still receive a hundred 8-Ks to find the one worth acting on.&lt;/p&gt;

&lt;p&gt;Forecite addresses both problems. The feed ingests directly from sources (SEC EDGAR, wire services, exchanges, central banks) with no aggregator in the middle, one hop from the publisher, processing 180,000+ items weekly. Each event reaches subscribers with a scored verdict in under 50 milliseconds from publication. The company publishes per-event latency telemetry and a 99.97% trailing uptime figure, which makes the sub-50 ms claim verifiable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How actionability scoring works
&lt;/h2&gt;

&lt;p&gt;The scoring layer is the Verdict Engine, a single-pass NLP model trained on 1.2M+ labeled headlines. The training labels come from what the market actually did: scores are calibrated to the realized 1-hour return following each event, and the model retrains weekly. Forecite describes this as headlines "labelled by the market, not by humans," which is the practical difference from generic sentiment tools. A generic model reads "material definitive agreement" and scores the language. A market-calibrated model has seen thousands of Item 1.01 filings and learned which phrasings, contexts, and issuers historically preceded a real move.&lt;/p&gt;

&lt;p&gt;Every event gets two numbers. Actionability runs from 0 to 1 and estimates whether the event is worth reacting to at all. The combined verdict runs from −1.0 to +1.0 and adds direction. In practice, this collapses the filing-type ranking above into a single filter: rather than subscribing to specific form types, you subscribe to a ticker universe and set an actionability threshold. A boilerplate Item 7.01 filing scores low and is filtered out before it reaches you. An Item 2.02 with a guidance cut scores high and arrives while the market is still reading it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting 8-K filing alerts in real time
&lt;/h2&gt;

&lt;p&gt;Delivery depends on how you trade. The WebSocket stream fits desks and bots that maintain a persistent connection. Webhooks push high-actionability events into whatever you already run, from an execution system to a Slack channel. REST covers queries and search across the scored corpus. SDKs exist for Python, Node.js/TypeScript, and Rust, and there is an MCP server (&lt;code&gt;@forecite/mcp&lt;/code&gt;) so AI agents can consume scored filings as a native tool without custom integration work.&lt;/p&gt;

&lt;p&gt;A minimal setup for filings alerting looks like this: subscribe to your tickers over WebSocket, filter for events sourced from EDGAR, and act only above your actionability cutoff. The Starter tier at $39/month includes the scored realtime feed with 5,000 feeds per day, which covers a focused watchlist. Pro at $119/month removes the feed cap and extends the historical API to 30 days for active desks. Quant at $399/month adds unlimited API keys, a 1-year historical API, and 1,000 daily artifact-scoring requests for systematic teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating the signal before you trade it
&lt;/h2&gt;

&lt;p&gt;A scored feed should be tested before you rely on it. Most alerting products make this difficult, because the alerts were never stored in a form you can backtest. Forecite provides historical backfill and deterministic replay: the same event stream, with the scores as they existed at the time, in a form the company calls point-in-time honest. You can replay the last year of scored 8-Ks against your strategy and measure what an actionability threshold of 0.7 versus 0.5 would have done to your hit rate.&lt;/p&gt;

&lt;p&gt;There is also a public benchmark. Forecite runs a live desk of three real-money Alpaca accounts trading US equities, where an autonomous bot uses one decision input: the Forecite feed. Equity curves have run since January 1, 2026, so the track record is short, and the standard caveat applies (past performance is not indicative of future results). Still, publishing a real-money bot is more accountability than most signal vendors offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the feed
&lt;/h2&gt;

&lt;p&gt;The Free tier costs $0, requires no card, and includes the unscored realtime feed with 50 feeds per day, which is enough to watch EDGAR events arrive in real time before you commit to scoring. When you are ready to see which of those filings the market would actually trade, upgrade to a scored tier and set your first actionability threshold. Create a free Forecite API key and point it at your watchlist.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a WebSocket Market News Consumer in Python: From First Event to Threshold-Gated Signals</title>
      <dc:creator>Forecite</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:51:23 +0000</pubDate>
      <link>https://dev.to/forecite/building-a-websocket-market-news-consumer-in-python-from-first-event-to-threshold-gated-signals-36da</link>
      <guid>https://dev.to/forecite/building-a-websocket-market-news-consumer-in-python-from-first-event-to-threshold-gated-signals-36da</guid>
      <description>&lt;h1&gt;
  
  
  Building a WebSocket Market News Consumer in Python: From First Event to Threshold-Gated Signals
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Subscribe to Forecite's scored WebSocket market news feed in Python, survive disconnects, and gate events into a clean signal queue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're building a trading bot, raw headlines are a liability. What you want from a websocket market news feed is not more events — it's fewer, scored ones, arriving fast enough to act on. Forecite delivers exactly that: 180,000+ news items a week ingested one hop from the publisher (SEC EDGAR, wire services, exchanges, central banks, macro releases), each scored by the Verdict Engine and pushed to subscribers in under 50 milliseconds.&lt;/p&gt;

&lt;p&gt;This tutorial walks through a production-shaped consumer using the Python SDK: first event on screen, then reconnects, backpressure, threshold gating into a signal queue, and REST catch-up so a dropped connection doesn't become a blind spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're consuming
&lt;/h2&gt;

&lt;p&gt;Every event on the feed carries two numbers you'll build your logic around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actionability&lt;/strong&gt; (0 to 1): how likely this headline is to move price in the short term. This is the noise filter — boilerplate filings score low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verdict&lt;/strong&gt; (−1.0 to +1.0): combined directional score, calibrated to realized 1-hour return. Headlines are labelled by the market, not by humans, and the model retrains weekly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That calibration detail matters for bot builders: you're not filtering on whether language &lt;em&gt;sounds&lt;/em&gt; positive, you're filtering on what historically moved price. Generic sentiment models score language; this scores market reaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and first event
&lt;/h2&gt;

&lt;p&gt;Install the Python SDK and export your API key. The Free tier needs no card and gives you the unscored realtime feed to test connectivity; you'll want Starter or above for scored events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;forecite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The minimal consumer is a few lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;forecite&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ForeciteClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeciteClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fc_live_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;act=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actionability&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verdict=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it during US market hours and events arrive continuously. Note the timestamps: Forecite publishes per-event latency telemetry, so you can measure publication-to-you delay yourself rather than taking "sub-50 ms" on faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconnects: assume the socket will die
&lt;/h2&gt;

&lt;p&gt;Any long-lived WebSocket connection will drop — deploys, network blips, laptop sleep. The consumer's job is to reconnect with backoff &lt;em&gt;and remember where it left off&lt;/em&gt;, because the gap is where you miss the thing.&lt;/p&gt;

&lt;p&gt;Wrap the stream in a supervisor loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_forever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;last_event_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;last_event_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;
                &lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# healthy connection resets backoff
&lt;/span&gt;                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ConnectionError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream dropped: %s — reconnecting in %ss&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_event_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;catch_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;since_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;last_event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two deliberate choices here. Backoff is capped at 30 seconds — on a feed where latency is the edge, minutes-long backoff defeats the purpose. And we record the last event ID &lt;em&gt;before&lt;/em&gt; handling, so the catch-up call (below) can close the gap exactly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catch-up over REST
&lt;/h2&gt;

&lt;p&gt;Forecite exposes the same scored corpus over REST, which turns "we were disconnected for 40 seconds" from an unknown into a bounded query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;catch_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;since_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;missed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;since_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;since_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replaying %d missed events&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;missed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;missed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How far back you can reach depends on tier: Starter covers a 48-hour historical window, Pro 30 days, Quant a full year. For gap-filling after a disconnect, even the Starter window is far more than you'll ever need; the longer windows matter when you graduate to backtesting, where the same historical API supports deterministic replay — point-in-time honest data, so your backtest sees exactly what the feed would have shown at that moment.&lt;/p&gt;

&lt;p&gt;If your infrastructure can't hold a socket open at all (serverless, restrictive networks), the platform also delivers over webhooks — same scored events, pushed to an HTTPS endpoint you control. A reasonable production posture is WebSocket as primary and a webhook endpoint as an independent fallback path writing into the same queue, deduplicated by event ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backpressure and the signal queue
&lt;/h2&gt;

&lt;p&gt;The Verdict Engine sustains thousands of verdicts per second at peak (the platform quotes 6.4k/second throughput). Your strategy code almost certainly can't — and shouldn't — process every event synchronously in the stream handler. If your handler blocks, you stall the socket read loop and your "real-time" feed quietly becomes a delayed one.&lt;/p&gt;

&lt;p&gt;The fix is the standard producer–consumer split, with the threshold gate applied at the cheapest possible point — before the queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="n"&gt;ACTIONABILITY_FLOOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;   &lt;span class="c1"&gt;# tune against your strategy's backtest
&lt;/span&gt;&lt;span class="n"&gt;QUEUE_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;

&lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;QUEUE_MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fast path: score check only. Never block here.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actionability&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ACTIONABILITY_FLOOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="c1"&gt;# boilerplate filings and low-impact noise die here
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_nowait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueueFull&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Explicit policy beats silent stalling. Here: drop oldest.
&lt;/span&gt;        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_nowait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_nowait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queue full — dropped oldest signal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;strategy_worker&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;place_or_adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# your execution logic
&lt;/span&gt;        &lt;span class="n"&gt;signal_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three patterns worth stealing even if you change everything else:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gate on actionability first, direction second.&lt;/strong&gt; Actionability answers "is this worth compute at all?" — it's your volume filter. The verdict's sign and magnitude answer "which way, and how confidently?" Keeping the checks separate makes each threshold independently tunable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make the overflow policy explicit.&lt;/strong&gt; A bounded queue with drop-oldest means that during an event storm — a Fed release, a cluster of filings — your bot acts on the freshest signals rather than working through a stale backlog. For news-driven strategies, a 90-second-old headline is usually worth less than the one that just landed. If your strategy disagrees, choose drop-newest or block — but choose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the socket loop non-blocking.&lt;/strong&gt; The &lt;code&gt;gate&lt;/code&gt; coroutine does one comparison and one queue operation. Everything slow — order placement, position checks, logging to disk — lives in the worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring it together
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeciteClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fc_live_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;run_forever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;strategy_worker&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole skeleton: a supervised stream feeding a bounded queue through a score gate, with REST catch-up sealing the gaps. From here, the natural next steps are tuning your actionability floor against the historical API (Quant's 1-year window and deterministic replay exist for exactly this), and — if you're building AI agents rather than classic bots — pointing them at the &lt;code&gt;@forecite/mcp&lt;/code&gt; server so they consume scored events natively.&lt;/p&gt;

&lt;p&gt;One honest caveat: nothing above is investment advice, and a scored feed doesn't make a strategy — it makes the input to one trustworthy. Forecite is confident enough in that input to run a public live desk: three real-money accounts trading US equities with one decision input, the Forecite feed. Past performance is not indicative of future results, but the telemetry is there to inspect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start streaming
&lt;/h2&gt;

&lt;p&gt;The Free tier takes no card and gets you connected to the realtime feed today; Starter ($39/month, billed annually) adds the scored feed and the 48-hour historical API this tutorial leans on. Grab an API key, run the twenty-line consumer above, and see what a Python SDK for financial news looks like when the headlines arrive already judged — signal, not volume.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
