TradingView indicators

Absolute Price Oscillator on TradingView

The Absolute Price Oscillator (APO) is the fast moving average minus the slow moving average, expressed in price units. It shows the gap between averages, not a percentage return. Specify EMA or SMA before comparing readings.

APO = fast MA − slow MA

Fast MA 102, slow MA 100: APO is +2 price units. The corresponding PPO is +2%.

Illustrative inputs, not market data. The worked example below checks the calculation from prices.

Why price scale changes APO but not PPO

Use four invented closing prices: 96, 100, 102, 106. Choose SMA with a fast length of 2 and slow length of 4 so every input is visible. At the fourth bar, the fast SMA is (102 + 106) / 2 = 104; the slow SMA is (96 + 100 + 102 + 106) / 4 = 101.

Synthetic price scaling test. Both rows use SMA(2, 4).
Input closesFast SMASlow SMAAPOPPO
96, 100, 102, 10610410132.9703%
960, 1000, 1020, 106010401010302.9703%

The first APO is 104 − 101 = 3; PPO is 100 × 3 / 101 = 2.9703%. Multiplying every price by 10 multiplies both SMAs and their difference by 10. In PPO, the factor cancels: 100 × 30 / 1010 gives the same percentage. The same scaling property holds for EMA when its history and initial values are scaled consistently.

A fixed APO threshold of 5 would reject the first row and accept the scaled row, despite their identical proportional path. That is why a raw APO threshold needs a price-scale assumption. PPO normalizes that gap but does not measure risk or prove that two markets are equally tradable.

Formula reference: TradingView PPO documentation. The sample prices and arithmetic are original demonstrations.

Choose the calculation before interpreting the line

EMA or SMA
The code offers both types and applies the selected type to both legs. Its initial settings are EMA, close, 12 and 26. The numerical table deliberately uses SMA(2, 4) for hand calculation; changing the type changes the output. TA-Lib documents the general MA difference.
Fast length must be below slow length
The example rejects equal or reversed lengths instead of silently swapping them. Equal lengths with identical source and type produce zero once values are available. The lengths count chart bars: 12 bars on a daily chart and 12 bars on a 15-minute chart cover different time spans.
Zero is an equality test
At zero, the two averages are equal. Moving from a negative value to a positive value means the fast average crossed above the slow one. Rising from −3 to −1 still leaves it below. Neither case alone defines a profitable entry, and repeated crossings can occur when the averages stay close.
PPO needs a usable denominator
The script returns an unavailable PPO value when the slow average is zero. Near zero, small denominator changes can create large percentages. With a negative slow average, PPO's sign need not match APO's sign; do not carry positive-price interpretations into synthetic spreads without checking them.

Pine Script v6: configurable APO and closed-bar alerts

Paste the complete script into TradingView's Pine Editor and add it to the chart. APO appears in a separate pane. Fast MA, slow MA and PPO are available in the Data Window for arithmetic checks; PPO is not plotted on the price-unit axis.

Pine Script v6

//@version=6
indicator("APO: EMA or SMA", shorttitle="APO", overlay=false)
source = input.source(close, "Source")
fastLength = input.int(12, "Fast length", minval=1)
slowLength = input.int(26, "Slow length", minval=2)
maType = input.string("EMA", "MA type", options=["EMA", "SMA"])
if fastLength >= slowLength
    runtime.error("Fast length must be smaller than slow length.")
