//@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 均线带出现做空信号")