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.
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)