ajiim

🎁

Oct 9th, 2026
478
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 61.97 KB | None | 0 0
  1. //@version=6
  2. indicator("Smart Signals Assistant", shorttitle = "AlgoAlpha - 🧠 Smart Signals 2.0", overlay = true, max_labels_count = 500, max_lines_count = 500, max_boxes_count = 500)
  3.  
  4. string G_DASH = "Master Dashboard"
  5. string G_SS = "Smart Signals"
  6. string G_OPT = "Smart Signals Optimization Engine"
  7. string G_FVT = "Fair Value Trail"
  8. string G_SP = "Trend Spine"
  9. string G_TB = "Trend Bias"
  10. string G_FC = "Firmament Clouds"
  11. string G_TRC = "Trend-Range Classifier"
  12. string G_TPSL = "Take-Profit / Stop-Loss"
  13. string G_APP = "Appearance"
  14. string G_TBL = "Component Table"
  15. string G_ALR = "Alerts"
  16. string G_SEQ = "Alert Sequence"
  17. string G_FLT = "Alert State Filters"
  18. string G_EXT = "External Sources"
  19.  
  20. string H_SHORT = "Short Term"
  21. string H_MEDIUM = "Medium Term"
  22. string H_LONG = "Long Term"
  23.  
  24. string P_TR = "Top Right"
  25. string P_TC = "Top Center"
  26. string P_TL = "Top Left"
  27. string P_MR = "Middle Right"
  28. string P_MC = "Middle Center"
  29. string P_ML = "Middle Left"
  30. string P_BR = "Bottom Right"
  31. string P_BC = "Bottom Center"
  32. string P_BL = "Bottom Left"
  33.  
  34. string C_NONE = "None"
  35. string T01 = "Smart Signals Bullish Signal [Trigger]"
  36. string T02 = "Smart Signals Bearish Signal [Trigger]"
  37. string T03 = "Smart Signals Normal Bullish Signal [Trigger]"
  38. string T04 = "Smart Signals Normal Bearish Signal [Trigger]"
  39. string T05 = "Smart Signals Strong Bullish Signal [Trigger]"
  40. string T06 = "Smart Signals Strong Bearish Signal [Trigger]"
  41. string T07 = "Bullish Exit Signal [Trigger]"
  42. string T08 = "Bearish Exit Signal [Trigger]"
  43. string T09 = "Take-Profit 1 Hit [Trigger]"
  44. string T10 = "Take-Profit 2 Hit [Trigger]"
  45. string T11 = "Take-Profit 3 Hit [Trigger]"
  46. string T12 = "Take-Profit 4 Hit [Trigger]"
  47. string T13 = "Take-Profit 5 Hit [Trigger]"
  48. string T14 = "Stop-Loss Hit [Trigger]"
  49. string T15 = "FVT Turns Bullish [Trigger]"
  50. string T16 = "FVT Turns Bearish [Trigger]"
  51. string T17 = "Optimal Bullish Entry [Trigger]"
  52. string T18 = "Optimal Bearish Entry [Trigger]"
  53. string T19 = "Trend Spine Turns Bullish [Trigger]"
  54. string T20 = "Trend Spine Turns Bearish [Trigger]"
  55. string T21 = "Trend Bias Turns Bullish [Trigger]"
  56. string T22 = "Trend Bias Turns Bearish [Trigger]"
  57. string T23 = "Trend Bias Strengthens [Trigger]"
  58. string T24 = "Trend Bias Weakens [Trigger]"
  59. string T25 = "Price Enters Upper Cloud [Trigger]"
  60. string T26 = "Price Enters Lower Cloud [Trigger]"
  61. string T27 = "Price Exits Clouds [Trigger]"
  62. string T28 = "Market Starts Trending [Trigger]"
  63. string T29 = "Market Starts Ranging [Trigger]"
  64. string T30 = "External Source 1 Signal [Trigger]"
  65. string T31 = "External Source 2 Signal [Trigger]"
  66. string T32 = "External Source 3 Signal [Trigger]"
  67. string T33 = "External Source 4 Signal [Trigger]"
  68. string T34 = "External Source 5 Signal [Trigger]"
  69.  
  70. string S01 = "Smart Signals In Bullish Trend [State]"
  71. string S02 = "Smart Signals In Bearish Trend [State]"
  72. string S03 = "FVT In Bullish Trend [State]"
  73. string S04 = "FVT In Bearish Trend [State]"
  74. string S05 = "Trend Spine Bullish [State]"
  75. string S06 = "Trend Spine Bearish [State]"
  76. string S07 = "Trend Bias Bullish [State]"
  77. string S08 = "Trend Bias Bearish [State]"
  78. string S09 = "Trend Bias Strong [State]"
  79. string S10 = "Trend Bias Weak [State]"
  80. string S11 = "Price In Upper Cloud [State]"
  81. string S12 = "Price In Lower Cloud [State]"
  82. string S13 = "Price Between Clouds [State]"
  83. string S14 = "Market Is Trending [State]"
  84. string S15 = "Market Is Ranging [State]"
  85. string S16 = "External Source 1 Active [State]"
  86. string S17 = "External Source 2 Active [State]"
  87. string S18 = "External Source 3 Active [State]"
  88. string S19 = "External Source 4 Active [State]"
  89. string S20 = "External Source 5 Active [State]"
  90.  
  91. int OPT_N = 8
  92. int OPT_BASE = 3
  93. int N_TRIG = 34
  94. float SWING_MULT = 1.3
  95. float SCALP_MULT = 3.0
  96. float STRONG_OSC = 1.75
  97. float FVT_MULT = 1.5
  98. float SPINE_ER = 0.15
  99. float TB_BAND = 0.30
  100. float FC_INNER = 2.0
  101. float FC_OUTER = 3.0
  102. int ML_TRAIN = 100
  103. int ML_ITER = 2
  104. int TRC_K = 8
  105. float TRC_THR = 0.30
  106. int TPSL_EXT = 20
  107. int EXIT_COOL = 3
  108. float EXIT_OB = 70.0
  109. float EXIT_OS = 30.0
  110.  
  111. color TBL_BG = #131722
  112. color TBL_HEAD = #1e222d
  113. color TBL_BORDER = #363a45
  114. color TXT_MAIN = #d1d4dc
  115. color TXT_DIM = #4a4e5a
  116. color TXT_DARK = #0b0e14
  117.  
  118. bool showSS = input.bool(true, "Smart Signals", inline = "d1", group = G_DASH)
  119. bool showFVT = input.bool(true, "Fair Value Trail", inline = "d1", group = G_DASH)
  120. bool showSpine = input.bool(false, "Trend Spine", inline = "d2", group = G_DASH)
  121. bool showBias = input.bool(false, "Trend Bias", inline = "d2", group = G_DASH)
  122. bool showClouds = input.bool(false, "Firmament Clouds", inline = "d3", group = G_DASH)
  123. bool showTRC = input.bool(false, "Trend-Range Classifier", inline = "d3", group = G_DASH)
  124. bool showTP = input.bool(false, "Take-Profit Levels", inline = "d4", group = G_DASH)
  125. bool showSL = input.bool(false, "Stop-Loss Level", inline = "d4", group = G_DASH)
  126. bool showExit = input.bool(true, "Exit Signals", inline = "d5", group = G_DASH)
  127. bool showOpt = input.bool(true, "Optimal Entry Signals", inline = "d5", group = G_DASH)
  128. bool showTable = input.bool(true, "Component Table", inline = "d6", group = G_DASH)
  129.  
  130. string ssMode = input.string("Swing", "Smart Signals Mode", options = ["Swing", "Scalping"], group = G_SS, tooltip = "Swing: proprietary model analysing price stability and volatility to identify stable, longer-term trends.\nScalping: responsive machine-learning trend system that adapts its parameters to learned market states.")
  131. string sigMode = input.string("Trend", "Signal Mode", options = ["Trend", "Reversal"], group = G_SS, tooltip = "Trend: trend-following signals.\nReversal: potential counter-trend reversal signals.")
  132. string ssHorizon = input.string(H_MEDIUM, "Time Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_SS, tooltip = "Controls the base length of the Smart Signals engine.")
  133.  
  134. bool autoOpt = input.bool(false, "Auto-Optimize Length", group = G_OPT, tooltip = "When enabled, the engine continuously tests 8 candidate lengths and uses the best performing one (walk-forward, no lookahead).")
  135. string optMetric = input.string("Net Profit", "Optimize By", options = ["Win Rate", "Net Profit", "Balanced"], group = G_OPT)
  136. int optMinTrades = input.int(5, "Minimum Trades", minval = 1, group = G_OPT, tooltip = "Minimum closed trades a candidate needs before it can be selected.")
  137. bool showOptTbl = input.bool(false, "Show Performance Table", group = G_OPT)
  138. string optTblPos = input.string(P_TR, "Performance Table Position", options = [P_TR, P_TC, P_TL, P_MR, P_MC, P_ML, P_BR, P_BC, P_BL], group = G_OPT)
  139.  
  140. string fvtHorizon = input.string(H_MEDIUM, "Time Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_FVT)
  141. float fvtWidth = input.float(1.0, "Trail Width", minval = 0.1, maxval = 5.0, step = 0.1, group = G_FVT, tooltip = "Thickness of the Fair Value Trail cloud (volatility multiple).")
  142.  
  143. string spHorizon = input.string(H_MEDIUM, "Time Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_SP)
  144.  
  145. string tbHorizon = input.string(H_MEDIUM, "Time Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_TB)
  146.  
  147. string fcHorizon = input.string(H_MEDIUM, "Time Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_FC)
  148.  
  149. string trcHorizon = input.string(H_MEDIUM, "Classification Horizon", options = [H_SHORT, H_MEDIUM, H_LONG], group = G_TRC)
  150. int trcMem = input.int(200, "Classification Memory", minval = 50, maxval = 2000, step = 50, group = G_TRC, tooltip = "Number of past samples the classifier keeps in memory. Higher = more robust but slower to compile.")
  151.  
  152. string tpslMode = input.string("Volatility", "TP/SL Distance Mode", options = ["Volatility", "Percentage"], group = G_TPSL)
  153. int tpTargets = input.int(3, "Take-Profit Targets", minval = 1, maxval = 5, group = G_TPSL)
  154. float tpMult = input.float(2.0, "TP Multiplier", minval = 0.1, step = 0.1, inline = "tpv", group = G_TPSL)
  155. float slMult = input.float(1.5, "SL Multiplier", minval = 0.1, step = 0.1, inline = "tpv", group = G_TPSL)
  156. float tpPct = input.float(1.0, "TP Distance %", minval = 0.01, step = 0.05, inline = "tpp", group = G_TPSL)
  157. float slPct = input.float(0.75, "SL Distance %", minval = 0.01, step = 0.05, inline = "tpp", group = G_TPSL)
  158.  
  159. string candleMode = input.string("Trend", "Candle Coloring", options = ["Trend", "Trend Gradient", "Volume Gradient", "None"], group = G_APP)
  160. bool detectRange = input.bool(true, "Detect Ranging Candles", group = G_APP, tooltip = "Colors candles neutral when the market is ranging (uses the Trend-Range Classifier when enabled).")
  161. color bullCol = input.color(#00ffbb, "Bullish", inline = "c1", group = G_APP)
  162. color bearCol = input.color(#ff1100, "Bearish", inline = "c1", group = G_APP)
  163. color neutCol = input.color(#787b86, "Neutral", inline = "c1", group = G_APP)
  164. color exitCol = input.color(#ff9800, "Exit Signals", inline = "c2", group = G_APP)
  165. color alertCol = input.color(#ffd600, "Historical Alerts", inline = "c2", group = G_APP)
  166.  
  167. string tblPos = input.string(P_BR, "Table Position", options = [P_TR, P_TC, P_TL, P_MR, P_MC, P_ML, P_BR, P_BC, P_BL], group = G_TBL)
  168. string tblSize = input.string("Small", "Table Size", options = ["Tiny", "Small", "Normal", "Large", "Huge"], group = G_TBL)
  169.  
  170. bool showHistAlerts = input.bool(false, "Show Historical Alerts", group = G_ALR, tooltip = "Marks every bar where the custom alert sequence would have fired and shows the Alert Logic table.")
  171. string alertFreqIn = input.string("Once Per Bar Close", "Alert Frequency", options = ["Once Per Bar", "Once Per Bar Close", "All"], group = G_ALR)
  172. string alertMsgIn = input.text_area("Smart Signals Alert: {{event}} | {{ticker}} ({{interval}}) @ {{close}}", "Custom Alert Message", group = G_ALR, tooltip = "Supported tags: {{event}}, {{ticker}}, {{exchange}}, {{interval}}, {{open}}, {{high}}, {{low}}, {{close}}, {{volume}}, {{time}}")
  173. int stepTimeout = input.int(50, "Max Bars Between Steps", minval = 0, group = G_ALR, tooltip = "Resets the sequence if the next step does not occur within this many bars. 0 = no limit.")
  174. bool universalAlerts = input.bool(false, "Enable Universal Alerts", group = G_ALR, tooltip = "Fires one alert() call per bar listing every built-in trigger that occurred. Create the alert with 'Any alert() function call'.")
  175.  
  176. string a1c1 = input.string(C_NONE, "Step 1", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  177. string a1op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a1", group = G_SEQ)
  178. string a1c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a1", group = G_SEQ)
  179. string a2c1 = input.string(C_NONE, "Step 2", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  180. string a2op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a2", group = G_SEQ)
  181. string a2c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a2", group = G_SEQ)
  182. string a3c1 = input.string(C_NONE, "Step 3", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  183. string a3op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a3", group = G_SEQ)
  184. string a3c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a3", group = G_SEQ)
  185. string a4c1 = input.string(C_NONE, "Step 4", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  186. string a4op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a4", group = G_SEQ)
  187. string a4c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a4", group = G_SEQ)
  188. string a5c1 = input.string(C_NONE, "Step 5", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  189. string a5op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a5", group = G_SEQ)
  190. string a5c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a5", group = G_SEQ)
  191. string a6c1 = input.string(C_NONE, "Step 6", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  192. string a6op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a6", group = G_SEQ)
  193. string a6c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a6", group = G_SEQ)
  194. string a7c1 = input.string(C_NONE, "Step 7", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_SEQ)
  195. string a7op = input.string("AND", " Logic", options = ["AND", "OR"], inline = "a7", group = G_SEQ)
  196. string a7c2 = input.string(C_NONE, "", options = [C_NONE, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], inline = "a7", group = G_SEQ)
  197.  
  198. string f1c = input.string(C_NONE, "State Filter 1", options = [C_NONE, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_FLT)
  199. string f2c = input.string(C_NONE, "State Filter 2", options = [C_NONE, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_FLT)
  200. string f3c = input.string(C_NONE, "State Filter 3", options = [C_NONE, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_FLT)
  201. string f4c = input.string(C_NONE, "State Filter 4", options = [C_NONE, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_FLT)
  202. string f5c = input.string(C_NONE, "State Filter 5", options = [C_NONE, S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20], group = G_FLT)
  203.  
  204. float ext1 = input.source(close, "External Source 1", group = G_EXT)
  205. float ext2 = input.source(close, "External Source 2", group = G_EXT)
  206. float ext3 = input.source(close, "External Source 3", group = G_EXT)
  207. float ext4 = input.source(close, "External Source 4", group = G_EXT)
  208. float ext5 = input.source(close, "External Source 5", group = G_EXT)
  209.  
  210. int ssBaseLen = ssMode == "Swing" ? (ssHorizon == H_SHORT ? 60 : ssHorizon == H_MEDIUM ? 120 : 200) : (ssHorizon == H_SHORT ? 6 : ssHorizon == H_MEDIUM ? 10 : 16)
  211. int L0 = math.max(2, math.round(ssBaseLen * 0.50))
  212. int L1 = math.max(2, math.round(ssBaseLen * 0.65))
  213. int L2 = math.max(2, math.round(ssBaseLen * 0.80))
  214. int L3 = math.max(2, ssBaseLen)
  215. int L4 = math.max(2, math.round(ssBaseLen * 1.20))
  216. int L5 = math.max(2, math.round(ssBaseLen * 1.45))
  217. int L6 = math.max(2, math.round(ssBaseLen * 1.70))
  218. int L7 = math.max(2, math.round(ssBaseLen * 2.00))
  219. int fvtLen = fvtHorizon == H_SHORT ? 20 : fvtHorizon == H_MEDIUM ? 50 : 100
  220. int spLen = spHorizon == H_SHORT ? 20 : spHorizon == H_MEDIUM ? 50 : 100
  221. int tbLen = tbHorizon == H_SHORT ? 20 : tbHorizon == H_MEDIUM ? 50 : 100
  222. int fcLen = fcHorizon == H_SHORT ? 50 : fcHorizon == H_MEDIUM ? 100 : 200
  223. int trcH = trcHorizon == H_SHORT ? 10 : trcHorizon == H_MEDIUM ? 20 : 40
  224.  
  225. type DurationTracker
  226. int lastState = 0
  227. int lastChangeBar = na
  228. bool started = false
  229. float sumDur = 0.0
  230. int count = 0
  231.  
  232. method update(DurationTracker this, int state) =>
  233. if na(this.lastChangeBar)
  234. this.lastChangeBar := bar_index
  235. this.lastState := state
  236. else if state != this.lastState
  237. if this.started
  238. this.sumDur := this.sumDur + (bar_index - this.lastChangeBar)
  239. this.count := this.count + 1
  240. this.started := true
  241. this.lastChangeBar := bar_index
  242. this.lastState := state
  243. this
  244.  
  245. method avgDur(DurationTracker this) =>
  246. this.count > 0 ? this.sumDur / this.count : na
  247.  
  248. method curDur(DurationTracker this) =>
  249. na(this.lastChangeBar) ? na : bar_index - this.lastChangeBar
  250.  
  251. type PerfTracker
  252. int length = 0
  253. int pos = 0
  254. float entry = na
  255. int trades = 0
  256. int wins = 0
  257. float netProfit = 0.0
  258. float grossWin = 0.0
  259. float grossLoss = 0.0
  260.  
  261. method onSignal(PerfTracker this, int dir, float price) =>
  262. if dir != this.pos
  263. if this.pos != 0 and not na(this.entry) and this.entry > 0
  264. float pnl = this.pos == 1 ? (price - this.entry) / this.entry * 100.0 : (this.entry - price) / this.entry * 100.0
  265. this.trades := this.trades + 1
  266. this.netProfit := this.netProfit + pnl
  267. if pnl > 0
  268. this.wins := this.wins + 1
  269. this.grossWin := this.grossWin + pnl
  270. else
  271. this.grossLoss := this.grossLoss + math.abs(pnl)
  272. this.pos := dir
  273. this.entry := price
  274. this
  275.  
  276. method feed(PerfTracker this, bool bullSig, bool bearSig) =>
  277. if bullSig
  278. this.onSignal(1, close)
  279. else if bearSig
  280. this.onSignal(-1, close)
  281. this
  282.  
  283. method winRate(PerfTracker this) =>
  284. this.trades > 0 ? float(this.wins) / this.trades * 100.0 : 0.0
  285.  
  286. method profitFactor(PerfTracker this) =>
  287. this.grossLoss > 0 ? this.grossWin / this.grossLoss : na
  288.  
  289. f_er(float src, int len) =>
  290. float chg = math.abs(src - src[len])
  291. float noise = math.sum(math.abs(ta.change(src)), len)
  292. noise > 0 ? chg / noise : 0.0
  293.  
  294. f_trail(float src, float vol, float mult) =>
  295. float up = src - mult * vol
  296. float dn = src + mult * vol
  297. var float upT = na
  298. var float dnT = na
  299. var int dir = 1
  300. float prevUp = nz(upT, up)
  301. float prevDn = nz(dnT, dn)
  302. upT := close[1] > prevUp ? math.max(up, prevUp) : up
  303. dnT := close[1] < prevDn ? math.min(dn, prevDn) : dn
  304. if dir == 1 and close < prevUp
  305. dir := -1
  306. else if dir == -1 and close > prevDn
  307. dir := 1
  308. float lineOut = dir == 1 ? upT : dnT
  309. [lineOut, dir, upT, dnT]
  310.  
  311. f_engine(simple int len, float stateRatio) =>
  312. int halfLen = math.max(2, int(len / 2))
  313. float rng = math.max(high - low, syminfo.mintick)
  314. float w = 1.0 / rng
  315. float sumW = math.sum(w, len)
  316. float sumCW = math.sum(close * w, len)
  317. float swBase = sumW > 0 ? sumCW / sumW : close
  318. float atrLen = ta.atr(len)
  319. [swLine, swDir, swUp, swDn] = f_trail(swBase, atrLen, SWING_MULT)
  320. float scVol = atrLen * stateRatio
  321. [scLine, scDir, scUp, scDn] = f_trail(hl2, scVol, SCALP_MULT)
  322. float scBase = ta.ema(hl2, len)
  323. bool isSwing = ssMode == "Swing"
  324. int tDir = isSwing ? swDir : scDir
  325. float base = isSwing ? swBase : scBase
  326. float vol = isSwing ? atrLen : scVol
  327. float mult = isSwing ? SWING_MULT : SCALP_MULT
  328. int tDirPrev = nz(tDir[1], tDir)
  329. bool tBull = tDir == 1 and tDirPrev == -1
  330. bool tBear = tDir == -1 and tDirPrev == 1
  331. float osc = vol > 0 ? (close - base) / (vol * mult) : 0.0
  332. bool rBull = ta.crossover(osc, -1.0)
  333. bool rBear = ta.crossunder(osc, 1.0)
  334. float oscLo = ta.lowest(osc, halfLen)
  335. float oscHi = ta.highest(osc, halfLen)
  336. float longBase = ta.ema(close, len * 2)
  337. float avgVol = ta.sma(volume, len)
  338. float relVol = avgVol > 0 ? volume / avgVol : 1.0
  339. float erv = f_er(close, halfLen)
  340. float mom = close - close[halfLen]
  341. int bullScore = (close > longBase ? 1 : 0) + (nz(relVol, 1.0) > 1.0 ? 1 : 0) + (mom > 0 and nz(erv) > 0.2 ? 1 : 0)
  342. int bearScore = (close < longBase ? 1 : 0) + (nz(relVol, 1.0) > 1.0 ? 1 : 0) + (mom < 0 and nz(erv) > 0.2 ? 1 : 0)
  343. bool isTrendMode = sigMode == "Trend"
  344. bool bullSig = isTrendMode ? tBull : rBull
  345. bool bearSig = isTrendMode ? tBear : rBear
  346. bool strongBull = bullSig and (isTrendMode ? bullScore >= 2 : oscLo <= -STRONG_OSC)
  347. bool strongBear = bearSig and (isTrendMode ? bearScore >= 2 : oscHi >= STRONG_OSC)
  348. var int revState = 0
  349. revState := bullSig ? 1 : bearSig ? -1 : revState
  350. int state = isTrendMode ? tDir : revState
  351. [state, bullSig, bearSig, strongBull, strongBear]
  352.  
  353. f_pickI(int i, int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) =>
  354. switch i
  355. 0 => a0
  356. 1 => a1
  357. 2 => a2
  358. 3 => a3
  359. 4 => a4
  360. 5 => a5
  361. 6 => a6
  362. => a7
  363.  
  364. f_pickB(int i, bool a0, bool a1, bool a2, bool a3, bool a4, bool a5, bool a6, bool a7) =>
  365. switch i
  366. 0 => a0
  367. 1 => a1
  368. 2 => a2
  369. 3 => a3
  370. 4 => a4
  371. 5 => a5
  372. 6 => a6
  373. => a7
  374.  
  375. f_pos(string p) =>
  376. switch p
  377. "Top Right" => position.top_right
  378. "Top Center" => position.top_center
  379. "Top Left" => position.top_left
  380. "Middle Right" => position.middle_right
  381. "Middle Center" => position.middle_center
  382. "Middle Left" => position.middle_left
  383. "Bottom Right" => position.bottom_right
  384. "Bottom Center" => position.bottom_center
  385. => position.bottom_left
  386.  
  387. f_size(string s) =>
  388. switch s
  389. "Tiny" => size.tiny
  390. "Small" => size.small
  391. "Normal" => size.normal
  392. "Large" => size.large
  393. => size.huge
  394.  
  395. f_cond(array<string> names, array<bool> vals, string c) =>
  396. int idx = names.indexof(c)
  397. bool r = false
  398. if idx >= 0
  399. r := vals.get(idx)
  400. r
  401.  
  402. f_step(array<string> names, array<bool> vals, string c1, string op, string c2) =>
  403. bool r = false
  404. if c1 != C_NONE
  405. bool r1 = f_cond(names, vals, c1)
  406. if c2 == C_NONE
  407. r := r1
  408. else
  409. bool r2 = f_cond(names, vals, c2)
  410. r := op == "AND" ? r1 and r2 : r1 or r2
  411. r
  412.  
  413. f_condCol(string c) =>
  414. color col = TXT_MAIN
  415. if str.contains(c, "Bearish") or str.contains(c, "Stop-Loss")
  416. col := bearCol
  417. else if str.contains(c, "Bullish") or str.contains(c, "Take-Profit") or str.contains(c, "Trending") or str.contains(c, "Strong") or str.contains(c, "Strengthens") or str.contains(c, "Upper")
  418. col := bullCol
  419. else if str.contains(c, "Ranging") or str.contains(c, "Weak") or str.contains(c, "Lower")
  420. col := bearCol
  421. col
  422.  
  423. f_fmt(string m, string evt) =>
  424. string r = m
  425. r := str.replace_all(r, "{{ticker}}", syminfo.ticker)
  426. r := str.replace_all(r, "{{exchange}}", syminfo.prefix)
  427. r := str.replace_all(r, "{{interval}}", timeframe.period)
  428. r := str.replace_all(r, "{{open}}", str.tostring(open, format.mintick))
  429. r := str.replace_all(r, "{{high}}", str.tostring(high, format.mintick))
  430. r := str.replace_all(r, "{{low}}", str.tostring(low, format.mintick))
  431. r := str.replace_all(r, "{{close}}", str.tostring(close, format.mintick))
  432. r := str.replace_all(r, "{{volume}}", str.tostring(volume))
  433. r := str.replace_all(r, "{{time}}", str.format_time(time, "yyyy-MM-dd HH:mm", syminfo.timezone))
  434. r := str.replace_all(r, "{{event}}", evt)
  435. r
  436.  
  437. f_lvl(array<float> a, int i) =>
  438. float r = na
  439. if i < a.size()
  440. r := a.get(i)
  441. r
  442.  
  443. f_compRow(table t, int row, string name, bool enabled, int state, float avgD, int curD, bool isTRC, string sz) =>
  444. color nameCol = enabled ? TXT_MAIN : TXT_DIM
  445. string sigTxt = ""
  446. color sigBg = TBL_BG
  447. if enabled
  448. if isTRC
  449. sigTxt := state == 1 ? "📈" : "⚖️"
  450. sigBg := state == 1 ? color.new(bullCol, 20) : neutCol
  451. else
  452. sigTxt := state == 1 ? "▲" : state == -1 ? "▼" : ""
  453. sigBg := state == 1 ? bullCol : state == -1 ? bearCol : TBL_BG
  454. table.cell(t, 0, row, name, text_color = nameCol, text_size = sz, bgcolor = TBL_BG)
  455. table.cell(t, 1, row, sigTxt, text_color = color.white, text_size = sz, bgcolor = sigBg)
  456. table.cell(t, 2, row, enabled ? str.tostring(avgD, "#.0") : "NaN", text_color = nameCol, text_size = sz, bgcolor = TBL_BG)
  457. table.cell(t, 3, row, enabled ? str.tostring(curD) : "NaN", text_color = nameCol, text_size = sz, bgcolor = TBL_BG)
  458.  
  459. float atr14 = ta.atr(14)
  460. float atr50 = ta.atr(50)
  461. float rsi14 = ta.rsi(close, 14)
  462.  
  463. float mlVol = ta.atr(10)
  464. var array<float> mlWin = array.new_float()
  465. var float cLow = na
  466. var float cMid = na
  467. var float cHigh = na
  468. float stateRatio = 1.0
  469. int mlState = 1
  470. if not na(mlVol)
  471. mlWin.push(mlVol)
  472. if mlWin.size() > ML_TRAIN
  473. mlWin.shift()
  474. if mlWin.size() >= 20 and not na(mlVol) and mlVol > 0
  475. if na(cLow)
  476. cLow := mlWin.percentile_linear_interpolation(25)
  477. cMid := mlWin.percentile_linear_interpolation(50)
  478. cHigh := mlWin.percentile_linear_interpolation(75)
  479. for iter = 1 to ML_ITER
  480. float s0 = 0.0
  481. float s1 = 0.0
  482. float s2 = 0.0
  483. int n0 = 0
  484. int n1 = 0
  485. int n2 = 0
  486. for v in mlWin
  487. float d0 = math.abs(v - cLow)
  488. float d1 = math.abs(v - cMid)
  489. float d2 = math.abs(v - cHigh)
  490. if d0 <= d1 and d0 <= d2
  491. s0 += v
  492. n0 += 1
  493. else if d1 <= d2
  494. s1 += v
  495. n1 += 1
  496. else
  497. s2 += v
  498. n2 += 1
  499. cLow := n0 > 0 ? s0 / n0 : cLow
  500. cMid := n1 > 0 ? s1 / n1 : cMid
  501. cHigh := n2 > 0 ? s2 / n2 : cHigh
  502. float e0 = math.abs(mlVol - cLow)
  503. float e1 = math.abs(mlVol - cMid)
  504. float e2 = math.abs(mlVol - cHigh)
  505. mlState := e0 <= e1 and e0 <= e2 ? 0 : e1 <= e2 ? 1 : 2
  506. float centroid = mlState == 0 ? cLow : mlState == 1 ? cMid : cHigh
  507. stateRatio := math.max(0.5, math.min(2.0, centroid / mlVol))
  508.  
  509. [st0, bs0, br0, sb0, sr0] = f_engine(L0, stateRatio)
  510. [st1, bs1, br1, sb1, sr1] = f_engine(L1, stateRatio)
  511. [st2, bs2, br2, sb2, sr2] = f_engine(L2, stateRatio)
  512. [st3, bs3, br3, sb3, sr3] = f_engine(L3, stateRatio)
  513. [st4, bs4, br4, sb4, sr4] = f_engine(L4, stateRatio)
  514. [st5, bs5, br5, sb5, sr5] = f_engine(L5, stateRatio)
  515. [st6, bs6, br6, sb6, sr6] = f_engine(L6, stateRatio)
  516. [st7, bs7, br7, sb7, sr7] = f_engine(L7, stateRatio)
  517.  
  518. float fvtAvgVol = ta.sma(volume, fvtLen)
  519. bool fvtSigVol = na(volume) or na(fvtAvgVol) or fvtAvgVol <= 0 or volume > fvtAvgVol
  520. float fvtAlpha = 2.0 / (fvtLen * 0.25 + 1.0)
  521. var float fvLevel = na
  522. fvLevel := na(fvLevel) ? hlc3 : fvtSigVol ? fvLevel + fvtAlpha * (hlc3 - fvLevel) : fvLevel
  523. float fvtAtr = ta.atr(fvtLen)
  524. [fvtLine, fvtDir, fvtUpT, fvtDnT] = f_trail(fvLevel, fvtAtr, FVT_MULT)
  525. float fvtBand = nz(fvtAtr) * fvtWidth
  526. int fvtDirPrev = nz(fvtDir[1], fvtDir)
  527. float fvtBullL = showFVT and fvtDir == 1 ? fvtLine : na
  528. float fvtBullM = showFVT and fvtDir == 1 ? fvtLine + fvtBand * 0.5 : na
  529. float fvtBullO = showFVT and fvtDir == 1 ? fvtLine + fvtBand : na
  530. float fvtBearL = showFVT and fvtDir == -1 ? fvtLine : na
  531. float fvtBearM = showFVT and fvtDir == -1 ? fvtLine - fvtBand * 0.5 : na
  532. float fvtBearO = showFVT and fvtDir == -1 ? fvtLine - fvtBand : na
  533.  
  534. float spEr = nz(f_er(close, spLen))
  535. float spFast = 2.0 / 3.0
  536. float spSlow = 2.0 / (spLen + 1.0)
  537. float spSc = math.pow(spEr * (spFast - spSlow) + spSlow, 2)
  538. var float spine = na
  539. spine := na(spine) ? close : spEr >= SPINE_ER ? spine + spSc * (close - spine) : spine
  540. float spinePrev = nz(spine[1], spine)
  541. var int spDir = 0
  542. spDir := spine > spinePrev ? 1 : spine < spinePrev ? -1 : spDir
  543. int spDirPrev = nz(spDir[1], spDir)
  544.  
  545. float tbCenter = ta.ema(close, tbLen)
  546. float tbAtr = ta.atr(tbLen)
  547. float tbHalf = nz(tbAtr) * TB_BAND
  548. int tbMomLen = math.max(2, int(tbLen / 4))
  549. float tbMom = ta.ema(close - tbCenter, tbMomLen)
  550. float tbAvg = ta.sma(math.abs(tbMom), tbLen * 2)
  551. var int tbDir = 0
  552. tbDir := tbMom > 0 ? 1 : tbMom < 0 ? -1 : tbDir
  553. bool tbStrong = math.abs(nz(tbMom)) > nz(tbAvg)
  554. bool tbStrongPrev = tbStrong[1]
  555. int tbDirPrev = nz(tbDir[1], tbDir)
  556.  
  557. float fcBasis = ta.ema(hlc3, fcLen)
  558. float fcDevRaw = ta.stdev(close, fcLen)
  559. int fcSmLen = math.max(2, int(fcLen / 5))
  560. float fcDev = ta.ema(fcDevRaw, fcSmLen)
  561. float fcUI = fcBasis + fcDev * FC_INNER
  562. float fcUO = fcBasis + fcDev * FC_OUTER
  563. float fcLI = fcBasis - fcDev * FC_INNER
  564. float fcLO = fcBasis - fcDev * FC_OUTER
  565. int fcState = close > fcUI ? 1 : close < fcLI ? -1 : 0
  566. int fcStatePrev = nz(fcState[1], fcState)
  567.  
  568. [diPlus, diMinus, adxVal] = ta.dmi(14, 14)
  569. float trSum14 = math.sum(ta.tr(true), 14)
  570. float hh14 = ta.highest(high, 14)
  571. float ll14 = ta.lowest(low, 14)
  572. float rng14 = hh14 - ll14
  573. float chop = rng14 > 0 ? 100.0 * math.log10(trSum14 / rng14) / math.log10(14.0) : 50.0
  574. float er14 = f_er(close, 14)
  575. float tf1 = math.min(nz(adxVal) / 50.0, 2.0)
  576. float tf2 = nz(chop, 50.0) / 100.0
  577. float tf3 = nz(er14)
  578. float tf4 = atr50 > 0 ? math.min(atr14 / atr50, 3.0) / 2.0 : 0.5
  579. float tf5 = math.abs(nz(rsi14, 50.0) - 50.0) / 50.0
  580. float tf1Lag = nz(tf1[trcH])
  581. float tf2Lag = nz(tf2[trcH], 0.5)
  582. float tf3Lag = nz(tf3[trcH])
  583. float tf4Lag = nz(tf4[trcH], 0.5)
  584. float tf5Lag = nz(tf5[trcH])
  585. float trcLabelEr = nz(f_er(close, trcH))
  586. float trcLabel = trcLabelEr > TRC_THR ? 1.0 : 0.0
  587.  
  588. var array<float> trcF1 = array.new_float()
  589. var array<float> trcF2 = array.new_float()
  590. var array<float> trcF3 = array.new_float()
  591. var array<float> trcF4 = array.new_float()
  592. var array<float> trcF5 = array.new_float()
  593. var array<float> trcLab = array.new_float()
  594. float trcProb = na
  595. if showTRC and bar_index > trcH + 60
  596. trcF1.push(tf1Lag)
  597. trcF2.push(tf2Lag)
  598. trcF3.push(tf3Lag)
  599. trcF4.push(tf4Lag)
  600. trcF5.push(tf5Lag)
  601. trcLab.push(trcLabel)
  602. if trcLab.size() > trcMem
  603. trcF1.shift()
  604. trcF2.shift()
  605. trcF3.shift()
  606. trcF4.shift()
  607. trcF5.shift()
  608. trcLab.shift()
  609. int nMem = trcLab.size()
  610. if nMem >= TRC_K
  611. array<float> dists = array.new_float(nMem, 0.0)
  612. for i = 0 to nMem - 1
  613. float d = math.log(1.0 + math.abs(tf1 - trcF1.get(i))) + math.log(1.0 + math.abs(tf2 - trcF2.get(i))) + math.log(1.0 + math.abs(tf3 - trcF3.get(i))) + math.log(1.0 + math.abs(tf4 - trcF4.get(i))) + math.log(1.0 + math.abs(tf5 - trcF5.get(i)))
  614. dists.set(i, d)
  615. array<int> knnIdx = dists.sort_indices(order.ascending)
  616. float votes = 0.0
  617. for j = 0 to TRC_K - 1
  618. votes += trcLab.get(knnIdx.get(j))
  619. trcProb := votes / TRC_K
  620. float trcProbS = ta.ema(nz(trcProb, 0.5), 3)
  621. var int trcState = 1
  622. if showTRC and not na(trcProb)
  623. trcState := trcProbS >= 0.55 ? 1 : trcProbS <= 0.45 ? 0 : trcState
  624. int trcStatePrev = nz(trcState[1], trcState)
  625. bool isRanging = showTRC ? trcState == 0 : nz(chop) > 61.8
  626.  
  627. bool rsiXDn = ta.crossunder(rsi14, EXIT_OB)
  628. bool rsiXUp = ta.crossover(rsi14, EXIT_OS)
  629.  
  630. float candleAvgVol = ta.sma(volume, 20)
  631.  
  632. var int activeIdx = OPT_BASE
  633. int useIdx = autoOpt ? activeIdx : OPT_BASE
  634. int ssState = f_pickI(useIdx, st0, st1, st2, st3, st4, st5, st6, st7)
  635. bool ssBullRaw = f_pickB(useIdx, bs0, bs1, bs2, bs3, bs4, bs5, bs6, bs7)
  636. bool ssBearRaw = f_pickB(useIdx, br0, br1, br2, br3, br4, br5, br6, br7)
  637. bool ssStrongBull = f_pickB(useIdx, sb0, sb1, sb2, sb3, sb4, sb5, sb6, sb7)
  638. bool ssStrongBear = f_pickB(useIdx, sr0, sr1, sr2, sr3, sr4, sr5, sr6, sr7)
  639. int ssActiveLen = f_pickI(useIdx, L0, L1, L2, L3, L4, L5, L6, L7)
  640. bool ssNormalBull = ssBullRaw and not ssStrongBull
  641. bool ssNormalBear = ssBearRaw and not ssStrongBear
  642.  
  643. var int lastExitBar = -1000
  644. bool bullExit = ssState == 1 and rsiXDn and bar_index - lastExitBar > EXIT_COOL
  645. bool bearExit = ssState == -1 and rsiXUp and bar_index - lastExitBar > EXIT_COOL
  646. if bullExit or bearExit
  647. lastExitBar := bar_index
  648.  
  649. bool optBull = fvtDir == 1 and fvtDirPrev == 1 and low <= fvtLine + fvtBand and close > fvtLine
  650. bool optBear = fvtDir == -1 and fvtDirPrev == -1 and high >= fvtLine - fvtBand and close < fvtLine
  651.  
  652. bool fvtTurnBull = fvtDir == 1 and fvtDirPrev == -1
  653. bool fvtTurnBear = fvtDir == -1 and fvtDirPrev == 1
  654. bool spTurnBull = spDir == 1 and spDirPrev == -1
  655. bool spTurnBear = spDir == -1 and spDirPrev == 1
  656. bool tbTurnBull = tbDir == 1 and tbDirPrev == -1
  657. bool tbTurnBear = tbDir == -1 and tbDirPrev == 1
  658. bool tbStrengthen = tbStrong and not tbStrongPrev
  659. bool tbWeaken = not tbStrong and tbStrongPrev
  660. bool fcEnterUpper = fcState == 1 and fcStatePrev != 1
  661. bool fcEnterLower = fcState == -1 and fcStatePrev != -1
  662. bool fcExit = fcState == 0 and fcStatePrev != 0
  663. bool trcTurnTrend = showTRC and trcState == 1 and trcStatePrev == 0
  664. bool trcTurnRange = showTRC and trcState == 0 and trcStatePrev == 1
  665.  
  666. bool extTrig1 = ext1 > 0 and nz(ext1[1]) <= 0
  667. bool extTrig2 = ext2 > 0 and nz(ext2[1]) <= 0
  668. bool extTrig3 = ext3 > 0 and nz(ext3[1]) <= 0
  669. bool extTrig4 = ext4 > 0 and nz(ext4[1]) <= 0
  670. bool extTrig5 = ext5 > 0 and nz(ext5[1]) <= 0
  671. bool extState1 = ext1 > 0
  672. bool extState2 = ext2 > 0
  673. bool extState3 = ext3 > 0
  674. bool extState4 = ext4 > 0
  675. bool extState5 = ext5 > 0
  676.  
  677. var line entryLn = na
  678. var label entryLb = na
  679. var line slLn = na
  680. var label slLb = na
  681. var box rewardBx = na
  682. var box riskBx = na
  683. var array<line> tpLns = array.new<line>()
  684. var array<label> tpLbs = array.new<label>()
  685. var array<float> tpLvls = array.new<float>()
  686. var array<bool> tpHit = array.new<bool>()
  687. var int trDir = 0
  688. var float trEntry = na
  689. var float trSL = na
  690. var bool trSLHit = false
  691. var int trStart = 0
  692. var int tpCount = 0
  693. array<bool> tpNow = array.new_bool(5, false)
  694. bool slNow = false
  695.  
  696. if trDir != 0 and not trSLHit and tpCount < tpLvls.size() and bar_index > trStart
  697. int nT = tpLvls.size()
  698. for i = 0 to nT - 1
  699. if not tpHit.get(i)
  700. float lvl = tpLvls.get(i)
  701. bool hit = trDir == 1 ? high >= lvl : low <= lvl
  702. if hit
  703. tpHit.set(i, true)
  704. tpNow.set(i, true)
  705. tpCount += 1
  706. bool slTouch = trDir == 1 ? low <= trSL : high >= trSL
  707. if slTouch
  708. trSLHit := true
  709. slNow := true
  710. bool tpAnyNow = tpNow.includes(true)
  711.  
  712. bool newLong = showSS and ssBullRaw
  713. bool newShort = showSS and ssBearRaw
  714. if newLong or newShort
  715. line.delete(entryLn)
  716. label.delete(entryLb)
  717. line.delete(slLn)
  718. label.delete(slLb)
  719. box.delete(rewardBx)
  720. box.delete(riskBx)
  721. entryLn := na
  722. entryLb := na
  723. slLn := na
  724. slLb := na
  725. rewardBx := na
  726. riskBx := na
  727. for l in tpLns
  728. line.delete(l)
  729. for lb in tpLbs
  730. label.delete(lb)
  731. tpLns.clear()
  732. tpLbs.clear()
  733. tpLvls.clear()
  734. tpHit.clear()
  735. trDir := newLong ? 1 : -1
  736. trEntry := close
  737. float tpStep = tpslMode == "Volatility" ? nz(atr14) * tpMult : close * tpPct / 100.0
  738. float slDist = tpslMode == "Volatility" ? nz(atr14) * slMult : close * slPct / 100.0
  739. trSL := close - trDir * slDist
  740. trSLHit := false
  741. trStart := bar_index
  742. tpCount := 0
  743. for i = 1 to tpTargets
  744. tpLvls.push(close + trDir * tpStep * i)
  745. tpHit.push(false)
  746. color trCol = trDir == 1 ? bullCol : bearCol
  747. color oppCol = trDir == 1 ? bearCol : bullCol
  748. int x2 = bar_index + TPSL_EXT
  749. if showTP or showSL
  750. entryLn := line.new(bar_index, close, x2, close, color = trCol, width = 2)
  751. entryLb := label.new(x2, close, "Entry: " + str.tostring(close, format.mintick), style = label.style_label_left, color = trCol, textcolor = TXT_DARK, size = size.small)
  752. if showTP
  753. float farTP = tpLvls.last()
  754. rewardBx := box.new(bar_index, math.max(close, farTP), x2, math.min(close, farTP), border_color = color.new(trCol, 100), border_width = 0, bgcolor = color.new(trCol, 93))
  755. for i = 0 to tpLvls.size() - 1
  756. float lvl = tpLvls.get(i)
  757. tpLns.push(line.new(bar_index, lvl, x2, lvl, color = color.new(trCol, 55), width = 1))
  758. tpLbs.push(label.new(x2, lvl, "TP" + str.tostring(i + 1) + ": " + str.tostring(lvl, format.mintick), style = label.style_label_left, color = color.new(trCol, 70), textcolor = color.white, size = size.small))
  759. if showSL
  760. riskBx := box.new(bar_index, math.max(close, trSL), x2, math.min(close, trSL), border_color = color.new(oppCol, 100), border_width = 0, bgcolor = color.new(oppCol, 93))
  761. slLn := line.new(bar_index, trSL, x2, trSL, color = color.new(oppCol, 55), width = 1)
  762. slLb := label.new(x2, trSL, "SL: " + str.tostring(trSL, format.mintick), style = label.style_label_left, color = color.new(oppCol, 70), textcolor = color.white, size = size.small)
  763.  
  764. int xExt = bar_index + TPSL_EXT
  765. if not na(entryLn)
  766. entryLn.set_x2(xExt)
  767. if not na(entryLb)
  768. entryLb.set_x(xExt)
  769. if not na(slLn)
  770. slLn.set_x2(xExt)
  771. if not na(slLb)
  772. slLb.set_x(xExt)
  773. if not na(rewardBx)
  774. rewardBx.set_right(xExt)
  775. if not na(riskBx)
  776. riskBx.set_right(xExt)
  777. if tpLns.size() > 0
  778. for i = 0 to tpLns.size() - 1
  779. tpLns.get(i).set_x2(xExt)
  780. tpLbs.get(i).set_x(xExt)
  781.  
  782. float expEntry = trDir != 0 ? trEntry : na
  783. float expTP1 = f_lvl(tpLvls, 0)
  784. float expTP2 = f_lvl(tpLvls, 1)
  785. float expTP3 = f_lvl(tpLvls, 2)
  786. float expTP4 = f_lvl(tpLvls, 3)
  787. float expTP5 = f_lvl(tpLvls, 4)
  788. float expSL = trDir != 0 ? trSL : na
  789. float expTPHit = float(tpCount)
  790.  
  791. var DurationTracker dtSS = DurationTracker.new()
  792. var DurationTracker dtFVT = DurationTracker.new()
  793. var DurationTracker dtSpine = DurationTracker.new()
  794. var DurationTracker dtBias = DurationTracker.new()
  795. var DurationTracker dtFC = DurationTracker.new()
  796. var DurationTracker dtTRC = DurationTracker.new()
  797.  
  798. dtSS.update(ssState)
  799. dtFVT.update(fvtDir)
  800. dtSpine.update(spDir)
  801. dtBias.update(tbDir)
  802. dtFC.update(fcState)
  803. if showTRC
  804. dtTRC.update(trcState)
  805.  
  806. var array<PerfTracker> trackers = array.new<PerfTracker>()
  807. if barstate.isfirst
  808. trackers.push(PerfTracker.new(L0))
  809. trackers.push(PerfTracker.new(L1))
  810. trackers.push(PerfTracker.new(L2))
  811. trackers.push(PerfTracker.new(L3))
  812. trackers.push(PerfTracker.new(L4))
  813. trackers.push(PerfTracker.new(L5))
  814. trackers.push(PerfTracker.new(L6))
  815. trackers.push(PerfTracker.new(L7))
  816.  
  817. trackers.get(0).feed(bs0, br0)
  818. trackers.get(1).feed(bs1, br1)
  819. trackers.get(2).feed(bs2, br2)
  820. trackers.get(3).feed(bs3, br3)
  821. trackers.get(4).feed(bs4, br4)
  822. trackers.get(5).feed(bs5, br5)
  823. trackers.get(6).feed(bs6, br6)
  824. trackers.get(7).feed(bs7, br7)
  825.  
  826. int bestIdx = OPT_BASE
  827. float bestScore = -1e9
  828. for i = 0 to OPT_N - 1
  829. PerfTracker pt = trackers.get(i)
  830. if pt.trades >= optMinTrades
  831. float score = optMetric == "Win Rate" ? pt.winRate() : optMetric == "Net Profit" ? pt.netProfit : (pt.winRate() * 0.5 + pt.netProfit * 0.5)
  832. if score > bestScore
  833. bestScore := score
  834. bestIdx := i
  835.  
  836. if autoOpt
  837. activeIdx := bestIdx
  838.  
  839. color cBase = ssState == 1 ? bullCol : bearCol
  840. float volRatio = candleAvgVol > 0 ? math.min(volume / candleAvgVol, 2.5) / 2.5 : 0.5
  841. color cVolGrad = color.from_gradient(volRatio, 0.2, 1.0, color.new(cBase, 60), cBase)
  842. color cTrGrad = color.from_gradient(math.abs(nz(rsi14, 50.0) - 50.0), 0.0, 30.0, color.new(cBase, 50), cBase)
  843.  
  844. color barColFinal = cBase
  845. if candleMode == "Trend Gradient"
  846. barColFinal := cTrGrad
  847. else if candleMode == "Volume Gradient"
  848. barColFinal := cVolGrad
  849. else if candleMode == "None"
  850. barColFinal := na
  851.  
  852. if detectRange and isRanging and candleMode != "None"
  853. barColFinal := neutCol
  854.  
  855. plotcandle(candleMode != "None" ? open : na, candleMode != "None" ? high : na, candleMode != "None" ? low : na, candleMode != "None" ? close : na, "Candles", barColFinal, barColFinal, bordercolor = barColFinal)
  856.  
  857. p_fvtBullL = plot(fvtBullL, "FVT Bull Line", color = color.new(#00e5ff, 10), linewidth = 2, style = plot.style_linebr)
  858. p_fvtBearL = plot(fvtBearL, "FVT Bear Line", color = color.new(bearCol, 10), linewidth = 2, style = plot.style_linebr)
  859. p_fvtBullM = plot(fvtBullM, "FVT Bull Mid", display = display.none)
  860. p_fvtBullO = plot(fvtBullO, "FVT Bull Outer", display = display.none)
  861. p_fvtBearM = plot(fvtBearM, "FVT Bear Mid", display = display.none)
  862. p_fvtBearO = plot(fvtBearO, "FVT Bear Outer", display = display.none)
  863.  
  864. fill(p_fvtBullL, p_fvtBullM, color.new(#00e5ff, 75), "FVT Bull Cloud Inner")
  865. fill(p_fvtBullM, p_fvtBullO, color.new(#00e5ff, 90), "FVT Bull Cloud Outer")
  866. fill(p_fvtBearL, p_fvtBearM, color.new(bearCol, 75), "FVT Bear Cloud Inner")
  867. fill(p_fvtBearM, p_fvtBearO, color.new(bearCol, 90), "FVT Bear Cloud Outer")
  868.  
  869. color spineCol = spDir == 1 ? bullCol : bearCol
  870. plot(showSpine ? spine : na, "Trend Spine", color = spineCol, linewidth = 3)
  871.  
  872. color tbCol = tbDir == 1 ? (tbStrong ? color.new(bullCol, 30) : color.new(bullCol, 70)) : (tbStrong ? color.new(bearCol, 30) : color.new(bearCol, 70))
  873. p_tbU = plot(showBias ? tbCenter + tbHalf : na, "TB Upper", display = display.none)
  874. p_tbL = plot(showBias ? tbCenter - tbHalf : na, "TB Lower", display = display.none)
  875. fill(p_tbU, p_tbL, tbCol, "Trend Bias Band")
  876.  
  877. p_fcUO = plot(showClouds ? fcUO : na, "FC Upper Outer", color = color.new(bearCol, 60), display = display.none)
  878. p_fcUI = plot(showClouds ? fcUI : na, "FC Upper Inner", color = color.new(bearCol, 70), display = display.none)
  879. p_fcLI = plot(showClouds ? fcLI : na, "FC Lower Inner", color = color.new(bullCol, 70), display = display.none)
  880. p_fcLO = plot(showClouds ? fcLO : na, "FC Lower Outer", color = color.new(bullCol, 60), display = display.none)
  881. fill(p_fcUO, p_fcUI, color.new(bearCol, 80), "FC Upper Zone")
  882. fill(p_fcLI, p_fcLO, color.new(bullCol, 80), "FC Lower Zone")
  883.  
  884. if showSS and ssBullRaw
  885. string txt = ssStrongBull ? "+▲" : "▲"
  886. color col = ssStrongBull ? bullCol : color.new(bullCol, 25)
  887. label.new(bar_index, low, txt, yloc = yloc.belowbar, color = col, textcolor = TXT_DARK, style = label.style_label_up, size = size.normal)
  888.  
  889. if showSS and ssBearRaw
  890. string txt = ssStrongBear ? "+▼" : "▼"
  891. color col = ssStrongBear ? bearCol : color.new(bearCol, 25)
  892. label.new(bar_index, high, txt, yloc = yloc.abovebar, color = col, textcolor = color.white, style = label.style_label_down, size = size.normal)
  893.  
  894. plotshape(showOpt and optBull, "Optimal Bullish Entry", shape.triangleup, location.belowbar, bullCol, size = size.tiny)
  895. plotshape(showOpt and optBear, "Optimal Bearish Entry", shape.triangledown, location.abovebar, bearCol, size = size.tiny)
  896. plotshape(showExit and bullExit, "Bullish Exit", shape.xcross, location.belowbar, exitCol, size = size.small)
  897. plotshape(showExit and bearExit, "Bearish Exit", shape.xcross, location.abovebar, exitCol, size = size.small)
  898.  
  899. var array<string> condNames = array.new_string()
  900. if barstate.isfirst
  901. condNames.push(T01), condNames.push(T02), condNames.push(T03), condNames.push(T04), condNames.push(T05), condNames.push(T06), condNames.push(T07)
  902. condNames.push(T08), condNames.push(T09), condNames.push(T10), condNames.push(T11), condNames.push(T12), condNames.push(T13), condNames.push(T14)
  903. condNames.push(T15), condNames.push(T16), condNames.push(T17), condNames.push(T18), condNames.push(T19), condNames.push(T20), condNames.push(T21)
  904. condNames.push(T22), condNames.push(T23), condNames.push(T24), condNames.push(T25), condNames.push(T26), condNames.push(T27), condNames.push(T28)
  905. condNames.push(T29), condNames.push(T30), condNames.push(T31), condNames.push(T32), condNames.push(T33), condNames.push(T34)
  906. condNames.push(S01), condNames.push(S02), condNames.push(S03), condNames.push(S04), condNames.push(S05), condNames.push(S06), condNames.push(S07)
  907. condNames.push(S08), condNames.push(S09), condNames.push(S10), condNames.push(S11), condNames.push(S12), condNames.push(S13), condNames.push(S14)
  908. condNames.push(S15), condNames.push(S16), condNames.push(S17), condNames.push(S18), condNames.push(S19), condNames.push(S20)
  909.  
  910. array<bool> condVals = array.new_bool()
  911. condVals.push(ssBullRaw)
  912. condVals.push(ssBearRaw)
  913. condVals.push(ssNormalBull)
  914. condVals.push(ssNormalBear)
  915. condVals.push(ssStrongBull)
  916. condVals.push(ssStrongBear)
  917. condVals.push(bullExit)
  918. condVals.push(bearExit)
  919. condVals.push(tpNow.get(0))
  920. condVals.push(tpNow.get(1))
  921. condVals.push(tpNow.get(2))
  922. condVals.push(tpNow.get(3))
  923. condVals.push(tpNow.get(4))
  924. condVals.push(slNow)
  925. condVals.push(fvtTurnBull)
  926. condVals.push(fvtTurnBear)
  927. condVals.push(optBull)
  928. condVals.push(optBear)
  929. condVals.push(spTurnBull)
  930. condVals.push(spTurnBear)
  931. condVals.push(tbTurnBull)
  932. condVals.push(tbTurnBear)
  933. condVals.push(tbStrengthen)
  934. condVals.push(tbWeaken)
  935. condVals.push(fcEnterUpper)
  936. condVals.push(fcEnterLower)
  937. condVals.push(fcExit)
  938. condVals.push(trcTurnTrend)
  939. condVals.push(trcTurnRange)
  940. condVals.push(extTrig1)
  941. condVals.push(extTrig2)
  942. condVals.push(extTrig3)
  943. condVals.push(extTrig4)
  944. condVals.push(extTrig5)
  945. condVals.push(ssState == 1)
  946. condVals.push(ssState == -1)
  947. condVals.push(fvtDir == 1)
  948. condVals.push(fvtDir == -1)
  949. condVals.push(spDir == 1)
  950. condVals.push(spDir == -1)
  951. condVals.push(tbDir == 1)
  952. condVals.push(tbDir == -1)
  953. condVals.push(tbStrong)
  954. condVals.push(not tbStrong)
  955. condVals.push(fcState == 1)
  956. condVals.push(fcState == -1)
  957. condVals.push(fcState == 0)
  958. condVals.push(showTRC ? trcState == 1 : not isRanging)
  959. condVals.push(isRanging)
  960. condVals.push(extState1)
  961. condVals.push(extState2)
  962. condVals.push(extState3)
  963. condVals.push(extState4)
  964. condVals.push(extState5)
  965.  
  966. bool s1Ok = f_step(condNames, condVals, a1c1, a1op, a1c2)
  967. bool s2Ok = f_step(condNames, condVals, a2c1, a2op, a2c2)
  968. bool s3Ok = f_step(condNames, condVals, a3c1, a3op, a3c2)
  969. bool s4Ok = f_step(condNames, condVals, a4c1, a4op, a4c2)
  970. bool s5Ok = f_step(condNames, condVals, a5c1, a5op, a5c2)
  971. bool s6Ok = f_step(condNames, condVals, a6c1, a6op, a6c2)
  972. bool s7Ok = f_step(condNames, condVals, a7c1, a7op, a7c2)
  973.  
  974. int seqLen = 0
  975. if a1c1 != C_NONE
  976. seqLen := 1
  977. if a2c1 != C_NONE
  978. seqLen := 2
  979. if a3c1 != C_NONE
  980. seqLen := 3
  981. if a4c1 != C_NONE
  982. seqLen := 4
  983. if a5c1 != C_NONE
  984. seqLen := 5
  985. if a6c1 != C_NONE
  986. seqLen := 6
  987. if a7c1 != C_NONE
  988. seqLen := 7
  989.  
  990. bool f1Ok = f1c == C_NONE or f_cond(condNames, condVals, f1c)
  991. bool f2Ok = f2c == C_NONE or f_cond(condNames, condVals, f2c)
  992. bool f3Ok = f3c == C_NONE or f_cond(condNames, condVals, f3c)
  993. bool f4Ok = f4c == C_NONE or f_cond(condNames, condVals, f4c)
  994. bool f5Ok = f5c == C_NONE or f_cond(condNames, condVals, f5c)
  995. bool allFilters = f1Ok and f2Ok and f3Ok and f4Ok and f5Ok
  996.  
  997. var int curStep = 0
  998. var int lastStepBar = 0
  999. bool seqComplete = false
  1000.  
  1001. if seqLen > 0
  1002. if stepTimeout > 0 and curStep > 0 and bar_index - lastStepBar > stepTimeout
  1003. curStep := 0
  1004. if curStep == 0 and s1Ok
  1005. curStep := 1
  1006. lastStepBar := bar_index
  1007. if curStep == 1 and seqLen >= 2 and s2Ok
  1008. curStep := 2
  1009. lastStepBar := bar_index
  1010. if curStep == 2 and seqLen >= 3 and s3Ok
  1011. curStep := 3
  1012. lastStepBar := bar_index
  1013. if curStep == 3 and seqLen >= 4 and s4Ok
  1014. curStep := 4
  1015. lastStepBar := bar_index
  1016. if curStep == 4 and seqLen >= 5 and s5Ok
  1017. curStep := 5
  1018. lastStepBar := bar_index
  1019. if curStep == 5 and seqLen >= 6 and s6Ok
  1020. curStep := 6
  1021. lastStepBar := bar_index
  1022. if curStep == 6 and seqLen >= 7 and s7Ok
  1023. curStep := 7
  1024. lastStepBar := bar_index
  1025. if curStep == seqLen and allFilters
  1026. seqComplete := true
  1027. curStep := 0
  1028.  
  1029. bool filterOnlyTrigger = seqLen == 0 and allFilters and bar_index > 0 and not allFilters[1]
  1030. bool customAlertFired = seqComplete or filterOnlyTrigger
  1031.  
  1032. plotshape(showHistAlerts and customAlertFired, "Historical Alert", shape.diamond, location.abovebar, alertCol, size = size.small)
  1033.  
  1034. if customAlertFired
  1035. string msg = f_fmt(alertMsgIn, "Sequence Complete")
  1036. if alertFreqIn == "Once Per Bar"
  1037. alert(msg, alert.freq_once_per_bar)
  1038. else if alertFreqIn == "Once Per Bar Close"
  1039. alert(msg, alert.freq_once_per_bar_close)
  1040. else
  1041. alert(msg, alert.freq_all)
  1042.  
  1043. if universalAlerts
  1044. string univEvt = ""
  1045. for k = 0 to N_TRIG - 1
  1046. if condVals.get(k)
  1047. string trigName = str.replace(condNames.get(k), " [Trigger]", "")
  1048. univEvt := univEvt == "" ? trigName : univEvt + " | " + trigName
  1049. if univEvt != ""
  1050. string uMsg = f_fmt(alertMsgIn, univEvt)
  1051. if alertFreqIn == "Once Per Bar"
  1052. alert(uMsg, alert.freq_once_per_bar)
  1053. else if alertFreqIn == "Once Per Bar Close"
  1054. alert(uMsg, alert.freq_once_per_bar_close)
  1055. else
  1056. alert(uMsg, alert.freq_all)
  1057.  
  1058. alertcondition(ssBullRaw, "Smart Signals Bullish Signal", "Smart Signals: Bullish Signal")
  1059. alertcondition(ssBearRaw, "Smart Signals Bearish Signal", "Smart Signals: Bearish Signal")
  1060. alertcondition(ssStrongBull, "Smart Signals Strong Bullish Signal", "Smart Signals: Strong Bullish Signal")
  1061. alertcondition(ssStrongBear, "Smart Signals Strong Bearish Signal", "Smart Signals: Strong Bearish Signal")
  1062. alertcondition(bullExit, "Bullish Exit Signal", "Smart Signals: Bullish Exit")
  1063. alertcondition(bearExit, "Bearish Exit Signal", "Smart Signals: Bearish Exit")
  1064. alertcondition(fvtTurnBull, "Fair Value Trail Turns Bullish", "FVT: Trend turned Bullish")
  1065. alertcondition(fvtTurnBear, "Fair Value Trail Turns Bearish", "FVT: Trend turned Bearish")
  1066. alertcondition(optBull, "Optimal Bullish Entry", "FVT: Optimal Bullish Entry")
  1067. alertcondition(optBear, "Optimal Bearish Entry", "FVT: Optimal Bearish Entry")
  1068. alertcondition(tpNow.get(0), "Take-Profit 1 Hit", "TP/SL: Take-Profit 1 Hit")
  1069. alertcondition(tpNow.get(1), "Take-Profit 2 Hit", "TP/SL: Take-Profit 2 Hit")
  1070. alertcondition(tpNow.get(2), "Take-Profit 3 Hit", "TP/SL: Take-Profit 3 Hit")
  1071. alertcondition(slNow, "Stop-Loss Hit", "TP/SL: Stop-Loss Hit")
  1072. alertcondition(customAlertFired, "Custom Alert Sequence Triggered", "Smart Signals: Custom Alert Sequence Complete")
  1073.  
  1074. if barstate.islast
  1075. string tSz = f_size(tblSize)
  1076.  
  1077. if showTable
  1078. var table compTbl = table.new(f_pos(tblPos), 4, 7, bgcolor = TBL_BG, frame_color = TBL_BORDER, frame_width = 1, border_color = TBL_BORDER, border_width = 1)
  1079. table.cell(compTbl, 0, 0, "Component Type", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1080. table.cell(compTbl, 1, 0, "Signal", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1081. table.cell(compTbl, 2, 0, "Avg Signal Duration", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1082. table.cell(compTbl, 3, 0, "Current Signal Duration",text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1083.  
  1084. f_compRow(compTbl, 1, "Smart Signals", showSS, ssState, dtSS.avgDur(), dtSS.curDur(), false, tSz)
  1085. f_compRow(compTbl, 2, "Fair Value Trail", showFVT, fvtDir, dtFVT.avgDur(), dtFVT.curDur(), false, tSz)
  1086. f_compRow(compTbl, 3, "Trend Spine", showSpine, spDir, dtSpine.avgDur(), dtSpine.curDur(), false, tSz)
  1087. f_compRow(compTbl, 4, "Trend Bias", showBias, tbDir, dtBias.avgDur(), dtBias.curDur(), false, tSz)
  1088. f_compRow(compTbl, 5, "Firmament Clouds", showClouds, fcState, dtFC.avgDur(), dtFC.curDur(), false, tSz)
  1089. f_compRow(compTbl, 6, "Trend-Range Classifier", showTRC, trcState, dtTRC.avgDur(), dtTRC.curDur(), true, tSz)
  1090.  
  1091. if showOptTbl
  1092. var table optTbl = table.new(f_pos(optTblPos), 5, 10, bgcolor = TBL_BG, frame_color = TBL_BORDER, frame_width = 1, border_color = TBL_BORDER, border_width = 1)
  1093. table.cell(optTbl, 0, 0, "Length", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1094. table.cell(optTbl, 1, 0, "Trades", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1095. table.cell(optTbl, 2, 0, "Win Rate", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1096. table.cell(optTbl, 3, 0, "Net Profit", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1097. table.cell(optTbl, 4, 0, "Profit Factor", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1098.  
  1099. for i = 0 to OPT_N - 1
  1100. PerfTracker pt = trackers.get(i)
  1101. bool isBest = (autoOpt ? bestIdx : OPT_BASE) == i
  1102. color rowBg = isBest ? color.new(bullCol, 85) : TBL_BG
  1103. string prefix = isBest ? "► " : ""
  1104. float pf = pt.profitFactor()
  1105. table.cell(optTbl, 0, i + 1, prefix + str.tostring(pt.length), text_color = isBest ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = rowBg)
  1106. table.cell(optTbl, 1, i + 1, str.tostring(pt.trades), text_color = TXT_MAIN, text_size = tSz, bgcolor = rowBg)
  1107. table.cell(optTbl, 2, i + 1, str.tostring(pt.winRate(), "#.1") + "%", text_color = TXT_MAIN, text_size = tSz, bgcolor = rowBg)
  1108. table.cell(optTbl, 3, i + 1, (pt.netProfit >= 0 ? "+" : "") + str.tostring(pt.netProfit, "#.2") + "%", text_color = pt.netProfit >= 0 ? bullCol : bearCol, text_size = tSz, bgcolor = rowBg)
  1109. table.cell(optTbl, 4, i + 1, na(pf) ? "NaN" : str.tostring(pf, "#.2"), text_color = TXT_MAIN, text_size = tSz, bgcolor = rowBg)
  1110.  
  1111. string optFoot = "Active: " + str.tostring(ssActiveLen) + " | Metric: " + optMetric + (autoOpt ? " (Auto)" : " (Fixed)")
  1112. table.cell(optTbl, 0, 9, optFoot, text_color = TXT_DIM, text_size = tSz, bgcolor = TBL_HEAD)
  1113. table.cell(optTbl, 1, 9, "", bgcolor = TBL_HEAD)
  1114. table.cell(optTbl, 2, 9, "", bgcolor = TBL_HEAD)
  1115. table.cell(optTbl, 3, 9, "", bgcolor = TBL_HEAD)
  1116. table.cell(optTbl, 4, 9, "", bgcolor = TBL_HEAD)
  1117.  
  1118. if showHistAlerts
  1119. var table alrTbl = table.new(position.bottom_left, 2, 14, bgcolor = TBL_BG, frame_color = TBL_BORDER, frame_width = 1, border_color = TBL_BORDER, border_width = 1)
  1120. table.cell(alrTbl, 0, 0, "Alert Step / Filter", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1121. table.cell(alrTbl, 1, 0, "Condition Logic", text_color = TXT_MAIN, text_size = tSz, bgcolor = TBL_HEAD)
  1122.  
  1123. int rIdx = 1
  1124. if seqLen == 0 and f1c == C_NONE and f2c == C_NONE and f3c == C_NONE and f4c == C_NONE and f5c == C_NONE
  1125. table.cell(alrTbl, 0, rIdx, "⚠️ Warning", text_color = alertCol, text_size = tSz, bgcolor = TBL_BG)
  1126. table.cell(alrTbl, 1, rIdx, "No alert conditions configured in Alert Sequence / Filters", text_color = alertCol, text_size = tSz, bgcolor = TBL_BG)
  1127. else
  1128. if a1c1 != C_NONE
  1129. string txt = a1c1 + (a1c2 != C_NONE ? " " + a1op + " " + a1c2 : "")
  1130. table.cell(alrTbl, 0, rIdx, "Step 1" + (curStep >= 1 ? " ✓" : ""), text_color = curStep >= 1 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1131. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a1c1), text_size = tSz, bgcolor = TBL_BG)
  1132. rIdx += 1
  1133. if a2c1 != C_NONE
  1134. string txt = a2c1 + (a2c2 != C_NONE ? " " + a2op + " " + a2c2 : "")
  1135. table.cell(alrTbl, 0, rIdx, "Step 2" + (curStep >= 2 ? " ✓" : ""), text_color = curStep >= 2 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1136. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a2c1), text_size = tSz, bgcolor = TBL_BG)
  1137. rIdx += 1
  1138. if a3c1 != C_NONE
  1139. string txt = a3c1 + (a3c2 != C_NONE ? " " + a3op + " " + a3c2 : "")
  1140. table.cell(alrTbl, 0, rIdx, "Step 3" + (curStep >= 3 ? " ✓" : ""), text_color = curStep >= 3 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1141. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a3c1), text_size = tSz, bgcolor = TBL_BG)
  1142. rIdx += 1
  1143. if a4c1 != C_NONE
  1144. string txt = a4c1 + (a4c2 != C_NONE ? " " + a4op + " " + a4c2 : "")
  1145. table.cell(alrTbl, 0, rIdx, "Step 4" + (curStep >= 4 ? " ✓" : ""), text_color = curStep >= 4 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1146. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a4c1), text_size = tSz, bgcolor = TBL_BG)
  1147. rIdx += 1
  1148. if a5c1 != C_NONE
  1149. string txt = a5c1 + (a5c2 != C_NONE ? " " + a5op + " " + a5c2 : "")
  1150. table.cell(alrTbl, 0, rIdx, "Step 5" + (curStep >= 5 ? " ✓" : ""), text_color = curStep >= 5 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1151. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a5c1), text_size = tSz, bgcolor = TBL_BG)
  1152. rIdx += 1
  1153. if a6c1 != C_NONE
  1154. string txt = a6c1 + (a6c2 != C_NONE ? " " + a6op + " " + a6c2 : "")
  1155. table.cell(alrTbl, 0, rIdx, "Step 6" + (curStep >= 6 ? " ✓" : ""), text_color = curStep >= 6 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1156. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a6c1), text_size = tSz, bgcolor = TBL_BG)
  1157. rIdx += 1
  1158. if a7c1 != C_NONE
  1159. string txt = a7c1 + (a7c2 != C_NONE ? " " + a7op + " " + a7c2 : "")
  1160. table.cell(alrTbl, 0, rIdx, "Step 7" + (curStep >= 7 ? " ✓" : ""), text_color = curStep >= 7 ? bullCol : TXT_MAIN, text_size = tSz, bgcolor = TBL_BG)
  1161. table.cell(alrTbl, 1, rIdx, txt, text_color = f_condCol(a7c1), text_size = tSz, bgcolor = TBL_BG)
  1162. rIdx += 1
  1163. if f1c != C_NONE
  1164. table.cell(alrTbl, 0, rIdx, "Filter 1" + (f1Ok ? " ✓" : ""), text_color = f1Ok ? bullCol : bearCol, text_size = tSz, bgcolor = TBL_BG)
  1165. table.cell(alrTbl, 1, rIdx, f1c, text_color = f_condCol(f1c), text_size = tSz, bgcolor = TBL_BG)
  1166. rIdx += 1
  1167. if f2c != C_NONE
  1168. table.cell(alrTbl, 0, rIdx, "Filter 2" + (f2Ok ? " ✓" : ""), text_color = f2Ok ? bullCol : bearCol, text_size = tSz, bgcolor = TBL_BG)
  1169. table.cell(alrTbl, 1, rIdx, f2c, text_color = f_condCol(f2c), text_size = tSz, bgcolor = TBL_BG)
  1170. rIdx += 1
  1171. if f3c != C_NONE
  1172. table.cell(alrTbl, 0, rIdx, "Filter 3" + (f3Ok ? " ✓" : ""), text_color = f3Ok ? bullCol : bearCol, text_size = tSz, bgcolor = TBL_BG)
  1173. table.cell(alrTbl, 1, rIdx, f3c, text_color = f_condCol(f3c), text_size = tSz, bgcolor = TBL_BG)
  1174. rIdx += 1
  1175. if f4c != C_NONE
  1176. table.cell(alrTbl, 0, rIdx, "Filter 4" + (f4Ok ? " ✓" : ""), text_color = f4Ok ? bullCol : bearCol, text_size = tSz, bgcolor = TBL_BG)
  1177. table.cell(alrTbl, 1, rIdx, f4c, text_color = f_condCol(f4c), text_size = tSz, bgcolor = TBL_BG)
  1178. rIdx += 1
  1179. if f5c != C_NONE
  1180. table.cell(alrTbl, 0, rIdx, "Filter 5" + (f5Ok ? " ✓" : ""), text_color = f5Ok ? bullCol : bearCol, text_size = tSz, bgcolor = TBL_BG)
  1181. table.cell(alrTbl, 1, rIdx, f5c, text_color = f_condCol(f5c), text_size = tSz, bgcolor = TBL_BG)
Advertisement
Add Comment
Please, Sign In to add comment