67 lines
No EOL
2.9 KiB
Text
67 lines
No EOL
2.9 KiB
Text
//@version=5
|
|
strategy("Pinbar Basic Strategy (1:1 RR)", overlay=true, initial_capital=10000, calc_on_every_tick=false, pyramiding=0)
|
|
|
|
// ===== 参数 =====
|
|
pinbarBodyRatio = input.float(0.30, "PinbarBodyRatio", minval=0, maxval=1.0)
|
|
pinbarShadowRatio = input.float(0.60, "PinbarShadowRatio", minval=0, maxval=1.0)
|
|
minPinbarLengthPts = input.int(10, "MinPinbarLength(Points)", minval=0)
|
|
qty = input.float(1.0, "Order Qty", minval=0.0, step=0.1)
|
|
minVolume = input.float(500, "Min Volume to Trade", minval=0)
|
|
|
|
// ===== 识别上一根K线 Pinbar =====
|
|
o1 = open[1]
|
|
h1 = high[1]
|
|
l1 = low[1]
|
|
c1 = close[1]
|
|
|
|
totalLen = h1 - l1
|
|
bodySize = math.abs(c1 - o1)
|
|
isBearish = o1 > c1
|
|
upperShadow = isBearish ? (h1 - o1) : (h1 - c1)
|
|
lowerShadow = isBearish ? (c1 - l1) : (o1 - l1)
|
|
|
|
// 最小长度:点数 * 最小跳动
|
|
minLen = minPinbarLengthPts * syminfo.mintick
|
|
|
|
validLen = totalLen > 0 and totalLen >= minLen
|
|
bodyOk = validLen and (bodySize / totalLen) <= pinbarBodyRatio
|
|
shadowOk = validLen and (math.max(upperShadow, lowerShadow) / totalLen) >= pinbarShadowRatio
|
|
|
|
isBullPinbar1 = shadowOk and bodyOk and (lowerShadow > upperShadow)
|
|
isBearPinbar1 = shadowOk and bodyOk and (upperShadow > lowerShadow)
|
|
isPinbar1 = validLen and bodyOk and shadowOk and (lowerShadow != upperShadow)
|
|
|
|
// ===== 标注(偏移到上一根K线位置) =====
|
|
plotshape(isBullPinbar1, title="Bull Pinbar", style=shape.triangleup, color=color.new(color.lime, 0), size=size.tiny, location=location.belowbar, offset=1, text="BP")
|
|
plotshape(isBearPinbar1, title="Bear Pinbar", style=shape.triangledown, color=color.new(color.red, 0), size=size.tiny, location=location.abovebar, offset=1, text="SP")
|
|
|
|
// ===== 只在新出现的上一根 Pinbar 时触发一次(兼容历史与实时) =====
|
|
var int lastPinbarTime = na
|
|
newSignal = isPinbar1 and (na(lastPinbarTime) or lastPinbarTime != time[1])
|
|
volOk = volume > minVolume
|
|
|
|
longSignal = newSignal and isBullPinbar1 and volOk
|
|
shortSignal = newSignal and isBearPinbar1 and volOk
|
|
|
|
// ===== 1:1 RR 止损/止盈 =====
|
|
// 入场使用当前K线的开盘/市价(由策略托管),SL 基于上一根 Pinbar 极点,TP 与入场到 SL 的距离相等
|
|
if longSignal
|
|
// 多:SL = pinbar低点
|
|
longSL = l1
|
|
// 预估入场价:用当前bar开盘价(更接近实际回测表现)
|
|
entryPriceLong = open
|
|
riskLong = math.max(entryPriceLong - longSL, syminfo.mintick)
|
|
longTP = entryPriceLong + riskLong
|
|
strategy.entry("Long", strategy.long, qty=qty)
|
|
strategy.exit("Long-Exit", "Long", stop=longSL, limit=longTP)
|
|
lastPinbarTime := time[1]
|
|
|
|
if shortSignal
|
|
// 空:SL = pinbar高点
|
|
shortSL = h1
|
|
entryPriceShort = open
|
|
riskShort = math.max(shortSL - entryPriceShort, syminfo.mintick)
|
|
shortTP = entryPriceShort - riskShort
|
|
strategy.entry("Short", strategy.short, qty=qty)
|
|
strategy.exit("Short-Exit", "Short", stop=shortSL, limit=shortTP)
|
|
lastPinbarTime := time[1] |