Strategy ยท Pine Script v6 ยท Own pane

MS+MACD Basic Tests

by iamrichardD

This script implements an automated unit testing suite for a 4-hour swing trading system based on market structure and MACD.

View on GitHub

GitHub stars57on the repository
Pine versionv6current
Lines of code513
Settings0inputs
LicenceApache-2.0
Last update1 year ago19 Aug 2025

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

513 lines of Pine Script v6 from production/4h-swing-trading/test-suite-basic.pine, published under Apache-2.0. Keep the author's credit and licence lines when you reuse it.

test-suite-basic.pine
// Market Structure MACD 4H Strategy - Basic Test Suite
// Tests for simplified MS+MACD+Trailing system
// Updated for streamlined strategy

//@version=6
strategy("MS+MACD Basic Tests", overlay=false, max_labels_count=100)

//=====================================================================================================================
// SIMPLIFIED PINEUNIT TESTING FRAMEWORK
//=====================================================================================================================

type TestCase
    string name
    bool passed
    string message
    float expected
    float actual
    
type TestSuite
    string name
    array<TestCase> tests
    int totalTests
    int passedTests
    int failedTests
    
    method addTest(string testName, bool condition, string message = "", float expected = na, float actual = na) =>
        test = TestCase.new(testName, condition, message, expected, actual)
        array.push(this.tests, test)
        this.totalTests += 1
        if condition
            this.passedTests += 1
        else
            this.failedTests += 1
    
    method getResults() =>
        passRate = this.totalTests > 0 ? (this.passedTests / this.totalTests) * 100 : 0
        [this.passedTests, this.failedTests, this.totalTests, passRate]

//=====================================================================================================================
// MOCK DATA AND HELPER FUNCTIONS FOR SIMPLIFIED STRATEGY
//=====================================================================================================================

// Mock Market Structure Detection
mockMarketStructureDetection(price, swingHigh, swingLow, trend) =>
    chochBullish = price > swingHigh and trend <= 0
    chochBearish = price < swingLow and trend >= 0
    
    currentHigh = trend == 1 ? math.max(price, swingHigh) : swingHigh
    currentLow = trend == -1 ? math.min(price, swingLow) : swingLow
    
    bosBullish = trend == 1 and price > currentHigh
    bosBearish = trend == -1 and price < currentLow
    
    idmBullish = trend == 1 and price > swingLow // Simplified IDM
    idmBearish = trend == -1 and price < swingHigh // Simplified IDM
    
    msLongSignal = chochBullish or bosBullish or idmBullish
    msShortSignal = chochBearish or bosBearish or idmBearish
    
    [msLongSignal, msShortSignal, chochBullish, chochBearish, bosBullish, bosBearish]

// Mock MACD Filter
mockMACDFilter(macdLine, signalLine) =>
    macdBullish = macdLine > signalLine and macdLine > 0
    macdBearish = macdLine < signalLine and macdLine < 0
    [macdBullish, macdBearish]

// Mock ATR Level Calculation
mockATRLevels(entryPrice, atrValue, stopMult, tpMult, isLong) =>
    stopLoss = isLong ? entryPrice - (atrValue * stopMult) : entryPrice + (atrValue * stopMult)
    takeProfit = isLong ? entryPrice + (atrValue * tpMult) : entryPrice - (atrValue * tpMult)
    riskRewardRatio = math.abs(takeProfit - entryPrice) / math.abs(entryPrice - stopLoss)
    [stopLoss, takeProfit, riskRewardRatio]

// Mock Trailing Stop Logic
mockTrailingStop(entryPrice, currentPrice, atrValue, stopMult, trailStartMult, isLong) =>
    currentProfit = isLong ? currentPrice - entryPrice : entryPrice - currentPrice
    trailTrigger = atrValue * trailStartMult
    shouldActivate = currentProfit >= trailTrigger
    
    if shouldActivate
        trailStop = isLong ? currentPrice - (atrValue * stopMult) : currentPrice + (atrValue * stopMult)
        trailDistance = math.abs(currentPrice - trailStop)
        [true, trailStop, trailDistance]
    else
        [false, na, na]

