< Back to Blog

Five Signals Are Better Than One: Inside the Econ Bot's Multi-Source Nowcast

TL;DR / Key Takeaways

  • The Econ Bot uses five independent signal sources: Cleveland Fed nowcast, FRED market indicators, BLS CPI subcomponents, BEA PCE data, and a homemade weighted composite.
  • Each signal is a separate Python module. If one API is down, the bot logs it and continues on the remaining signals.
  • Single-source nowcasts are fragile. When your one data feed goes stale, you don't know it until the trade already hurt you.
  • The Predict & Profit Econ Bot ships with all five modules, configurable weights, and a startup log that tells you exactly which signals are active before the first order goes out.

Most Kalshi CPI traders are working from one number. Maybe they check the Cleveland Fed. Maybe they just look at the last print and guess the direction. One data point, one trade, hope for the best.

That is not a system. That is a coin flip dressed up in economic vocabulary.

The Econ Bot uses five independent signal sources to build a composite probability estimate for every CPI and PCE market before it considers a trade. This post walks through the architecture: what each source contributes, how they combine, and what happens when one of them stops working.


Why One Source Is a Fragile Foundation

Before getting into the architecture, it is worth spending a minute on why single-source systems fail quietly.

The Cleveland Fed nowcast is the best publicly available CPI probability estimate I have found. It is genuinely useful. But it updates on a schedule, not in real time. Between updates, market conditions can shift. Oil spikes. Gasoline prices move. The 10-year breakeven inflation expectation drifts. The Cleveland Fed number does not know any of that until the next update cycle.

If you are trading a Kalshi CPI contract with three days to settlement and the Cleveland Fed last updated four days ago, you are flying partly blind. You have a good baseline but no visibility into what has changed since.

The multi-signal architecture exists to close that gap. Each source covers something the others miss. Together they give a more complete picture than any one of them provides alone.


The Five Signals

Signal 1: Cleveland Fed Nowcast (Primary)

nowcast_scraper.py

This is the anchor. The Cleveland Fed publishes a probabilistic nowcast for CPI and PCE that represents their best current estimate of where inflation will print. It is a Bayesian model with a solid track record. I use it as the baseline probability around which everything else adjusts.

The scraper pulls directly from the Cleveland Fed website on each bot cycle. The output is a probability for each market strike currently active on Kalshi. That probability becomes the starting point before any adjustments are applied.

If this signal fails, the bot does not trade. The Cleveland Fed nowcast is the only hard dependency in the stack. Everything else is additive.

Signal 2: FRED Market Indicators

fred_signals.py

Four market-based signals pulled from the FRED API:

  • DCOILWTICO: WTI crude oil spot price
  • GASREGW: US regular gasoline retail price
  • T10YIE: 10-year breakeven inflation rate
  • UNRATE: Unemployment rate

Each of these applies a small confidence nudge to the baseline Cleveland Fed probability. The nudges are calibrated at +/-0.03 to +/-0.05 depending on how far the indicator sits from its recent baseline.

The logic is straightforward: when oil and gas prices are elevated going into a CPI release, that is upward pressure the Cleveland Fed model may not have fully incorporated yet. When the 10-year breakeven is rising, the market is pricing in more inflation ahead. When unemployment is unexpectedly low, wage pressure feeds into services inflation.

None of these individually moves the needle much. That is intentional. FRED signals are adjustments, not overrides.

Signal 3: BLS CPI Subcomponents

bls_signals.py

The headline CPI number is an average. It hides a lot. The Bureau of Labor Statistics publishes component-level data: shelter, food at home, food away from home, energy, apparel, medical care, and several more. Each component has its own trend.

This module pulls the recent trend for each major component and uses it to assess whether the upcoming print is likely to come in above or below the Cleveland Fed baseline. A shelter component that has been running hot for three consecutive months is a different setup than one that has been decelerating.

This signal is slower-moving than FRED. It does not update daily. But it adds structural context that market price signals miss entirely.

Signal 4: BEA PCE Data

bea_signals.py

The Federal Reserve's preferred inflation measure is PCE, not CPI. Kalshi lists markets for both. The BEA module pulls Personal Consumption Expenditures data from the Bureau of Economic Analysis and uses it to calibrate the PCE-specific probability estimates.

CPI and PCE track each other but they diverge, sometimes significantly, because they use different basket weights. Housing is weighted more heavily in CPI. Healthcare shows up differently. If I am trading a PCE market, I want PCE-specific data, not just a CPI signal ported over.

This module is only active when the bot is evaluating a PCE market. For CPI markets it contributes nothing, which is the correct behavior.

Signal 5: Homemade Weighted Nowcast

homemade_nowcast.py

This is the synthesis layer. It takes all available signals, applies configurable weights, and produces a single composite probability estimate.

The weighting schema is defined in config:

NOWCAST_WEIGHTS = {
    "cleveland_fed": 0.50,
    "fred_signals": 0.20,
    "bls_subcomponents": 0.15,
    "bea_pce": 0.10,
    "market_implied": 0.05,
}

The Cleveland Fed gets half the weight because it is the most direct and purpose-built estimate. FRED market signals get 20% because they are real-time but noisy. BLS subcomponents get 15% for structural context. BEA gets 10% for PCE-specific calibration. The remaining 5% goes to a market-implied probability derived from current Kalshi contract pricing.

