Посмотреть исходный код
//@version=6
strategy("PRISM Volume Context · RESEARCH TESTER", overlay=true, max_labels_count=100,
initial_capital=50, currency=currency.USD, default_qty_type=strategy.percent_of_equity,
default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.05,
slippage=2, pyramiding=0, process_orders_on_close=false, calc_on_every_tick=false,
margin_long=100, margin_short=100)
// Research artifact. Profitability is NOT validated. No OKX order connection.
// Signal calculations target the five-minute OHLCV chart. Closed bars only.
string mode = input.string("Hybrid", "Research mechanism", options=["Climax", "Reclaim", "Hybrid"])
bool showSignals = input.bool(false, "Show experimental entry plans", tooltip="Historical screening failed. These are research plans, not trade recommendations.")
float costFraction = input.float(0.19, "Round-trip cost reserve %", minval=0, step=0.01) / 100
if timeframe.in_seconds() != 300
runtime.error("PRISM Volume Context requires a 5-minute chart. The research rules are not calibrated for other timeframes.")
float atr = ta.atr(14)
float volumeSum = math.sum(volume, 24)
float weighted = volumeSum > 0 ? math.sum(hlc3 * volume, 24) / volumeSum : na
float priorVolume = ta.sma(volume[1], 20)
float relativeVolume = priorVolume > 0 ? volume / priorVolume : na
float variation = math.sum(math.abs(ta.change(close)), 48)
float efficiency = variation > 0 ? math.abs(close - close[48]) / variation : 0
float weightedSlope = atr > 0 ? (weighted - weighted[6]) / atr : na
float priorHigh12 = ta.highest(high[1], 12)
float priorLow12 = ta.lowest(low[1], 12)
float priorHigh3 = ta.highest(high[1], 3)
float priorLow3 = ta.lowest(low[1], 3)
float low6 = ta.lowest(low, 6)
float high6 = ta.highest(high, 6)
f_setup(int side, bool climax) =>
float wick = side == 1 ? math.min(open, close) - low : high - math.max(open, close)
bool sweep = side == 1 ? low < priorLow12 and close > priorLow12 : high > priorHigh12 and close < priorHigh12
bool rejected = relativeVolume >= 2 and high - low >= 1.5 * atr and wick >= 0.45 * (high - low) and efficiency <= 0.35 and math.abs(weightedSlope) <= 0.8 and sweep
float boundary = side == 1 ? priorHigh3 : priorLow3
bool reclaimed = relativeVolume >= 1.5 and side * (close[1] - weighted[1]) <= 0 and side * (close - weighted) > 0 and side * weightedSlope >= 0.1 and efficiency >= 0.2 and side * (close - boundary) > 0 and high - low <= 2.5 * atr
float stop = climax ? (side == 1 ? low - 0.2 * atr : high + 0.2 * atr) : (side == 1 ? low6 - 0.15 * atr : high6 + 0.15 * atr)
float target = climax ? weighted : close + 2 * (close - stop)
float risk = side * (close - stop)
float reward = side * (target - close)
float cost = close * costFraction
bool geometry = risk >= 0.75 * atr and risk <= 3 * atr and target > 0 and (reward - cost) / (risk + cost) >= 1.2
bool valid = bar_index >= 60 and barstate.isconfirmed and not na(weightedSlope) and not na(relativeVolume) and geometry and (climax ? rejected : reclaimed)
[valid, stop, target]
[cl, cls, clt] = f_setup(1, true)
[cs, css, cst] = f_setup(-1, true)
[rl, rls, rlt] = f_setup(1, false)
[rs, rss, rst] = f_setup(-1, false)
bool longClimax = mode != "Reclaim" and cl
bool shortClimax = mode != "Reclaim" and cs
bool longReclaim = mode != "Climax" and rl
bool shortReclaim = mode != "Climax" and rs
// Fixed tie order matches Python: climax before reclaim, long before short.
int direction = longClimax ? 1 : shortClimax ? -1 : longReclaim ? 1 : shortReclaim ? -1 : 0
float stopPlan = longClimax ? cls : shortClimax ? css : longReclaim ? rls : shortReclaim ? rss : na
float targetPlan = longClimax ? clt : shortClimax ? cst : longReclaim ? rlt : shortReclaim ? rst : na
bool signalLong = showSignals and direction == 1
bool signalShort = showSignals and direction == -1
color accent = #5DD9BD
plot(weighted, "Rolling volume-weighted typical price (24)", color=accent, linewidth=2)
upper = plot(weighted + 1.5 * atr, "Upper volatility band", color=color.new(accent, 65))
lower = plot(weighted - 1.5 * atr, "Lower volatility band", color=color.new(accent, 65))
fill(upper, lower, color=color.new(accent, 95))
plot(efficiency, "Efficiency48", display=display.data_window)
plot(relativeVolume, "Relative volume20", display=display.data_window)
plot(weightedSlope, "Weighted-price slope / ATR", display=display.data_window)
plotshape(signalLong, title="Research long", text="PLAN L", style=shape.triangleup, location=location.belowbar, color=#5DD9BD, textcolor=#5DD9BD, size=size.small)
plotshape(signalShort, title="Research short", text="PLAN S", style=shape.triangledown, location=location.abovebar, color=#F28BA8, textcolor=#F28BA8, size=size.small)
var float shownStop = na
var float shownTarget = na
var int planBar = na
if signalLong or signalShort
shownStop := stopPlan
shownTarget := targetPlan
planBar := bar_index
bool recentPlan = showSignals and not na(planBar) and bar_index - planBar < 24
plot(recentPlan ? shownStop : na, "Latest plan stop — not an execution", color=#F28BA8, style=plot.style_linebr)
plot(recentPlan ? shownTarget : na, "Latest plan full target — not an execution", color=accent, style=plot.style_linebr)
var table panel = table.new(position.top_right, 2, 5, bgcolor=#101722, border_width=1)
if barstate.islast
table.cell(panel, 0, 0, "PRISM · RESEARCH", text_color=accent)
table.cell(panel, 1, 0, "NOT VALIDATED", text_color=#F28BA8)
table.cell(panel, 0, 1, "Efficiency", text_color=color.white)
table.cell(panel, 1, 1, str.tostring(efficiency, "#.00"), text_color=color.white)
table.cell(panel, 0, 2, "Relative volume", text_color=color.white)
table.cell(panel, 1, 2, str.tostring(relativeVolume, "#.00") + "x", text_color=color.white)
table.cell(panel, 0, 3, "Cost reserve", text_color=color.white)
table.cell(panel, 1, 3, str.tostring(costFraction * 100, "#.00") + "%", text_color=color.white)
table.cell(panel, 0, 4, "Mechanism", text_color=color.white)
table.cell(panel, 1, 4, mode, text_color=color.white)
// TradingView's emulator differs from the Python research simulator:
// 2 ticks slippage, no funding, no cross-symbol portfolio, no historical depth.
// Contract quantity/margin properties must be inspected for the chosen symbol.
// No independent Pine compiler/execution parity verification was performed.
var float fixedStop = na
var float fixedTarget = na
bool freshFlat = strategy.position_size == 0 and (strategy.closedtrades == 0 or bar_index > strategy.closedtrades.exit_bar_index(strategy.closedtrades - 1))
if showSignals and direction != 0 and freshFlat
fixedStop := stopPlan
fixedTarget := targetPlan
if direction == 1
strategy.entry("LONG", strategy.long)
strategy.exit("LONG-EXIT", "LONG", stop=fixedStop, limit=fixedTarget)
else
strategy.entry("SHORT", strategy.short)
strategy.exit("SHORT-EXIT", "SHORT", stop=fixedStop, limit=fixedTarget)
if strategy.position_size != 0
int held = bar_index - strategy.opentrades.entry_bar_index(0)
if held >= 23
strategy.close_all(comment="Two-hour timeout", immediately=true)