//=====================================================================================================================
// TEST SUITES INITIALIZATION
//=====================================================================================================================

var testSuiteMS = TestSuite.new("Market Structure Detection", array.new<TestCase>(), 0, 0, 0)
var testSuiteMACD = TestSuite.new("MACD Filter Logic", array.new<TestCase>(), 0, 0, 0)
var testSuiteRisk = TestSuite.new("Risk Management", array.new<TestCase>(), 0, 0, 0)
var testSuiteEntry = TestSuite.new("Entry/Exit Conditions", array.new<TestCase>(), 0, 0, 0)
var testSuiteTrailing = TestSuite.new("Trailing Stop Logic", array.new<TestCase>(), 0, 0, 0)

//=====================================================================================================================
// MARKET STRUCTURE DETECTION TESTS
//=====================================================================================================================

if bar_index == 100
    // Test CHoCH detection
    [msLong1, msShort1, chochBull1, chochBear1, bosBull1, bosBear1] = mockMarketStructureDetection(105.0, 100.0, 90.0, 0)
    testSuiteMS.addTest("CHoCH Bullish Detection", chochBull1, 
                        "Should detect bullish CHoCH when price breaks above swing high", na, na)
    
    [msLong2, msShort2, chochBull2, chochBear2, bosBull2, bosBear2] = mockMarketStructureDetection(85.0, 100.0, 90.0, 1)
    testSuiteMS.addTest("CHoCH Bearish Detection", chochBear2, 
                        "Should detect bearish CHoCH when price breaks below swing low", na, na)
    
    // Test BOS detection
    [msLong3, msShort3, chochBull3, chochBear3, bosBull3, bosBear3] = mockMarketStructureDetection(110.0, 105.0, 90.0, 1)
    testSuiteMS.addTest("BOS Bullish Detection", bosBull3, 
                        "Should detect bullish BOS in uptrend", na, na)
    
    [msLong4, msShort4, chochBull4, chochBear4, bosBull4, bosBear4] = mockMarketStructureDetection(85.0, 100.0, 90.0, -1)
    testSuiteMS.addTest("BOS Bearish Detection", bosBear4, 
                        "Should detect bearish BOS in downtrend", na, na)
    
    // Test overall MS signal
    testSuiteMS.addTest("MS Long Signal Aggregation", msLong1 or msLong3, 
                        "Should trigger MS long signal for structure breaks", na, na)

//=====================================================================================================================
// MACD FILTER TESTS
//=====================================================================================================================

if bar_index == 200
    // Test MACD bullish conditions
    [macdBull1, macdBear1] = mockMACDFilter(0.5, 0.3)
    testSuiteMACD.addTest("MACD Bullish Strong", macdBull1, 
                         "MACD above signal and positive should be bullish", na, na)
    
    [macdBull2, macdBear2] = mockMACDFilter(-0.2, -0.1)
    testSuiteMACD.addTest("MACD Bearish Strong", macdBear2, 
                         "MACD below signal and negative should be bearish", na, na)
    
    // Test MACD neutral/weak conditions
    [macdBull3, macdBear3] = mockMACDFilter(-0.1, 0.1)
    testSuiteMACD.addTest("MACD Neutral Block", not macdBull3 and not macdBear3, 
                         "Mixed MACD signals should block both directions", na, na)
    
    [macdBull4, macdBear4] = mockMACDFilter(0.1, 0.2)
    testSuiteMACD.addTest("MACD Below Signal Block", not macdBull4, 
                         "MACD below signal should not be bullish", na, na)

//=====================================================================================================================
// RISK MANAGEMENT TESTS (1.5/3.0 ATR SYSTEM)
//=====================================================================================================================

