マルチインジケーター適応トレンド・トレード戦略は,複数の技術指標からの信号を統合した定量的なトレード戦略である.それは市場のトレンド方向性を自動的に特定し,異なる市場状況に基づいて異なる構成を持つトレード・シグナルを生成することができる.
この戦略は,移動平均値,ストックRSI,WaveTrendなどを含む指標を組み合わせて取引信号を形成する.また,全体的な市場傾向の判断に基づいて,各指標のパラメータ構成を動的に切り替える.これは異なる市場環境下で適応的な取引を可能にします.
全体的に見ると,この戦略は傾向を追跡し,適応する能力が強い.取引頻度を削減し,大きな片方向のトレンド利益を得ることができます.
この戦略は,全体的なトレンド方向を決定するために300期指数関数移動平均を使用する. 上向きEMA線は上昇見通し,下向きEMA線は下向き見通しを示す.
価格がEMA線を突破すると,逆売り信号を誘発し,以前のロングポジションをロックします. これによりリスクを効果的に制御できます.
異なる市場動向下で,戦略は異なるパラメータ構成を採用して取引信号を生成します.
上向きのトレンドの下での取引シグナルには,以下が含まれます.
ダウントレンドの下での取引信号には,以下が含まれます.
ユーザは,カスタマイズされた取引ロジックを実装するために,異なる指標から異なる信号を有効または無効にすることができます.
各信号は +1 の信号スコアに貢献します. 合計スコアがユーザーによって設定された
戦略は,利益の取得率,損失の停止率,価格の破綻率などを含む,利益の取得とストップ損失の複数の方法を用意している.これらのパラメータは,異なる市場動向に基づいて動的に変化する.
利得要件が満たされていない場合,戦略は保有期間とリスクを制御するために直接ポジションを閉鎖する方法も提供します.
多指標適応トレンド取引戦略には以下の利点があります.
多指標適応トレンド取引戦略には,次のリスクもあります.
EMAの長さを適切に調整し,ストップロスの範囲を拡大することで,いくつかのリスクが解決できます.
この戦略は,次の側面からも向上することができる.
マルチインジケーター適応トレンドトレード戦略は,トレンド判断,複数のインジケーター信号の融合,ダイナミックパラメータスイッチングを含む方法を統合する.定量的なトレード戦略として,それは大きな適応性とカスタマイズ可能性を持っています.一方的なトレンドを最大限に捕捉しながら不必要な取引を減らすことができます.この戦略は定量的な取引の優れた代表であり,深層の研究と適用に値します.
/*backtest start: 2022-12-21 00:00:00 end: 2023-12-27 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //////////////////////////////////////////////////////////////////////////////// //START▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ c="███████╗ █████╗ █████╗ ██╗ ██╗ █████╗ ██╗ ██╗ ██████╗ ██╗ ██╗███╗ ██╗" o="╚════██║██╔══██╗██╔══██╗ ██║ ██║██╔══██╗██║ ██║██╔════╝ ██║ ██║████╗ ██║" d=" ███╔═╝███████║██║ ╚═╝ ╚██╗ ██╔╝███████║██║ ██║██║ ██╗ ███████║██╔██╗██║" e="██╔══╝ ██╔══██║██║ ██╗ ╚████╔╝ ██╔══██║██║ ██║██║ ╚██╗██╔══██║██║╚████║" r="███████╗██║ ██║╚█████╔╝ ╚██╔╝ ██║ ██║╚██████╔╝╚██████╔╝██║ ██║██║ ╚███║" s="╚══════╝╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚══╝" //@version=5 strategy("Instrument-Z", overlay=true, initial_capital=1600, default_qty_type=strategy.percent_of_equity, default_qty_value=90, commission_value=0.075) //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //BAR COLOR AND EMA AREA▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //BAR COLOR bullCcolor = close > open ? #80cbc4 : na bearCcolor = close < open ? #ef9a9a : na bullC = close > open bearC = close < open bullE = bullC and bearC[1] and close > open[1] ? color.new(#ffffff, 100) : bullCcolor bearE = bearC and bullC[1] and close < open[1] ? color.new(#ffffff, 100) : bearCcolor barcolor(bullE) barcolor(bearE) //EMA 1 len1 = 10 ema1 = ta.ema(close, len1) //EMA 2 len2 = 100 ema2 = ta.ema(close, len2) //EMA COLORS emacolor = ema1 > ema2 ? #26a69a : #ef5350 //EMA PLOTS ema1line = plot(ema1, title="EMA 1", color=color.new(#ffffff, 100), editable=false) ema2line = plot(ema2, title="EMA 2", color=color.new(#ffffff, 100), editable=false) fill(ema1line, ema2line, title="EMA Area", color=color.new(emacolor, 90)) //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //INITIAL OPTIONS▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ src = input.source(defval=close, title="Source", group="SETUP GUIDE AT YouTube.com/c/ZacVaughnYT") //tfr = input.timeframe("", title="Resolution") //request.security(syminfo.tickerid, tfr, expression, barmerge.gaps_on) //POSITIONS TradeDir = input.string("LONG", title="Trade Direction", options=["LONG", "SHORT"], group="POSITIONS") TrendTrade = input(false, "Only Trade with Trend", group="POSITIONS") //UPTREND PROFIT AND LOSS UTsellProf = input(true, title="Only Sell in Profit", group="UPTREND 🠕 PROFIT & LOSS") UTminProf = input.float(title="Minimum Profit (%)", defval=3.6, minval=0, maxval=100, step=.1, group="UPTREND 🠕 PROFIT & LOSS") / 100 UTuseTP = input(true, title="Use Take Profit", group="UPTREND 🠕 PROFIT & LOSS") UTTPperc = input.float(title="Take Profit (%)", defval=11.5, minval=0, maxval=1000, step=.1, group="UPTREND 🠕 PROFIT & LOSS") / 100 UTuseSL = input(true, title="Use Stop Loss", group="UPTREND 🠕 PROFIT & LOSS") UTSLperc = input.float(title="Stop Loss (%)", defval=-7.5, minval=-50, maxval=0, step=.1, group="UPTREND 🠕 PROFIT & LOSS") / 100 UTuseTE = input(false, title="Use Trade Expiration", group="UPTREND 🠕 PROFIT & LOSS") UTTEbars = input.int(title="Expire After (bars)", defval=200, minval=1, maxval=10000, group="UPTREND 🠕 PROFIT & LOSS") //DOWNTREND PROFIT AND LOSS DTsellProf = input(true, title="Only Sell in Profit", group="DOWNTREND 🠗 PROFIT & LOSS") DTminProf = input.float(title="Minimum Profit (%)", defval=1, minval=0, maxval=100, step=.1, group="DOWNTREND 🠗 PROFIT & LOSS") / 100 DTuseTP = input(false, title="Use Take Profit", group="DOWNTREND 🠗 PROFIT & LOSS") DTTPperc = input.float(title="Take Profit (%)", defval=15, minval=0, maxval=1000, step=.1, group="DOWNTREND 🠗 PROFIT & LOSS") / 100 DTuseSL = input(true, title="Use Stop Loss", group="DOWNTREND 🠗 PROFIT & LOSS") DTSLperc = input.float(title="Stop Loss (%)", defval=-7.4, minval=-50, maxval=0, step=.1, group="DOWNTREND 🠗 PROFIT & LOSS") / 100 DTuseTE = input(false, title="Use Trade Expiration", group="DOWNTREND 🠗 PROFIT & LOSS") DTTEbars = input.int(title="Expire After (bars)", defval=200, minval=1, maxval=10000, group="DOWNTREND 🠗 PROFIT & LOSS") //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //TREND MOVING AVERAGE▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //TREND MA ma(source, length, type) => type == "SMA" ? ta.sma(source, length) : type == "EMA" ? ta.ema(source, length) : type == "RMA" ? ta.rma(source, length) : type == "HMA" ? ta.wma(2*ta.wma(source, length/2)-ta.wma(source, length), math.floor(math.sqrt(length))) : type == "WMA" ? ta.wma(source, length) : type == "VWMA" ? ta.vwma(source, length) : na mat_type = input.string("EMA", "Trend MA", inline="Trend MA", options=["SMA", "EMA", "RMA", "HMA", "WMA", "VWMA"], group="POSITIONS") mat_length = input.int(300, "", inline="Trend MA", minval=1, step=5, group="POSITIONS") mat = ma(src, mat_length, mat_type) matcolor = mat > mat[1] ? #26a69a : #ef5350 matline = plot(mat, color=color.new(matcolor, 50), linewidth=2, title="Trend MA") matRevS = input(false, title="Sell After Trend Reverses", group="POSITIONS") matRevSbars = input.int(10, "Sell After (bars)", group="POSITIONS") //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //CROSSING MOVING AVERAGES▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //UPTREND OPTIONS //Cross UTUsemaX = input(false, "Moving Average Cross", group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTReqmaXscore = UTUsemaX ? 1 : 0 //Position UTUsemaP = input(true, "Moving Average Position", group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTReqmaPscore = UTUsemaP ? 1 : 0 //Histogram UTUsemaH = input(false, "MA Histogram Reverse", group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTReqmaHscore = UTUsemaH ? 1 : 0 //DOWNTREND OPTIONS //Cross DTUsemaX = input(false, "Moving Average Cross", group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTReqmaXscore = DTUsemaX ? 1 : 0 //Position DTUsemaP = input(true, "Moving Average Position", group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTReqmaPscore = DTUsemaP ? 1 : 0 //Histogram DTUsemaH = input(false, "MA Histogram Reverse", group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTReqmaHscore = DTUsemaH ? 1 : 0 //UPTREND INPUTS //MA1 UTma1_type = input.string("RMA", "MA 1", inline="UT MA 1", options=["SMA", "EMA", "RMA", "HMA", "WMA", "VWMA"], group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTma1_length = input.int(7, "", inline="UT MA 1", minval=1, group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTma1 = ma(src, UTma1_length, UTma1_type) UTma1Color = mat > mat[1] ? color.new(color.blue, 35) : color.new(color.blue, 100) UTma1line = plot(UTma1, color=UTma1Color, title="UT MA 1") //MA2 UTma2_type = input.string("HMA", "MA 2", inline="UT MA 2", options=["SMA", "EMA", "RMA", "HMA", "WMA", "VWMA"], group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTma2_length = input.int(54, "", inline="UT MA 2", minval=1, group="UPTREND 🠕 MOVING AVERAGE SIGNALS") UTma2 = ma(src, UTma2_length, UTma2_type) UTma2Color = mat > mat[1] ? color.new(color.purple, 35) : color.new(color.purple, 100) UTma2line = plot(UTma2, color=UTma2Color, title="UT MA 2") UTmahist = UTma1 - UTma2 //DOWNTREND INPUTS //MA1 DTma1_type = input.string("RMA", "MA 1", inline="DT MA 1", options=["SMA", "EMA", "RMA", "HMA", "WMA", "VWMA"], group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTma1_length = input.int(7, "", inline="DT MA 1", minval=1, group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTma1 = ma(src, DTma1_length, DTma1_type) DTma1Color = mat > mat[1] ? color.new(color.blue, 100) : color.new(color.blue, 35) DTma1line = plot(DTma1, color=DTma1Color, title="DT MA 1") //MA2 DTma2_type = input.string("HMA", "MA 2", inline="DT MA 2", options=["SMA", "EMA", "RMA", "HMA", "WMA", "VWMA"], group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTma2_length = input.int(54, "", inline="DT MA 2", minval=1, group="DOWNTREND 🠗 MOVING AVERAGE SIGNALS") DTma2 = ma(src, DTma2_length, DTma2_type) DTma2Color = mat > mat[1] ? color.new(color.purple, 100) : color.new(color.purple, 35) DTma2line = plot(DTma2, color=DTma2Color, title="DT MA 2") DTmahist = DTma1 - DTma2 //UPTREND SIGNALS UTmaXup = UTUsemaX and UTma1 > UTma2 and UTma1[1] < UTma2[1] ? 1 : 0 UTmaXdn = UTUsemaX and UTma1 < UTma2 and UTma1[1] > UTma2[1] ? 1 : 0 UTmaPup = UTUsemaP and UTma1 > UTma2 ? 1 : 0 UTmaPdn = UTUsemaP and UTma1 < UTma2 ? 1 : 0 UTmaHup = UTUsemaH and UTmahist > UTmahist[1] and UTmahist[1] < UTmahist[2] ? 1 : 0 UTmaHdn = UTUsemaH and UTmahist < UTmahist[1] and UTmahist[1] > UTmahist[2] ? 1 : 0 //DOWNTREND SIGNALS DTmaXup = DTUsemaX and DTma1 > DTma2 and DTma1[1] < DTma2[1] ? 1 : 0 DTmaXdn = DTUsemaX and DTma1 < DTma2 and DTma1[1] > DTma2[1] ? 1 : 0 DTmaPup = DTUsemaP and DTma1 > DTma2 ? 1 : 0 DTmaPdn = DTUsemaP and DTma1 < DTma2 ? 1 : 0 DTmaHup = DTUsemaH and DTmahist > DTmahist[1] and DTmahist[1] < DTmahist[2] ? 1 : 0 DTmaHdn = DTUsemaH and DTmahist < DTmahist[1] and DTmahist[1] > DTmahist[2] ? 1 : 0 //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //STOCHASTIC RSI▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //UPTREND OPTIONS //Cross UTUseSrsiX = input(false, "Stoch RSI Cross Signal", group="UPTREND 🠕 STOCH RSI SIGNALS") UTReqSrsiXscore = UTUseSrsiX ? 1 : 0 //Level UTUseSrsiL = input(true, "Use Buy/Sell Levels", group="UPTREND 🠕 STOCH RSI SIGNALS") UTsablevelb = input.int(61, "Buy Below Level", group="UPTREND 🠕 STOCH RSI SIGNALS") UTsablevels = input.int(13, "Sell Above Level", group="UPTREND 🠕 STOCH RSI SIGNALS") UTReqSrsiLscore = UTUseSrsiL ? 1 : 0 //Position UTUseSrsiP = input(false, "Use Stoch RSI Position", group="UPTREND 🠕 STOCH RSI SIGNALS") UTReqSrsiPscore = UTUseSrsiP ? 1 : 0 //Divergence UTUseSrsiD = input(false, "Stoch RSI Divergence", group="UPTREND 🠕 STOCH RSI SIGNALS") UTReqSrsiDscore = UTUseSrsiD ? 1 : 0 //DOWNTREND OPTIONS //Cross DTUseSrsiX = input(false, "Stoch RSI Cross Signal", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTReqSrsiXscore = DTUseSrsiX ? 1 : 0 //Level DTUseSrsiL = input(true, "Use Buy/Sell Levels", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTsablevelb = input.int(61, "Buy Below Level", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTsablevels = input.int(13, "Sell Above Level", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTReqSrsiLscore = DTUseSrsiL ? 1 : 0 //Position DTUseSrsiP = input(false, "Use Stoch RSI Position", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTReqSrsiPscore = DTUseSrsiP ? 1 : 0 //Divergence DTUseSrsiD = input(false, "Stoch RSI Divergence", group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTReqSrsiDscore = DTUseSrsiD ? 1 : 0 //UPTREND INPUTS //STOCH RSI UTlengthRSI = input.int(12, "RSI Length", minval=1, group="UPTREND 🠕 STOCH RSI SIGNALS") UTlengthStoch = input.int(20, "Stochastic Length", minval=1, group="UPTREND 🠕 STOCH RSI SIGNALS") UTrsi1 = ta.rsi(src, UTlengthRSI) UTrk = ta.sma(ta.stoch(UTrsi1, UTrsi1, UTrsi1, UTlengthStoch), 3) UTrd = ta.sma(UTrk, 3) //DOWNTREND INPUTS //STOCH RSI DTlengthRSI = input.int(12, "RSI Length", minval=1, group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTlengthStoch = input.int(20, "Stochastic Length", minval=1, group="DOWNTREND 🠗 STOCH RSI SIGNALS") DTrsi1 = ta.rsi(src, DTlengthRSI) DTrk = ta.sma(ta.stoch(DTrsi1, DTrsi1, DTrsi1, DTlengthStoch), 3) DTrd = ta.sma(DTrk, 3) //UPTREND DIVERGENCE inRange(cond) => bars = ta.barssince(cond == true) 5 <= bars and bars <= 60 osc2 = UTrk //Pivots plFound2 = na(ta.pivotlow(osc2, 5, 2)) ? false : true phFound2 = na(ta.pivothigh(osc2, 5, 2)) ? false : true //Regular Bullish oscHL2 = osc2[2] > ta.valuewhen(plFound2, osc2[2], 1) and inRange(plFound2[1]) priceLL2 = low[2] < ta.valuewhen(plFound2, low[2], 1) bullCond2 = priceLL2 and oscHL2 and plFound2 //Hidden Bullish oscLL2 = osc2[2] < ta.valuewhen(plFound2, osc2[2], 1) and inRange(plFound2[1]) priceHL2 = low[2] > ta.valuewhen(plFound2, low[2], 1) hiddenBullCond2 = priceHL2 and oscLL2 and plFound2 //Regular Bearish oscLH2 = osc2[2] < ta.valuewhen(phFound2, osc2[2], 1) and inRange(phFound2[1]) priceHH2 = high[2] > ta.valuewhen(phFound2, high[2], 1) bearCond2 = priceHH2 and oscLH2 and phFound2 //Hidden Bearish oscHH2 = osc2[2] > ta.valuewhen(phFound2, osc2[2], 1) and inRange(phFound2[1]) priceLH2 = high[2] < ta.valuewhen(phFound2, high[2], 1) hiddenBearCond2 = priceLH2 and oscHH2 and phFound2 //DOWNTREND DIVERGENCE osc3 = DTrk //Pivots plFound3 = na(ta.pivotlow(osc3, 5, 2)) ? false : true phFound3 = na(ta.pivothigh(osc3, 5, 2)) ? false : true //Regular Bullish oscHL3 = osc3[2] > ta.valuewhen(plFound3, osc3[2], 1) and inRange(plFound3[1]) priceLL3 = low[2] < ta.valuewhen(plFound3, low[2], 1) bullCond3 = priceLL3 and oscHL3 and plFound3 //Hidden Bullish oscLL3 = osc3[2] < ta.valuewhen(plFound3, osc3[2], 1) and inRange(plFound3[1]) priceHL3 = low[2] > ta.valuewhen(plFound3, low[2], 1) hiddenBullCond3 = priceHL3 and oscLL3 and plFound3 //Regular Bearish oscLH3 = osc3[2] < ta.valuewhen(phFound3, osc3[2], 1) and inRange(phFound3[1]) priceHH3 = high[2] > ta.valuewhen(phFound3, high[2], 1) bearCond3 = priceHH3 and oscLH3 and phFound3 //Hidden Bearish oscHH3 = osc3[2] > ta.valuewhen(phFound3, osc3[2], 1) and inRange(phFound3[1]) priceLH3 = high[2] < ta.valuewhen(phFound3, high[2], 1) hiddenBearCond3 = priceLH3 and oscHH3 and phFound3 //UPTREND SIGNALS UTSrsiXup = UTUseSrsiX and UTrk > UTrd and UTrk[1] < UTrd[1] ? 1 : 0 UTSrsiXdn = UTUseSrsiX and UTrk < UTrd and UTrk[1] > UTrd[1] ? 1 : 0 UTSrsiLup = UTUseSrsiL and UTrk < UTsablevelb ? 1 : 0 UTSrsiLdn = UTUseSrsiL and UTrk > UTsablevels ? 1 : 0 UTSrsiPup = UTUseSrsiP and UTrk > UTrd ? 1 : 0 UTSrsiPdn = UTUseSrsiP and UTrk < UTrd ? 1 : 0 UTSrsiDup = UTUseSrsiD and bullCond2 ? 1 : 0 UTSrsiDdn = UTUseSrsiD and bearCond2 ? 1 : 0 //DOWNTREND SIGNALS DTSrsiXup = DTUseSrsiX and DTrk > DTrd and DTrk[1] < DTrd[1] ? 1 : 0 DTSrsiXdn = DTUseSrsiX and DTrk < DTrd and DTrk[1] > DTrd[1] ? 1 : 0 DTSrsiLup = DTUseSrsiL and DTrk < DTsablevelb ? 1 : 0 DTSrsiLdn = DTUseSrsiL and DTrk > DTsablevels ? 1 : 0 DTSrsiPup = DTUseSrsiP and DTrk > DTrd ? 1 : 0 DTSrsiPdn = DTUseSrsiP and DTrk < DTrd ? 1 : 0 DTSrsiDup = DTUseSrsiD and bullCond3 ? 1 : 0 DTSrsiDdn = DTUseSrsiD and bearCond3 ? 1 : 0 //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //WAVETREND▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //UPTREND OPTIONS //Cross UTUsewtX = input(false, "WaveTrend Cross", group="UPTREND 🠕 WAVETREND SIGNALS") UTReqwtXscore = UTUsewtX ? 1 : 0 //Level UTUsewtL = input(true, "WaveTrend Level", group="UPTREND 🠕 WAVETREND SIGNALS") UTwablevelb = input.int(82, "Buy Below Level", group="UPTREND 🠕 WAVETREND SIGNALS") UTwablevels = input.int(15, "Sell Above Level", group="UPTREND 🠕 WAVETREND SIGNALS") UTReqwtLscore = UTUsewtL ? 1 : 0 //Position UTUsewtP = input(false, "WaveTrend Position", group="UPTREND 🠕 WAVETREND SIGNALS") UTReqwtPscore = UTUsewtP ? 1 : 0 //Divergence UTUsewtD = input(false, "WaveTrend Divergence", group="UPTREND 🠕 WAVETREND SIGNALS") UTReqwtDscore = UTUsewtD ? 1 : 0 //DOWNTREND OPTIONS //Cross DTUsewtX = input(false, "WaveTrend Cross", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTReqwtXscore = DTUsewtX ? 1 : 0 //Level DTUsewtL = input(false, "WaveTrend Level", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTwablevelb = input.int(0, "Buy Below Level", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTwablevels = input.int(0, "Sell Above Level", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTReqwtLscore = DTUsewtL ? 1 : 0 //Position DTUsewtP = input(false, "WaveTrend Position", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTReqwtPscore = DTUsewtP ? 1 : 0 //Divergence DTUsewtD = input(false, "WaveTrend Divergence", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTReqwtDscore = DTUsewtD ? 1 : 0 //UPTREND INPUTS //WT UTlenC = input.int(9, title="Channel Length", group="UPTREND 🠕 WAVETREND SIGNALS") UTlenA = input.int(12, title="Average Length", group="UPTREND 🠕 WAVETREND SIGNALS") UTap = hlc3 UTesa = ta.ema(UTap, UTlenC) UTd1 = ta.ema(math.abs(UTap - UTesa), UTlenC) UTci = (UTap - UTesa) / (0.015 * UTd1) UTtci = ta.ema(UTci, UTlenA) UTwt1 = UTtci UTwt2 = ta.sma(UTwt1, 4) UTwthist = UTwt2 - UTwt1 //DOWNTREND INPUTS //WT DTlenC = input.int(9, title="Channel Length", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTlenA = input.int(12, title="Average Length", group="DOWNTREND 🠗 WAVETREND SIGNALS") DTap = hlc3 DTesa = ta.ema(DTap, DTlenC) DTd1 = ta.ema(math.abs(DTap - DTesa), DTlenC) DTci = (DTap - DTesa) / (0.015 * DTd1) DTtci = ta.ema(DTci, DTlenA) DTwt1 = DTtci DTwt2 = ta.sma(DTwt1, 4) DTwthist = DTwt2 - DTwt1 //UPTREND DIVERGENCE osc4 = UTwt1 //Pivots plFound4 = na(ta.pivotlow(osc4, 5, 2)) ? false : true phFound4 = na(ta.pivothigh(osc4, 5, 2)) ? false : true //Regular Bullish oscHL4 = osc4[2] > ta.valuewhen(plFound4, osc4[2], 1) and inRange(plFound4[1]) priceLL4 = low[2] < ta.valuewhen(plFound4, low[2], 1) bullCond4 = priceLL4 and oscHL4 and plFound4 //Hidden Bullish oscLL4 = osc4[2] < ta.valuewhen(plFound4, osc4[2], 1) and inRange(plFound4[1]) priceHL4 = low[2] > ta.valuewhen(plFound4, low[2], 1) hiddenBullCond4 = priceHL4 and oscLL4 and plFound4 //Regular Bearish oscLH4 = osc4[2] < ta.valuewhen(phFound4, osc4[2], 1) and inRange(phFound4[1]) priceHH4 = high[2] > ta.valuewhen(phFound4, high[2], 1) bearCond4 = priceHH4 and oscLH4 and phFound4 //Hidden Bearish oscHH4 = osc4[2] > ta.valuewhen(phFound4, osc4[2], 1) and inRange(phFound4[1]) priceLH4 = high[2] < ta.valuewhen(phFound4, high[2], 1) hiddenBearCond4 = priceLH4 and oscHH4 and phFound4 //DOWNTREND DIVERGENCE osc5 = DTwt1 //Pivots plFound5 = na(ta.pivotlow(osc5, 5, 2)) ? false : true phFound5 = na(ta.pivothigh(osc5, 5, 2)) ? false : true //Regular Bullish oscHL5 = osc5[2] > ta.valuewhen(plFound5, osc5[2], 1) and inRange(plFound5[1]) priceLL5 = low[2] < ta.valuewhen(plFound5, low[2], 1) bullCond5 = priceLL5 and oscHL5 and plFound5 //Hidden Bullish oscLL5 = osc5[2] < ta.valuewhen(plFound5, osc5[2], 1) and inRange(plFound5[1]) priceHL5 = low[2] > ta.valuewhen(plFound5, low[2], 1) hiddenBullCond5 = priceHL5 and oscLL5 and plFound5 //Regular Bearish oscLH5 = osc5[2] < ta.valuewhen(phFound5, osc5[2], 1) and inRange(phFound5[1]) priceHH5 = high[2] > ta.valuewhen(phFound5, high[2], 1) bearCond5 = priceHH5 and oscLH5 and phFound5 //Hidden Bearish oscHH5 = osc5[2] > ta.valuewhen(phFound5, osc5[2], 1) and inRange(phFound5[1]) priceLH5 = high[2] < ta.valuewhen(phFound5, high[2], 1) hiddenBearCond5 = priceLH5 and oscHH5 and phFound5 //UPTREND SIGNALS UTwtXup = UTUsewtX and UTwt1 > UTwt2 and UTwt1[1] < UTwt2[1] and UTwt1 < 0 ? 1 : 0 UTwtXdn = UTUsewtX and UTwt1 < UTwt2 and UTwt1[1] > UTwt2[1] and UTwt1 > 0 ? 1 : 0 UTwtLup = UTUsewtL and UTwt1 < UTwablevelb ? 1 : 0 UTwtLdn = UTUsewtL and UTwt1 > UTwablevels ? 1 : 0 UTwtPup = UTUsewtP and UTwt1 > UTwt2 ? 1 : 0 UTwtPdn = UTUsewtP and UTwt1 < UTwt2 ? 1 : 0 UTwtDup = UTUsewtD and bullCond4 ? 1 : 0 UTwtDdn = UTUsewtD and bearCond4 ? 1 : 0 //DOWNTREND SIGNALS DTwtXup = DTUsewtX and DTwt1 > DTwt2 and DTwt1[1] < DTwt2[1] and DTwt1 < 0 ? 1 : 0 DTwtXdn = DTUsewtX and DTwt1 < DTwt2 and DTwt1[1] > DTwt2[1] and DTwt1 > 0 ? 1 : 0 DTwtLup = DTUsewtL and DTwt1 < DTwablevelb ? 1 : 0 DTwtLdn = DTUsewtL and DTwt1 > DTwablevels ? 1 : 0 DTwtPup = DTUsewtP and DTwt1 > DTwt2 ? 1 : 0 DTwtPdn = DTUsewtP and DTwt1 < DTwt2 ? 1 : 0 DTwtDup = DTUsewtD and bullCond5 ? 1 : 0 DTwtDdn = DTUsewtD and bearCond5 ? 1 : 0 //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //COLLECT SIGNALS▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //UT REQUIRED SCORES UTReqScore = UTReqmaXscore + UTReqmaPscore + UTReqmaHscore + UTReqSrsiXscore + UTReqSrsiLscore + UTReqSrsiPscore + UTReqSrsiDscore + UTReqwtXscore + UTReqwtLscore + UTReqwtPscore + UTReqwtDscore //DT REQUIRED SCORES DTReqScore = DTReqmaXscore + DTReqmaPscore + DTReqmaHscore + DTReqSrsiXscore + DTReqSrsiLscore + DTReqSrsiPscore + DTReqSrsiDscore + DTReqwtXscore + DTReqwtLscore + DTReqwtPscore + DTReqwtDscore //UT SIGNAL SCORES UTSigB = UTmaXup + UTmaPup + UTmaHup + UTSrsiXup + UTSrsiLup + UTSrsiPup + UTSrsiDup + UTwtXup + UTwtLup + UTwtPup + UTwtDup UTSigS = UTmaXdn + UTmaPdn + UTmaHdn + UTSrsiXdn + UTSrsiLdn + UTSrsiPdn + UTSrsiDdn + UTwtXdn + UTwtLdn + UTwtPdn + UTwtDdn //DT SIGNAL SCORES DTSigB = DTmaXup + DTmaPup + DTmaHup + DTSrsiXup + DTSrsiLup + DTSrsiPup + DTSrsiDup + DTwtXup + DTwtLup + DTwtPup + DTwtDup DTSigS = DTmaXdn + DTmaPdn + DTmaHdn + DTSrsiXdn + DTSrsiLdn + DTSrsiPdn + DTSrsiDdn + DTwtXdn + DTwtLdn + DTwtPdn + DTwtDdn //UT BUY AND SELL UTNormB = UTSigB == UTReqScore ? 1 : na UTNormS = UTSigS == UTReqScore ? 1 : na //DT BUY AND SELL DTNormB = DTSigB == DTReqScore ? 1 : na DTNormS = DTSigS == DTReqScore ? 1 : na //CHECK TREND DIRECTION UpTrend = mat > mat[1] BCond = UpTrend ? UTNormB : DTNormB SCond = UpTrend ? UTNormS : DTNormS //FINALIZE LongEntryFinal = TrendTrade ? BCond and mat > mat[1] : BCond LongExitFinal = TrendTrade ? SCond and mat > mat[1] : SCond ShortEntryFinal = TrendTrade ? SCond and mat < mat[1] : SCond ShortExitFinal = TrendTrade ? BCond and mat < mat[1] : BCond //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //STOP LOSS & TAKE PROFIT▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //UT MINIMUM PROFIT UTmpconvertL = strategy.position_avg_price * (1 + UTminProf) UTmpconvertS = strategy.position_avg_price * (1 - UTminProf) UTmpdefineL = TradeDir == "LONG" ? (UTmpconvertL < close and strategy.openprofit > 0) and UTsellProf : na UTmpdefineS = TradeDir == "SHORT" ? (UTmpconvertS > close and strategy.openprofit > 0) and UTsellProf : na UTSPL = LongExitFinal and UTmpdefineL UTSPS = ShortExitFinal and UTmpdefineS //DT MINIMUM PROFIT DTmpconvertL = strategy.position_avg_price * (1 + DTminProf) DTmpconvertS = strategy.position_avg_price * (1 - DTminProf) DTmpdefineL = TradeDir == "LONG" ? (DTmpconvertL < close and strategy.openprofit > 0) and DTsellProf : na DTmpdefineS = TradeDir == "SHORT" ? (DTmpconvertS > close and strategy.openprofit > 0) and DTsellProf : na DTSPL = LongExitFinal and DTmpdefineL DTSPS = ShortExitFinal and DTmpdefineS //COLLECT sellProf = UpTrend ? UTsellProf : DTsellProf SPL = UpTrend ? UTSPL : DTSPL SPS = UpTrend ? UTSPS : DTSPS //UT TAKE PROFIT UTtpconvertL = strategy.position_avg_price * (1 + UTTPperc) UTtpconvertS = strategy.position_avg_price * (1 - UTTPperc) UTTPL = TradeDir == "LONG" ? (UTtpconvertL < close) and UTuseTP : na UTTPS = TradeDir == "SHORT" ? (UTtpconvertS > close) and UTuseTP : na //DT TAKE PROFIT DTtpconvertL = strategy.position_avg_price * (1 + DTTPperc) DTtpconvertS = strategy.position_avg_price * (1 - DTTPperc) DTTPL = TradeDir == "LONG" ? (DTtpconvertL < close) and DTuseTP : na DTTPS = TradeDir == "SHORT" ? (DTtpconvertS > close) and DTuseTP : na //COLLECT TPL = UpTrend ? UTTPL : DTTPL TPS = UpTrend ? UTTPS : DTTPS //UT STOP LOSS UTslconvertL = strategy.position_avg_price * (1 + UTSLperc) UTslconvertS = strategy.position_avg_price * (1 - UTSLperc) UTSLL = TradeDir == "LONG" ? (UTslconvertL > close) and UTuseSL : na UTSLS = TradeDir == "SHORT" ? (UTslconvertS < close) and UTuseSL : na //DT STOP LOSS DTslconvertL = strategy.position_avg_price * (1 + DTSLperc) DTslconvertS = strategy.position_avg_price * (1 - DTSLperc) DTSLL = TradeDir == "LONG" ? (DTslconvertL > close) and DTuseSL : na DTSLS = TradeDir == "SHORT" ? (DTslconvertS < close) and DTuseSL : na //COLLECT SLL = UpTrend ? UTSLL : DTSLL SLS = UpTrend ? UTSLS : DTSLS //UT TRADE EXPIRE entrypos = strategy.opentrades == 1 and strategy.opentrades[1] < 1 UTexpirebars = UTuseTE ? UTTEbars : 1000000 UTTE = ta.barssince(entrypos) >= UTexpirebars //DT TRADE EXPIRE DTexpirebars = DTuseTE ? DTTEbars : 1000000 DTTE = ta.barssince(entrypos) >= DTexpirebars //COLLECT TE = UpTrend ? UTTE : DTTE //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //PLOTSHAPES▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //LONG plotshape((TradeDir == "LONG") and LongEntryFinal, location=location.belowbar, style=shape.arrowup, color=color.new(#26a69a, 100), text="⌃", textcolor=#26a69a, size=size.tiny, title="Long BUY Label") plotshape((TradeDir == "LONG") and LongExitFinal, location=location.abovebar, style=shape.arrowdown, color=color.new(#ef5350, 100), text="⌄", textcolor=#ef5350, size=size.tiny, title="Long SELL Label") //SHORT plotshape((TradeDir == "SHORT") and ShortEntryFinal, location=location.abovebar, style=shape.arrowdown, color=color.new(#ef5350, 100), text="⌄", textcolor=#ef5350, size=size.tiny, title="Short SELL Label") plotshape((TradeDir == "SHORT") and ShortExitFinal, location=location.belowbar, style=shape.arrowup, color=color.new(#26a69a, 100), text="⌃", textcolor=#26a69a, size=size.tiny, title="Short BUY Label") //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //STRATEGY TRADES▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ //LONG if (TradeDir == "LONG") and LongEntryFinal strategy.entry("inLong", strategy.long, comment="LEn") if (TradeDir == "LONG") and sellProf ? SPL : LongExitFinal strategy.close("inLong", comment="LEx") //SHORT if (TradeDir == "SHORT") and ShortEntryFinal strategy.entry("inShort", strategy.short, comment="SEn") if (TradeDir == "SHORT") and sellProf ? SPS : ShortExitFinal strategy.close("inShort", comment="SEx") //TAKE if TPL strategy.close("inLong", comment="TP") if TPS strategy.close("inShort", comment="TP") //STOP if SLL strategy.close("inLong", comment="SL") if SLS strategy.close("inShort", comment="SL") //EXPIRE if TE strategy.close_all(comment="TE") //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ //////////////////////////////////////////////////////////////////////////////// //ALERTS▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ useentryalert = input(defval=true, title="Use ENTRY Alert", group="Custom Alert Messages") entrystring = input.string(title="Entry Alert Message", defval="ENTRY", confirm=false, group="Custom Alert Messages") useexitalert = input(defval=true, title="Use EXIT Alert", group="Custom Alert Messages") exitstring = input.string(title="Exit Alert Message", defval="EXIT", confirm=false, group="Custom Alert Messages") usetakealert = input(defval=true, title="Use TAKE Alert", group="Custom Alert Messages") takestring = input.string(title="Take Profit Alert Message", defval="TAKE", confirm=false, group="Custom Alert Messages") usestopalert = input(defval=true, title="Use STOP Alert", group="Custom Alert Messages") stopstring = input.string(title="Stop Loss Alert Message", defval="STOP", confirm=false, group="Custom Alert Messages") useexpirealert = input(defval=true, title="Use EXPIRE Alert", group="Custom Alert Messages") expirestring = input.string(title="Expire Trade Alert Message", defval="EXPIRE", confirm=false, group="Custom Alert Messages") //LONG if ((TradeDir == "LONG") and LongEntryFinal) and useentryalert alert("{\"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) if (TradeDir == "LONG") and (UTsellProf ? SPL : LongExitFinal) and useexitalert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) //SHORT if ((TradeDir == "SHORT") and ShortEntryFinal) and useentryalert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) if (TradeDir == "SHORT") and (UTsellProf ? SPL : ShortExitFinal) and useexitalert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) //OTHER if TPL or TPS and usetakealert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) if SLL or SLS and usestopalert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) if TE and useexpirealert alert("{\"action\": \"close_at_market_price\", \"message_type\": \"bot\", \"bot_id\": 7040545, \"email_token\": \"9b842a1b-9cb4-48ac-9ed4-524c98557e5f\", \"delay_seconds\": 0}", alert.freq_once_per_bar) //END▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ ////////////////////////////////////////////////////////////////////////////////