<?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: 473185670</title>
    <description>The latest articles on DEV Community by 473185670 (@473185670).</description>
    <link>https://dev.to/473185670</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%2F4068155%2F7b476736-baf5-4a82-b30d-f07f3b9e7e7f.png</url>
      <title>DEV Community: 473185670</title>
      <link>https://dev.to/473185670</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/473185670"/>
    <language>en</language>
    <item>
      <title>I Built a Natural Language -&gt; pandas Code Generator (Open Source + Free)</title>
      <dc:creator>473185670</dc:creator>
      <pubDate>Thu, 13 Aug 2026 14:27:32 +0000</pubDate>
      <link>https://dev.to/473185670/i-built-a-natural-language-pandas-code-generator-open-source-free-10i</link>
      <guid>https://dev.to/473185670/i-built-a-natural-language-pandas-code-generator-open-source-free-10i</guid>
      <description>&lt;p&gt;If you've spent more time in pandas documentation than in your actual data, this is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I analyze data with pandas every day. And every day, I spend a non-trivial chunk of time looking up syntax I've used a hundred times but can't remember exactly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Was it &lt;code&gt;.agg()&lt;/code&gt; with a dict or a list of tuples?"&lt;/li&gt;
&lt;li&gt;"How do I do a rolling average with a min period?"&lt;/li&gt;
&lt;li&gt;"What's the seaborn one-liner for a correlation heatmap?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each lookup is 2-5 minutes of context-switching. Multiply by 30 lookups/day and that's an hour gone — not on analysis, just on syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A tool where you describe what you want in English, and it returns syntax-validated, copy-paste-ready pandas code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example input:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;Group&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;revenue&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Generated output:&lt;/strong&gt;&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;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;month&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_period&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;M&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;month&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;revenue&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sum&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;avg_order_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;order_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the datetime handling — the kind of thing you'd forget on the first pass and debug for 10 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Three components, no magic:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Few-Shot Examples (22 curated patterns)
&lt;/h3&gt;

&lt;p&gt;The system prompt includes 22 examples covering the patterns developers actually use: groupby+agg, merge/join, datetime, string ops, missing data, pivots, visualization, binning, filtering, chaining. This isn't a generic LLM wrapper — it's specialized for pandas.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Schema Awareness
&lt;/h3&gt;

&lt;p&gt;Upload a CSV or describe your columns, and the generator knows &lt;code&gt;df['date']&lt;/code&gt; is datetime and &lt;code&gt;df['user_id']&lt;/code&gt; is a string. No more "assume column X exists" placeholders.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AST Validation
&lt;/h3&gt;