if bar_index == 300
    // Test 1.5 ATR stop, 3.0 ATR target system
    entryPrice = 100.0
    atrValue = 2.0
    stopMult = 1.5
    tpMult = 3.0
    
    [longStop, longTP, longRR] = mockATRLevels(entryPrice, atrValue, stopMult, tpMult, true)
    expectedLongStop = 97.0  // 100 - (2 * 1.5)
    expectedLongTP = 106.0   // 100 + (2 * 3.0)
    expectedRR = 2.0         // 6/3 = 2:1 ratio
    
    testSuiteRisk.addTest("Long 1.5 ATR Stop", math.abs(longStop - expectedLongStop) < 0.01, 
                         "Long stop should be 1.5 ATR below entry", expectedLongStop, longStop)
    
    testSuiteRisk.addTest("Long 3.0 ATR Target", math.abs(longTP - expectedLongTP) < 0.01, 
                         "Long target should be 3.0 ATR above entry", expectedLongTP, longTP)
    
    testSuiteRisk.addTest("Risk Reward Ratio 1:2", math.abs(longRR - expectedRR) < 0.01, 
                         "Should achieve 1:2 risk/reward ratio", expectedRR, longRR)
    
    // Test short position levels
    [shortStop, shortTP, shortRR] = mockATRLevels(entryPrice, atrValue, stopMult, tpMult, false)
    expectedShortStop = 103.0  // 100 + (2 * 1.5)
    expectedShortTP = 94.0     // 100 - (2 * 3.0)
    
    testSuiteRisk.addTest("Short 1.5 ATR Stop", math.abs(shortStop - expectedShortStop) < 0.01, 
                         "Short stop should be 1.5 ATR above entry", expectedShortStop, shortStop)
    
    testSuiteRisk.addTest("Short 3.0 ATR Target", math.abs(shortTP - expectedShortTP) < 0.01, 
                         "Short target should be 3.0 ATR below entry", expectedShortTP, shortTP)
    
    // Test different ATR values
    [stopSmall, tpSmall, rrSmall] = mockATRLevels(entryPrice, 0.5, stopMult, tpMult, true)
    testSuiteRisk.addTest("Small ATR Handling", not na(stopSmall) and not na(tpSmall), 
                         "Should handle small ATR values correctly", na, na)

//=====================================================================================================================
// ENTRY/EXIT CONDITIONS TESTS
//=====================================================================================================================

if bar_index == 400
    // Test complete entry conditions
    mockMSLong = true
    mockMSShort = false
    mockMACDBull = true
    mockMACDBear = false
    mockPosition = 0  // No existing position
    
    // Long entry condition
    longEntryValid = mockMSLong and mockMACDBull and mockPosition == 0
    testSuiteEntry.addTest("Complete Long Entry", longEntryValid, 
                          "Should allow long entry with MS signal + MACD bullish + no position", na, na)
    
    // Short entry condition  
    shortEntryValid = mockMSShort and mockMACDBear and mockPosition == 0
    testSuiteEntry.addTest("Complete Short Entry", not shortEntryValid, 
                          "Should not allow short entry without proper signals", na, na)
    
    // Test position blocking
    mockPositionActive = 1  // Existing position
    longEntryBlocked = mockMSLong and mockMACDBull and mockPositionActive != 0
    testSuiteEntry.addTest("Position Blocking", not longEntryBlocked, 
                          "Should block new entries when position exists", na, na)
    
    // Test signal mismatch
    signalMismatch = mockMSLong and mockMACDBear and mockPosition == 0
    testSuiteEntry.addTest("Signal Mismatch Block", not signalMismatch, 
                          "Should block entries when MS and MACD disagree", na, na)

//=====================================================================================================================
// TRAILING STOP TESTS
//=====================================================================================================================

