smc/smt indicator

package All in 1 Indicator

# indie:lang_version = 5 from indie import strategy, MainStrategyContext, param, color, plot from indie.plot import marker_style, marker_position from indie.algorithms import PivotHighLow, Atr, Ema from indie.strategies import order_side, Commission, commission_type, intrabar_order_filter from math import nan, isnan

# HTF bias: proxy EMA used (calc_on with time_frame= not supported in @strategy) # Ema(close, 21*6) approximates daily-21 EMA on a 4H chart (6 4H bars ≈ 1 day) HTF_FAST_MULT = 6 HTF_SLOW_MULT = 6 OB_POOL = 10 FVG_POOL = 10 BSL_POOL = 10 SSL_POOL = 10

def _tp_mult(choice: str, tp1: float, tp2: float, tp3: float) -> float: if choice == 'TP2': return tp2 if choice == 'TP3': return tp3 return tp1

def _position_size(cash: float, risk_pct: float, sl_dist: float) -> float: if sl_dist <= 0.0 or isnan(sl_dist): return 0.001 raw = (cash * risk_pct / 100.0) / sl_dist if raw < 0.001 or isnan(raw): return 0.001 return raw

class OBRecord: def __init__(self, ob_high: float, ob_low: float, is_bull: bool): self.ob_high: float = ob_high self.ob_low: float = ob_low self.is_bull: bool = is_bull self.state: int = 0 # 0=active, 1=mitigated, 2=breaker

class FVGRecord: def __init__(self, fvg_high: float, fvg_low: float, is_bull: bool): self.fvg_high: float = fvg_high self.fvg_low: float = fvg_low self.is_bull: bool = is_bull self.state: int = 0 # 0=active, 1=50pct-mitigated, 2=fully-mitigated

@strategy('SMC / SMT Strategy', overlay_main_pane=True, initial_capital=10000.0, commission=Commission(0.0004, commission_type.PERCENT), intrabar_order_filter=intrabar_order_filter.ON_BAR_CLOSE) @param.int('pivot_left', default=10, min=1, title='Pivot Left Bars') @param.int('pivot_right', default=10, min=1, title='Pivot Right Bars') @param.int('smt_left', default=5, min=1, title='SMT Pivot Left') @param.int('smt_right', default=5, min=1, title='SMT Pivot Right') @param.int('htf_ema_fast', default=21, min=1, title='HTF EMA Fast') @param.int('htf_ema_slow', default=50, min=1, title='HTF EMA Slow') @param.float('displacement_mult', default=1.8, min=0.1, title='OB Displacement ATR Mult') @param.int('score_threshold', default=60, min=1, max=100, title='Score Threshold') @param.float('atr_tp1', default=2.0, min=0.1, title='ATR TP1 Mult') @param.float('atr_tp2', default=3.5, min=0.1, title='ATR TP2 Mult') @param.float('atr_tp3', default=5.5, min=0.1, title='ATR TP3 Mult') @param.float('atr_sl', default=1.2, min=0.1, title='ATR SL Mult') @param.str('tp_choice', default='TP1', options=['TP1', 'TP2', 'TP3'], title='TP Level') @param.float('risk_pct', default=1.0, min=0.01, max=100.0, title='Risk % per Trade') @param.bool('show_signals', default=True, title='Show Signals') @plot.line('Equity', color=color.AQUA) @plot.marker('BUY', color=color.GREEN, text='B', style=marker_style.LABEL, position=marker_position.BELOW, size=3) @plot.marker('SELL', color=color.RED, text='S', style=marker_style.LABEL, position=marker_position.ABOVE, size=3) @plot.marker('TP', color=color.LIME, text='T', style=marker_style.CIRCLE, position=marker_position.ABOVE, size=2) @plot.marker('SL', color=color.MAROON, text='X', style=marker_style.CIRCLE, position=marker_position.BELOW, size=2) class Main(MainStrategyContext):

