DocsStrategy APIindicators

PPO (Percent Price Oscillator)

The PPO measures momentum as the percentage difference between two moving averages. In Quanthop, PPO uses Laguerre filters for smoother, less noisy signals.

Declaration

function init(ctx) { // Standard PPO ctx.indicator('ppo', 'PPO', { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 }); // Laguerre-based PPO (smoother, used in TDR) ctx.indicator('ppoRisk', 'PPO', { shortGamma: 0.4, longGamma: 0.8, accuracy: 10, source: 'close' }); }

Options

Standard Mode

OptionTypeDefaultDescription
fastPeriodnumber12Fast EMA period
slowPeriodnumber26Slow EMA period
signalPeriodnumber9Signal line period
sourcestring'close'Price source

Laguerre Mode

OptionTypeDefaultDescription
shortGammanumber0.4Fast Laguerre filter gamma (0-1)
longGammanumber0.8Slow Laguerre filter gamma (0-1)
accuracynumber10Calculation precision (higher = more bars)
sourcestring'close'Price source

Output

Returns a single series of values (typically -100 to +100 range):

function onBar(ctx, i) { const ppoValue = ctx.ind.ppo[i]; // Value interpretation: // Positive: Price above its average (bullish momentum) // Negative: Price below its average (bearish momentum) // Extreme values: Overbought/oversold conditions }

Use Cases

Risk Zone Detection

Define risk zones for position management:

function define(ctx) { ctx.param('lowRiskThreshold', { type: 'int', default: -85, min: -100, max: -50 }); ctx.param('highRiskThreshold', { type: 'int', default: 85, min: 50, max: 100 }); } function onBar(ctx, i) { const ppo = ctx.ind.ppo[i]; if (ppo < ctx.p.lowRiskThreshold) { // LOW RISK ZONE: Good for entries // Market is oversold, potential reversal } else if (ppo > ctx.p.highRiskThreshold) { // HIGH RISK ZONE: Consider taking profits // Market is overbought, extended move } else { // NEUTRAL ZONE: Normal market conditions } }

Zone Duration Trading

Track how long the market stays in a risk zone:

function init(ctx) { ctx.indicator('ppo', 'PPO', { shortGamma: 0.4, longGamma: 0.8, accuracy: 10 }); ctx.state.lowRiskBars = 0; ctx.state.avgLowRiskLength = 0; ctx.state.lowRiskZoneCount = 0; } function onBar(ctx, i) { const ppo = ctx.ind.ppo[i]; const inLowRisk = ppo < -85; if (inLowRisk) { ctx.state.lowRiskBars++; // Entry signal: in zone for average duration if (ctx.state.lowRiskBars === Math.round(ctx.state.avgLowRiskLength)) { ctx.order.market('ASSET', 0.1, { signal: 'lowRiskEntry' }); } } else if (ctx.state.lowRiskBars > 0) { // Zone ended - update average ctx.state.lowRiskZoneCount++; ctx.state.avgLowRiskLength = ( ctx.state.avgLowRiskLength * (ctx.state.lowRiskZoneCount - 1) + ctx.state.lowRiskBars ) / ctx.state.lowRiskZoneCount; ctx.state.lowRiskBars = 0; } }

Momentum Confirmation

Use PPO to confirm trend signals:

function onBar(ctx, i) { const ema = ctx.ind.ema; const baseline = ctx.ind.baseline_middle; const ppo = ctx.ind.ppo[i]; // Only enter long if PPO not in high-risk zone if (q.crossOver(ema, baseline, i) && ppo < 70) { ctx.order.market('ASSET', 1, { signal: 'buy' }); } }

Value Ranges

RangeInterpretation
< -85Strongly oversold (low risk for longs)
-85 to -50Moderately oversold
-50 to 0Weak bearish momentum
0 to 50Weak bullish momentum
50 to 85Moderately overbought
> 85Strongly overbought (high risk for longs)

Related

indicatorppomomentumoscillatorrisklaguerreqsl