if bar_index == 500
    // Test trailing stop activation
    entryPrice = 100.0
    atrValue = 2.0
    stopMult = 1.5
    trailStartMult = 1.0
    
    // Test trail activation - profit reached 1.0 ATR
    currentPrice = 102.0  // 2.0 profit = 1.0 ATR trigger
    [shouldActivate1, trailStop1, trailDist1] = mockTrailingStop(entryPrice, currentPrice, atrValue, stopMult, trailStartMult, true)
    testSuiteTrailing.addTest("Trail Activation at 1.0 ATR", shouldActivate1, 
                             "Should activate trailing when profit reaches 1.0 ATR", na, na)
    
    expectedTrailStop = 99.0  // 102 - (2 * 1.5)
    testSuiteTrailing.addTest("Trail Stop Level", math.abs(trailStop1 - expectedTrailStop) < 0.01, 
                             "Trail stop should be 1.5 ATR from current price", expectedTrailStop, trailStop1)
    
    // Test trail not activating too early
    currentPriceEarly = 101.5  // 1.5 profit < 2.0 trigger
    [shouldActivate2, trailStop2, trailDist2] = mockTrailingStop(entryPrice, currentPriceEarly, atrValue, stopMult, trailStartMult, true)
    testSuiteTrailing.addTest("Trail Not Early Activation", not shouldActivate2, 
                             "Should not activate trailing before 1.0 ATR profit", na, na)
    
    // Test short position trailing
    [shouldActivate3, trailStop3, trailDist3] = mockTrailingStop(entryPrice, 98.0, atrValue, stopMult, trailStartMult, false)
    testSuiteTrailing.addTest("Short Trail Activation", shouldActivate3, 
                             "Should activate trailing for profitable short positions", na, na)

//=====================================================================================================================
// INTEGRATION TESTS
//=====================================================================================================================

if bar_index == 600
    // Test complete signal chain
    [msLong, msShort, chochBull, chochBear, bosBull, bosBear] = mockMarketStructureDetection(105.0, 100.0, 90.0, 1)
    [macdBull, macdBear] = mockMACDFilter(0.5, 0.3)
    
    completeSignal = msLong and macdBull
    testSuiteEntry.addTest("Complete Signal Chain", completeSignal, 
                          "Should generate valid signal when MS and MACD align", na, na)
    
    // Test signal with levels
    [stopLevel, tpLevel, rrRatio] = mockATRLevels(105.0, 2.0, 1.5, 3.0, true)
    validLevels = not na(stopLevel) and not na(tpLevel) and rrRatio > 1.5
    testSuiteRisk.addTest("Signal with Valid Levels", validLevels, 
                         "Should calculate valid stop/target levels for signals", na, na)

//=====================================================================================================================
// PERFORMANCE VALIDATION TESTS
//=====================================================================================================================

if bar_index == 700
    // Test win rate calculation mock
    totalTrades = 22
    winningTrades = 9
    winRate = (winningTrades / totalTrades) * 100
    targetWinRate = 40.0
    
    testSuiteEntry.addTest("Win Rate Target", winRate >= targetWinRate, 
                          "Should achieve target win rate of 40%+", targetWinRate, winRate)
    
    // Test risk/reward target
    avgWin = 1990.0
    avgLoss = 976.0
    actualRR = avgWin / avgLoss
    targetRR = 1.5
    
    testSuiteRisk.addTest("Risk/Reward Target", actualRR >= targetRR, 
                         "Should achieve target R/R of 1.5+", targetRR, actualRR)
    
    // Test profitability
    netProfit = 116.0
    testSuiteEntry.addTest("Strategy Profitability", netProfit > 0, 
                          "Strategy should be profitable", 0.0, netProfit)

//=====================================================================================================================
// EDGE CASE TESTS
//=====================================================================================================================

if bar_index == 800
    // Test zero ATR scenario
    [stopZero, tpZero, rrZero] = mockATRLevels(100.0, 0.0, 1.5, 3.0, true)
    testSuiteRisk.addTest("Zero ATR Handling", stopZero == 100.0 and tpZero == 100.0, 
                         "Should handle zero ATR gracefully", na, na)
    
    // Test extreme ATR values
    [stopExtreme, tpExtreme, rrExtreme] = mockATRLevels(100.0, 50.0, 1.5, 3.0, true)
    testSuiteRisk.addTest("Extreme ATR Handling", not na(stopExtreme) and not na(tpExtreme), 
                         "Should handle extreme ATR values", na, na)
    
    // Test MACD edge cases
    [macdBullEdge, macdBearEdge] = mockMACDFilter(0.0001, 0.0)
    testSuiteMACD.addTest("MACD Near Zero", macdBullEdge, 
                         "Should handle near-zero MACD values", na, na)

