TradingView strategy research

Time-series momentum: own-history signals and scaling

Time series momentum uses an asset's own past return to choose its direction. A positive signal can request a long position and a negative signal a short position, independently of how other assets performed. Position size is a separate decision: this example scales exposure inversely with estimated volatility and rebalances monthly. A neutral band, exposure cap and explicit order timing make the rule testable on one TradingView chart.

See the decision guide

What the original research establishes

Moskowitz, Ooi and Pedersen's 2012 paper studies own-return predictability in futures and forwards. Its featured strategy uses the sign of the past 12-month excess return and inverse-volatility sizing. Cross-sectional momentum instead compares returns across securities. These definitions do not make a positive return signal a guarantee of continuation.

  • The script below is a teaching variant: 252 daily bars of chart price return, a symmetric neutral band, a rolling sample volatility estimate and a capped allocation. It does not reproduce the paper's excess-return data, volatility estimator or diversified portfolio.
  • Suppose three assets return -2%, -5% and -9%. The first ranks highest, but all three have negative own-history signals under a zero threshold. A long-short time-series rule can be short all three; it need not balance long and short exposure.
  • Price return, dividend-inclusive total return and excess return over cash are different inputs. Record the feed and adjustment settings. The example uses chart prices without a separate dividend or cash-interest ledger.

A complete monthly rule for one stock or ETF

Use standard one-day candles for a stock or unleveraged ETF with one price point worth one unit of quote currency per share. The strategy account uses that quote currency. Let R(t) = close(t) / close(t - L) - 1, with L = 252 daily bars. This is approximately a trading year, not an exact calendar-year return. All percentages below enter the formulas as decimals.

  • A neutral band requests flat; it is not hysteresis that preserves the previous direction. The signal may change during the month without changing the position before the next scheduled decision.
  • Sizing uses the decision close and equity before the fill. Overnight gaps, commissions and subsequent price changes make executed exposure differ from the target. The cap is checked at sizing time, not continuously.
  • There is no protective stop or profit target. Monthly timing can leave a stale long through a sharp decline or a stale short through a rebound. Short availability and borrow costs require separate research.
DecisionBaseline rule
DirectionWith b = 0.01, set s = +1 when R > b; s = -1 when R < -b; otherwise s = 0. Both boundaries belong to the flat band.
VolatilityUse the last 60 daily log returns x = ln(close / previous close). Estimate sigma = sample standard deviation(x) × sqrt(252), with denominator 59. Require 60 consecutive valid returns.
Exposurew = s × min(0.50, 0.10 / max(sigma, 0.02)). The 10% target, 2% volatility floor and 50% notional cap are illustrative settings.
Decision timeAt the close of the first available daily bar in each new exchange-calendar month, after warm-up. The first dataset bar is excluded. Wait for the next monthly decision if warm-up finishes midmonth.
Quantityq* = sign(w) × floor(abs(w) × current equity / current close). Trade delta q = q* - existing shares. Round toward zero to whole shares.
Fill and holdingSubmit a market order after the decision close; with the declared settings it normally fills at the next bar open. Hold share count between decisions, so weight can drift.
Invalid dataOn any confirmed bar, request flat if the price history, volatility or equity is invalid. Zero estimated volatility also requests flat. A missing market bar cannot supply an executable exit.

Pine v6 strategy with target-share rebalancing

The code trades only the chart symbol. It uses strategy.order with the signed share difference, because this order changes the existing position by its quantity instead of automatically adding a reversal quantity. Keep standard candles, 1D, next-bar fills and the stated calculation settings. The interval guard does not detect synthetic chart construction.

  • The example uses 0.10% commission on transacted notional and two adverse ticks per fill. These are assumptions, not broker quotes. Replace them with suitable cost scenarios in Strategy Properties.
  • The script starts flat and waits for sufficient history and a monthly decision. It does not liquidate at the end of the dataset. Report open equity and closed trades separately.
  • For an untouched-date experiment, add an explicit evaluation start and end policy while retaining earlier history for warm-up. Confirm that the strategy begins flat at that boundary and that any final liquidation occurs on an available later bar.