&lt;p&gt;Before returning code, it runs &lt;code&gt;ast.parse()&lt;/code&gt; to catch syntax errors. If the model hallucinates a method, the validator flags it. You never get broken code — and it also scans for dangerous operations (&lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;subprocess&lt;/code&gt;, &lt;code&gt;os.remove&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  More Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rolling average:&lt;/strong&gt;&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;Calculate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;rolling&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;close&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rolling_avg&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;rolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Merge with conflict handling:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Merge&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt; &lt;span class="n"&gt;matching&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inner&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quantile binning:&lt;/strong&gt;&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;Create&lt;/span&gt; &lt;span class="n"&gt;quartile&lt;/span&gt; &lt;span class="n"&gt;bins&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;income&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="n"&gt;them&lt;/span&gt; &lt;span class="n"&gt;Q1&lt;/span&gt; &lt;span class="n"&gt;through&lt;/span&gt; &lt;span class="n"&gt;Q4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;income_quartile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qcut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;income&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Q1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Q2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Q3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Q4&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Correlation heatmap:&lt;/strong&gt;&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;Create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;heatmap&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;correlation&lt;/span&gt; &lt;span class="n"&gt;matrix&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;seaborn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sns&lt;/span&gt;
&lt;span class="n"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heatmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;corr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeric_only&lt;/span&gt;&lt;span class="o"&gt;=&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;annot&lt;/span&gt;&lt;span class="o"&gt;=&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;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;coolwarm&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What It's Not
&lt;/h2&gt;

&lt;p&gt;Let me be honest about the boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's not a black-box analyst.&lt;/strong&gt; It generates code you should read and verify. &lt;code&gt;df.groupby('date')['revenue'].sum()&lt;/code&gt; runs whether or not it answers your question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't know your data.&lt;/strong&gt; It doesn't know "revenue" is in cents, or that null means "not applicable." Domain knowledge stays human.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's not for complex multi-step pipelines (yet).&lt;/strong&gt; 2-3 step compositions work well. 10-step exploratory analysis is still your job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest value prop: it saves the 20-30% of time spent on syntax lookup, so you can spend it on the 70-80% that matters — understanding your data and interpreting results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Python FastAPI, pluggable LLM providers (OpenAI / Anthropic / Ollama / stub)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React + Vite, syntax highlighting, nature-themed UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt;: &lt;code&gt;ast.parse()&lt;/code&gt; + dangerous-op scanner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt;: 5 free queries/day per IP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;The free tier gives you 5 queries/day, no signup required:&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://pandasai-frontend.vercel.app" rel="noopener noreferrer"&gt;PandasAI — try it here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type a data operation in English, get validated pandas code. If you find a pattern it handles well (or badly), I'd love to hear about it.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>python</category>
      <category>pandas</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Backtested a Macro Scenario Classifier. The Signal Was Backwards.</title>
      <dc:creator>473185670</dc:creator>
      <pubDate>Mon, 10 Aug 2026 12:33:05 +0000</pubDate>
      <link>https://dev.to/473185670/i-backtested-a-macro-scenario-classifier-the-signal-was-backwards-2pb</link>
      <guid>https://dev.to/473185670/i-backtested-a-macro-scenario-classifier-the-signal-was-backwards-2pb</guid>
      <description>&lt;p&gt;I spent two weeks building a classifier that sorts ISM Manufacturing PMI releases into "GOLDILOCKS" (growth without overheating) and "CONTRACTION" (economy shrinking) scenarios. The textbook hypothesis: GOLDILOCKS predicts positive S&amp;amp;P 500 forward returns, CONTRACTION predicts negative ones.&lt;/p&gt;

&lt;p&gt;The backtest showed the exact opposite. CONTRACTION releases produced &lt;strong&gt;higher&lt;/strong&gt; forward S&amp;amp;P 500 returns than GOLDILOCKS at every horizon I tested -- and the sign test confirms this is not noise (p &amp;lt; 10^-13 at 42 days).&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;ISM Manufacturing PMI is a monthly survey of ~300 supply managers; above 50 = expanding, below 50 = contracting. The classification: &lt;strong&gt;GOLDILOCKS&lt;/strong&gt; (PMI ~52-58, strong new orders) = textbook bullish. &lt;strong&gt;CONTRACTION&lt;/strong&gt; (PMI &amp;lt; 50, weak new orders) = textbook bearish. This is not a controversial framework -- it's the kind of thing you'd find in any macro strategy deck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The backtest
&lt;/h2&gt;

&lt;p&gt;Event study on &lt;strong&gt;72 ISM PMI releases (Feb 2019 - Dec 2024)&lt;/strong&gt;, measuring actual S&amp;amp;P 500 forward return after each release. S&amp;amp;P 500 data is 100% live (yfinance, 1,530 trading days).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Horizon&lt;/th&gt;
&lt;th&gt;GOLDILOCKS&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;CONTRACTION&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;Spread (G-C)&lt;/th&gt;
&lt;th&gt;p (parametric)&lt;/th&gt;
&lt;th&gt;p (sign test)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5 days&lt;/td&gt;
&lt;td&gt;+0.80%&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;+1.13%&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.33%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.643&lt;/td&gt;
&lt;td&gt;0.882&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 days&lt;/td&gt;
&lt;td&gt;+0.97%&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;+1.90%&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.94%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.317&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00058&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21 days&lt;/td&gt;
&lt;td&gt;+1.19%&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;+2.37%&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-1.18%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.335&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00083&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42 days&lt;/td&gt;
&lt;td&gt;+2.20%&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;+4.73%&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-2.52%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7x10^-14&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The spread is &lt;strong&gt;negative at all four horizons&lt;/strong&gt; and &lt;em&gt;widens&lt;/em&gt; with the holding period. A CONTRACTION release followed by a 2-month hold returned &lt;strong&gt;4.73%&lt;/strong&gt; on average -- more than double GOLDILOCKS's 2.20%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the sign test matters here (and the parametric p doesn't kill this)
&lt;/h2&gt;