//=====================================================================================================================
// RESULTS DISPLAY
//=====================================================================================================================

if barstate.islast
    // Get all test results
    [msPassed, msFailed, msTotal, msRate] = testSuiteMS.getResults()
    [macdPassed, macdFailed, macdTotal, macdRate] = testSuiteMACD.getResults()
    [riskPassed, riskFailed, riskTotal, riskRate] = testSuiteRisk.getResults()
    [entryPassed, entryFailed, entryTotal, entryRate] = testSuiteEntry.getResults()
    [trailingPassed, trailingFailed, trailingTotal, trailingRate] = testSuiteTrailing.getResults()
    
    // Calculate overall results
    totalPassed = msPassed + macdPassed + riskPassed + entryPassed + trailingPassed
    totalFailed = msFailed + macdFailed + riskFailed + entryFailed + trailingFailed
    totalTests = msTotal + macdTotal + riskTotal + entryTotal + trailingTotal
    overallRate = totalTests > 0 ? (totalPassed / totalTests) * 100 : 0
    
    // Create results table
    var table resultsTable = table.new(position.bottom_right, 6, 10, bgcolor=color.white, border_width=1)
    
    // Headers
    table.cell(resultsTable, 0, 0, "๐Ÿงช MS+MACD Test Suite", text_color=color.white, bgcolor=color.navy)
    table.cell(resultsTable, 1, 0, "โœ… Pass", text_color=color.white, bgcolor=color.navy)
    table.cell(resultsTable, 2, 0, "โŒ Fail", text_color=color.white, bgcolor=color.navy)
    table.cell(resultsTable, 3, 0, "๐Ÿ“Š Total", text_color=color.white, bgcolor=color.navy)
    table.cell(resultsTable, 4, 0, "๐Ÿ“ˆ Rate", text_color=color.white, bgcolor=color.navy)
    table.cell(resultsTable, 5, 0, "๐ŸŽฏ Status", text_color=color.white, bgcolor=color.navy)
    
    // Market Structure results
    table.cell(resultsTable, 0, 1, "Market Structure", text_color=color.black)
    table.cell(resultsTable, 1, 1, str.tostring(msPassed), text_color=color.green)
    table.cell(resultsTable, 2, 1, str.tostring(msFailed), text_color=color.red)
    table.cell(resultsTable, 3, 1, str.tostring(msTotal), text_color=color.black)
    table.cell(resultsTable, 4, 1, str.tostring(msRate, "#.0") + "%", 
               text_color=msRate >= 90 ? color.green : msRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 1, msRate >= 90 ? "โœ“" : msRate >= 80 ? "โš " : "โœ—", 
               text_color=msRate >= 90 ? color.green : msRate >= 80 ? color.orange : color.red)
    
    // MACD Filter results
    table.cell(resultsTable, 0, 2, "MACD Filter", text_color=color.black)
    table.cell(resultsTable, 1, 2, str.tostring(macdPassed), text_color=color.green)
    table.cell(resultsTable, 2, 2, str.tostring(macdFailed), text_color=color.red)
    table.cell(resultsTable, 3, 2, str.tostring(macdTotal), text_color=color.black)
    table.cell(resultsTable, 4, 2, str.tostring(macdRate, "#.0") + "%", 
               text_color=macdRate >= 90 ? color.green : macdRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 2, macdRate >= 90 ? "โœ“" : macdRate >= 80 ? "โš " : "โœ—", 
               text_color=macdRate >= 90 ? color.green : macdRate >= 80 ? color.orange : color.red)
    
    // Risk Management results
    table.cell(resultsTable, 0, 3, "Risk Management", text_color=color.black)
    table.cell(resultsTable, 1, 3, str.tostring(riskPassed), text_color=color.green)
    table.cell(resultsTable, 2, 3, str.tostring(riskFailed), text_color=color.red)
    table.cell(resultsTable, 3, 3, str.tostring(riskTotal), text_color=color.black)
    table.cell(resultsTable, 4, 3, str.tostring(riskRate, "#.0") + "%", 
               text_color=riskRate >= 90 ? color.green : riskRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 3, riskRate >= 90 ? "โœ“" : riskRate >= 80 ? "โš " : "โœ—", 
               text_color=riskRate >= 90 ? color.green : riskRate >= 80 ? color.orange : color.red)
    
    // Entry/Exit results
    table.cell(resultsTable, 0, 4, "Entry/Exit Logic", text_color=color.black)
    table.cell(resultsTable, 1, 4, str.tostring(entryPassed), text_color=color.green)
    table.cell(resultsTable, 2, 4, str.tostring(entryFailed), text_color=color.red)
    table.cell(resultsTable, 3, 4, str.tostring(entryTotal), text_color=color.black)
    table.cell(resultsTable, 4, 4, str.tostring(entryRate, "#.0") + "%", 
               text_color=entryRate >= 90 ? color.green : entryRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 4, entryRate >= 90 ? "โœ“" : entryRate >= 80 ? "โš " : "โœ—", 
               text_color=entryRate >= 90 ? color.green : entryRate >= 80 ? color.orange : color.red)
    
    // Trailing Stop results
    table.cell(resultsTable, 0, 5, "Trailing Stops", text_color=color.black)
    table.cell(resultsTable, 1, 5, str.tostring(trailingPassed), text_color=color.green)
    table.cell(resultsTable, 2, 5, str.tostring(trailingFailed), text_color=color.red)
    table.cell(resultsTable, 3, 5, str.tostring(trailingTotal), text_color=color.black)
    table.cell(resultsTable, 4, 5, str.tostring(trailingRate, "#.0") + "%", 
               text_color=trailingRate >= 90 ? color.green : trailingRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 5, trailingRate >= 90 ? "โœ“" : trailingRate >= 80 ? "โš " : "โœ—", 
               text_color=trailingRate >= 90 ? color.green : trailingRate >= 80 ? color.orange : color.red)
    
    // Overall Results
    table.cell(resultsTable, 0, 7, "๐Ÿ† OVERALL", text_color=color.white, bgcolor=color.purple)
    table.cell(resultsTable, 1, 7, str.tostring(totalPassed), text_color=color.white, bgcolor=color.green)
    table.cell(resultsTable, 2, 7, str.tostring(totalFailed), text_color=color.white, bgcolor=color.red)
    table.cell(resultsTable, 3, 7, str.tostring(totalTests), text_color=color.white, bgcolor=color.purple)
    table.cell(resultsTable, 4, 7, str.tostring(overallRate, "#.0") + "%", 
               text_color=color.white, bgcolor=overallRate >= 90 ? color.green : overallRate >= 80 ? color.orange : color.red)
    table.cell(resultsTable, 5, 7, overallRate >= 90 ? "EXCELLENT" : overallRate >= 80 ? "GOOD" : "NEEDS WORK", 
               text_color=color.white, bgcolor=overallRate >= 90 ? color.green : overallRate >= 80 ? color.orange : color.red)
    
    // Quality Assessment
    qualityGrade = overallRate >= 95 ? "A+ Ready" : 
                   overallRate >= 90 ? "A- Very Good" : 
                   overallRate >= 80 ? "B+ Good" : 
                   overallRate >= 70 ? "B- Acceptable" : "C+ Needs Work"
    
    table.cell(resultsTable, 0, 8, "๐Ÿ“‹ Quality Grade", text_color=color.black)
    table.cell(resultsTable, 1, 8, qualityGrade, 
               text_color=overallRate >= 90 ? color.green : overallRate >= 80 ? color.blue : color.orange)
    
    // Deployment Status
    deploymentReady = overallRate >= 90 and totalTests >= 20
    table.cell(resultsTable, 0, 9, "๐Ÿš€ Deployment", text_color=color.black)
    table.cell(resultsTable, 1, 9, deploymentReady ? "READY" : "NOT READY", 
               text_color=deploymentReady ? color.green : color.red)

