다중 시간 프레임 확률적 RSI 크로스오버 전략

RSI STOCH RSI MTF TRENDING MARKETS STOP LOSS MULTI-STAGE TP
생성 날짜: 2025-06-05 13:13:32 마지막으로 수정됨: 2025-06-05 13:13:32
복사: 0 클릭수: 336
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

다중 시간 프레임 확률적 RSI 크로스오버 전략 다중 시간 프레임 확률적 RSI 크로스오버 전략

전략 개요

다중 시간 프레임 Random Relative Strength Index (RSI) 은 Stochastic RSI (random Relative Strength Index) 를 기반으로 한 복합 거래 시스템으로, 5분 및 15분 두 시간 주기 데이터를 사용하여 거래 신호를 생성하고 확인합니다. 이것은 명확한 입문 조건, 스톱 손실 제어 및 단계별 수익 프로그램을 포함하는 완전한 거래 시스템입니다. 이 전략은 시장의 과매 / 과매 상태를 특별히 고려하여 가격 동력의 전환을 캡처하여 수익을 창출합니다.

이 전략은 5분 차트에서 작동하지만 15분 차트에서 데이터를 참조하여 거래 신호를 확인합니다. 이는 다중 시간 프레임 분석의 깊이를 나타냅니다. 이 전략은 다중 헤드 및 빈 헤드 거래에 대해 다른 파라미터 설정을 채택하여 전체적인 낙관적 인 시장 환경에 맞게 설계되었습니다.

전략 원칙