&lt;p&gt;The parametric Welch t-test doesn't reach significance (p = 0.64 / 0.32 / 0.33 / 0.10). Here's why that's not the end of the story: with n = 22-33 per group and heavy-tailed return distributions (equity returns have fat tails), the parametric test is &lt;strong&gt;underpowered&lt;/strong&gt; -- it needs large samples to detect a difference under non-normality. The parametric p = 0.64 means "can't confirm the mean difference with a normal-distribution assumption," not "there's no effect."&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;non-parametric sign test&lt;/strong&gt; doesn't assume any distribution. It just asks: "did CONTRACTION beat GOLDILOCKS more often than a coin flip would?" At 10, 21, and 42 days, the answer is yes with p = 0.00058 / 0.00083 / 7x10^-14. At 42 days, CONTRACTION outperformed GOLDILOCKS so consistently that the sign test is significant to &lt;strong&gt;14 decimal places&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The sign test is significant &lt;strong&gt;in the wrong direction&lt;/strong&gt;. That's the finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why? (my best guess)
&lt;/h2&gt;

&lt;p&gt;The most likely explanation: &lt;strong&gt;markets are forward-looking; contraction implies policy easing.&lt;/strong&gt; When ISM PMI drops below 50, the market doesn't just see "economy shrinking" -- it sees "Fed will cut rates." Rate-cut expectations are themselves bullish: they lower the discount rate on future cash flows, raising equity valuations. The 2019 and 2024 CONTRACTION episodes both coincided with dovish Fed pivots that drove sharp rallies.&lt;/p&gt;

&lt;p&gt;The classifier reads the &lt;em&gt;current&lt;/em&gt; economic state. The market prices the &lt;em&gt;future&lt;/em&gt; policy response. That's the disconnect.&lt;/p&gt;

&lt;p&gt;A secondary possibility: mean reversion. CONTRACTION releases cluster around sentiment-washed-out troughs (2020 COVID PMI 41 -&amp;gt; fastest recovery in history); GOLDILOCKS releases cluster around complacency peaks (2021 PMI 60 -&amp;gt; 2022 bear market). And yes, 72 releases is a small sample spanning a unusual regime (COVID + bear-&amp;gt;bull). The result may not generalize. But the sign test at p &amp;lt; 10^-13 is hard to dismiss as pure sample noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/473185670/macro-scenario-api
&lt;span class="nb"&gt;cd &lt;/span&gt;macro-scenario-api
pip &lt;span class="nb"&gt;install &lt;/span&gt;yfinance pandas scipy
python multi_horizon_backtest.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script reuses the same &lt;code&gt;classify_scenario()&lt;/code&gt; function the API exposes -- no look-ahead bias. S&amp;amp;P 500 pulls live from yfinance. Full results: &lt;code&gt;multi_horizon_result.json&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The interesting part isn't the classifier. It's that "CONTRACTION -&amp;gt; higher forward equity returns" is a real, statistically significant, counter-intuitive empirical regularity with a plausible mechanism. Whether it survives out-of-sample is an open question.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this counter-intuitive, the most useful thing you can do is try to refute it -- run the backtest on a different sample (services PMI, non-US equities, pre-2019 data) and tell me what you find.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>finance</category>
    </item>
    <item>
      <title>Classify ISM PMI Macro Scenarios in 10 Lines of Python (Free API)</title>
      <dc:creator>473185670</dc:creator>
      <pubDate>Sun, 09 Aug 2026 22:20:03 +0000</pubDate>
      <link>https://dev.to/473185670/classify-ism-pmi-macro-scenarios-in-10-lines-of-python-free-api-42f3</link>
      <guid>https://dev.to/473185670/classify-ism-pmi-macro-scenarios-in-10-lines-of-python-free-api-42f3</guid>
      <description>&lt;h1&gt;
  
  
  Classify ISM PMI Macro Scenarios in 10 Lines of Python
&lt;/h1&gt;