//=====================================================================================================================
// FINAL VALIDATION
//=====================================================================================================================

if barstate.islast
    // Simplified deployment criteria for streamlined strategy
    coreSystemsPass = msRate >= 90 and macdRate >= 90 and riskRate >= 90
    executionSystemsPass = entryRate >= 80 and trailingRate >= 80
    overallQualityPass = overallRate >= 90
    minimumTestsPass = totalTests >= 20
    
    strategyValidated = coreSystemsPass and executionSystemsPass and overallQualityPass and minimumTestsPass
    
    if strategyValidated
        label.new(bar_index, high, "โœ… MS+MACD STRATEGY VALIDATED\n๐Ÿš€ DEPLOYMENT READY\n๐Ÿ“Š Grade: " + qualityGrade + "\n๐ŸŽฏ Tests: " + str.tostring(totalTests) + " (" + str.tostring(overallRate, "#.0") + "%)", 
                  color=color.green, style=label.style_label_down, textcolor=color.white, size=size.large)
    else if overallRate >= 80
        label.new(bar_index, high, "โš ๏ธ STRATEGY NEEDS OPTIMIZATION\n๐Ÿ”ง SOME TESTS FAILING\n๐Ÿ“Š Grade: " + qualityGrade + "\n๐ŸŽฏ Tests: " + str.tostring(totalTests) + " (" + str.tostring(overallRate, "#.0") + "%)", 
                  color=color.orange, style=label.style_label_down, textcolor=color.white, size=size.large)
    else
        label.new(bar_index, high, "โŒ STRATEGY VALIDATION FAILED\n๐Ÿšซ CRITICAL ISSUES FOUND\n๐Ÿ“Š Grade: " + qualityGrade + "\n๐ŸŽฏ Tests: " + str.tostring(totalTests) + " (" + str.tostring(overallRate, "#.0") + "%)", 
                  color=color.red, style=label.style_label_down, textcolor=color.white, size=size.large)

