Bitcoin cycle indicators

TradingView Pi Cycle Top Indicator: Formula, Daily Data, and Limits

The Pi Cycle Top indicator compares Bitcoin's 111-day simple moving average with twice its 350-day simple moving average. An upward crossover is the event commonly called a top signal. Philip Swift created the indicator in April 2019. Historical proximity to selected peaks does not establish a future prediction rate. On TradingView, use daily price data and distinguish a developing crossover from one confirmed at the daily close.

See the decision guide

Read the formula before choosing a TradingView script

Look Into Bitcoin identifies Philip Swift as the creator and describes the two daily averages. The name refers to 350 / 111, approximately 3.153, being close to pi. That numerical resemblance is not a causal model of price. Search TradingView Indicators for Pi Cycle Top, then inspect the author, source availability, price input, timeframe, and alert rules; scripts with the same name can differ.

  • Keep the symbol, exchange, quote currency, and daily session fixed when comparing scripts. A different feed can produce different daily closes and crossing dates.
  • Use standard candles. Heikin Ashi and other synthetic chart prices change the input being averaged.
  • With uninterrupted daily observations, the slow line needs 350 closes. Detecting a crossover also requires the prior pair of valid averages.
QuantityDefinitionInterpretation
Fast lineSum of the latest 111 daily closes / 111Mean closing price over the shorter window.
Slow line2 × (sum of the latest 350 daily closes / 350)Twice the longer-window mean, not investor cost basis.
Upward crossoverFast > slow today, and fast <= slow on the prior dayA one-day event; remaining above the slow line is a state.
Spread100 × (fast / slow - 1)Relative distance between averages, not a probability or time-to-top estimate.

Why historical alignment is not a prediction success rate

The creator's page describes alignment over three past market cycles and also warns that the relationship may cease to be relevant as market structure changes. This page does not independently reproduce those historical results or report a hit rate. The following are evaluation constraints, not claims about a completed backtest.

  • Two peaks in one market cycle are not automatically two independent tests. A handful of cycles gives limited evidence about future conditions.
  • A future high can occur without a crossover. An observed crossover can be followed by further gains. Neither outcome contradicts the arithmetic.
  • Do not infer that ETF flows or another narrative caused a particular miss without evidence. Changed market structure is a possible failure mechanism, not a measured explanation here.
Research choicePotential biasA reproducible alternative
Choose parameters after seeing old peaksThe apparent fit includes information unavailable before those peaks.Separate history before the April 2019 publication from later observations.
Show only famous peaks near a crossSelection can hide peaks without a cross and crosses without a qualifying peak.Define a peak and matching window in advance; enumerate both misses and extra signals.
Count every day above the slow lineRepeated observations from one episode inflate the sample.Count distinct upward crossings and disclose clustered events within the same cycle.
Change the tolerance after seeing resultsA wider window can turn misses into apparent successes.Freeze the tolerance, source feed, and price convention before evaluation.

Daily chart example: confirm the event at the close

Paste this complete indicator into Pine Editor and add it to a standard 1D Bitcoin chart. The lines use the current daily close and can move while that bar is open. The marker and alert condition require a completed daily bar. Select Pi Cycle daily cross in Create Alert and use Once Per Bar Close. This indicator creates no orders and no Strategy Tester results.

Pine Script v6: standard daily chart onlypinescript
//@version=6
indicator("Pi Cycle: daily close confirmation", overlay = true)

if not chart.is_standard or not (timeframe.isdaily and timeframe.multiplier == 1)
    runtime.error("Use a standard 1D chart.")

float fast = ta.sma(close, 111)
float slow = 2.0 * ta.sma(close, 350)
bool crossed = ta.crossover(fast, slow)
bool confirmedCross = crossed and barstate.isconfirmed
float spread = not na(slow) and slow != 0 ? 100.0 * (fast / slow - 1.0) : na

