The core idea of this strategy is to combine the dual thrust indicator with a basic moving average line to implement trend following and trend reversal trading. When the price is in the same direction as the indicator, follow the trend; when the price is in the opposite direction of the indicator, take reversal trades.
The strategy is mainly based on three custom indicators:
Dual Thrust Indicator (Trend): Calculates the relationship between the price and the overbought/oversold channel to determine the bullish and bearish trends, returning 1, 0, -1 three states.
Overbought/Oversold Channel (Tsl): Calculates the upper and lower rails with reference to ATR. Breaking through the upper rail is regarded as overbought, and breaking through the lower rail is regarded as oversold.
Basic Moving Average Line (MA): Calculates the 20-period simple moving average of the closing price.
Specifically, the strategy judges whether the price is in bullish, sideways or bearish state according to the dual thrust indicator value. When the dual thrust indicator is 1, it means a bullish state; when the dual thrust indicator is -1, it means a bearish state. At this point, if the price is in the same direction as the indicator, a trend following strategy is adopted, going long or short at the right spot. If the price is in the opposite direction of the indicator, such as the indicator showing bullish while the price breaking through the lower rail, a reversal strategy is adopted by going short to capture profits.
In addition, the breaking through of price on moving average line also serves as an auxiliary signal to guide the trading direction. Go long when the price breaks through the average line upwards, and go short when the price breaks through the average line downwards.
The specific long trade strategies are as follows:
Dual thrust indicator > 0, price rises to break through the upper rail, which belongs to trend following, go long.
Dual thrust indicator < 0, price falls to break through the lower rail, which belongs to trend reversal, go short.
Closing price > Opening price > Pivot level, regarded as breaking the pivot to go long, go long.
Closing price breaks through upper rail, and closing price > Moving average line, go long.
The short trade strategies are as follows:
Dual thrust indicator < 0, price falls to break through the lower rail, which belongs to trend following, go short.
Dual thrust indicator > 0, price rises to break through the upper rail, which belongs to trend reversal, go long.
Opening price > Closing price < Pivot level, regarded as breaking the pivot to go short, go short.
Closing price breaks through lower rail, and closing price < Moving average line, go short.
The exit strategy is simple by stopping loss when price breaks through the overbought/oversold channel again.
The strategy has the following advantages:
The dual thrust indicator can accurately determine the market trend and is the core indicator of the strategy.
The overbought/oversold channel combined with the indicator can discover potential reversal opportunities.
The basic moving average line can serve as an auxiliary filtering signal to avoid false breakouts.
The pivot point combined with the dual thrust indicator forms high-probability trading spots.
It has both trend following and reversal trading capabilities for more profit opportunities.
The overbought/oversold channel stop loss is simple and clear, which is beneficial for risk control.
The strategy also has the following risks:
The dual thrust indicator may give out wrong signals, and needs to be filtered with other indicators.
Breakout trading is prone to being trapped, so strict stop loss is required.
Improper moving average period setting may miss trends or generate false signals.
The pivot points need backtesting to verify probability reliability.
The overbought/oversold channel needs optimization of parameters to adapt to different products.
Mismatch of indicator parameters may lead to frequent trading.
To address these risks, the following measures can be taken:
Combine other indicators like K-line, volume to verify dual thrust indicator signals.
Strictly follow the overbought/oversold channel stop loss strategy for quick stop loss.
Test different moving average period parameters to find the optimal one.
Fully backtest the pivot point strategy probability.
Optimize parameters to find the optimal combination for each product.
Adjust indicator parameters to keep the overall system running smoothly.
The strategy can also be optimized in the following aspects:
Increase machine learning algorithms to train the dual thrust indicator with big data. This can improve accuracy and reduce false signals.
Add adaptive channels to automatically adjust channel parameters based on market volatility. This can improve breakout accuracy.
Use deep learning to extract more changeable indicators to optimize entry and exit strategies.
Add advanced stop loss algorithms that can track trends for stop loss, avoiding being stopped out by reversals.
Conduct parameter optimization and combination tests to improve overall strategy stability.
Add risk management modules for more scientific risk control.
The strategy combines trend following and trend reversal organically by judging market structure with the dual thrust indicator and generating trading signals with channels and moving average lines. It has the advantages of good indicator effectiveness, abundant trading opportunities, and clear stop loss. At the same time, it also has certain risks that need further optimization to improve stability. Overall, the strategy fully integrates the ideas of trend trading and reversal trading, and is worth further research and application.
/*backtest start: 2023-08-25 00:00:00 end: 2023-09-24 00:00:00 period: 2h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © amysojexson //@version=3 strategy(title="Pivots strategy", overlay=true) // Input settings // Create a pull-down menu for the pivot type pivotType = input(title="Pivot Type", options=["Daily", "Intraday", "Weekly"], defval="Daily") // Make toggles for pivot level options plotPP = input(title="Plot PP", type=bool, defval=true) plotS1R1 = input(title="Plot S1 and R1", type=bool, defval=true) plotS2R2 = input(title="Plot S2 and R2", type=bool, defval=true) plotS3R3 = input(title="Plot S3 and R3", type=bool, defval=true) plotTCBC = input(title="Plot S3 and R3", type=bool, defval=true) // Configure session options sessRange = input(title="Trading Session", defval="0800-1600") showSess = input(title="Highlight Session?", type=bool, defval=false) // Enable or disable pivot labels showLabels = input(title="Show Labels?", type=bool, defval=false) // Step 2. Calculate indicator values // Create a function to fetch daily and weekly data GetData(res, data) => security(syminfo.tickerid, res, data[1], lookahead=barmerge.lookahead_on) // Fetch daily and weekly price data dailyHigh = GetData("D", high) dailyLow = GetData("D", low) dailyClose = GetData("D", close) weeklyHigh = GetData("W", high) weeklyLow = GetData("W", low) weeklyClose = GetData("W", close) // Determine session pivot data // First see how the price bar relates to // the session time range inSession = not na(time(timeframe.period, sessRange)[1]) sessStart = inSession and not inSession[1] sessEnd = not inSession and inSession[1] // Determine session price data sessHigh = 0.0 sessLow = 0.0 sessClose = 0.0 sessHigh := sessStart ? high : inSession ? max(high, sessHigh[1]) : na sessLow := sessStart ? low : inSession ? min(low, sessLow[1]) : na sessClose := sessEnd ? close[1] : na // Compute high, low, close from previous intra-day session highPrevSess = 0.0 lowPrevSess = 0.0 closePrevSess = 0.0 highPrevSess := sessEnd ? fixnan(sessHigh) : highPrevSess[1] lowPrevSess := sessEnd ? fixnan(sessLow) : lowPrevSess[1] closePrevSess := sessEnd ? fixnan(sessClose) : closePrevSess[1] // Now figure out which kind of price data // to use for the pivot calculation theHigh = if (pivotType == "Daily") dailyHigh else if (pivotType == "Intraday") highPrevSess else weeklyHigh theLow = if (pivotType == "Daily") dailyLow else if (pivotType == "Intraday") lowPrevSess else weeklyLow theClose = if (pivotType == "Daily") dailyClose else if (pivotType == "Intraday") closePrevSess else weeklyClose // Finally calculate the pivot levels pp = (theHigh + theLow + theClose) / 3 bc= (theHigh + theLow)/2 tc= (pp-bc)+pp r1 = pp+(.382*(theHigh-theLow)) s1 = pp-(.382*(theHigh-theLow)) r2 = pp +(.618*(theHigh-theLow)) s2 = pp -(.618*(theHigh-theLow)) r3 = pp +(1*(theHigh-theLow)) s3 = pp -(1*(theHigh-theLow)) // Step 3. Output indicator data // Plot the various pivot levels plot(series=plotS3R3 ? r3 : na, title="R3", style=circles, linewidth=1, color=#0023FF) plot(series=plotS2R2 ? r2 : na, title="R2", style=circles, linewidth=1, color=#1E90FF) plot(series=plotS1R1 ? r1 : na, title="R1", style=circles, linewidth=1, color=#09E0F3) plot(series=plotTCBC ? tc : na, title="TC", style=circles, linewidth=.75, color=#FF00D1) plot(series=plotPP ? pp : na, title="PP", style=circles, linewidth=1, color=#000000) plot(series=plotTCBC ? bc : na, title="BC", style=circles, linewidth=.75, color=#FF00D1) plot(series=plotS1R1 ? s1 : na, title="S1", style=circles, linewidth=1, color=#09E0F3) plot(series=plotS2R2 ? s2 : na, title="S2", style=circles, linewidth=1, color=#1E90FF) plot(series=plotS3R3 ? s3 : na, title="S3", style=circles, linewidth=1, color=#0023FF) // Display the pivot names on the chart, if applicable newPivots = (showLabels == false) ? false : (pivotType == "Intraday") ? sessEnd : (pivotType == "Daily") ? dayofmonth != dayofmonth[1] : dayofweek == monday and dayofmonth != dayofmonth[1] plotchar(series=newPivots and plotS3R3 ? r3 : na, char='', text="R3", offset=1, location=location.absolute, color=#0023FF, title="R3 label") plotchar(series=newPivots and plotS2R2 ? r2 : na, char='', text="R2", offset=1, location=location.absolute, color=#1E90FF, title="R2 label") plotchar(series=newPivots and plotS1R1 ? r1 : na, char='', text="R1", offset=1, location=location.absolute, color=#09E0F3, title="R1 label") plotchar(series=newPivots and plotTCBC ? r1 : na, char='', text="TC", offset=1, location=location.absolute, color=#FF00D1, title="TC label") plotchar(series=newPivots and plotTCBC ? r1 : na, char='', text="BC", offset=1, location=location.absolute, color=#FF00D1, title="BC label") plotchar(series=newPivots and plotS1R1 ? s1 : na, char='', text="S1", offset=1, location=location.absolute, color=#09E0F3, title="S1 label") plotchar(series=newPivots and plotS2R2 ? s2 : na, char='', text="S2", offset=1, location=location.absolute, color=#1E90FF, title="S2 label") plotchar(series=newPivots and plotS3R3 ? s3 : na, char='', text="S3", offset=1, location=location.absolute, color=#0023FF, title="S3 label") // Highlight the intra-day price data session on the chart bgcolor(color=showSess and inSession and (pivotType == "Intraday") ? orange : na, transp=95) // Step 4. Create indicator alerts alertcondition(condition=cross(close, s3), title="Pivot S3 Cross", message="Prices crossed Pivot S3 level") alertcondition(condition=cross(close, s2), title="Pivot S2 Cross", message="Prices crossed Pivot S2 level") alertcondition(condition=cross(close, s1), title="Pivot S1 Cross", message="Prices crossed Pivot S1 level") alertcondition(condition=cross(close, tc), title="Pivot TC Cross", message="Prices crossed Pivot TC level") alertcondition(condition=cross(close, pp), title="Pivot PP Cross", message="Prices crossed the main Pivot Point level") alertcondition(condition=cross(close, bc), title="Pivot BC Cross", message="Prices crossed Pivot BC level") alertcondition(condition=cross(close, r1), title="Pivot R1 Cross", message="Prices crossed Pivot R1 level") alertcondition(condition=cross(close, r2), title="Pivot R2 Cross", message="Prices crossed Pivot R2 level") alertcondition(condition=cross(close, r3), title="Pivot R3 Cross", message="Prices crossed Pivot R3 level") MA = sma(close, 20) plot(MA, color=red) Factor = input(2, type=float) Pd = input(10, minval=1,maxval = 100) Up = hl2-(Factor*atr(Pd)) Dn = hl2+(Factor*atr(Pd)) TrendUp = 0.0 TrendUp := close[1]>TrendUp[1]? max(Up,TrendUp[1]) : Up TrendDown = 0.0 TrendDown := close[1]<TrendDown[1]? min(Dn,TrendDown[1]) : Dn Trend = 0.0 Trend := close > TrendDown[1] ? 1: close< TrendUp[1]? -1: nz(Trend[1],1) Tsl = Trend==1? TrendUp: TrendDown plot(Tsl, color=blue) if close>open if open<pp if close>pp if close>MA strategy.entry("long", true) if close<open if open>pp if close<pp if close<MA strategy.entry("short", false) strategy.close("long", when = open<Tsl) strategy.close("short", when = open>Tsl)