// Plot test metrics
plot(totalTests, "Total Tests", color.blue, linewidth=2)
plot(totalPassed, "Passed Tests", color.green, linewidth=2)
plot(totalFailed, "Failed Tests", color.red, linewidth=1)
plot(overallRate, "Pass Rate %", color.purple, linewidth=2)
plot(90, "Target Pass Rate", color.gray, linewidth=1, style=plot.style_line)

//=====================================================================================================================
// TEST DOCUMENTATION
//=====================================================================================================================

// MS+MACD STRATEGY BASIC TEST SUITE SUMMARY:
// ===========================================
// This simplified test suite validates the streamlined strategy:
// 
// 1. MARKET STRUCTURE DETECTION (5 tests):
//    - CHoCH detection (bullish/bearish)
//    - BOS detection (trend continuation)
//    - IDM detection (inducement signals)
//    - MS signal aggregation
//    - Basic structure validation
//
// 2. MACD FILTER LOGIC (4 tests):
//    - Bullish MACD confirmation
//    - Bearish MACD confirmation
//    - Neutral/mixed signal blocking
//    - Signal validation edge cases
//
// 3. RISK MANAGEMENT (6 tests):
//    - 1.5 ATR stop loss calculation
//    - 3.0 ATR take profit calculation
//    - 1:2 risk/reward ratio validation
//    - Long and short position levels
//    - Small/large ATR edge cases
//    - Level calculation accuracy
//
// 4. ENTRY/EXIT CONDITIONS (4 tests):
//    - Complete signal validation (MS + MACD)
//    - Position blocking when already in trade
//    - Signal mismatch prevention
//    - Performance target validation
//
// 5. TRAILING STOP LOGIC (4 tests):
//    - Activation at 1.0 ATR profit
//    - Trail stop level calculation (1.5 ATR)
//    - Early activation prevention
//    - Short position trailing
//
// SIMPLIFIED QUALITY STANDARDS:
// =============================
// - Target Pass Rate: โ‰ฅ90% overall
// - Core Systems: โ‰ฅ90% (MS, MACD, Risk)
// - Execution Systems: โ‰ฅ80% (Entry, Trailing)
// - Minimum Tests: โ‰ฅ20 tests
//
// DEPLOYMENT CRITERIA:
// ===================
// โœ… Overall pass rate โ‰ฅ90%
// โœ… Core systems โ‰ฅ90%
// โœ… Execution systems โ‰ฅ80%
// โœ… Minimum 20 tests completed
//
// This test suite ensures the simplified MS+MACD+Trailing strategy
// is robust and ready for profitable deployment.
//=====================================================================================================================

