//@version=6
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 PineForge
// PineForge Owned Strategy: Loopback Method For
// A typed history method is called repeatedly across several return horizons.
strategy("PineForge — Loopback Method For", overlay=true,
initial_capital=100000,
default_qty_type=strategy.fixed, default_qty_value=2,
pyramiding=0, commission_type=strategy.commission.percent,
commission_value=0.05, slippage=1,
margin_long=100, margin_short=100,
process_orders_on_close=false, calc_on_order_fills=false)
type HorizonLedger
float value
method directionAgainst(HorizonLedger self, float referenceValue) =>
self.value > referenceValue ? 1.0 : -1.0
horizonCount = input.int(5, "Horizon Count", minval=2, maxval=8, group="Horizons")
horizonSpacing = input.int(4, "Horizon Spacing", minval=1, maxval=12, group="Horizons")
minimumVote = input.float(0.55, "Minimum Average Vote", minval=-1, maxval=1, step=0.05, group="Horizons")
trendLength = input.int(51, "Trend EMA Length", minval=5, group="Trend")
atrLength = input.int(15, "ATR Length", minval=2, group="Risk")
maximumAtrLoss = input.float(2.4, "Maximum ATR Loss", minval=0.5, step=0.1, group="Risk")
HorizonLedger ledger = HorizonLedger.new(close)
float voteSum = 0.0
for horizon = 1 to horizonCount
historicalValue = close[horizon * horizonSpacing]
voteSum += na(historicalValue) ? 0.0 : ledger.directionAgainst(historicalValue)
averageVote = voteSum / horizonCount
trendLine = ta.ema(close, trendLength)
atrValue = ta.atr(atrLength)
enterLong = ta.crossover(averageVote, minimumVote) and close > trendLine
voteEnded = averageVote < 0 or close < trendLine
riskExceeded = strategy.position_size > 0 and close < strategy.position_avg_price - atrValue * maximumAtrLoss
if strategy.position_size == 0 and enterLong
strategy.entry("Loopback Long", strategy.long)
else if strategy.position_size > 0 and (voteEnded or riskExceeded)
strategy.close("Loopback Long", comment=riskExceeded ? "ATR risk" : "Vote ended")
plot(trendLine, "Trend EMA", color=color.orange)
plot(averageVote, "Average Horizon Vote", color=color.blue, display=display.data_window)