&lt;p&gt;Every first business day of the month, the Institute for Supply Management releases Manufacturing PMI. Traders scramble to interpret three numbers — headline PMI, New Orders, Prices Paid — into a macro posture: risk-on or risk-off?&lt;/p&gt;

&lt;p&gt;I built a free REST API that does this classification for you. It takes the PMI triple and returns a scenario (Goldilocks, Moderate, Soft Landing, or Contraction) with a confidence score and concrete trading actions across SPY, US10Y, BTC, and CRDO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No pip install. No API key for the demo. Copy-paste and run.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10-Line Version
&lt;/h2&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;urllib.request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://macro-scenario-api.onrender.com/classify_scenario&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headline_pmi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;52.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;54.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prices_paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;48.5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                             &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&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;as&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scenario"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GOLDILOCKS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.87&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Growth above 52, prices contained — risk-on"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SPY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LONG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HIGH"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US10Y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SHORT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MEDIUM"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LONG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MEDIUM"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The API is live, hosted on Render with a keep-alive cron so the free-tier cold start stays warm.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Production-ready on RapidAPI&lt;/strong&gt; — rate limits, Swagger docs, marketplace reliability. &lt;a href="https://rapidapi.com/qq1032153999/api/macro-scenario-analysis" rel="noopener noreferrer"&gt;&lt;strong&gt;Get your API key →&lt;/strong&gt;&lt;/a&gt; (free tier: 100 calls/mo, no credit card)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Four Scenarios
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Posture&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🍯 &lt;strong&gt;Goldilocks&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;PMI &amp;gt; 52, prices contained&lt;/td&gt;
&lt;td&gt;Risk-on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚖️ &lt;strong&gt;Moderate&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Solid growth, mild price pressure&lt;/td&gt;
&lt;td&gt;Risk-on (selective)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🪂 &lt;strong&gt;Soft Landing&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Growth cooling toward 50, prices easing&lt;/td&gt;
&lt;td&gt;Neutral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📉 &lt;strong&gt;Contraction&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Sub-50 headline, falling new orders&lt;/td&gt;
&lt;td&gt;Risk-off&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Full Markdown Report Endpoint
&lt;/h2&gt;

&lt;p&gt;Want a human-readable report you can paste into a trading journal? Hit the second endpoint:&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://macro-scenario-api.onrender.com/ism_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headline_pmi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;48.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;46.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prices_paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;55.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                             &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&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;as&lt;/span&gt; &lt;span class="n"&gt;resp&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns a formatted Markdown reaction report with the scenario, confidence, and a prioritized action table — ready for Notion, Obsidian, or any markdown journal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch Processing (CSV → Scenarios)
&lt;/h2&gt;

&lt;p&gt;Processing a year of historical PMI data? Loop it:&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;csv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://macro-scenario-api.onrender.com/classify_scenario&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ism_history.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&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;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headline_pmi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pmi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prices_paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prices_paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                     &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&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;as&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&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;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scenario&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (conf=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get the API on RapidAPI
&lt;/h2&gt;

&lt;p&gt;The demo above hits the public Render instance directly. For production usage with rate limits, Swagger docs, and marketplace reliability, the API is also published on &lt;strong&gt;RapidAPI&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://rapidapi.com/qq1032153999/api/macro-scenario-analysis" rel="noopener noreferrer"&gt;Macro Scenario Analysis API on RapidAPI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Free tier: 100 calls/month. Paid tier: $0.01/call — pay only for what you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Now
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Health check — confirms the API is awake
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://macro-scenario-api.onrender.com/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&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;as&lt;/span&gt; &lt;span class="n"&gt;r&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="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  &lt;span class="c1"&gt;# {"status":"ok","version":"1.0.0"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you build something with this, drop a comment — I'd love to see what scenarios you're tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest Note on "Edge"
&lt;/h2&gt;

&lt;p&gt;I ran a real event study on this classification: 72 ISM PMI releases mapped to actual S&amp;amp;P 500 returns. &lt;strong&gt;Result: the classification does NOT predict 5-day returns&lt;/strong&gt; (GOLDILOCKS +0.80% vs CONTRACTION +1.13%, p=0.643, direction backwards at 5/10/21/42-day horizons).&lt;/p&gt;

