Mood Detector Trendshift Strategy

Pivot ATR STRUCTURE BAND
Created on: 2025-12-04 16:34:26 Modified on: 2025-12-04 16:34:26
Copy: 0 Number of hits: 30
avatar of ianzeng123 ianzeng123
2
Follow
329
Followers

 Mood Detector Trendshift Strategy  Mood Detector Trendshift Strategy

🎯 What Does This Strategy Actually Do?

You know what? This strategy is like a “mood detector” for the market! 📊 It specializes in catching those pivotal turning points that catch retail traders off guard. Imagine if you could know in advance when prices are about to “change face” - wouldn’t that be like having trading superpowers?

The core idea is super simple: when price breaks through important highs or lows, market structure shifts. It’s like climbing a mountain and suddenly realizing the path ahead goes downhill - trend changes often happen in that instant!

🔍 Key Point! Three Core Mechanisms

1. Swing Point Identification System 🎢 The strategy automatically finds important highs and lows from past periods, essentially drawing “peaks” and “valleys” for the market. When price breaks through these key levels, it signals potential trend changes!

2. ATR Filter 📏 Here’s the brilliant design! The strategy won’t be fooled by minor fluctuations - breakouts must exceed a certain ATR multiple to be valid. It’s like setting a “minimum threshold” to filter out false breakouts.

3. Premium/Discount Zone Framework 💎 Here’s the most interesting part! The strategy divides price ranges into “cheap zones” and “expensive zones.” Buy in cheap zones, sell in expensive zones - isn’t this the golden rule of investing?

🚀 What Are the Practical Advantages?

Pitfall Avoidance Guide #1: Say goodbye to chasing highs and selling lows! This strategy enters at the first sign of trend reversal, making you “smart money” instead of a “bag holder.”

Pitfall Avoidance Guide #2: Risk control is super thoughtful! It can automatically calculate position sizes based on account percentage and set zone-based stop losses, letting you sleep peacefully.

Pitfall Avoidance Guide #3: Visualization is amazing! Charts automatically mark turning points, and backgrounds change color to indicate whether you’re in cheap or expensive zones - crystal clear!

💡 What Type of Trader Is This For?

If you’re the type who likes to “buy low, sell high” but always struggles with timing, this strategy is practically tailor-made for you! It’s especially suitable for medium to long-term traders because it focuses on fundamental market structure changes, not short-term noise.

Remember, the best strategy isn’t one that makes you trade every day, but one that helps you do the right thing at the right time! 🎯

