OPEN-SOURCE SCRIPT
ABE'S KNN Machine Learning Momentum Indicator

//version=5
indicator("ABE'S KNN Machine Learning Momentum Indicator", overlay=true, max_bars_back=2000)
// ==========================================
// --- CONSTANTS & STYLING ---
// ==========================================
color_bull = color.new(#00ffbb, 0)
color_bear = color.new(#ff3355, 0)
color_bull_dim = color.new(#00ffbb, 50)
color_bear_dim = color.new(#ff3355, 50)
color_neutral = color.new(#64748b, 20)
color_gold = color.new(#ffd700, 0)
// ==========================================
// --- MA SELECTOR & HELPER FUNCTIONS ---
// ==========================================
f_zlsma(s, l) =>
lsma = ta.linreg(s, l, 0)
lsma + (lsma - ta.sma(s, l))
f_dema(s, l) =>
e1 = ta.ema(s, l)
2 * e1 - ta.ema(e1, l)
f_tema(s, l) =>
e1 = ta.ema(s, l)
e2 = ta.ema(e1, l)
3 * (e1 - e2) + ta.ema(e2, l)
f_thma(s, l) =>
l_3 = math.max(1, math.round(l / 3))
l_2 = math.max(1, math.round(l / 2))
ta.wma(ta.wma(s, l_3) * 3 - ta.wma(s, l_2) - ta.wma(s, l), l)
calcMA(type, s, l) =>
len = math.max(1, l)
switch type
"SMA" => ta.sma(s, len)
"EMA" => ta.ema(s, len)
"DEMA" => f_dema(s, len)
"TEMA" => f_tema(s, len)
"LSMA" => ta.linreg(s, len, 0)
"WMA" => ta.wma(s, len)
"HMA" => ta.hma(s, len)
"ZLSMA" => f_zlsma(s, len)
"SMMA" => ta.rma(s, len)
"THMA" => f_thma(s, len)
=> ta.sma(s, len)
// ==========================================
// --- INPUT PARAMETERS ---
// ==========================================
group_ml = "🧠 Machine Learning Engine"
k_neighbors = input.int(100, "K-Neighbors (K)", minval=1, group=group_ml, tooltip="Number of nearest neighbors to consider.")
window_size = input.int(1200, "Learning Window Size", minval=10, group=group_ml, tooltip="Historical data lookback for training.")
prob_threshold = input.float(0.9, "Prediction Threshold", minval=0.1, maxval=1.0, step=0.01, group=group_ml, tooltip="Confidence level required for a signal.")
momentum_window = input.int(4, "Momentum Window", minval=1, group=group_ml, tooltip="Look-back period for labeling price direction.")
group_feat = "📊 Feature Engineering"
feat_ma_type = input.string("SMA", "Feature MA Type", options=["SMA", "EMA", "DEMA", "TEMA", "LSMA", "WMA", "HMA", "ZLSMA", "SMMA", "THMA"], group=group_feat, tooltip="MA type used for feature calculation.")
rsi_short_len = input.int(2, "Short RSI Period", group=group_feat)
rsi_mid_len = input.int(3, "Mid RSI Period", group=group_feat)
rsi_long_len = input.int(4, "Long RSI Period", group=group_feat)
ma_short_len = input.int(2, "Short MA Period", group=group_feat)
ma_medium_len = input.int(3, "Medium MA Period", group=group_feat)
ma_long_len = input.int(4, "Long MA Period", group=group_feat)
signal_len = input.int(4, "Signal Line Period", group=group_feat)
p_param = input.float(4.0, "Minkowski Parameter (p)", group=group_feat, tooltip="Distance metric exponent. 2=Euclidean, 1=Manhattan.")
w_param = input.float(4.0, "Shape Parameter", group=group_feat, tooltip="Gausian Weighting exponent.")
group_filter = "🛡️ Signal Filters"
filter_mode = input.string("Price & Fast MA", "Filter Condition Mode", options=["None", "Price & Fast MA", "Fast MA & Slow MA", "Price & Fast & Slow"], group=group_filter, tooltip="Defines which trend conditions must be met for a 'Major' signal.")
filter_ma_type = input.string("EMA", "Filter MA Type", options=["SMA", "EMA", "DEMA", "TEMA", "LSMA", "WMA", "HMA", "ZLSMA", "SMMA", "THMA"], group=group_filter)
fast_filter_len = input.int(20, "Fast Filter Period", minval=1, group=group_filter)
slow_filter_len = input.int(50, "Slow Filter Period", minval=1, group=group_filter)
group_pca = "⚡ Dimensionality Reduction"
use_pca = input.bool(true, "Enable PCA Compression", group=group_pca, tooltip="Compresses features into 3 Principal Components to reduce noise.")
group_vis = "🎨 Visual Analytics"
use_bar_color = input.bool(true, "Dynamic Bar Coloring", group=group_vis, tooltip="Colors bars based on KNN prediction confidence.")
show_vwap = input.bool(true, "Show VWAP", group=group_vis)
group_mom = "🚀 Momentum Entry Engine"
use_momentum_filter = input.bool(true, "Require Momentum Confirmation", group=group_mom)
use_htf_filter = input.bool(true, "Require 15m Trend Alignment", group=group_mom)
use_vwap_filter = input.bool(true, "Require VWAP Alignment", group=group_mom)
use_adx_filter = input.bool(true, "Require ADX Strength", group=group_mom)
adx_len = input.int(14, "ADX Length", minval=3, group=group_mom)
adx_min = input.float(18.0, "Minimum ADX", minval=5, maxval=60, step=1, group=group_mom)
atr_len = input.int(14, "ATR Length", minval=1, group=group_mom)
vol_len = input.int(30, "Volume Average", minval=5, group=group_mom)
relative_vol_min = input.float(1.20, "Relative Volume Minimum", minval=0.5, step=0.05, group=group_mom)
body_atr_min = input.float(0.35, "Minimum Body ATR", minval=0.05, step=0.05, group=group_mom)
range_atr_min = input.float(0.60, "Minimum Range ATR", minval=0.10, step=0.05, group=group_mom)
close_strength_min = input.float(65.0, "Minimum Close Strength %", minval=50, maxval=95, step=5, group=group_mom)
breakout_lookback = input.int(12, "Breakout Lookback", minval=3, maxval=100, group=group_mom)
pullback_tolerance_atr = input.float(0.20, "Pullback Tolerance ATR", minval=0.02, step=0.01, group=group_mom)
entry_mode = input.string("Either", "Entry Type", options=["Pullback", "Breakout", "Either"], group=group_mom)
signal_cooldown = input.int(10, "Signal Cooldown Bars", minval=0, maxval=100, group=group_mom)
show_setup_markers = input.bool(true, "Show Setup Markers", group=group_mom)
// ==========================================
// --- LABELING (Supervised Learning) ---
// ==========================================
target = 1
for i = 0 to momentum_window - 1
if close[momentum_window - i] >= close
target := 0
target := target == 0 ? -1 : target
if target == -1
for i = 0 to momentum_window - 1
if close[momentum_window - i] <= close
target := 0
// ==========================================
// --- FEATURE CALCULATION & NORMALIZATION ---
// ==========================================
normalize(src, len) =>
float _mean = ta.sma(src[1], len)
float _std = ta.stdev(src[1], len)
(src - _mean) / math.max(_std, 0.00001)
f_rsi_s = ta.rsi(close, rsi_short_len)
f_rsi_m = ta.rsi(close, rsi_mid_len)
f_rsi_l = ta.rsi(close, rsi_long_len)
f_ma_s_dev = (close - calcMA(feat_ma_type, close[1], ma_short_len)) / calcMA(feat_ma_type, close[1], ma_short_len) * 100
f_ma_m_dev = (close - calcMA(feat_ma_type, close[1], ma_medium_len)) / calcMA(feat_ma_type, close[1], ma_medium_len) * 100
f_ma_l_dev = (close - calcMA(feat_ma_type, close[1], ma_long_len)) / calcMA(feat_ma_type, close[1], ma_long_len) * 100
f_rsi_s_sig_dist = f_rsi_s - ta.sma(f_rsi_s[1], signal_len)
f_rsi_m_sig_dist = f_rsi_m - ta.sma(f_rsi_m[1], signal_len)
f_rsi_l_sig_dist = f_rsi_l - ta.sma(f_rsi_l[1], signal_len)
f_rsi_s_z = normalize(f_rsi_s, window_size)
f_rsi_m_z = normalize(f_rsi_m, window_size)
f_rsi_l_z = normalize(f_rsi_l, window_size)
f_ma_s_dev_z = normalize(f_ma_s_dev, window_size)
f_ma_m_dev_z = normalize(f_ma_m_dev, window_size)
f_ma_l_dev_z = normalize(f_ma_l_dev, window_size)
f_rsi_s_sd_z = normalize(f_rsi_s_sig_dist, window_size)
f_rsi_m_sd_z = normalize(f_rsi_m_sig_dist, window_size)
f_rsi_l_sd_z = normalize(f_rsi_l_sig_dist, window_size)
body_size = normalize(close - open, window_size)
body_ratio = normalize((close - open)/(high-low), window_size)
// ==========================================
// --- DIMENSIONALITY REDUCTION ---
// ==========================================
float pc1 = 0.0, float pc2 = 0.0, float pc3 = 0.0, float pc4 = 0.0
if use_pca
pc1 := (f_rsi_s_z + f_rsi_m_z + f_rsi_l_z)
pc2 := (f_ma_s_dev_z + f_ma_m_dev_z + f_ma_l_dev_z) * 2.0
pc3 := (f_rsi_s_sd_z + f_rsi_m_sd_z + f_rsi_l_sd_z) * 0.5
pc4 := (body_size + body_ratio) * 0.5
else
pc1 := f_rsi_m_z
pc2 := f_ma_m_dev_z
pc3 := f_rsi_m_sd_z
pc4 := (body_size)
// ==========================================
// --- KNN CORE ENGINE ---
// ==========================================
float prob_up = 0.0, float prob_down = 0.0
var float[] distances = array.new_float(0)
var float[] labels = array.new_float(0)
stride = momentum_window
if bar_index > window_size + momentum_window
array.clear(distances)
array.clear(labels)
for i = momentum_window to window_size + momentum_window by stride
float d1 = math.abs(pc1 - pc1)
float d2 = math.abs(pc2 - pc2)
float d3 = math.abs(pc3 - pc3)
float d4 = math.abs(pc4 - pc4)
float dist_knn = math.pow(math.pow(d1, p_param) + math.pow(d2, p_param) + math.pow(d3, p_param) + math.pow(d4, p_param), 1/p_param)
array.push(distances, dist_knn)
array.push(labels, target)
if array.size(distances) >= k_neighbors
int[] sorted_indices = array.sort_indices(distances, order.ascending)
float sum_weight_up = 0.0, float sum_weight_down = 0.0, float total_weight = 0.0
float[] dist_sorted = array.copy(distances)
array.sort(dist_sorted)
float sigma = array.get(dist_sorted, math.min(int(k_neighbors/2), array.size(dist_sorted)-1))
sigma := math.max(sigma, 0.0001)
for j = 0 to k_neighbors - 1
int idx = array.get(sorted_indices, j)
float d = array.get(distances, idx)
float lbl = array.get(labels, idx)
float weight = math.exp(-math.pow(d, w_param) / (2 * math.pow(sigma, 2)))
if lbl == 1
sum_weight_up += weight
else if lbl == -1
sum_weight_down += weight
total_weight += weight
prob_up := total_weight > 0 ? sum_weight_up / total_weight : 0.0
prob_down := total_weight > 0 ? sum_weight_down / total_weight : 0.0
// ==========================================
// --- FILTER CALCULATION ---
// ==========================================
fast_ma = calcMA(filter_ma_type, close, fast_filter_len)
slow_ma = calcMA(filter_ma_type, close, slow_filter_len)
bool filter_bull = true
bool filter_bear = true
switch filter_mode
"Price & Fast MA" =>
filter_bull := close > fast_ma
filter_bear := close < fast_ma
"Fast MA & Slow MA" =>
filter_bull := fast_ma > slow_ma
filter_bear := fast_ma < slow_ma
"Price & Fast & Slow" =>
filter_bull := close > fast_ma and fast_ma > slow_ma
filter_bear := close < fast_ma and fast_ma < slow_ma
=> // "None"
filter_bull := true
filter_bear := true
// ==========================================
// --- MOMENTUM CONFIRMATION ENGINE ---
// ==========================================
atr_m = ta.atr(atr_len)
avg_vol_m = ta.sma(volume, vol_len)
relative_volume = avg_vol_m > 0 ? volume / avg_vol_m : 0.0
bar_range_m = math.max(high - low, syminfo.mintick)
body_m = math.abs(close - open)
bull_close_strength = (close - low) / bar_range_m * 100.0
bear_close_strength = (high - close) / bar_range_m * 100.0
[plus_di, minus_di, adx_value] = ta.dmi(adx_len, adx_len)
htf_fast = request.security(syminfo.tickerid, "15", ta.ema(close, 9), barmerge.gaps_off, barmerge.lookahead_off)
htf_slow = request.security(syminfo.tickerid, "15", ta.ema(close, 21), barmerge.gaps_off, barmerge.lookahead_off)
session_vwap = ta.vwap(hlc3)
volume_ok = relative_volume >= relative_vol_min
adx_ok = not use_adx_filter or adx_value >= adx_min
htf_bull_ok = not use_htf_filter or htf_fast > htf_slow
htf_bear_ok = not use_htf_filter or htf_fast < htf_slow
vwap_bull_ok = not use_vwap_filter or close > session_vwap
vwap_bear_ok = not use_vwap_filter or close < session_vwap
bull_expansion = close > open and body_m >= atr_m * body_atr_min and bar_range_m >= atr_m * range_atr_min and bull_close_strength >= close_strength_min
bear_expansion = close < open and body_m >= atr_m * body_atr_min and bar_range_m >= atr_m * range_atr_min and bear_close_strength >= close_strength_min
prior_high = ta.highest(high, breakout_lookback)[1]
prior_low = ta.lowest(low, breakout_lookback)[1]
bull_breakout = close > prior_high and close[1] <= prior_high
bear_breakout = close < prior_low and close[1] >= prior_low
bull_pullback = low <= fast_ma + atr_m * pullback_tolerance_atr and close > fast_ma and close > open
bear_pullback = high >= fast_ma - atr_m * pullback_tolerance_atr and close < fast_ma and close < open
long_location_ok = entry_mode == "Pullback" ? bull_pullback : entry_mode == "Breakout" ? bull_breakout : bull_pullback or bull_breakout
short_location_ok = entry_mode == "Pullback" ? bear_pullback : entry_mode == "Breakout" ? bear_breakout : bear_pullback or bear_breakout
long_momentum_ok = not use_momentum_filter or (filter_bull and htf_bull_ok and vwap_bull_ok and adx_ok and volume_ok and bull_expansion and long_location_ok)
short_momentum_ok = not use_momentum_filter or (filter_bear and htf_bear_ok and vwap_bear_ok and adx_ok and volume_ok and bear_expansion and short_location_ok)
// ==========================================
// --- SIGNAL GENERATION ---
// ==========================================
bool raw_long_signal = ta.crossover(prob_up, prob_threshold)
bool raw_short_signal = ta.crossover(prob_down, prob_threshold)
var int last_long_bar = na
var int last_short_bar = na
long_setup = prob_up >= prob_threshold and filter_bull and htf_bull_ok and vwap_bull_ok and adx_ok and long_location_ok
short_setup = prob_down >= prob_threshold and filter_bear and htf_bear_ok and vwap_bear_ok and adx_ok and short_location_ok
long_signal = barstate.isconfirmed and raw_long_signal and long_momentum_ok and (na(last_long_bar) or bar_index - last_long_bar > signal_cooldown)
short_signal = barstate.isconfirmed and raw_short_signal and short_momentum_ok and (na(last_short_bar) or bar_index - last_short_bar > signal_cooldown)
if long_signal
last_long_bar := bar_index
if short_signal
last_short_bar := bar_index
setup_long_marker = show_setup_markers and long_setup and not long_setup[1]
setup_short_marker = show_setup_markers and short_setup and not short_setup[1]
// ==========================================
// --- VISUALIZATION & PLOTTING ---
// ==========================================
color g_color = prob_up > prob_down ? color.from_gradient(prob_up, 0.4, 1.0, color_neutral, color_bull) : color.from_gradient(prob_down, 0.4, 1.0, color_neutral, color_bear)
barcolor(use_bar_color ? g_color : na)
bgcolor(long_signal ? color.new(color_bull, 90) : short_signal ? color.new(color_bear, 90) : na)
plot_fast = (filter_mode == "Price & Fast MA" or filter_mode == "Fast MA & Slow MA" or filter_mode == "Price & Fast & Slow")
plot_slow = (filter_mode == "Fast MA & Slow MA" or filter_mode == "Price & Fast & Slow")
plot(plot_fast ? fast_ma : na, "Fast Filter MA", color=color.blue, linewidth=1)
plot(plot_slow ? slow_ma : na, "Slow Filter MA", color=color.orange, linewidth=1)
plotshape(setup_long_marker, "Long Setup", shape.circle, location.belowbar, color_bull_dim, size=size.tiny, text="SET", textcolor=color.white)
plotshape(setup_short_marker, "Short Setup", shape.circle, location.abovebar, color_bear_dim, size=size.tiny, text="SET", textcolor=color.white)
plotshape(long_signal, "Momentum BUY", shape.labelup, location.belowbar, color_bull, size=size.large, text="BUY", textcolor=color.black)
plotshape(short_signal, "Momentum SELL", shape.labeldown, location.abovebar, color_bear, size=size.large, text="SELL", textcolor=color.white)
if long_signal
label.new(bar_index, low, "BUY\n" + str.tostring(prob_up * 100.0, "#") + "%", style=label.style_label_up, color=color_bull, textcolor=color.black, size=size.large)
if short_signal
label.new(bar_index, high, "SELL\n" + str.tostring(prob_down * 100.0, "#") + "%", style=label.style_label_down, color=color_bear, textcolor=color.white, size=size.large)
plot(show_vwap ? session_vwap : na, "Session VWAP", color=color_gold, linewidth=2)
// ==========================================
// --- ALERTS ---
// ==========================================
alert_long = long_signal and filter_bull
alert_short = short_signal and filter_bear
alert_combo = alert_long or alert_short
alertcondition(alert_long, "KNN Major Long", "Bullish Signal with Filter Confirmation")
alertcondition(alert_short, "KNN Major Short", "Bearish Signal with Filter Confirmation")
alertcondition(alert_combo, "KNN Combo Alert", "Major KNN Signal (Bull or Bear) with Filter Confirmation")
indicator("ABE'S KNN Machine Learning Momentum Indicator", overlay=true, max_bars_back=2000)
// ==========================================
// --- CONSTANTS & STYLING ---
// ==========================================
color_bull = color.new(#00ffbb, 0)
color_bear = color.new(#ff3355, 0)
color_bull_dim = color.new(#00ffbb, 50)
color_bear_dim = color.new(#ff3355, 50)
color_neutral = color.new(#64748b, 20)
color_gold = color.new(#ffd700, 0)
// ==========================================
// --- MA SELECTOR & HELPER FUNCTIONS ---
// ==========================================
f_zlsma(s, l) =>
lsma = ta.linreg(s, l, 0)
lsma + (lsma - ta.sma(s, l))
f_dema(s, l) =>
e1 = ta.ema(s, l)
2 * e1 - ta.ema(e1, l)
f_tema(s, l) =>
e1 = ta.ema(s, l)
e2 = ta.ema(e1, l)
3 * (e1 - e2) + ta.ema(e2, l)
f_thma(s, l) =>
l_3 = math.max(1, math.round(l / 3))
l_2 = math.max(1, math.round(l / 2))
ta.wma(ta.wma(s, l_3) * 3 - ta.wma(s, l_2) - ta.wma(s, l), l)
calcMA(type, s, l) =>
len = math.max(1, l)
switch type
"SMA" => ta.sma(s, len)
"EMA" => ta.ema(s, len)
"DEMA" => f_dema(s, len)
"TEMA" => f_tema(s, len)
"LSMA" => ta.linreg(s, len, 0)
"WMA" => ta.wma(s, len)
"HMA" => ta.hma(s, len)
"ZLSMA" => f_zlsma(s, len)
"SMMA" => ta.rma(s, len)
"THMA" => f_thma(s, len)
=> ta.sma(s, len)
// ==========================================
// --- INPUT PARAMETERS ---
// ==========================================
group_ml = "🧠 Machine Learning Engine"
k_neighbors = input.int(100, "K-Neighbors (K)", minval=1, group=group_ml, tooltip="Number of nearest neighbors to consider.")
window_size = input.int(1200, "Learning Window Size", minval=10, group=group_ml, tooltip="Historical data lookback for training.")
prob_threshold = input.float(0.9, "Prediction Threshold", minval=0.1, maxval=1.0, step=0.01, group=group_ml, tooltip="Confidence level required for a signal.")
momentum_window = input.int(4, "Momentum Window", minval=1, group=group_ml, tooltip="Look-back period for labeling price direction.")
group_feat = "📊 Feature Engineering"
feat_ma_type = input.string("SMA", "Feature MA Type", options=["SMA", "EMA", "DEMA", "TEMA", "LSMA", "WMA", "HMA", "ZLSMA", "SMMA", "THMA"], group=group_feat, tooltip="MA type used for feature calculation.")
rsi_short_len = input.int(2, "Short RSI Period", group=group_feat)
rsi_mid_len = input.int(3, "Mid RSI Period", group=group_feat)
rsi_long_len = input.int(4, "Long RSI Period", group=group_feat)
ma_short_len = input.int(2, "Short MA Period", group=group_feat)
ma_medium_len = input.int(3, "Medium MA Period", group=group_feat)
ma_long_len = input.int(4, "Long MA Period", group=group_feat)
signal_len = input.int(4, "Signal Line Period", group=group_feat)
p_param = input.float(4.0, "Minkowski Parameter (p)", group=group_feat, tooltip="Distance metric exponent. 2=Euclidean, 1=Manhattan.")
w_param = input.float(4.0, "Shape Parameter", group=group_feat, tooltip="Gausian Weighting exponent.")
group_filter = "🛡️ Signal Filters"
filter_mode = input.string("Price & Fast MA", "Filter Condition Mode", options=["None", "Price & Fast MA", "Fast MA & Slow MA", "Price & Fast & Slow"], group=group_filter, tooltip="Defines which trend conditions must be met for a 'Major' signal.")
filter_ma_type = input.string("EMA", "Filter MA Type", options=["SMA", "EMA", "DEMA", "TEMA", "LSMA", "WMA", "HMA", "ZLSMA", "SMMA", "THMA"], group=group_filter)
fast_filter_len = input.int(20, "Fast Filter Period", minval=1, group=group_filter)
slow_filter_len = input.int(50, "Slow Filter Period", minval=1, group=group_filter)
group_pca = "⚡ Dimensionality Reduction"
use_pca = input.bool(true, "Enable PCA Compression", group=group_pca, tooltip="Compresses features into 3 Principal Components to reduce noise.")
group_vis = "🎨 Visual Analytics"
use_bar_color = input.bool(true, "Dynamic Bar Coloring", group=group_vis, tooltip="Colors bars based on KNN prediction confidence.")
show_vwap = input.bool(true, "Show VWAP", group=group_vis)
group_mom = "🚀 Momentum Entry Engine"
use_momentum_filter = input.bool(true, "Require Momentum Confirmation", group=group_mom)
use_htf_filter = input.bool(true, "Require 15m Trend Alignment", group=group_mom)
use_vwap_filter = input.bool(true, "Require VWAP Alignment", group=group_mom)
use_adx_filter = input.bool(true, "Require ADX Strength", group=group_mom)
adx_len = input.int(14, "ADX Length", minval=3, group=group_mom)
adx_min = input.float(18.0, "Minimum ADX", minval=5, maxval=60, step=1, group=group_mom)
atr_len = input.int(14, "ATR Length", minval=1, group=group_mom)
vol_len = input.int(30, "Volume Average", minval=5, group=group_mom)
relative_vol_min = input.float(1.20, "Relative Volume Minimum", minval=0.5, step=0.05, group=group_mom)
body_atr_min = input.float(0.35, "Minimum Body ATR", minval=0.05, step=0.05, group=group_mom)
range_atr_min = input.float(0.60, "Minimum Range ATR", minval=0.10, step=0.05, group=group_mom)
close_strength_min = input.float(65.0, "Minimum Close Strength %", minval=50, maxval=95, step=5, group=group_mom)
breakout_lookback = input.int(12, "Breakout Lookback", minval=3, maxval=100, group=group_mom)
pullback_tolerance_atr = input.float(0.20, "Pullback Tolerance ATR", minval=0.02, step=0.01, group=group_mom)
entry_mode = input.string("Either", "Entry Type", options=["Pullback", "Breakout", "Either"], group=group_mom)
signal_cooldown = input.int(10, "Signal Cooldown Bars", minval=0, maxval=100, group=group_mom)
show_setup_markers = input.bool(true, "Show Setup Markers", group=group_mom)
// ==========================================
// --- LABELING (Supervised Learning) ---
// ==========================================
target = 1
for i = 0 to momentum_window - 1
if close[momentum_window - i] >= close
target := 0
target := target == 0 ? -1 : target
if target == -1
for i = 0 to momentum_window - 1
if close[momentum_window - i] <= close
target := 0
// ==========================================
// --- FEATURE CALCULATION & NORMALIZATION ---
// ==========================================
normalize(src, len) =>
float _mean = ta.sma(src[1], len)
float _std = ta.stdev(src[1], len)
(src - _mean) / math.max(_std, 0.00001)
f_rsi_s = ta.rsi(close, rsi_short_len)
f_rsi_m = ta.rsi(close, rsi_mid_len)
f_rsi_l = ta.rsi(close, rsi_long_len)
f_ma_s_dev = (close - calcMA(feat_ma_type, close[1], ma_short_len)) / calcMA(feat_ma_type, close[1], ma_short_len) * 100
f_ma_m_dev = (close - calcMA(feat_ma_type, close[1], ma_medium_len)) / calcMA(feat_ma_type, close[1], ma_medium_len) * 100
f_ma_l_dev = (close - calcMA(feat_ma_type, close[1], ma_long_len)) / calcMA(feat_ma_type, close[1], ma_long_len) * 100
f_rsi_s_sig_dist = f_rsi_s - ta.sma(f_rsi_s[1], signal_len)
f_rsi_m_sig_dist = f_rsi_m - ta.sma(f_rsi_m[1], signal_len)
f_rsi_l_sig_dist = f_rsi_l - ta.sma(f_rsi_l[1], signal_len)
f_rsi_s_z = normalize(f_rsi_s, window_size)
f_rsi_m_z = normalize(f_rsi_m, window_size)
f_rsi_l_z = normalize(f_rsi_l, window_size)
f_ma_s_dev_z = normalize(f_ma_s_dev, window_size)
f_ma_m_dev_z = normalize(f_ma_m_dev, window_size)
f_ma_l_dev_z = normalize(f_ma_l_dev, window_size)
f_rsi_s_sd_z = normalize(f_rsi_s_sig_dist, window_size)
f_rsi_m_sd_z = normalize(f_rsi_m_sig_dist, window_size)
f_rsi_l_sd_z = normalize(f_rsi_l_sig_dist, window_size)
body_size = normalize(close - open, window_size)
body_ratio = normalize((close - open)/(high-low), window_size)
// ==========================================
// --- DIMENSIONALITY REDUCTION ---
// ==========================================
float pc1 = 0.0, float pc2 = 0.0, float pc3 = 0.0, float pc4 = 0.0
if use_pca
pc1 := (f_rsi_s_z + f_rsi_m_z + f_rsi_l_z)
pc2 := (f_ma_s_dev_z + f_ma_m_dev_z + f_ma_l_dev_z) * 2.0
pc3 := (f_rsi_s_sd_z + f_rsi_m_sd_z + f_rsi_l_sd_z) * 0.5
pc4 := (body_size + body_ratio) * 0.5
else
pc1 := f_rsi_m_z
pc2 := f_ma_m_dev_z
pc3 := f_rsi_m_sd_z
pc4 := (body_size)
// ==========================================
// --- KNN CORE ENGINE ---
// ==========================================
float prob_up = 0.0, float prob_down = 0.0
var float[] distances = array.new_float(0)
var float[] labels = array.new_float(0)
stride = momentum_window
if bar_index > window_size + momentum_window
array.clear(distances)
array.clear(labels)
for i = momentum_window to window_size + momentum_window by stride
float d1 = math.abs(pc1 - pc1)
float d2 = math.abs(pc2 - pc2)
float d3 = math.abs(pc3 - pc3)
float d4 = math.abs(pc4 - pc4)
float dist_knn = math.pow(math.pow(d1, p_param) + math.pow(d2, p_param) + math.pow(d3, p_param) + math.pow(d4, p_param), 1/p_param)
array.push(distances, dist_knn)
array.push(labels, target)
if array.size(distances) >= k_neighbors
int[] sorted_indices = array.sort_indices(distances, order.ascending)
float sum_weight_up = 0.0, float sum_weight_down = 0.0, float total_weight = 0.0
float[] dist_sorted = array.copy(distances)
array.sort(dist_sorted)
float sigma = array.get(dist_sorted, math.min(int(k_neighbors/2), array.size(dist_sorted)-1))
sigma := math.max(sigma, 0.0001)
for j = 0 to k_neighbors - 1
int idx = array.get(sorted_indices, j)
float d = array.get(distances, idx)
float lbl = array.get(labels, idx)
float weight = math.exp(-math.pow(d, w_param) / (2 * math.pow(sigma, 2)))
if lbl == 1
sum_weight_up += weight
else if lbl == -1
sum_weight_down += weight
total_weight += weight
prob_up := total_weight > 0 ? sum_weight_up / total_weight : 0.0
prob_down := total_weight > 0 ? sum_weight_down / total_weight : 0.0
// ==========================================
// --- FILTER CALCULATION ---
// ==========================================
fast_ma = calcMA(filter_ma_type, close, fast_filter_len)
slow_ma = calcMA(filter_ma_type, close, slow_filter_len)
bool filter_bull = true
bool filter_bear = true
switch filter_mode
"Price & Fast MA" =>
filter_bull := close > fast_ma
filter_bear := close < fast_ma
"Fast MA & Slow MA" =>
filter_bull := fast_ma > slow_ma
filter_bear := fast_ma < slow_ma
"Price & Fast & Slow" =>
filter_bull := close > fast_ma and fast_ma > slow_ma
filter_bear := close < fast_ma and fast_ma < slow_ma
=> // "None"
filter_bull := true
filter_bear := true
// ==========================================
// --- MOMENTUM CONFIRMATION ENGINE ---
// ==========================================
atr_m = ta.atr(atr_len)
avg_vol_m = ta.sma(volume, vol_len)
relative_volume = avg_vol_m > 0 ? volume / avg_vol_m : 0.0
bar_range_m = math.max(high - low, syminfo.mintick)
body_m = math.abs(close - open)
bull_close_strength = (close - low) / bar_range_m * 100.0
bear_close_strength = (high - close) / bar_range_m * 100.0
[plus_di, minus_di, adx_value] = ta.dmi(adx_len, adx_len)
htf_fast = request.security(syminfo.tickerid, "15", ta.ema(close, 9), barmerge.gaps_off, barmerge.lookahead_off)
htf_slow = request.security(syminfo.tickerid, "15", ta.ema(close, 21), barmerge.gaps_off, barmerge.lookahead_off)
session_vwap = ta.vwap(hlc3)
volume_ok = relative_volume >= relative_vol_min
adx_ok = not use_adx_filter or adx_value >= adx_min
htf_bull_ok = not use_htf_filter or htf_fast > htf_slow
htf_bear_ok = not use_htf_filter or htf_fast < htf_slow
vwap_bull_ok = not use_vwap_filter or close > session_vwap
vwap_bear_ok = not use_vwap_filter or close < session_vwap
bull_expansion = close > open and body_m >= atr_m * body_atr_min and bar_range_m >= atr_m * range_atr_min and bull_close_strength >= close_strength_min
bear_expansion = close < open and body_m >= atr_m * body_atr_min and bar_range_m >= atr_m * range_atr_min and bear_close_strength >= close_strength_min
prior_high = ta.highest(high, breakout_lookback)[1]
prior_low = ta.lowest(low, breakout_lookback)[1]
bull_breakout = close > prior_high and close[1] <= prior_high
bear_breakout = close < prior_low and close[1] >= prior_low
bull_pullback = low <= fast_ma + atr_m * pullback_tolerance_atr and close > fast_ma and close > open
bear_pullback = high >= fast_ma - atr_m * pullback_tolerance_atr and close < fast_ma and close < open
long_location_ok = entry_mode == "Pullback" ? bull_pullback : entry_mode == "Breakout" ? bull_breakout : bull_pullback or bull_breakout
short_location_ok = entry_mode == "Pullback" ? bear_pullback : entry_mode == "Breakout" ? bear_breakout : bear_pullback or bear_breakout
long_momentum_ok = not use_momentum_filter or (filter_bull and htf_bull_ok and vwap_bull_ok and adx_ok and volume_ok and bull_expansion and long_location_ok)
short_momentum_ok = not use_momentum_filter or (filter_bear and htf_bear_ok and vwap_bear_ok and adx_ok and volume_ok and bear_expansion and short_location_ok)
// ==========================================
// --- SIGNAL GENERATION ---
// ==========================================
bool raw_long_signal = ta.crossover(prob_up, prob_threshold)
bool raw_short_signal = ta.crossover(prob_down, prob_threshold)
var int last_long_bar = na
var int last_short_bar = na
long_setup = prob_up >= prob_threshold and filter_bull and htf_bull_ok and vwap_bull_ok and adx_ok and long_location_ok
short_setup = prob_down >= prob_threshold and filter_bear and htf_bear_ok and vwap_bear_ok and adx_ok and short_location_ok
long_signal = barstate.isconfirmed and raw_long_signal and long_momentum_ok and (na(last_long_bar) or bar_index - last_long_bar > signal_cooldown)
short_signal = barstate.isconfirmed and raw_short_signal and short_momentum_ok and (na(last_short_bar) or bar_index - last_short_bar > signal_cooldown)
if long_signal
last_long_bar := bar_index
if short_signal
last_short_bar := bar_index
setup_long_marker = show_setup_markers and long_setup and not long_setup[1]
setup_short_marker = show_setup_markers and short_setup and not short_setup[1]
// ==========================================
// --- VISUALIZATION & PLOTTING ---
// ==========================================
color g_color = prob_up > prob_down ? color.from_gradient(prob_up, 0.4, 1.0, color_neutral, color_bull) : color.from_gradient(prob_down, 0.4, 1.0, color_neutral, color_bear)
barcolor(use_bar_color ? g_color : na)
bgcolor(long_signal ? color.new(color_bull, 90) : short_signal ? color.new(color_bear, 90) : na)
plot_fast = (filter_mode == "Price & Fast MA" or filter_mode == "Fast MA & Slow MA" or filter_mode == "Price & Fast & Slow")
plot_slow = (filter_mode == "Fast MA & Slow MA" or filter_mode == "Price & Fast & Slow")
plot(plot_fast ? fast_ma : na, "Fast Filter MA", color=color.blue, linewidth=1)
plot(plot_slow ? slow_ma : na, "Slow Filter MA", color=color.orange, linewidth=1)
plotshape(setup_long_marker, "Long Setup", shape.circle, location.belowbar, color_bull_dim, size=size.tiny, text="SET", textcolor=color.white)
plotshape(setup_short_marker, "Short Setup", shape.circle, location.abovebar, color_bear_dim, size=size.tiny, text="SET", textcolor=color.white)
plotshape(long_signal, "Momentum BUY", shape.labelup, location.belowbar, color_bull, size=size.large, text="BUY", textcolor=color.black)
plotshape(short_signal, "Momentum SELL", shape.labeldown, location.abovebar, color_bear, size=size.large, text="SELL", textcolor=color.white)
if long_signal
label.new(bar_index, low, "BUY\n" + str.tostring(prob_up * 100.0, "#") + "%", style=label.style_label_up, color=color_bull, textcolor=color.black, size=size.large)
if short_signal
label.new(bar_index, high, "SELL\n" + str.tostring(prob_down * 100.0, "#") + "%", style=label.style_label_down, color=color_bear, textcolor=color.white, size=size.large)
plot(show_vwap ? session_vwap : na, "Session VWAP", color=color_gold, linewidth=2)
// ==========================================
// --- ALERTS ---
// ==========================================
alert_long = long_signal and filter_bull
alert_short = short_signal and filter_bear
alert_combo = alert_long or alert_short
alertcondition(alert_long, "KNN Major Long", "Bullish Signal with Filter Confirmation")
alertcondition(alert_short, "KNN Major Short", "Bearish Signal with Filter Confirmation")
alertcondition(alert_combo, "KNN Combo Alert", "Major KNN Signal (Bull or Bear) with Filter Confirmation")
สคริปต์โอเพนซอร์ซ
ด้วยเจตนารมณ์หลักของ TradingView ผู้สร้างสคริปต์นี้ได้ทำให้เป็นโอเพนซอร์ส เพื่อให้เทรดเดอร์สามารถตรวจสอบและยืนยันฟังก์ชันการทำงานของมันได้ ขอชื่นชมผู้เขียน! แม้ว่าคุณจะใช้งานได้ฟรี แต่โปรดจำไว้ว่าการเผยแพร่โค้ดซ้ำจะต้องเป็นไปตาม กฎระเบียบการใช้งาน ของเรา
คำจำกัดสิทธิ์ความรับผิดชอบ
ข้อมูลและบทความไม่ได้มีวัตถุประสงค์เพื่อก่อให้เกิดกิจกรรมทางการเงิน, การลงทุน, การซื้อขาย, ข้อเสนอแนะ หรือคำแนะนำประเภทอื่น ๆ ที่ให้หรือรับรองโดย TradingView อ่านเพิ่มเติมใน ข้อกำหนดการใช้งาน
สคริปต์โอเพนซอร์ซ
ด้วยเจตนารมณ์หลักของ TradingView ผู้สร้างสคริปต์นี้ได้ทำให้เป็นโอเพนซอร์ส เพื่อให้เทรดเดอร์สามารถตรวจสอบและยืนยันฟังก์ชันการทำงานของมันได้ ขอชื่นชมผู้เขียน! แม้ว่าคุณจะใช้งานได้ฟรี แต่โปรดจำไว้ว่าการเผยแพร่โค้ดซ้ำจะต้องเป็นไปตาม กฎระเบียบการใช้งาน ของเรา
คำจำกัดสิทธิ์ความรับผิดชอบ
ข้อมูลและบทความไม่ได้มีวัตถุประสงค์เพื่อก่อให้เกิดกิจกรรมทางการเงิน, การลงทุน, การซื้อขาย, ข้อเสนอแนะ หรือคำแนะนำประเภทอื่น ๆ ที่ให้หรือรับรองโดย TradingView อ่านเพิ่มเติมใน ข้อกำหนดการใช้งาน