A single-symbol Pine Script v6 research strategy. The daily target plot is indicative; only monthly decisions create normal rebalance orders. Syntax validation is not a performance test.pine
//@version=6
strategy("Own-history momentum with monthly sizing", overlay = false,
     initial_capital = 100000, margin_long = 100, margin_short = 100,
     commission_type = strategy.commission.percent, commission_value = 0.10,
     slippage = 2, calc_on_every_tick = false,
     calc_on_order_fills = false, process_orders_on_close = false)

int lookback = input.int(252, "Return lookback (daily bars)", minval = 1, maxval = 2000)
int volLength = input.int(60, "Volatility window", minval = 2, maxval = 2000)
float band = input.float(1.0, "Neutral band (%)", minval = 0.0) / 100.0
float volTarget = input.float(10.0, "Annual volatility target (%)", minval = 0.1) / 100.0
float volFloor = input.float(2.0, "Annual volatility floor (%)", minval = 0.1) / 100.0
float exposureCap = input.float(50.0, "Exposure cap (%)", minval = 1.0, maxval = 90.0) / 100.0
if not timeframe.isdaily or timeframe.multiplier != 1
    runtime.error("Use a standard one-day stock or ETF chart.")
if syminfo.pointvalue != 1
    runtime.error("This example requires a point value of one per share.")

bool validPrice = not na(close) and close > 0
bool validReturn = validPrice and not na(close[1]) and close[1] > 0
float logReturn = validReturn ? math.log(close / close[1]) : na
var int validRun = 0
validRun := validReturn ? validRun + 1 : 0
float sigma = ta.stdev(logReturn, volLength, false) * math.sqrt(252.0)
bool ready = validRun >= math.max(lookback, volLength) and not na(sigma) and sigma > 0 and strategy.equity > 0
float momentum = ready ? close / close[lookback] - 1.0 : na
int direction = ready ? (momentum > band ? 1 : momentum < -band ? -1 : 0) : 0
float weight = ready ? direction * math.min(exposureCap, volTarget / math.max(sigma, volFloor)) : 0.0
bool rebalance = timeframe.change("1M") and bar_index > 0

if barstate.isconfirmed
    if not ready
        if strategy.position_size != 0
            strategy.close_all(comment = "Invalid measurement")
    else if rebalance
        float targetShares = math.sign(weight) * math.floor(math.abs(weight) * strategy.equity / close)
        float deltaShares = targetShares - strategy.position_size
        if deltaShares > 0
            strategy.order("Rebalance buy", strategy.long, qty = deltaShares)
        else if deltaShares < 0
            strategy.order("Rebalance sell", strategy.short, qty = -deltaShares)

plot(momentum * 100.0, "Own-history return (%)", color = color.blue)
plot(weight * 100.0, "Indicative target weight (%)", display = display.data_window)
plot(sigma * 100.0, "Estimated annual volatility (%)", display = display.data_window)
hline(0, "Zero", color = color.gray)

Recompute a signal, volatility and order from raw inputs

This invented snapshot demonstrates arithmetic, not market performance. Set the current close to 100, its close 252 bars earlier to 90, and current equity to 100,000 in the same currency. Assume the final 60 daily log returns alternate +0.01 and -0.01, with 30 of each. They sum to zero, so this 60-day block starts and ends at 100; the earlier path from 90 to 100 is outside that block.

  • If the next open is 104 instead, the same order fills at 104.02 under the assumption. The 500 shares now represent 52,010 of notional before fees. Sizing at the previous close cannot guarantee a 50% fill-time weight.
  • At a separate rebalance snapshot with equity 100,000, close 100, a positive signal and sigma = 40%, weight is 25% and target is 250 shares. From an existing 500 shares, sell 250 even though the direction has not changed.
  • With positive sigma = 1%, the floor substitutes 2%, then the cap limits the result to 50%. With sigma exactly zero, the script requests flat rather than treating a constant-price history as a low-risk opportunity.
CalculationResult
Own-history return100 / 90 - 1 = 0.111111, or +11.1111%; above +1%, so s = +1.
Mean and squared deviationsMean = 0. Sum of squared deviations = 60 × 0.01² = 0.006.
Sample annual volatilitysqrt(0.006 / 59) × sqrt(252) = 0.16008472, or 16.0085%.
Uncapped weight and cap0.10 / 0.16008472 = 0.62466922. min(0.50, 0.62466922) = +0.50.
Target shares and initial orderfloor(0.50 × 100,000 / 100) = 500. From flat, buy 500 shares after the decision close.
Next-open fill assumptionWith next open 100 and tick size 0.01, two-tick slippage gives a buy fill of 100.02. Notional = 50,010; commission = 50.01.