Strategy source code
/*backtest
start: 2024-12-04 00:00:00
end: 2025-12-02 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//  _______           _______  _______           _______  _       _________ _        _______ 
// (  ____ \|\     /|(  ____ \(  ____ )|\     /|(  ___  )( \      \__   __/( (    /|(  ___  )
// | (    \/| )   ( || (    \/| (    )|| )   ( || (   ) || (         ) (   |  \  ( || (   ) |
// | |      | (___) || (__    | (____)|| |   | || |   | || |         | |   |   \ | || |   | |
// | |      |  ___  ||  __)   |     __)( (   ) )| |   | || |         | |   | (\ \) || |   | |
// | |      | (   ) || (      | (\ (    \ \_/ / | |   | || |         | |   | | \   || |   | |
// | (____/\| )   ( || (____/\| ) \ \__  \   /  | (___) || (____/\___) (___| )  \  || (___) |
// (_______/|/     \|(_______/|/   \__/   \_/   (_______)(_______/\_______/|/    )_)(_______)
// © chervolino
//@version=6
strategy(title="Trendshift [CHE] Strategy", shorttitle="TrShStr", overlay=true, max_bars_back=5000, max_lines_count=500, max_labels_count=500, scale=scale.right, initial_capital=100000, commission_type=strategy.commission.percent, commission_value=0.0, process_orders_on_close=true)

// ——— SECTION: Constants & Enums
string GROUP_MARKET_STRUCTURE = "Market Structure"
string GROUP_FRAMEWORK = "Premium/Discount Framework"
string GROUP_VISUAL = "Visuals"
string GROUP_RISK = "Execution and Risk"

// ——— SECTION: Inputs (grouped; tooltips; one-row via inline)
swing_len_input = input.int(5, "Swing length", minval=1, group=GROUP_MARKET_STRUCTURE, inline="msw", tooltip="Bars left and right for major swing highs and lows.")
is_use_atr_filter_input = input.bool(true, "Use ATR filter", group=GROUP_MARKET_STRUCTURE, inline="msw", tooltip="Require breakout to exceed swing level by an ATR multiple.")
atr_len_input = input.int(14, "ATR length", minval=1, group=GROUP_MARKET_STRUCTURE, inline="atr", tooltip="ATR length for conviction and band checks.")
atr_mult_break_input = input.float(1.0, "Break ATR mult", minval=0.0, step=0.1, group=GROUP_MARKET_STRUCTURE, inline="atr", tooltip="Distance beyond swing, in ATR units, to confirm a structure shift.")

is_enable_framework_input = input.bool(true, "Enable framework", group=GROUP_FRAMEWORK, inline="fw", tooltip="Enable premium and discount band logic.")
is_persist_last_band_input = input.bool(true, "Persist band on timeout", group=GROUP_FRAMEWORK, inline="fw", tooltip="Keep last band after regime timeout.")
min_band_atr_mult_input = input.float(0.5, "Min band ATR mult", minval=0.0, step=0.1, group=GROUP_FRAMEWORK, inline="band", tooltip="Minimum band height relative to ATR.")
regime_timeout_bars_input = input.int(500, "Regime timeout bars", minval=0, group=GROUP_FRAMEWORK, inline="band", tooltip="Bars since last shift before regime reset. Zero disables timeout.")
is_invert_colors_input = input.bool(false, "Invert colors", group=GROUP_FRAMEWORK, inline="col", tooltip="Swap premium and discount colors.")

show_zone_tint_input = input.bool(true, "Show zone tint", group=GROUP_VISUAL, inline="vis", tooltip="Tint background in discount or premium bands.")
show_structure_marks_input = input.bool(true, "Show shift markers", group=GROUP_VISUAL, inline="vis", tooltip="Show first bullish and first bearish structure shift markers.")

risk_percent_input = input.float(1.0, "Risk per trade percent", minval=0.0, maxval=100.0, step=0.1, group=GROUP_RISK, inline="risk", tooltip="Account percent used to size position.")
is_use_band_for_size_input = input.bool(false, "Use band for size", group=GROUP_RISK, inline="risk", tooltip="If enabled, band height is used to scale position size.")
is_close_on_opposite_input = input.bool(true, "Flat on opposite shift", group=GROUP_RISK, inline="exit", tooltip="Close and reverse on opposite first shift.")
is_use_stop_band_input = input.bool(false, "Use stop at band", group=GROUP_RISK, inline="exit", tooltip="If enabled, band edge is used as stop distance.")
stop_band_side_input = input.string("Opposite band edge", "Stop band side", options=["Opposite band edge", "Same band edge"], group=GROUP_RISK, inline="exit", tooltip="Defines which band edge is used as stop reference.")

// ——— SECTION: Types
// (no custom types)

// ——— SECTION: Persistent Vars → Runtime Vars
var float last_swing_high = na
var float last_swing_low = na
var int last_swing_high_bar = na
var int last_swing_low_bar = na

var int regime = 0
var float band_low = na
var float band_high = na
var float struct_level = na

var int last_shift_bar = na
var bool is_last_shift_bullish = false

// ——— SECTION: Helpers (pure, no side effects)
stop_from_band(is_long, band_low_value, band_high_value, stop_side) =>
    float stop_price = na
    if is_long
        stop_price := stop_side == "Opposite band edge" ? band_low_value : band_high_value
    else
        stop_price := stop_side == "Opposite band edge" ? band_high_value : band_low_value
    stop_price

// ——— SECTION: Core Calculations

// Swings and ATR
pivot_high_value = ta.pivothigh(high, swing_len_input, swing_len_input)
pivot_low_value = ta.pivotlow(low, swing_len_input, swing_len_input)

if not na(pivot_high_value)
    last_swing_high := pivot_high_value
    last_swing_high_bar := bar_index - swing_len_input

if not na(pivot_low_value)
    last_swing_low := pivot_low_value
    last_swing_low_bar := bar_index - swing_len_input

atr_value = ta.atr(atr_len_input)

// Structure shifts
has_major_high = not na(last_swing_high)
has_major_low = not na(last_swing_low)

is_bullish_break_base = has_major_high and close > last_swing_high
is_bearish_break_base = has_major_low and close < last_swing_low

is_bullish_break = is_bullish_break_base
is_bearish_break = is_bearish_break_base

if is_use_atr_filter_input and atr_value > 0.0
    is_bullish_break := is_bullish_break_base and (close - last_swing_high) >= atr_mult_break_input * atr_value
    is_bearish_break := is_bearish_break_base and (last_swing_low - close) >= atr_mult_break_input * atr_value

is_bullish_shift = is_bullish_break and has_major_low
is_bearish_shift = is_bearish_break and has_major_high

if is_bullish_shift and is_bearish_shift
    is_bullish_shift := close >= open
    is_bearish_shift := not is_bullish_shift

is_bullish_shift_first = is_bullish_shift and (na(last_shift_bar) or not is_last_shift_bullish)
is_bearish_shift_first = is_bearish_shift and (na(last_shift_bar) or is_last_shift_bullish)

// Regime and band update
if is_bullish_shift
    regime := 1
    band_low := last_swing_low
    band_high := high
    struct_level := last_swing_high
    last_shift_bar := bar_index
    is_last_shift_bullish := true

if is_bearish_shift
    regime := -1
    band_low := low
    band_high := last_swing_high
    struct_level := last_swing_low
    last_shift_bar := bar_index
    is_last_shift_bullish := false

// Regime timeout and band clear
if regime_timeout_bars_input > 0 and regime != 0 and not is_bullish_shift and not is_bearish_shift and not na(last_shift_bar) and bar_index - last_shift_bar > regime_timeout_bars_input
    regime := 0
    if not is_persist_last_band_input
        band_low := na
        band_high := na
        struct_level := na

// Premium and discount band
is_base_valid_band = is_enable_framework_input and not na(band_low) and not na(band_high) and band_high > band_low
price_span = is_base_valid_band ? band_high - band_low : na
is_band_not_tiny = is_base_valid_band and atr_value > 0.0 and min_band_atr_mult_input > 0.0 and price_span >= min_band_atr_mult_input * atr_value or is_base_valid_band and (min_band_atr_mult_input == 0.0 or atr_value <= 0.0)
is_valid_band = is_base_valid_band and is_band_not_tiny

discount_threshold = is_valid_band ? band_low + 0.25 * price_span : na
premium_threshold = is_valid_band ? band_low + 0.75 * price_span : na

is_in_discount = is_valid_band and close <= discount_threshold
is_in_premium = is_valid_band and close >= premium_threshold

// Execution sizing and stops
acc_value = strategy.equity
base_qty = risk_percent_input > 0.0 ? acc_value * risk_percent_input * 0.01 / nz(close, 1.0) : 0.0
band_qty_factor = is_use_band_for_size_input and is_valid_band and atr_value > 0.0 ? math.min(2.0, math.max(0.25, price_span / atr_value)) : 1.0
trade_qty = base_qty * band_qty_factor

is_long_entry = is_bullish_shift_first
is_short_entry = is_bearish_shift_first

float long_stop = na
float short_stop = na

if is_use_stop_band_input and is_valid_band
    long_stop := stop_from_band(true, band_low, band_high, stop_band_side_input)
    short_stop := stop_from_band(false, band_low, band_high, stop_band_side_input)

// Strategy entries and exits
if is_long_entry and trade_qty > 0.0
    if is_close_on_opposite_input and strategy.position_size < 0
        strategy.close("Short")
    if is_use_stop_band_input and not na(long_stop)
        strategy.entry("Long", strategy.long, qty=trade_qty, stop=na, limit=na)
        strategy.exit("Long SL", "Long", stop=long_stop)
    else
        strategy.entry("Long", strategy.long, qty=trade_qty)

if is_short_entry and trade_qty > 0.0
    if is_close_on_opposite_input and strategy.position_size > 0
        strategy.close("Long")
    if is_use_stop_band_input and not na(short_stop)
        strategy.entry("Short", strategy.short, qty=trade_qty, stop=na, limit=na)
        strategy.exit("Short SL", "Short", stop=short_stop)
    else
        strategy.entry("Short", strategy.short, qty=trade_qty)

// ——— SECTION: Rendering/UI (GLOBAL ONLY; single-line calls)
discount_zone_color = is_invert_colors_input ? color.new(color.red, 30) : color.new(color.green, 30)
premium_zone_color = is_invert_colors_input ? color.new(color.green, 30) : color.new(color.red, 30)

discount_bg_color = show_zone_tint_input and is_in_discount ? color.new(discount_zone_color, 85) : na
premium_bg_color = show_zone_tint_input and is_in_premium ? color.new(premium_zone_color, 85) : na

bgcolor(discount_bg_color, title="Discount zone tint")
bgcolor(premium_bg_color, title="Premium zone tint")

plotshape(show_structure_marks_input and is_bullish_shift_first ? low : na, title="Bullish structure shift first", style=shape.triangleup, location=location.belowbar, size=size.small, color=color.new(color.lime, 0), text="Shift Up", textcolor=color.white)
plotshape(show_structure_marks_input and is_bearish_shift_first ? high : na, title="Bearish structure shift first", style=shape.triangledown, location=location.abovebar, size=size.small, color=color.new(color.red, 0), text="Shift Down", textcolor=color.white)