圣杯指标


创建日期: 2026-03-18 02:54:53 最后修改: 2026-03-18 14:18:34
复制: 5 点击次数: 123
avatar of 玄雷策略库 玄雷策略库
0
关注
0
关注者
策略源码
//@version=5
strategy(title='EMA+MACD共振策略(15M) V5 - 固定风险', overlay=true, default_qty_type=strategy.cash, default_qty_value=100)

// === 输入参数 ===
emaFast = input.int(28, "EMA快线周期")
emaSlow = input.int(58, "EMA慢线周期")
macdFast = input.int(9, "MACD快线")
macdSlow = input.int(19, "MACD慢线")
macdSignal = input.int(9, "MACD信号线")
rrRatio = input.float(2.0, "盈亏比", minval=1.0)
riskPercent = input.float(10.0, "单笔风险%", minval=1.0, maxval=50.0, step=1.0, tooltip="每笔交易最大亏损占账户权益的百分比,如10%表示500账户止损50")

// === 指标计算 ===
emaF = ta.ema(close, emaFast)
emaS = ta.ema(close, emaSlow)
[dif, dea, hist] = ta.macd(close, macdFast, macdSlow, macdSignal)

// === 信号检测 ===
emaGoldenCross = ta.crossover(emaF, emaS)
emaDeadCross = ta.crossunder(emaF, emaS)
macdGoldenCross = ta.crossover(dif, dea)
macdDeadCross = ta.crossunder(dif, dea)
aboveZero = dif > 0
belowZero = dif < 0

// === 状态机 ===
var int longPhase = 0
var int shortPhase = 0

var float longStopLoss = na
var float longTakeProfit = na
var float shortStopLoss = na
var float shortTakeProfit = na
var float zoneLow = na
var float zoneHigh = na
var float longEntryPrice = na
var float shortEntryPrice = na

// === 仓位计算函数 ===
// 固定风险金额 = 账户权益 × 风险百分比
// 仓位大小 = 风险金额 / 止损点数
calcPositionSize(float entryPrice, float stopLoss) =>
    float equity = strategy.equity
    float riskAmount = equity * (riskPercent / 100)  // 固定风险金额
    float stopDistance = math.abs(entryPrice - stopLoss)  // 止损距离
    float posSize = stopDistance > 0 ? riskAmount / stopDistance : 0
    posSize

// ==================== 做多逻辑 ====================

// Phase 0→1: EMA28上穿EMA58
if longPhase == 0 and emaGoldenCross
    longPhase := 1

// Phase 1→2: DIF上零轴
if longPhase == 1 and aboveZero
    longPhase := 2

// Phase 2→3: 零轴上第一个死叉
if longPhase == 2 and macdDeadCross and aboveZero
    longPhase := 3
    zoneLow := low

// Phase 3: 等零轴上金叉入场
if longPhase == 3
    zoneLow := math.min(zoneLow, low)
    
    if macdGoldenCross and aboveZero
        float entryPrice = close
        float stopLoss = zoneLow
        float risk = entryPrice - stopLoss
        
        if risk > 0
            longStopLoss := stopLoss
            longTakeProfit := entryPrice + risk * rrRatio
            longEntryPrice := entryPrice
            // 计算仓位:固定风险 / 止损距离
            float qty = calcPositionSize(entryPrice, stopLoss)
            strategy.entry("Long", strategy.long, qty=qty)
            strategy.exit("Long Exit", "Long", stop=longStopLoss, limit=longTakeProfit)
            longPhase := 4
    
    if belowZero
        longPhase := 0

// Phase 4: 持仓,平仓后重置
if longPhase == 4 and strategy.position_size <= 0
    longPhase := 0

// 做多重置: EMA死叉时重置(除了持仓状态)
if longPhase > 0 and longPhase != 4 and emaDeadCross
    longPhase := 0

// ==================== 做空逻辑 ====================

