← Back to Dashboard

Documentation

How each tab works, where the data comes from, and how calculations are performed.

BRL USDC

Compare the true cost of buying USDC across Brazilian exchanges

How it works

For a given BRL amount, the dashboard fetches live prices from 7 exchanges and calculates the total USDC you'd receive after all fees — not just the exchange rate.

1
IOF tax (if applicable)
Brazilian tax on international transfers. Only Wise charges this (0.38%). Deducted from BRL before conversion.
2
Trading fee
Each exchange charges a taker fee on the trade (0.075% to 0.70%). Deducted from BRL after IOF.
3
BRL → USDC conversion
Remaining BRL is divided by the ask price (the price sellers are offering) to get USDC.
4
Withdrawal fee
Some exchanges charge a flat fee to withdraw USDC to your wallet (0 to 5 USDC). Subtracted from the total.

Calculation

brl_after_iof = input_brl - (input_brl × iof_pct)
brl_after_fees = brl_after_iof - (brl_after_iof × trading_fee_pct)
usdc_received = (brl_after_fees / ask_price) - withdrawal_fee

The "total cost %" shown on each card is how much USDC you lose vs. a hypothetical perfect trade at the Coinbase mid-market rate with zero fees.

Exchanges tracked

ExchangePairFeeWithdrawal
BinanceUSDC/BRL0.075%0.30 USDC (BSC)
BitybankUSDC/BRL0.20%Free (Solana)
BitsoUSDT/BRL0.40%5 USDT (ERC-20)
FoxbitUSDC/BRL~0.50%1 USDC (ERC-20)
Mercado BitcoinUSDC/BRL0.70%1 USDC (Polygon)
NovaDAXUSDC/BRL0.45%1 USDC (Polygon)
WiseBRL/USD~1.3% + 0.38% IOFFree (Base)

Coinbase spot rate is used as the mid-market reference only — not included in the ranking since its quoted rate doesn't reflect what you'd actually pay after their spread and fees. Wise is a wire transfer service (BRL → USD → mint USDC), not a crypto exchange — it's included because the end result is the same: USDC in your wallet.

News Sentiment

Crypto news sentiment scored by FinBERT, overlaid with BTC price

Pipeline

1
Scrape RSS feeds
Daily at 1 AM ET. Sources: Decrypt, Blockworks, CoinDesk, U.Today, BeInCrypto, CryptoTimes.
2
Score with FinBERT
Each headline is run through FinBERT (a BERT model fine-tuned on financial text). Outputs: probability of positive, negative, and neutral sentiment.
3
Compute daily aggregate
Headlines are grouped by date. The daily sentiment score is the average of all headline scores for that day, normalized to a 0–100 scale.
4
Overlay BTC price
Daily BTC closing price from yfinance is stored alongside sentiment for correlation analysis.

Sentiment score

FinBERT outputs three probabilities for each headline: P(positive), P(negative), P(neutral). The raw score ranges from -1 to +1 and is rescaled to 0–100 for display.

raw_score = P(positive) - P(negative) ∈ [-1, +1]
display_score = (raw_score + 1) × 50 ∈ [0, 100]

Historical data includes ~37,000 headlines going back to May 2024. Only English-language crypto news is scored — the model does not capture sentiment from social media, forums, or non-English sources.

Fear & Greed gauge

The gauge shows a 7-day moving average of the daily sentiment score. It's a simple sentiment-derived analog of the popular Fear & Greed Index, based purely on news tone rather than market indicators.

0–20 Extreme Fear20–40 Fear40–60 Neutral60–80 Greed80–100 Extreme Greed

What's on the chart

Main chart (top): Daily sentiment score (0–100) as an area chart, with 7-day and 30-day moving averages. BTC price is plotted on a secondary axis for visual correlation.

Volume bars (bottom): Number of headlines per day, colored green/red based on whether sentiment was above or below 50.

Headlines feed: Most recent headlines with their individual sentiment scores and source.

Beta Analyzer

Measure altcoin volatility relative to Bitcoin

What is Beta?

Beta (β) measures how much an altcoin moves relative to Bitcoin. It's the slope of a linear regression of the altcoin's daily returns against Bitcoin's daily returns.

β < 1
Less volatile than BTC
β = 1
Same as BTC
β > 1
More volatile than BTC

Step-by-step calculation

1
Fetch daily closing prices
~2000 days of history for BTC and the selected altcoin (SOL or ETH) from CryptoCompare.
2
Compute daily returns
For each consecutive pair of days: return = (price_today - price_yesterday) / price_yesterday. Simple percentage change, not log returns.
3
Align by date
Match BTC and altcoin returns that fall on the same calendar day. Discard days where one has data and the other doesn't.
4
Scatter plot regression
Run OLS linear regression: ALT_return = β × BTC_return + α. The slope (β) is the beta shown in the stats. R² measures goodness of fit.
5
30-day rolling window
For the "over time" chart: slide a 30-day window across the full history. At each position, compute β from just those 30 paired returns. Plot each β value on the date of the window's end.
6
Timeframe trimming
The timeframe buttons (30D, 90D, 1Y, etc.) control how far back the charts display. The scatter plot uses returns from the selected period. The rolling beta always uses a 30-day window but shows more or less history.

Formulas

Daily return
r(t) = (price(t) - price(t-1)) / price(t-1)
Beta (OLS slope)
β = Cov(r_alt, r_btc) / Var(r_btc)
R-squared (goodness of fit)
R² = 1 - SS_residual / SS_total