이 전략의 핵심 원칙은 Stochastic RSI 지표의 교차 신호를 기반으로, 여러 시간 프레임 확인 메커니즘과 결합하여 낮은 품질의 신호를 필터링합니다. 구체적인 작업 과정은 다음과 같습니다:

  1. 초기 발사 신호 ((5분 시간 프레임)

    • 다중 헤드 신호: 5 분 차트에서 Stoch RSI의 K 선이 D 선을 상향으로 통과하고, 통과 시 K 값이 지정된 트리거 레벨보다 낮을 때.
    • 공백 신호: 5 분 차트에서 Stoch RSI의 K 선이 D 선을 아래로 통과하고, 통과 시 K 값이 지정된 트리거 레벨보다 높을 때 ((stoch_5min_k_short_trigger))
  2. 고위급 확인 (시간 15분)

    • 5분 초기 신호가 발동된 후, 정책은 설정된 대기 창 ((wait_window_5min_bars) 에서 15분 시간 프레임의 확인을 찾습니다.
    • 다중 머리 확인: 15분 Stoch RSI의 K선은 그것의 D선보다 엄격하게 크어야 하며, 15분 K값은 stoch_15min_long_entry_level의 설정값보다 낮아야 한다.
    • 공백 확인: 15분 Stoch RSI의 K선은 그 D선보다 엄격하게 작아야 하며, 15분 K값은 stoch_15min_short_entry_level의 설정값보다 높아야 한다.
  3. 반복 신호 필터링

    • 전략은 냉각기기 메커니즘 ((min_bars_between_signals) 을 구현하여, 같은 방향의 신호 사이에 지정된 수의 K선을 통과해야만 새로운 신호가 고려된다.
  4. 포지션 관리

    • 포지션 잠금 (Open Position Lock): 이미 매장된 포지션이 있을 때, 전략은 새로운 입문 신호를 생성하지 않는다.
    • 스톱로스 설정: 입구 K 라인의 낮은 점 ((더 많은 쌍) 또는 높은 점 ((공백 쌍) 의 설정에 따라, 후속 K 라인의 종료 가격이 이 수준을 돌파하면 스톱로스가 트리거된다.
    • 손해정지검은 수익정지검보다 우선한다.
  5. 2단계 수익 메커니즘

    • 첫 번째 단계 (TP1): 50%의 지점을 매기며 다음 두 가지 방법 중 하나를 통해 촉발됩니다.
      • 우선 순위 방식 A ((극한 K 값): 5분 또는 15분 Stoch K 값이 extreme_long_tp_level ((다중 머리) 를 초과하거나 extreme_short_tp_level ((공백 머리) 를 초과하는 경우)
      • 우선방법 B ((조건적인 5분 교차 + 15분 K값 역전): 5분 Stoch RSI의 K/D 교차가 발생했을 때 ((다중체 때 K는 아래로 D를 통과하고, 공체 때 K는 위로 D를 통과하며, 15분 Stoch K값의 “반전”이 확인되었을 때 ((현재 15분 K < 이전 15분 K는 다중체; 현재 15분 K > 이전 15분 K는 공체) )
    • 2단계 ((TP2)): 나머지 50%의 포지션을 평행하고, TP1이 트리거된 후에만 활성화되며, 5분 또는 15분 Stoch K 값이 다시 동일한 극한 수준에 도달했을 때 실행한다.

전략적 이점

  1. 다중 시간 프레임 확인 메커니즘

    • 5분 및 15분 시간 프레임의 신호를 결합함으로써, 이 전략은 가짜 신호를 줄이고 거래의 질을 향상시킵니다. 짧은 시간 프레임은 입문 기회를 제공하며, 긴 시간 프레임은 트렌드 확인을 제공하며, 이 방법은 단기 시장 소음을 효과적으로 필터링 할 수 있습니다.
  2. 오버 바이/오버 셀 조건의 정확한 위치

    • 스토카스틱 RSI는 전통적인 RSI보다 더 민감하며, 가격 동력의 변화를 더 일찍 포착할 수 있다. 이 특성을 이용한 전략은 가격이 반전될 때 거래를 하며, 진입 시기의 정확성을 향상시킨다.
  3. 단계적 정지 전략

    • 두 단계의 정지 메커니즘은 거래자가 수익의 일부를 잠금하는 동시에 더 큰 시장을 포착하기 위해 남은 포지션을 보유 할 수 있습니다. 이 방법은 위험과 수익을 균형을 맞추고 특히 변동성이 높은 시장에 적합합니다.
  4. 사용자 정의 설정

    • 전략의 매개 변수는 시장의 선호도를 반영하도록 조정할 수 있습니다. (현재의 전략은 다자 (多頭) 에 대해 더 관대합니다.) 이는 다른 시장 환경과 거래 선호도에 적응할 수 있도록 합니다.
  5. 전체적인 위험 관리

    • 명확한 손실 메커니즘은 입력 K 라인의 극치에 기반하여 각 거래에 대해 측정 가능한 위험 제어를 제공합니다. 손실을 막는 검사는 수익 검사에 우선하여 위험 제어가 항상 최우선 고려 사항이 되도록합니다.
  6. 반복 신호 필터링

    • 신호 냉각 기간을 시행함으로써 짧은 시간에 같은 방향으로 과도한 거래를 피하고 거래 비용을 줄이고 신호 품질을 향상시킵니다.

전략적 위험

  1. 매개변수 민감도

    • 이 전략은 다양한 트리거 레벨과 확인 값과 같은 여러 개의 값 변수에 의존한다. 부적절한 변수 설정은 과도한 가짜 신호를 유발하거나 중요한 거래 기회를 놓칠 수 있다. 이러한 변수들은 다양한 시장 조건에 대한 리테크를 통해 최적화되어야 한다.
  2. 스톱포트는 넓을 수 있습니다.

    • 입수 K선 극한값에 기반한 스톱 로즈는 특정 상황에서는 특히 변동성이 높은 시장에서 더 느슨할 수 있습니다. 이것은 단일 거래의 잠재적 손실이 예상보다 더 커질 수 있습니다. 과도한 위험 노출을 피하기 위해 최대 스톱 로즈 제한을 설정하는 것을 고려하십시오.
  3. 시장 조건 의존성

    • 스토카스틱 RSI는 주간 변동 시장에서 잘 작동하지만 강한 추세 시장에서 조기 반전 신호를 일으킬 수 있습니다. 이 전략은 빠른 단방향 움직임에서 좋지 않을 수 있습니다. 가격이 계속 오버 바이 또는 오버 셀 상태에서 반전하지 않을 수 있기 때문입니다.
  4. 다발성 편견

    • 현재 전략 구성은 다중 거래에 대한 선호를 나타냅니다. 이것은 곰 시장 환경에서 과도한 거래 또는 부적절한 다중 신호로 이어질 수 있습니다. 균형 유지하기 위해 시장 환경에 따라 파라미터를 조정해야합니다.
  5. 15분 지연 확인

    • 15분 시간 프레임 확인을 기다리는 것은 출입 지연을 초래할 수 있으며, 빠른 시장에서 이상적인 출입 지점을 놓칠 수 있다. 극단적으로 변동하는 시장에서 이러한 지연은 전략 성능에 상당한 영향을 미칠 수 있다.

전략 최적화 방향

  1. 동적 차단 장치

    • 현재 고정된 퍼센트 스톱은 ATR (Average True Range) 기반의 동적 스톱으로 업그레이드되거나 트렌드 상황에서 더 많은 수익을 잡기 위해 후속 손실 메커니즘을 적용할 수 있습니다. 특히 2단계 스톱의 경우 변동률이나 트렌드 강도 조정 스톱 레벨을 사용하는 것을 고려하십시오.
  2. 시장 상태는 적응합니다.

    • 시장 상태 검출 메커니즘을 도입하기 (ADX 지표와 같은 트렌드 강도를 평가하기), 전략이 다른 시장 환경에 따라 자동으로 매개 변수를 조정할 수 있도록 한다. 예를 들어, 강한 트렌드 시장에서 반전 조건을 완화하고, 흔들림 시장에서 이러한 조건을 강화한다.
  3. 다중 지표 공인

    • MACD, 브린 밴드 또는 이동 평균과 같은 추가 기술 지표를 통합하여 보조 확인 도구로 사용한다. 다중 지표 공진은 신호의 신뢰성을 높이고, 가짜 돌파구를 줄일 수 있다.
  4. 리스크 을 최적화

    • 동적인 포지션 규모 관리를 실시하고, 현재 변동성이나 최근 거래 성과에 따라 각 거래의 위험 을 조정한다. 또한, 극심한 손실을 방지하기 위해 최대 중지 손실 제한을 추가할 수 있다.
  5. 다중 시간 프레임워크 계층 확장

    • 세 번째 시간 프레임 (예: 1시간 또는 4시간) 을 추가하는 것을 고려하여 높은 수준의 시장 배경 분석을 제공하십시오.
  6. 거래 시간 필터

    • 거래 시간 필터를 추가하여 유동성이 부족하거나 불규칙하게 변동하는 시장 시간에 거래하는 것을 피하십시오. 예를 들어, 시장 개시 전과 종료 후의 높은 변동 기간 동안 거래하는 것을 제한 할 수 있습니다.

요약하다

다중 시간 프레임 무작위 상대적으로 약한 지표 교차 전략은 다중 시간 프레임 분석과 엄격한 신호 확인 과정을 통해 거래 품질을 향상시키는 구조화된 거래 시스템입니다. 이 전략의 핵심 장점은 전체적인 입시 조건과 위험 관리 시스템, 특히 2 단계의 스톱 메커니즘이 일부 포지션을 유지하면서 이익을 잠금하는 것입니다.

그러나 이 전략의 효과는 파라미터 설정과 시장 조건에 크게 의존한다. 흔들리는 시장에서 잘 수행 할 수 있지만 강한 추세 또는 높은 변동 환경에서는 조정해야 할 수 있다. 거래자는 역사적인 회귀를 통해 파라미터를 최적화하고 시장 상태 탐지 및 동적 정지 장치와 같은 기능을 추가하는 것을 고려하여 적응력을 높이는 것이 좋습니다.

이 전략은 프로그래밍 지식을 가진 중급에서 고급 거래자에게 가장 적합하며, 이러한 복잡한 거래 규칙을 이해하고 사용자 정의 할 수 있습니다. 적절한 변수 조정과 위험 관리로 이 시스템은 일간 및 단기 거래자의 도구 상자에 귀중한 구성 요소가 될 수 있습니다. 특히 시장의 동적 변화를 포착하는 데 초점을 맞춘 거래자.

전략 소스 코드
/*backtest
start: 2024-06-05 00:00:00
end: 2025-06-04 00:00:00
period: 2d
basePeriod: 2d
exchanges: [{"eid":"Futures_Binance","currency":"DOGE_USDT"}]
*/

// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Archertoria

//@version=6
strategy("System 0530 - Stoch RSI Strategy v13 SL-Priority TP-Reversal", 
         overlay=true, 
         default_qty_type=strategy.percent_of_equity, 
         default_qty_value=100, 
         calc_on_order_fills=false, 
         process_orders_on_close=true,
         margin_short=50) 

// --- Original Indicator Input Parameters ---
g_stoch = "Stochastic RSI Parameters"
rsi_len = input.int(14, "RSI Period", minval=1, group=g_stoch)
stoch_rsi_len = input.int(14, "Stochastic of RSI Period (K Period for Stoch)", minval=1, group=g_stoch)
stoch_k_smooth = input.int(3, "Stochastic %K Smoothing (D Period for Stoch)", minval=1, group=g_stoch)
stoch_d_smooth = input.int(3, "Stochastic %D Smoothing (Smoothing for final D)", minval=1, group=g_stoch)

g_signal = "Signal Trigger and Confirmation Parameters"
stoch_5min_k_long_trigger = input.float(40.0, "5-min Stoch K Long Trigger Level (K must be ≤ this value)", minval=0, maxval=100, step=0.1, group=g_signal, tooltip="On the 5-minute chart, when the K line crosses above the D line, the K value at that time must be less than or equal to this setting to initiate a long signal wait.")
stoch_5min_k_short_trigger = input.float(70.0, "5-min Stoch K Short Trigger Level (K must be ≥ this value)", minval=0, maxval=100, step=0.1, group=g_signal, tooltip="On the 5-minute chart, when the K line crosses below the D line, the K value at that time must be greater than or equal to this setting to initiate a short signal wait.")
stoch_15min_long_entry_level = input.int(50, "15-min Stoch K Long Confirmation Threshold (K must be below this value)", minval=0, maxval=100, group=g_signal, tooltip="On the 15-minute chart, for final long confirmation, the 15-minute K line value must be below this setting.")
stoch_15min_short_entry_level = input.int(70, "15-min Stoch K Short Confirmation Threshold (K must be above this value)", minval=0, maxval=100, group=g_signal, tooltip="On the 15-minute chart, for final short confirmation, the 15-minute K line value must be above this setting.")
wait_window_5min_bars = input.int(7, "Number of 5-min bars to wait for 15-min signal", minval=1, group=g_signal, tooltip="After a 5-minute signal is issued, wait for 15-minute signal confirmation within the next N 5-minute bars.")

g_repeat_filter = "Duplicate Signal Filtering Settings"
use_signal_cooldown_filter = input.bool(true, title="Enable Duplicate Signal Filter", group=g_repeat_filter, tooltip="Filters out duplicate signals in the same direction within a short period.")
min_bars_between_signals = input.int(12, title="Minimum Bars Between Same-Direction Signals", minval=1, group=g_repeat_filter, tooltip="After a signal is issued, at least this many bars must pass before another signal in the same direction can be issued.")

// --- Take Profit Parameters ---
g_tp_params = "Take Profit Parameters"
extreme_long_tp_level = input.float(95.0, "Extreme Long TP Level (Stoch K >)", minval=50, maxval=100, step=0.1, group=g_tp_params, tooltip="Direct TP for longs if 5-min OR 15-min Stoch K exceeds this.")
extreme_short_tp_level = input.float(5.0, "Extreme Short TP Level (Stoch K <)", minval=0, maxval=50, step=0.1, group=g_tp_params, tooltip="Direct TP for shorts if 5-min OR 15-min Stoch K is below this.")

// --- Strategy Specific Input Parameters ---
g_strategy = "Strategy Parameters"
leverage_multiplier = input.float(1.0, "Leverage Multiplier (Affects theoretical position size only)", minval=1.0, step=0.1, group=g_strategy, tooltip="Note: TradingView strategies do not directly simulate margin account liquidation. This leverage is used to calculate theoretical position size. Actual leverage effects must be realized with a broker that supports leverage.")

// --- Function: Calculate Stochastic RSI ---
getStochasticRSI(src, rsiLen, stochLen, kSmooth, dSmooth) =>
    rsi_val = ta.rsi(src, rsiLen)
    stoch_rsi_k_raw = ta.stoch(rsi_val, rsi_val, rsi_val, stochLen) // Stoch of RSI
    stoch_rsi_k = ta.sma(stoch_rsi_k_raw, kSmooth)
    stoch_rsi_d = ta.sma(stoch_rsi_k, dSmooth)
    [stoch_rsi_k, stoch_rsi_d]

// --- Helper Function to get only K-series for Stochastic RSI (RE-ADDED for 15-min prev K) ---
getStochKSeriesOnly(src, rsiLen, stochLen, kSmooth, dSmooth) =>
    rsi_val = ta.rsi(src, rsiLen)
    stoch_rsi_k_raw = ta.stoch(rsi_val, rsi_val, rsi_val, stochLen)
    stoch_rsi_k = ta.sma(stoch_rsi_k_raw, kSmooth)
    stoch_rsi_k // Return only the K series

// --- Time Series Data Fetching and Stochastic RSI Calculation ---
[stoch_k_15min_val, stoch_d_15min_val] = request.security(syminfo.tickerid, "15", getStochasticRSI(close, rsi_len, stoch_rsi_len, stoch_k_smooth, stoch_d_smooth), lookahead=barmerge.lookahead_off)
// RE-ADDED: K value of the PREVIOUS 15-minute bar's Stochastic RSI
stoch_k_15min_prev_tf_bar = request.security(syminfo.tickerid, "15", nz(getStochKSeriesOnly(close, rsi_len, stoch_rsi_len, stoch_k_smooth, stoch_d_smooth)[1]), lookahead=barmerge.lookahead_off)
[stoch_k_5min_val, stoch_d_5min_val] = getStochasticRSI(close, rsi_len, stoch_rsi_len, stoch_k_smooth, stoch_d_smooth)

// --- Signal Logic State Variables ---
var bool waiting_for_15m_long_confirm = false
var bool waiting_for_15m_short_confirm = false
var int bars_elapsed_in_wait_state = 0
var int last_long_signal_bar_idx = -min_bars_between_signals 
var int last_short_signal_bar_idx = -min_bars_between_signals

// --- Variables to store SL reference points from ENTRY bar ---
var float entry_bar_low_for_sl = na
var float entry_bar_high_for_sl = na

// --- Take Profit Logic State Variables ---
var bool first_tp_long_taken = false
var bool first_tp_short_taken = false
// RE-ADDED: State variables for pending TP confirmation on 15-min reversal
var bool pending_long_tp_on_15m_reversal = false
var bool pending_short_tp_on_15m_reversal = false

// --- Detect 5-minute Stochastic RSI crossover events for ENTRY ---
bool stoch_5min_crossed_up_prev_bar = ta.crossover(stoch_k_5min_val[1], stoch_d_5min_val[1])
bool stoch_5min_crossed_down_prev_bar = ta.crossunder(stoch_k_5min_val[1], stoch_d_5min_val[1])
bool condition_5min_k_level_for_long_trigger = stoch_k_5min_val[1] <= stoch_5min_k_long_trigger
bool condition_5min_k_level_for_short_trigger = stoch_k_5min_val[1] >= stoch_5min_k_short_trigger

// --- Specific 5-minute Stochastic RSI crossover for Take Profit (current bar) ---
bool stoch_5min_k_cross_under_d_tp = ta.crossunder(stoch_k_5min_val, stoch_d_5min_val) // For Long TP trigger
bool stoch_5min_k_cross_over_d_tp  = ta.crossover(stoch_k_5min_val, stoch_d_5min_val)  // For Short TP trigger

// --- RE-ADDED: 15-minute Reversal Confirmation for Take Profit ---
bool confirm_15m_reversal_for_long_tp = stoch_k_15min_val < stoch_k_15min_prev_tf_bar
bool confirm_15m_reversal_for_short_tp = stoch_k_15min_val > stoch_k_15min_prev_tf_bar

// --- Manage waiting state and tolerance period for ENTRY ---
if (strategy.position_size == 0)
    if (stoch_5min_crossed_up_prev_bar and condition_5min_k_level_for_long_trigger)
        can_trigger_new_long = not use_signal_cooldown_filter or (bar_index - last_long_signal_bar_idx >= min_bars_between_signals)
        if (can_trigger_new_long)
            waiting_for_15m_long_confirm := true
            waiting_for_15m_short_confirm := false 
            bars_elapsed_in_wait_state := 1
    else if (stoch_5min_crossed_down_prev_bar and condition_5min_k_level_for_short_trigger)
        can_trigger_new_short = not use_signal_cooldown_filter or (bar_index - last_short_signal_bar_idx >= min_bars_between_signals)
        if (can_trigger_new_short)
            waiting_for_15m_short_confirm := true
            waiting_for_15m_long_confirm := false 
            bars_elapsed_in_wait_state := 1
    else if (waiting_for_15m_long_confirm or waiting_for_15m_short_confirm)
        bars_elapsed_in_wait_state += 1
    
    if (bars_elapsed_in_wait_state > wait_window_5min_bars)
        waiting_for_15m_long_confirm := false
        waiting_for_15m_short_confirm := false
        bars_elapsed_in_wait_state := 0 
else 
    waiting_for_15m_long_confirm := false
    waiting_for_15m_short_confirm := false
    bars_elapsed_in_wait_state := 0

// --- 15-minute Stochastic RSI confirmation conditions for ENTRY (Strict Crossover) ---
bool confirm_15min_long_stoch_kd_cond = stoch_k_15min_val > stoch_d_15min_val // K must be strictly greater than D
bool confirm_15min_short_stoch_kd_cond = stoch_k_15min_val < stoch_d_15min_val // K must be strictly less than D
bool filter_15min_stoch_level_long = stoch_k_15min_val < stoch_15min_long_entry_level
bool filter_15min_stoch_level_short = stoch_k_15min_val > stoch_15min_short_entry_level

// --- Main Signal Determination (for strategy logic) ---
entry_long_signal = false
entry_short_signal = false

if (strategy.position_size == 0) 
    if (waiting_for_15m_long_confirm and bars_elapsed_in_wait_state <= wait_window_5min_bars)
        if (confirm_15min_long_stoch_kd_cond and filter_15min_stoch_level_long)
            can_confirm_new_long = not use_signal_cooldown_filter or (bar_index - last_long_signal_bar_idx >= min_bars_between_signals)
            if (can_confirm_new_long)
                entry_long_signal := true
    if (waiting_for_15m_short_confirm and bars_elapsed_in_wait_state <= wait_window_5min_bars)
        if (confirm_15min_short_stoch_kd_cond and filter_15min_stoch_level_short)
            can_confirm_new_short = not use_signal_cooldown_filter or (bar_index - last_short_signal_bar_idx >= min_bars_between_signals)
            if (can_confirm_new_short)
                entry_short_signal := true

// --- Strategy Execution Logic ---
// Reset SL ref and TP flags if position just closed
if (strategy.position_size == 0 and strategy.position_size[1] != 0) 
    first_tp_long_taken := false
    first_tp_short_taken := false
    entry_bar_low_for_sl := na 
    entry_bar_high_for_sl := na 
    pending_long_tp_on_15m_reversal := false // Reset pending TP flag
    pending_short_tp_on_15m_reversal := false // Reset pending TP flag

if (entry_long_signal) 
    strategy.entry("LE", strategy.long, comment="Long Entry")
    last_long_signal_bar_idx := bar_index 
    waiting_for_15m_long_confirm := false 
    bars_elapsed_in_wait_state := 0
    first_tp_long_taken := false 
    entry_bar_low_for_sl := low 
    entry_bar_high_for_sl := na 
    pending_long_tp_on_15m_reversal := false // Reset for new trade
    pending_short_tp_on_15m_reversal := false     

if (entry_short_signal) 
    strategy.entry("SE", strategy.short, comment="Short Entry")
    last_short_signal_bar_idx := bar_index 
    waiting_for_15m_short_confirm := false 
    bars_elapsed_in_wait_state := 0
    first_tp_short_taken := false  
    entry_bar_high_for_sl := high 
    entry_bar_low_for_sl := na    
    pending_short_tp_on_15m_reversal := false // Reset for new trade
    pending_long_tp_on_15m_reversal := false

// --- Stop Loss Logic (PRIORITY 1) ---
// Check and execute SL first. If SL triggers, position size becomes 0, preventing TP logic below from executing on the same bar.
bool sl_triggered_this_bar = false
if (strategy.position_size > 0) // If in a long trade
    if (not na(entry_bar_low_for_sl) and close < entry_bar_low_for_sl)
        strategy.close(id="LE", comment="SL Long")
        sl_triggered_this_bar := true
        pending_long_tp_on_15m_reversal := false // Ensure pending TP is cancelled if SL hits

if (strategy.position_size < 0) // If in a short trade
    if (not na(entry_bar_high_for_sl) and close > entry_bar_high_for_sl)
        strategy.close(id="SE", comment="SL Short")
        sl_triggered_this_bar := true
        pending_short_tp_on_15m_reversal := false // Ensure pending TP is cancelled if SL hits

// --- Take Profit Logic (PRIORITY 2 - only if SL did not trigger on this bar) ---
if (not sl_triggered_this_bar) // Only proceed with TP if SL hasn't already closed the position on this bar
    if (strategy.position_size > 0) // --- LONG TP LOGIC ---
        extreme_long_tp_condition = stoch_k_5min_val > extreme_long_tp_level or stoch_k_15min_val > extreme_long_tp_level
        if (extreme_long_tp_condition)
            if (not first_tp_long_taken)
                strategy.close(id="LE", comment="TP1 Long", qty_percent=50)
                first_tp_long_taken := true
            else 
                strategy.close(id="LE", comment="TP2 Long")
            pending_long_tp_on_15m_reversal := false // Reset pending state as this TP takes precedence
        else 
            // Conditional TP logic (5-min trigger + 15-min reversal)
            if (stoch_5min_k_cross_under_d_tp and not pending_long_tp_on_15m_reversal) // Set pending state
                pending_long_tp_on_15m_reversal := true
        
            if (pending_long_tp_on_15m_reversal and confirm_15m_reversal_for_long_tp) // Check for confirmation
                if (not first_tp_long_taken)
                    strategy.close(id="LE", comment="TP1 Long", qty_percent=50)
                    first_tp_long_taken := true
                else 
                    strategy.close(id="LE", comment="TP2 Long")
                pending_long_tp_on_15m_reversal := false // Reset after TP

    if (strategy.position_size < 0) // --- SHORT TP LOGIC ---
        extreme_short_tp_condition = stoch_k_5min_val < extreme_short_tp_level or stoch_k_15min_val < extreme_short_tp_level
        if (extreme_short_tp_condition)
            if (not first_tp_short_taken)
                strategy.close(id="SE", comment="TP1 Short", qty_percent=50)
                first_tp_short_taken := true
            else 
                strategy.close(id="SE", comment="TP2 Short")
            pending_short_tp_on_15m_reversal := false // Reset pending state
        else
            // Conditional TP logic (5-min trigger + 15-min reversal)
            if (stoch_5min_k_cross_over_d_tp and not pending_short_tp_on_15m_reversal) // Set pending state
                pending_short_tp_on_15m_reversal := true

            if (pending_short_tp_on_15m_reversal and confirm_15m_reversal_for_short_tp) // Check for confirmation
                if (not first_tp_short_taken)
                    strategy.close(id="SE", comment="TP1 Short", qty_percent=50)
                    first_tp_short_taken := true
                else 
                    strategy.close(id="SE", comment="TP2 Short")
                pending_short_tp_on_15m_reversal := false // Reset after TP