def __init__(self, pivot_left, pivot_right, smt_left, smt_right, htf_ema_fast, htf_ema_slow, displacement_mult, score_threshold, atr_tp1, atr_tp2, atr_tp3, atr_sl, tp_choice, risk_pct, show_signals): self._bull_obs: list[OBRecord] = [] self._bear_obs: list[OBRecord] = [] self._bull_fvgs: list[FVGRecord] = [] self._bear_fvgs: list[FVGRecord] = [] self._bsl: list[float] = [] self._ssl: list[float] = [] self._sh0: float = nan self._sh1: float = nan self._sl0: float = nan self._sl1: float = nan self._sh0_hh: bool = True self._sl0_hl: bool = True self._bias: int = 0 self._choch: bool = False self._bos: bool = False self._sell_sweep_bar: int = -999 self._buy_sweep_bar: int = -999

def calc(self, pivot_left, pivot_right, smt_left, smt_right, htf_ema_fast, htf_ema_slow, displacement_mult, score_threshold, atr_tp1, atr_tp2, atr_tp3, atr_sl, tp_choice, risk_pct, show_signals):

atr = Atr.new(14) atr_val = atr[0] ph_series, pl_series = PivotHighLow.new(self.close, pivot_left, pivot_right) ph_val = ph_series[0] pl_val = pl_series[0] smt_ph, smt_pl = PivotHighLow.new(self.close, smt_left, smt_right) htf_fast_len = htf_ema_fast * HTF_FAST_MULT htf_slow_len = htf_ema_slow * HTF_SLOW_MULT ema_fast = Ema.new(self.close, htf_fast_len) ema_slow = Ema.new(self.close, htf_slow_len) htf_bias = 1 if ema_fast[0] > ema_slow[0] else -1 cur_close = self.close[0] cur_high = self.high[0] cur_low = self.low[0] cur_open = self.open[0] cur_bar = self.bar_index

if not isnan(ph_val): self._bsl.append(ph_val) if len(self._bsl) > BSL_POOL: del self._bsl[0] if not isnan(pl_val): self._ssl.append(pl_val) if len(self._ssl) > SSL_POOL: del self._ssl[0]

if not isnan(ph_val): if isnan(self._sh0): self._sh0 = ph_val self._sh0_hh = True elif ph_val > self._sh0: self._sh1 = self._sh0 self._sh0 = ph_val self._sh0_hh = True else: self._sh1 = self._sh0 self._sh0 = ph_val self._sh0_hh = False

if not isnan(pl_val): if isnan(self._sl0): self._sl0 = pl_val self._sl0_hl = True elif pl_val > self._sl0: self._sl1 = self._sl0 self._sl0 = pl_val self._sl0_hl = True else: self._sl1 = self._sl0 self._sl0 = pl_val self._sl0_hl = False

self._bos = False self._choch = False if not isnan(self._sh0) and cur_close > self._sh0: if self._bias == -1: self._choch = True self._bias = 1 self._bos = not self._choch elif not isnan(self._sl0) and cur_close < self._sl0: if self._bias == 1: self._choch = True self._bias = -1 self._bos = not self._choch

body = abs(cur_close - cur_open) displacement = not isnan(atr_val) and body > displacement_mult * atr_val

if displacement and cur_close > cur_open: prev_close = self.close[1] prev_open = self.open[1] if prev_close < prev_open: ob = OBRecord(prev_open, prev_close, True) self._bull_obs.append(ob) if len(self._bull_obs) > OB_POOL: del self._bull_obs[0]

if displacement and cur_close < cur_open: prev_close = self.close[1] prev_open = self.open[1] if prev_close > prev_open: ob = OBRecord(prev_close, prev_open, False) self._bear_obs.append(ob) if len(self._bear_obs) > OB_POOL: del self._bear_obs[0]

