Skip to content

Methodology

This page documents how the numbers and charts on this site are produced. The intent is that any figure cited in a brief can be traced back to its inputs and to the formula used.

If anything here looks wrong, the source is in the repository — issues and corrections are welcome.

What this site does

The author runs a daily process on real market data and publishes the output as dated briefs. Each brief uses the metrics defined below, applied to the data described below. A paper-portfolio log records the decisions the briefs lead to. There is no real-time data, no automated trading, and no recommendation to buy or sell anything.

Data sources (v1)

Spot prices: BTC and ETH

Field Value
Source Binance public REST endpoint /api/v3/klines
Symbols BTCUSDT, ETHUSDT
Interval 1d — one daily candle per asset per UTC day
Fields kept open time, open, high, low, close, volume
"Daily close" The close field of the 1d candle that ends at UTC midnight
Timezone UTC throughout — no local-time conversions
Authentication None (public endpoint, no API key)
First available day Each pair was first listed on Binance in 2017; the exact first day available is whatever the endpoint returns on first backfill

Why Binance. It is a venue the author has actually traded on. Prices reported here are prices that were tradable for retail at the relevant time. The public klines endpoint is free, requires no account, and has continuous coverage since each pair was listed.

Why daily, not intraday. The site is not a real-time tool. Daily candles are sufficient for the metrics below and avoid the noise and effort cost of higher frequencies. Intraday data may be added later if a brief topic genuinely needs it.

Single venue, not an index. All prices here come from one exchange. They are not consensus prices and they are not an average across venues. A brief that needs a cross-venue check will note that explicitly.

What v1 excludes (and will add later)

Excluded in v1 Why deferred
Social-media or news sentiment Adds API choice, rate-limit handling, and a separate methodology section — none of which v1 needs
On-chain data Same reason
Order book or trade tape Daily closes are enough for v1 metrics
Equities, commodities, FX, macro Different sources and different conventions (e.g. equities annualize over 252 trading days, not 365)
Prediction markets (Polymarket, Kalshi) Separate methodology section needed when added
Other exchanges (Coinbase, Kraken, DEXes, DeFi) Cross-venue work is interesting and not v1

Historicity

On first run the fetcher backfills the full available daily history per pair (from the first day Binance returns up to the previous UTC day). Each subsequent run pulls only days newer than the most recent row already in the parquet. The result is a parquet file per data type, committed to the repo, so that every brief is reproducible from the repo state at its commit.

There is no resampling, no forward-fill, and no interpolation. Crypto trades 24/7 so there are no calendar gaps the way there would be for equities. Any day missing from Binance's response — for example due to an outage that crosses UTC midnight — is left missing rather than imputed. If a missing day affects a brief, the brief notes it.

Metrics

All metrics operate on the daily close prices described above. They are computed by scripts/compute_metrics.py in the repository. The annualization factor used throughout is 365, because crypto trades every day. This differs from the equities convention of 252, which assumes a 252-trading-day year.

Notation: P_t is the daily close on day t. r_t and ℓ_t are the simple and log return for day t. W is the rolling-window length in days.

Simple return

The fractional change in price from the previous close to today's close.

r_t = P_t / P_{t-1} − 1

A simple return of 0.042 means the asset closed 4.2% higher than the prior day's close. Used because it is the intuitive answer to "how much did the price move."

Caveat. Simple returns are not additive over time. A +10% day followed by a −10% day does not return to start: (1 + 0.10)(1 − 0.10) = 0.99, i.e. a 1% loss. For any multi-period analysis we use log returns instead.

Log return

The natural logarithm of the price ratio.

ℓ_t = ln(P_t / P_{t-1})

Log returns are additive across time — the log return over a 30-day window is the sum of the 30 daily log returns. They are also symmetric — a move from 100 to 110 has the same magnitude (opposite sign) as a move from 110 to 100.

We use log returns whenever a calculation involves summing or comparing returns across multiple periods (volatility, Sharpe, cumulative). We use simple returns when a brief wants to show "the price moved X% today" to the reader, because simple returns are more intuitive at that level.