fastEMA = ta.ema(source, fastLength)
slowEMA = ta.ema(source, slowLength)
fastSMA = ta.sma(source, fastLength)
slowSMA = ta.sma(source, slowLength)
fastMA = maType == "EMA" ? fastEMA : fastSMA
slowMA = maType == "EMA" ? slowEMA : slowSMA
apo = fastMA - slowMA
ppo = slowMA != 0 ? 100 * apo / slowMA : na
crossUp = ta.crossover(apo, 0)
crossDown = ta.crossunder(apo, 0)
confirmedUp = crossUp and barstate.isconfirmed
confirmedDown = crossDown and barstate.isconfirmed
plot(apo, "APO (price units)", color=color.blue, linewidth=2)
hline(0, "Zero", color=color.gray)
plot(fastMA, "Fast MA", display=display.data_window)
plot(slowMA, "Slow MA", display=display.data_window)
plot(ppo, "PPO (%)", display=display.data_window)
plotshape(confirmedUp, title="Confirmed cross up", style=shape.triangleup, location=location.bottom, color=color.green, size=size.tiny)
plotshape(confirmedDown, title="Confirmed cross down", style=shape.triangledown, location=location.top, color=color.red, size=size.tiny)
alertcondition(confirmedUp, "APO above zero at close", "APO crossed above zero on a confirmed chart bar.")
alertcondition(confirmedDown, "APO below zero at close", "APO crossed below zero on a confirmed chart bar.")

The line updates during the open bar. Triangle markers and alert conditions wait for the chart bar to close through barstate.isconfirmed. A temporary intrabar crossing that disappears before close produces no confirmed marker. This script uses the chart timeframe and makes no higher-timeframe requests.

Create an alert from one of the script's two named conditions in TradingView, using Once Per Bar Close. Declaring alertcondition does not create an active alert. Recreate alerts after changing the script or inputs so their saved configuration matches the chart.

Check values before turning APO into a strategy

  1. Record the symbol, chart type, session, timeframe, source, MA type and lengths. Use the same inputs for any reference calculation, including adjusted versus unadjusted prices.
  2. On several closed bars, subtract the Data Window's slow MA from its fast MA. Compare the result with APO and account for displayed rounding. Early SMA bars can be unavailable; EMA comparisons also depend on the available initialization history.
  3. At a confirmed up marker, check that current APO is greater than zero and the preceding value was at or below zero. Confirm both bars have valid values before comparing a marker with another implementation.
  4. For a relative comparison, calculate 100 × APO / slow MA and compare with the Data Window's PPO. Keep these percentage values separate from the APO pane scale.
  5. Define entries, exits, position sizing, commission and slippage separately. The indicator contains no strategy orders or backtest results.

Use Pineify to make the rules explicit

Ask the Pine Script AI Coding Agent to adapt the inputs or confirmation rules, then repeat the bar-by-bar checks. A useful request specifies the MA type, source, fast/slow lengths, zero-cross definition and whether alerts wait for close.

Use an EMA APO on close with lengths 12 and 26. Keep fast length below slow length. Mark zero crossings only on confirmed chart bars and expose both averages in the Data Window. Keep trade exits and costs separate.
Open Pine Script AI Coding Agent

APO questions

No. Absolute refers to price units rather than a percentage. A fast average of 98 and a slow average of 100 give APO = -2. Applying an absolute-value function would remove direction and change the indicator.

An APO implementation can use either. This example defaults to EMA with lengths 12 and 26, and offers SMA as an input. Match the moving average type, source, lengths, chart data and calculation history before comparing two implementations.

An EMA-based APO uses the same fast EMA minus slow EMA formula as the MACD line with matching inputs. It is not the MACD histogram, which subtracts a signal average from the MACD line. Choosing SMA changes the comparison.

Raw APO values carry each instrument's price units. A larger number alone does not establish stronger percentage momentum. PPO divides the same gap by the slow average; use matching settings and check the denominator before making relative comparisons.

No. The example marks a crossing only when its chart bar closes and exposes alert conditions. It does not submit orders. A strategy still needs separate entry, exit, sizing and cost assumptions, followed by backtesting.

APO subtracts two moving averages. ROC compares a current price with a price a chosen number of bars ago, as a percentage. They can disagree because they measure different relationships.

Sources and related calculations

Official references checked October 17, 2026.

Continue with PPO for the normalized difference, MACD for signal-line and histogram calculations, or return to TradingView indicators.