i = 0 while i < len(self._bull_obs): ob = self._bull_obs[i] if ob.state == 0: if cur_low <= ob.ob_high and cur_high >= ob.ob_low: ob.state = 1 if cur_close < ob.ob_low: ob.state = 2 elif ob.state == 1: if cur_close < ob.ob_low: ob.state = 2 i = i + 1

i = 0 while i < len(self._bear_obs): ob = self._bear_obs[i] if ob.state == 0: if cur_low <= ob.ob_high and cur_high >= ob.ob_low: ob.state = 1 if cur_close > ob.ob_high: ob.state = 2 elif ob.state == 1: if cur_close > ob.ob_high: ob.state = 2 i = i + 1

if self.high[2] < cur_low: fvg = FVGRecord(cur_low, self.high[2], True) self._bull_fvgs.append(fvg) if len(self._bull_fvgs) > FVG_POOL: del self._bull_fvgs[0]

if self.low[2] > cur_high: fvg = FVGRecord(self.low[2], cur_high, False) self._bear_fvgs.append(fvg) if len(self._bear_fvgs) > FVG_POOL: del self._bear_fvgs[0]

mid_fvg: float = 0.0 i = 0 while i < len(self._bull_fvgs): fvg = self._bull_fvgs[i] if fvg.state == 0: mid_fvg = fvg.fvg_low + (fvg.fvg_high - fvg.fvg_low) * 0.5 if cur_low <= mid_fvg: fvg.state = 1 if cur_low <= fvg.fvg_low: fvg.state = 2 elif fvg.state == 1: if cur_low <= fvg.fvg_low: fvg.state = 2 i = i + 1

i = 0 while i < len(self._bear_fvgs): fvg = self._bear_fvgs[i] if fvg.state == 0: mid_fvg = fvg.fvg_low + (fvg.fvg_high - fvg.fvg_low) * 0.5 if cur_high >= mid_fvg: fvg.state = 1 if cur_high >= fvg.fvg_high: fvg.state = 2 elif fvg.state == 1: if cur_high >= fvg.fvg_high: fvg.state = 2 i = i + 1

i = 0 while i < len(self._ssl): ssl_price = self._ssl[i] if cur_low < ssl_price and cur_close > ssl_price: self._sell_sweep_bar = cur_bar i = i + 1

i = 0 while i < len(self._bsl): bsl_price = self._bsl[i] if cur_high > bsl_price and cur_close < bsl_price: self._buy_sweep_bar = cur_bar i = i + 1

sell_sweep_recent = (cur_bar - self._sell_sweep_bar) <= 1 buy_sweep_recent = (cur_bar - self._buy_sweep_bar) <= 1

in_discount = False in_premium = False if not isnan(self._sh0) and not isnan(self._sl0): swing_range = self._sh0 - self._sl0 if swing_range > 0.0: in_discount = cur_close <= self._sl0 + 0.25 * swing_range in_premium = cur_close >= self._sl0 + 0.75 * swing_range

price_in_bull_ob = False i = 0 while i < len(self._bull_obs): ob = self._bull_obs[i] if ob.state == 0 and cur_low <= ob.ob_high and cur_high >= ob.ob_low: price_in_bull_ob = True i = i + 1

price_in_bear_ob = False i = 0 while i < len(self._bear_obs): ob = self._bear_obs[i] if ob.state == 0 and cur_low <= ob.ob_high and cur_high >= ob.ob_low: price_in_bear_ob = True i = i + 1

price_in_bull_fvg = False i = 0 while i < len(self._bull_fvgs): fvg = self._bull_fvgs[i] if fvg.state == 0 and cur_low <= fvg.fvg_high and cur_high >= fvg.fvg_low: price_in_bull_fvg = True i = i + 1

price_in_bear_fvg = False i = 0 while i < len(self._bear_fvgs): fvg = self._bear_fvgs[i] if fvg.state == 0 and cur_low <= fvg.fvg_high and cur_high >= fvg.fvg_low: price_in_bear_fvg = True i = i + 1

