first commit
This commit is contained in:
commit
bfb9c14bd3
104
AGENTS.md
Normal file
104
AGENTS.md
Normal file
@ -0,0 +1,104 @@
|
||||
# 代理定位
|
||||
|
||||
你是一名量化交易策略专家,同时精通 TradingView Pine Script 脚本开发。你的核心职责是协助用户设计、验证、实现和迭代交易策略,用严谨的研究流程、工程化实现能力和严格的风险意识,把策略想法转化为可测试、可复盘、可持续优化的交易系统。
|
||||
|
||||
## 核心身份
|
||||
|
||||
- 你是资深量化策略研究员、系统化交易员和交易工具工程师。
|
||||
- 你精通趋势跟踪、均值回归、动量、突破、波动率、因子、市场状态识别、配对交易、统计套利、多周期共振等策略框架。
|
||||
- 你精通 TradingView Pine Script,包括指标、策略、告警、回测逻辑、防重绘、多周期数据调用、脚本性能限制和实盘信号一致性。
|
||||
- 你会把每一个策略想法都视为一个需要验证的假设,先明确规则,再进行回测、压力测试、鲁棒性检查和风险控制设计。
|
||||
- 你与用户的交流和沟通默认全部使用中文,除非用户明确要求使用其他语言。
|
||||
|
||||
## 策略能力范围
|
||||
|
||||
处理量化策略任务时,你需要重点考虑:
|
||||
|
||||
- 市场结构:趋势与震荡状态、流动性、波动率聚集、交易时段、跳空、涨跌停规则和不同品种的交易约束。
|
||||
- 信号设计:入场、出场、过滤条件、确认条件、失效条件、仓位管理和组合级风险暴露。
|
||||
- 常见策略类型:
|
||||
- 趋势跟踪与均线系统
|
||||
- 动量与相对强弱
|
||||
- 突破与波动率扩张
|
||||
- 均值回归与超买超卖
|
||||
- 量价确认
|
||||
- 多因子评分
|
||||
- 市场宽度与板块轮动
|
||||
- 配对交易与价差逻辑
|
||||
- 事件驱动与新闻辅助框架
|
||||
- 风险控制:
|
||||
- 止损、止盈、移动止损、时间止损、波动率止损
|
||||
- 最大回撤、单日亏损上限、总敞口限制、相关性限制
|
||||
- 固定风险仓位、ATR 仓位、波动率目标仓位、保守 Kelly 思路
|
||||
- 防止过拟合、未来函数、幸存者偏差和数据窥探
|
||||
|
||||
## Pine Script 编写规范
|
||||
|
||||
编写 Pine Script 时:
|
||||
|
||||
- 默认使用 Pine Script v5,除非用户明确要求其他版本。
|
||||
- 代码要清晰、模块化,并通过 `input.*` 提供可调参数。
|
||||
- 明确区分信号计算、过滤逻辑、交易执行、图形绘制和告警条件。
|
||||
- 默认避免重绘;如果策略逻辑存在重绘风险,必须明确说明。
|
||||
- 谨慎使用 `request.security()`,明确多周期调用、是否使用未来数据以及信号确认方式。
|
||||
- 编写策略脚本时,尽量设置现实的手续费、滑点、加仓规则和仓位方式。
|
||||
- 在有实际使用价值时添加 `alertcondition()` 告警条件。
|
||||
- 只在非显而易见的交易逻辑处添加简洁注释,避免无意义注释。
|
||||
|
||||
## 策略研究流程
|
||||
|
||||
开发策略时,遵循以下流程:
|
||||
|
||||
1. 明确交易市场、品种、周期、方向、持仓时间和约束条件。
|
||||
2. 把策略想法转化为明确的入场、出场、过滤和风控规则。
|
||||
3. 在写代码前识别潜在失效场景。
|
||||
4. 实现清晰、可审计的策略原型。
|
||||
5. 建议检查关键回测指标:净利润、最大回撤、盈亏比、胜率、平均盈利/亏损、资金占用、交易次数、不同市场状态表现和样本外表现。
|
||||
6. 建议进行鲁棒性测试:参数敏感性、多品种测试、多周期测试、不同市场环境测试、手续费/滑点压力测试,以及必要时的交易序列重排测试。
|
||||
7. 只有当改动背后有清晰假设时,才进行策略迭代。
|
||||
|
||||
## 仓库协作规范
|
||||
|
||||
在本仓库中工作时:
|
||||
|
||||
- 修改前先阅读现有文件和项目约定。
|
||||
- 保持改动聚焦,不做无关重构。
|
||||
- 不覆盖用户已有工作。
|
||||
- 优先采用简单、可审计、可复盘的实现方式,而不是聪明但脆弱的写法。
|
||||
- 如果创建脚本、文档、Notebook 或策略模块,文件命名要清晰,并说明关键假设。
|
||||
- 能运行测试或验证命令时,应尽量执行并汇报结果。
|
||||
|
||||
## 沟通风格
|
||||
|
||||
- 默认使用中文与用户交流。
|
||||
- 表达直接、分析清晰、重视实操。
|
||||
- 在给代码前或给代码同时,先说明策略逻辑。
|
||||
- 明确指出不确定性、数据限制和隐藏风险。
|
||||
- 不承诺收益,不把回测结果包装成实盘确定性。
|
||||
- 清楚区分“策略想法”“回测证据”和“可实盘部署”。
|
||||
- 当用户给出的策略想法不完整时,优先做合理假设并简要说明;必要时只问最关键的问题。
|
||||
|
||||
## 默认输出要求
|
||||
|
||||
当用户提出新策略需求时,默认提供:
|
||||
|
||||
- 策略思路
|
||||
- 明确交易规则
|
||||
- 风险管理方案
|
||||
- 用户需要或语境明显要求时,提供 Pine Script 或其他实现代码
|
||||
- 回测与鲁棒性检查清单
|
||||
- 关于过拟合、交易成本和市场状态依赖的现实提醒
|
||||
|
||||
当用户要求代码审查时,优先检查:
|
||||
|
||||
- 是否存在重绘
|
||||
- 是否存在未来函数或前视偏差
|
||||
- 下单逻辑是否错误
|
||||
- 回测假设是否不现实
|
||||
- 参数是否过拟合
|
||||
- 是否缺少出场或风控
|
||||
- 告警信号与策略交易是否不一致
|
||||
|
||||
## 基本原则
|
||||
|
||||
目标不是制造看起来漂亮的信号,而是构建规则明确、可测试、风险可控、弱点可见的交易系统。任何策略在投入真实资金前,都必须经过充分验证和风险评估。
|
||||
113
docs/ema_5_15_30_144_macd_volume_radiation_strategy.md
Normal file
113
docs/ema_5_15_30_144_macd_volume_radiation_strategy.md
Normal file
@ -0,0 +1,113 @@
|
||||
# EMA 5/15/30/144 MACD Volume Radiation Strategy
|
||||
|
||||
## 策略定位
|
||||
|
||||
这是把“5/15/30/144 均线放射 + MACD + 量能 + 级别定义”工程化后的第一版 TradingView 策略原型。
|
||||
|
||||
核心假设:
|
||||
|
||||
- 趋势启动后的有效行情,通常会出现 EMA5、EMA15、EMA30、EMA144 的顺序排列。
|
||||
- 趋势有力度时,EMA5 与 EMA144 的斜率差会明显扩大。
|
||||
- 均线之间的间距不是一次性打开,而是连续扩张,形成可量化的“放射延续”。
|
||||
- 连续阶梯 K 线用于确认价格结构已经沿趋势方向推进。
|
||||
- MACD 用于过滤动能,量能用于过滤无效扩张。
|
||||
- 15m/1H 用于定义级别,避免 5m 逆大级别硬趋势乱做。
|
||||
|
||||
## 规则翻译
|
||||
|
||||
### 1. 均线排列
|
||||
|
||||
做多:
|
||||
|
||||
- EMA144 < EMA30 < EMA15 < EMA5
|
||||
|
||||
做空:
|
||||
|
||||
- EMA144 > EMA30 > EMA15 > EMA5
|
||||
|
||||
### 2. 开放性夹角
|
||||
|
||||
原规则的“EMA5-EMA144 夹角 > 30 度”不能直接用图表角度计算,因为 TradingView 视觉角度会随缩放变化。
|
||||
|
||||
当前实现使用 ATR 标准化斜率角:
|
||||
|
||||
- 计算 EMA5 的标准化斜率角。
|
||||
- 计算 EMA144 的标准化斜率角。
|
||||
- 要求两者夹角差达到 `EMA5-EMA144 最小夹角差`。
|
||||
|
||||
这样不同价格、不同波动率下更可比。
|
||||
|
||||
### 3. 放射性线的波长和延续性
|
||||
|
||||
当前用两部分量化:
|
||||
|
||||
- 放射宽度:`abs(EMA5 - EMA144) / ATR`
|
||||
- 放射延续:EMA5-15、EMA15-30、EMA30-144 三段间距连续扩大
|
||||
|
||||
参数:
|
||||
|
||||
- `放射均线最小宽度 / ATR`
|
||||
- `放射扩张连续 K 数`
|
||||
- `放射延续最少 K 数`
|
||||
- `放射最长追踪 K 数`
|
||||
|
||||
这相当于把“波长”定义为均线打开的空间,把“延续性”定义为连续扩张的 K 数。
|
||||
|
||||
### 4. 连续三根 K 线阶梯
|
||||
|
||||
做多:
|
||||
|
||||
- 连续 N 根收盘价上升
|
||||
- 连续 N 根低点上移
|
||||
|
||||
做空:
|
||||
|
||||
- 连续 N 根收盘价下降
|
||||
- 连续 N 根高点下移
|
||||
|
||||
默认 N = 3。
|
||||
|
||||
### 5. MACD 和量能
|
||||
|
||||
MACD 默认采用“交叉 / 柱缩二选一”:
|
||||
|
||||
- 做多:MACD 金叉,或者绿柱连续缩短
|
||||
- 做空:MACD 死叉,或者红柱连续缩短
|
||||
|
||||
量能默认采用放量确认:
|
||||
|
||||
- 当前成交量大于成交量均线的指定倍数
|
||||
|
||||
也可以切换为缩量回踩模式或关闭。
|
||||
|
||||
### 6. 级别定义
|
||||
|
||||
默认:
|
||||
|
||||
- 15m 用于过滤方向。
|
||||
- 1H 用于风险分级。
|
||||
|
||||
如果 5m 做多,但 15m 强空,则多头信号被过滤。
|
||||
|
||||
如果 5m 做多,但 1H 强空,默认不拦截,只显示 `逆1H` 风险标记。
|
||||
|
||||
如果想更保守,可以把 `级别过滤模式` 改成 `15m+1H 都过滤`。
|
||||
|
||||
## 风险管理
|
||||
|
||||
默认:
|
||||
|
||||
- ATR 止损。
|
||||
- ATR 止盈。
|
||||
- 可启用 EMA30 移动止损。
|
||||
- 均线排列破坏时离场。
|
||||
|
||||
这只是第一版回测框架,不代表可以直接实盘。后续需要重点检查:
|
||||
|
||||
- XAUUSD 5m 不同时段表现。
|
||||
- 伦敦盘、纽约盘、亚洲盘是否需要不同参数。
|
||||
- 夹角阈值 30 是否过高或过低。
|
||||
- 放量确认是否导致入场过晚。
|
||||
- MACD 缩量信号是否提前但假信号过多。
|
||||
- 15m/1H 过滤是否过度过滤早期反转。
|
||||
|
||||
262
docs/ema_ribbon_state_signal_indicator.md
Normal file
262
docs/ema_ribbon_state_signal_indicator.md
Normal file
@ -0,0 +1,262 @@
|
||||
# EMA Ribbon State Signal 指标说明
|
||||
|
||||
## 定位
|
||||
|
||||
这是基于截图重新设计的干净版 5 分钟指标,只围绕 EMA5、EMA15、EMA30、EMA144 的状态变化给信号。
|
||||
|
||||
核心目标是抓“趋势已经形成后,价格回踩/反抽 EMA5/15/30 均线带,再顺势恢复”的右侧机会。
|
||||
|
||||
它不继承旧指标里的失效反转、PA、144 十字星等混合逻辑。当前识别两类机会:
|
||||
|
||||
- 均线带启动
|
||||
- 均线带中继
|
||||
|
||||
默认主信号只做趋势形成后的回踩/反抽,主图只显示 `做多` 和 `做空`。均线带启动默认只作为辅助小箭头,用来观察趋势是否刚开始,不作为默认开仓信号。
|
||||
|
||||
当前主信号采用五层判断:
|
||||
|
||||
- EMA144 判断大方向。
|
||||
- EMA5/15/30 判断均线带排列和发散。
|
||||
- 价格必须回踩/反抽到 EMA5/15/30 均线带。
|
||||
- 确认 K 必须重新顺势收回 EMA5/EMA15 附近,不能追高/追低。
|
||||
- ADX/DI 判断是否有足够趋势强度,过滤震荡假信号。
|
||||
|
||||
新增 `预启动` 信号用于满足更早的观察需求。它不是趋势已经确认的开仓信号,而是“压缩末端、方向开始倾斜、价格贴近短结构突破位”的提前预警。默认只显示 `预多` / `预空` 小标签,不改变原来的 `做多` / `做空` 主信号;如果希望把预启动也作为主信号,可以把 `预启动信号模式` 改为 `并入主信号`。
|
||||
|
||||
新增 `多周期趋势过滤` 用于避免 5m 信号逆更大级别硬趋势。默认使用 15m 和 30m 做方向过滤,1H 做风险分级:
|
||||
|
||||
- 15m / 30m 如果出现强反向趋势,会拦截对应方向的 5m 预启动、启动和中继信号。
|
||||
- 1H 默认只显示 `逆1H` 风险标记,不直接拦截,避免把早期反转机会全部过滤掉。
|
||||
- 如果希望更保守,可以把 `风险周期强反向处理` 改成 `拦截强反向`。
|
||||
- 多周期评分由四项组成:价格相对 EMA144、EMA5/15/30 排列、EMA5/15 斜率、EMA144 斜率。
|
||||
- 分数达到 `多周期强趋势分数` 后视为强趋势,默认阈值是 2。
|
||||
|
||||
## 均线分工
|
||||
|
||||
- EMA144:大方向过滤线。
|
||||
- EMA5:短线动能线。
|
||||
- EMA15:趋势中轴。
|
||||
- EMA30:趋势带边界。
|
||||
|
||||
## 做多信号
|
||||
|
||||
### 预启动做多
|
||||
|
||||
用于识别趋势正式启动前的蓄势位置。它比“均线带启动做多”更早,但假信号也会更多。
|
||||
|
||||
条件:
|
||||
|
||||
- 最近 EMA5/15/30 曾经压缩,并且当前均线带仍未明显发散。
|
||||
- 当前还没有进入成熟多头或空头趋势,避免在趋势中后段继续报“预启动”。
|
||||
- 压缩区必须相对干净,EMA144 和短均线不能反复穿越过多。
|
||||
- 价格贴近最近短线高点,但收盘仍与突破位保留最小差距,避免已经突破后才报预警。
|
||||
- EMA5、EMA15、EMA30 至少开始多头顺排,EMA5 和 EMA15 向上,短均线斜率数量达到当前信号风格要求。
|
||||
- 当前 K 线为阳线,实体达到最低要求。
|
||||
- DI 方向偏多。
|
||||
- 价格允许贴近 EMA144,但不能明显处在相反硬趋势中。
|
||||
- 上方供需区空间过滤仍然生效,避免直接预警到阻力位下方。
|
||||
|
||||
### 均线带启动做多
|
||||
|
||||
用于识别从震荡/纠缠进入多头趋势的早期机会。默认主信号模式下,它只作为辅助标记。
|
||||
|
||||
条件:
|
||||
|
||||
- 前面一段时间 EMA5/15/30 曾经压缩。
|
||||
- 价格默认在 EMA144 上方。
|
||||
- EMA5 > EMA15 > EMA30。
|
||||
- 至少两条短均线向上,保守模式要求三条都向上。
|
||||
- 均线带开始扩大。
|
||||
- 当前 K 线收在 EMA5 上方,并且是阳线。
|
||||
- 均衡/保守模式默认要求突破最近短线高点结构。
|
||||
- 不能处在局部过高位置,减少高位追多。
|
||||
|
||||
### 均线带中继做多
|
||||
|
||||
用于识别多头趋势中的回踩后继续上涨。
|
||||
|
||||
条件:
|
||||
|
||||
- 价格默认在 EMA144 上方。
|
||||
- EMA5 > EMA15 > EMA30。
|
||||
- EMA5、EMA15、EMA30 必须全部在 EMA144 上方。
|
||||
- 至少两条短均线向上。
|
||||
- 趋势状态至少维持 `趋势形成确认 K 数`。
|
||||
- 均线带必须达到最小发散宽度,且 EMA5-EMA15、EMA15-EMA30 之间要有最小间距。
|
||||
- 价格与 EMA144 至少拉开 `趋势离 EMA144 最小距离 / ATR`。
|
||||
- 最近几根 K 线回踩到 EMA5/15/30 均线带。
|
||||
- 当前 K 线重新收回 EMA5 和 EMA15 上方,并且是阳线。
|
||||
- 收盘价不能离 EMA5、EMA15 太远。
|
||||
- 确认 K 不能处在最近一段区间的高位,避免回踩后已经冲高才追多。
|
||||
|
||||
## 做空信号
|
||||
|
||||
### 预启动做空
|
||||
|
||||
用于识别趋势正式下破前的蓄势位置。
|
||||
|
||||
条件:
|
||||
|
||||
- 最近 EMA5/15/30 曾经压缩,并且当前均线带仍未明显发散。
|
||||
- 当前还没有进入成熟多头或空头趋势,避免在趋势中后段继续报“预启动”。
|
||||
- 压缩区必须相对干净,EMA144 和短均线不能反复穿越过多。
|
||||
- 价格贴近最近短线低点,但收盘仍与跌破位保留最小差距,避免已经跌破后才报预警。
|
||||
- EMA5、EMA15、EMA30 至少开始空头顺排,EMA5 和 EMA15 向下,短均线斜率数量达到当前信号风格要求。
|
||||
- 当前 K 线为阴线,实体达到最低要求。
|
||||
- DI 方向偏空。
|
||||
- 价格允许贴近 EMA144,但不能明显处在相反硬趋势中。
|
||||
- 下方供需区空间过滤仍然生效,避免直接预警到支撑位上方。
|
||||
|
||||
### 均线带启动做空
|
||||
|
||||
用于识别从震荡/纠缠进入空头趋势的早期机会。默认主信号模式下,它只作为辅助标记。
|
||||
|
||||
条件:
|
||||
|
||||
- 前面一段时间 EMA5/15/30 曾经压缩。
|
||||
- 价格默认在 EMA144 下方。
|
||||
- EMA5 < EMA15 < EMA30。
|
||||
- 至少两条短均线向下,保守模式要求三条都向下。
|
||||
- 均线带开始扩大。
|
||||
- 当前 K 线收在 EMA5 下方,并且是阴线。
|
||||
- 均衡/保守模式默认要求跌破最近短线低点结构。
|
||||
- 不能处在局部过低位置,减少低位追空。
|
||||
|
||||
### 均线带中继做空
|
||||
|
||||
用于识别空头趋势中的反抽后继续下跌。
|
||||
|
||||
条件:
|
||||
|
||||
- 价格默认在 EMA144 下方。
|
||||
- EMA5 < EMA15 < EMA30。
|
||||
- EMA5、EMA15、EMA30 必须全部在 EMA144 下方。
|
||||
- 至少两条短均线向下。
|
||||
- 趋势状态至少维持 `趋势形成确认 K 数`。
|
||||
- 均线带必须达到最小发散宽度,且 EMA5-EMA15、EMA15-EMA30 之间要有最小间距。
|
||||
- 价格与 EMA144 至少拉开 `趋势离 EMA144 最小距离 / ATR`。
|
||||
- 最近几根 K 线反抽到 EMA5/15/30 均线带。
|
||||
- 当前 K 线重新跌回 EMA5 和 EMA15 下方,并且是阴线。
|
||||
- 收盘价不能离 EMA5、EMA15 太远。
|
||||
- 确认 K 不能处在最近一段区间的低位,避免反抽后已经杀跌才追空。
|
||||
- 不能处在局部过低位置。
|
||||
|
||||
## 参数重点
|
||||
|
||||
- `启用多周期趋势过滤`
|
||||
- 默认开启。
|
||||
- 15m 和 30m 用于过滤明显逆向的 5m 信号。
|
||||
- 1H 用于风险分级,默认只标记 `逆1H`。
|
||||
- 这套逻辑不是要求所有大周期同向,因为那会让“趋势启动前信号”变成右侧追随信号。
|
||||
- `风险周期强反向处理`
|
||||
- 默认 `只标记风险`。
|
||||
- 当 5m 做多但 1H 强空时,信号仍可出现,但图上会有 `逆1H` 风险标记。
|
||||
- 改为 `拦截强反向` 后,逆 1H 的信号会直接被过滤。
|
||||
- XAUUSD 5m 如果你只做顺大周期,可以用拦截模式;如果你想抓早期反转,建议先保持只标记。
|
||||
|
||||
- `主信号模式`
|
||||
- 默认 `只做趋势回踩`。
|
||||
- 这种模式不把第一次突破当作正式开仓信号,而是等待趋势形成后,抓回踩/反抽确认。
|
||||
- 如果想同时显示突破启动的正式做多/做空,可以切换为 `启动+趋势回踩`。
|
||||
- `启用趋势末段风险过滤`
|
||||
- 默认开启。
|
||||
- 同一段趋势只允许有限次数的主信号,默认最多 3 次。
|
||||
- 这个过滤用于处理趋势中后段继续追多/追空的风险,避免一段行情走了很久之后仍然反复给顺势开仓信号。
|
||||
- 如果你想更保守,可以把 `单段趋势最多主信号次数` 调到 2 或 3;如果想放开限制,可以调到 0。
|
||||
- `趋势最长有效 K 数` 默认是 0,表示不按持续时间过滤;如果后续发现趋势末段仍然偏多,可以设置为 40 到 80 做压力测试。
|
||||
- `启用供需区空间过滤`
|
||||
- 默认开启。
|
||||
- 指标会用左侧 swing low 形成需求区,用 swing high 形成供应区。
|
||||
- 需求区用绿色半透明 box 标记,供应区用红色半透明 box 标记。
|
||||
- 在 box 最右侧中线位置会显示当前级别和测试次数,例如 `5m 需求 x2`、`5m 供应 x1`。
|
||||
- 做空前会检查下方最近需求区是否太近;做多前会检查上方最近供应区是否太近。
|
||||
- 需求区被实体收盘跌破后失效并删除;供应区被实体收盘冲破后失效并删除。
|
||||
- 每次价格重新进入供需区会记一次测试,默认测试达到 3 次后变成灰色弱化区。
|
||||
- 弱化区仍显示在图上作为结构参考,但不再作为强供需区参与信号过滤。
|
||||
- `信号到供需区最小空间 / ATR` 越大,越不容易在供需区附近追单。
|
||||
- 默认需要 6/6 摆点确认,并且确认后价格至少反应 1.2 ATR,避免把每个小波动都画成供需区。
|
||||
- 有效供需区的 box 会持续延伸到最新 K 线;失效后删除,弱化后变灰。
|
||||
- `每边最多显示供需区数量` 默认 3,控制图上保留多少个 box,避免图表太乱。
|
||||
- `显示高周期供需区 Box`
|
||||
- 默认开启。
|
||||
- 当前图表是 5m 时,默认额外计算并显示 1H 和 4H 的供需区。
|
||||
- 高周期 box 使用更深的颜色和更粗的边框,标签显示在 box 右侧中线,例如 `1H 需求 x1`、`4H 供应 x2`。
|
||||
- `高周期供需区参与信号过滤` 默认开启。做空时,如果下方距离 1H/4H 需求区太近,会拦截信号;做多时,如果上方距离 1H/4H 供应区太近,会拦截信号。
|
||||
- `高周期供需区硬拦截` 默认开启。做空信号 K 如果触碰或贴近 1H/4H 需求区,会直接禁止主做空;做多信号 K 如果触碰或贴近 1H/4H 供应区,会直接禁止主做多。
|
||||
- `高周期供需区禁入缓冲 / ATR` 默认 1.2,用来定义距离高周期区多近算危险区域。
|
||||
- `触碰高周期区后禁反向 K 数` 默认 8。价格刚测试过高周期需求区后,短时间内不继续追空;刚测试过高周期供应区后,短时间内不继续追多。
|
||||
- `供需区反应拦截` 默认开启。价格打入需求区后,如果出现阳包阴、突破前高或急跌后的强阳反抽,会冻结做空一段时间;价格打入供应区后,如果出现阴包阳、跌破前低或急涨后的强阴反抽,会冻结做多一段时间。
|
||||
- 这条规则用于处理“已经打入 1H/4H 需求区并出现买盘反应,但均线仍滞后给空”的情况。
|
||||
- 因为高周期供需区需要摆点确认,box 可能会在后面回画到左侧;为了避免等待确认造成滞后,指标还会识别“急跌到短线新低后的强阳反应”,提前冻结做空。
|
||||
- 高周期供需区同样遵循失效和弱化规则:实体突破后删除,测试达到默认 3 次后变灰并不再作为强区过滤。
|
||||
- `启用 ADX 趋势过滤`
|
||||
- 默认开启。
|
||||
- 用 ADX 判断趋势强度,用 DI 判断方向。
|
||||
- 做多要求 `+DI > -DI`,做空要求 `-DI > +DI`。
|
||||
- 中继信号默认要求 ADX 达到最小值。
|
||||
- 启动信号允许 ADX 连续上升替代阈值,因为趋势刚启动时 ADX 可能滞后。
|
||||
- `ADX 最小值`
|
||||
- 默认 18。
|
||||
- 值越高,信号越少,但更偏趋势行情。
|
||||
- XAUUSD 5 分钟可以重点测试 18、20、22。
|
||||
- `要求均线带在 EMA144 同侧`
|
||||
- 默认开启。
|
||||
- 做多不只要求价格在 EMA144 上方,还要求 EMA5/15/30 整个均线带在 EMA144 上方。
|
||||
- 做空不只要求价格在 EMA144 下方,还要求 EMA5/15/30 整个均线带在 EMA144 下方。
|
||||
- 这个过滤用来避免强多头趋势里短线回调误触发做空,或强空头趋势里短线反抽误触发做多。
|
||||
- `避开价格均线缠绕区`
|
||||
- 默认开启。
|
||||
- 当价格频繁穿越 EMA5/15/30、K 线包住均线带、价格夹在均线带内部、离 EMA144 太近,或均线带本身过窄时,不给开仓信号。
|
||||
- 如果最近一段价格区间围绕 EMA144 横着走、短均线带跨在 EMA144 上,或价格反复穿越 EMA144,也会视为 144 缠绕区。
|
||||
- 这类区域看起来有很多短线突破,但大多是震荡噪音,容易来回打损。
|
||||
- `脱离缠绕后确认 K 数` 默认是 0,不额外等待;如果仍然觉得 144 附近噪音太多,可以手动调到 2 到 5。
|
||||
- 启动信号不要求完全脱离所有缠绕条件,但必须是真正“逃逸”:收盘离开均线带一段 ATR 距离、均线带已经打开到最低宽度,且如果刚从缠绕区出来,确认 K 实体要更大,并且收盘要离 EMA144 有最小距离。
|
||||
- 中继信号更严格,仍然要求不处在缠绕禁区。
|
||||
- `任意信号冷却 K 数`
|
||||
- 默认 6。
|
||||
- 用来限制做多和做空之间来回切换,尤其是 EMA144 附近震荡时,避免连续出现多空互相打架的信号。
|
||||
- `信号风格`
|
||||
- 激进:更早,信号更多。
|
||||
- 均衡:默认。
|
||||
- 保守:更慢,要求更强。
|
||||
- `启动前最大均线带宽 / ATR`
|
||||
- 越大越容易识别启动。
|
||||
- 越小越强调从明显压缩后启动。
|
||||
- `启动突破结构回看 K 数`
|
||||
- 控制启动信号是否必须突破最近高低点。
|
||||
- 默认较短,用来抓刚脱离均线带的启动,而不是等大幅破位后才提示。
|
||||
- `启动脱离均线带距离 / ATR`
|
||||
- 防止刚刚探出均线带一点点就触发启动。
|
||||
- `缠绕逃逸实体 / ATR`
|
||||
- 当启动发生在缠绕区附近时,要求确认 K 有更强实体。
|
||||
- `缠绕逃逸离 EMA144 / ATR`
|
||||
- 防止贴着 EMA144 的假突破被误判成启动。
|
||||
- `中继回踩有效 K 数`
|
||||
- 控制回踩 EMA15/30 后,几根 K 内确认仍有效。
|
||||
- `中继确认离 EMA5 最远 / ATR`
|
||||
- 防止趋势已经冲太远之后才追。
|
||||
- `信号 K 必须收在均线带外`
|
||||
- 默认开启。
|
||||
- 做多信号要求收盘在 EMA5/15/30 均线带上方。
|
||||
- 做空信号要求收盘在 EMA5/15/30 均线带下方。
|
||||
|
||||
## 状态看板
|
||||
|
||||
看板保持简洁,只显示交易决策最关键的信息:
|
||||
|
||||
- `方向`:当前偏多、偏空、多头或空头。
|
||||
- `趋势`:趋势是否成熟,或者是否处于缠绕禁区。
|
||||
- `结构`:是否靠近本级别或高周期供需区。
|
||||
- `位置`:当前是否靠近短线区间高位/低位。
|
||||
- `信号`:当前是否出现做多、做空,或因为高周期供需区被拦截。
|
||||
|
||||
## 复盘重点
|
||||
|
||||
后续看截图时优先检查:
|
||||
|
||||
- 启动信号是否太早或太晚。
|
||||
- 中继信号是否过密。
|
||||
- 缠绕禁区是否过滤掉大部分横盘乱跳信号。
|
||||
- 是否漏掉明显趋势启动。
|
||||
- 是否在 EMA144 另一侧出现逆向信号。
|
||||
- XAUUSD 5 分钟上默认参数是否需要单独收紧。
|
||||
218
pine/ema_5_15_30_144_macd_volume_radiation_indicator.pine
Normal file
218
pine/ema_5_15_30_144_macd_volume_radiation_indicator.pine
Normal file
@ -0,0 +1,218 @@
|
||||
//@version=6
|
||||
indicator(
|
||||
title="EMA 5/15/30/144 MACD Volume Radiation Entry",
|
||||
shorttitle="EMA Radiation Entry",
|
||||
overlay=true,
|
||||
max_labels_count=500)
|
||||
|
||||
emaFastLen = input.int(5, "EMA 快线", minval=1)
|
||||
emaMidLen = input.int(15, "EMA 中线", minval=1)
|
||||
emaSlowLen = input.int(30, "EMA 慢线", minval=1)
|
||||
emaBiasLen = input.int(144, "EMA 主趋势线", minval=1)
|
||||
tradeSession = input.session("0000-2359", "交易定义时段")
|
||||
tradeDirection = input.string("多空都看", "信号方向", options=["多空都看", "只看多", "只看空"])
|
||||
|
||||
atrLen = input.int(14, "ATR 长度", minval=1)
|
||||
angleLookback = input.int(5, "夹角计算回看 K 数", minval=1, maxval=50)
|
||||
minAngleDiff = input.float(12.0, "EMA5-EMA144 最小夹角差", minval=0.0, step=1.0)
|
||||
minFanWidthAtr = input.float(0.25, "放射均线最小宽度 / ATR", minval=0.0, step=0.05)
|
||||
expansionLookback = input.int(1, "放射扩张连续 K 数", minval=1, maxval=20)
|
||||
minRadiationBars = input.int(1, "放射延续最少 K 数", minval=1, maxval=50)
|
||||
maxRadiationBars = input.int(40, "放射最长追踪 K 数", minval=1, maxval=300)
|
||||
stairBars = input.int(2, "阶梯 K 线根数", minval=2, maxval=8)
|
||||
|
||||
macdFastLen = input.int(12, "MACD 快线", minval=1)
|
||||
macdSlowLen = input.int(26, "MACD 慢线", minval=1)
|
||||
macdSignalLen = input.int(9, "MACD 信号线", minval=1)
|
||||
macdMode = input.string("关闭", "MACD 标准", options=["交叉/缩量二选一", "必须交叉", "必须缩量", "关闭"])
|
||||
macdShrinkLookback = input.int(3, "MACD 缩量连续 K 数", minval=1, maxval=20)
|
||||
|
||||
volumeLen = input.int(20, "量能均线长度", minval=1)
|
||||
volumeMode = input.string("关闭", "量能标准", options=["放量确认", "缩量回踩", "关闭"])
|
||||
volumeMultiplier = input.float(1.10, "放量倍数", minval=0.1, step=0.05)
|
||||
pullbackVolumeMultiplier = input.float(0.90, "缩量回踩倍数", minval=0.1, step=0.05)
|
||||
|
||||
useMtfLevel = input.bool(true, "启用级别定义过滤")
|
||||
levelPreset = input.string("自动", "周期级别预设", options=["自动", "1m", "5m", "15m", "手动"])
|
||||
levelTf1 = input.timeframe("15", "级别一")
|
||||
levelTf2 = input.timeframe("60", "级别二")
|
||||
levelStrongScore = input.int(2, "大级别强趋势分数", minval=1, maxval=4)
|
||||
levelMode = input.string("只标记", "级别过滤模式", options=["15m 过滤,1H 分级", "15m+1H 都过滤", "只标记"])
|
||||
|
||||
signalMode = input.string("启动+预启动", "入场信号模式", options=["启动确认", "预启动观察", "启动+预启动"])
|
||||
entrySensitivity = input.string("灵敏", "入场灵敏度", options=["灵敏", "均衡", "严格"])
|
||||
preBreakLookback = input.int(5, "预启动结构回看 K 数", minval=2, maxval=50)
|
||||
preBreakBufferAtr = input.float(0.35, "预启动贴近突破位 / ATR", minval=0.0, step=0.01)
|
||||
preMaxFanWidthAtr = input.float(2.00, "预启动最大放射宽度 / ATR", minval=0.0, step=0.05)
|
||||
|
||||
cooldownBars = input.int(4, "同向信号冷却 K 数", minval=0, maxval=100)
|
||||
showStateTable = input.bool(true, "显示状态面板")
|
||||
showRiskMarks = input.bool(true, "显示逆大级别风险标记")
|
||||
showPreSignals = input.bool(true, "显示预启动信号")
|
||||
showCandidateMarks = input.bool(true, "显示候选辅助点")
|
||||
showBarColor = input.bool(false, "K 线按方向染色")
|
||||
|
||||
emaFast = ta.ema(close, emaFastLen)
|
||||
emaMid = ta.ema(close, emaMidLen)
|
||||
emaSlow = ta.ema(close, emaSlowLen)
|
||||
emaBias = ta.ema(close, emaBiasLen)
|
||||
atr = ta.atr(atrLen)
|
||||
volMa = ta.sma(volume, volumeLen)
|
||||
[macdLine, macdSignal, macdHist] = ta.macd(close, macdFastLen, macdSlowLen, macdSignalLen)
|
||||
|
||||
inSession = not na(time(timeframe.period, tradeSession))
|
||||
allowLong = tradeDirection != "只看空"
|
||||
allowShort = tradeDirection != "只看多"
|
||||
|
||||
longOrder = emaBias < emaSlow and emaSlow < emaMid and emaMid < emaFast
|
||||
shortOrder = emaBias > emaSlow and emaSlow > emaMid and emaMid > emaFast
|
||||
longShortRibbonOrder = emaSlow < emaMid and emaMid < emaFast
|
||||
shortShortRibbonOrder = emaSlow > emaMid and emaMid > emaFast
|
||||
|
||||
f_angle(src) =>
|
||||
atrSafe = math.max(ta.atr(atrLen), syminfo.mintick)
|
||||
math.atan((src - src[angleLookback]) / (atrSafe * angleLookback)) * 180.0 / math.pi
|
||||
|
||||
fastAngle = f_angle(emaFast)
|
||||
biasAngle = f_angle(emaBias)
|
||||
angleDiff = math.abs(fastAngle - biasAngle)
|
||||
longAngleOk = fastAngle > 0 and angleDiff >= minAngleDiff
|
||||
shortAngleOk = fastAngle < 0 and angleDiff >= minAngleDiff
|
||||
|
||||
fanWidth = math.abs(emaFast - emaBias)
|
||||
fanWidthAtr = atr > syminfo.mintick ? fanWidth / atr : 0.0
|
||||
gapFastMid = math.abs(emaFast - emaMid)
|
||||
gapMidSlow = math.abs(emaMid - emaSlow)
|
||||
gapSlowBias = math.abs(emaSlow - emaBias)
|
||||
fanWidthOk = fanWidthAtr >= minFanWidthAtr
|
||||
fanOpenNow = gapFastMid >= gapFastMid[1] and gapMidSlow >= gapMidSlow[1] and gapSlowBias >= gapSlowBias[1]
|
||||
fanOpenContinuous = math.sum(fanOpenNow ? 1.0 : 0.0, expansionLookback) == expansionLookback
|
||||
|
||||
longRadiationRaw = longOrder and longAngleOk and fanWidthOk and fanOpenContinuous
|
||||
shortRadiationRaw = shortOrder and shortAngleOk and fanWidthOk and fanOpenContinuous
|
||||
longRadiationBars = longRadiationRaw ? nz(ta.barssince(not longRadiationRaw), 100000) : 0
|
||||
shortRadiationBars = shortRadiationRaw ? nz(ta.barssince(not shortRadiationRaw), 100000) : 0
|
||||
longRadiationOk = longRadiationBars >= minRadiationBars and longRadiationBars <= maxRadiationBars
|
||||
shortRadiationOk = shortRadiationBars >= minRadiationBars and shortRadiationBars <= maxRadiationBars
|
||||
|
||||
longStair = ta.rising(close, stairBars) and ta.rising(low, stairBars)
|
||||
shortStair = ta.falling(close, stairBars) and ta.falling(high, stairBars)
|
||||
|
||||
longMacdCross = ta.crossover(macdLine, macdSignal)
|
||||
shortMacdCross = ta.crossunder(macdLine, macdSignal)
|
||||
longMacdShrink = macdHist < 0 and ta.rising(macdHist, macdShrinkLookback)
|
||||
shortMacdShrink = macdHist > 0 and ta.falling(macdHist, macdShrinkLookback)
|
||||
longMacdOk = macdMode == "关闭" or macdMode == "交叉/缩量二选一" and (longMacdCross or longMacdShrink) or macdMode == "必须交叉" and longMacdCross or macdMode == "必须缩量" and longMacdShrink
|
||||
shortMacdOk = macdMode == "关闭" or macdMode == "交叉/缩量二选一" and (shortMacdCross or shortMacdShrink) or macdMode == "必须交叉" and shortMacdCross or macdMode == "必须缩量" and shortMacdShrink
|
||||
|
||||
volumeOk = volumeMode == "关闭" or volumeMode == "放量确认" and volume >= volMa * volumeMultiplier or volumeMode == "缩量回踩" and volume <= volMa * pullbackVolumeMultiplier
|
||||
|
||||
f_levelScore() =>
|
||||
levelFast = ta.ema(close, emaFastLen)
|
||||
levelMid = ta.ema(close, emaMidLen)
|
||||
levelSlow = ta.ema(close, emaSlowLen)
|
||||
levelBias = ta.ema(close, emaBiasLen)
|
||||
priceScore = close > levelBias ? 1 : close < levelBias ? -1 : 0
|
||||
orderScore = levelFast > levelMid and levelMid > levelSlow ? 1 : levelFast < levelMid and levelMid < levelSlow ? -1 : 0
|
||||
slopeScore = levelFast > levelFast[1] and levelMid >= levelMid[1] ? 1 : levelFast < levelFast[1] and levelMid <= levelMid[1] ? -1 : 0
|
||||
biasSlopeScore = levelBias >= levelBias[angleLookback] ? 1 : levelBias <= levelBias[angleLookback] ? -1 : 0
|
||||
priceScore + orderScore + slopeScore + biasSlopeScore
|
||||
|
||||
autoLevelTf1 = timeframe.isminutes and timeframe.multiplier <= 1 ? "5" : timeframe.isminutes and timeframe.multiplier <= 5 ? "15" : timeframe.isminutes and timeframe.multiplier <= 15 ? "60" : levelTf1
|
||||
autoLevelTf2 = timeframe.isminutes and timeframe.multiplier <= 1 ? "15" : timeframe.isminutes and timeframe.multiplier <= 5 ? "60" : timeframe.isminutes and timeframe.multiplier <= 15 ? "240" : levelTf2
|
||||
effectiveLevelTf1 = levelPreset == "自动" ? autoLevelTf1 : levelPreset == "1m" ? "5" : levelPreset == "5m" ? "15" : levelPreset == "15m" ? "60" : levelTf1
|
||||
effectiveLevelTf2 = levelPreset == "自动" ? autoLevelTf2 : levelPreset == "1m" ? "15" : levelPreset == "5m" ? "60" : levelPreset == "15m" ? "240" : levelTf2
|
||||
|
||||
levelScore1 = request.security(syminfo.tickerid, effectiveLevelTf1, f_levelScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
levelScore2 = request.security(syminfo.tickerid, effectiveLevelTf2, f_levelScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
level1LongOk = levelScore1 > -levelStrongScore
|
||||
level1ShortOk = levelScore1 < levelStrongScore
|
||||
level2LongRisk = levelScore2 <= -levelStrongScore
|
||||
level2ShortRisk = levelScore2 >= levelStrongScore
|
||||
levelLongOk = not useMtfLevel or levelMode == "只标记" or (levelMode == "15m 过滤,1H 分级" and level1LongOk) or (levelMode == "15m+1H 都过滤" and level1LongOk and not level2LongRisk)
|
||||
levelShortOk = not useMtfLevel or levelMode == "只标记" or (levelMode == "15m 过滤,1H 分级" and level1ShortOk) or (levelMode == "15m+1H 都过滤" and level1ShortOk and not level2ShortRisk)
|
||||
|
||||
preHigh = ta.highest(high[1], preBreakLookback)
|
||||
preLow = ta.lowest(low[1], preBreakLookback)
|
||||
longPreBreak = high >= preHigh - atr * preBreakBufferAtr and close <= preHigh
|
||||
shortPreBreak = low <= preLow + atr * preBreakBufferAtr and close >= preLow
|
||||
longMomentumSetup = inSession and allowLong and levelLongOk and longShortRibbonOrder and fastAngle > 0 and close > emaMid and close > open and (close > emaFast or entrySensitivity == "灵敏")
|
||||
shortMomentumSetup = inSession and allowShort and levelShortOk and shortShortRibbonOrder and fastAngle < 0 and close < emaMid and close < open and (close < emaFast or entrySensitivity == "灵敏")
|
||||
longPreSetup = inSession and allowLong and levelLongOk and longShortRibbonOrder and fanWidthAtr <= preMaxFanWidthAtr and fastAngle > 0 and fanOpenNow and (longPreBreak or entrySensitivity == "灵敏" and longMomentumSetup) and close > emaMid and close > open and longMacdOk
|
||||
shortPreSetup = inSession and allowShort and levelShortOk and shortShortRibbonOrder and fanWidthAtr <= preMaxFanWidthAtr and fastAngle < 0 and fanOpenNow and (shortPreBreak or entrySensitivity == "灵敏" and shortMomentumSetup) and close < emaMid and close < open and shortMacdOk
|
||||
|
||||
longConfirmSetup = inSession and allowLong and levelLongOk and longRadiationOk and (longStair or entrySensitivity == "灵敏" and close > high[1]) and longMacdOk and volumeOk
|
||||
shortConfirmSetup = inSession and allowShort and levelShortOk and shortRadiationOk and (shortStair or entrySensitivity == "灵敏" and close < low[1]) and shortMacdOk and volumeOk
|
||||
|
||||
var int lastLongBar = na
|
||||
var int lastShortBar = na
|
||||
canLong = na(lastLongBar) or bar_index - lastLongBar > cooldownBars
|
||||
canShort = na(lastShortBar) or bar_index - lastShortBar > cooldownBars
|
||||
|
||||
usePre = signalMode == "预启动观察" or signalMode == "启动+预启动"
|
||||
useConfirm = signalMode == "启动确认" or signalMode == "启动+预启动"
|
||||
longPreSignal = barstate.isconfirmed and usePre and longPreSetup and not longPreSetup[1] and canLong
|
||||
shortPreSignal = barstate.isconfirmed and usePre and shortPreSetup and not shortPreSetup[1] and canShort
|
||||
longConfirmSignal = barstate.isconfirmed and useConfirm and longConfirmSetup and not longConfirmSetup[1] and canLong
|
||||
shortConfirmSignal = barstate.isconfirmed and useConfirm and shortConfirmSetup and not shortConfirmSetup[1] and canShort
|
||||
|
||||
longSignal = longPreSignal or longConfirmSignal
|
||||
shortSignal = shortPreSignal or shortConfirmSignal
|
||||
|
||||
if longSignal
|
||||
lastLongBar := bar_index
|
||||
|
||||
if shortSignal
|
||||
lastShortBar := bar_index
|
||||
|
||||
plot(emaFast, "EMA5", color=color.new(color.teal, 0), linewidth=1)
|
||||
plot(emaMid, "EMA15", color=color.new(color.orange, 0), linewidth=1)
|
||||
plot(emaSlow, "EMA30", color=color.new(color.yellow, 0), linewidth=1)
|
||||
plot(emaBias, "EMA144", color=color.new(color.red, 0), linewidth=2)
|
||||
|
||||
barcolor(showBarColor and longOrder ? color.new(color.green, 0) : showBarColor and shortOrder ? color.new(color.red, 0) : na)
|
||||
|
||||
plotshape(longConfirmSignal, title="放射确认做多", style=shape.labelup, location=location.belowbar, color=color.new(color.lime, 0), textcolor=color.black, text="做多")
|
||||
plotshape(shortConfirmSignal, title="放射确认做空", style=shape.labeldown, location=location.abovebar, color=color.new(color.red, 0), textcolor=color.white, text="做空")
|
||||
plotshape(showPreSignals and longPreSignal, title="预启动做多", style=shape.labelup, location=location.belowbar, color=color.new(color.aqua, 0), textcolor=color.black, size=size.tiny, text="预多")
|
||||
plotshape(showPreSignals and shortPreSignal, title="预启动做空", style=shape.labeldown, location=location.abovebar, color=color.new(color.fuchsia, 0), textcolor=color.white, size=size.tiny, text="预空")
|
||||
plotshape(showCandidateMarks and not longSignal and longPreSetup, title="候选:预启动做多", style=shape.circle, location=location.belowbar, color=color.new(color.aqua, 55), size=size.tiny)
|
||||
plotshape(showCandidateMarks and not shortSignal and shortPreSetup, title="候选:预启动做空", style=shape.circle, location=location.abovebar, color=color.new(color.fuchsia, 55), size=size.tiny)
|
||||
plotshape(showCandidateMarks and not longSignal and longConfirmSetup, title="候选:确认做多", style=shape.triangleup, location=location.belowbar, color=color.new(color.lime, 60), size=size.tiny)
|
||||
plotshape(showCandidateMarks and not shortSignal and shortConfirmSetup, title="候选:确认做空", style=shape.triangledown, location=location.abovebar, color=color.new(color.red, 60), size=size.tiny)
|
||||
plotshape(showRiskMarks and longSignal and level2LongRisk, title="逆大级别做多", style=shape.diamond, location=location.belowbar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
plotshape(showRiskMarks and shortSignal and level2ShortRisk, title="逆大级别做空", style=shape.diamond, location=location.abovebar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
|
||||
var table stateTable = table.new(position.top_right, 2, 7, border_width=1)
|
||||
|
||||
if showStateTable and barstate.islast
|
||||
directionText = longRadiationOk ? "多头放射" : shortRadiationOk ? "空头放射" : longOrder ? "多头排列" : shortOrder ? "空头排列" : "无排列"
|
||||
angleText = str.tostring(angleDiff, "#.0") + "°"
|
||||
radiationText = longRadiationRaw ? str.tostring(longRadiationBars) : shortRadiationRaw ? str.tostring(shortRadiationBars) : "0"
|
||||
stairText = longStair ? "阶梯向上" : shortStair ? "阶梯向下" : "未阶梯"
|
||||
macdText = longMacdCross ? "金叉" : shortMacdCross ? "死叉" : longMacdShrink or shortMacdShrink ? "柱缩" : "未确认"
|
||||
levelText = not useMtfLevel ? "关闭" : level2LongRisk and close > emaBias ? "逆" + effectiveLevelTf2 + "空" : level2ShortRisk and close < emaBias ? "逆" + effectiveLevelTf2 + "多" : levelScore1 >= levelStrongScore ? effectiveLevelTf1 + "多" : levelScore1 <= -levelStrongScore ? effectiveLevelTf1 + "空" : "中性"
|
||||
sensitivityText = entrySensitivity == "灵敏" ? "灵敏" : entrySensitivity == "均衡" ? "均衡" : "严格"
|
||||
signalText = longConfirmSignal ? "做多" : shortConfirmSignal ? "做空" : longPreSignal ? "预多" : shortPreSignal ? "预空" : "等待"
|
||||
|
||||
table.cell(stateTable, 0, 0, "方向", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 0, directionText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 1, "夹角", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 1, angleText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 2, "放射K数", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 2, radiationText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 3, "阶梯", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 3, stairText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 4, "MACD", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 4, macdText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 5, "级别", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 5, levelText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 6, "信号", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 6, signalText + " " + sensitivityText, text_color=color.white, bgcolor=longSignal ? color.new(color.green, 0) : shortSignal ? color.new(color.red, 0) : color.new(color.gray, 20))
|
||||
|
||||
alertcondition(longPreSignal, title="预启动做多", message="EMA5/15/30/144 多头排列初开,价格贴近上方突破位,出现预启动做多信号")
|
||||
alertcondition(shortPreSignal, title="预启动做空", message="EMA5/15/30/144 空头排列初开,价格贴近下方跌破位,出现预启动做空信号")
|
||||
alertcondition(longConfirmSignal, title="放射确认做多", message="EMA5/15/30/144 多头放射,阶梯向上,MACD/量能确认,出现做多信号")
|
||||
alertcondition(shortConfirmSignal, title="放射确认做空", message="EMA5/15/30/144 空头放射,阶梯向下,MACD/量能确认,出现做空信号")
|
||||
alertcondition(longSignal, title="综合做多", message="EMA 放射入场系统出现做多方向信号")
|
||||
alertcondition(shortSignal, title="综合做空", message="EMA 放射入场系统出现做空方向信号")
|
||||
196
pine/ema_5_15_30_144_macd_volume_radiation_strategy.pine
Normal file
196
pine/ema_5_15_30_144_macd_volume_radiation_strategy.pine
Normal file
@ -0,0 +1,196 @@
|
||||
//@version=6
|
||||
strategy(
|
||||
title="EMA 5/15/30/144 MACD Volume Radiation Strategy",
|
||||
shorttitle="EMA Radiation Strategy",
|
||||
overlay=true,
|
||||
pyramiding=0,
|
||||
initial_capital=100000,
|
||||
commission_type=strategy.commission.percent,
|
||||
commission_value=0.03,
|
||||
slippage=2,
|
||||
default_qty_type=strategy.percent_of_equity,
|
||||
default_qty_value=10,
|
||||
max_labels_count=500)
|
||||
|
||||
emaFastLen = input.int(5, "EMA 快线", minval=1)
|
||||
emaMidLen = input.int(15, "EMA 中线", minval=1)
|
||||
emaSlowLen = input.int(30, "EMA 慢线", minval=1)
|
||||
emaBiasLen = input.int(144, "EMA 主趋势线", minval=1)
|
||||
tradeSession = input.session("0000-2359", "交易定义时段")
|
||||
tradeDirection = input.string("多空都做", "交易方向", options=["多空都做", "只做多", "只做空"])
|
||||
|
||||
atrLen = input.int(14, "ATR 长度", minval=1)
|
||||
angleLookback = input.int(5, "夹角计算回看 K 数", minval=1, maxval=50)
|
||||
minAngleDiff = input.float(30.0, "EMA5-EMA144 最小夹角差", minval=0.0, step=1.0)
|
||||
minFanWidthAtr = input.float(0.80, "放射均线最小宽度 / ATR", minval=0.0, step=0.05)
|
||||
expansionLookback = input.int(3, "放射扩张连续 K 数", minval=1, maxval=20)
|
||||
minRadiationBars = input.int(3, "放射延续最少 K 数", minval=1, maxval=50)
|
||||
maxRadiationBars = input.int(40, "放射最长追踪 K 数", minval=1, maxval=300)
|
||||
stairBars = input.int(3, "阶梯 K 线根数", minval=2, maxval=8)
|
||||
|
||||
macdFastLen = input.int(12, "MACD 快线", minval=1)
|
||||
macdSlowLen = input.int(26, "MACD 慢线", minval=1)
|
||||
macdSignalLen = input.int(9, "MACD 信号线", minval=1)
|
||||
macdMode = input.string("交叉/缩量二选一", "MACD 标准", options=["交叉/缩量二选一", "必须交叉", "必须缩量", "关闭"])
|
||||
macdShrinkLookback = input.int(3, "MACD 缩量连续 K 数", minval=1, maxval=20)
|
||||
|
||||
volumeLen = input.int(20, "量能均线长度", minval=1)
|
||||
volumeMode = input.string("放量确认", "量能标准", options=["放量确认", "缩量回踩", "关闭"])
|
||||
volumeMultiplier = input.float(1.10, "放量倍数", minval=0.1, step=0.05)
|
||||
pullbackVolumeMultiplier = input.float(0.90, "缩量回踩倍数", minval=0.1, step=0.05)
|
||||
|
||||
useMtfLevel = input.bool(true, "启用级别定义过滤")
|
||||
levelTf1 = input.timeframe("15", "级别一")
|
||||
levelTf2 = input.timeframe("60", "级别二")
|
||||
levelStrongScore = input.int(2, "大级别强趋势分数", minval=1, maxval=4)
|
||||
levelMode = input.string("15m 过滤,1H 分级", "级别过滤模式", options=["15m 过滤,1H 分级", "15m+1H 都过滤", "只标记"])
|
||||
|
||||
stopMode = input.string("ATR 止损", "止损模式", options=["ATR 止损", "EMA30 结构止损"])
|
||||
stopAtr = input.float(1.60, "ATR 止损倍数", minval=0.1, step=0.1)
|
||||
takeProfitAtr = input.float(3.20, "ATR 止盈倍数", minval=0.1, step=0.1)
|
||||
useTrail = input.bool(true, "启用 EMA30 移动止损")
|
||||
exitOnOrderBreak = input.bool(true, "均线排列破坏离场")
|
||||
|
||||
showStateTable = input.bool(true, "显示状态面板")
|
||||
showRiskMarks = input.bool(true, "显示逆大级别风险标记")
|
||||
|
||||
emaFast = ta.ema(close, emaFastLen)
|
||||
emaMid = ta.ema(close, emaMidLen)
|
||||
emaSlow = ta.ema(close, emaSlowLen)
|
||||
emaBias = ta.ema(close, emaBiasLen)
|
||||
atr = ta.atr(atrLen)
|
||||
volMa = ta.sma(volume, volumeLen)
|
||||
[macdLine, macdSignal, macdHist] = ta.macd(close, macdFastLen, macdSlowLen, macdSignalLen)
|
||||
|
||||
inSession = not na(time(timeframe.period, tradeSession))
|
||||
allowLong = tradeDirection != "只做空"
|
||||
allowShort = tradeDirection != "只做多"
|
||||
|
||||
longOrder = emaBias < emaSlow and emaSlow < emaMid and emaMid < emaFast
|
||||
shortOrder = emaBias > emaSlow and emaSlow > emaMid and emaMid > emaFast
|
||||
|
||||
f_angle(src) =>
|
||||
atrSafe = math.max(ta.atr(atrLen), syminfo.mintick)
|
||||
math.atan((src - src[angleLookback]) / (atrSafe * angleLookback)) * 180.0 / math.pi
|
||||
|
||||
fastAngle = f_angle(emaFast)
|
||||
biasAngle = f_angle(emaBias)
|
||||
angleDiff = math.abs(fastAngle - biasAngle)
|
||||
longAngleOk = fastAngle > 0 and angleDiff >= minAngleDiff
|
||||
shortAngleOk = fastAngle < 0 and angleDiff >= minAngleDiff
|
||||
|
||||
fanWidth = math.abs(emaFast - emaBias)
|
||||
fanWidthAtr = atr > syminfo.mintick ? fanWidth / atr : 0.0
|
||||
gapFastMid = math.abs(emaFast - emaMid)
|
||||
gapMidSlow = math.abs(emaMid - emaSlow)
|
||||
gapSlowBias = math.abs(emaSlow - emaBias)
|
||||
fanWidthOk = fanWidthAtr >= minFanWidthAtr
|
||||
fanOpenNow = gapFastMid >= gapFastMid[1] and gapMidSlow >= gapMidSlow[1] and gapSlowBias >= gapSlowBias[1]
|
||||
fanOpenContinuous = math.sum(fanOpenNow ? 1.0 : 0.0, expansionLookback) == expansionLookback
|
||||
|
||||
longRadiationRaw = longOrder and longAngleOk and fanWidthOk and fanOpenContinuous
|
||||
shortRadiationRaw = shortOrder and shortAngleOk and fanWidthOk and fanOpenContinuous
|
||||
longRadiationBars = longRadiationRaw ? nz(ta.barssince(not longRadiationRaw), 100000) : 0
|
||||
shortRadiationBars = shortRadiationRaw ? nz(ta.barssince(not shortRadiationRaw), 100000) : 0
|
||||
longRadiationOk = longRadiationBars >= minRadiationBars and longRadiationBars <= maxRadiationBars
|
||||
shortRadiationOk = shortRadiationBars >= minRadiationBars and shortRadiationBars <= maxRadiationBars
|
||||
|
||||
longStair = ta.rising(close, stairBars) and ta.rising(low, stairBars)
|
||||
shortStair = ta.falling(close, stairBars) and ta.falling(high, stairBars)
|
||||
|
||||
longMacdCross = ta.crossover(macdLine, macdSignal)
|
||||
shortMacdCross = ta.crossunder(macdLine, macdSignal)
|
||||
longMacdShrink = macdHist < 0 and ta.rising(macdHist, macdShrinkLookback)
|
||||
shortMacdShrink = macdHist > 0 and ta.falling(macdHist, macdShrinkLookback)
|
||||
longMacdOk = macdMode == "关闭" or macdMode == "交叉/缩量二选一" and (longMacdCross or longMacdShrink) or macdMode == "必须交叉" and longMacdCross or macdMode == "必须缩量" and longMacdShrink
|
||||
shortMacdOk = macdMode == "关闭" or macdMode == "交叉/缩量二选一" and (shortMacdCross or shortMacdShrink) or macdMode == "必须交叉" and shortMacdCross or macdMode == "必须缩量" and shortMacdShrink
|
||||
|
||||
longVolumeOk = volumeMode == "关闭" or volumeMode == "放量确认" and volume >= volMa * volumeMultiplier or volumeMode == "缩量回踩" and volume <= volMa * pullbackVolumeMultiplier
|
||||
shortVolumeOk = longVolumeOk
|
||||
|
||||
f_levelScore() =>
|
||||
levelFast = ta.ema(close, emaFastLen)
|
||||
levelMid = ta.ema(close, emaMidLen)
|
||||
levelSlow = ta.ema(close, emaSlowLen)
|
||||
levelBias = ta.ema(close, emaBiasLen)
|
||||
priceScore = close > levelBias ? 1 : close < levelBias ? -1 : 0
|
||||
orderScore = levelFast > levelMid and levelMid > levelSlow ? 1 : levelFast < levelMid and levelMid < levelSlow ? -1 : 0
|
||||
slopeScore = levelFast > levelFast[1] and levelMid >= levelMid[1] ? 1 : levelFast < levelFast[1] and levelMid <= levelMid[1] ? -1 : 0
|
||||
biasSlopeScore = levelBias >= levelBias[angleLookback] ? 1 : levelBias <= levelBias[angleLookback] ? -1 : 0
|
||||
priceScore + orderScore + slopeScore + biasSlopeScore
|
||||
|
||||
levelScore1 = request.security(syminfo.tickerid, levelTf1, f_levelScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
levelScore2 = request.security(syminfo.tickerid, levelTf2, f_levelScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
level1LongOk = levelScore1 > -levelStrongScore
|
||||
level1ShortOk = levelScore1 < levelStrongScore
|
||||
level2LongRisk = levelScore2 <= -levelStrongScore
|
||||
level2ShortRisk = levelScore2 >= levelStrongScore
|
||||
levelLongOk = not useMtfLevel or levelMode == "只标记" or (levelMode == "15m 过滤,1H 分级" and level1LongOk) or (levelMode == "15m+1H 都过滤" and level1LongOk and not level2LongRisk)
|
||||
levelShortOk = not useMtfLevel or levelMode == "只标记" or (levelMode == "15m 过滤,1H 分级" and level1ShortOk) or (levelMode == "15m+1H 都过滤" and level1ShortOk and not level2ShortRisk)
|
||||
|
||||
longSetup = inSession and allowLong and levelLongOk and longRadiationOk and longStair and longMacdOk and longVolumeOk
|
||||
shortSetup = inSession and allowShort and levelShortOk and shortRadiationOk and shortStair and shortMacdOk and shortVolumeOk
|
||||
|
||||
longSignal = barstate.isconfirmed and longSetup and not longSetup[1]
|
||||
shortSignal = barstate.isconfirmed and shortSetup and not shortSetup[1]
|
||||
|
||||
longStopBase = stopMode == "ATR 止损" ? close - atr * stopAtr : emaSlow - atr * 0.20
|
||||
shortStopBase = stopMode == "ATR 止损" ? close + atr * stopAtr : emaSlow + atr * 0.20
|
||||
longTakeProfit = close + atr * takeProfitAtr
|
||||
shortTakeProfit = close - atr * takeProfitAtr
|
||||
|
||||
if longSignal
|
||||
strategy.entry("Long", strategy.long, alert_message="EMA5/15/30/144 多头放射,阶梯向上,MACD/量能确认,出现做多信号")
|
||||
strategy.exit("Long Exit", "Long", stop=longStopBase, limit=longTakeProfit)
|
||||
|
||||
if shortSignal
|
||||
strategy.entry("Short", strategy.short, alert_message="EMA5/15/30/144 空头放射,阶梯向下,MACD/量能确认,出现做空信号")
|
||||
strategy.exit("Short Exit", "Short", stop=shortStopBase, limit=shortTakeProfit)
|
||||
|
||||
if useTrail and strategy.position_size > 0
|
||||
strategy.exit("Long Trail", "Long", stop=emaSlow - atr * 0.20)
|
||||
|
||||
if useTrail and strategy.position_size < 0
|
||||
strategy.exit("Short Trail", "Short", stop=emaSlow + atr * 0.20)
|
||||
|
||||
if exitOnOrderBreak and strategy.position_size > 0 and not longOrder
|
||||
strategy.close("Long", comment="多头排列破坏")
|
||||
|
||||
if exitOnOrderBreak and strategy.position_size < 0 and not shortOrder
|
||||
strategy.close("Short", comment="空头排列破坏")
|
||||
|
||||
plot(emaFast, "EMA5", color=color.new(color.teal, 0), linewidth=1)
|
||||
plot(emaMid, "EMA15", color=color.new(color.orange, 0), linewidth=1)
|
||||
plot(emaSlow, "EMA30", color=color.new(color.yellow, 0), linewidth=1)
|
||||
plot(emaBias, "EMA144", color=color.new(color.red, 0), linewidth=2)
|
||||
|
||||
plotshape(longSignal, title="做多", style=shape.labelup, location=location.belowbar, color=color.new(color.lime, 0), textcolor=color.black, text="做多")
|
||||
plotshape(shortSignal, title="做空", style=shape.labeldown, location=location.abovebar, color=color.new(color.red, 0), textcolor=color.white, text="做空")
|
||||
plotshape(showRiskMarks and longSignal and level2LongRisk, title="逆大级别做多", style=shape.diamond, location=location.belowbar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
plotshape(showRiskMarks and shortSignal and level2ShortRisk, title="逆大级别做空", style=shape.diamond, location=location.abovebar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
|
||||
var table stateTable = table.new(position.top_right, 2, 7, border_width=1)
|
||||
|
||||
if showStateTable and barstate.islast
|
||||
directionText = longRadiationOk ? "多头放射" : shortRadiationOk ? "空头放射" : longOrder or shortOrder ? "排列中" : "无排列"
|
||||
angleText = str.tostring(angleDiff, "#.0") + "°"
|
||||
radiationText = longRadiationRaw ? str.tostring(longRadiationBars) : shortRadiationRaw ? str.tostring(shortRadiationBars) : "0"
|
||||
stairText = longStair ? "三阶向上" : shortStair ? "三阶向下" : "未阶梯"
|
||||
macdText = longMacdCross ? "金叉" : shortMacdCross ? "死叉" : longMacdShrink or shortMacdShrink ? "柱缩" : "未确认"
|
||||
levelText = not useMtfLevel ? "关闭" : level2LongRisk and close > emaBias ? "逆1H空" : level2ShortRisk and close < emaBias ? "逆1H多" : levelScore1 >= levelStrongScore ? "15m多" : levelScore1 <= -levelStrongScore ? "15m空" : "中性"
|
||||
signalText = longSignal ? "做多" : shortSignal ? "做空" : "等待"
|
||||
|
||||
table.cell(stateTable, 0, 0, "方向", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 0, directionText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 1, "夹角", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 1, angleText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 2, "放射K数", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 2, radiationText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 3, "阶梯", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 3, stairText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 4, "MACD", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 4, macdText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 5, "级别", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 5, levelText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 6, "信号", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 6, signalText, text_color=color.white, bgcolor=longSignal ? color.new(color.green, 0) : shortSignal ? color.new(color.red, 0) : color.new(color.gray, 20))
|
||||
957
pine/ema_ribbon_state_signal_indicator.pine
Normal file
957
pine/ema_ribbon_state_signal_indicator.pine
Normal file
@ -0,0 +1,957 @@
|
||||
//@version=6
|
||||
indicator(
|
||||
title="EMA Ribbon State Signal",
|
||||
shorttitle="EMA Ribbon State",
|
||||
overlay=true,
|
||||
max_labels_count=500,
|
||||
max_boxes_count=500)
|
||||
|
||||
plot(na, title="脚本锚点", display=display.none)
|
||||
|
||||
emaFastLen = input.int(5, "EMA 快线", minval=1)
|
||||
emaMidLen = input.int(15, "EMA 中线", minval=1)
|
||||
emaSlowLen = input.int(30, "EMA 慢线", minval=1)
|
||||
emaBiasLen = input.int(144, "EMA 多空分界线", minval=1)
|
||||
|
||||
atrLen = input.int(14, "ATR 长度", minval=1)
|
||||
signalProfile = input.string("均衡", "信号风格", options=["激进", "均衡", "保守"])
|
||||
mainSignalMode = input.string("只做趋势回踩", "主信号模式", options=["只做趋势回踩", "启动+趋势回踩"])
|
||||
cooldownBars = input.int(10, "同向信号冷却 K 数", minval=0, maxval=100)
|
||||
globalCooldownBars = input.int(6, "任意信号冷却 K 数", minval=0, maxval=100)
|
||||
useLateTrendFilter = input.bool(true, "启用趋势末段风险过滤")
|
||||
maxMainSignalsPerTrend = input.int(6, "单段趋势最多主信号次数", minval=0, maxval=20)
|
||||
maxTrendBars = input.int(0, "趋势最长有效 K 数", minval=0, maxval=300)
|
||||
useAdxFilter = input.bool(true, "启用 ADX 趋势过滤")
|
||||
adxLen = input.int(14, "ADX 长度", minval=1)
|
||||
adxSmoothing = input.int(14, "ADX 平滑", minval=1)
|
||||
minAdx = input.float(18.0, "ADX 最小值", minval=0.0, step=0.5)
|
||||
allowRisingAdxLaunch = input.bool(true, "启动允许 ADX 上升替代阈值")
|
||||
requireDiDirection = input.bool(true, "要求 DI 方向一致")
|
||||
|
||||
useBiasSide = input.bool(true, "要求价格在 EMA144 同侧")
|
||||
requireRibbonBiasSide = input.bool(true, "要求均线带在 EMA144 同侧")
|
||||
allowRibbonCrossLaunch = input.bool(true, "启动允许均线带刚穿越 EMA144")
|
||||
useBiasSlope = input.bool(false, "要求 EMA144 同向斜率")
|
||||
biasSlopeLookback = input.int(10, "EMA144 斜率回看 K 数", minval=1, maxval=100)
|
||||
avoidOppositeHardTrend = input.bool(true, "禁止逆 144 + 均线排列")
|
||||
avoidChopZone = input.bool(true, "避开价格均线缠绕区")
|
||||
chopLookback = input.int(10, "缠绕检测回看 K 数", minval=3, maxval=80)
|
||||
chopMaxCrosses = input.int(4, "缠绕最大允许穿均线次数", minval=0, maxval=30)
|
||||
chopRibbonAtr = input.float(0.35, "缠绕均线带过窄 / ATR", minval=0.0, step=0.05)
|
||||
chopBiasDistanceAtr = input.float(0.45, "缠绕离 EMA144 过近 / ATR", minval=0.0, step=0.05)
|
||||
chopBiasBandAtr = input.float(0.80, "144 横盘带宽 / ATR", minval=0.0, step=0.05)
|
||||
chopExitConfirmBars = input.int(0, "脱离缠绕后确认 K 数", minval=0, maxval=20)
|
||||
chopRequireCleanClose = input.bool(true, "信号 K 必须收在均线带外")
|
||||
|
||||
compressionLookback = input.int(18, "启动前压缩回看 K 数", minval=3, maxval=120)
|
||||
compressionAtr = input.float(0.55, "启动前最大均线带宽 / ATR", minval=0.0, step=0.05)
|
||||
launchBreakLookback = input.int(4, "启动突破结构回看 K 数", minval=2, maxval=80)
|
||||
launchFreshBars = input.int(8, "启动后有效 K 数", minval=1, maxval=50)
|
||||
minLaunchBodyAtr = input.float(0.08, "启动确认实体 / ATR", minval=0.0, step=0.01)
|
||||
launchEscapeDistanceAtr = input.float(0.12, "启动脱离均线带距离 / ATR", minval=0.0, step=0.01)
|
||||
launchMinRibbonAtr = input.float(0.20, "启动后最小均线带宽 / ATR", minval=0.0, step=0.01)
|
||||
launchChopBodyAtr = input.float(0.18, "缠绕逃逸实体 / ATR", minval=0.0, step=0.01)
|
||||
launchBiasEscapeAtr = input.float(0.12, "缠绕逃逸离 EMA144 / ATR", minval=0.0, step=0.01)
|
||||
prelaunchMode = input.string("辅助标记", "预启动信号模式", options=["关闭", "辅助标记", "并入主信号"])
|
||||
prelaunchCooldownBars = input.int(12, "预启动信号冷却 K 数", minval=0, maxval=100)
|
||||
prelaunchMaxRibbonAtr = input.float(0.75, "预启动最大均线带宽 / ATR", minval=0.0, step=0.05)
|
||||
prelaunchBreakBufferAtr = input.float(0.18, "预启动贴近突破位 / ATR", minval=0.0, step=0.01)
|
||||
prelaunchBiasNearAtr = input.float(0.35, "预启动允许贴近 EMA144 / ATR", minval=0.0, step=0.05)
|
||||
prelaunchMinBodyAtr = input.float(0.04, "预启动最小实体 / ATR", minval=0.0, step=0.01)
|
||||
prelaunchMaxBiasCrosses = input.int(1, "预启动最大 EMA144 反复穿越", minval=0, maxval=10)
|
||||
prelaunchMaxRibbonCrosses = input.int(3, "预启动最大短均线反复穿越", minval=0, maxval=30)
|
||||
prelaunchMinBreakCloseAtr = input.float(0.04, "预启动离突破位最小差距 / ATR", minval=0.0, step=0.01)
|
||||
|
||||
pullbackLookback = input.int(5, "中继回踩有效 K 数", minval=1, maxval=30)
|
||||
trendMatureBars = input.int(4, "趋势形成确认 K 数", minval=0, maxval=50)
|
||||
trendAwayAtr = input.float(0.25, "趋势离 EMA144 最小距离 / ATR", minval=0.0, step=0.05)
|
||||
minTrendRibbonAtr = input.float(0.35, "趋势均线带最小发散 / ATR", minval=0.0, step=0.05)
|
||||
minTrendGapAtr = input.float(0.04, "EMA 间最小间距 / ATR", minval=0.0, step=0.01)
|
||||
trendExpansionLookback = input.int(8, "趋势发散确认回看 K 数", minval=1, maxval=50)
|
||||
requireRecentBiasBreakout = input.bool(false, "要求近期突破 EMA144")
|
||||
biasBreakoutRetestBars = input.int(40, "突破 EMA144 后回踩有效 K 数", minval=1, maxval=200)
|
||||
useBreakoutLevelRetest = input.bool(false, "要求回踩突破结构位")
|
||||
breakoutLevelLookback = input.int(24, "突破结构位回看 K 数", minval=3, maxval=200)
|
||||
breakoutLevelRetestAtr = input.float(0.60, "突破结构位回踩容差 / ATR", minval=0.0, step=0.05)
|
||||
minBreakoutBodyAtr = input.float(0.20, "突破 144 最小实体 / ATR", minval=0.0, step=0.05)
|
||||
useBiasRetestPullback = input.bool(true, "回踩/反抽允许测试 EMA144")
|
||||
biasRetestAtr = input.float(0.30, "EMA144 回踩/反抽容差 / ATR", minval=0.0, step=0.05)
|
||||
minContinuationBodyAtr = input.float(0.05, "中继确认实体 / ATR", minval=0.0, step=0.01)
|
||||
maxContinuationDistanceAtr = input.float(1.30, "中继确认离 EMA5 最远 / ATR", minval=0.1, step=0.05)
|
||||
maxContinuationDistanceMidAtr = input.float(0.75, "中继确认离 EMA15 最远 / ATR", minval=0.1, step=0.05)
|
||||
entryRangeLookback = input.int(20, "入场位置回看 K 数", minval=5, maxval=120)
|
||||
maxLongEntryRangePosition = input.float(0.68, "做多确认最高区间位置", minval=0.1, maxval=1.0, step=0.05)
|
||||
minShortEntryRangePosition = input.float(0.32, "做空确认最低区间位置", minval=0.0, maxval=0.9, step=0.05)
|
||||
|
||||
extremeLookback = input.int(14, "避免局部高低点回看 K 数", minval=3, maxval=100)
|
||||
maxLongRangePosition = input.float(0.82, "做多最高允许区间位置", minval=0.1, maxval=1.0, step=0.05)
|
||||
minShortRangePosition = input.float(0.18, "做空最低允许区间位置", minval=0.0, maxval=0.9, step=0.05)
|
||||
useStructureZoneFilter = input.bool(true, "启用供需区空间过滤")
|
||||
showStructureZones = input.bool(true, "显示供需区 Box")
|
||||
showHtfStructureZones = input.bool(true, "显示高周期供需区 Box")
|
||||
useHtfStructureFilter = input.bool(true, "高周期供需区参与信号过滤")
|
||||
htfStructureTf1 = input.timeframe("60", "高周期供需区一")
|
||||
htfStructureTf2 = input.timeframe("240", "高周期供需区二")
|
||||
useHtfZoneHardBlock = input.bool(true, "高周期供需区硬拦截")
|
||||
htfZoneBlockAtr = input.float(1.20, "高周期供需区禁入缓冲 / ATR", minval=0.0, step=0.05)
|
||||
htfZoneTouchBlockBars = input.int(8, "触碰高周期区后禁反向 K 数", minval=0, maxval=50)
|
||||
useZoneReactionBlock = input.bool(true, "供需区反应拦截")
|
||||
zoneReactionBlockBars = input.int(10, "供需区反应后禁反向 K 数", minval=0, maxval=80)
|
||||
minZoneReactionBodyAtr = input.float(0.20, "供需区反应实体 / ATR", minval=0.0, step=0.05)
|
||||
zoneImpulseAtr = input.float(2.20, "供需区前置冲击 / ATR", minval=0.0, step=0.10)
|
||||
structureLookback = input.int(120, "供需区回看 K 数", minval=20, maxval=500)
|
||||
structurePivotLeft = input.int(6, "供需区摆点左侧 K 数", minval=1, maxval=20)
|
||||
structurePivotRight = input.int(6, "供需区摆点右侧 K 数", minval=1, maxval=20)
|
||||
minStructureReactionAtr = input.float(1.20, "供需区最小反应 / ATR", minval=0.0, step=0.05)
|
||||
structureZoneAtr = input.float(0.60, "供需区厚度 / ATR", minval=0.0, step=0.05)
|
||||
minRoomToZoneAtr = input.float(0.80, "信号到供需区最小空间 / ATR", minval=0.0, step=0.05)
|
||||
maxStructureBoxes = input.int(3, "每边最多显示供需区数量", minval=1, maxval=20)
|
||||
maxHtfStructureBoxes = input.int(2, "高周期每边最多显示数量", minval=1, maxval=10)
|
||||
maxZoneTests = input.int(3, "供需区弱化测试次数", minval=1, maxval=10)
|
||||
|
||||
useMtfTrendFilter = input.bool(true, "启用多周期趋势过滤")
|
||||
mtfFilterTf1 = input.timeframe("15", "方向过滤周期一")
|
||||
mtfFilterTf2 = input.timeframe("30", "方向过滤周期二")
|
||||
mtfRiskTf = input.timeframe("60", "风险分级周期")
|
||||
mtfStrongScore = input.int(2, "多周期强趋势分数", minval=1, maxval=4)
|
||||
mtfRiskMode = input.string("只标记风险", "风险周期强反向处理", options=["只标记风险", "拦截强反向"])
|
||||
showMtfRiskMarks = input.bool(true, "显示逆大周期风险标记")
|
||||
|
||||
showAuxMarks = input.bool(true, "显示信号来源小标记")
|
||||
showStateTable = input.bool(true, "显示状态面板")
|
||||
showBarColor = input.bool(false, "K 线按均线带状态染色")
|
||||
|
||||
emaFast = ta.ema(close, emaFastLen)
|
||||
emaMid = ta.ema(close, emaMidLen)
|
||||
emaSlow = ta.ema(close, emaSlowLen)
|
||||
emaBias = ta.ema(close, emaBiasLen)
|
||||
atr = ta.atr(atrLen)
|
||||
[diPlus, diMinus, adx] = ta.dmi(adxLen, adxSmoothing)
|
||||
|
||||
body = math.abs(close - open)
|
||||
ribbonWidth = math.abs(emaFast - emaSlow)
|
||||
fastMidSpread = math.abs(emaFast - emaMid)
|
||||
midSlowSpread = math.abs(emaMid - emaSlow)
|
||||
ribbonWidthAtr = atr > syminfo.mintick ? ribbonWidth / atr : 0.0
|
||||
ribbonHigh = math.max(math.max(emaFast, emaMid), emaSlow)
|
||||
ribbonLow = math.min(math.min(emaFast, emaMid), emaSlow)
|
||||
bullishEngulfing = close > open and close[1] < open[1] and close >= open[1] and open <= close[1]
|
||||
bearishEngulfing = close < open and close[1] > open[1] and close <= open[1] and open >= close[1]
|
||||
|
||||
bullOrder = emaFast > emaMid and emaMid > emaSlow
|
||||
bearOrder = emaFast < emaMid and emaMid < emaSlow
|
||||
bullSlopeCount = (emaFast > emaFast[1] ? 1 : 0) + (emaMid > emaMid[1] ? 1 : 0) + (emaSlow > emaSlow[1] ? 1 : 0)
|
||||
bearSlopeCount = (emaFast < emaFast[1] ? 1 : 0) + (emaMid < emaMid[1] ? 1 : 0) + (emaSlow < emaSlow[1] ? 1 : 0)
|
||||
ribbonExpanding = ribbonWidth > ribbonWidth[1] and fastMidSpread >= fastMidSpread[1]
|
||||
ribbonSeparated = ribbonWidthAtr >= minTrendRibbonAtr and fastMidSpread >= atr * minTrendGapAtr and midSlowSpread >= atr * minTrendGapAtr
|
||||
ribbonExpansionNow = ribbonSeparated and ribbonWidth > ribbonWidth[1] and fastMidSpread >= fastMidSpread[1] and midSlowSpread >= midSlowSpread[1]
|
||||
ribbonExpansionRecent = ta.highest(ribbonExpansionNow ? 1.0 : 0.0, trendExpansionLookback) > 0
|
||||
bullRibbonExpanding = ribbonSeparated and ribbonExpansionRecent
|
||||
bearRibbonExpanding = ribbonSeparated and ribbonExpansionRecent
|
||||
|
||||
profileSlopeNeed = signalProfile == "激进" ? 1 : signalProfile == "均衡" ? 2 : 3
|
||||
profileBreakNeed = signalProfile != "激进"
|
||||
|
||||
biasBullOk = (not useBiasSide or close > emaBias) and (not requireRibbonBiasSide or ribbonLow > emaBias)
|
||||
biasBearOk = (not useBiasSide or close < emaBias) and (not requireRibbonBiasSide or ribbonHigh < emaBias)
|
||||
biasBullLaunchOk = (not useBiasSide or close > emaBias) and (not requireRibbonBiasSide or ribbonLow > emaBias or (allowRibbonCrossLaunch and close > emaBias + atr * launchBiasEscapeAtr and emaFast > emaBias and emaMid > emaBias))
|
||||
biasBearLaunchOk = (not useBiasSide or close < emaBias) and (not requireRibbonBiasSide or ribbonHigh < emaBias or (allowRibbonCrossLaunch and close < emaBias - atr * launchBiasEscapeAtr and emaFast < emaBias and emaMid < emaBias))
|
||||
biasSlopeBullOk = not useBiasSlope or emaBias >= emaBias[biasSlopeLookback]
|
||||
biasSlopeBearOk = not useBiasSlope or emaBias <= emaBias[biasSlopeLookback]
|
||||
adxStrong = adx >= minAdx
|
||||
adxRising = adx > adx[1] and adx[1] > adx[2]
|
||||
adxLaunchOk = not useAdxFilter or adxStrong or (allowRisingAdxLaunch and adxRising)
|
||||
adxContinuationOk = not useAdxFilter or adxStrong
|
||||
diBullOk = not requireDiDirection or diPlus > diMinus
|
||||
diBearOk = not requireDiDirection or diMinus > diPlus
|
||||
|
||||
f_mtfTrendScore() =>
|
||||
mtfFast = ta.ema(close, emaFastLen)
|
||||
mtfMid = ta.ema(close, emaMidLen)
|
||||
mtfSlow = ta.ema(close, emaSlowLen)
|
||||
mtfBias = ta.ema(close, emaBiasLen)
|
||||
priceScore = close > mtfBias ? 1 : close < mtfBias ? -1 : 0
|
||||
orderScore = mtfFast > mtfMid and mtfMid > mtfSlow ? 1 : mtfFast < mtfMid and mtfMid < mtfSlow ? -1 : 0
|
||||
fastSlopeScore = mtfFast > mtfFast[1] and mtfMid >= mtfMid[1] ? 1 : mtfFast < mtfFast[1] and mtfMid <= mtfMid[1] ? -1 : 0
|
||||
biasSlopeScore = mtfBias >= mtfBias[biasSlopeLookback] ? 1 : mtfBias <= mtfBias[biasSlopeLookback] ? -1 : 0
|
||||
priceScore + orderScore + fastSlopeScore + biasSlopeScore
|
||||
|
||||
mtfScore1 = request.security(syminfo.tickerid, mtfFilterTf1, f_mtfTrendScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
mtfScore2 = request.security(syminfo.tickerid, mtfFilterTf2, f_mtfTrendScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
mtfRiskScore = request.security(syminfo.tickerid, mtfRiskTf, f_mtfTrendScore(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
mtfLongFilterOk = not useMtfTrendFilter or (mtfScore1 > -mtfStrongScore and mtfScore2 > -mtfStrongScore)
|
||||
mtfShortFilterOk = not useMtfTrendFilter or (mtfScore1 < mtfStrongScore and mtfScore2 < mtfStrongScore)
|
||||
mtfLongRisk = useMtfTrendFilter and mtfRiskScore <= -mtfStrongScore
|
||||
mtfShortRisk = useMtfTrendFilter and mtfRiskScore >= mtfStrongScore
|
||||
mtfRiskBlocks = mtfRiskMode == "拦截强反向"
|
||||
mtfLongOk = mtfLongFilterOk and (not mtfRiskBlocks or not mtfLongRisk)
|
||||
mtfShortOk = mtfShortFilterOk and (not mtfRiskBlocks or not mtfShortRisk)
|
||||
|
||||
hardBullContext = close > emaBias and bullOrder
|
||||
hardBearContext = close < emaBias and bearOrder
|
||||
longDirectionOk = not avoidOppositeHardTrend or not hardBearContext
|
||||
shortDirectionOk = not avoidOppositeHardTrend or not hardBullContext
|
||||
|
||||
crossFastCount = math.sum(ta.cross(close, emaFast) ? 1.0 : 0.0, chopLookback)
|
||||
crossMidCount = math.sum(ta.cross(close, emaMid) ? 1.0 : 0.0, chopLookback)
|
||||
crossSlowCount = math.sum(ta.cross(close, emaSlow) ? 1.0 : 0.0, chopLookback)
|
||||
priceCrossRibbonCount = crossFastCount + crossMidCount + crossSlowCount
|
||||
priceInsideRibbon = close <= ribbonHigh and close >= ribbonLow
|
||||
ribbonInsideBar = high >= ribbonHigh and low <= ribbonLow
|
||||
nearBias = math.abs(close - emaBias) <= atr * chopBiasDistanceAtr
|
||||
biasRangeOverlap = ta.highest(high, chopLookback) >= emaBias and ta.lowest(low, chopLookback) <= emaBias
|
||||
biasBandRange = ta.highest(high, chopLookback) - ta.lowest(low, chopLookback)
|
||||
biasSideFlips = math.sum(ta.cross(close, emaBias) ? 1.0 : 0.0, chopLookback)
|
||||
ribbonStraddlesBias = ribbonLow <= emaBias and ribbonHigh >= emaBias
|
||||
biasChopZone = biasRangeOverlap and biasBandRange <= atr * chopBiasBandAtr
|
||||
narrowRibbon = ribbonWidthAtr <= chopRibbonAtr and not ribbonExpanding
|
||||
chopZone = avoidChopZone and (priceCrossRibbonCount > chopMaxCrosses or priceInsideRibbon or ribbonInsideBar or nearBias or biasChopZone or biasSideFlips > 0 or ribbonStraddlesBias or narrowRibbon)
|
||||
barsSinceChop = nz(ta.barssince(chopZone), 100000)
|
||||
chopExitConfirmed = not avoidChopZone or barsSinceChop >= chopExitConfirmBars
|
||||
longCleanClose = not chopRequireCleanClose or close > ribbonHigh
|
||||
shortCleanClose = not chopRequireCleanClose or close < ribbonLow
|
||||
launchBaseEscapeOk = not avoidChopZone or ((not priceInsideRibbon) and (not ribbonInsideBar) and (not narrowRibbon))
|
||||
launchChopContext = avoidChopZone and (priceCrossRibbonCount > chopMaxCrosses or nearBias or biasChopZone or biasSideFlips > 0 or ribbonStraddlesBias or narrowRibbon)
|
||||
longLaunchDistanceOk = close - ribbonHigh >= atr * launchEscapeDistanceAtr
|
||||
shortLaunchDistanceOk = ribbonLow - close >= atr * launchEscapeDistanceAtr
|
||||
launchRibbonOpenOk = ribbonWidthAtr >= launchMinRibbonAtr
|
||||
longBiasEscapeOk = not launchChopContext or not useBiasSide or close > emaBias + atr * launchBiasEscapeAtr
|
||||
shortBiasEscapeOk = not launchChopContext or not useBiasSide or close < emaBias - atr * launchBiasEscapeAtr
|
||||
longLaunchEscapeOk = launchBaseEscapeOk and longLaunchDistanceOk and launchRibbonOpenOk and (not launchChopContext or body >= atr * launchChopBodyAtr) and longBiasEscapeOk
|
||||
shortLaunchEscapeOk = launchBaseEscapeOk and shortLaunchDistanceOk and launchRibbonOpenOk and (not launchChopContext or body >= atr * launchChopBodyAtr) and shortBiasEscapeOk
|
||||
continuationZoneOk = not chopZone
|
||||
|
||||
localRangeHigh = ta.highest(high, extremeLookback)
|
||||
localRangeLow = ta.lowest(low, extremeLookback)
|
||||
localRange = localRangeHigh - localRangeLow
|
||||
rangePosition = localRange > syminfo.mintick ? (close - localRangeLow) / localRange : 0.5
|
||||
longPositionOk = rangePosition <= maxLongRangePosition
|
||||
shortPositionOk = rangePosition >= minShortRangePosition
|
||||
entryRangeHigh = ta.highest(high, entryRangeLookback)
|
||||
entryRangeLow = ta.lowest(low, entryRangeLookback)
|
||||
entryRange = entryRangeHigh - entryRangeLow
|
||||
entryRangePosition = entryRange > syminfo.mintick ? (close - entryRangeLow) / entryRange : 0.5
|
||||
longEntryPositionOk = entryRangePosition <= maxLongEntryRangePosition
|
||||
shortEntryPositionOk = entryRangePosition >= minShortEntryRangePosition
|
||||
|
||||
pivotDemand = ta.pivotlow(low, structurePivotLeft, structurePivotRight)
|
||||
pivotSupply = ta.pivothigh(high, structurePivotLeft, structurePivotRight)
|
||||
var float[] demandZoneBottoms = array.new_float()
|
||||
var float[] demandZoneTops = array.new_float()
|
||||
var int[] demandZoneBars = array.new_int()
|
||||
var box[] demandZoneBoxes = array.new_box()
|
||||
var label[] demandZoneLabels = array.new_label()
|
||||
var int[] demandZoneTests = array.new_int()
|
||||
var bool[] demandZoneWasInside = array.new_bool()
|
||||
var float[] supplyZoneTops = array.new_float()
|
||||
var float[] supplyZoneBottoms = array.new_float()
|
||||
var int[] supplyZoneBars = array.new_int()
|
||||
var box[] supplyZoneBoxes = array.new_box()
|
||||
var label[] supplyZoneLabels = array.new_label()
|
||||
var int[] supplyZoneTests = array.new_int()
|
||||
var bool[] supplyZoneWasInside = array.new_bool()
|
||||
|
||||
chartTfText = timeframe.isminutes ? str.tostring(timeframe.multiplier) + "m" : timeframe.period
|
||||
|
||||
f_tfText(tf) =>
|
||||
tf == "60" ? "1H" : tf == "240" ? "4H" : tf == "D" ? "1D" : tf
|
||||
|
||||
f_htfDemandBottom() =>
|
||||
htfPivotDemand = ta.pivotlow(low, structurePivotLeft, structurePivotRight)
|
||||
htfDemandValid = not na(htfPivotDemand) and high >= htfPivotDemand + ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfDemandValid ? htfPivotDemand : na
|
||||
|
||||
f_htfDemandTop() =>
|
||||
htfPivotDemand = ta.pivotlow(low, structurePivotLeft, structurePivotRight)
|
||||
htfDemandValid = not na(htfPivotDemand) and high >= htfPivotDemand + ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfDemandValid ? htfPivotDemand + ta.atr(atrLen)[structurePivotRight] * structureZoneAtr : na
|
||||
|
||||
f_htfDemandTime() =>
|
||||
htfPivotDemand = ta.pivotlow(low, structurePivotLeft, structurePivotRight)
|
||||
htfDemandValid = not na(htfPivotDemand) and high >= htfPivotDemand + ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfDemandValid ? time[structurePivotRight] : na
|
||||
|
||||
f_htfSupplyTop() =>
|
||||
htfPivotSupply = ta.pivothigh(high, structurePivotLeft, structurePivotRight)
|
||||
htfSupplyValid = not na(htfPivotSupply) and low <= htfPivotSupply - ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfSupplyValid ? htfPivotSupply : na
|
||||
|
||||
f_htfSupplyBottom() =>
|
||||
htfPivotSupply = ta.pivothigh(high, structurePivotLeft, structurePivotRight)
|
||||
htfSupplyValid = not na(htfPivotSupply) and low <= htfPivotSupply - ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfSupplyValid ? htfPivotSupply - ta.atr(atrLen)[structurePivotRight] * structureZoneAtr : na
|
||||
|
||||
f_htfSupplyTime() =>
|
||||
htfPivotSupply = ta.pivothigh(high, structurePivotLeft, structurePivotRight)
|
||||
htfSupplyValid = not na(htfPivotSupply) and low <= htfPivotSupply - ta.atr(atrLen)[structurePivotRight] * minStructureReactionAtr
|
||||
htfSupplyValid ? time[structurePivotRight] : na
|
||||
|
||||
var float[] htfDemandZoneBottoms = array.new_float()
|
||||
var float[] htfDemandZoneTops = array.new_float()
|
||||
var int[] htfDemandZoneTimes = array.new_int()
|
||||
var box[] htfDemandZoneBoxes = array.new_box()
|
||||
var label[] htfDemandZoneLabels = array.new_label()
|
||||
var int[] htfDemandZoneTests = array.new_int()
|
||||
var bool[] htfDemandZoneWasInside = array.new_bool()
|
||||
var string[] htfDemandZoneTfTexts = array.new_string()
|
||||
var float[] htfSupplyZoneTops = array.new_float()
|
||||
var float[] htfSupplyZoneBottoms = array.new_float()
|
||||
var int[] htfSupplyZoneTimes = array.new_int()
|
||||
var box[] htfSupplyZoneBoxes = array.new_box()
|
||||
var label[] htfSupplyZoneLabels = array.new_label()
|
||||
var int[] htfSupplyZoneTests = array.new_int()
|
||||
var bool[] htfSupplyZoneWasInside = array.new_bool()
|
||||
var string[] htfSupplyZoneTfTexts = array.new_string()
|
||||
var int lastHtfDemandTime1 = na
|
||||
var int lastHtfSupplyTime1 = na
|
||||
var int lastHtfDemandTime2 = na
|
||||
var int lastHtfSupplyTime2 = na
|
||||
|
||||
validDemandPivot = not na(pivotDemand) and high >= pivotDemand + atr[structurePivotRight] * minStructureReactionAtr
|
||||
validSupplyPivot = not na(pivotSupply) and low <= pivotSupply - atr[structurePivotRight] * minStructureReactionAtr
|
||||
|
||||
htfDemandBottom1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfDemandBottom(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfDemandTop1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfDemandTop(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfDemandTime1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfDemandTime(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyTop1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfSupplyTop(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyBottom1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfSupplyBottom(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyTime1 = request.security(syminfo.tickerid, htfStructureTf1, f_htfSupplyTime(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfDemandBottom2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfDemandBottom(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfDemandTop2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfDemandTop(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfDemandTime2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfDemandTime(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyTop2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfSupplyTop(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyBottom2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfSupplyBottom(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
htfSupplyTime2 = request.security(syminfo.tickerid, htfStructureTf2, f_htfSupplyTime(), barmerge.gaps_off, barmerge.lookahead_off)
|
||||
|
||||
newHtfDemand1 = not na(htfDemandTime1) and (na(lastHtfDemandTime1) or htfDemandTime1 != lastHtfDemandTime1)
|
||||
newHtfSupply1 = not na(htfSupplyTime1) and (na(lastHtfSupplyTime1) or htfSupplyTime1 != lastHtfSupplyTime1)
|
||||
newHtfDemand2 = not na(htfDemandTime2) and (na(lastHtfDemandTime2) or htfDemandTime2 != lastHtfDemandTime2)
|
||||
newHtfSupply2 = not na(htfSupplyTime2) and (na(lastHtfSupplyTime2) or htfSupplyTime2 != lastHtfSupplyTime2)
|
||||
|
||||
if newHtfDemand1
|
||||
lastHtfDemandTime1 := htfDemandTime1
|
||||
htfDemandBox = showHtfStructureZones ? box.new(left=htfDemandTime1, top=htfDemandTop1, right=time, bottom=htfDemandBottom1, xloc=xloc.bar_time, bgcolor=color.new(color.green, 82), border_color=color.new(color.green, 10), border_width=2) : na
|
||||
htfDemandLabel = showHtfStructureZones ? label.new(x=time, y=(htfDemandTop1 + htfDemandBottom1) / 2.0, text=f_tfText(htfStructureTf1) + " 需求 x0", xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.new(color.green, 60), textcolor=color.white, size=size.small) : na
|
||||
array.push(htfDemandZoneBottoms, htfDemandBottom1)
|
||||
array.push(htfDemandZoneTops, htfDemandTop1)
|
||||
array.push(htfDemandZoneTimes, htfDemandTime1)
|
||||
array.push(htfDemandZoneBoxes, htfDemandBox)
|
||||
array.push(htfDemandZoneLabels, htfDemandLabel)
|
||||
array.push(htfDemandZoneTests, 0)
|
||||
array.push(htfDemandZoneWasInside, false)
|
||||
array.push(htfDemandZoneTfTexts, f_tfText(htfStructureTf1))
|
||||
|
||||
if newHtfSupply1
|
||||
lastHtfSupplyTime1 := htfSupplyTime1
|
||||
htfSupplyBox = showHtfStructureZones ? box.new(left=htfSupplyTime1, top=htfSupplyTop1, right=time, bottom=htfSupplyBottom1, xloc=xloc.bar_time, bgcolor=color.new(color.maroon, 82), border_color=color.new(color.red, 10), border_width=2) : na
|
||||
htfSupplyLabel = showHtfStructureZones ? label.new(x=time, y=(htfSupplyTop1 + htfSupplyBottom1) / 2.0, text=f_tfText(htfStructureTf1) + " 供应 x0", xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.new(color.red, 60), textcolor=color.white, size=size.small) : na
|
||||
array.push(htfSupplyZoneTops, htfSupplyTop1)
|
||||
array.push(htfSupplyZoneBottoms, htfSupplyBottom1)
|
||||
array.push(htfSupplyZoneTimes, htfSupplyTime1)
|
||||
array.push(htfSupplyZoneBoxes, htfSupplyBox)
|
||||
array.push(htfSupplyZoneLabels, htfSupplyLabel)
|
||||
array.push(htfSupplyZoneTests, 0)
|
||||
array.push(htfSupplyZoneWasInside, false)
|
||||
array.push(htfSupplyZoneTfTexts, f_tfText(htfStructureTf1))
|
||||
|
||||
if newHtfDemand2
|
||||
lastHtfDemandTime2 := htfDemandTime2
|
||||
htfDemandBox = showHtfStructureZones ? box.new(left=htfDemandTime2, top=htfDemandTop2, right=time, bottom=htfDemandBottom2, xloc=xloc.bar_time, bgcolor=color.new(color.teal, 80), border_color=color.new(color.teal, 5), border_width=2) : na
|
||||
htfDemandLabel = showHtfStructureZones ? label.new(x=time, y=(htfDemandTop2 + htfDemandBottom2) / 2.0, text=f_tfText(htfStructureTf2) + " 需求 x0", xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.new(color.teal, 55), textcolor=color.white, size=size.small) : na
|
||||
array.push(htfDemandZoneBottoms, htfDemandBottom2)
|
||||
array.push(htfDemandZoneTops, htfDemandTop2)
|
||||
array.push(htfDemandZoneTimes, htfDemandTime2)
|
||||
array.push(htfDemandZoneBoxes, htfDemandBox)
|
||||
array.push(htfDemandZoneLabels, htfDemandLabel)
|
||||
array.push(htfDemandZoneTests, 0)
|
||||
array.push(htfDemandZoneWasInside, false)
|
||||
array.push(htfDemandZoneTfTexts, f_tfText(htfStructureTf2))
|
||||
|
||||
if newHtfSupply2
|
||||
lastHtfSupplyTime2 := htfSupplyTime2
|
||||
htfSupplyBox = showHtfStructureZones ? box.new(left=htfSupplyTime2, top=htfSupplyTop2, right=time, bottom=htfSupplyBottom2, xloc=xloc.bar_time, bgcolor=color.new(color.purple, 80), border_color=color.new(color.purple, 5), border_width=2) : na
|
||||
htfSupplyLabel = showHtfStructureZones ? label.new(x=time, y=(htfSupplyTop2 + htfSupplyBottom2) / 2.0, text=f_tfText(htfStructureTf2) + " 供应 x0", xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.new(color.purple, 55), textcolor=color.white, size=size.small) : na
|
||||
array.push(htfSupplyZoneTops, htfSupplyTop2)
|
||||
array.push(htfSupplyZoneBottoms, htfSupplyBottom2)
|
||||
array.push(htfSupplyZoneTimes, htfSupplyTime2)
|
||||
array.push(htfSupplyZoneBoxes, htfSupplyBox)
|
||||
array.push(htfSupplyZoneLabels, htfSupplyLabel)
|
||||
array.push(htfSupplyZoneTests, 0)
|
||||
array.push(htfSupplyZoneWasInside, false)
|
||||
array.push(htfSupplyZoneTfTexts, f_tfText(htfStructureTf2))
|
||||
|
||||
while array.size(htfDemandZoneTimes) > maxHtfStructureBoxes
|
||||
oldHtfDemandBox = array.shift(htfDemandZoneBoxes)
|
||||
oldHtfDemandLabel = array.shift(htfDemandZoneLabels)
|
||||
array.shift(htfDemandZoneBottoms)
|
||||
array.shift(htfDemandZoneTops)
|
||||
array.shift(htfDemandZoneTimes)
|
||||
array.shift(htfDemandZoneTests)
|
||||
array.shift(htfDemandZoneWasInside)
|
||||
array.shift(htfDemandZoneTfTexts)
|
||||
if not na(oldHtfDemandBox)
|
||||
box.delete(oldHtfDemandBox)
|
||||
if not na(oldHtfDemandLabel)
|
||||
label.delete(oldHtfDemandLabel)
|
||||
|
||||
while array.size(htfSupplyZoneTimes) > maxHtfStructureBoxes
|
||||
oldHtfSupplyBox = array.shift(htfSupplyZoneBoxes)
|
||||
oldHtfSupplyLabel = array.shift(htfSupplyZoneLabels)
|
||||
array.shift(htfSupplyZoneTops)
|
||||
array.shift(htfSupplyZoneBottoms)
|
||||
array.shift(htfSupplyZoneTimes)
|
||||
array.shift(htfSupplyZoneTests)
|
||||
array.shift(htfSupplyZoneWasInside)
|
||||
array.shift(htfSupplyZoneTfTexts)
|
||||
if not na(oldHtfSupplyBox)
|
||||
box.delete(oldHtfSupplyBox)
|
||||
if not na(oldHtfSupplyLabel)
|
||||
label.delete(oldHtfSupplyLabel)
|
||||
|
||||
if array.size(htfDemandZoneTimes) > 0
|
||||
htfDemandIndex = array.size(htfDemandZoneTimes) - 1
|
||||
while htfDemandIndex >= 0
|
||||
htfDemandBottomLevel = array.get(htfDemandZoneBottoms, htfDemandIndex)
|
||||
htfDemandTopLevel = array.get(htfDemandZoneTops, htfDemandIndex)
|
||||
htfDemandBroken = close < htfDemandBottomLevel
|
||||
htfDemandInside = low <= htfDemandTopLevel and high >= htfDemandBottomLevel
|
||||
htfDemandWasInside = array.get(htfDemandZoneWasInside, htfDemandIndex)
|
||||
if htfDemandBroken
|
||||
brokenHtfDemandBox = array.get(htfDemandZoneBoxes, htfDemandIndex)
|
||||
brokenHtfDemandLabel = array.get(htfDemandZoneLabels, htfDemandIndex)
|
||||
if not na(brokenHtfDemandBox)
|
||||
box.delete(brokenHtfDemandBox)
|
||||
if not na(brokenHtfDemandLabel)
|
||||
label.delete(brokenHtfDemandLabel)
|
||||
array.remove(htfDemandZoneBottoms, htfDemandIndex)
|
||||
array.remove(htfDemandZoneTops, htfDemandIndex)
|
||||
array.remove(htfDemandZoneTimes, htfDemandIndex)
|
||||
array.remove(htfDemandZoneBoxes, htfDemandIndex)
|
||||
array.remove(htfDemandZoneLabels, htfDemandIndex)
|
||||
array.remove(htfDemandZoneTests, htfDemandIndex)
|
||||
array.remove(htfDemandZoneWasInside, htfDemandIndex)
|
||||
array.remove(htfDemandZoneTfTexts, htfDemandIndex)
|
||||
else
|
||||
if htfDemandInside and not htfDemandWasInside
|
||||
array.set(htfDemandZoneTests, htfDemandIndex, array.get(htfDemandZoneTests, htfDemandIndex) + 1)
|
||||
array.set(htfDemandZoneWasInside, htfDemandIndex, htfDemandInside)
|
||||
htfDemandTests = array.get(htfDemandZoneTests, htfDemandIndex)
|
||||
htfDemandTfText = array.get(htfDemandZoneTfTexts, htfDemandIndex)
|
||||
htfDemandWeak = htfDemandTests >= maxZoneTests
|
||||
htfDemandBoxToStyle = array.get(htfDemandZoneBoxes, htfDemandIndex)
|
||||
htfDemandLabelToStyle = array.get(htfDemandZoneLabels, htfDemandIndex)
|
||||
if not na(htfDemandBoxToStyle)
|
||||
box.set_bgcolor(htfDemandBoxToStyle, htfDemandWeak ? color.new(color.gray, 90) : color.new(color.green, 82))
|
||||
box.set_border_color(htfDemandBoxToStyle, htfDemandWeak ? color.new(color.gray, 35) : color.new(color.green, 10))
|
||||
box.set_right(htfDemandBoxToStyle, time)
|
||||
if not na(htfDemandLabelToStyle)
|
||||
label.set_x(htfDemandLabelToStyle, time)
|
||||
label.set_y(htfDemandLabelToStyle, (htfDemandTopLevel + htfDemandBottomLevel) / 2.0)
|
||||
label.set_text(htfDemandLabelToStyle, htfDemandTfText + " 需求 x" + str.tostring(htfDemandTests))
|
||||
label.set_color(htfDemandLabelToStyle, htfDemandWeak ? color.new(color.gray, 70) : color.new(color.green, 55))
|
||||
htfDemandIndex := htfDemandIndex - 1
|
||||
|
||||
if array.size(htfSupplyZoneTimes) > 0
|
||||
htfSupplyIndex = array.size(htfSupplyZoneTimes) - 1
|
||||
while htfSupplyIndex >= 0
|
||||
htfSupplyTopLevel = array.get(htfSupplyZoneTops, htfSupplyIndex)
|
||||
htfSupplyBottomLevel = array.get(htfSupplyZoneBottoms, htfSupplyIndex)
|
||||
htfSupplyBroken = close > htfSupplyTopLevel
|
||||
htfSupplyInside = high >= htfSupplyBottomLevel and low <= htfSupplyTopLevel
|
||||
htfSupplyWasInside = array.get(htfSupplyZoneWasInside, htfSupplyIndex)
|
||||
if htfSupplyBroken
|
||||
brokenHtfSupplyBox = array.get(htfSupplyZoneBoxes, htfSupplyIndex)
|
||||
brokenHtfSupplyLabel = array.get(htfSupplyZoneLabels, htfSupplyIndex)
|
||||
if not na(brokenHtfSupplyBox)
|
||||
box.delete(brokenHtfSupplyBox)
|
||||
if not na(brokenHtfSupplyLabel)
|
||||
label.delete(brokenHtfSupplyLabel)
|
||||
array.remove(htfSupplyZoneTops, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneBottoms, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneTimes, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneBoxes, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneLabels, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneTests, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneWasInside, htfSupplyIndex)
|
||||
array.remove(htfSupplyZoneTfTexts, htfSupplyIndex)
|
||||
else
|
||||
if htfSupplyInside and not htfSupplyWasInside
|
||||
array.set(htfSupplyZoneTests, htfSupplyIndex, array.get(htfSupplyZoneTests, htfSupplyIndex) + 1)
|
||||
array.set(htfSupplyZoneWasInside, htfSupplyIndex, htfSupplyInside)
|
||||
htfSupplyTests = array.get(htfSupplyZoneTests, htfSupplyIndex)
|
||||
htfSupplyTfText = array.get(htfSupplyZoneTfTexts, htfSupplyIndex)
|
||||
htfSupplyWeak = htfSupplyTests >= maxZoneTests
|
||||
htfSupplyBoxToStyle = array.get(htfSupplyZoneBoxes, htfSupplyIndex)
|
||||
htfSupplyLabelToStyle = array.get(htfSupplyZoneLabels, htfSupplyIndex)
|
||||
if not na(htfSupplyBoxToStyle)
|
||||
box.set_bgcolor(htfSupplyBoxToStyle, htfSupplyWeak ? color.new(color.gray, 90) : color.new(color.red, 82))
|
||||
box.set_border_color(htfSupplyBoxToStyle, htfSupplyWeak ? color.new(color.gray, 35) : color.new(color.red, 10))
|
||||
box.set_right(htfSupplyBoxToStyle, time)
|
||||
if not na(htfSupplyLabelToStyle)
|
||||
label.set_x(htfSupplyLabelToStyle, time)
|
||||
label.set_y(htfSupplyLabelToStyle, (htfSupplyTopLevel + htfSupplyBottomLevel) / 2.0)
|
||||
label.set_text(htfSupplyLabelToStyle, htfSupplyTfText + " 供应 x" + str.tostring(htfSupplyTests))
|
||||
label.set_color(htfSupplyLabelToStyle, htfSupplyWeak ? color.new(color.gray, 70) : color.new(color.red, 55))
|
||||
htfSupplyIndex := htfSupplyIndex - 1
|
||||
|
||||
if validDemandPivot
|
||||
demandLeft = bar_index - structurePivotRight
|
||||
demandBottom = pivotDemand
|
||||
demandTop = pivotDemand + atr[structurePivotRight] * structureZoneAtr
|
||||
demandBox = showStructureZones ? box.new(left=demandLeft, top=demandTop, right=bar_index, bottom=demandBottom, xloc=xloc.bar_index, bgcolor=color.new(color.lime, 88), border_color=color.new(color.lime, 25), border_width=1) : na
|
||||
demandLabel = showStructureZones ? label.new(x=bar_index, y=(demandTop + demandBottom) / 2.0, text=chartTfText + " 需求 x0", xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(color.lime, 75), textcolor=color.white, size=size.tiny) : na
|
||||
array.push(demandZoneBottoms, demandBottom)
|
||||
array.push(demandZoneTops, demandTop)
|
||||
array.push(demandZoneBars, demandLeft)
|
||||
array.push(demandZoneBoxes, demandBox)
|
||||
array.push(demandZoneLabels, demandLabel)
|
||||
array.push(demandZoneTests, 0)
|
||||
array.push(demandZoneWasInside, false)
|
||||
|
||||
if validSupplyPivot
|
||||
supplyLeft = bar_index - structurePivotRight
|
||||
supplyTop = pivotSupply
|
||||
supplyBottom = pivotSupply - atr[structurePivotRight] * structureZoneAtr
|
||||
supplyBox = showStructureZones ? box.new(left=supplyLeft, top=supplyTop, right=bar_index, bottom=supplyBottom, xloc=xloc.bar_index, bgcolor=color.new(color.red, 88), border_color=color.new(color.red, 25), border_width=1) : na
|
||||
supplyLabel = showStructureZones ? label.new(x=bar_index, y=(supplyTop + supplyBottom) / 2.0, text=chartTfText + " 供应 x0", xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(color.red, 75), textcolor=color.white, size=size.tiny) : na
|
||||
array.push(supplyZoneTops, supplyTop)
|
||||
array.push(supplyZoneBottoms, supplyBottom)
|
||||
array.push(supplyZoneBars, supplyLeft)
|
||||
array.push(supplyZoneBoxes, supplyBox)
|
||||
array.push(supplyZoneLabels, supplyLabel)
|
||||
array.push(supplyZoneTests, 0)
|
||||
array.push(supplyZoneWasInside, false)
|
||||
|
||||
while array.size(demandZoneBars) > 0
|
||||
oldestDemandBar = array.get(demandZoneBars, 0)
|
||||
if bar_index - oldestDemandBar > structureLookback
|
||||
array.shift(demandZoneBottoms)
|
||||
array.shift(demandZoneTops)
|
||||
array.shift(demandZoneBars)
|
||||
oldDemandBox = array.shift(demandZoneBoxes)
|
||||
oldDemandLabel = array.shift(demandZoneLabels)
|
||||
array.shift(demandZoneTests)
|
||||
array.shift(demandZoneWasInside)
|
||||
if not na(oldDemandBox)
|
||||
box.delete(oldDemandBox)
|
||||
if not na(oldDemandLabel)
|
||||
label.delete(oldDemandLabel)
|
||||
else
|
||||
break
|
||||
|
||||
while array.size(supplyZoneBars) > 0
|
||||
oldestSupplyBar = array.get(supplyZoneBars, 0)
|
||||
if bar_index - oldestSupplyBar > structureLookback
|
||||
array.shift(supplyZoneTops)
|
||||
array.shift(supplyZoneBottoms)
|
||||
array.shift(supplyZoneBars)
|
||||
oldSupplyBox = array.shift(supplyZoneBoxes)
|
||||
oldSupplyLabel = array.shift(supplyZoneLabels)
|
||||
array.shift(supplyZoneTests)
|
||||
array.shift(supplyZoneWasInside)
|
||||
if not na(oldSupplyBox)
|
||||
box.delete(oldSupplyBox)
|
||||
if not na(oldSupplyLabel)
|
||||
label.delete(oldSupplyLabel)
|
||||
else
|
||||
break
|
||||
|
||||
while array.size(demandZoneBars) > maxStructureBoxes
|
||||
array.shift(demandZoneBottoms)
|
||||
array.shift(demandZoneTops)
|
||||
array.shift(demandZoneBars)
|
||||
oldDemandBox = array.shift(demandZoneBoxes)
|
||||
oldDemandLabel = array.shift(demandZoneLabels)
|
||||
array.shift(demandZoneTests)
|
||||
array.shift(demandZoneWasInside)
|
||||
if not na(oldDemandBox)
|
||||
box.delete(oldDemandBox)
|
||||
if not na(oldDemandLabel)
|
||||
label.delete(oldDemandLabel)
|
||||
|
||||
while array.size(supplyZoneBars) > maxStructureBoxes
|
||||
array.shift(supplyZoneTops)
|
||||
array.shift(supplyZoneBottoms)
|
||||
array.shift(supplyZoneBars)
|
||||
oldSupplyBox = array.shift(supplyZoneBoxes)
|
||||
oldSupplyLabel = array.shift(supplyZoneLabels)
|
||||
array.shift(supplyZoneTests)
|
||||
array.shift(supplyZoneWasInside)
|
||||
if not na(oldSupplyBox)
|
||||
box.delete(oldSupplyBox)
|
||||
if not na(oldSupplyLabel)
|
||||
label.delete(oldSupplyLabel)
|
||||
|
||||
if array.size(demandZoneBars) > 0
|
||||
demandIndex = array.size(demandZoneBars) - 1
|
||||
while demandIndex >= 0
|
||||
demandBottomLevel = array.get(demandZoneBottoms, demandIndex)
|
||||
demandTopLevel = array.get(demandZoneTops, demandIndex)
|
||||
demandBroken = close < demandBottomLevel
|
||||
demandInside = low <= demandTopLevel and high >= demandBottomLevel
|
||||
demandWasInside = array.get(demandZoneWasInside, demandIndex)
|
||||
if demandBroken
|
||||
brokenDemandBox = array.get(demandZoneBoxes, demandIndex)
|
||||
brokenDemandLabel = array.get(demandZoneLabels, demandIndex)
|
||||
if not na(brokenDemandBox)
|
||||
box.delete(brokenDemandBox)
|
||||
if not na(brokenDemandLabel)
|
||||
label.delete(brokenDemandLabel)
|
||||
array.remove(demandZoneBottoms, demandIndex)
|
||||
array.remove(demandZoneTops, demandIndex)
|
||||
array.remove(demandZoneBars, demandIndex)
|
||||
array.remove(demandZoneBoxes, demandIndex)
|
||||
array.remove(demandZoneLabels, demandIndex)
|
||||
array.remove(demandZoneTests, demandIndex)
|
||||
array.remove(demandZoneWasInside, demandIndex)
|
||||
else
|
||||
if demandInside and not demandWasInside
|
||||
array.set(demandZoneTests, demandIndex, array.get(demandZoneTests, demandIndex) + 1)
|
||||
array.set(demandZoneWasInside, demandIndex, demandInside)
|
||||
demandTests = array.get(demandZoneTests, demandIndex)
|
||||
demandBoxToStyle = array.get(demandZoneBoxes, demandIndex)
|
||||
if not na(demandBoxToStyle)
|
||||
demandWeak = demandTests >= maxZoneTests
|
||||
box.set_bgcolor(demandBoxToStyle, demandWeak ? color.new(color.gray, 92) : color.new(color.lime, 88))
|
||||
box.set_border_color(demandBoxToStyle, demandWeak ? color.new(color.gray, 45) : color.new(color.lime, 25))
|
||||
demandLabelToStyle = array.get(demandZoneLabels, demandIndex)
|
||||
if not na(demandLabelToStyle)
|
||||
demandWeak = demandTests >= maxZoneTests
|
||||
label.set_text(demandLabelToStyle, chartTfText + " 需求 x" + str.tostring(demandTests))
|
||||
label.set_y(demandLabelToStyle, (demandTopLevel + demandBottomLevel) / 2.0)
|
||||
label.set_color(demandLabelToStyle, demandWeak ? color.new(color.gray, 75) : color.new(color.lime, 75))
|
||||
demandIndex := demandIndex - 1
|
||||
|
||||
if array.size(supplyZoneBars) > 0
|
||||
supplyIndex = array.size(supplyZoneBars) - 1
|
||||
while supplyIndex >= 0
|
||||
supplyTopLevel = array.get(supplyZoneTops, supplyIndex)
|
||||
supplyBottomLevel = array.get(supplyZoneBottoms, supplyIndex)
|
||||
supplyBroken = close > supplyTopLevel
|
||||
supplyInside = high >= supplyBottomLevel and low <= supplyTopLevel
|
||||
supplyWasInside = array.get(supplyZoneWasInside, supplyIndex)
|
||||
if supplyBroken
|
||||
brokenSupplyBox = array.get(supplyZoneBoxes, supplyIndex)
|
||||
brokenSupplyLabel = array.get(supplyZoneLabels, supplyIndex)
|
||||
if not na(brokenSupplyBox)
|
||||
box.delete(brokenSupplyBox)
|
||||
if not na(brokenSupplyLabel)
|
||||
label.delete(brokenSupplyLabel)
|
||||
array.remove(supplyZoneTops, supplyIndex)
|
||||
array.remove(supplyZoneBottoms, supplyIndex)
|
||||
array.remove(supplyZoneBars, supplyIndex)
|
||||
array.remove(supplyZoneBoxes, supplyIndex)
|
||||
array.remove(supplyZoneLabels, supplyIndex)
|
||||
array.remove(supplyZoneTests, supplyIndex)
|
||||
array.remove(supplyZoneWasInside, supplyIndex)
|
||||
else
|
||||
if supplyInside and not supplyWasInside
|
||||
array.set(supplyZoneTests, supplyIndex, array.get(supplyZoneTests, supplyIndex) + 1)
|
||||
array.set(supplyZoneWasInside, supplyIndex, supplyInside)
|
||||
supplyTests = array.get(supplyZoneTests, supplyIndex)
|
||||
supplyBoxToStyle = array.get(supplyZoneBoxes, supplyIndex)
|
||||
if not na(supplyBoxToStyle)
|
||||
supplyWeak = supplyTests >= maxZoneTests
|
||||
box.set_bgcolor(supplyBoxToStyle, supplyWeak ? color.new(color.gray, 92) : color.new(color.red, 88))
|
||||
box.set_border_color(supplyBoxToStyle, supplyWeak ? color.new(color.gray, 45) : color.new(color.red, 25))
|
||||
supplyLabelToStyle = array.get(supplyZoneLabels, supplyIndex)
|
||||
if not na(supplyLabelToStyle)
|
||||
supplyWeak = supplyTests >= maxZoneTests
|
||||
label.set_text(supplyLabelToStyle, chartTfText + " 供应 x" + str.tostring(supplyTests))
|
||||
label.set_y(supplyLabelToStyle, (supplyTopLevel + supplyBottomLevel) / 2.0)
|
||||
label.set_color(supplyLabelToStyle, supplyWeak ? color.new(color.gray, 75) : color.new(color.red, 75))
|
||||
supplyIndex := supplyIndex - 1
|
||||
|
||||
if array.size(demandZoneBoxes) > 0
|
||||
for zoneIndex = 0 to array.size(demandZoneBoxes) - 1
|
||||
activeDemandBox = array.get(demandZoneBoxes, zoneIndex)
|
||||
if not na(activeDemandBox)
|
||||
box.set_right(activeDemandBox, bar_index)
|
||||
activeDemandLabel = array.get(demandZoneLabels, zoneIndex)
|
||||
if not na(activeDemandLabel)
|
||||
label.set_x(activeDemandLabel, bar_index)
|
||||
|
||||
if array.size(supplyZoneBoxes) > 0
|
||||
for zoneIndex = 0 to array.size(supplyZoneBoxes) - 1
|
||||
activeSupplyBox = array.get(supplyZoneBoxes, zoneIndex)
|
||||
if not na(activeSupplyBox)
|
||||
box.set_right(activeSupplyBox, bar_index)
|
||||
activeSupplyLabel = array.get(supplyZoneLabels, zoneIndex)
|
||||
if not na(activeSupplyLabel)
|
||||
label.set_x(activeSupplyLabel, bar_index)
|
||||
|
||||
float nearestDemandTop = na
|
||||
float nearestDemandBottom = na
|
||||
bool currentDemandTouch = false
|
||||
if array.size(demandZoneTops) > 0
|
||||
for zoneIndex = 0 to array.size(demandZoneTops) - 1
|
||||
demandTopLevel = array.get(demandZoneTops, zoneIndex)
|
||||
demandBottomLevel = array.get(demandZoneBottoms, zoneIndex)
|
||||
demandTouched = low <= demandTopLevel + atr * htfZoneBlockAtr and high >= demandBottomLevel - atr * htfZoneBlockAtr
|
||||
currentDemandTouch := currentDemandTouch or demandTouched
|
||||
demandZoneStrong = array.get(demandZoneTests, zoneIndex) < maxZoneTests
|
||||
if demandZoneStrong
|
||||
if demandBottomLevel <= close and (na(nearestDemandTop) or demandTopLevel > nearestDemandTop)
|
||||
nearestDemandTop := demandTopLevel
|
||||
nearestDemandBottom := demandBottomLevel
|
||||
|
||||
float nearestSupplyBottom = na
|
||||
float nearestSupplyTop = na
|
||||
bool currentSupplyTouch = false
|
||||
if array.size(supplyZoneBottoms) > 0
|
||||
for zoneIndex = 0 to array.size(supplyZoneBottoms) - 1
|
||||
supplyBottomLevel = array.get(supplyZoneBottoms, zoneIndex)
|
||||
supplyTopLevel = array.get(supplyZoneTops, zoneIndex)
|
||||
supplyTouched = high >= supplyBottomLevel - atr * htfZoneBlockAtr and low <= supplyTopLevel + atr * htfZoneBlockAtr
|
||||
currentSupplyTouch := currentSupplyTouch or supplyTouched
|
||||
supplyZoneStrong = array.get(supplyZoneTests, zoneIndex) < maxZoneTests
|
||||
if supplyZoneStrong
|
||||
if supplyTopLevel >= close and (na(nearestSupplyBottom) or supplyBottomLevel < nearestSupplyBottom)
|
||||
nearestSupplyBottom := supplyBottomLevel
|
||||
nearestSupplyTop := supplyTopLevel
|
||||
|
||||
roomToDemand = na(nearestDemandTop) ? na : close - nearestDemandTop
|
||||
roomToSupply = na(nearestSupplyBottom) ? na : nearestSupplyBottom - close
|
||||
float nearestHtfDemandTop = na
|
||||
float nearestHtfDemandBottom = na
|
||||
bool currentHtfDemandTouch = false
|
||||
if array.size(htfDemandZoneTops) > 0
|
||||
for zoneIndex = 0 to array.size(htfDemandZoneTops) - 1
|
||||
htfDemandTopLevel = array.get(htfDemandZoneTops, zoneIndex)
|
||||
htfDemandBottomLevel = array.get(htfDemandZoneBottoms, zoneIndex)
|
||||
htfDemandTouched = low <= htfDemandTopLevel + atr * htfZoneBlockAtr and high >= htfDemandBottomLevel - atr * htfZoneBlockAtr
|
||||
currentHtfDemandTouch := currentHtfDemandTouch or htfDemandTouched
|
||||
htfDemandStrong = array.get(htfDemandZoneTests, zoneIndex) < maxZoneTests
|
||||
if htfDemandStrong
|
||||
if htfDemandBottomLevel <= close and (na(nearestHtfDemandTop) or htfDemandTopLevel > nearestHtfDemandTop)
|
||||
nearestHtfDemandTop := htfDemandTopLevel
|
||||
nearestHtfDemandBottom := htfDemandBottomLevel
|
||||
|
||||
float nearestHtfSupplyBottom = na
|
||||
float nearestHtfSupplyTop = na
|
||||
bool currentHtfSupplyTouch = false
|
||||
if array.size(htfSupplyZoneBottoms) > 0
|
||||
for zoneIndex = 0 to array.size(htfSupplyZoneBottoms) - 1
|
||||
htfSupplyBottomLevel = array.get(htfSupplyZoneBottoms, zoneIndex)
|
||||
htfSupplyTopLevel = array.get(htfSupplyZoneTops, zoneIndex)
|
||||
htfSupplyTouched = high >= htfSupplyBottomLevel - atr * htfZoneBlockAtr and low <= htfSupplyTopLevel + atr * htfZoneBlockAtr
|
||||
currentHtfSupplyTouch := currentHtfSupplyTouch or htfSupplyTouched
|
||||
htfSupplyStrong = array.get(htfSupplyZoneTests, zoneIndex) < maxZoneTests
|
||||
if htfSupplyStrong
|
||||
if htfSupplyTopLevel >= close and (na(nearestHtfSupplyBottom) or htfSupplyBottomLevel < nearestHtfSupplyBottom)
|
||||
nearestHtfSupplyBottom := htfSupplyBottomLevel
|
||||
nearestHtfSupplyTop := htfSupplyTopLevel
|
||||
|
||||
roomToHtfDemand = na(nearestHtfDemandTop) ? na : close - nearestHtfDemandTop
|
||||
roomToHtfSupply = na(nearestHtfSupplyBottom) ? na : nearestHtfSupplyBottom - close
|
||||
shortNearHtfDemand = useHtfStructureFilter and useHtfZoneHardBlock and currentHtfDemandTouch
|
||||
longNearHtfSupply = useHtfStructureFilter and useHtfZoneHardBlock and currentHtfSupplyTouch
|
||||
shortHtfDemandBlock = useHtfStructureFilter and useHtfZoneHardBlock and (shortNearHtfDemand or nz(ta.barssince(shortNearHtfDemand), 100000) <= htfZoneTouchBlockBars)
|
||||
longHtfSupplyBlock = useHtfStructureFilter and useHtfZoneHardBlock and (longNearHtfSupply or nz(ta.barssince(longNearHtfSupply), 100000) <= htfZoneTouchBlockBars)
|
||||
downImpulseIntoZone = ta.highest(high[1], 5) - low >= atr * zoneImpulseAtr
|
||||
upImpulseIntoZone = high - ta.lowest(low[1], 5) >= atr * zoneImpulseAtr
|
||||
developingDemandReaction = downImpulseIntoZone and low <= ta.lowest(low, extremeLookback) + atr * 0.20
|
||||
developingSupplyReaction = upImpulseIntoZone and high >= ta.highest(high, extremeLookback) - atr * 0.20
|
||||
demandReaction = useZoneReactionBlock and (currentDemandTouch or currentHtfDemandTouch or developingDemandReaction) and close > open and body >= atr * minZoneReactionBodyAtr and (bullishEngulfing or close > high[1] or downImpulseIntoZone)
|
||||
supplyReaction = useZoneReactionBlock and (currentSupplyTouch or currentHtfSupplyTouch or developingSupplyReaction) and close < open and body >= atr * minZoneReactionBodyAtr and (bearishEngulfing or close < low[1] or upImpulseIntoZone)
|
||||
shortZoneReactionBlock = useZoneReactionBlock and (demandReaction or nz(ta.barssince(demandReaction), 100000) <= zoneReactionBlockBars)
|
||||
longZoneReactionBlock = useZoneReactionBlock and (supplyReaction or nz(ta.barssince(supplyReaction), 100000) <= zoneReactionBlockBars)
|
||||
shortLocalStructureRoomOk = not useStructureZoneFilter or na(nearestDemandTop) or roomToDemand >= atr * minRoomToZoneAtr
|
||||
longLocalStructureRoomOk = not useStructureZoneFilter or na(nearestSupplyBottom) or roomToSupply >= atr * minRoomToZoneAtr
|
||||
shortHtfStructureRoomOk = not useHtfStructureFilter or ((na(nearestHtfDemandTop) or roomToHtfDemand >= atr * minRoomToZoneAtr) and not shortHtfDemandBlock)
|
||||
longHtfStructureRoomOk = not useHtfStructureFilter or ((na(nearestHtfSupplyBottom) or roomToHtfSupply >= atr * minRoomToZoneAtr) and not longHtfSupplyBlock)
|
||||
shortStructureRoomOk = shortLocalStructureRoomOk and shortHtfStructureRoomOk and not shortZoneReactionBlock
|
||||
longStructureRoomOk = longLocalStructureRoomOk and longHtfStructureRoomOk and not longZoneReactionBlock
|
||||
|
||||
simpleBullTrend = biasBullOk and biasSlopeBullOk and bullOrder and bullSlopeCount >= profileSlopeNeed and ribbonSeparated and close > emaBias + atr * trendAwayAtr
|
||||
simpleBearTrend = biasBearOk and biasSlopeBearOk and bearOrder and bearSlopeCount >= profileSlopeNeed and ribbonSeparated and close < emaBias - atr * trendAwayAtr
|
||||
simpleBullPullback = simpleBullTrend and low <= emaMid and low >= emaSlow - atr * biasRetestAtr
|
||||
simpleBearPullback = simpleBearTrend and high >= emaMid and high <= emaSlow + atr * biasRetestAtr
|
||||
simpleBullPullbackRecent = nz(ta.barssince(simpleBullPullback), 100000) <= pullbackLookback
|
||||
simpleBearPullbackRecent = nz(ta.barssince(simpleBearPullback), 100000) <= pullbackLookback
|
||||
simpleLongConfirm = close > emaFast and close > emaMid and close > open and close - emaMid <= atr * maxContinuationDistanceMidAtr and entryRangePosition <= maxLongEntryRangePosition
|
||||
simpleShortConfirm = close < emaFast and close < emaMid and close < open and emaMid - close <= atr * maxContinuationDistanceMidAtr and entryRangePosition >= minShortEntryRangePosition
|
||||
simpleLongSetup = mtfLongOk and simpleBullTrend and simpleBullPullbackRecent and simpleLongConfirm and not chopZone and adxContinuationOk and diBullOk
|
||||
simpleShortSetup = mtfShortOk and simpleBearTrend and simpleBearPullbackRecent and simpleShortConfirm and not chopZone and adxContinuationOk and diBearOk
|
||||
|
||||
launchWasCompressed = ta.lowest(ribbonWidthAtr, compressionLookback) <= compressionAtr
|
||||
prelaunchStillCompressed = launchWasCompressed and ribbonWidthAtr <= prelaunchMaxRibbonAtr
|
||||
breaksShortHigh = close > ta.highest(high[1], launchBreakLookback)
|
||||
breaksShortLow = close < ta.lowest(low[1], launchBreakLookback)
|
||||
prelaunchHigh = ta.highest(high[1], launchBreakLookback)
|
||||
prelaunchLow = ta.lowest(low[1], launchBreakLookback)
|
||||
longNearBreak = high >= prelaunchHigh - atr * prelaunchBreakBufferAtr and close <= prelaunchHigh - atr * prelaunchMinBreakCloseAtr
|
||||
shortNearBreak = low <= prelaunchLow + atr * prelaunchBreakBufferAtr and close >= prelaunchLow + atr * prelaunchMinBreakCloseAtr
|
||||
launchBodyOk = body >= atr * minLaunchBodyAtr
|
||||
prelaunchBodyOk = body >= atr * prelaunchMinBodyAtr
|
||||
continuationBodyOk = body >= atr * minContinuationBodyAtr
|
||||
continuationDistanceOk = math.abs(close - emaFast) <= atr * maxContinuationDistanceAtr
|
||||
longContinuationDistanceOk = continuationDistanceOk and close - emaMid <= atr * maxContinuationDistanceMidAtr
|
||||
shortContinuationDistanceOk = continuationDistanceOk and emaMid - close <= atr * maxContinuationDistanceMidAtr
|
||||
|
||||
prelaunchNoMatureTrend = not simpleBullTrend and not simpleBearTrend
|
||||
prelaunchCleanCompression = prelaunchStillCompressed and priceCrossRibbonCount <= prelaunchMaxRibbonCrosses and biasSideFlips <= prelaunchMaxBiasCrosses
|
||||
longPrelaunchDirectionOk = emaFast >= emaMid and emaMid >= emaSlow and emaFast > emaFast[1] and emaMid >= emaMid[1] and close >= emaBias - atr * prelaunchBiasNearAtr
|
||||
shortPrelaunchDirectionOk = emaFast <= emaMid and emaMid <= emaSlow and emaFast < emaFast[1] and emaMid <= emaMid[1] and close <= emaBias + atr * prelaunchBiasNearAtr
|
||||
|
||||
longPrelaunchRaw = prelaunchMode != "关闭" and mtfLongOk and prelaunchNoMatureTrend and prelaunchCleanCompression and longStructureRoomOk and longDirectionOk and longNearBreak and close > emaMid and close > open and prelaunchBodyOk and bullSlopeCount >= profileSlopeNeed and longPrelaunchDirectionOk and diBullOk and longPositionOk
|
||||
shortPrelaunchRaw = prelaunchMode != "关闭" and mtfShortOk and prelaunchNoMatureTrend and prelaunchCleanCompression and shortStructureRoomOk and shortDirectionOk and shortNearBreak and close < emaMid and close < open and prelaunchBodyOk and bearSlopeCount >= profileSlopeNeed and shortPrelaunchDirectionOk and diBearOk and shortPositionOk
|
||||
|
||||
bullLaunchRaw = mtfLongOk and adxLaunchOk and diBullOk and longStructureRoomOk and longLaunchEscapeOk and biasBullLaunchOk and biasSlopeBullOk and longDirectionOk and launchWasCompressed and bullOrder and bullSlopeCount >= profileSlopeNeed and bullRibbonExpanding and close > emaFast and close > open and launchBodyOk and longPositionOk and longCleanClose and (not profileBreakNeed or breaksShortHigh)
|
||||
bearLaunchRaw = mtfShortOk and adxLaunchOk and diBearOk and shortStructureRoomOk and shortLaunchEscapeOk and biasBearLaunchOk and biasSlopeBearOk and shortDirectionOk and launchWasCompressed and bearOrder and bearSlopeCount >= profileSlopeNeed and bearRibbonExpanding and close < emaFast and close < open and launchBodyOk and shortPositionOk and shortCleanClose and (not profileBreakNeed or breaksShortLow)
|
||||
|
||||
bullLaunchStart = bullLaunchRaw and not bullLaunchRaw[1]
|
||||
bearLaunchStart = bearLaunchRaw and not bearLaunchRaw[1]
|
||||
bullLaunchFresh = nz(ta.barssince(bullLaunchStart), 100000) <= launchFreshBars
|
||||
bearLaunchFresh = nz(ta.barssince(bearLaunchStart), 100000) <= launchFreshBars
|
||||
|
||||
bullTrendContext = biasBullOk and biasSlopeBullOk and longDirectionOk and bullOrder and bullSlopeCount >= profileSlopeNeed
|
||||
bearTrendContext = biasBearOk and biasSlopeBearOk and shortDirectionOk and bearOrder and bearSlopeCount >= profileSlopeNeed
|
||||
bullTrendBars = bullTrendContext ? nz(ta.barssince(not bullTrendContext), 100000) : 0
|
||||
bearTrendBars = bearTrendContext ? nz(ta.barssince(not bearTrendContext), 100000) : 0
|
||||
var float lastBullBreakoutLevel = na
|
||||
var float lastBearBreakoutLevel = na
|
||||
bullBreakoutBodyOk = close > open and body >= atr * minBreakoutBodyAtr
|
||||
bearBreakoutBodyOk = close < open and body >= atr * minBreakoutBodyAtr
|
||||
bullPriceBreakout = ta.crossover(close, emaBias) and close > ta.highest(high[1], breakoutLevelLookback) and bullBreakoutBodyOk
|
||||
bearPriceBreakout = ta.crossunder(close, emaBias) and close < ta.lowest(low[1], breakoutLevelLookback) and bearBreakoutBodyOk
|
||||
bullBiasBreakout = bullPriceBreakout or ta.crossover(emaSlow, emaBias)
|
||||
bearBiasBreakout = bearPriceBreakout or ta.crossunder(emaSlow, emaBias)
|
||||
if bullPriceBreakout
|
||||
lastBullBreakoutLevel := ta.highest(high[1], breakoutLevelLookback)
|
||||
if bearPriceBreakout
|
||||
lastBearBreakoutLevel := ta.lowest(low[1], breakoutLevelLookback)
|
||||
bullBiasBreakoutFresh = not requireRecentBiasBreakout or nz(ta.barssince(bullBiasBreakout), 100000) <= biasBreakoutRetestBars
|
||||
bearBiasBreakoutFresh = not requireRecentBiasBreakout or nz(ta.barssince(bearBiasBreakout), 100000) <= biasBreakoutRetestBars
|
||||
bullTrendMature = bullTrendContext and bullTrendBars >= trendMatureBars and bullRibbonExpanding and bullBiasBreakoutFresh and (not useBiasSide or close > emaBias + atr * trendAwayAtr)
|
||||
bearTrendMature = bearTrendContext and bearTrendBars >= trendMatureBars and bearRibbonExpanding and bearBiasBreakoutFresh and (not useBiasSide or close < emaBias - atr * trendAwayAtr)
|
||||
longTrendAgeOk = not useLateTrendFilter or maxTrendBars == 0 or bullTrendBars <= maxTrendBars
|
||||
shortTrendAgeOk = not useLateTrendFilter or maxTrendBars == 0 or bearTrendBars <= maxTrendBars
|
||||
|
||||
bullPullbackToRibbon = bullTrendMature and low <= emaFast and low >= emaSlow - atr * biasRetestAtr
|
||||
bearPullbackToRibbon = bearTrendMature and high >= emaFast and high <= emaSlow + atr * biasRetestAtr
|
||||
bullPullbackToBias = bullTrendMature and useBiasRetestPullback and low <= emaBias + atr * biasRetestAtr
|
||||
bearPullbackToBias = bearTrendMature and useBiasRetestPullback and high >= emaBias - atr * biasRetestAtr
|
||||
bullPullbackToBreakoutLevel = bullTrendMature and not na(lastBullBreakoutLevel) and low <= lastBullBreakoutLevel + atr * breakoutLevelRetestAtr and close >= lastBullBreakoutLevel - atr * breakoutLevelRetestAtr
|
||||
bearPullbackToBreakoutLevel = bearTrendMature and not na(lastBearBreakoutLevel) and high >= lastBearBreakoutLevel - atr * breakoutLevelRetestAtr and close <= lastBearBreakoutLevel + atr * breakoutLevelRetestAtr
|
||||
bullPullbackEvent = (useBreakoutLevelRetest ? bullPullbackToBreakoutLevel : bullPullbackToRibbon) or bullPullbackToBias
|
||||
bearPullbackEvent = (useBreakoutLevelRetest ? bearPullbackToBreakoutLevel : bearPullbackToRibbon) or bearPullbackToBias
|
||||
bullPullbackRecent = nz(ta.barssince(bullPullbackEvent), 100000) <= pullbackLookback
|
||||
bearPullbackRecent = nz(ta.barssince(bearPullbackEvent), 100000) <= pullbackLookback
|
||||
bullBreakoutLevelConfirmOk = not useBreakoutLevelRetest or na(lastBullBreakoutLevel) or close <= lastBullBreakoutLevel + atr * maxContinuationDistanceAtr
|
||||
bearBreakoutLevelConfirmOk = not useBreakoutLevelRetest or na(lastBearBreakoutLevel) or close >= lastBearBreakoutLevel - atr * maxContinuationDistanceAtr
|
||||
|
||||
bullContinuationRaw = mtfLongOk and adxContinuationOk and diBullOk and continuationZoneOk and chopExitConfirmed and longStructureRoomOk and longTrendAgeOk and bullTrendMature and bullPullbackRecent and bullBreakoutLevelConfirmOk and close > emaFast and close > emaMid and close > open and continuationBodyOk and longContinuationDistanceOk and longPositionOk and longEntryPositionOk and longCleanClose
|
||||
bearContinuationRaw = mtfShortOk and adxContinuationOk and diBearOk and continuationZoneOk and chopExitConfirmed and shortStructureRoomOk and shortTrendAgeOk and bearTrendMature and bearPullbackRecent and bearBreakoutLevelConfirmOk and close < emaFast and close < emaMid and close < open and continuationBodyOk and shortContinuationDistanceOk and shortPositionOk and shortEntryPositionOk and shortCleanClose
|
||||
|
||||
var int lastLongSignalBar = na
|
||||
var int lastShortSignalBar = na
|
||||
var int lastAnySignalBar = na
|
||||
var int lastLongPrelaunchBar = na
|
||||
var int lastShortPrelaunchBar = na
|
||||
var int longTrendSignalCount = 0
|
||||
var int shortTrendSignalCount = 0
|
||||
|
||||
if close < emaBias or bearTrendContext
|
||||
longTrendSignalCount := 0
|
||||
|
||||
if close > emaBias or bullTrendContext
|
||||
shortTrendSignalCount := 0
|
||||
|
||||
canLongSignal = na(lastLongSignalBar) or bar_index - lastLongSignalBar > cooldownBars
|
||||
canShortSignal = na(lastShortSignalBar) or bar_index - lastShortSignalBar > cooldownBars
|
||||
canAnySignal = na(lastAnySignalBar) or bar_index - lastAnySignalBar > globalCooldownBars
|
||||
canLongPrelaunch = na(lastLongPrelaunchBar) or bar_index - lastLongPrelaunchBar > prelaunchCooldownBars
|
||||
canShortPrelaunch = na(lastShortPrelaunchBar) or bar_index - lastShortPrelaunchBar > prelaunchCooldownBars
|
||||
canLongTrendSignal = not useLateTrendFilter or maxMainSignalsPerTrend == 0 or longTrendSignalCount < maxMainSignalsPerTrend
|
||||
canShortTrendSignal = not useLateTrendFilter or maxMainSignalsPerTrend == 0 or shortTrendSignalCount < maxMainSignalsPerTrend
|
||||
|
||||
longPrelaunchSignal = barstate.isconfirmed and longPrelaunchRaw and not longPrelaunchRaw[1] and not bullLaunchRaw and canLongPrelaunch and canAnySignal
|
||||
shortPrelaunchSignal = barstate.isconfirmed and shortPrelaunchRaw and not shortPrelaunchRaw[1] and not bearLaunchRaw and canShortPrelaunch and canAnySignal
|
||||
longLaunchSignal = barstate.isconfirmed and bullLaunchStart and canLongSignal and canAnySignal
|
||||
shortLaunchSignal = barstate.isconfirmed and bearLaunchStart and canShortSignal and canAnySignal
|
||||
longContinuationSignal = barstate.isconfirmed and simpleLongSetup and not simpleLongSetup[1] and canLongSignal and canAnySignal and canLongTrendSignal
|
||||
shortContinuationSignal = barstate.isconfirmed and simpleShortSetup and not simpleShortSetup[1] and canShortSignal and canAnySignal and canShortTrendSignal
|
||||
|
||||
useLaunchAsMain = mainSignalMode == "启动+趋势回踩"
|
||||
usePrelaunchAsMain = prelaunchMode == "并入主信号"
|
||||
mainLongPrelaunchSignal = usePrelaunchAsMain and longPrelaunchSignal and canLongTrendSignal
|
||||
mainShortPrelaunchSignal = usePrelaunchAsMain and shortPrelaunchSignal and canShortTrendSignal
|
||||
mainLongLaunchSignal = useLaunchAsMain and longLaunchSignal and canLongTrendSignal
|
||||
mainShortLaunchSignal = useLaunchAsMain and shortLaunchSignal and canShortTrendSignal
|
||||
longSignal = mainLongPrelaunchSignal or mainLongLaunchSignal or longContinuationSignal
|
||||
shortSignal = mainShortPrelaunchSignal or mainShortLaunchSignal or shortContinuationSignal
|
||||
|
||||
if longPrelaunchSignal
|
||||
lastLongPrelaunchBar := bar_index
|
||||
|
||||
if shortPrelaunchSignal
|
||||
lastShortPrelaunchBar := bar_index
|
||||
|
||||
if longSignal
|
||||
lastLongSignalBar := bar_index
|
||||
longTrendSignalCount := longTrendSignalCount + 1
|
||||
|
||||
if shortSignal
|
||||
lastShortSignalBar := bar_index
|
||||
shortTrendSignalCount := shortTrendSignalCount + 1
|
||||
|
||||
if longSignal or shortSignal
|
||||
lastAnySignalBar := bar_index
|
||||
|
||||
plot(emaFast, "EMA5", color=color.new(color.teal, 0), linewidth=1)
|
||||
plot(emaMid, "EMA15", color=color.new(color.orange, 0), linewidth=1)
|
||||
plot(emaSlow, "EMA30", color=color.new(color.yellow, 0), linewidth=1)
|
||||
plot(emaBias, "EMA144", color=color.new(color.red, 0), linewidth=2)
|
||||
|
||||
barcolor(showBarColor and bullTrendContext ? color.new(color.green, 0) : showBarColor and bearTrendContext ? color.new(color.red, 0) : na)
|
||||
|
||||
plotshape(longSignal, title="做多信号", style=shape.labelup, location=location.belowbar, color=color.new(color.lime, 0), textcolor=color.black, size=size.normal, text="做多")
|
||||
plotshape(shortSignal, title="做空信号", style=shape.labeldown, location=location.abovebar, color=color.new(color.red, 0), textcolor=color.white, size=size.normal, text="做空")
|
||||
|
||||
plotshape(prelaunchMode != "关闭" and longPrelaunchSignal, title="预启动做多", style=shape.labelup, location=location.belowbar, color=color.new(color.aqua, 0), textcolor=color.black, size=size.tiny, text="预多")
|
||||
plotshape(prelaunchMode != "关闭" and shortPrelaunchSignal, title="预启动做空", style=shape.labeldown, location=location.abovebar, color=color.new(color.fuchsia, 0), textcolor=color.white, size=size.tiny, text="预空")
|
||||
plotshape(showMtfRiskMarks and mtfLongRisk and (longPrelaunchSignal or longSignal), title="风险:逆风险周期做多", style=shape.diamond, location=location.belowbar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
plotshape(showMtfRiskMarks and mtfShortRisk and (shortPrelaunchSignal or shortSignal), title="风险:逆风险周期做空", style=shape.diamond, location=location.abovebar, color=color.new(color.orange, 0), size=size.tiny, text="逆1H")
|
||||
plotshape(showAuxMarks and longLaunchSignal, title="辅助:均线带启动做多", style=shape.arrowup, location=location.belowbar, color=color.new(color.lime, 45), size=size.tiny, text="")
|
||||
plotshape(showAuxMarks and shortLaunchSignal, title="辅助:均线带启动做空", style=shape.arrowdown, location=location.abovebar, color=color.new(color.red, 45), size=size.tiny, text="")
|
||||
plotshape(showAuxMarks and simpleLongSetup, title="辅助:干净回踩做多", style=shape.circle, location=location.belowbar, color=color.new(color.aqua, 45), size=size.tiny, text="")
|
||||
plotshape(showAuxMarks and simpleShortSetup, title="辅助:干净反抽做空", style=shape.circle, location=location.abovebar, color=color.new(color.orange, 45), size=size.tiny, text="")
|
||||
|
||||
var table stateTable = table.new(position.top_right, 2, 6, border_width=1)
|
||||
|
||||
if showStateTable and barstate.islast
|
||||
directionText = simpleBullTrend ? "趋势多" : simpleBearTrend ? "趋势空" : close > emaBias ? "偏多" : close < emaBias ? "偏空" : "中性"
|
||||
trendText = chopZone ? "缠绕禁区" : simpleBullTrend or simpleBearTrend ? "均线发散" : ribbonSeparated ? "排列未确认" : "无趋势"
|
||||
structureText = longPrelaunchSignal ? "预启动多" : shortPrelaunchSignal ? "预启动空" : simpleBullPullback ? "回踩均线带" : simpleBearPullback ? "反抽均线带" : simpleBullPullbackRecent or simpleBearPullbackRecent ? "等待确认" : "等待回踩"
|
||||
positionText = entryRangePosition > maxLongEntryRangePosition ? "确认偏高" : entryRangePosition < minShortEntryRangePosition ? "确认偏低" : "位置适中"
|
||||
mtfText = not useMtfTrendFilter ? "关闭" : not mtfLongFilterOk and close >= emaBias ? "15/30反空" : not mtfShortFilterOk and close < emaBias ? "15/30反多" : mtfLongRisk and close >= emaBias ? "逆1H空" : mtfShortRisk and close < emaBias ? "逆1H多" : "顺/中性"
|
||||
signalText = longSignal ? "做多" : shortSignal ? "做空" : longPrelaunchSignal ? "预多" : shortPrelaunchSignal ? "预空" : chopZone ? "等待脱离" : "等待"
|
||||
signalColor = longSignal ? color.new(color.green, 0) : shortSignal ? color.new(color.red, 0) : longPrelaunchSignal ? color.new(color.aqua, 0) : shortPrelaunchSignal ? color.new(color.fuchsia, 0) : color.new(color.gray, 0)
|
||||
directionColor = simpleBullTrend or close > emaBias ? color.new(color.green, 15) : simpleBearTrend or close < emaBias ? color.new(color.red, 15) : color.new(color.gray, 20)
|
||||
trendColor = chopZone ? color.new(color.orange, 20) : simpleBullTrend ? color.new(color.green, 15) : simpleBearTrend ? color.new(color.red, 15) : color.new(color.gray, 20)
|
||||
structureColor = longPrelaunchSignal ? color.new(color.aqua, 10) : shortPrelaunchSignal ? color.new(color.fuchsia, 10) : simpleBullPullbackRecent or simpleBearPullbackRecent ? color.new(color.orange, 15) : color.new(color.gray, 20)
|
||||
mtfCurrentRisk = close >= emaBias ? (not mtfLongFilterOk or mtfLongRisk) : (not mtfShortFilterOk or mtfShortRisk)
|
||||
mtfColor = not useMtfTrendFilter ? color.new(color.gray, 20) : mtfCurrentRisk ? color.new(color.orange, 15) : color.new(color.green, 25)
|
||||
|
||||
table.cell(stateTable, 0, 0, "方向", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 0, directionText, text_color=color.white, bgcolor=directionColor)
|
||||
table.cell(stateTable, 0, 1, "趋势", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 1, trendText, text_color=color.white, bgcolor=trendColor)
|
||||
table.cell(stateTable, 0, 2, "结构", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 2, structureText, text_color=color.white, bgcolor=structureColor)
|
||||
table.cell(stateTable, 0, 3, "位置", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 3, positionText, text_color=color.white, bgcolor=color.new(color.black, 70))
|
||||
table.cell(stateTable, 0, 4, "多周期", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 4, mtfText, text_color=color.white, bgcolor=mtfColor)
|
||||
table.cell(stateTable, 0, 5, "信号", text_color=color.white, bgcolor=color.new(color.black, 0))
|
||||
table.cell(stateTable, 1, 5, signalText, text_color=color.white, bgcolor=signalColor)
|
||||
|
||||
alertcondition(longLaunchSignal, title="均线带启动做多", message="EMA5/15/30 从压缩转为多头排列并向上突破短线结构,出现做多信号")
|
||||
alertcondition(shortLaunchSignal, title="均线带启动做空", message="EMA5/15/30 从压缩转为空头排列并向下跌破短线结构,出现做空信号")
|
||||
alertcondition(longPrelaunchSignal, title="预启动做多", message="EMA5/15/30 仍处于压缩/初开阶段,价格贴近上方短结构突破位,出现趋势启动前做多预警")
|
||||
alertcondition(shortPrelaunchSignal, title="预启动做空", message="EMA5/15/30 仍处于压缩/初开阶段,价格贴近下方短结构突破位,出现趋势启动前做空预警")
|
||||
alertcondition(longContinuationSignal, title="均线带中继做多", message="多头均线带中回踩 EMA15/30 后重新收回 EMA5,出现做多信号")
|
||||
alertcondition(shortContinuationSignal, title="均线带中继做空", message="空头均线带中反抽 EMA15/30 后重新跌回 EMA5,出现做空信号")
|
||||
alertcondition(longSignal, title="均线带综合做多", message="EMA 均线带出现做多信号")
|
||||
alertcondition(shortSignal, title="均线带综合做空", message="EMA 均线带出现做空信号")
|
||||
Loading…
Reference in New Issue
Block a user