&lt;h2&gt;
  
  
  So what's this API good for? &lt;strong&gt;Organization and journaling, not alpha.&lt;/strong&gt; It gives you a consistent, reproducible framework to log your macro reactions and build a personal dataset over time. The edge — if you find one — comes from your &lt;em&gt;reaction&lt;/em&gt; to the scenario, not the scenario label itself. Use it as a decision journal, not a crystal ball.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The API is open and documented at &lt;a href="https://473185670.github.io/macro-scenario-api/" rel="noopener noreferrer"&gt;473185670.github.io/macro-scenario-api&lt;/a&gt;. Source on GitHub. Built as a macro decision journal, not financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>tutorial</category>
      <category>finance</category>
    </item>
    <item>
      <title>I Built a Macro Catalyst Trading Journal That Auto-Classifies ISM PMI Scenarios</title>
      <dc:creator>473185670</dc:creator>
      <pubDate>Fri, 07 Aug 2026 23:47:01 +0000</pubDate>
      <link>https://dev.to/473185670/i-built-a-macro-catalyst-trading-journal-that-auto-classifies-ism-pmi-scenarios-1kji</link>
      <guid>https://dev.to/473185670/i-built-a-macro-catalyst-trading-journal-that-auto-classifies-ism-pmi-scenarios-1kji</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Correction (Aug 9, 2026) — please read first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A comment below claimed the backtest showed GOLDILOCKS fired 3× (each preceding a &amp;gt;2% SPX weekly gain) and CONTRACTION correctly flagged risk-off 2 of 2 cases. &lt;strong&gt;That was wrong.&lt;/strong&gt; Those numbers came from a &lt;em&gt;simulator&lt;/em&gt; with hardcoded return assumptions, not real market data.&lt;/p&gt;

&lt;p&gt;I subsequently ran a &lt;strong&gt;real event-study backtest&lt;/strong&gt; (72 ISM PMI releases, 2019–2024, actual S&amp;amp;P 500 5-day forward returns via yfinance):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;5-day avg return&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GOLDILOCKS&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;+0.80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CONTRACTION&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;+1.13%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SOFT_LANDING&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;-2.47%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MODERATE&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;+0.25%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GOLDILOCKS vs CONTRACTION spread &lt;strong&gt;−0.33%, p=0.643 (not significant)&lt;/strong&gt;. The classification does &lt;strong&gt;not&lt;/strong&gt; reliably predict 5-day forward returns. Backtest code is open-source: &lt;a href="https://github.com/473185670/macro-scenario-api" rel="noopener noreferrer"&gt;&lt;code&gt;real_backtest.py&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So what is this about?&lt;/strong&gt; The tool is still useful as a &lt;strong&gt;macro organizer/journal&lt;/strong&gt; — it structures messy prints into 4 scenarios and logs your reasoning. But it is &lt;strong&gt;not a validated alpha signal&lt;/strong&gt;, and I should not have implied it was. Apologies. The bundle is now described honestly on Gumroad as an organizer toolkit, not an edge product.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;Every macro print — ISM, NFP, CPI, FOMC — I was manually reasoning about what it meant for my book. Three problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Slow&lt;/strong&gt;: By the time I'd thought through the implications, the move was done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent&lt;/strong&gt;: Same print on different days → different conclusion depending on my mood.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unlogged&lt;/strong&gt;: Two weeks later I couldn't remember why I'd rotated into industrials.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  The Solution
&lt;/h1&gt;

&lt;p&gt;I built a scenario classifier that takes 3 inputs — ISM Headline, New Orders, Prices Paid — and outputs one of 4 scenarios:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Bias&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🟢 GOLDILOCKS&lt;/td&gt;
&lt;td&gt;Strong growth, no overheat&lt;/td&gt;
&lt;td&gt;RISK-ON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟡 MODERATE&lt;/td&gt;
&lt;td&gt;Growth with cost pressure&lt;/td&gt;
&lt;td&gt;NEUTRAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟠 SOFT_LANDING&lt;/td&gt;
&lt;td&gt;Cooling but positive&lt;/td&gt;
&lt;td&gt;CAUTIOUS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔴 CONTRACTION&lt;/td&gt;
&lt;td&gt;Below 50 / decelerating&lt;/td&gt;
&lt;td&gt;RISK-OFF&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each scenario maps to sector rotation calls, duration positioning, and crypto/risk-asset bias.&lt;/p&gt;