R² close to 1 means BTC explains most of the altcoin's movement. R² close to 0 means the altcoin moves independently.

Limitations

Simple returns, not log returns. The calculation uses arithmetic daily returns (price change / previous price) rather than logarithmic returns. For typical daily crypto moves (<5%), the difference is negligible. For extreme days (+20%), simple returns slightly overstate volatility.

Rolling window is fixed at 30 days. This captures short-term regime changes well but can be noisy. A longer window (60–90d) would be smoother but slower to react to shifts in market behavior.

Only two altcoins. SOL and ETH are included because they have deep, reliable price history. Other altcoins could be added but may have thinner data or gaps that distort the regression.

Mayer Multiple

Price / 200-day moving average — a long-term valuation signal

How it works

1
Fetch price history
~2000 days of daily closing prices from CryptoCompare. Available for BTC, ETH, and SOL.
2
Compute 200-day simple moving average
For each day from day 200 onward: MA200 = average of the previous 200 closing prices.
3
Divide price by MA200
Mayer Multiple = today's price / 200-day MA. That's it.
Mayer Multiple = Price / SMA(200)

Zone interpretation

Popularized by Trace Mayer. The 200-day MA is a widely-watched trend indicator in traditional finance. The multiple tells you how stretched the price is relative to its long-term trend. Note that the zone thresholds are based on BTC's historical cycles — they may not apply directly to ETH or SOL, which have shorter histories and different market dynamics.

< 0.8Undervalued
Price is well below the 200-day trend. Historically rare — strong accumulation signal.
0.8 – 1.0Below Average
Price is below its 200-day MA. Often seen during corrections or early recovery.
1.0 – 1.4Neutral
Price is near the 200-day MA. Normal conditions.
1.4 – 2.4Caution
Price is significantly above trend. Consider taking profits or reducing exposure.
> 2.4Overvalued
Price is far above the 200-day MA. Historically preceded major corrections.

MVRV Ratio

Market Value to Realized Value — on-chain valuation metric

What is MVRV?

MVRV compares two ways of measuring a blockchain's total value:

Market Value (MV)
The total market cap: current price × circulating supply. What the market thinks it's worth right now.
Realized Value (RV)
Each coin valued at the price it last moved on-chain, summed up. An approximation of the aggregate cost basis of all holders.
MVRV = Market Cap / Realized Cap

When MVRV is high, the average holder is sitting on large unrealized gains — historically a signal that profit-taking may be near. When MVRV is below 1, the average holder is underwater.

Zone interpretation

< 1.0Undervalued
Market cap is below realized cap. The average holder is at a loss. Historically the strongest accumulation zone — capitulation bottoms.
1.0 – 2.0Fair Value
Market is above cost basis but not stretched. Normal bull/bear market range.
2.0 – 3.5Overheated
Average holder has 2–3.5x unrealized gains. Increased likelihood of distribution and corrections.
> 3.5Euphoria
Extreme unrealized profit across the network. Historically marks cycle tops. Every BTC cycle top has peaked with MVRV above 3.5.

Data source

MVRV data comes from the CoinMetrics Community API (free, no API key). They compute realized cap by tracking every coin's on-chain movement — via UTXOs for BTC and account state for ETH. Available for BTC since July 2010 (~5,700 daily data points) and ETH since August 2015 (~3,900 points). SOL is not available on CoinMetrics' free tier.

Data Pipeline

How data is fetched, stored, and served

Data sources

SourceWhatRefresh
Exchange APIsLive USDC/BRL ask/bid from 7 exchanges + Coinbase referenceEvery page load (5 min ISR cache)
CoinGeckoDaily prices for 7 coins (seeded at 365d, grows over time)Hourly cron, fetches 7-day window and merges
CryptoCompareDaily prices for BTC, ETH, SOL (seeded at 2000d, grows over time)Hourly cron, fetches 30-day window and merges
CoinMetricsMVRV ratio for BTC (since 2010) and ETH (since 2015)Hourly cron, appends only new days
Sentiment pipeline~37K headlines from 6 RSS sources + BTC price + FinBERT scoresDaily at 1 AM ET via systemd timer

Storage strategy

All market data is stored as local JSON files. Fetches are incremental — existing data is preserved and only new or recent data points are fetched and merged.

Price data (CoinGecko, CryptoCompare): Stored as [[timestamp_ms, price], ...] arrays. Deduplication is done by normalizing timestamps to calendar dates — if two entries fall on the same day, the newer fetch wins. History grows indefinitely beyond the API's rolling window.

MVRV data (CoinMetrics): Stored as {date, mvrv} objects. The API supports start_time, so we only request days after our last entry. No dedup needed.

Sentiment data: Stored in SQLite. The daily pipeline scrapes, scores, and inserts. No overwrites.

What happens on page load

The page is statically generated by Next.js and revalidated every 5 minutes (ISR). When you visit, all tab components mount and fire their data fetches in parallel:

TabAPI callsReads from
BRL → USDC/api/ratesLive exchange APIs
Sentiment/api/sentiment/* (3 calls)Local SQLite DB
Beta/api/coingecko (2 calls)Local JSON files
Mayer Multiple/api/coingecko (1 call)Local JSON files
MVRV/api/mvrv (1 call)Local JSON files

Except for the exchange rates API (which hits live external APIs), every call reads from local storage. No external API calls are made on page load.

Built by Lucas · Data from CoinGecko, CryptoCompare, CoinMetrics, and FinBERT