bull_smt = not isnan(self._sl0) and not self._sl0_hl bear_smt = not isnan(self._sh0) and not self._sh0_hh

bull_score = 0 bear_score = 0 if htf_bias == 1: bull_score = bull_score + 20 if htf_bias == -1: bear_score = bear_score + 20 if self._bos and self._bias == 1: bull_score = bull_score + 15 if self._bos and self._bias == -1: bear_score = bear_score + 15 if self._choch and self._bias == 1: bull_score = bull_score + 10 if self._choch and self._bias == -1: bear_score = bear_score + 10 if price_in_bull_ob: bull_score = bull_score + 15 if price_in_bear_ob: bear_score = bear_score + 15 if price_in_bull_fvg: bull_score = bull_score + 10 if price_in_bear_fvg: bear_score = bear_score + 10 if bull_smt: bull_score = bull_score + 15 if bear_smt: bear_score = bear_score + 15 if sell_sweep_recent: bull_score = bull_score + 10 if buy_sweep_recent: bear_score = bear_score + 10 if in_discount: bull_score = bull_score + 5 if in_premium: bear_score = bear_score + 5 if bull_score > 100: bull_score = 100 if bear_score > 100: bear_score = 100

buy_signal = (bull_score >= score_threshold and htf_bias == 1 and sell_sweep_recent and (in_discount or price_in_bull_ob or price_in_bull_fvg))

sell_signal = (bear_score >= score_threshold and htf_bias == -1 and buy_sweep_recent and (in_premium or price_in_bear_ob or price_in_bear_fvg))

pos_size = self.trading.position.size + 0.0 has_position = pos_size != 0.0 chosen_tp_mult = _tp_mult(tp_choice, atr_tp1, atr_tp2, atr_tp3) buy_fired = False sell_fired = False

if not isnan(atr_val) and atr_val > 0.0: sl_dist = atr_sl * atr_val if buy_signal: if has_position and pos_size < 0.0: self.trading.place_order(order_side.BUY, size=abs(pos_size)).limit(price=cur_close).submit() if not has_position or pos_size < 0.0: tp_price = cur_close + chosen_tp_mult * atr_val sl_price = cur_close - sl_dist size = _position_size(self.trading.cash, risk_pct, sl_dist) self.trading.place_order(order_side.BUY, size=size).limit(price=cur_close).take_profit(stop=tp_price).stop_loss(stop=sl_price).submit() buy_fired = True elif sell_signal: if has_position and pos_size > 0.0: self.trading.place_order(order_side.SELL, size=abs(pos_size)).limit(price=cur_close).submit() if not has_position or pos_size > 0.0: tp_price = cur_close - chosen_tp_mult * atr_val sl_price = cur_close + sl_dist size = _position_size(self.trading.cash, risk_pct, sl_dist) self.trading.place_order(order_side.SELL, size=size).limit(price=cur_close).take_profit(stop=tp_price).stop_loss(stop=sl_price).submit() sell_fired = True

equity_val = self.trading.cash buy_marker_val = nan sell_marker_val = nan tp_marker_val = nan sl_marker_val = nan

if show_signals: if buy_fired: buy_marker_val = cur_close if not isnan(atr_val): tp_marker_val = cur_close + chosen_tp_mult * atr_val sl_marker_val = cur_close - atr_sl * atr_val if sell_fired: sell_marker_val = cur_close if not isnan(atr_val): tp_marker_val = cur_close - chosen_tp_mult * atr_val sl_marker_val = cur_close + atr_sl * atr_val

return (equity_val, plot.Marker(buy_marker_val, color=color.GREEN, text='B'), plot.Marker(sell_marker_val, color=color.RED, text='S'), plot.Marker(tp_marker_val, color=color.LIME, text='T'), plot.Marker(sl_marker_val, color=color.MAROON, text='X'))


Comments
Not authorized user image
No Comments yet image

Be the first to comment

Publish your first comment to unleash the wisdom of crowd.