plot(fast, "111-day SMA", color.orange, 2)
plot(slow, "2 x 350-day SMA", color.purple, 2)
plot(spread, "Spread (%)", display = display.data_window)
plotshape(confirmedCross, title = "Confirmed cross", style = shape.triangledown,
     location = location.abovebar, color = color.red, size = size.small)
alertcondition(confirmedCross, "Pi Cycle daily cross",
     "Daily 111 SMA crossed above 2 x 350 SMA on {{ticker}}.")

Intraday example: display only completed daily values

This version calculates both averages and the crossover inside request.security. Every requested result is offset by one daily bar and paired with lookahead_on. It makes the prior completed daily result available in the next daily period. The marker appears at the close of that period's first intraday bar, so its timestamp differs from the daily example by design. Use a standard time-based intraday chart; weekly and daily charts are rejected.

  • lookahead_off alone can return developing daily values in real time. Offsetting the expression while retaining lookahead_off is not the same historical mapping as the recipe above.
  • Using lookahead_on without the offset leaks final daily information into earlier historical intraday bars.
  • Do not average a stepped daily-close series outside the request: that counts chart bars. Likewise, confirming a 1-hour bar does not confirm the unfinished daily bar.
  • The code avoids changes caused by an unfinished daily bar. It cannot prevent exchange data revisions or changes caused by selecting another symbol.
Pine Script v6: confirmed daily data on an intraday chartpinescript
//@version=6
indicator("Pi Cycle: completed daily data", overlay = true)

if not chart.is_standard or not (timeframe.isseconds or timeframe.isminutes)
    runtime.error("Use a standard time-based intraday chart.")

completedDailyValues() =>
    float fast = ta.sma(close, 111)
    float slow = 2.0 * ta.sma(close, 350)
    bool crossed = ta.crossover(fast, slow)
    [fast[1], slow[1], crossed[1]]

[dailyFast, dailySlow, dailyCross] = request.security(syminfo.tickerid, "1D",
     completedDailyValues(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_on)
bool eventBar = timeframe.change("1D") and dailyCross and barstate.isconfirmed

plot(dailyFast, "Completed 111-day SMA", color.orange, 2, plot.style_stepline)
plot(dailySlow, "Completed 2 x 350-day SMA", color.purple, 2, plot.style_stepline)
plotshape(eventBar, title = "Prior daily cross", style = shape.triangledown,
     location = location.abovebar, color = color.red, size = size.small)
alertcondition(eventBar, "Pi Cycle prior daily cross",
     "The prior completed daily bar crossed on {{ticker}}.")

Reproduce the calculation and check alert timing

These are verification steps for your chart, not reported market-test results. Record the exchange-qualified ticker, standard chart type, data range, and script version. Start with a feed containing more than 350 daily bars; a recently listed instrument may not have enough history.

  • On 1D, choose a completed date and calculate the two averages from the last 111 and 350 closes, including that date. Compare the results with the Data Window.
  • For a hypothetical calculation, fast = 99 and slow = 100 gives a -1% spread. If the next pair is 101 and 100, the spread is +1% and an upward cross has occurred. This is arithmetic, not a Bitcoin price observation.
  • On the same symbol at 1 hour, compare each day's stepped values with the prior completed day in the daily example. The first intraday bar after a daily cross carries the marker only when it closes.
  • Reload after a daily boundary and compare the recorded values. Also inspect a still-open daily bar to distinguish the developing daily lines from the completed intraday lines.
  • Create the alert explicitly; past markers do not send historical notifications. After changing script inputs, symbol, or timeframe, recreate the alert to update its saved configuration.
Where Pineify fits

Pine Script AI Coding Agent

Use Pineify to draft or revise an inspectable cycle indicator with a specified daily source and alert rule. Review syntax diagnostics, then verify the values and timing in TradingView. Generated code does not establish predictive performance.

Customize the Pine Script

Frequently asked questions

Educational programming examples, not investment advice. Historical associations do not guarantee future outcomes. No predictive accuracy, return, or profitable trading strategy is claimed.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.