A reversal pays for both sides of the position change

For another independent snapshot, keep equity 100,000 and close 100, but use a reference close of 110 and sigma = 40%. R = 100 / 110 - 1 = -9.0909%, so w = -25% and q* = -250. If the account holds +500 shares, delta q = -250 - 500 = -750: sell 750 shares, closing 500 and opening 250 short.

  • Charging only the new 250-share short would omit the cost of closing the 500-share long. Slippage is already embedded in the fill price; do not deduct the 15 again from Strategy Tester P&L.
  • This cost calculation does not provide the prior long's realized P&L, which also needs its entry price. It excludes borrowing, financing, dividends owed on shorts, market impact and taxes.
  • If R enters the neutral band at a scheduled decision, target shares become zero. Liquidating still incurs costs. If rounding produces zero target shares, do not round up to manufacture a trade.
Reversal cost assumptionCalculation
Next open and sell fillOpen 100, tick 0.01, two adverse ticks: fill 99.98.
Traded notional750 × 99.98 = 74,985; turnover at the reference price is 75,000 / 100,000 = 75%.
Commission74,985 × 0.001 = 74.985.
Slippage against the 100 reference750 × 0.02 = 15.00.
Immediate execution drag74.985 + 15 = 89.985, or about 0.089985% of the snapshot equity.

Where this rule can fail

Inverse-volatility sizing reacts to an estimate of past variation. It cannot impose a realized volatility ceiling. A low-volatility period can end with a gap; the next scheduled resize arrives after that loss. A cap reduces exposure at the decision but does not remove short-side, gap or liquidity risk.

  • Near the thresholds, monthly observations can alternate long, flat and short. A wider band may reduce turnover but also delays entry; measure net results instead of assuming the tradeoff is favorable.
  • The rolling reference price moves too. R can change sign because an old observation leaves the window, even with little change in the current price. Inspect both endpoints of every reversal.
  • The 252 annualization factor is a convention for this daily stock example. It is inappropriate to transfer it unchanged to intraday bars or a seven-day trading calendar.
  • Stock splits, inconsistent dividend adjustments, stale prices and missing observations can distort both the signal and volatility. The script guards invalid observations present in the feed; it cannot detect an exchange session omitted entirely by the data vendor.
  • A stock short can lose more than its initial notional. Borrow can be unavailable or recalled. The emulator's margin settings do not establish real borrow availability or broker liquidation terms.
  • For futures or a multi-asset portfolio, add dated contracts, roll accounting, point values, currency conversion, capital allocation and correlated risk outside this share-based example. Requests for other symbols do not create independently traded positions in those symbols.

Compare the rule without selecting a lucky parameter

Save the symbol, session, adjustments, dates, starting equity, costs and every tested input. First audit several monthly orders by hand, including an unchanged-direction resize and a reversal. Then compare a small declared set of lookbacks and thresholds while keeping the sizing and execution policy fixed.

  • Compare the scaled strategy with the same directional signal at fixed notional exposure. Differences can come from sizing rather than the momentum signal itself; report time invested, turnover, drawdown and net return together.
  • Use separate later dates after freezing the parameter choice. Retain unprofitable combinations and stress commission, slippage and delayed fills. The best historical row is a selection result, not evidence of future performance.
  • Pine Script AI Coding Agent can help modify the explicit rule and add test-date inputs. Inspect its source and validate syntax. Strategy Optimizer can compare exposed input combinations in TradingView reports; it does not establish a diversified portfolio result or automatically make the research independent.
Where Pineify fits

Pine Script AI Coding Agent

Turn a specified own-history signal, neutral band and rebalance policy into reviewable Pine code. Check the generated timing, quantities and cost settings before interpreting a backtest.

Also useful: Strategy Optimizer. Compare a preselected range of Pine input values on the same TradingView dataset. Keep later evaluation dates separate and retain the full set of trials.

Build the time-series rule

Frequently asked questions

Educational research, not investment advice. All numerical snapshots and costs are hypothetical. No performance backtest is claimed. Momentum, volatility scaling and parameter selection can lose money; short positions can lose more than their initial notional.

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.