Understand how the perpetual premium is computed, avoid the two most common misreads, and put it into a strategy.
The perpetual trades above spot. Does that mean the market is bullish? Market Sentiment measures how far Binance perpetuals sit above the index price, but it uses a USDT gap and compares only against the coin's own past 30 days. Those two details are where most people misread it.
Market Sentiment (MS) is Blave's futures premium indicator. It compares the close of Binance USDT-margined perpetuals with the Binance index price, then converts the gap into a z-score against that coin's past 30 days. The index price is Binance's weighted blend of spot quotes from several exchanges, not the spot price of a single venue. The calculation has three steps:
| Step | What it computes |
|---|---|
| 1. Gap | Every 5 minutes, perpetual close minus index price close, in USDT. Above 0 is a premium, below 0 a discount. |
| 2. Smooth | A 1-day rolling median of the gap filters out short-lived jumps. |
| 3. Standardize | A z-score using the past 30 days' mean and standard deviation gives the final value. |
Because it is a z-score, the value has no fixed bounds and every coin sits on the same scale. A positive value means the gap is wider than usual for the past 30 days: longs are willing to pay up on the perpetual. The data contains no trader counts and no positions. Studio's status badges use these thresholds:
| Value | Studio badge | Meaning |
|---|---|---|
| ≥ +3 | Over Optimistic | Gap far above the 30-day norm, an extreme reading |
| +2 ~ +3 | Highly Optimistic | Gap clearly above the norm |
| +0.5 ~ +2 | Optimistic | Gap above the norm |
| −0.5 ~ +0.5 | Neutral | In line with the 30-day norm |
| ≤ −0.5 | Pessimistic / Highly Pessimistic / Over Pessimistic | Mirror of the positive side at −0.5, −2 and −3: the gap is below normal and the perpetual is weak against the index |
The raw input is perpetual price minus index price in USDT, and nothing in the calculation divides by price. So with the percentage premium unchanged, the USDT gap grows as the same coin's price rises. Across coins, price level does not matter, because each coin is standardized against itself.
A hypothetical example: 30 days ago a coin traded near 1 USDT and the perpetual sat 0.001 USDT above the index, a 0.1% premium. The price then climbs to 2 USDT and the premium is still 0.1%, but the gap is now 0.002 USDT. The percentage has not moved, yet the gap is above its 30-day average, so Market Sentiment rises. A sharp price drop within 30 days works the other way and pushes the value down.
The z-score compares the coin with its own 30-day average. If a coin's perpetual holds roughly the same premium for two months, the average rises to meet it and Market Sentiment drifts back toward 0. Here 0 means "about the same as the past 30 days", not "no premium".
The reverse also happens. When a coin falls from a large premium to a small one, the gap drops below its 30-day average and the value can turn negative while the perpetual still trades above the index. The same +2 on different coins or in different months can reflect very different actual gaps.
No official strategy uses Market Sentiment today, so all three uses below are sketches, not backtested. The ±0.5 and 3 in the code borrow Studio's badge thresholds as a starting point. They did not come from a parameter scan, so backtest before you use them.
The most direct version: go long when Market Sentiment rises above an entry threshold, and go flat when it falls below an exit threshold. The buffer between the two keeps the strategy from flipping in and out when the value hovers around a single level.
ENTRY_TH = 0.5 # sketch: the Optimistic badge threshold
EXIT_TH = -0.5 # sketch: the Pessimistic badge threshold
def compute_signals(df, entry_th=ENTRY_TH, exit_th=EXIT_TH):
# df['MS'] = the coin's Market Sentiment value
signal = pd.Series(np.nan, index=df.index)
signal[df['MS'] > entry_th] = 1.0 # gap above normal -> go long
signal[df['MS'] < exit_th] = 0.0 # gap below normal -> go flat
return signal
Since the value is already a 1-day median, this signal follows day-level changes in the gap and does not react to price moves within minutes. It has no backtest, so scan the thresholds and the direction (trend-following or contrarian) yourself.
A value of ±3 means the gap is extreme relative to the past 30 days. A conservative use is to skip it as an entry signal and add it to an existing strategy's entry rule instead, holding off new positions while it is extreme:
# sketch: no entry while |MS| >= 3 (Over Optimistic or Over Pessimistic) too_hot = df['MS'].abs() >= 3 entry = compute_entry(df) & ~too_hot
This is not a reversal signal, and it is not backtested. Blave has not verified that price reverses after a ±3 reading, or that skipping those readings improves results; here an extreme gap simply pauses new entries. Because ±3 is relative to the past 30 days, a coin whose gap has been very stable can reach ±3 on a small change. Replace compute_entry with your strategy's existing entry condition.
Market Sentiment is a slow, day-level signal, which suits a background filter: accept long signals from a short-window indicator such as Taker Intensity only while Market Sentiment is above 0, and go flat once it drops to 0 or below. The structure below is a sketch; replace compute_fast_entry with your own condition:
ms = fetch_market_sentiment(SYMBOL, INTERVAL, START, END, hdrs) df['MS'] = ms['alpha'] regime_long = df['MS'] > 0 # sketch: long only while the gap beats its 30-day average fast_entry = compute_fast_entry(df) # e.g. a short-window Taker Intensity condition signal = pd.Series(np.nan, index=df.index) signal[regime_long & fast_entry] = 1.0 signal[~regime_long] = 0.0
This combination is not backtested and the threshold of 0 is only illustrative. Scan the parameters and check performance after fees before you use it.
Market Sentiment has one setting: the bar interval (period), one of 5min, 15min, 1h, 4h, 8h or 1d, with 5 minutes as the minimum. There is no window parameter like Whale Hunter's timeframe. Whatever interval you pick, the value is already a 1-day median, so the interval only sets how often you read the value; it does not remove the underlying 1-day median smoothing.
| Interval | Studio default range | Notes |
|---|---|---|
5min / 15min | 5min: 3 days; 15min: 7 days | Densest plot, but it still shows day-level smoothed changes; not for short-term timing |
1h / 4h | 1h: 14 days; 4h: 30 days | For strategies that check every few hours |
8h / 1d | 8h: 60 days; 1d: 180 days | For reading the sentiment trend over a longer stretch |
Pick the interval by how often your strategy checks, not to catch short-term moves. Data starts on 2020-01-01 (or the coin's listing date). The z-score needs 30 days of samples, so meaningful values begin around 2020-01-31, and the same applies to the first 30 days of a newly listed coin.
| Page | What it shows |
|---|---|
| Overview | An overall sentiment gauge (Market Sentiment averaged across all coins, weighted by open interest value in USDT) plus optimistic and pessimistic rankings with symbol, 24h change, index and status. |
| Sectors | Market Sentiment ranked by sector; each sector's value is the average of its coins weighted by open interest value. |
| History | Market Sentiment bars for one coin over price, with 5min to 1d intervals and the stat field. For non-Pro users, the most recent 7 days are delayed. |
These are ideas for combining signals, not verified results:
| Pairing | Purpose |
|---|---|
| MS + Whale Hunter | When the gap widens, check Whale Hunter for an unusual rise in open interest at the same time, to help judge whether new positions sit behind the premium. |
| MS + Taker Intensity | Market Sentiment reacts slowly; Taker Intensity shows aggressive buying and selling on short windows, filling in the short-term moves it cannot see. |
The API endpoint is GET /market_sentiment/get_alpha with symbol, period and start/end dates (start_date, end_date); in Blave Agent the helper is fetch_market_sentiment. Coverage is Binance USDT-margined perpetuals only; other exchanges are not included. Only closed bars are returned, with timestamp, alpha and stat and no price. Without a start date you get the last 365 days, and ranges longer than 365 days are truncated.
The stat object describes the latest reading, and its field names don't quite match what they compute:
| Field | What it actually computes |
|---|---|
up_prob | A logistic regression trained on the past 365 days uses Market Sentiment to predict whether price is up or down 24h later, and returns the probability of up. The training data includes the current period, so it is an in-sample estimate, not an out-of-sample win rate. |
avg_up_return /avg_down_return | Average 24h return across all up / down outcomes in the past 365 days, regardless of the Market Sentiment level. |
exp_value | up_prob × avg_up_return + (1 − up_prob) × avg_down_return, as a decimal, not a percentage. |
is_data_sufficient | Whether the coin's data starts more than 365 days ago, not whether this reading level has enough samples. |
stat is an in-sample estimate. Verify any threshold with your own backtest.