For small daily moves the two are nearly equal: ℓ ≈ r − r²/2. They diverge for large moves.

Cumulative return

Total return from a chosen start date to today.

R_cum(t) = ∏ (1 + r_s)  −  1                  (compounded simple returns)
         = exp( Σ ℓ_s ) − 1                   (sum of log returns)

Reported as a percentage. Used in the weekly review to show paper-portfolio P&L and to give "since inception" or "year-to-date" context.

Volatility (realized, rolling, annualized)

Standard deviation of daily log returns over a rolling window, scaled to a one-year horizon.

σ_ann(t) = stdev( ℓ_{t-W+1}, …, ℓ_t )  ·  √365

Default window: W = 30 days. Reported as a percentage.

What it tells us. How dispersed the asset's daily log returns have been recently. A 30-day annualized volatility of 60% on BTC means: if the recent dispersion of daily returns continued for a year, one standard deviation of the year's return would be about ±60%.

Caveats.

  • Volatility is backward-looking. It describes recent dispersion, not the next period.
  • The √365 annualization assumes returns are uncorrelated day-to-day (no autocorrelation) and have stable variance. Both are approximations; crypto sometimes shows clustering of high-volatility days that breaks them.
  • Volatility systematically understates tail risk: rare large moves contribute more to real-world loss than their effect on the standard deviation suggests.
  • The choice of window matters. A 30-day window reacts faster to a change in regime than a 90-day window but is noisier.

Sharpe ratio (rolling, annualized)

Mean excess return per unit of risk, over the same rolling window.

Sharpe_ann(t) = √365  ·  ( mean( ℓ_{t-W+1..t} ) − r_f / 365 )  /  stdev( ℓ_{t-W+1..t} )

Read left-to-right: compute the daily Sharpe ratio — (mean excess daily log return) / (stdev of daily log returns) — then multiply by √365 to annualize.

Default window: W = 30 days. Risk-free rate r_f: 0 in v1 (reconsider when briefs cover longer horizons).

What it tells us. Whether the asset's recent returns have compensated for the risk taken to earn them. A Sharpe of 1 means about one unit of return per unit of volatility, annualized; 0 means the asset's average return is no better than holding the risk-free rate; negative means losing on average.

Caveats.

  • Sharpe assumes returns are approximately normal. Crypto returns have fat tails, so Sharpe overstates how attractive a strategy looks in calm periods and understates the risk during turbulence.
  • A 30-day Sharpe is noisy. Without many years of data, it should be read as a snapshot of a recent regime, not a verdict on the asset.
  • Sharpe is path-blind: two return series with the same daily mean and standard deviation but very different drawdown paths have the same Sharpe.
  • Setting r_f = 0 is a simplification. In an environment with non-trivial cash yields, this overstates the Sharpe of any positive-mean strategy. v1 keeps it at 0 for clarity; this will be revisited.

Refresh cadence

The daily-brief fetcher is run by hand during the daily ritual, targeted at 3–4 days per week initially. There is no automated cron in v1. Adding one is a small change to the build pipeline and is on the v2 list.

Limits and known caveats

  • All numbers come from a single exchange. Cross-venue checks against Coinbase, Kraken, or an aggregator are not done in v1.
  • The paper portfolio uses Binance daily closes as mark prices. Real execution would differ by fees, slippage, and intraday timing — none of which the paper portfolio models.
  • The metrics above are textbook definitions. Production-grade work would add: regime-aware volatility estimators (GARCH, EWMA), tail-aware risk measures (CVaR, expected shortfall), and benchmark-relative versions (excess return over buy-and-hold). All v2.
  • Risk-free rate is currently 0. This affects every Sharpe value here.

Disclaimer

Nothing on this site is investment advice. Numbers are historical and reproducible from the source data; they do not predict future returns. The paper portfolio is a learning exercise; it does not reflect real positions or real money at risk.