//@version=6 indicator("缠论系统 - Chan Theory", shorttitle="缠论", overlay=true, max_lines_count=500, max_labels_count=500) // ================== 参数设置 ================== show_merged_klines = input.bool(true, "显示合并K线", group="显示设置") show_bi = input.bool(true, "显示笔", group="显示设置") show_segment = input.bool(true, "显示线段", group="显示设置") show_zhongshu = input.bool(true, "显示中枢", group="显示设置") show_signals = input.bool(true, "显示买卖点", group="显示设置") bi_color = input.color(color.blue, "笔的颜色", group="颜色设置") segment_color = input.color(color.red, "线段颜色", group="颜色设置") zhongshu_color = input.color(color.gray, "中枢颜色", group="颜色设置") // ================== 数据结构定义 ================== type KLine float high float low float open float close int index type FenXing int type // 1为顶分型,-1为底分型 float price int index bool valid type Bi FenXing start_fx FenXing end_fx bool valid type Segment Bi start_bi Bi end_bi bool valid type ZhongShu float high float low int start_index int end_index bool valid // ================== K线合并函数 ================== merge_klines(prev_kline, curr_kline) => var merged = KLine.new() // 判断包含关系 prev_includes_curr = prev_kline.high >= curr_kline.high and prev_kline.low <= curr_kline.low curr_includes_prev = curr_kline.high >= prev_kline.high and curr_kline.low <= prev_kline.low if prev_includes_curr or curr_includes_prev // 有包含关系,进行合并 if prev_kline.high >= prev_kline.low // 向上趋势中的合并 merged.high := math.max(prev_kline.high, curr_kline.high) merged.low := math.max(prev_kline.low, curr_kline.low) else // 向下趋势中的合并 merged.high := math.min(prev_kline.high, curr_kline.high) merged.low := math.min(prev_kline.low, curr_kline.low) merged.open := prev_kline.open merged.close := curr_kline.close merged.index := curr_kline.index [merged, true] else // 无包含关系,返回当前K线 [curr_kline, false] // ================== 分型识别函数 ================== check_fenxing(k1, k2, k3) => var fx = FenXing.new() // 顶分型:中间K线的高点是最高的,低点也是最高的 if k2.high > k1.high and k2.high > k3.high and k2.low > k1.low and k2.low > k3.low fx.type := 1 fx.price := k2.high fx.index := k2.index fx.valid := true fx // 底分型:中间K线的低点是最低的,高点也是最低的 else if k2.low < k1.low and k2.low < k3.low and k2.high < k1.high and k2.high < k3.high fx.type := -1 fx.price := k2.low fx.index := k2.index fx.valid := true fx else fx.valid := false fx // ================== 笔的识别函数 ================== create_bi(start_fx, end_fx) => var bi = Bi.new() // 检查笔的有效性 if start_fx.valid and end_fx.valid and start_fx.type != end_fx.type and start_fx.index < end_fx.index bi.start_fx := start_fx bi.end_fx := end_fx bi.valid := true bi else bi.valid := false bi // ================== 线段识别函数 ================== check_segment_break(bi_array) => // 简化的线段破坏判断逻辑 // 当新笔突破前面第三根笔的端点时,认为线段被破坏 bool segment_break = false if array.size(bi_array) >= 4 current_bi = array.get(bi_array, array.size(bi_array) - 1) third_bi = array.get(bi_array, array.size(bi_array) - 4) if current_bi.valid and third_bi.valid if current_bi.start_fx.type == 1 // 向下笔 segment_break := current_bi.end_fx.price < third_bi.end_fx.price else // 向上笔 segment_break := current_bi.end_fx.price > third_bi.end_fx.price segment_break // ================== 中枢识别函数 ================== find_zhongshu(bi_array) => var zhongshu_array = array.new() if array.size(bi_array) >= 3 for i = 0 to array.size(bi_array) - 3 bi1 = array.get(bi_array, i) bi2 = array.get(bi_array, i + 1) bi3 = array.get(bi_array, i + 2) if bi1.valid and bi2.valid and bi3.valid // 计算重叠区间 high1 = math.max(bi1.start_fx.price, bi1.end_fx.price) low1 = math.min(bi1.start_fx.price, bi1.end_fx.price) high2 = math.max(bi2.start_fx.price, bi2.end_fx.price) low2 = math.min(bi2.start_fx.price, bi2.end_fx.price) high3 = math.max(bi3.start_fx.price, bi3.end_fx.price) low3 = math.min(bi3.start_fx.price, bi3.end_fx.price) overlap_high = math.min(math.min(high1, high2), high3) overlap_low = math.max(math.max(low1, low2), low3) if overlap_high > overlap_low var zs = ZhongShu.new() zs.high := overlap_high zs.low := overlap_low zs.start_index := bi1.start_fx.index zs.end_index := bi3.end_fx.index zs.valid := true array.push(zhongshu_array, zs) zhongshu_array // ================== 买卖点识别函数 ================== identify_trading_signals(bi_array, zhongshu_array) => var buy_signals = array.new() var sell_signals = array.new() if array.size(bi_array) >= 2 and array.size(zhongshu_array) >= 1 current_bi = array.get(bi_array, array.size(bi_array) - 1) latest_zs = array.get(zhongshu_array, array.size(zhongshu_array) - 1) if current_bi.valid and latest_zs.valid // 一买:价格跌破中枢下沿后的第一次回调 if current_bi.end_fx.type == -1 and current_bi.end_fx.price < latest_zs.low array.push(buy_signals, current_bi.end_fx.index) // 一卖:价格突破中枢上沿后的第一次回调 if current_bi.end_fx.type == 1 and current_bi.end_fx.price > latest_zs.high array.push(sell_signals, current_bi.end_fx.index) [buy_signals, sell_signals] // ================== 主逻辑 ================== var merged_klines = array.new() var fenxing_array = array.new() var bi_array = array.new() var segment_array = array.new() // 当前K线数据 current_kline = KLine.new(high, low, open, close, bar_index) // K线合并处理 if array.size(merged_klines) > 0 last_merged = array.get(merged_klines, array.size(merged_klines) - 1) [new_kline, is_merged] = merge_klines(last_merged, current_kline) if is_merged array.set(merged_klines, array.size(merged_klines) - 1, new_kline) else array.push(merged_klines, new_kline) else array.push(merged_klines, current_kline) // 分型识别 if array.size(merged_klines) >= 3 k1 = array.get(merged_klines, array.size(merged_klines) - 3) k2 = array.get(merged_klines, array.size(merged_klines) - 2) k3 = array.get(merged_klines, array.size(merged_klines) - 1) fx = check_fenxing(k1, k2, k3) if fx.valid array.push(fenxing_array, fx) // 笔的构建 if array.size(fenxing_array) >= 2 for i = 0 to array.size(fenxing_array) - 2 start_fx = array.get(fenxing_array, i) end_fx = array.get(fenxing_array, i + 1) bi = create_bi(start_fx, end_fx) if bi.valid array.push(bi_array, bi) // 中枢识别 zhongshu_array = find_zhongshu(bi_array) // 买卖点识别 [buy_signals, sell_signals] = identify_trading_signals(bi_array, zhongshu_array) // ================== 绘图显示 ================== // 显示合并K线 if show_merged_klines and array.size(merged_klines) > 1 last_kline = array.get(merged_klines, array.size(merged_klines) - 1) prev_kline = array.get(merged_klines, array.size(merged_klines) - 2) line.new(bar_index[1], prev_kline.close, bar_index, last_kline.close, color=color.yellow, width=1) // 显示笔 if show_bi and array.size(bi_array) > 0 for i = 0 to array.size(bi_array) - 1 bi = array.get(bi_array, i) if bi.valid line.new(bi.start_fx.index, bi.start_fx.price, bi.end_fx.index, bi.end_fx.price, color=bi_color, width=2, style=line.style_solid) // 显示分型 if array.size(fenxing_array) > 0 last_fx = array.get(fenxing_array, array.size(fenxing_array) - 1) if last_fx.valid and last_fx.index == bar_index if last_fx.type == 1 label.new(bar_index, last_fx.price, "顶", color=color.red, style=label.style_label_down, size=size.small) else label.new(bar_index, last_fx.price, "底", color=color.green, style=label.style_label_up, size=size.small) // 显示中枢 if show_zhongshu and array.size(zhongshu_array) > 0 for i = 0 to array.size(zhongshu_array) - 1 zs = array.get(zhongshu_array, i) if zs.valid box.new(zs.start_index, zs.high, zs.end_index, zs.low, border_color=zhongshu_color, bgcolor=color.new(zhongshu_color, 90)) // 显示买卖点 if show_signals if array.size(buy_signals) > 0 for i = 0 to array.size(buy_signals) - 1 signal_index = array.get(buy_signals, i) if signal_index == bar_index label.new(bar_index, low, "买", color=color.green, style=label.style_label_up, size=size.normal) if array.size(sell_signals) > 0 for i = 0 to array.size(sell_signals) - 1 signal_index = array.get(sell_signals, i) if signal_index == bar_index label.new(bar_index, high, "卖", color=color.red, style=label.style_label_down, size=size.normal) // ================== 警报设置 ================== alertcondition(array.size(buy_signals) > 0 and array.get(buy_signals, array.size(buy_signals) - 1) == bar_index, title="缠论买点", message="发现缠论买点信号") alertcondition(array.size(sell_signals) > 0 and array.get(sell_signals, array.size(sell_signals) - 1) == bar_index, title="缠论卖点", message="发现缠论卖点信号") // ================== 信息面板 ================== if barstate.islast var table info_table = table.new(position.top_right, 2, 6, bgcolor=color.white, border_width=1) table.cell(info_table, 0, 0, "缠论统计", text_color=color.black, text_size=size.normal) table.cell(info_table, 1, 0, "", text_color=color.black) table.cell(info_table, 0, 1, "合并K线数", text_color=color.black) table.cell(info_table, 1, 1, str.tostring(array.size(merged_klines)), text_color=color.black) table.cell(info_table, 0, 2, "分型数量", text_color=color.black) table.cell(info_table, 1, 2, str.tostring(array.size(fenxing_array)), text_color=color.black) table.cell(info_table, 0, 3, "笔数量", text_color=color.black) table.cell(info_table, 1, 3, str.tostring(array.size(bi_array)), text_color=color.black) table.cell(info_table, 0, 4, "中枢数量", text_color=color.black) table.cell(info_table, 1, 4, str.tostring(array.size(zhongshu_array)), text_color=color.black) table.cell(info_table, 0, 5, "当前级别", text_color=color.black) table.cell(info_table, 1, 5, "1分钟", text_color=color.black)