// Phase 0→1: EMA28下穿EMA58
if shortPhase == 0 and emaDeadCross
    shortPhase := 1

// Phase 1→2: DIF下零轴
if shortPhase == 1 and belowZero
    shortPhase := 2

// Phase 2→3: 零轴下第一个金叉
if shortPhase == 2 and macdGoldenCross and belowZero
    shortPhase := 3
    zoneHigh := high

// Phase 3: 等零轴下死叉入场
if shortPhase == 3
    zoneHigh := math.max(zoneHigh, high)
    
    if macdDeadCross and belowZero
        float entryPrice = close
        float stopLoss = zoneHigh
        float risk = stopLoss - entryPrice
        
        if risk > 0
            shortStopLoss := stopLoss
            shortTakeProfit := entryPrice - risk * rrRatio
            shortEntryPrice := entryPrice
            // 计算仓位:固定风险 / 止损距离
            float qty = calcPositionSize(entryPrice, stopLoss)
            strategy.entry("Short", strategy.short, qty=qty)
            strategy.exit("Short Exit", "Short", stop=shortStopLoss, limit=shortTakeProfit)
            shortPhase := 4
    
    if aboveZero
        shortPhase := 0

// Phase 4: 持仓,平仓后重置
if shortPhase == 4 and strategy.position_size >= 0
    shortPhase := 0

// 做空重置: EMA金叉时重置(除了持仓状态)
if shortPhase > 0 and shortPhase != 4 and emaGoldenCross
    shortPhase := 0

// === 绘图 ===
plot(emaF, "EMA28", color=color.red, linewidth=1)
plot(emaS, "EMA58", color=color.blue, linewidth=1)

// 入场标记
plotshape(longPhase[1] == 3 and longPhase == 4, "做多入场", shape.triangleup, location.belowbar, color.green, size=size.small, text="L")
plotshape(shortPhase[1] == 3 and shortPhase == 4, "做空入场", shape.triangledown, location.abovebar, color.red, size=size.small, text="S")

// 止损止盈线
plot(strategy.position_size > 0 ? longStopLoss : na, "多止损", color=color.red, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size > 0 ? longTakeProfit : na, "多止盈", color=color.green, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size < 0 ? shortStopLoss : na, "空止损", color=color.red, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size < 0 ? shortTakeProfit : na, "空止盈", color=color.green, style=plot.style_linebr, linewidth=1)

// 背景色
longBgColor = longPhase == 1 ? color.new(color.blue, 93) : longPhase == 2 ? color.new(color.aqua, 90) : longPhase == 3 ? color.new(color.green, 88) : na
shortBgColor = shortPhase == 1 ? color.new(color.purple, 93) : shortPhase == 2 ? color.new(color.fuchsia, 90) : shortPhase == 3 ? color.new(color.red, 88) : na
bgcolor(longBgColor)
bgcolor(shortBgColor)

// 状态标签(含仓位信息)
var label statusLabel = na
if barstate.islast
    label.delete(statusLabel)
    longText = longPhase == 0 ? "L:等EMA金叉" : longPhase == 1 ? "L:等DIF上零轴" : longPhase == 2 ? "L:等零轴上死叉" : longPhase == 3 ? "L:等金叉入场" : longPhase == 4 ? "L:持仓中" : ""
    shortText = shortPhase == 0 ? "S:等EMA死叉" : shortPhase == 1 ? "S:等DIF下零轴" : shortPhase == 2 ? "S:等零轴下金叉" : shortPhase == 3 ? "S:等死叉入场" : shortPhase == 4 ? "S:持仓中" : ""
    riskText = "风险:" + str.tostring(riskPercent, "#.#") + "% | 权益:" + str.tostring(strategy.equity, "#.##")
    statusLabel := label.new(bar_index, high, longText + "\n" + shortText + "\n" + riskText, color=color.new(color.black, 70), textcolor=color.white, size=size.normal)