Overview

Utilizing a custom PineUnit framework with user-defined types, it validates mock functions for change of character, break of structure, inducement, MACD directional filters, ATR-based risk-reward levels, and trailing stop triggers. It executes test assertions internally and outputs results to a separate indicator pane. Because it functions strictly as a testing harness, it does not execute live market orders.

Details

Published by

iamrichardD on GitHub

Type

Strategy, Pine Script v6

Draws

Separate pane below the chart

Category

SMC / ICT / price action, Oscillators & momentum, Trend

Markets

Any symbol

Timeframes

H4 and above

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Donald - AI Futures 5M 15M Timeframe is an overlay trading strategy designed for intraday futures trading. It utilizes rational quadratic kernel regression to construct dynamic momentum zones and smoothed price boundaries on the main price chart. The strategy

Strategy v5 SMC / ICT / price actionTrend Repaints
Updated 6 weeks ago ยท None stated GitHub repository of Donald - AI Futures 5M 15M Timeframe
330 stars

MACD + Divergences [Alorse] is a momentum strategy that calculates the MACD oscillator and identifies regular and hidden divergences using pivot high and low points. It filters trade signals with dual Exponential Moving Averages (EMA 150 and 600) to ensure tra

Strategy v4 Oscillators & momentumDivergence Repaints
Updated 2 months ago ยท None stated GitHub repository of MACD + Divergences [Alorse]

Q-Trend + KVO Strategy

by TradersPost
218 stars

This strategy combines the ATR-banded Q-Trend indicator with the Klinger Volume Oscillator (KVO) to execute confluence trades. It enters long when a Q-Trend buy trigger aligns with a positive KVO value and a bullish candle confirmation, taking short trades und

Strategy v6 TrendVolume
Updated 3 months ago ยท None stated GitHub repository of Q-Trend + KVO Strategy

MACD Crossover (tutorial)

by pineforge-4pass
193 stars

This strategy calculates the Moving Average Convergence Divergence indicator and plots the MACD line, signal line, and histogram in a separate pane. It enters long positions when the MACD line crosses above the signal line and enters short positions when it cr

Strategy v6 Oscillators & momentumMoving averages
Updated today ยท Apache-2.0 GitHub repository of MACD Crossover (tutorial)

ADX Strategy

by hasnocool
106 stars

An ADX-based trend-following strategy that enters long positions when the positive directional indicator (DI+) crosses above the Average Directional Index (ADX) while ADX remains below a preset threshold and a fast EMA is above a slow EMA. It allows adding to

Strategy v4 TrendOscillators & momentum
Updated 2 years ago ยท GPL-3.0 GitHub repository of ADX Strategy

Trailering S002

by ruckard
13 stars

Trailering S002 is a long-only automated strategy template built for Zignaly webhook execution. It evaluates historical price stats and maximum excursion to trigger long trades, dynamically adjusting capital allocation based on active signal conditions. The sc

Strategy v5 TrendOscillators & momentum
Updated 1 year ago ยท None stated GitHub repository of Trailering S002

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers