<?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: SignalStates</title>
    <description>The latest articles on DEV Community by SignalStates (@signalstates).</description>
    <link>https://dev.to/signalstates</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%2F4204309%2Fbd1ca7cd-c8c1-479c-a8d5-981f567814cb.jpg</url>
      <title>DEV Community: SignalStates</title>
      <link>https://dev.to/signalstates</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/signalstates"/>
    <language>en</language>
    <item>
      <title>How we built a crypto Fear &amp; Greed index from futures data, and what it can't tell you</title>
      <dc:creator>SignalStates</dc:creator>
      <pubDate>Sat, 24 Oct 2026 17:16:16 +0000</pubDate>
      <link>https://dev.to/signalstates/how-we-built-a-crypto-fear-greed-index-from-futures-data-and-what-it-cant-tell-you-bol</link>
      <guid>https://dev.to/signalstates/how-we-built-a-crypto-fear-greed-index-from-futures-data-and-what-it-cant-tell-you-bol</guid>
      <description>&lt;p&gt;Every crypto chart site quotes a Fear &amp;amp; Greed number. Few say what is inside it. We built one from the futures market's own daily prices and wrote the method down so anyone can reproduce it. This post explains the four measures, the maths, how we checked it, and where it falls short.&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes in
&lt;/h2&gt;

&lt;p&gt;The index is the plain average of four scores. Each runs from 0 (extreme fear) to 100 (extreme greed), and each counts for 25%.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Volatility.&lt;/strong&gt; Bitcoin's 30-day realised volatility: the standard deviation of its daily log returns, annualised. The score is 100 minus the percentile rank of today's value among the previous 365 days. Calm markets score high, turbulent ones low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Momentum.&lt;/strong&gt; How far Bitcoin's close sits above or below the average of its last 90 closes, ranked against the previous 365 days in the same way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breadth.&lt;/strong&gt; The share of the 100 most traded altcoins whose close is above their own 30-day average. The share is the score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appetite.&lt;/strong&gt; The Altcoin Season Index: the share of those same coins that beat Bitcoin over 90 days.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The bands are a convention: below 25 is extreme fear, 25 to 44 fear, 45 to 55 neutral, 56 to 74 greed, and 75 or more extreme greed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why percentile ranks
&lt;/h2&gt;

&lt;p&gt;Volatility and momentum have no natural 0 to 100 scale. Ranking today's value against the past year gives them one, and it answers a useful question: is this unusual for this year? The cost is that a very quiet year makes ordinary moves look large, so the score says "high for this year", not "high".&lt;/p&gt;

&lt;h2&gt;
  
  
  The maths in a few lines
&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;math&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;realised_vol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Annualised volatility in percent. `closes` are daily closes, oldest first.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;closes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;closes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stdev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;momentum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Percent above (or below) the average of the last n closes.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;percentile_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Share of the sample below value, ties counting half, from 0 to 100.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;below&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;sample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="c1"&gt;# volatility_score = 100 - percentile_rank(vol_today, vol_on_each_of_the_last_365_days)
# momentum_score   = percentile_rank(momentum_today, momentum_on_each_of_the_last_365_days)
# index            = (volatility_score + momentum_score + breadth + appetite) / 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only closed daily candles (UTC) are used, so the last point is the last completed day and a day's value never changes during the day. The history is recomputed from the same candles with the same rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we checked it
&lt;/h2&gt;

&lt;p&gt;We recomputed the Bitcoin measures independently from the raw daily closes and the scores matched to the decimal. The headline equals the mean of the four scores, and the appetite score equals the Altcoin Season Index for the same day. The maths has unit tests, including one that rebuilds the last day with a separate implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can't tell you
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It describes mood, not the next move.&lt;/strong&gt; It is not a forecast and not a buy or sell signal. In the year to October 2026 the index spent 93 days in extreme fear and 3 in extreme greed. Extreme readings can last a long time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calm is scored as greed.&lt;/strong&gt; Quiet markets usually go with confidence, but quiet can also come before a sharp move, and the index cannot tell which.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two measures are relative to the past year.&lt;/strong&gt; After a very quiet or very wild year, ordinary moves can look large or small.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The coin list is today's.&lt;/strong&gt; A coin that has since left the top 100 is not in the history, so older values carry survivorship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is not the same as other Fear &amp;amp; Greed indexes.&lt;/strong&gt; Others add social media activity, surveys and search trends. This one uses only price data, so the numbers differ even though the idea is the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  See it live
&lt;/h2&gt;

&lt;p&gt;The index, its one-year history with Bitcoin's price, a calendar of every day, and the full method are here, free and without an account: &lt;a href="https://signalstates.com/tools/crypto-fear-and-greed-index" rel="noopener noreferrer"&gt;https://signalstates.com/tools/crypto-fear-and-greed-index&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is not financial advice. Leveraged trading can lose more than you put in.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>python</category>
      <category>datascience</category>
      <category>bitcoin</category>
    </item>
  </channel>
</rss>