&lt;h1&gt;
  
  
  The July 2026 ISM Mfg PMI Test
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Headline: &lt;strong&gt;55.6&lt;/strong&gt; vs consensus 54.0 → beat by 1.6&lt;/li&gt;
&lt;li&gt;New Orders: &lt;strong&gt;54.2&lt;/strong&gt; → expansion accelerating&lt;/li&gt;
&lt;li&gt;Employment: first expansion in &lt;strong&gt;34 months&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Prices Paid: &lt;strong&gt;71.1&lt;/strong&gt; → cost pressure persists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Classifier output&lt;/strong&gt;: GOLDILOCKS, 85% confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actions fired&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotate cyclicals &amp;gt; defensives (Industrials, Materials, Small Caps)&lt;/li&gt;
&lt;li&gt;US10Y → test 4.80%+ → short duration&lt;/li&gt;
&lt;li&gt;BTC risk-on, target $66k+&lt;/li&gt;
&lt;li&gt;AI interconnect (CRDO) structural bid reinforced&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The Code (Zero Dependencies)
&lt;/h1&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;urllib.request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify_scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices_paid&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;headline&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;new_orders&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;53&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;prices_paid&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GOLDILOCKS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RISK-ON&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;headline&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;prices_paid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MODERATE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;NEUTRAL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;headline&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SOFT_LANDING&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CAUTIOUS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CONTRACTION&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RISK-OFF&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;

&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;classify_scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;55.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;54.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;71.1&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;scenario&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;% confidence&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Try the full engine live in your browser (no signup): &lt;a href="https://473185670.github.io/macro-scenario-api/macro-scenario-backtest.html" rel="noopener noreferrer"&gt;Backtest Simulator&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The Packaging
&lt;/h1&gt;

&lt;p&gt;I packaged it as four products:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Notion Trading Journal Template ($7)&lt;/strong&gt;&lt;br&gt;
Four databases with 13 pre-loaded entries and 4 scenario playbooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Macro Scenario Analysis API (pay-per-call)&lt;/strong&gt;&lt;br&gt;
The classification engine wrapped in FastAPI, deployed on Render, listed on RapidAPI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Pine Script Indicator&lt;/strong&gt;&lt;br&gt;
Displays the scenario classification directly on TradingView charts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Semi Decoupling Dashboard ($9.99)&lt;/strong&gt;&lt;br&gt;
An HTML dashboard tracking NVDA vs semi equipment/storage decoupling.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Bundle
&lt;/h1&gt;

&lt;p&gt;All four for $14.99: &lt;a href="https://4043969836017.gumroad.com/l/txmuvz" rel="noopener noreferrer"&gt;gumroad.com/l/txmuvz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notion template standalone: &lt;a href="https://4043969836017.gumroad.com/l/nztlu" rel="noopener noreferrer"&gt;gumroad.com/l/nztlu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free preview: &lt;a href="https://pale-earth-1ab.notion.site/Macro-Catalyst-Trading-Journal-3b2bf3457ff381ec85fac20dfb726a0c" rel="noopener noreferrer"&gt;notion.site&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why This Works
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Zero competition on Gumroad.&lt;/li&gt;
&lt;li&gt;Zero maintenance (static template).&lt;/li&gt;
&lt;li&gt;Category creator on TradingView.&lt;/li&gt;
&lt;li&gt;Marketplace distribution via RapidAPI.&lt;/li&gt;
&lt;/ul&gt;







&lt;h2&gt;
  
  
  🎁 Free Cheat Sheet
&lt;/h2&gt;

&lt;p&gt;Grab the &lt;strong&gt;free ISM PMI Macro Scenario Cheat Sheet&lt;/strong&gt; — one page, 4 scenarios, live API demo, no signup:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://473185670.github.io/macro-scenario-api/static/free_macro_cheatsheet.html" rel="noopener noreferrer"&gt;Get the free cheat sheet&lt;/a&gt;&lt;br&gt;
&lt;em&gt;If you found this useful, the bundle is $14.99. Questions? Ask in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>productivity</category>
      <category>finance</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
