diff --git a/4EMA策略使用说明.md b/4EMA策略使用说明.md new file mode 100644 index 0000000..d004e1a --- /dev/null +++ b/4EMA策略使用说明.md @@ -0,0 +1,135 @@ +# 4根EMA均线收束发散策略使用说明 + +## 策略概述 + +这个策略基于4根不同周期的EMA(指数移动平均线)的收束和发散来识别买卖时机,主要特点: + +- **买入信号**:4根均线从收束状态开始向同一方向发散 +- **卖出信号**:均线开口达到最大时平仓 + +## 核心理念 + +**均线收束发散理论**:当多条均线聚集在一起(收束)时,表示市场处于整理状态;当均线开始向同一方向散开(发散)时,往往是新趋势的开始。这个策略专门捕捉这种从收束到发散的转折点。 + +## 核心参数设置 + +### EMA周期参数 +- **EMA1周期**:默认5(快速均线,红色) +- **EMA2周期**:默认10(中速均线,橙色) +- **EMA3周期**:默认20(慢速均线,蓝色) +- **EMA4周期**:默认60(超慢速均线,紫色) + +### 开口阈值 +- **开口阈值(%)**:默认0.5%,控制卖出信号的敏感度 + +### 交易频率控制 +- **最小交易间隔(K线数)**:默认20根,控制两次交易之间的最小间隔 +- **最小价格变化(%)**:默认0.5%,要求价格有足够变化才能开新仓 + +### 均线收束参数 +- **均线最大间距(%)**:默认0.3%,定义均线收束的最大距离阈值 +- **收束确认周期**:默认3根K线,确认收束状态的持续时间 + +## 买入条件详解 + +### 1. 多头买入条件(向上发散) +- **均线之前收束**:4根均线距离在设定阈值内且持续足够周期 +- **开始向上发散**:4根均线同时向上且距离开始扩大 +- **价格在EMA52上方**:确保顺应长期趋势 +- **交易间隔足够**:距离上次交易至少20根K线 +- **价格变化足够**:相对上次交易价格变化超过0.5% +- 满足条件时产生**买多信号** + +### 2. 空头买入条件(向下发散) +- **均线之前收束**:4根均线距离在设定阈值内且持续足够周期 +- **开始向下发散**:4根均线同时向下且距离开始扩大 +- **价格在EMA52下方**:确保顺应长期趋势 +- **交易间隔足够**:距离上次交易至少20根K线 +- **价格变化足够**:相对上次交易价格变化超过0.5% +- 满足条件时产生**买空信号** + +## 卖出条件详解 + +### 开口最大检测 +- 计算**最快均线(EMA5)**和**最慢均线(EMA60)**之间的距离 +- 使用相对价格百分比来衡量开口程度 +- 当开口达到**历史最大值的90%**且超过**设定阈值**时触发平仓 + +## 视觉指示功能 + +### 1. 均线显示 +- **红色线**:EMA5(最快) +- **橙色线**:EMA10 +- **蓝色线**:EMA20 +- **紫色线**:EMA60(最慢) + +### 2. 背景颜色 +- **浅黄色背景**:均线处于收束状态 +- **浅绿色背景**:均线开始向上发散 +- **浅红色背景**:均线开始向下发散 + +### 3. 交易信号标记 +- **绿色向上箭头"买多"**:向上发散买入信号 +- **红色向下箭头"买空"**:向下发散买入信号 +- **黄色"平仓"**:开口最大卖出信号 + +### 4. 信息表格 +显示实时状态: +- 均线间距(当前4根均线的最大距离) +- 收束阈值(定义收束状态的距离上限) +- 收束状态(收束中/发散中) +- 发散方向(向上发散/向下发散/无发散) +- 趋势方向(同向上/同向下/分歧) +- 价格位置(EMA52上方/下方/附近) +- 距上次交易(K线数) +- 可交易状态(可交易/等待中) +- 当前仓位状态 + +## 策略优势 + +1. **趋势起点捕捉**:专门捕捉从整理到趋势的转折点,入场时机精准 +2. **双向交易**:可以做多也可以做空,适应不同市场环境 +3. **风险控制**:在开口最大时及时平仓,避免趋势反转损失 +4. **频率控制**:严格的收束发散条件,避免过度交易 +5. **多重过滤**:收束状态+发散方向+价格位置+时间间隔多重过滤 +6. **信号质量高**:只在均线真正开始发散时才触发,减少假信号 +7. **视觉友好**:直观的背景颜色显示收束/发散状态 + +## 使用建议 + +### 1. 时间周期选择 +- **短线交易**:建议使用15分钟或1小时图 +- **中线交易**:建议使用4小时或日线图 +- **长线交易**:建议使用日线或周线图 + +### 2. 参数调优 +- **活跃市场**:可以降低均线间距阈值(0.2%-0.25%),减少交易间隔(10-15根K线) +- **平静市场**:可以提高均线间距阈值(0.4%-0.5%),增加交易间隔(25-30根K线) +- **不同品种**:根据标的物波动性调整EMA周期和收束阈值 +- **降低频率**:增大收束阈值和交易间隔,提高价格变化要求 +- **提高敏感度**:减小收束阈值,缩短收束确认周期 +- **波动性大的品种**:适当增大收束阈值,避免噪音干扰 + +### 3. 风险管理 +- 建议设置固定的止损比例(如2-3%) +- 不要在横盘震荡市场中使用 +- 注意重大消息面对策略的影响 + +### 4. 最佳使用场景 +- **震荡后的突破**:最适合捕捉整理后的趋势启动 +- **趋势转换点**:识别从无趋势到有趋势的转折 +- **配合成交量**:发散时配合放量效果更佳 +- **多时间框架**:可在不同时间周期上同时使用 +- **避免强势单边市**:不适合已经大幅单边运行的市场 + +## 注意事项 + +1. 这是一个趋势跟踪策略,在震荡市场中可能产生较多假信号 +2. 开口最大的判断具有一定滞后性,可能错过最佳卖点 +3. 建议在回测中验证参数设置的有效性 +4. 实盘使用时请注意资金管理和风险控制 + +## 版本信息 +- Pine Script版本:v6 +- 策略类型:双向交易策略 +- 适用市场:股票、期货、外汇、加密货币 \ No newline at end of file diff --git a/README 2.md b/README 2.md new file mode 100644 index 0000000..659c436 --- /dev/null +++ b/README 2.md @@ -0,0 +1,126 @@ +# 缠论 TradingView Pine Script 实现 + +本项目使用 Pine Script 6.0 实现了完整的缠论分析系统,包含K线合并、分型、笔、线段、中枢识别和买卖点信号。 + +## 文件说明 + +### 1. chan_theory.pine +**完整版缠论指标** +- 实现了缠论的全部核心概念 +- 包含K线合并逻辑 +- 完整的分型、笔、线段、中枢识别 +- 基于中枢的买卖点信号 +- 丰富的自定义参数和显示选项 + +### 2. chan_theory_simple.pine +**精简版缠论指标** +- 优化性能和可读性 +- 使用Pine Script内置函数提高效率 +- 简化的中枢识别算法 +- 更稳定的绘图对象管理 +- 适合日常使用 + +### 3. 缠论使用说明.md +**详细使用文档** +- 缠论理论基础解释 +- 参数设置说明 +- 使用方法和注意事项 +- 常见问题解答 + +## 快速开始 + +1. **导入指标** + - 复制任一 `.pine` 文件内容 + - 在 TradingView 的 Pine Editor 中粘贴 + - 点击"添加到图表" + +2. **选择版本** + - `chan_theory.pine`: 功能完整,适合深入学习 + - `chan_theory_simple.pine`: 性能优化,适合实际交易 + +3. **参数调整** + - 根据交易级别调整分型周期 + - 自定义颜色和显示选项 + - 开启所需的警报功能 + +## 核心功能 + +### 🔍 分型识别 +- 自动识别顶分型和底分型 +- 标记为 "T"(顶)和 "B"(底) +- 可调节识别灵敏度 + +### 📈 笔的构建 +- 连接相邻反向分型 +- 蓝色线条显示价格波动路径 +- 形成缠论分析的基础单位 + +### 🎯 中枢识别 +- 自动识别三笔以上的重叠区间 +- 灰色半透明方框显示 +- 支持多级别中枢分析 + +### 💰 买卖点信号 +- 基于中枢突破的交易信号 +- 绿色"买"标签:跌破中枢下沿回调 +- 红色"卖"标签:突破中枢上沿回调 + +### 📊 信息面板 +- 实时显示分型和中枢统计 +- 当前分析状态一目了然 +- 右上角位置,不影响图表分析 + +## 技术特点 + +- **Pine Script 6.0**: 使用最新版本特性 +- **内存优化**: 限制数组大小避免内存溢出 +- **绘图管理**: 自动清理旧对象防止超限 +- **警报功能**: 支持实时买卖点通知 +- **多时间框架**: 适用于任何时间级别 + +## 使用建议 + +### 新手用户 +1. 从精简版开始使用 +2. 在日线级别练习识别 +3. 先关注分型和笔的形成 +4. 逐步学习中枢概念 + +### 进阶用户 +1. 使用完整版深入分析 +2. 结合多个时间级别 +3. 自定义参数优化信号 +4. 结合其他技术分析工具 + +### 实盘交易 +1. 充分回测验证信号 +2. 设置合理的风险控制 +3. 结合基本面分析 +4. 不要盲目依赖单一信号 + +## 免责声明 + +⚠️ **重要提示** +- 本指标仅供学习和研究使用 +- 不构成投资建议 +- 投资有风险,入市需谨慎 +- 请结合自身风险承受能力使用 + +## 技术支持 + +如果在使用过程中遇到问题: +1. 查看使用说明文档 +2. 检查 Pine Script 版本兼容性 +3. 确认参数设置是否合理 +4. 参考缠论相关书籍和资料 + +## 版本更新 + +- **v1.0**: 初始版本,实现核心功能 +- **v1.1**: 性能优化,添加精简版 +- **v1.2**: 改进中枢识别算法 +- **v1.3**: 增强买卖点逻辑 + +--- + +*愿此工具能助您在技术分析的道路上更进一步!* \ No newline at end of file diff --git a/bollinger_atr_strategy.pine b/bollinger_atr_strategy.pine new file mode 100644 index 0000000..6f6decb --- /dev/null +++ b/bollinger_atr_strategy.pine @@ -0,0 +1,136 @@ +//@version=6 +strategy("布林带ATR反转策略", shorttitle="BBB_ATR", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, calc_on_every_tick=true) + +// 输入参数 +bb_length = input.int(90, "布林带长度", minval=10, maxval=200) +atr_multiplier = input.float(3.0, "ATR乘数(轨道)", minval=1.0, maxval=10.0, step=0.1) +atr_stop_multiplier = input.float(3.0, "ATR乘数(止损)", minval=0.5, maxval=5.0, step=0.1) +atr_length = input.int(9, "ATR计算周期", minval=5, maxval=50) + +// 显示设置 +show_bands = input.bool(true, "显示布林带") +show_signals = input.bool(true, "显示信号") + +// 计算移动平均线(中线) +bb_middle = ta.sma(close, bb_length) + +// 计算ATR +atr_value = ta.atr(atr_length) + +// 计算上下轨 +bb_upper = bb_middle + (atr_multiplier * atr_value) +bb_lower = bb_middle - (atr_multiplier * atr_value) + +// 显示布林带 +plot(show_bands ? bb_middle : na, "中线", color=color.blue, linewidth=2) +plot(show_bands ? bb_upper : na, "上轨", color=color.red, linewidth=2) +plot(show_bands ? bb_lower : na, "下轨", color=color.green, linewidth=2) + + +// 交易条件 +// 做空条件:价格突破上轨 +short_condition = close > bb_upper and close[1] <= bb_upper[1] + +// 做多条件:价格跌破下轨 +long_condition = close < bb_lower and close[1] >= bb_lower[1] + +// 做空止盈条件:价格跌破下轨 +short_take_profit = close < bb_lower + +// 做多止盈条件:价格突破上轨 +long_take_profit = close > bb_upper + +// 记录入场价格和止损位 +var float long_entry_price = na +var float short_entry_price = na +var float long_stop_loss = na +var float short_stop_loss = na + +// 执行交易逻辑 +if strategy.position_size == 0 + if long_condition + strategy.entry("做多", strategy.long) + long_entry_price := close + long_stop_loss := close - (atr_stop_multiplier * atr_value) + + if short_condition + strategy.entry("做空", strategy.short) + short_entry_price := close + short_stop_loss := close + (atr_stop_multiplier * atr_value) + +// 多头仓位管理 +if strategy.position_size > 0 + // 止盈:价格突破上轨 + if long_take_profit + strategy.close("做多", comment="多头止盈") + long_entry_price := na + long_stop_loss := na + // 止损:价格跌破止损位 + else if close <= long_stop_loss + strategy.close("做多", comment="多头止损") + long_entry_price := na + long_stop_loss := na + +// 空头仓位管理 +if strategy.position_size < 0 + // 止盈:价格跌破下轨 + if short_take_profit + strategy.close("做空", comment="空头止盈") + short_entry_price := na + short_stop_loss := na + // 止损:价格突破止损位 + else if close >= short_stop_loss + strategy.close("做空", comment="空头止损") + short_entry_price := na + short_stop_loss := na + +// 显示信号 +if show_signals + if long_condition and strategy.position_size == 0 + label.new(bar_index, low, "做多", color=color.green, style=label.style_label_up, size=size.normal, textcolor=color.white) + if short_condition and strategy.position_size == 0 + label.new(bar_index, high, "做空", color=color.red, style=label.style_label_down, size=size.normal, textcolor=color.white) + if long_take_profit and strategy.position_size > 0 + label.new(bar_index, high, "多头止盈", color=color.green, style=label.style_label_down, size=size.small, textcolor=color.white) + if short_take_profit and strategy.position_size < 0 + label.new(bar_index, low, "空头止盈", color=color.red, style=label.style_label_up, size=size.small, textcolor=color.white) + +// 显示止损线 +plot(strategy.position_size > 0 and not na(long_stop_loss) ? long_stop_loss : na, "多头止损", color=color.red, style=plot.style_linebr, linewidth=1) +plot(strategy.position_size < 0 and not na(short_stop_loss) ? short_stop_loss : na, "空头止损", color=color.red, style=plot.style_linebr, linewidth=1) + + +// 信息表格 +if barstate.islast + var table info_table = table.new(position.top_right, 2, 10, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "布林带ATR反转策略", text_color=color.black, bgcolor=color.gray) + table.cell(info_table, 1, 0, "", text_color=color.black, bgcolor=color.gray) + + table.cell(info_table, 0, 1, "布林带长度", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(bb_length), text_color=color.black) + + table.cell(info_table, 0, 2, "ATR轨道乘数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(atr_multiplier), text_color=color.black) + + table.cell(info_table, 0, 3, "ATR止损乘数", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(atr_stop_multiplier), text_color=color.black) + + table.cell(info_table, 0, 4, "当前ATR", text_color=color.black) + table.cell(info_table, 1, 4, str.tostring(math.round(atr_value, 4)), text_color=color.black) + + table.cell(info_table, 0, 5, "上轨价位", text_color=color.black) + table.cell(info_table, 1, 5, str.tostring(math.round(bb_upper, 2)), text_color=color.black) + + table.cell(info_table, 0, 6, "下轨价位", text_color=color.black) + table.cell(info_table, 1, 6, str.tostring(math.round(bb_lower, 2)), text_color=color.black) + + table.cell(info_table, 0, 7, "当前价格", text_color=color.black) + table.cell(info_table, 1, 7, str.tostring(math.round(close, 2)), text_color=color.black) + + table.cell(info_table, 0, 8, "仓位状态", text_color=color.black) + position_text = strategy.position_size > 0 ? "多头" : strategy.position_size < 0 ? "空头" : "空仓" + table.cell(info_table, 1, 8, position_text, text_color=color.black) + + table.cell(info_table, 0, 9, "价格位置", text_color=color.black) + price_position = close > bb_upper ? "上轨之上" : close < bb_lower ? "下轨之下" : "轨道之间" + table.cell(info_table, 1, 9, price_position, text_color=color.black) \ No newline at end of file diff --git a/bollinger_band_strategy_new.pine b/bollinger_band_strategy_new.pine new file mode 100644 index 0000000..68913e9 --- /dev/null +++ b/bollinger_band_strategy_new.pine @@ -0,0 +1,133 @@ +//@version=5 +strategy("布林带反转策略", shorttitle="BB_REV", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, calc_on_every_tick=true) + +// 输入参数 +bb_length = input.int(90, "布林带长度", minval=10, maxval=200) +bb_mult = input.float(3.0, "布林带倍数", minval=1.0, maxval=10.0, step=0.1) +atr_length = input.int(14, "ATR计算周期", minval=5, maxval=50) +atr_mult = input.float(1.0, "止损ATR倍数", minval=0.5, maxval=5.0, step=0.1) + +// 显示设置 +show_bands = input.bool(true, "显示布林带") +show_signals = input.bool(true, "显示信号") + +// 计算布林带(保持标准差计算) +bb_basis = ta.sma(close, bb_length) +bb_dev = bb_mult * ta.stdev(close, bb_length) +bb_upper = bb_basis + bb_dev +bb_lower = bb_basis - bb_dev + +// 计算ATR(仅用于止损) +atr_value = ta.atr(atr_length) + +// 显示布林带 +plot(show_bands ? bb_basis : na, "中线", color=color.blue, linewidth=2) +plot(show_bands ? bb_upper : na, "上轨", color=color.red, linewidth=2) +plot(show_bands ? bb_lower : na, "下轨", color=color.green, linewidth=2) + +// 交易条件 +// 做空条件:价格突破上轨 +short_condition = close > bb_upper and close[1] <= bb_upper[1] + +// 做多条件:价格跌破下轨 +long_condition = close < bb_lower and close[1] >= bb_lower[1] + +// 做空止盈条件:价格跌破下轨 +short_take_profit = close < bb_lower + +// 做多止盈条件:价格突破上轨 +long_take_profit = close > bb_upper + +// 记录入场价格和止损位 +var float long_entry_price = na +var float short_entry_price = na +var float long_stop_loss = na +var float short_stop_loss = na + +// 执行交易逻辑 +if strategy.position_size == 0 + if long_condition + strategy.entry("做多", strategy.long) + long_entry_price := close + long_stop_loss := close - (atr_mult * atr_value) + + if short_condition + strategy.entry("做空", strategy.short) + short_entry_price := close + short_stop_loss := close + (atr_mult * atr_value) + +// 多头仓位管理 +if strategy.position_size > 0 + // 止盈:价格突破上轨 + if long_take_profit + strategy.close("做多", comment="多头止盈") + long_entry_price := na + long_stop_loss := na + // 止损:价格跌破止损位 + else if close <= long_stop_loss + strategy.close("做多", comment="多头止损") + long_entry_price := na + long_stop_loss := na + +// 空头仓位管理 +if strategy.position_size < 0 + // 止盈:价格跌破下轨 + if short_take_profit + strategy.close("做空", comment="空头止盈") + short_entry_price := na + short_stop_loss := na + // 止损:价格突破止损位 + else if close >= short_stop_loss + strategy.close("做空", comment="空头止损") + short_entry_price := na + short_stop_loss := na + +// 显示信号 +if show_signals + if long_condition and strategy.position_size == 0 + label.new(bar_index, low, "做多", color=color.green, style=label.style_label_up, size=size.normal, textcolor=color.white) + if short_condition and strategy.position_size == 0 + label.new(bar_index, high, "做空", color=color.red, style=label.style_label_down, size=size.normal, textcolor=color.white) + if long_take_profit and strategy.position_size > 0 + label.new(bar_index, high, "多头止盈", color=color.green, style=label.style_label_down, size=size.small, textcolor=color.white) + if short_take_profit and strategy.position_size < 0 + label.new(bar_index, low, "空头止盈", color=color.red, style=label.style_label_up, size=size.small, textcolor=color.white) + +// 显示止损线 +plot(strategy.position_size > 0 and not na(long_stop_loss) ? long_stop_loss : na, "多头止损", color=color.red, style=plot.style_linebr, linewidth=1) +plot(strategy.position_size < 0 and not na(short_stop_loss) ? short_stop_loss : na, "空头止损", color=color.red, style=plot.style_linebr, linewidth=1) + +// 信息表格 +if barstate.islast + var table info_table = table.new(position.top_right, 2, 10, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "布林带反转策略", text_color=color.black, bgcolor=color.gray) + table.cell(info_table, 1, 0, "", text_color=color.black, bgcolor=color.gray) + + table.cell(info_table, 0, 1, "布林带长度", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(bb_length), text_color=color.black) + + table.cell(info_table, 0, 2, "布林带倍数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(bb_mult), text_color=color.black) + + table.cell(info_table, 0, 3, "ATR止损倍数", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(atr_mult), text_color=color.black) + + table.cell(info_table, 0, 4, "当前ATR", text_color=color.black) + table.cell(info_table, 1, 4, str.tostring(math.round(atr_value, 4)), text_color=color.black) + + table.cell(info_table, 0, 5, "上轨价位", text_color=color.black) + table.cell(info_table, 1, 5, str.tostring(math.round(bb_upper, 2)), text_color=color.black) + + table.cell(info_table, 0, 6, "下轨价位", text_color=color.black) + table.cell(info_table, 1, 6, str.tostring(math.round(bb_lower, 2)), text_color=color.black) + + table.cell(info_table, 0, 7, "当前价格", text_color=color.black) + table.cell(info_table, 1, 7, str.tostring(math.round(close, 2)), text_color=color.black) + + table.cell(info_table, 0, 8, "仓位状态", text_color=color.black) + position_text = strategy.position_size > 0 ? "多头" : strategy.position_size < 0 ? "空头" : "空仓" + table.cell(info_table, 1, 8, position_text, text_color=color.black) + + table.cell(info_table, 0, 9, "价格位置", text_color=color.black) + price_position = close > bb_upper ? "上轨之上" : close < bb_lower ? "下轨之下" : "轨道之间" + table.cell(info_table, 1, 9, price_position, text_color=color.black) \ No newline at end of file diff --git a/chan_theory.pine b/chan_theory.pine new file mode 100644 index 0000000..feab409 --- /dev/null +++ b/chan_theory.pine @@ -0,0 +1,289 @@ +//@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) \ No newline at end of file diff --git a/chan_theory_association.pine b/chan_theory_association.pine new file mode 100644 index 0000000..12989cc --- /dev/null +++ b/chan_theory_association.pine @@ -0,0 +1,154 @@ +//@version=6 +indicator("缠论结合律版", shorttitle="结合律", overlay=true, max_lines_count=100, max_labels_count=100) + +// 参数 +min_gap = input.int(3, "分型间隔", minval=1, maxval=20) +show_fractals = input.bool(true, "显示分型") +show_strokes = input.bool(true, "显示笔") +show_filtered = input.bool(true, "显示过滤后分型") + +// 数据类型 +type Fractal + int bar_index + float price + string type + bool is_valid // 是否为有效分型(非中继) + +// 全局变量 +var all_fractals = array.new() // 所有分型 +var valid_fractals = array.new() // 过滤后的分型 +var stroke_lines = array.new() + +// 分型识别 +is_high = high[1] > high[0] and high[1] > high[2] +is_low = low[1] < low[0] and low[1] < low[2] + +// 距离检查 +distance_ok(new_bar) => + result = true + if array.size(all_fractals) > 0 + last_fractal = array.get(all_fractals, array.size(all_fractals) - 1) + if new_bar - last_fractal.bar_index < min_gap + result := false + result + +// 添加原始分型 +if is_high and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], high[1], "top", true) + array.push(all_fractals, new_fractal) + + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +if is_low and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], low[1], "bottom", true) + array.push(all_fractals, new_fractal) + + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +// 显示原始分型 +if show_fractals + if is_high and distance_ok(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.tiny) + + if is_low and distance_ok(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.tiny) + +// 应用结合律,过滤中继分型 +filter_fractals() => + // 清空有效分型数组 + array.clear(valid_fractals) + + if array.size(all_fractals) <= 1 + // 如果分型数量不足,直接返回 + if array.size(all_fractals) == 1 + array.push(valid_fractals, array.get(all_fractals, 0)) + else + // 第一个分型总是有效的 + first_fractal = array.get(all_fractals, 0) + array.push(valid_fractals, first_fractal) + + // 从第二个分型开始处理 + i = 1 + while i < array.size(all_fractals) + current_fractal = array.get(all_fractals, i) + last_valid = array.get(valid_fractals, array.size(valid_fractals) - 1) + + if current_fractal.type != last_valid.type + // 不同类型,直接添加 + array.push(valid_fractals, current_fractal) + i += 1 + else + // 相同类型,找到最极端的分型 + extreme_fractal = current_fractal + extreme_idx = i + + // 继续查找同类型的更极端分型 + j = i + 1 + while j < array.size(all_fractals) + next_fractal = array.get(all_fractals, j) + if next_fractal.type == current_fractal.type + // 同类型,比较极端程度 + if current_fractal.type == "top" + if next_fractal.price > extreme_fractal.price + extreme_fractal := next_fractal + extreme_idx := j + else // bottom + if next_fractal.price < extreme_fractal.price + extreme_fractal := next_fractal + extreme_idx := j + j += 1 + else + // 不同类型,结束查找 + break + + // 添加最极端的分型 + array.push(valid_fractals, extreme_fractal) + i := j // 跳到不同类型的分型 + +// 每根K线更新 +if barstate.isconfirmed + // 过滤分型 + filter_fractals() + + // 清理旧笔 + if array.size(stroke_lines) > 0 + for i = 0 to array.size(stroke_lines) - 1 + line.delete(array.get(stroke_lines, i)) + array.clear(stroke_lines) + + // 绘制笔(连接有效分型) + if show_strokes and array.size(valid_fractals) >= 2 + for i = 0 to array.size(valid_fractals) - 2 + current_fractal = array.get(valid_fractals, i) + next_fractal = array.get(valid_fractals, i + 1) + + // 检查距离 + distance = bar_index - current_fractal.bar_index + if distance <= 500 + stroke_line = line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=color.blue, width=2, style=line.style_solid) + array.push(stroke_lines, stroke_line) + +// 显示过滤后的分型 +if show_filtered and barstate.islast + for i = 0 to array.size(valid_fractals) - 1 + fractal = array.get(valid_fractals, i) + if fractal.type == "top" + label.new(fractal.bar_index, fractal.price, "T", color=color.yellow, style=label.style_label_down, size=size.small) + else + label.new(fractal.bar_index, fractal.price, "B", color=color.orange, style=label.style_label_up, size=size.small) + +// 信息显示 +if barstate.islast + var table info = table.new(position.top_right, 2, 5, bgcolor=color.white, border_width=1) + table.cell(info, 0, 0, "缠论结合律版", text_color=color.black, text_size=size.small) + table.cell(info, 1, 0, "", text_color=color.black) + table.cell(info, 0, 1, "原始分型", text_color=color.black) + table.cell(info, 1, 1, str.tostring(array.size(all_fractals)), text_color=color.black) + table.cell(info, 0, 2, "有效分型", text_color=color.black) + table.cell(info, 1, 2, str.tostring(array.size(valid_fractals)), text_color=color.black) + table.cell(info, 0, 3, "笔数", text_color=color.black) + table.cell(info, 1, 3, str.tostring(array.size(stroke_lines)), text_color=color.black) + table.cell(info, 0, 4, "分型间隔", text_color=color.black) + table.cell(info, 1, 4, str.tostring(min_gap), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_correct.pine b/chan_theory_correct.pine new file mode 100644 index 0000000..984531e --- /dev/null +++ b/chan_theory_correct.pine @@ -0,0 +1,114 @@ +//@version=6 +indicator("缠论正确版", shorttitle="缠论正确", overlay=true, max_lines_count=100, max_labels_count=100) + +// 简单参数 +min_gap = input.int(5, "分型间隔") +show_fractals = input.bool(true, "显示分型") +show_strokes = input.bool(true, "显示笔") + +// 数据类型 +type Fractal + int bar_index + float price + string type // "top" or "bottom" + +// 全局变量 +var fractals = array.new() +var stroke_lines = array.new() + +// 简单分型检测 +is_high = high[1] > high[0] and high[1] > high[2] +is_low = low[1] < low[0] and low[1] < low[2] + +// 距离检查 +distance_ok(new_bar) => + result = true + if array.size(fractals) > 0 + last_fractal = array.get(fractals, array.size(fractals) - 1) + if new_bar - last_fractal.bar_index < min_gap + result := false + result + +// 添加分型 +if is_high and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], high[1], "top") + array.push(fractals, new_fractal) + + if array.size(fractals) > 50 + array.shift(fractals) + +if is_low and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], low[1], "bottom") + array.push(fractals, new_fractal) + + if array.size(fractals) > 50 + array.shift(fractals) + +// 显示分型 +if show_fractals + if is_high and distance_ok(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.small) + + if is_low and distance_ok(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.small) + +// 重新构建所有笔(满足结合律) +if barstate.isconfirmed and show_strokes + // 清理旧笔 + if array.size(stroke_lines) > 0 + for i = 0 to array.size(stroke_lines) - 1 + line.delete(array.get(stroke_lines, i)) + array.clear(stroke_lines) + + // 构建连续的笔序列(处理中继分型) + if array.size(fractals) >= 2 + var current_start_idx = 0 + var current_direction = "" + + // 确定起始方向 + if array.size(fractals) >= 2 + first_fractal = array.get(fractals, 0) + second_fractal = array.get(fractals, 1) + if first_fractal.type != second_fractal.type + current_direction := first_fractal.type + + // 从第二个分型开始遍历 + for i = 1 to array.size(fractals) - 1 + current_fractal = array.get(fractals, i) + + // 如果找到不同类型的分型,结束当前笔 + if current_fractal.type != current_direction + start_fractal = array.get(fractals, current_start_idx) + + // 绘制笔 + distance = bar_index - start_fractal.bar_index + if distance <= 500 + stroke_line = line.new(start_fractal.bar_index, start_fractal.price, current_fractal.bar_index, current_fractal.price, color=color.blue, width=2, style=line.style_solid) + array.push(stroke_lines, stroke_line) + + // 开始新笔 + current_start_idx := i + current_direction := current_fractal.type + else + // 同类型分型,处理中继 + start_fractal = array.get(fractals, current_start_idx) + + // 如果当前分型更极端,更新起始点 + if current_direction == "top" + if current_fractal.price > start_fractal.price + current_start_idx := i + else // bottom + if current_fractal.price < start_fractal.price + current_start_idx := i + +// 信息显示 +if barstate.islast + var table info = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info, 0, 0, "缠论正确版", text_color=color.black, text_size=size.small) + table.cell(info, 1, 0, "", text_color=color.black) + table.cell(info, 0, 1, "分型数", text_color=color.black) + table.cell(info, 1, 1, str.tostring(array.size(fractals)), text_color=color.black) + table.cell(info, 0, 2, "笔数", text_color=color.black) + table.cell(info, 1, 2, str.tostring(array.size(stroke_lines)), text_color=color.black) + table.cell(info, 0, 3, "分型间隔", text_color=color.black) + table.cell(info, 1, 3, str.tostring(min_gap), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_debug.pine b/chan_theory_debug.pine new file mode 100644 index 0000000..48ecdfd --- /dev/null +++ b/chan_theory_debug.pine @@ -0,0 +1,102 @@ +//@version=6 +indicator("缠论调试版", shorttitle="缠论调试", overlay=true, max_lines_count=200, max_labels_count=200) + +// ================== 参数设置 ================== +show_fenxing = input.bool(true, "显示分型", group="显示设置") +show_bi = input.bool(true, "显示笔", group="显示设置") +debug_mode = input.bool(true, "调试模式", group="显示设置") + +// 缠论参数 +min_bars_between = input.int(3, "分型最小间隔", minval=1, maxval=20, group="缠论参数") + +// ================== 数据类型定义 ================== +type FractalPoint + int bar_index + float price + string fractal_type + bool confirmed + +// ================== 全局变量 ================== +var fractal_points = array.new() +var bi_lines = array.new() + +// ================== 简单分型识别 ================== +// 检查高点分型 +is_pivot_high = high[1] > high[0] and high[1] > high[2] +// 检查低点分型 +is_pivot_low = low[1] < low[0] and low[1] < low[2] + +// ================== 距离过滤 ================== +distance_ok(new_bar, new_type) => + if debug_mode + true + else + result = true + if array.size(fractal_points) > 0 + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + bar_distance = new_bar - last_fractal.bar_index + if bar_distance < min_bars_between + result := false + result + +// ================== 添加分型 ================== +var bool fractal_added = false +fractal_added := false + +if is_pivot_high and distance_ok(bar_index[1], "top") + new_fractal = FractalPoint.new(bar_index[1], high[1], "top", true) + array.push(fractal_points, new_fractal) + fractal_added := true + + if array.size(fractal_points) > 100 + array.shift(fractal_points) + +if is_pivot_low and distance_ok(bar_index[1], "bottom") + new_fractal = FractalPoint.new(bar_index[1], low[1], "bottom", true) + array.push(fractal_points, new_fractal) + fractal_added := true + + if array.size(fractal_points) > 100 + array.shift(fractal_points) + +// ================== 显示分型 ================== +if show_fenxing + if is_pivot_high and distance_ok(bar_index[1], "top") + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.small) + + if is_pivot_low and distance_ok(bar_index[1], "bottom") + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.small) + +// ================== 构建笔 ================== +if fractal_added and array.size(fractal_points) >= 2 + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + second_last_fractal = array.get(fractal_points, array.size(fractal_points) - 2) + + // 如果最近两个分型类型不同,构建笔 + if last_fractal.fractal_type != second_last_fractal.fractal_type + // 检查bar_index距离是否在合理范围内(Pine Script限制) + bar_distance = bar_index - second_last_fractal.bar_index + if bar_distance <= 500 // 限制在500根K线范围内 + // 绘制笔 + if show_bi + new_line = line.new(second_last_fractal.bar_index, second_last_fractal.price, last_fractal.bar_index, last_fractal.price, color=color.blue, width=2, style=line.style_solid) + array.push(bi_lines, new_line) + + // 限制笔的数量 + if array.size(bi_lines) > 200 + old_line = array.shift(bi_lines) + line.delete(old_line) + +// ================== 信息面板 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 5, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论调试版", text_color=color.black, text_size=size.small) + table.cell(info_table, 1, 0, "", text_color=color.black) + table.cell(info_table, 0, 1, "分型数", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(array.size(fractal_points)), text_color=color.black) + table.cell(info_table, 0, 2, "笔数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(bi_lines)), text_color=color.black) + table.cell(info_table, 0, 3, "调试模式", text_color=color.black) + table.cell(info_table, 1, 3, debug_mode ? "开" : "关", text_color=color.black) + table.cell(info_table, 0, 4, "当前K线", text_color=color.black) + table.cell(info_table, 1, 4, str.tostring(bar_index), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_enhanced.pine b/chan_theory_enhanced.pine new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/chan_theory_enhanced.pine @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chan_theory_final.pine b/chan_theory_final.pine new file mode 100644 index 0000000..d10b1b8 --- /dev/null +++ b/chan_theory_final.pine @@ -0,0 +1,89 @@ +//@version=6 +indicator("缠论最终版", shorttitle="缠论最终", overlay=true, max_lines_count=200, max_labels_count=200) + +// ================== 参数设置 ================== +show_fenxing = input.bool(true, "显示分型", group="显示设置") +show_bi = input.bool(true, "显示笔", group="显示设置") +min_bars_between = input.int(3, "分型最小间隔", minval=1, maxval=20, group="缠论参数") + +// ================== 数据类型定义 ================== +type FractalPoint + int bar_index + float price + string fractal_type + +// ================== 全局变量 ================== +var fractal_points = array.new() +var bi_lines = array.new() + +// ================== 简单分型识别 ================== +// 基于原始K线的简单分型 +is_top_fractal = high[1] > high[0] and high[1] > high[2] +is_bottom_fractal = low[1] < low[0] and low[1] < low[2] + +// ================== 距离过滤 ================== +distance_ok(new_bar) => + result = true + if array.size(fractal_points) > 0 + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + bar_distance = new_bar - last_fractal.bar_index + if bar_distance < min_bars_between + result := false + result + +// ================== 添加分型 ================== +if is_top_fractal and distance_ok(bar_index[1]) + new_fractal = FractalPoint.new(bar_index[1], high[1], "top") + array.push(fractal_points, new_fractal) + + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +if is_bottom_fractal and distance_ok(bar_index[1]) + new_fractal = FractalPoint.new(bar_index[1], low[1], "bottom") + array.push(fractal_points, new_fractal) + + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +// ================== 显示分型 ================== +if show_fenxing + if is_top_fractal and distance_ok(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.small) + + if is_bottom_fractal and distance_ok(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.small) + +// ================== 每根K线重新构建所有笔 ================== +if barstate.isconfirmed + // 清理旧笔 + if array.size(bi_lines) > 0 + for i = 0 to array.size(bi_lines) - 1 + line.delete(array.get(bi_lines, i)) + array.clear(bi_lines) + + // 重新构建所有笔 + if array.size(fractal_points) >= 2 and show_bi + for i = 0 to array.size(fractal_points) - 2 + current_fractal = array.get(fractal_points, i) + next_fractal = array.get(fractal_points, i + 1) + + // 只连接不同类型的分型 + if current_fractal.fractal_type != next_fractal.fractal_type + // 检查距离限制 + distance = bar_index - current_fractal.bar_index + if distance <= 500 + new_line = line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=color.blue, width=2, style=line.style_solid) + array.push(bi_lines, new_line) + +// ================== 信息面板 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论最终版", text_color=color.black, text_size=size.small) + table.cell(info_table, 1, 0, "", text_color=color.black) + table.cell(info_table, 0, 1, "分型数", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(array.size(fractal_points)), text_color=color.black) + table.cell(info_table, 0, 2, "笔数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(bi_lines)), text_color=color.black) + table.cell(info_table, 0, 3, "间隔设置", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(min_bars_between), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_fixed.pine b/chan_theory_fixed.pine new file mode 100644 index 0000000..e110b9c --- /dev/null +++ b/chan_theory_fixed.pine @@ -0,0 +1,127 @@ +//@version=6 +indicator("缠论修复版", shorttitle="修复版", overlay=true, max_lines_count=100, max_labels_count=100) + +// 参数 +min_gap = input.int(3, "分型间隔", minval=1, maxval=20) +show_fractals = input.bool(true, "显示分型") +show_strokes = input.bool(true, "显示笔") +show_filtered = input.bool(true, "显示过滤后分型") + +// 数据类型 +type Fractal + int bar_index + float price + string type + bool is_valid + +// 全局变量 +var all_fractals = array.new() +var valid_fractals = array.new() +var stroke_lines = array.new() + +// 分型识别 +is_high = high[1] > high[0] and high[1] > high[2] +is_low = low[1] < low[0] and low[1] < low[2] + +// 距离检查 +distance_ok(new_bar) => + result = true + if array.size(all_fractals) > 0 + last_fractal = array.get(all_fractals, array.size(all_fractals) - 1) + if new_bar - last_fractal.bar_index < min_gap + result := false + result + +// 添加原始分型 +if is_high and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], high[1], "top", true) + array.push(all_fractals, new_fractal) + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +if is_low and distance_ok(bar_index[1]) + new_fractal = Fractal.new(bar_index[1], low[1], "bottom", true) + array.push(all_fractals, new_fractal) + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +// 显示原始分型 +if show_fractals + if is_high and distance_ok(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.tiny) + if is_low and distance_ok(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.tiny) + +// 每根K线更新 +if barstate.isconfirmed + // 清空有效分型数组 + array.clear(valid_fractals) + + // 应用结合律过滤分型 + if array.size(all_fractals) >= 1 + array.push(valid_fractals, array.get(all_fractals, 0)) + + i = 1 + while i < array.size(all_fractals) + current_fractal = array.get(all_fractals, i) + last_valid = array.get(valid_fractals, array.size(valid_fractals) - 1) + + if current_fractal.type != last_valid.type + array.push(valid_fractals, current_fractal) + i += 1 + else + extreme_fractal = current_fractal + j = i + 1 + while j < array.size(all_fractals) + next_fractal = array.get(all_fractals, j) + if next_fractal.type == current_fractal.type + if current_fractal.type == "top" + if next_fractal.price > extreme_fractal.price + extreme_fractal := next_fractal + else + if next_fractal.price < extreme_fractal.price + extreme_fractal := next_fractal + j += 1 + else + break + array.push(valid_fractals, extreme_fractal) + i := j + + // 清理旧笔 + if array.size(stroke_lines) > 0 + for k = 0 to array.size(stroke_lines) - 1 + line.delete(array.get(stroke_lines, k)) + array.clear(stroke_lines) + + // 绘制笔 + if show_strokes and array.size(valid_fractals) >= 2 + for m = 0 to array.size(valid_fractals) - 2 + current_fractal = array.get(valid_fractals, m) + next_fractal = array.get(valid_fractals, m + 1) + distance = bar_index - current_fractal.bar_index + if distance <= 500 + stroke_line = line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=color.blue, width=2) + array.push(stroke_lines, stroke_line) + +// 显示过滤后的分型 +if show_filtered and barstate.islast + for n = 0 to array.size(valid_fractals) - 1 + fractal = array.get(valid_fractals, n) + if fractal.type == "top" + label.new(fractal.bar_index, fractal.price, "T", color=color.yellow, style=label.style_label_down, size=size.small) + else + label.new(fractal.bar_index, fractal.price, "B", color=color.orange, style=label.style_label_up, size=size.small) + +// 信息显示 +if barstate.islast + var table info = table.new(position.top_right, 2, 5, bgcolor=color.white, border_width=1) + table.cell(info, 0, 0, "缠论修复版", text_color=color.black, text_size=size.small) + table.cell(info, 1, 0, "", text_color=color.black) + table.cell(info, 0, 1, "原始分型", text_color=color.black) + table.cell(info, 1, 1, str.tostring(array.size(all_fractals)), text_color=color.black) + table.cell(info, 0, 2, "有效分型", text_color=color.black) + table.cell(info, 1, 2, str.tostring(array.size(valid_fractals)), text_color=color.black) + table.cell(info, 0, 3, "笔数", text_color=color.black) + table.cell(info, 1, 3, str.tostring(array.size(stroke_lines)), text_color=color.black) + table.cell(info, 0, 4, "分型间隔", text_color=color.black) + table.cell(info, 1, 4, str.tostring(min_gap), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_optimized.pine b/chan_theory_optimized.pine new file mode 100644 index 0000000..d71135a --- /dev/null +++ b/chan_theory_optimized.pine @@ -0,0 +1,172 @@ +//@version=6 +indicator("缠论优化版", shorttitle="优化版", overlay=true, max_lines_count=100, max_labels_count=100) + +// 优化参数设置 +min_gap = input.int(8, "分型最小间隔", minval=5, maxval=20, tooltip="增大此值可减少分型数量") +strict_mode = input.bool(true, "严格分型模式", tooltip="开启后要求高低点都满足条件") +show_original = input.bool(false, "显示原始分型", tooltip="小标签显示所有分型") +show_valid = input.bool(true, "显示有效分型", tooltip="大标签显示过滤后分型") +show_strokes = input.bool(true, "显示笔连接", tooltip="蓝色粗线连接有效分型") +stroke_width = input.int(3, "笔线宽度", minval=1, maxval=5) + +// 数据类型 +type Fractal + int bar_index + float price + string type // "top" or "bottom" + bool is_extreme // 是否为极值点 + +// 全局变量 +var all_fractals = array.new() +var valid_fractals = array.new() +var stroke_lines = array.new() + +// 优化的分型识别 +check_fractal() => + top_found = false + bottom_found = false + + if strict_mode + // 严格模式:高低点都要满足条件 + if high[1] > high[0] and high[1] > high[2] and low[1] > low[0] and low[1] > low[2] + top_found := true + if low[1] < low[0] and low[1] < low[2] and high[1] < high[0] and high[1] < high[2] + bottom_found := true + else + // 宽松模式:只要高点或低点满足条件 + if high[1] > high[0] and high[1] > high[2] + top_found := true + if low[1] < low[0] and low[1] < low[2] + bottom_found := true + + [top_found, bottom_found] + +// 距离和类型检查 +distance_and_type_ok(new_bar, new_type) => + result = true + if array.size(all_fractals) > 0 + last_fractal = array.get(all_fractals, array.size(all_fractals) - 1) + distance = new_bar - last_fractal.bar_index + + // 距离检查 + if distance < min_gap + result := false + // 同类型分型需要更大间隔 + else if last_fractal.type == new_type and distance < min_gap * 1.5 + result := false + result + +[is_top, is_bottom] = check_fractal() + +// 添加分型 +if is_top and distance_and_type_ok(bar_index[1], "top") + new_fractal = Fractal.new(bar_index[1], high[1], "top", false) + array.push(all_fractals, new_fractal) + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +if is_bottom and distance_and_type_ok(bar_index[1], "bottom") + new_fractal = Fractal.new(bar_index[1], low[1], "bottom", false) + array.push(all_fractals, new_fractal) + if array.size(all_fractals) > 100 + array.shift(all_fractals) + +// 显示原始分型 +if show_original + if is_top and distance_and_type_ok(bar_index[1], "top") + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.tiny) + if is_bottom and distance_and_type_ok(bar_index[1], "bottom") + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.tiny) + +// 每根K线应用结合律过滤 +if barstate.isconfirmed + // 清空有效分型数组 + array.clear(valid_fractals) + + // 应用结合律过滤 + if array.size(all_fractals) > 0 + // 添加第一个分型 + array.push(valid_fractals, array.get(all_fractals, 0)) + + i = 1 + while i < array.size(all_fractals) + current = array.get(all_fractals, i) + last_valid = array.get(valid_fractals, array.size(valid_fractals) - 1) + + if current.type != last_valid.type + // 不同类型,直接添加 + array.push(valid_fractals, current) + i += 1 + else + // 相同类型,找到最极端的 + extreme = current + j = i + 1 + + // 向前搜索相同类型的分型 + while j < array.size(all_fractals) + next = array.get(all_fractals, j) + if next.type == current.type + // 比较极值 + if current.type == "top" + if next.price > extreme.price + extreme := next + else // bottom + if next.price < extreme.price + extreme := next + j += 1 + else + break + + // 添加极值分型 + array.push(valid_fractals, extreme) + i := j + + // 清理旧笔 + if array.size(stroke_lines) > 0 + for k = 0 to array.size(stroke_lines) - 1 + line.delete(array.get(stroke_lines, k)) + array.clear(stroke_lines) + + // 绘制新笔 + if show_strokes and array.size(valid_fractals) >= 2 + for m = 0 to array.size(valid_fractals) - 2 + current = array.get(valid_fractals, m) + next = array.get(valid_fractals, m + 1) + + // 检查距离限制 + distance = bar_index - current.bar_index + if distance <= 500 + line_color = current.type == "bottom" ? color.blue : color.navy + stroke_line = line.new(current.bar_index, current.price, next.bar_index, next.price, color=line_color, width=stroke_width) + array.push(stroke_lines, stroke_line) + +// 显示有效分型(大标签) +if show_valid and barstate.islast + for n = 0 to array.size(valid_fractals) - 1 + fractal = array.get(valid_fractals, n) + if fractal.type == "top" + label.new(fractal.bar_index, fractal.price, "T", color=color.yellow, style=label.style_label_down, size=size.normal, textcolor=color.black) + else + label.new(fractal.bar_index, fractal.price, "B", color=color.orange, style=label.style_label_up, size=size.normal, textcolor=color.black) + +// 优化的信息面板 +if barstate.islast + var table info = table.new(position.top_right, 2, 6, bgcolor=color.white, border_width=1) + table.cell(info, 0, 0, "缠论优化版", text_color=color.blue, text_size=size.normal) + table.cell(info, 1, 0, "", text_color=color.black) + table.cell(info, 0, 1, "原始分型", text_color=color.black) + table.cell(info, 1, 1, str.tostring(array.size(all_fractals)), text_color=color.green) + table.cell(info, 0, 2, "有效分型", text_color=color.black) + table.cell(info, 1, 2, str.tostring(array.size(valid_fractals)), text_color=color.red) + table.cell(info, 0, 3, "过滤率", text_color=color.black) + filter_rate = array.size(all_fractals) > 0 ? math.round((1 - array.size(valid_fractals) / array.size(all_fractals)) * 100) : 0 + table.cell(info, 1, 3, str.tostring(filter_rate) + "%", text_color=color.purple) + table.cell(info, 0, 4, "笔数", text_color=color.black) + table.cell(info, 1, 4, str.tostring(array.size(stroke_lines)), text_color=color.blue) + table.cell(info, 0, 5, "分型间隔", text_color=color.black) + table.cell(info, 1, 5, str.tostring(min_gap), text_color=color.gray) + +// 质量检查:理论上笔数应该 = 有效分型数 - 1 +quality_check = array.size(valid_fractals) > 0 ? array.size(stroke_lines) == (array.size(valid_fractals) - 1) : true +if barstate.islast and not quality_check + label.new(bar_index, high, "⚠️质量检查失败", color=color.red, style=label.style_label_down, size=size.large) \ No newline at end of file diff --git a/chan_theory_perfect.pine b/chan_theory_perfect.pine new file mode 100644 index 0000000..a02c32f --- /dev/null +++ b/chan_theory_perfect.pine @@ -0,0 +1,168 @@ +//@version=6 +indicator("缠论完美版", shorttitle="完美版", overlay=true, max_lines_count=100, max_labels_count=100) + +// 参数设置 +min_gap = input.int(10, "分型间隔", minval=5, maxval=30) +show_debug = input.bool(false, "显示调试信息") +show_strokes = input.bool(true, "显示笔") + +// 数据类型 +type Fractal + int bar_index + float price + string type + +// 全局变量 +var raw_fractals = array.new() +var final_fractals = array.new() +var strokes = array.new() + +// 安全的分型识别 - 添加历史数据检查 +is_top = bar_index >= 2 and high[1] > high[0] and high[1] > high[2] and low[1] > low[0] and low[1] > low[2] +is_bottom = bar_index >= 2 and low[1] < low[0] and low[1] < low[2] and high[1] < high[0] and high[1] < high[2] + +// 距离检查 +valid_distance(new_bar) => + result = true + if array.size(raw_fractals) > 0 + last = array.get(raw_fractals, array.size(raw_fractals) - 1) + if new_bar - last.bar_index < min_gap + result := false + result + +// 添加原始分型 - 简化条件检查 +if is_top and valid_distance(bar_index[1]) + array.push(raw_fractals, Fractal.new(bar_index[1], high[1], "top")) + if array.size(raw_fractals) > 50 // 减少数组大小限制 + array.shift(raw_fractals) + +if is_bottom and valid_distance(bar_index[1]) + array.push(raw_fractals, Fractal.new(bar_index[1], low[1], "bottom")) + if array.size(raw_fractals) > 50 // 减少数组大小限制 + array.shift(raw_fractals) + +// 显示原始分型(调试) +if show_debug + if is_top and valid_distance(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.tiny) + if is_bottom and valid_distance(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.tiny) + +// 核心:结合律过滤 - 添加更多安全检查 +if barstate.isconfirmed and array.size(raw_fractals) > 0 + // 重新构建有效分型 + array.clear(final_fractals) + + // 第一个分型 + array.push(final_fractals, array.get(raw_fractals, 0)) + + // 从第二个开始处理 + if array.size(raw_fractals) > 1 + i = 1 + while i < array.size(raw_fractals) + current = array.get(raw_fractals, i) + + if array.size(final_fractals) > 0 + last_final = array.get(final_fractals, array.size(final_fractals) - 1) + + if current.type != last_final.type + // 不同类型:直接加入 + array.push(final_fractals, current) + i += 1 + else + // 相同类型:找最极端的 + extreme = current + j = i + 1 + + // 扫描后续同类型分型 + while j < array.size(raw_fractals) + next = array.get(raw_fractals, j) + if next.type == current.type + if current.type == "top" + if next.price > extreme.price + extreme := next + else + if next.price < extreme.price + extreme := next + j += 1 + else + break + + // 加入极值分型 + array.push(final_fractals, extreme) + i := j + else + // 如果final_fractals为空,直接添加 + array.push(final_fractals, current) + i += 1 + + // 重绘笔 - 修复统计问题 + if array.size(strokes) > 0 + for k = 0 to array.size(strokes) - 1 + line.delete(array.get(strokes, k)) + array.clear(strokes) + + if show_strokes and array.size(final_fractals) >= 2 + for m = 0 to array.size(final_fractals) - 2 + f1 = array.get(final_fractals, m) + f2 = array.get(final_fractals, m + 1) + + // 放宽距离限制,确保所有笔都能绘制 + distance_from_current = bar_index - f1.bar_index + if distance_from_current <= 500 and distance_from_current >= 0 // 恢复到500根K线 + color_line = f1.type == "bottom" ? color.blue : color.red + line_obj = line.new(f1.bar_index, f1.price, f2.bar_index, f2.price, color=color_line, width=3) + array.push(strokes, line_obj) + +// 显示最终分型 - 添加距离检查 +if barstate.islast and array.size(final_fractals) > 0 + for n = 0 to array.size(final_fractals) - 1 + frac = array.get(final_fractals, n) + distance_from_current = bar_index - frac.bar_index + if distance_from_current <= 500 // 恢复到500根K线 + if frac.type == "top" + label.new(frac.bar_index, frac.price, "T", color=color.yellow, style=label.style_label_down, size=size.normal) + else + label.new(frac.bar_index, frac.price, "B", color=color.orange, style=label.style_label_up, size=size.normal) + +// 改进的信息统计 +if barstate.islast + var table info = table.new(position.top_right, 2, 7, bgcolor=color.white, border_width=1) + + raw_count = array.size(raw_fractals) + final_count = array.size(final_fractals) + stroke_count = array.size(strokes) + theoretical_strokes = final_count > 0 ? final_count - 1 : 0 + filter_percent = raw_count > 0 ? math.round((raw_count - final_count) * 100 / raw_count) : 0 + + // 计算实际可绘制的笔数 + drawable_strokes = 0 + if array.size(final_fractals) >= 2 + for m = 0 to array.size(final_fractals) - 2 + f1 = array.get(final_fractals, m) + distance_from_current = bar_index - f1.bar_index + if distance_from_current <= 500 and distance_from_current >= 0 + drawable_strokes += 1 + + table.cell(info, 0, 0, "缠论完美版", text_color=color.blue, text_size=size.normal) + table.cell(info, 1, 0, "V1.2", text_color=color.gray) + + table.cell(info, 0, 1, "原始分型", text_color=color.black) + table.cell(info, 1, 1, str.tostring(raw_count), text_color=color.green) + + table.cell(info, 0, 2, "有效分型", text_color=color.black) + table.cell(info, 1, 2, str.tostring(final_count), text_color=color.red) + + table.cell(info, 0, 3, "过滤率", text_color=color.black) + table.cell(info, 1, 3, str.tostring(filter_percent) + "%", text_color=color.purple) + + table.cell(info, 0, 4, "笔数", text_color=color.black) + table.cell(info, 1, 4, str.tostring(stroke_count), text_color=color.blue) + + table.cell(info, 0, 5, "可绘制笔", text_color=color.black) + table.cell(info, 1, 5, str.tostring(drawable_strokes), text_color=color.gray) + + table.cell(info, 0, 6, "状态", text_color=color.black) + status = stroke_count == drawable_strokes ? "✓正常" : "✗异常" + status_color = stroke_count == drawable_strokes ? color.green : color.red + table.cell(info, 1, 6, status, text_color=status_color) \ No newline at end of file diff --git a/chan_theory_simple.pine b/chan_theory_simple.pine new file mode 100644 index 0000000..257dd5d --- /dev/null +++ b/chan_theory_simple.pine @@ -0,0 +1,191 @@ +//@version=6 +indicator("缠论精简版", shorttitle="缠论", overlay=true, max_lines_count=100, max_labels_count=100) + +// ================== 输入参数 ================== +show_fractal = input.bool(true, "显示分型", group="显示") +show_stroke = input.bool(true, "显示笔", group="显示") +show_hub = input.bool(true, "显示中枢", group="显示") +show_signals = input.bool(true, "显示买卖点", group="显示") + +fractal_length = input.int(3, "分型周期", minval=3, maxval=10, group="参数") +stroke_color = input.color(color.blue, "笔颜色", group="颜色") +hub_color = input.color(color.gray, "中枢颜色", group="颜色") + +// ================== 分型识别 ================== +// 顶分型 +top_fractal = ta.pivothigh(high, fractal_length, fractal_length) +// 底分型 +bottom_fractal = ta.pivotlow(low, fractal_length, fractal_length) + +// ================== 存储分型数据 ================== +var fractal_highs = array.new() +var fractal_lows = array.new() +var fractal_high_bars = array.new() +var fractal_low_bars = array.new() + +// 记录新的分型 +if not na(top_fractal) + array.push(fractal_highs, top_fractal) + array.push(fractal_high_bars, bar_index - fractal_length) + + // 保持数组大小 + if array.size(fractal_highs) > 50 + array.shift(fractal_highs) + array.shift(fractal_high_bars) + +if not na(bottom_fractal) + array.push(fractal_lows, bottom_fractal) + array.push(fractal_low_bars, bar_index - fractal_length) + + // 保持数组大小 + if array.size(fractal_lows) > 50 + array.shift(fractal_lows) + array.shift(fractal_low_bars) + +// ================== 显示分型 ================== +if show_fractal + // 顶分型标记 + if not na(top_fractal) + label.new(bar_index - fractal_length, top_fractal, "T", + color=color.red, style=label.style_label_down, size=size.tiny) + + // 底分型标记 + if not na(bottom_fractal) + label.new(bar_index - fractal_length, bottom_fractal, "B", + color=color.green, style=label.style_label_up, size=size.tiny) + +// ================== 笔的构建 ================== +var strokes = array.new() + +// 构建笔 +build_strokes() => + if array.size(fractal_highs) >= 1 and array.size(fractal_lows) >= 1 + high_size = array.size(fractal_highs) + low_size = array.size(fractal_lows) + + last_high = array.get(fractal_highs, high_size - 1) + last_low = array.get(fractal_lows, low_size - 1) + last_high_bar = array.get(fractal_high_bars, high_size - 1) + last_low_bar = array.get(fractal_low_bars, low_size - 1) + + // 根据最后的分型连接笔 + if last_high_bar > last_low_bar + // 最后是顶分型,连接到前一个底分型 + if low_size >= 2 + prev_low = array.get(fractal_lows, low_size - 2) + prev_low_bar = array.get(fractal_low_bars, low_size - 2) + + if show_stroke + new_line = line.new(prev_low_bar, prev_low, last_high_bar, last_high, + color=stroke_color, width=2) + array.push(strokes, new_line) + else + // 最后是底分型,连接到前一个顶分型 + if high_size >= 2 + prev_high = array.get(fractal_highs, high_size - 2) + prev_high_bar = array.get(fractal_high_bars, high_size - 2) + + if show_stroke + new_line = line.new(prev_high_bar, prev_high, last_low_bar, last_low, + color=stroke_color, width=2) + array.push(strokes, new_line) + +// 执行笔构建 +if not na(top_fractal) or not na(bottom_fractal) + build_strokes() + +// ================== 中枢识别 ================== +var hubs = array.new() + +identify_hubs() => + if array.size(fractal_highs) >= 3 and array.size(fractal_lows) >= 3 + // 简化的中枢识别:连续三个分型的重叠区域 + high_size = array.size(fractal_highs) + low_size = array.size(fractal_lows) + + if high_size >= 2 and low_size >= 2 + h1 = array.get(fractal_highs, high_size - 2) + h2 = array.get(fractal_highs, high_size - 1) + l1 = array.get(fractal_lows, low_size - 2) + l2 = array.get(fractal_lows, low_size - 1) + + hub_high = math.min(h1, h2) + hub_low = math.max(l1, l2) + + if hub_high > hub_low + start_bar = math.min(array.get(fractal_high_bars, high_size - 2), + array.get(fractal_low_bars, low_size - 2)) + end_bar = math.max(array.get(fractal_high_bars, high_size - 1), + array.get(fractal_low_bars, low_size - 1)) + + if show_hub + hub_box = box.new(start_bar, hub_high, end_bar, hub_low, + border_color=hub_color, bgcolor=color.new(hub_color, 85)) + array.push(hubs, hub_box) + +// 执行中枢识别 +if barstate.islast and (not na(top_fractal) or not na(bottom_fractal)) + identify_hubs() + +// ================== 买卖点信号 ================== +var buy_point = false +var sell_point = false + +// 简化的买卖点逻辑 +if array.size(fractal_lows) >= 2 and array.size(hubs) >= 1 + current_low = array.get(fractal_lows, array.size(fractal_lows) - 1) + + if array.size(hubs) > 0 + latest_hub = array.get(hubs, array.size(hubs) - 1) + hub_low = box.get_bottom(latest_hub) + + // 跌破中枢下沿的买点 + if current_low < hub_low + buy_point := true + +if array.size(fractal_highs) >= 2 and array.size(hubs) >= 1 + current_high = array.get(fractal_highs, array.size(fractal_highs) - 1) + + if array.size(hubs) > 0 + latest_hub = array.get(hubs, array.size(hubs) - 1) + hub_high = box.get_top(latest_hub) + + // 突破中枢上沿的卖点 + if current_high > hub_high + sell_point := true + +// 显示买卖点 +if show_signals + if buy_point and not na(bottom_fractal) + label.new(bar_index - fractal_length, bottom_fractal, "买", + color=color.green, style=label.style_label_up, size=size.normal) + + if sell_point and not na(top_fractal) + label.new(bar_index - fractal_length, top_fractal, "卖", + color=color.red, style=label.style_label_down, size=size.normal) + +// ================== 清理旧对象 ================== +// 限制绘图对象数量,避免超出限制 +if array.size(strokes) > 30 + old_line = array.shift(strokes) + line.delete(old_line) + +if array.size(hubs) > 10 + old_hub = array.shift(hubs) + box.delete(old_hub) + +// ================== 警报 ================== +alertcondition(buy_point and not na(bottom_fractal), title="缠论买点", message="发现买入信号") +alertcondition(sell_point and not na(top_fractal), title="缠论卖点", message="发现卖出信号") + +// ================== 状态显示 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论状态", text_color=color.black, text_size=size.small) + table.cell(info_table, 1, 0, "", text_color=color.black) + table.cell(info_table, 0, 1, "顶分型", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(array.size(fractal_highs)), text_color=color.black) + table.cell(info_table, 0, 2, "底分型", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(fractal_lows)), text_color=color.black) + table.cell(info_table, 0, 3, "中枢数", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(array.size(hubs)), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_simple_test.pine b/chan_theory_simple_test.pine new file mode 100644 index 0000000..3ec7cb5 --- /dev/null +++ b/chan_theory_simple_test.pine @@ -0,0 +1,89 @@ +//@version=6 +indicator("缠论简化测试", shorttitle="缠论测试", overlay=true, max_lines_count=100, max_labels_count=100) + +// ================== 参数设置 ================== +show_fenxing = input.bool(true, "显示分型", group="显示设置") +show_bi = input.bool(true, "显示笔", group="显示设置") +min_bars_between = input.int(8, "分型最小间隔", minval=5, maxval=20, group="缠论参数") + +// ================== 数据类型定义 ================== +type FractalPoint + int bar_index + float price + string fractal_type + +// ================== 全局变量 ================== +var fractal_points = array.new() +var bi_lines = array.new() + +// ================== 简单分型识别(严格模式)================== +// 严格分型:高点和低点都要满足条件 +is_top_fractal = high[1] > high[0] and high[1] > high[2] and low[1] > low[0] and low[1] > low[2] +is_bottom_fractal = high[1] < high[0] and high[1] < high[2] and low[1] < low[0] and low[1] < low[2] + +// ================== 距离过滤 ================== +distance_ok(new_bar) => + result = true + if array.size(fractal_points) > 0 + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + bar_distance = new_bar - last_fractal.bar_index + if bar_distance < min_bars_between + result := false + result + +// ================== 添加分型 ================== +if is_top_fractal and distance_ok(bar_index[1]) + new_fractal = FractalPoint.new(bar_index[1], high[1], "top") + array.push(fractal_points, new_fractal) + + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +if is_bottom_fractal and distance_ok(bar_index[1]) + new_fractal = FractalPoint.new(bar_index[1], low[1], "bottom") + array.push(fractal_points, new_fractal) + + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +// ================== 显示分型 ================== +if show_fenxing + if is_top_fractal and distance_ok(bar_index[1]) + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.small) + + if is_bottom_fractal and distance_ok(bar_index[1]) + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.small) + +// ================== 重新构建所有笔 ================== +if barstate.islast + // 清理旧笔 + if array.size(bi_lines) > 0 + for i = 0 to array.size(bi_lines) - 1 + line.delete(array.get(bi_lines, i)) + array.clear(bi_lines) + + // 重新构建所有笔 + if array.size(fractal_points) >= 2 and show_bi + for i = 0 to array.size(fractal_points) - 2 + current_fractal = array.get(fractal_points, i) + next_fractal = array.get(fractal_points, i + 1) + + // 只连接不同类型的分型 + if current_fractal.fractal_type != next_fractal.fractal_type + // 检查距离限制 + distance = bar_index - current_fractal.bar_index + if distance <= 500 + new_line = line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=color.blue, width=2, style=line.style_solid) + array.push(bi_lines, new_line) + +// ================== 信息面板 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论简化测试", text_color=color.black, text_size=size.small) + table.cell(info_table, 1, 0, "", text_color=color.black) + table.cell(info_table, 0, 1, "分型数", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(array.size(fractal_points)), text_color=color.black) + table.cell(info_table, 0, 2, "笔数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(bi_lines)), text_color=color.black) + table.cell(info_table, 0, 3, "间隔设置", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(min_bars_between), text_color=color.black) \ No newline at end of file diff --git a/chan_theory_simple_v2.pine b/chan_theory_simple_v2.pine new file mode 100644 index 0000000..ccfd6a8 --- /dev/null +++ b/chan_theory_simple_v2.pine @@ -0,0 +1,206 @@ +//@version=6 +indicator("缠论简化版V2", shorttitle="缠论V2", overlay=true, max_lines_count=100, max_labels_count=100) + +// ================== 参数设置 ================== +show_fenxing = input.bool(true, "显示分型", group="显示设置") +show_bi = input.bool(true, "显示笔", group="显示设置") +show_zhongshu = input.bool(true, "显示中枢", group="显示设置") +show_signals = input.bool(true, "显示买卖点", group="显示设置") + +// 缠论参数 +fractal_length = input.int(2, "分型识别周期", minval=1, maxval=5, group="缠论参数") +min_bars_between = input.int(5, "分型最小间隔", minval=3, maxval=20, group="缠论参数") +bi_color = input.color(color.blue, "笔的颜色", group="颜色设置") +zhongshu_color = input.color(color.gray, "中枢颜色", group="颜色设置") + +// ================== 数据类型定义 ================== +type FractalPoint + int bar_index + float price + string fractal_type // "top" or "bottom" + +// ================== 全局变量 ================== +var fractal_points = array.new() +var bi_lines = array.new() +var zhongshu_boxes = array.new() + +// ================== 分型识别 ================== +// 检查基本分型条件 +is_basic_top_fractal = fractal_length > 0 and + high[fractal_length] > high[fractal_length-1] and + high[fractal_length] > high[fractal_length+1] and + low[fractal_length] > low[fractal_length-1] and + low[fractal_length] > low[fractal_length+1] + +is_basic_bottom_fractal = fractal_length > 0 and + low[fractal_length] < low[fractal_length-1] and + low[fractal_length] < low[fractal_length+1] and + high[fractal_length] < high[fractal_length-1] and + high[fractal_length] < high[fractal_length+1] + +// 检查距离过滤 +check_distance_filter(new_bar, new_type) => + if array.size(fractal_points) == 0 + true + else + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + bar_distance = new_bar - last_fractal.bar_index + + // 如果距离太近,则不添加新分型 + if bar_distance < min_bars_between + false + // 如果是相同类型且距离不够远,也不添加 + else if last_fractal.fractal_type == new_type and bar_distance < min_bars_between * 2 + false + else + true + +// ================== 添加分型 ================== +current_bar = bar_index - fractal_length + +// 检查顶分型 +if is_basic_top_fractal and check_distance_filter(current_bar, "top") + new_fractal = FractalPoint.new(current_bar, high[fractal_length], "top") + array.push(fractal_points, new_fractal) + + // 保持数组大小 + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +// 检查底分型 +if is_basic_bottom_fractal and check_distance_filter(current_bar, "bottom") + new_fractal = FractalPoint.new(current_bar, low[fractal_length], "bottom") + array.push(fractal_points, new_fractal) + + // 保持数组大小 + if array.size(fractal_points) > 50 + array.shift(fractal_points) + +// ================== 显示分型 ================== +if show_fenxing + if is_basic_top_fractal and check_distance_filter(current_bar, "top") + label.new(current_bar, high[fractal_length], "T", + color=color.red, style=label.style_label_down, size=size.small) + + if is_basic_bottom_fractal and check_distance_filter(current_bar, "bottom") + label.new(current_bar, low[fractal_length], "B", + color=color.green, style=label.style_label_up, size=size.small) + +// ================== 构建笔 ================== +// 重建所有笔(当有新分型时) +rebuild_bi() => + // 清空现有笔 + for i = 0 to array.size(bi_lines) - 1 + line.delete(array.get(bi_lines, i)) + array.clear(bi_lines) + + // 构建新笔 + if array.size(fractal_points) >= 2 + for i = 0 to array.size(fractal_points) - 2 + current_fractal = array.get(fractal_points, i) + next_fractal = array.get(fractal_points, i + 1) + + // 连接相邻的反向分型 + if current_fractal.fractal_type != next_fractal.fractal_type and show_bi + new_line = line.new( + current_fractal.bar_index, current_fractal.price, + next_fractal.bar_index, next_fractal.price, + color=bi_color, width=2, style=line.style_solid) + array.push(bi_lines, new_line) + +// 当分型数组发生变化时重建笔 +var last_fractal_count = 0 +current_fractal_count = array.size(fractal_points) + +if current_fractal_count != last_fractal_count + rebuild_bi() + last_fractal_count := current_fractal_count + +// ================== 中枢识别 ================== +// 简化的中枢识别 +if array.size(bi_lines) >= 3 and show_zhongshu + // 检查最近是否需要添加新中枢 + if array.size(bi_lines) >= 3 + line1 = array.get(bi_lines, array.size(bi_lines) - 3) + line2 = array.get(bi_lines, array.size(bi_lines) - 2) + line3 = array.get(bi_lines, array.size(bi_lines) - 1) + + // 获取价格区间 + h1 = math.max(line.get_y1(line1), line.get_y2(line1)) + l1 = math.min(line.get_y1(line1), line.get_y2(line1)) + h2 = math.max(line.get_y1(line2), line.get_y2(line2)) + l2 = math.min(line.get_y1(line2), line.get_y2(line2)) + h3 = math.max(line.get_y1(line3), line.get_y2(line3)) + l3 = math.min(line.get_y1(line3), line.get_y2(line3)) + + // 计算重叠区域 + overlap_high = math.min(math.min(h1, h2), h3) + overlap_low = math.max(math.max(l1, l2), l3) + + // 形成中枢 + if overlap_high > overlap_low + start_bar = math.min(line.get_x1(line1), line.get_x2(line1)) + end_bar = math.max(line.get_x1(line3), line.get_x2(line3)) + + // 检查是否需要添加新中枢 + should_add = true + if array.size(zhongshu_boxes) > 0 + last_box = array.get(zhongshu_boxes, array.size(zhongshu_boxes) - 1) + if math.abs(box.get_right(last_box) - end_bar) < 10 + should_add := false + + if should_add + zs_box = box.new(start_bar, overlap_high, end_bar, overlap_low, + border_color=zhongshu_color, + bgcolor=color.new(zhongshu_color, 80)) + array.push(zhongshu_boxes, zs_box) + +// ================== 买卖点识别 ================== +var last_signal_bar = 0 + +if array.size(zhongshu_boxes) > 0 and array.size(fractal_points) > 0 and show_signals + latest_zs = array.get(zhongshu_boxes, array.size(zhongshu_boxes) - 1) + zs_high = box.get_top(latest_zs) + zs_low = box.get_bottom(latest_zs) + zs_right = box.get_right(latest_zs) + + // 检查最新分型 + if array.size(fractal_points) > 0 + latest_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + + // 确保信号间隔 + if latest_fractal.bar_index > last_signal_bar + 5 and latest_fractal.bar_index > zs_right + // 买点:底分型跌破中枢下沿 + if latest_fractal.fractal_type == "bottom" and latest_fractal.price < zs_low + label.new(latest_fractal.bar_index, latest_fractal.price, "买", + color=color.green, style=label.style_label_up, size=size.normal) + last_signal_bar := latest_fractal.bar_index + + // 卖点:顶分型突破中枢上沿 + if latest_fractal.fractal_type == "top" and latest_fractal.price > zs_high + label.new(latest_fractal.bar_index, latest_fractal.price, "卖", + color=color.red, style=label.style_label_down, size=size.normal) + last_signal_bar := latest_fractal.bar_index + +// ================== 清理旧对象 ================== +if array.size(zhongshu_boxes) > 10 + old_box = array.shift(zhongshu_boxes) + box.delete(old_box) + +// ================== 信息面板 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论V2", text_color=color.black, text_size=size.small) + table.cell(info_table, 1, 0, "", text_color=color.black) + table.cell(info_table, 0, 1, "分型数", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(array.size(fractal_points)), text_color=color.black) + table.cell(info_table, 0, 2, "笔数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(bi_lines)), text_color=color.black) + table.cell(info_table, 0, 3, "中枢数", text_color=color.black) + table.cell(info_table, 1, 3, str.tostring(array.size(zhongshu_boxes)), text_color=color.black) + +// ================== 警报 ================== +alertcondition(is_basic_bottom_fractal and check_distance_filter(current_bar, "bottom"), + title="缠论买点", message="发现底分型") +alertcondition(is_basic_top_fractal and check_distance_filter(current_bar, "top"), + title="缠论卖点", message="发现顶分型") \ No newline at end of file diff --git a/chan_theory_simple_v3.pine b/chan_theory_simple_v3.pine new file mode 100644 index 0000000..02f90bd --- /dev/null +++ b/chan_theory_simple_v3.pine @@ -0,0 +1,371 @@ +//@version=6 +indicator("缠论标准版V3", shorttitle="缠论标准V3", overlay=true, max_lines_count=200, max_labels_count=200) + +// ================== 参数设置 ================== +show_merged_k = input.bool(true, "显示合并K线", group="显示设置") +show_fenxing = input.bool(true, "显示分型", group="显示设置") +show_bi = input.bool(true, "显示笔", group="显示设置") +show_xianduan = input.bool(true, "显示线段", group="显示设置") +show_zhongshu = input.bool(true, "显示中枢", group="显示设置") +show_signals = input.bool(true, "显示买卖点", group="显示设置") +debug_mode = input.bool(false, "调试模式(禁用分型间隔过滤)", group="显示设置") + +// 缠论参数 +fractal_length = input.int(1, "分型识别周期", minval=1, maxval=3, group="缠论参数") +min_bars_between = input.int(2, "分型最小间隔", minval=1, maxval=20, group="缠论参数") +strict_fractal = input.bool(false, "严格分型模式", group="缠论参数") +bi_color = input.color(color.blue, "笔的颜色", group="颜色设置") +xianduan_color = input.color(color.red, "线段颜色", group="颜色设置") +zhongshu_color = input.color(color.gray, "中枢颜色", group="颜色设置") +merged_k_color = input.color(color.orange, "合并K线颜色", group="颜色设置") + +// ================== 数据类型定义 ================== +type MergedK + int bar_index + float high + float low + float open + float close + int direction // 1: 向上, -1: 向下, 0: 未确定 + +type FractalPoint + int bar_index + float price + string fractal_type + bool confirmed + +type BiSegment + FractalPoint start_point + FractalPoint end_point + int direction + +type XianDuan + array bi_segments + FractalPoint start_point + FractalPoint end_point + bool broken + +// ================== 全局变量 ================== +var merged_ks = array.new() +var fractal_points = array.new() +var bi_segments = array.new() +var xianduan_segments = array.new() +var bi_lines = array.new() +var xianduan_lines = array.new() +var zhongshu_boxes = array.new() +var merged_k_lines = array.new() +var last_signal_bar = 0 +var current_trend = 0 // 当前趋势方向 + +// ================== K线合并处理 ================== +// 判断是否存在包含关系 +is_contained(k1_high, k1_low, k2_high, k2_low) => + (k1_high >= k2_high and k1_low <= k2_low) or (k2_high >= k1_high and k2_low <= k1_low) + +// 执行K线合并 +if barstate.isconfirmed + current_k = MergedK.new(bar_index, high, low, open, close, 0) + + if array.size(merged_ks) == 0 + array.push(merged_ks, current_k) + else + last_k = array.get(merged_ks, array.size(merged_ks) - 1) + + // 检查包含关系 + if is_contained(last_k.high, last_k.low, current_k.high, current_k.low) + // 存在包含关系,需要合并 + merged_high = 0.0 + merged_low = 0.0 + + // 根据趋势方向确定合并规则 + if current_trend > 0 // 向上趋势 + merged_high := math.max(last_k.high, current_k.high) + merged_low := math.max(last_k.low, current_k.low) + else if current_trend < 0 // 向下趋势 + merged_high := math.min(last_k.high, current_k.high) + merged_low := math.min(last_k.low, current_k.low) + else // 趋势未确定,按第一根K线方向 + if last_k.close > last_k.open // 阳线趋势 + merged_high := math.max(last_k.high, current_k.high) + merged_low := math.max(last_k.low, current_k.low) + else // 阴线趋势 + merged_high := math.min(last_k.high, current_k.high) + merged_low := math.min(last_k.low, current_k.low) + + // 更新最后一个合并K线 + last_k.high := merged_high + last_k.low := merged_low + last_k.close := current_k.close + last_k.bar_index := current_k.bar_index + else + // 无包含关系,直接添加 + array.push(merged_ks, current_k) + + // 更新趋势方向 + if array.size(merged_ks) >= 2 + prev_k = array.get(merged_ks, array.size(merged_ks) - 2) + if current_k.high > prev_k.high + current_trend := 1 + else if current_k.low < prev_k.low + current_trend := -1 + + // 限制数组大小 + if array.size(merged_ks) > 1000 + array.shift(merged_ks) + +// ================== 分型识别(基于合并K线)================== +// 标准分型识别 +check_fractal_from_merged() => + var top_fractal = false + var bottom_fractal = false + var fractal_bar = 0 + var fractal_high = 0.0 + var fractal_low = 0.0 + + if array.size(merged_ks) >= 3 + // 检查最近三根合并K线 + k1 = array.get(merged_ks, array.size(merged_ks) - 3) + k2 = array.get(merged_ks, array.size(merged_ks) - 2) + k3 = array.get(merged_ks, array.size(merged_ks) - 1) + + if strict_fractal + // 严格分型:中间K线的高低点都比左右K线高/低 + if k2.high > k1.high and k2.high > k3.high and k2.low > k1.low and k2.low > k3.low + top_fractal := true + fractal_bar := k2.bar_index + fractal_high := k2.high + + if k2.high < k1.high and k2.high < k3.high and k2.low < k1.low and k2.low < k3.low + bottom_fractal := true + fractal_bar := k2.bar_index + fractal_low := k2.low + else + // 宽松分型:只要高点或低点满足条件即可 + if k2.high > k1.high and k2.high > k3.high + top_fractal := true + fractal_bar := k2.bar_index + fractal_high := k2.high + + if k2.low < k1.low and k2.low < k3.low + bottom_fractal := true + fractal_bar := k2.bar_index + fractal_low := k2.low + + [top_fractal, bottom_fractal, fractal_bar, fractal_high, fractal_low] + +[is_top_fractal, is_bottom_fractal, fractal_bar_index, fractal_high_price, fractal_low_price] = check_fractal_from_merged() + +// 检查距离过滤 +distance_ok(new_bar, new_type) => + if debug_mode + true + else + result = true + if array.size(fractal_points) > 0 + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + bar_distance = new_bar - last_fractal.bar_index + if bar_distance < min_bars_between + result := false + result + +// ================== 添加分型 ================== +var bool fractal_added = false +fractal_added := false + +if is_top_fractal and distance_ok(fractal_bar_index, "top") + new_fractal = FractalPoint.new(fractal_bar_index, fractal_high_price, "top", true) + array.push(fractal_points, new_fractal) + fractal_added := true + + if array.size(fractal_points) > 100 + array.shift(fractal_points) + +if is_bottom_fractal and distance_ok(fractal_bar_index, "bottom") + new_fractal = FractalPoint.new(fractal_bar_index, fractal_low_price, "bottom", true) + array.push(fractal_points, new_fractal) + fractal_added := true + + if array.size(fractal_points) > 100 + array.shift(fractal_points) + +// ================== 显示合并K线 ================== +if show_merged_k and array.size(merged_ks) >= 2 + // 清理旧线条 + if array.size(merged_k_lines) > 0 + for i = 0 to array.size(merged_k_lines) - 1 + line.delete(array.get(merged_k_lines, i)) + array.clear(merged_k_lines) + + // 绘制合并K线连线 + for i = 0 to array.size(merged_ks) - 2 + k1 = array.get(merged_ks, i) + k2 = array.get(merged_ks, i + 1) + + // 检查距离限制 + k_distance = bar_index - k1.bar_index + if k_distance <= 500 + high_line = line.new(k1.bar_index, k1.high, k2.bar_index, k2.high, color=merged_k_color, width=1, style=line.style_dashed) + low_line = line.new(k1.bar_index, k1.low, k2.bar_index, k2.low, color=merged_k_color, width=1, style=line.style_dashed) + array.push(merged_k_lines, high_line) + array.push(merged_k_lines, low_line) + +// ================== 显示分型 ================== +if show_fenxing + if is_top_fractal and distance_ok(fractal_bar_index, "top") + label.new(fractal_bar_index, fractal_high_price, "顶", color=color.red, style=label.style_label_down, size=size.small) + + if is_bottom_fractal and distance_ok(fractal_bar_index, "bottom") + label.new(fractal_bar_index, fractal_low_price, "底", color=color.green, style=label.style_label_up, size=size.small) + +// ================== 构建笔 ================== +// 在每根K线重新构建所有笔 +if barstate.isconfirmed + // 清理旧笔 + if array.size(bi_lines) > 0 + for i = 0 to array.size(bi_lines) - 1 + line.delete(array.get(bi_lines, i)) + array.clear(bi_lines) + array.clear(bi_segments) + + // 重新构建所有笔 + if array.size(fractal_points) >= 2 and show_bi + for i = 0 to array.size(fractal_points) - 2 + current_fractal = array.get(fractal_points, i) + next_fractal = array.get(fractal_points, i + 1) + + // 只连接不同类型的分型 + if current_fractal.fractal_type != next_fractal.fractal_type + // 确定方向 + direction = current_fractal.fractal_type == "bottom" ? 1 : -1 + + // 创建笔段 + bi_seg = BiSegment.new(current_fractal, next_fractal, direction) + array.push(bi_segments, bi_seg) + + // 检查距离限制 + distance = bar_index - current_fractal.bar_index + if distance <= 500 + new_line = line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=bi_color, width=2, style=line.style_solid) + array.push(bi_lines, new_line) + +// ================== 线段识别 ================== +// 在每根K线重新构建线段 +if barstate.isconfirmed and array.size(bi_segments) >= 3 + // 清理旧线段 + if array.size(xianduan_lines) > 0 + for i = 0 to array.size(xianduan_lines) - 1 + line.delete(array.get(xianduan_lines, i)) + array.clear(xianduan_lines) + array.clear(xianduan_segments) + + // 每三笔构建一个线段 + segment_count = array.size(bi_segments) // 3 + for j = 0 to segment_count - 1 + start_idx = j * 3 + if start_idx + 2 < array.size(bi_segments) + bi1 = array.get(bi_segments, start_idx) + bi2 = array.get(bi_segments, start_idx + 1) + bi3 = array.get(bi_segments, start_idx + 2) + + // 创建线段 + bi_array = array.new() + array.push(bi_array, bi1) + array.push(bi_array, bi2) + array.push(bi_array, bi3) + xianduan = XianDuan.new(bi_array, bi1.start_point, bi3.end_point, false) + array.push(xianduan_segments, xianduan) + + // 绘制线段 + if show_xianduan + xianduan_distance = bar_index - bi1.start_point.bar_index + if xianduan_distance <= 500 + xianduan_line = line.new(bi1.start_point.bar_index, bi1.start_point.price, bi3.end_point.bar_index, bi3.end_point.price, color=xianduan_color, width=3, style=line.style_solid) + array.push(xianduan_lines, xianduan_line) + +// ================== 中枢识别(基于笔的重叠)================== +if barstate.isconfirmed and array.size(bi_segments) >= 3 and show_zhongshu + // 清理旧中枢 + if array.size(zhongshu_boxes) > 0 + for i = 0 to array.size(zhongshu_boxes) - 1 + box.delete(array.get(zhongshu_boxes, i)) + array.clear(zhongshu_boxes) + + // 为每三笔检查中枢 + for k = 0 to array.size(bi_segments) - 3 + bi1 = array.get(bi_segments, k) + bi2 = array.get(bi_segments, k + 1) + bi3 = array.get(bi_segments, k + 2) + + // 计算笔的价格区间 + bi1_high = math.max(bi1.start_point.price, bi1.end_point.price) + bi1_low = math.min(bi1.start_point.price, bi1.end_point.price) + bi2_high = math.max(bi2.start_point.price, bi2.end_point.price) + bi2_low = math.min(bi2.start_point.price, bi2.end_point.price) + bi3_high = math.max(bi3.start_point.price, bi3.end_point.price) + bi3_low = math.min(bi3.start_point.price, bi3.end_point.price) + + // 计算重叠区域 + overlap_high = math.min(math.min(bi1_high, bi2_high), bi3_high) + overlap_low = math.max(math.max(bi1_low, bi2_low), bi3_low) + + // 形成中枢 + if overlap_high > overlap_low + start_bar = math.min(bi1.start_point.bar_index, bi1.end_point.bar_index) + end_bar = math.max(bi3.start_point.bar_index, bi3.end_point.bar_index) + + // 创建中枢(检查距离限制) + zs_distance = bar_index - start_bar + if zs_distance <= 500 + zs_box = box.new(start_bar, overlap_high, end_bar, overlap_low, border_color=zhongshu_color, bgcolor=color.new(zhongshu_color, 85)) + array.push(zhongshu_boxes, zs_box) + +// ================== 改进的买卖点识别 ================== +if show_signals and array.size(zhongshu_boxes) > 0 and array.size(fractal_points) >= 2 + last_zhongshu = array.get(zhongshu_boxes, array.size(zhongshu_boxes) - 1) + last_fractal = array.get(fractal_points, array.size(fractal_points) - 1) + + zhongshu_high = box.get_top(last_zhongshu) + zhongshu_low = box.get_bottom(last_zhongshu) + + // 一买点:跌破中枢下沿后的底分型 + if last_fractal.fractal_type == "bottom" and last_fractal.price < zhongshu_low and last_fractal.bar_index > last_signal_bar + 5 + label.new(last_fractal.bar_index, last_fractal.price, "一买", color=color.green, style=label.style_label_up, size=size.normal) + last_signal_bar := last_fractal.bar_index + + // 一卖点:突破中枢上沿后的顶分型 + if last_fractal.fractal_type == "top" and last_fractal.price > zhongshu_high and last_fractal.bar_index > last_signal_bar + 5 + label.new(last_fractal.bar_index, last_fractal.price, "一卖", color=color.red, style=label.style_label_down, size=size.normal) + last_signal_bar := last_fractal.bar_index + + + +// ================== 信息面板 ================== +if barstate.islast + var info_table = table.new(position.top_right, 2, 10, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论标准V3", text_color=color.black, text_size=size.small) + 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_ks)), text_color=color.black) + table.cell(info_table, 0, 2, "分型数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(fractal_points)), 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_segments)), text_color=color.black) + table.cell(info_table, 0, 4, "线段数", text_color=color.black) + table.cell(info_table, 1, 4, str.tostring(array.size(xianduan_segments)), text_color=color.black) + table.cell(info_table, 0, 5, "中枢数", text_color=color.black) + table.cell(info_table, 1, 5, str.tostring(array.size(zhongshu_boxes)), text_color=color.black) + table.cell(info_table, 0, 6, "当前趋势", text_color=color.black) + trend_text = current_trend > 0 ? "向上" : current_trend < 0 ? "向下" : "震荡" + table.cell(info_table, 1, 6, trend_text, text_color=color.black) + table.cell(info_table, 0, 7, "合并K线", text_color=color.black) + table.cell(info_table, 1, 7, show_merged_k ? "开" : "关", text_color=color.black) + table.cell(info_table, 0, 8, "线段显示", text_color=color.black) + table.cell(info_table, 1, 8, show_xianduan ? "开" : "关", text_color=color.black) + table.cell(info_table, 0, 9, "调试模式", text_color=color.black) + table.cell(info_table, 1, 9, debug_mode ? "开" : "关", text_color=color.black) + +// ================== 警报 ================== +alertcondition(is_bottom_fractal and distance_ok(fractal_bar_index, "bottom"), + title="缠论买点", message="发现底分型") +alertcondition(is_top_fractal and distance_ok(fractal_bar_index, "top"), + title="缠论卖点", message="发现顶分型") \ No newline at end of file diff --git a/chan_theory_test.pine b/chan_theory_test.pine new file mode 100644 index 0000000..0181ec6 --- /dev/null +++ b/chan_theory_test.pine @@ -0,0 +1,106 @@ +//@version=6 +indicator("缠论测试版", shorttitle="缠论测试", overlay=true) + +// 参数设置 +show_merged_k = input.bool(true, "显示合并K线") +show_fenxing = input.bool(true, "显示分型") +show_bi = input.bool(true, "显示笔") + +// 数据类型 +type MergedK + int bar_index + float high + float low + float open + float close + +type FractalPoint + int bar_index + float price + string fractal_type + +// 全局变量 +var merged_ks = array.new() +var fractal_points = array.new() +var current_trend = 0 + +// 包含关系判断 +is_contained(k1_high, k1_low, k2_high, k2_low) => + (k1_high >= k2_high and k1_low <= k2_low) or (k2_high >= k1_high and k2_low <= k1_low) + +// K线合并 +if barstate.isconfirmed + current_k = MergedK.new(bar_index, high, low, open, close) + + if array.size(merged_ks) == 0 + array.push(merged_ks, current_k) + else + last_k = array.get(merged_ks, array.size(merged_ks) - 1) + + if is_contained(last_k.high, last_k.low, current_k.high, current_k.low) + // 合并K线 + if current_trend > 0 + last_k.high := math.max(last_k.high, current_k.high) + last_k.low := math.max(last_k.low, current_k.low) + else if current_trend < 0 + last_k.high := math.min(last_k.high, current_k.high) + last_k.low := math.min(last_k.low, current_k.low) + else + if last_k.close > last_k.open + last_k.high := math.max(last_k.high, current_k.high) + last_k.low := math.max(last_k.low, current_k.low) + else + last_k.high := math.min(last_k.high, current_k.high) + last_k.low := math.min(last_k.low, current_k.low) + last_k.bar_index := current_k.bar_index + else + array.push(merged_ks, current_k) + // 更新趋势 + if array.size(merged_ks) >= 2 + prev_k = array.get(merged_ks, array.size(merged_ks) - 2) + if current_k.high > prev_k.high + current_trend := 1 + else if current_k.low < prev_k.low + current_trend := -1 + +// 分型识别 +if array.size(merged_ks) >= 3 + k1 = array.get(merged_ks, array.size(merged_ks) - 3) + k2 = array.get(merged_ks, array.size(merged_ks) - 2) + k3 = array.get(merged_ks, array.size(merged_ks) - 1) + + // 顶分型 + if k2.high > k1.high and k2.high > k3.high and k2.low > k1.low and k2.low > k3.low + new_fractal = FractalPoint.new(k2.bar_index, k2.high, "top") + array.push(fractal_points, new_fractal) + if show_fenxing + label.new(k2.bar_index, k2.high, "顶", color=color.red, style=label.style_label_down) + + // 底分型 + if k2.high < k1.high and k2.high < k3.high and k2.low < k1.low and k2.low < k3.low + new_fractal = FractalPoint.new(k2.bar_index, k2.low, "bottom") + array.push(fractal_points, new_fractal) + if show_fenxing + label.new(k2.bar_index, k2.low, "底", color=color.green, style=label.style_label_up) + +// 构建笔 +if show_bi and array.size(fractal_points) >= 2 + for i = 0 to array.size(fractal_points) - 2 + current_fractal = array.get(fractal_points, i) + next_fractal = array.get(fractal_points, i + 1) + + if current_fractal.fractal_type != next_fractal.fractal_type + line.new(current_fractal.bar_index, current_fractal.price, next_fractal.bar_index, next_fractal.price, color=color.blue, width=2) + +// 信息面板 +if barstate.islast + var info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "缠论测试", text_color=color.black) + 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_ks)), text_color=color.black) + table.cell(info_table, 0, 2, "分型数", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(array.size(fractal_points)), text_color=color.black) + table.cell(info_table, 0, 3, "当前趋势", text_color=color.black) + trend_text = current_trend > 0 ? "向上" : current_trend < 0 ? "向下" : "震荡" + table.cell(info_table, 1, 3, trend_text, text_color=color.black) \ No newline at end of file diff --git a/chan_theory_ultra_simple.pine b/chan_theory_ultra_simple.pine new file mode 100644 index 0000000..3ba3563 --- /dev/null +++ b/chan_theory_ultra_simple.pine @@ -0,0 +1,47 @@ +//@version=6 +indicator("缠论超简版", shorttitle="缠论超简", overlay=true) + +// 简单参数 +min_gap = input.int(5, "分型间隔") + +// 全局变量 +var int last_fractal_bar = 0 +var float last_fractal_price = 0.0 +var string last_fractal_type = "" + +// 简单分型检测 +is_high = high[1] > high[0] and high[1] > high[2] +is_low = low[1] < low[0] and low[1] < low[2] + +// 距离检查 +gap_ok = bar_index[1] - last_fractal_bar >= min_gap + +// 识别并显示顶分型 +if is_high and gap_ok + label.new(bar_index[1], high[1], "顶", color=color.red, style=label.style_label_down, size=size.normal) + // 如果上一个是底分型,画笔 + if last_fractal_type == "bottom" and last_fractal_bar > 0 + line.new(last_fractal_bar, last_fractal_price, bar_index[1], high[1], color=color.blue, width=2) + last_fractal_bar := bar_index[1] + last_fractal_price := high[1] + last_fractal_type := "top" + +// 识别并显示底分型 +if is_low and gap_ok + label.new(bar_index[1], low[1], "底", color=color.green, style=label.style_label_up, size=size.normal) + // 如果上一个是顶分型,画笔 + if last_fractal_type == "top" and last_fractal_bar > 0 + line.new(last_fractal_bar, last_fractal_price, bar_index[1], low[1], color=color.blue, width=2) + last_fractal_bar := bar_index[1] + last_fractal_price := low[1] + last_fractal_type := "bottom" + +// 信息显示 +if barstate.islast + var table info = table.new(position.top_right, 2, 3, bgcolor=color.white) + table.cell(info, 0, 0, "缠论超简版", text_color=color.black) + table.cell(info, 1, 0, "", text_color=color.black) + table.cell(info, 0, 1, "最后分型", text_color=color.black) + table.cell(info, 1, 1, last_fractal_type, text_color=color.black) + table.cell(info, 0, 2, "分型间隔", text_color=color.black) + table.cell(info, 1, 2, str.tostring(min_gap), text_color=color.black) \ No newline at end of file diff --git a/ema_strategy_4lines.pine b/ema_strategy_4lines.pine new file mode 100644 index 0000000..2384b4e --- /dev/null +++ b/ema_strategy_4lines.pine @@ -0,0 +1,190 @@ +//@version=6 +strategy("4均线开口策略", shorttitle="EMA4线", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10, calc_on_every_tick=true) + +// 输入参数 +ema1_length = input.int(5, "EMA1周期", minval=1) +ema2_length = input.int(10, "EMA2周期", minval=1) +ema3_length = input.int(26, "EMA3周期", minval=1) +ema4_length = input.int(52, "EMA4周期", minval=1) + +// 开口阈值设置 +opening_threshold = input.float(0.5, "开口阈值(%)", minval=0.1, maxval=5.0) / 100 + +// 交易频率控制 +min_bars_between_trades = input.int(10, "最小交易间隔(K线数)", minval=1, maxval=100) +min_price_change = input.float(0.2, "最小价格变化(%)", minval=0.1, maxval=2.0) / 100 + +// 均线收束参数 +max_ema_spread = input.float(0.8, "均线最大间距(%)", minval=0.1, maxval=2.0) / 100 // 均线间最大距离 +convergence_periods = input.int(2, "收束确认周期", minval=1, maxval=10) // 收束状态持续周期 + +// 显示设置 +show_signals = input.bool(true, "显示信号") +show_ema_lines = input.bool(true, "显示EMA线") + +// 计算EMA +ema1 = ta.ema(close, ema1_length) +ema2 = ta.ema(close, ema2_length) +ema3 = ta.ema(close, ema3_length) +ema4 = ta.ema(close, ema4_length) + +// 显示EMA线 +plot(show_ema_lines ? ema1 : na, "EMA快线", color=color.red, linewidth=2) +plot(show_ema_lines ? ema2 : na, "EMA中线", color=color.orange, linewidth=2) +plot(show_ema_lines ? ema3 : na, "EMA慢线", color=color.blue, linewidth=2) +plot(show_ema_lines ? ema4 : na, "EMA超慢线", color=color.purple, linewidth=2) + +// 计算均线间距 +max_ema = math.max(math.max(ema1, ema2), math.max(ema3, ema4)) +min_ema = math.min(math.min(ema1, ema2), math.min(ema3, ema4)) +ema_range = (max_ema - min_ema) / close // 所有均线的最大间距 + +// 计算均线开口程度(使用相对距离) +ema_spread = math.abs(ema1 - ema4) / close +opening_magnitude = ema_spread + +// 检测均线收束状态(所有均线距离很近) +emas_converged = ema_range <= max_ema_spread +emas_converged_prev = ema_range[1] <= max_ema_spread + +// 简化的收束状态检测 +was_converged = emas_converged[1] or emas_converged[2] // 前1-2根K线有收束状态即可 + +// 检测均线排列状态 +// 多头排列:EMA1 > EMA2 > EMA3 > EMA4 +bull_alignment_now = ema1 > ema2 and ema2 > ema3 and ema3 > ema4 +bull_alignment = bull_alignment_now and bull_alignment_now[1] and bull_alignment_now[2] // 至少持续3个K线 + +// 空头排列:EMA1 < EMA2 < EMA3 < EMA4 +bear_alignment_now = ema1 < ema2 and ema2 < ema3 and ema3 < ema4 +bear_alignment = bear_alignment_now and bear_alignment_now[1] and bear_alignment_now[2] // 至少持续3个K线 + +// 检测均线同向趋势(通过斜率判断) +ema1_rising = ema1 > ema1[1] +ema2_rising = ema2 > ema2[1] +ema3_rising = ema3 > ema3[1] +ema4_rising = ema4 > ema4[1] + +ema1_falling = ema1 < ema1[1] +ema2_falling = ema2 < ema2[1] +ema3_falling = ema3 < ema3[1] +ema4_falling = ema4 < ema4[1] + +// 同向上升趋势 +all_rising = ema1_rising and ema2_rising and ema3_rising and ema4_rising +// 同向下降趋势 +all_falling = ema1_falling and ema2_falling and ema3_falling and ema4_falling + +// 交易频率控制变量 +var int last_trade_bar = 0 +var float last_trade_price = 0.0 +var int last_signal_bar = 0 + +// 价格过滤条件 +price_above_ema60 = close > ema4 // 价格在EMA60上方 +price_below_ema60 = close < ema4 // 价格在EMA60下方 + +// 交易间隔和价格变化检查 +bars_since_last_trade = bar_index - last_trade_bar +sufficient_time_gap = bars_since_last_trade >= min_bars_between_trades +sufficient_price_change = last_trade_price == 0.0 or math.abs(close - last_trade_price) / last_trade_price >= min_price_change + +// 检测均线开始发散(从收束状态开始向同一方向移动) +starting_divergence_up = was_converged and all_rising and not emas_converged // 从收束开始向上发散 +starting_divergence_down = was_converged and all_falling and not emas_converged // 从收束开始向下发散 + +// 买入条件:均线从收束开始发散 + 价格过滤 + 频率控制 +buy_long_condition = starting_divergence_up and price_above_ema60 and sufficient_time_gap and sufficient_price_change +buy_short_condition = starting_divergence_down and price_below_ema60 and sufficient_time_gap and sufficient_price_change +buy_condition = buy_long_condition or buy_short_condition + +// 卖出条件:均线开口达到最大(这里用阈值判断) +// 使用历史最大开口的相对比较 +var float max_opening = 0.0 +if opening_magnitude > max_opening + max_opening := opening_magnitude + +// 当开口超过阈值且达到近期高点时触发卖出 +sell_condition = opening_magnitude >= opening_threshold and opening_magnitude >= max_opening * 0.9 + +// 重置最大开口(当开口显著收窄时) +if opening_magnitude < max_opening * 0.3 + max_opening := opening_magnitude + +// 执行交易 +if buy_long_condition and strategy.position_size == 0 + strategy.entry("多头买入", strategy.long) + last_trade_bar := bar_index + last_trade_price := close + +if buy_short_condition and strategy.position_size == 0 + strategy.entry("空头买入", strategy.short) + last_trade_bar := bar_index + last_trade_price := close + +if sell_condition and strategy.position_size != 0 + if strategy.position_size > 0 + strategy.close("多头买入", comment="多头平仓") + else + strategy.close("空头买入", comment="空头平仓") + +// 信号显示间隔控制 +signal_gap_ok = bar_index - last_signal_bar >= min_bars_between_trades + +// 显示信号 - 只在实际交易时显示 +if show_signals + if buy_long_condition and strategy.position_size == 0 and sufficient_time_gap and sufficient_price_change and signal_gap_ok + label.new(bar_index, low, "买多", color=color.green, style=label.style_label_up, size=size.normal) + last_signal_bar := bar_index + if buy_short_condition and strategy.position_size == 0 and sufficient_time_gap and sufficient_price_change and signal_gap_ok + label.new(bar_index, high, "买空", color=color.red, style=label.style_label_down, size=size.normal) + last_signal_bar := bar_index + if sell_condition and strategy.position_size != 0 + label.new(bar_index, close, "平仓", color=color.yellow, style=label.style_label_left, size=size.normal) + +// 背景颜色指示 +bgcolor(emas_converged ? color.new(color.yellow, 95) : na, title="均线收束背景") +bgcolor(starting_divergence_up ? color.new(color.green, 90) : na, title="向上发散背景") +bgcolor(starting_divergence_down ? color.new(color.red, 90) : na, title="向下发散背景") + +// 信息表格 +if barstate.islast + var table info_table = table.new(position.top_right, 2, 12, bgcolor=color.white, border_width=1) + table.cell(info_table, 0, 0, "4EMA收束发散策略", text_color=color.black, bgcolor=color.gray) + table.cell(info_table, 1, 0, "", text_color=color.black, bgcolor=color.gray) + + table.cell(info_table, 0, 1, "均线间距", text_color=color.black) + table.cell(info_table, 1, 1, str.tostring(math.round(ema_range * 10000) / 100) + "%", text_color=color.black) + + table.cell(info_table, 0, 2, "收束阈值", text_color=color.black) + table.cell(info_table, 1, 2, str.tostring(math.round(max_ema_spread * 10000) / 100) + "%", text_color=color.black) + + table.cell(info_table, 0, 3, "当前收束", text_color=color.black) + table.cell(info_table, 1, 3, emas_converged ? "是" : "否", text_color=color.black) + + table.cell(info_table, 0, 4, "之前收束", text_color=color.black) + table.cell(info_table, 1, 4, was_converged ? "是" : "否", text_color=color.black) + + table.cell(info_table, 0, 5, "趋势方向", text_color=color.black) + table.cell(info_table, 1, 5, all_rising ? "同向上" : all_falling ? "同向下" : "分歧", text_color=color.black) + + table.cell(info_table, 0, 6, "发散检测", text_color=color.black) + divergence_text = starting_divergence_up ? "向上发散" : starting_divergence_down ? "向下发散" : "无发散" + table.cell(info_table, 1, 6, divergence_text, text_color=color.black) + + table.cell(info_table, 0, 7, "价格位置", text_color=color.black) + price_position = price_above_ema60 ? "EMA52上方" : price_below_ema60 ? "EMA52下方" : "EMA52附近" + table.cell(info_table, 1, 7, price_position, text_color=color.black) + + table.cell(info_table, 0, 8, "时间间隔", text_color=color.black) + table.cell(info_table, 1, 8, sufficient_time_gap ? "满足" : "不足", text_color=color.black) + + table.cell(info_table, 0, 9, "价格变化", text_color=color.black) + table.cell(info_table, 1, 9, sufficient_price_change ? "满足" : "不足", text_color=color.black) + + table.cell(info_table, 0, 10, "买多条件", text_color=color.black) + table.cell(info_table, 1, 10, buy_long_condition ? "满足" : "不满足", text_color=color.black) + + table.cell(info_table, 0, 11, "仓位状态", text_color=color.black) + position_text = strategy.position_size > 0 ? "多头" : strategy.position_size < 0 ? "空头" : "空仓" + table.cell(info_table, 1, 11, position_text, text_color=color.black) \ No newline at end of file diff --git a/缠论使用说明.md b/缠论使用说明.md new file mode 100644 index 0000000..69aa81b --- /dev/null +++ b/缠论使用说明.md @@ -0,0 +1,220 @@ +# 缠论标准版 Pine Script 6.0 使用说明 + +## 概述 +这是一个基于 TradingView Pine Script 6.0 开发的**完整标准缠论分析系统**,严格按照缠中说禅理论实现了缠论的所有核心概念:K线合并、分型、笔、线段、中枢和买卖点识别。 + +## 🔥 核心改进 + +### ✅ 新增功能 +1. **K线合并处理** - 正确处理包含关系的K线 +2. **标准分型识别** - 完整的顶底分型判断条件 +3. **线段识别** - 实现线段破坏和确认逻辑 +4. **智能买卖点** - 基于中枢突破的一买一卖点 +5. **趋势追踪** - 实时显示当前趋势方向 + +## 核心功能详解 + +### 1. K线合并处理 🆕 +- **理论基础**:缠论要求先处理K线包含关系,获得标准化序列 +- **包含关系判断**: + ``` + - K1包含K2:K1.high ≥ K2.high 且 K1.low ≤ K2.low + - K2包含K1:K2.high ≥ K1.high 且 K2.low ≤ K1.low + ``` +- **合并规则**: + - **向上趋势**:取两根K线的最高价和较高低价 + - **向下趋势**:取两根K线的最低价和较低高价 + - **趋势未定**:根据第一根K线的阴阳性确定方向 +- **显示**:橙色虚线连接合并K线的高低点 + +### 2. 标准分型识别 ✅ +- **顶分型条件**:中间K线的高点和低点都比左右K线高 + ``` + K2.high > K1.high 且 K2.high > K3.high + K2.low > K1.low 且 K2.low > K3.low + ``` +- **底分型条件**:中间K线的高点和低点都比左右K线低 + ``` + K2.high < K1.high 且 K2.high < K3.high + K2.low < K1.low 且 K2.low < K3.low + ``` +- **基于合并K线**:分型识别基于处理后的合并K线序列 +- **距离过滤**:相邻分型间必须有最小K线间隔(默认5根) + +### 3. 笔的构建 ✅ +- **定义**:连接相邻反向分型的线段 +- **构建规则**: + - 只连接不同类型的分型(顶→底 或 底→顶) + - 记录笔的方向(1为向上,-1为向下) + - 存储完整的笔段信息(起点、终点、方向) +- **显示**:蓝色实线,线宽2 + +### 4. 线段识别 🆕 +- **定义**:由多个笔组成的更高级别结构 +- **破坏条件**: + - **向上线段破坏**:当前向下笔的低点破坏第三笔的高点 + - **向下线段破坏**:当前向上笔的高点破坏第三笔的低点 +- **确认机制**:线段破坏后确认并开始新线段 +- **显示**:红色粗线,线宽3 + +### 5. 中枢识别 ✅ +- **定义**:三笔及以上的重叠价格区间 +- **计算方法**: + ``` + 重叠高点 = min(笔1高点, 笔2高点, 笔3高点) + 重叠低点 = max(笔1低点, 笔2低点, 笔3低点) + ``` +- **形成条件**:重叠高点 > 重叠低点 +- **显示**:灰色半透明方框,透明度85% + +### 6. 买卖点识别 🆕 +- **一买点**:价格跌破中枢下沿后出现的底分型 +- **一卖点**:价格突破中枢上沿后出现的顶分型 +- **确认条件**: + - 分型价格与中枢边界的突破关系 + - 与上一个信号的时间间隔(最少5根K线) +- **显示**:绿色"一买"标签向上,红色"一卖"标签向下 + +## 参数设置 + +### 显示设置 +- ☑️ `显示合并K线`:显示K线合并的连线(橙色虚线) +- ☑️ `显示分型`:显示顶底分型标记 +- ☑️ `显示笔`:显示笔的连线 +- ☑️ `显示线段`:显示线段(高级别结构) +- ☑️ `显示中枢`:显示中枢方框 +- ☑️ `显示买卖点`:显示交易信号 +- ☑️ `调试模式`:禁用分型间隔过滤,显示所有分型 + +### 缠论参数 +- `分型识别周期`:1(标准设置,不建议修改) +- `分型最小间隔`:5根K线(确保分型质量) + +### 颜色设置 +- 🔵 `笔的颜色`:蓝色(默认) +- 🔴 `线段颜色`:红色(默认) +- ⚫ `中枢颜色`:灰色(默认) +- 🟠 `合并K线颜色`:橙色(默认) + +## 使用方法 + +### 1. 导入指标 +1. 打开 TradingView +2. 进入 Pine Editor +3. 复制 `chan_theory_simple_v3.pine` 文件内容 +4. 点击"添加到图表" + +### 2. 参数调整 +- **新手建议**:开启所有显示选项,完整学习缠论结构 +- **实战使用**:可关闭合并K线显示,专注于笔和线段 +- **调试学习**:开启调试模式查看所有分型 + +### 3. 分析流程 +1. **观察K线合并** 🔍:理解价格的真实波动结构 +2. **识别标准分型** 📍:确定准确的局部高低点 +3. **跟踪笔的形成** 📈:观察价格波动的基本单位 +4. **关注线段变化** 📊:把握趋势的转折信号 +5. **识别中枢结构** ⬜:确定盘整和突破区间 +6. **等待买卖信号** 💰:基于中枢突破的交易机会 + +## 信息面板 📊 +右上角实时显示: +- 合并K线数量 +- 分型数量 +- 笔数量 +- 线段数量 +- 中枢数量 +- 当前趋势方向(向上/向下/震荡) +- 各功能开关状态 + +## 技术优势 + +### 1. 理论完整性 ✅ +- 严格按照缠中说禅原理实现 +- 包含K线合并这一基础步骤 +- 分型识别符合标准定义 +- 线段识别逻辑准确 + +### 2. 实用性强 💪 +- 自动识别所有缠论结构 +- 实时生成交易信号 +- 多层级结构同时显示 +- 参数可调适应不同市场 + +### 3. 技术先进 🚀 +- 使用Pine Script 6.0最新语法 +- 优化的数据结构和算法 +- 完善的内存管理机制 +- 流畅的图形渲染性能 + +## 进阶使用技巧 + +### 1. 多周期分析 🔄 +- 在不同时间周期应用指标 +- 大周期线段指导小周期操作 +- 寻找多周期结构共振点 + +### 2. 市场适应性 📈 +- **股票市场**:关注日线和周线结构 +- **外汇市场**:适用于4小时和日线 +- **加密货币**:1小时和4小时效果良好 + +### 3. 交易策略 💡 +- **趋势跟踪**:基于线段方向确定趋势 +- **区间交易**:利用中枢上下沿做震荡 +- **突破交易**:等待一买一卖点确认 + +## 注意事项 + +### 1. 理论学习 📚 +- 建议先学习缠论基础理论 +- 理解K线合并的重要性 +- 掌握分型、笔、线段的递进关系 + +### 2. 实战运用 ⚠️ +- 买卖点需结合具体走势确认 +- 注意资金管理和风险控制 +- 建议与其他技术指标结合使用 + +### 3. 系统限制 🔧 +- Pine Script对象数量有限制 +- 建议定期刷新图表清理历史数据 +- 长周期历史数据可能影响性能 + +## 常见问题 FAQ + +### Q: 为什么要先处理K线合并? +A: 缠论理论要求先消除K线包含关系,获得标准化序列,这是后续所有分析的基础。 + +### Q: 分型识别与传统高低点有什么区别? +A: 缠论分型要求中间K线的高低点都比左右K线高(或低),条件更严格,信号更可靠。 + +### Q: 线段和笔有什么区别? +A: 笔是连接相邻反向分型的线段,而线段是由多个笔组成的更高级别结构,代表更大的趋势变化。 + +### Q: 一买一卖点的成功率如何? +A: 这是基于缠论理论的客观信号,需要结合市场环境、资金管理等因素综合判断。 + +## 版本历史 + +### V3.0 标准版(当前版本) +- ✅ 新增K线合并处理 +- ✅ 完善分型识别条件 +- ✅ 实现线段识别功能 +- ✅ 改进买卖点逻辑 +- ✅ 优化代码结构和性能 + +### V2.0 简化版 +- 基础分型和笔识别 +- 简单中枢识别 +- 基础买卖点提示 + +## 技术支持 + +如需更多帮助,请: +1. 参考缠中说禅《教你炒股票》系列文章 +2. 学习缠论基础理论知识 +3. 在实盘中逐步验证和优化 + +--- +**重要声明**:此指标严格按照缠论理论实现,仅供学习和研究使用。投资有风险,入市需谨慎。建议结合基本面分析和风险管理原则使用。 \ No newline at end of file