keep ATR freeze coverage on generic RSI compiler path #242
Annotations
4 errors and 1 warning
|
test-and-build
Process completed with exit code 1.
|
|
tests/strategy-divergence-alignment.test.ts > Strategy divergence alignment > does not change indicator output:
tests/strategy-divergence-alignment.test.ts#L46
AssertionError: expected '//@Version=6\n// PineForge validated …' to contain '// === Integrated RSI divergence pane…'
- Expected
+ Received
- // === Integrated RSI divergence pane ===
+ //@Version=6
+ // PineForge validated profile: BNBUSDT, 30-minute chart.
+ // Development: 2019-2022. Validation: 2023-2024. Final 2025+ holdout was not opened.
+ // Commission 0.15% per side is used as a TradingView proxy for the research model's 0.10% commission plus 0.05% adverse slippage.
+ // Review and test this script before using real capital.
+ indicator("RSI Divergence Reversal · BNBUSDT 30m", overlay=true, max_labels_count=500, max_lines_count=500)
+
+ // === Validated profile constants ===
+ expectedTicker = "BNBUSDT"
+ expectedTimeframe = "30"
+ profileMarketOk = syminfo.ticker == expectedTicker
+ profileTimeframeOk = timeframe.period == expectedTimeframe
+ profileAllowed = profileMarketOk and profileTimeframeOk
+ confirmedOnly = input.bool(true, "Confirmed candles only")
+ rsiLength = input.int(14, "RSI length", minval=2)
+ pivotLeft = input.int(5, "Divergence pivot left", minval=1)
+ pivotRight = input.int(5, "Divergence pivot right", minval=1)
+ pivotRangeMin = input.int(5, "Minimum pivot range", minval=1)
+ pivotRangeMax = input.int(60, "Maximum pivot range", minval=2)
+ confirmationExpiry = input.int(30, "EMA confirmation expiry bars", minval=1)
+ swingLength = input.int(15, "Swing stop lookback", minval=2)
+ riskReward = input.float(1.8, "Risk/reward target", minval=0.1, step=0.1)
+ volumeLength = input.int(20, "Volume average length", minval=1)
+ volumeMultiplier = input.float(0.8, "Minimum volume multiplier", minval=0.1, step=0.05)
+
+ // === Core calculations ===
+ rsiValue = ta.rsi(close, rsiLength)
+ ema9 = ta.ema(close, 9)
+ wma45 = ta.wma(close, 45)
+ ema50 = ta.ema(close, 50)
+ ema200 = ta.ema(close, 200)
+ volumeAverage = ta.sma(volume, volumeLength)
+ confirmationOk = not confirmedOnly or barstate.isconfirmed
+ volumeOk = volume >= volumeAverage * volumeMultiplier
+ longTrendOk = ema50 > ema200 and close > ema200
+ shortTrendOk = ema50 < ema200 and close < ema200
+
+ // === Confirmed regular RSI divergence ===
+ pivotLowFound = not na(ta.pivotlow(rsiValue, pivotLeft, pivotRight))
+ pivotHighFound = not na(ta.pivothigh(rsiValue, pivotLeft, pivotRight))
+ inPivotRange(condition) =>
+ barsSince = ta.barssince(condition)
+ pivotRangeMin <= barsSince and barsSince <= pivotRangeMax
+ previousLowInRange = inPivotRange(pivotLowFound[1])
+ rsiHigherLow = rsiValue[pivotRight] > ta.valuewhen(pivotLowFound, rsiValue[pivotRight], 1) and previousLowInRange
+ priceLowerLow = low[pivotRight] < ta.valuewhen(pivotLowFound, low[pivotRight], 1)
+ regularBullishDivergence = pivotLowFound and rsiHigherLow and priceLowerLow
+ previousHighInRange = inPivotRange(pivotHighFound[1])
+ rsiLowerHigh = rsiValue[pivotRight] < ta.valuewhen(pivotHighFound, rsiValue[pivotRight], 1) and previousHighInRange
+ priceHigherHigh = high[pivotRight] > ta.valuewhen(pivotHighFound, high[pivotRight], 1)
+ regularBearishDivergence = pivotHighFound and rsiLowerHigh and priceHigherHigh
+
+ // === Divergence is armed until EMA9/WMA45 confirms ===
+ var int pendingDirection = 0
+ var int pendingExpiresAt = na
+ if regularBullishDivergence
+ pendingDirection := 1
+ pendingExpiresAt := bar_index + confirmationExpiry
+ if regularBearishDivergence
+ pendingDirection := -1
+ pendingExpiresAt := bar_index + confirmationExpiry
+ if not na(pendingExpiresAt) and bar_index > pendingExpiresAt
+ pendingDirection := 0
+ pendingExpiresAt := na
+ longConfirmation = pendingDirection == 1 and ta.crossover(ema9, wma45)
+ shortConfirmation = pendingDirection == -1 and ta.crossunder(ema9, wma45)
+ longSignal = profileAllowed and confirmationOk and volumeOk and longTrendOk and longConfirmation
+ shortSignal = profileAllowed and confirmationOk and volumeOk and shortTrendOk and shortConfirmation
+ if longSignal or shortSignal
+ pendingDirection := 0
+ pendingExpiresAt := na
+
+ // === Frozen swing risk captured at entry ===
+ var float
|
|
tests/strategy-divergence-alignment.test.ts > Strategy divergence alignment > uses the confirmed regular divergence engine when divergence is enabled:
tests/strategy-divergence-alignment.test.ts#L16
AssertionError: expected '//@Version=6\n// PineForge validated …' to contain '// Confirmed regular RSI divergence s…'
- Expected
+ Received
- // Confirmed regular RSI divergence shared with Indicator mode.
+ //@Version=6
+ // PineForge validated profile: BNBUSDT, 30-minute chart.
+ // Development: 2019-2022. Validation: 2023-2024. Final 2025+ holdout was not opened.
+ // Commission 0.15% per side is used as a TradingView proxy for the research model's 0.10% commission plus 0.05% adverse slippage.
+ // Review and test this script before using real capital.
+ strategy("RSI Divergence Reversal · BNBUSDT 30m", overlay=true, pyramiding=0, process_orders_on_close=true, initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.15)
+
+ // === Validated profile constants ===
+ expectedTicker = "BNBUSDT"
+ expectedTimeframe = "30"
+ profileMarketOk = syminfo.ticker == expectedTicker
+ profileTimeframeOk = timeframe.period == expectedTimeframe
+ profileAllowed = profileMarketOk and profileTimeframeOk
+ confirmedOnly = input.bool(true, "Confirmed candles only")
+ rsiLength = input.int(14, "RSI length", minval=2)
+ pivotLeft = input.int(5, "Divergence pivot left", minval=1)
+ pivotRight = input.int(5, "Divergence pivot right", minval=1)
+ pivotRangeMin = input.int(5, "Minimum pivot range", minval=1)
+ pivotRangeMax = input.int(60, "Maximum pivot range", minval=2)
+ confirmationExpiry = input.int(30, "EMA confirmation expiry bars", minval=1)
+ swingLength = input.int(15, "Swing stop lookback", minval=2)
+ riskReward = input.float(1.8, "Risk/reward target", minval=0.1, step=0.1)
+ volumeLength = input.int(20, "Volume average length", minval=1)
+ volumeMultiplier = input.float(0.8, "Minimum volume multiplier", minval=0.1, step=0.05)
+
+ // === Core calculations ===
+ rsiValue = ta.rsi(close, rsiLength)
+ ema9 = ta.ema(close, 9)
+ wma45 = ta.wma(close, 45)
+ ema50 = ta.ema(close, 50)
+ ema200 = ta.ema(close, 200)
+ volumeAverage = ta.sma(volume, volumeLength)
+ confirmationOk = not confirmedOnly or barstate.isconfirmed
+ volumeOk = volume >= volumeAverage * volumeMultiplier
+ longTrendOk = ema50 > ema200 and close > ema200
+ shortTrendOk = ema50 < ema200 and close < ema200
+
+ // === Confirmed regular RSI divergence ===
+ pivotLowFound = not na(ta.pivotlow(rsiValue, pivotLeft, pivotRight))
+ pivotHighFound = not na(ta.pivothigh(rsiValue, pivotLeft, pivotRight))
+ inPivotRange(condition) =>
+ barsSince = ta.barssince(condition)
+ pivotRangeMin <= barsSince and barsSince <= pivotRangeMax
+ previousLowInRange = inPivotRange(pivotLowFound[1])
+ rsiHigherLow = rsiValue[pivotRight] > ta.valuewhen(pivotLowFound, rsiValue[pivotRight], 1) and previousLowInRange
+ priceLowerLow = low[pivotRight] < ta.valuewhen(pivotLowFound, low[pivotRight], 1)
+ regularBullishDivergence = pivotLowFound and rsiHigherLow and priceLowerLow
+ previousHighInRange = inPivotRange(pivotHighFound[1])
+ rsiLowerHigh = rsiValue[pivotRight] < ta.valuewhen(pivotHighFound, rsiValue[pivotRight], 1) and previousHighInRange
+ priceHigherHigh = high[pivotRight] > ta.valuewhen(pivotHighFound, high[pivotRight], 1)
+ regularBearishDivergence = pivotHighFound and rsiLowerHigh and priceHigherHigh
+
+ // === Divergence is armed until EMA9/WMA45 confirms ===
+ var int pendingDirection = 0
+ var int pendingExpiresAt = na
+ if regularBullishDivergence
+ pendingDirection := 1
+ pendingExpiresAt := bar_index + confirmationExpiry
+ if regularBearishDivergence
+ pendingDirection := -1
+ pendingExpiresAt := bar_index + confirmationExpiry
+ if not na(pendingExpiresAt) and bar_index > pendingExpiresAt
+ pendingDirection := 0
+ pendingExpiresAt := na
+ longConfirmation = pendingDirection == 1 and ta.crossover(ema9, wma45)
+ shortConfirmation = pendingDirection == -1 and ta.crossunder(ema9, wma45)
+ longSignal = profileAllowed and confirmationOk and volumeOk and longTrendOk and longConfirmation
+ shortSignal = profileAllowed and confirmationOk and volumeOk and shortTrendOk and shortConfirmation
+ if longSignal or shortSignal
+
|
|
tests/compiler.test.ts > preset behavior fixtures > RSI Divergence Reversal satisfies validation, Pine and explanation contracts:
tests/compiler.test.ts#L26
AssertionError: [
{
"level": "error",
"code": "filter.ema_trend.long_missing",
"message": "Long filter ema_trend is missing."
},
{
"level": "error",
"code": "filter.ema_trend.short_missing",
"message": "Short filter ema_trend is missing."
},
{
"level": "error",
"code": "filter.divergence.long_missing",
"message": "Long filter divergence is missing."
},
{
"level": "error",
"code": "filter.divergence.short_missing",
"message": "Short filter divergence is missing."
},
{
"level": "error",
"code": "indicator.risk_stop_missing",
"message": "Indicator risk settings require a visible stop plot."
},
{
"level": "error",
"code": "indicator.risk_target_missing",
"message": "Indicator target settings require a visible target plot."
}
]: expected [ { level: 'error', …(2) }, …(5) ] to deeply equal []
- Expected
+ Received
- []
+ [
+ {
+ "code": "filter.ema_trend.long_missing",
+ "level": "error",
+ "message": "Long filter ema_trend is missing.",
+ },
+ {
+ "code": "filter.ema_trend.short_missing",
+ "level": "error",
+ "message": "Short filter ema_trend is missing.",
+ },
+ {
+ "code": "filter.divergence.long_missing",
+ "level": "error",
+ "message": "Long filter divergence is missing.",
+ },
+ {
+ "code": "filter.divergence.short_missing",
+ "level": "error",
+ "message": "Short filter divergence is missing.",
+ },
+ {
+ "code": "indicator.risk_stop_missing",
+ "level": "error",
+ "message": "Indicator risk settings require a visible stop plot.",
+ },
+ {
+ "code": "indicator.risk_target_missing",
+ "level": "error",
+ "message": "Indicator target settings require a visible target plot.",
+ },
+ ]
❯ expectClean tests/compiler.test.ts:26:85
❯ tests/compiler.test.ts:150:7
|
|
test-and-build
Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v4, actions/setup-node@v4. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
|