//@version=6 strategy(“Brooks_Final_V53_ThreeState_Logic”, overlay=true, initial_capital=100000, process_orders_on_close=true)
// — 1. 参数设置 — t0_enabled = input.bool(false, “开启T+0日内交易”) qty_per_hand = input.int(100, “每手股数”) risk_reward_ratio = input.float(1.0, “P1盈亏比”)
// — 2. 全局变量 — var float dynamic_res = 0.0 var float dynamic_sup = 0.0 var int range_test_count = 0 var int state = 1 // 1=区间, 2=上涨趋势, 3=下跌趋势 var int bull_count = 0 var float stop_level = 0.0 var float tp_p1 = 0.0 var int last_entry_date = 0
// — 3. 指标 — ema20 = ta.ema(close, 20) atr = ta.atr(14) h20 = ta.highest(high, 20) l20 = ta.lowest(low, 20)
// — 4. 动态边界 — // — 4.1. 动态初始化/定期重置 — if bar_index == 0 or bar_index % 50 == 0 dynamic_res := h20 dynamic_sup := l20
// — 4.2. 状态机判断 — float ma_20 = ta.sma(close, 20) float range_threshold = ta.atr(20) * 1.5 bool is_in_range = (high < (ma_20 + range_threshold)) and (low > (ma_20 - range_threshold))
// — 4.3. 支撑阻力更新逻辑 (纳入状态判断) — if is_in_range // 在区间内:我们要求更严格,只有明确打破区间边界才更新,减少噪音 if close > dynamic_res dynamic_res := close if close < dynamic_sup dynamic_sup := close else // 在趋势中:跟随趋势节奏,允许线位跟随移动 (类似于阶梯式止损) // 只有当价格突破时,才更新线位,保持滞后性,防止过早被踢出 if close > dynamic_res dynamic_res := close if close < dynamic_sup dynamic_sup := close
// — 4.4. 逻辑锁定优化 (防止线位在区间内漂移) — // 如果你觉得在区间内线位还是太乱,可以加入此锁定开关: var float locked_res = dynamic_res var float locked_sup = dynamic_sup
if is_in_range // 区间内只更新极值,保持平滑 dynamic_res := math.max(dynamic_res, high) dynamic_sup := math.min(dynamic_sup, low) else // 趋势中,动态调整线位 dynamic_res := close dynamic_sup := close
// 状态逻辑改进: // 1. 如果价格在区间阈值内,强制为状态 1(区间) // 2. 只有当价格突破这个阈值,且均线方向明确(slope)时,才切换为 2 或 3 bool is_trending_up = (close > (ma_20 + range_threshold)) and (ma_20 > ma_20[5]) bool is_trending_down = (close < (ma_20 - range_threshold)) and (ma_20 < ma_20[5])
if is_in_range state := 1 else if is_trending_up state := 2 else if is_trending_down state := 3
is_bull = close > open is_bear = close < open // 仅在上涨趋势下进行趋势回调计数 bull_count := (state == 2 and is_bear) ? bull_count + 1 : (is_bull ? 0 : bull_count)
// — 6. 进场决策 — // 1. 获取昨日收盘价 (确保在盘中可以正确获取日级别数据) float close_prev = request.security(syminfo.tickerid, “D”, close[1], barmerge.gaps_off, barmerge.lookahead_on) float daily_pct = (close - close_prev) / close_prev * 100 bool is_daily_runup_too_high = daily_pct > 7
// 2. K线强度与涨幅逻辑 float kline_change_pct = (close - open) / open * 100 // 实体占比 > 40% 且涨幅在 1% 到 7% 之间 bool is_strong_bar = (close > open) and (math.abs(close - open) / (math.max(high - low, 0.0001)) > 0.4) bool is_valid_growth = (kline_change_pct > 1.01 and kline_change_pct < 6.99)
bool is_breakout = (high > high[1])
// 3. 整合进场条件 // 共同限制:形态必须强、日内涨幅不能过高、且突破前高 bool common_entry_filters = is_strong_bar and is_valid_growth and not is_daily_runup_too_high and is_breakout
// 区间入场 // 关键改动:给区间入场增加一个不需要严格回调序列的“强力反转线”条件 bool is_ultra_strong_bar = (close > open) and (math.abs(close - open) / (math.max(high - low, 0.0001)) > 0.9) // 实体占比 > 90% // 要求该阳线不仅踩在支撑上,且具备决定性力度 bool climax_support_test = (is_ultra_strong_bar and common_entry_filters)
// 1. 计算上下影线长度 float lower_shadow = math.min(open, close) - low float upper_shadow = high - math.max(open, close) float body_size = math.abs(close - open)
// 2. 锤线/反转线判定逻辑 // A. 下影线至少是实体的 2 倍 // B. 下影线必须比上影线长 // C. 必须要刺破过支撑线 (low <= dynamic_sup) bool is_hammer_bar = is_bull and not is_daily_runup_too_high and (lower_shadow > body_size * 2) and (lower_shadow > upper_shadow) and (low <= dynamic_sup)
// 原有的区间入场(需严格回调序列) // 逻辑:只要当前K线收盘价低于前一根K线收盘价,就视为多头在“让步”或“试探”,此时计数增加 // 一旦出现阳线(is_bull)且该K线确认反转,计数器重置 // 定义支撑位临近度 (例如:在支撑位上方 1.5% 以内) float support_zone_limit = dynamic_sup * 1.015 bool is_near_support = (low <= support_zone_limit) range_test_count := (state == 1 and close < close[1]) ? range_test_count + 1 : (is_bull ? 0 : range_test_count) bool range_h1 = (state == 1 and range_test_count[1] == 1 and (climax_support_test or is_hammer_bar) and is_near_support) bool range_h2 = (state == 1 and range_test_count[1] >= 2 and (climax_support_test or is_hammer_bar) and is_near_support)
// 整合区间逻辑:满足其一即可 bool is_range_entry = (range_h1 or range_h2)
// 趋势入场 // 判定连续突破三次高点 bool is_continue_bull= is_breakout and not is_daily_runup_too_high bool consecutive_bull = is_continue_bull and is_continue_bull[1] and is_continue_bull[2]
// 3. 趋势内入场逻辑整合: //支持“连续阳线”动能入场 bool momentum_signal = (state == 2 and consecutive_bull)
bool h1_signal = (state == 2 and is_bull and bull_count[1] == 1 and is_breakout and common_entry_filters) bool h2_signal = (state == 2 and is_bull and bull_count[1] >= 2 and is_breakout and common_entry_filters) bool h3_signal = (state == 2 and is_bull and bull_count[1] >= 3 and is_breakout and common_entry_filters) bool is_trend_entry = (h1_signal or h2_signal or h3_signal or momentum_signal or is_hammer_bar)
// 标记来源状态:在状态切换前记录当前 state var int prev_state = state if state != state[1] prev_state := state[1]
var bool is_in_cool_down = false var bool has_pulled_back = false // 新增一个标志,记录是否发生过回调
// 1. 监测冷却开启 if (prev_state == 3 and state == 2) is_in_cool_down := true
// 3. 解除冷却的真正条件:回调后且再次创新高 (即成功确认支撑) if is_in_cool_down and state != 2 is_in_cool_down := false
// 关键改动:增加初始突破入场逻辑 bool initial_breakout_entry = (state == 2) and not is_in_cool_down and is_valid_growth and daily_pct < 9.95 and (close >= dynamic_res)
// 获取日线数据 float d_ema10 = request.security(syminfo.tickerid, “D”, ta.ema(close, 10))
// 趋势判断:EMA 向上倾斜且价格在 EMA 10之上 bool is_daily_trend_bull = (close > d_ema10)
var int trade_count_in_range = 0 if state != state[1] trade_count_in_range := 0 // 状态变了,计数器归零
// — 1. 计算实体涨幅 — // — 2. 计算过去 5 根 K 线的平均实体涨幅 — // ta.sma 是简单移动平均,这里用它来计算过去 5 根 K 线的平均实体 float avg_body_size_5 = ta.sma(body_size, 5)
// — 3. 定义入场过滤条件 — // 条件 A:必须是阳线 (close > open) // 条件 B:实体涨幅必须大于过去 5 根平均值的 1.5 倍(倍数可根据需求调整) bool is_strong_bull = (close > open) and (body_size > avg_body_size_5 * 1.5)
// 最终入场逻辑 go_long = (state != 3) and is_daily_trend_bull and close > ema20 and (initial_breakout_entry or (is_range_entry and trade_count_in_range <= 2 and is_strong_bull) or is_trend_entry)
// — 7. 订单 — if strategy.position_size == 0 and go_long strategy.entry(“Long_P1”, strategy.long, qty=qty_per_hand, comment=is_range_entry ? “R” : “T”) strategy.entry(“Long_P2”, strategy.long, qty=qty_per_hand, comment=is_range_entry ? “R” : “T”) stop_level := low - atr * 1 tp_p1 := close + (close - stop_level) * risk_reward_ratio last_entry_date := year * 10000 + month * 100 + dayofmonth
// — 8. 离场 — if strategy.position_size > 0 stop_level := math.max(nz(stop_level, low - atr), low - atr) is_today = (year * 10000 + month * 100 + dayofmonth == last_entry_date) can_exit = t0_enabled or not is_today
if can_exit
if close >= tp_p1
strategy.close("Long_P1", "P1_TP")
if close <= stop_level or close < dynamic_sup
strategy.close_all("Exit_Stop")
// — 9. 画图 — // 绿色=上涨(2), 红色=下跌(3), 灰色=区间(1) color bg_color = state == 2 ? color.new(color.green, 90) : (state == 3 ? color.new(color.red, 90) : color.new(color.gray, 95)) bgcolor(bg_color)
plot(dynamic_res, color=color.blue, title=”Dynamic Resistance”, linewidth=2) plot(dynamic_sup, color=color.red, title=”Dynamic Support”, linewidth=2) plot(strategy.position_size > 0 ? stop_level : na, color=color.orange, linewidth=2, style=plot.style_linebr, title=”Trail Stop”) plot(strategy.position_size > 0 ? tp_p1 : na, color=color.green, linewidth=2, style=plot.style_linebr, title=”P1 TP”)
plotshape(go_long and strategy.position_size == 0, style=shape.triangleup, location=location.belowbar, color=is_range_entry ? color.red : color.green, size=size.small, title=”Entry Marker”)
plot(stop_level, “Stop_Level_Debug”, display=display.data_window) plot(tp_p1, “TP_P1_Debug”, display=display.data_window)