These weights are not sacred. They are configurable. If you have a reason to trust FRED signals more or less for a particular release, adjust the config and rerun. The bot logs the composite at every cycle so you can see exactly how the weights translated to a final probability.


How the Signals Combine in Practice

Here is a simplified version of the composite calculation:

def build_composite_nowcast(signals: dict, weights: dict) -> float:
    """
    Build a weighted composite probability from available signals.
    Signals that failed to load are excluded and weights are renormalized.
    """
    available = {k: v for k, v in signals.items() if v is not None}

    if not available:
        raise RuntimeError("No signals available. Cannot compute nowcast.")

    total_weight = sum(weights[k] for k in available)
    composite = sum(
        (weights[k] / total_weight) * available[k]
        for k in available
    )

    return round(composite, 4)

The key line is the renormalization: weights[k] / total_weight. If FRED is down and that signal returns None, it gets excluded. The remaining weights are rescaled so they still sum to 1.0. The composite stays valid. The bot logs which signals contributed.

This is graceful degradation. The bot does not crash when an API is unavailable. It keeps running on whatever it has, and it tells you exactly what that is.


The Startup Log

Every bot cycle starts with a signal inventory. Before any market data is pulled, before any edge calculations run, the bot logs exactly which signals are active. Here is what a healthy startup looks like:

[ECON BOT] Signal stack initializing...
  [OK] cleveland_fed       -- probability: 0.6812
  [OK] fred_signals        -- oil: 78.42, gas: 3.21, t10yie: 2.31, unrate: 4.1
  [OK] bls_subcomponents   -- shelter: +0.02, food_home: -0.01, energy: +0.04
  [OK] bea_pce             -- latest PCE: 2.6 YoY
  [OK] homemade_nowcast    -- composite: 0.6934
[ECON BOT] All 5 signals active. Proceeding to market scan.

And here is what a degraded but operational cycle looks like:

[ECON BOT] Signal stack initializing...
  [OK]   cleveland_fed     -- probability: 0.6812
  [WARN] fred_signals      -- FRED returned HTTP 500. Using 6hr cache.
  [OK]   bls_subcomponents -- shelter: +0.02, food_home: -0.01, energy: +0.04
  [OK]   bea_pce           -- latest PCE: 2.6 YoY
  [OK]   homemade_nowcast  -- composite: 0.6891 (fred on cache, weights renormalized)
[ECON BOT] 4/5 signals active. FRED on cached data. Proceeding with caution flag.

The composite still runs. The weights renormalize. You know what state the system is in before a single order goes out.


What the Composite Actually Does to Edge

The edge calculation compares the composite probability against the current Kalshi market price. If the market is pricing a contract at 0.55 and the composite says 0.69, that is a 14-point edge. The bot evaluates that against its minimum threshold and decides whether to trade.

The five-signal composite does not magically make the edge larger. What it does is make the composite probability more stable and more defensible than a single-source estimate. A Cleveland Fed reading of 0.68 that is confirmed by rising FRED breakevens, elevated shelter costs in BLS data, and a consistent BEA PCE trend is a very different trade than a 0.68 from Cleveland Fed alone when everything else is pointing the other direction.

That is the whole point. Not more edge. Better-quality edge.


What This Costs in API Overhead

Very little. FRED, BLS, and BEA are all public APIs with generous rate limits. The Cleveland Fed scraper is a single HTTP request to a static page. The BEA and BLS calls happen once per cycle, not per market.

The total overhead to run the full 5-signal stack on a single cycle is maybe 3-4 seconds of network IO. That is nothing. You are not paying for speed here, you are paying with code complexity: five modules to maintain, five failure modes to handle, five sources to keep up to date when APIs change.

That is a real cost. But it is a fixed cost, and it is already paid. The modules exist. The fallback logic exists. The tests exist: 28 unit tests for regime-change detection alone, 34 for the strike-consistency enforcer that prevents the bot from holding contradictory positions on the same release.


The Module Structure

For reference, the relevant files in kalshiEconTrading:

kalshiEconTrading/
  signals/
    nowcast_scraper.py      # Cleveland Fed
    fred_signals.py         # FRED market indicators
    bls_signals.py          # BLS CPI subcomponents
    bea_signals.py          # BEA PCE data
    homemade_nowcast.py     # Weighted composite
  regime_change.py          # Auto-close on nowcast shift
  trade_executor.py         # Position management + caps
  kalshi_client.py          # API wrapper

Each signal module has the same interface: a load() function that returns either a dict of values or None on failure. The compositor does not care which signal it is talking to. It just asks for the value and handles None.

That uniformity is what makes graceful degradation clean rather than messy.


One Honest Limitation

The homemade nowcast is not a trained ML model. It is a weighted average with rules. It does not learn from past predictions. It does not update its own weights based on what worked last quarter.

That is a real limitation. A proper Bayesian updating scheme would improve it. It is on the list. For now, the weights are set by judgment and held constant. If you buy the source code and want to experiment with dynamic weight adjustment, the architecture supports it. The NOWCAST_WEIGHTS dict is just a config value.


The Econ Bot is available bundled with the Weather Bot at $97 one-time at predictandprofit.gumroad.com. If you came here from the ebook, code BOOKREADER saves 15%.

Five signals do not guarantee a winning trade. Nothing does. But they give you a more complete picture of where the probability actually sits, and that is all edge is: a better estimate than the market price reflects. Build it from one source or five. Your call.