Machine Learning kNN-based Indicator For ThinkOrSwim

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

The indicator supposedly is quite good in backtesting and would love to use with ThinkorSwim. The script can be found here: https://www.tradingview.com/script/8cAQrM6a-Machine-Learning-kNN-based-Strategy-update/

Could someone please convert it, I'd greatly appreciate it. It's an open source script:



// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © capissimo
//@version=4
study("Machine Learning: kNN-based Strategy (update)", '', true, precision=4, max_labels_count=200)
// kNN-based Strategy (FX and Crypto)
// Description:
/////////////////////////////////////////////////////////////////////////////////
// This update to the popular kNN-based strategy features:
// improvements in the business logic,
// an adjustible k value for the kNN model,
// one more feature (MOM),
// a streamlined signal filter and
// some other minor fixes.
//
// Now this script works in all timeframes !
//
// I intentionally decided to publish this script separately
// in order for the users to see the differences.
/////////////////////////////////////////////////////////////////////////////////
// This strategy uses a classic machine learning algorithm - k Nearest Neighbours (kNN) -
// to let you find a prediction for the next (tomorrow's, next month's, etc.) market move.
// Being an unsupervised machine learning algorithm, kNN is one of the most simple learning algorithms.
// To do a prediction of the next market move, the kNN algorithm uses the historic data,
// collected in 3 arrays - feature1, feature2 and directions, - and finds the k-nearest
// neighbours of the current indicator(s) values.
// The two dimensional kNN algorithm just has a look on what has happened in the past when
// the two indicators had a similar level. It then looks at the k nearest neighbours,
// sees their state and thus classifies the current point.
// The kNN algorithm offers a framework to test all kinds of indicators easily to see if they
// have got any predictive value. One can easily add cog, wpr and others.
// Note: TradingViews's playback feature helps to see this strategy in action.
// Style tags: Trend Following, Trend Analysis
// Asset class: Equities, Futures, ETFs, Currencies and Commodities
// Dataset: FX Minutes/Hours+++/Days
//-------------------- Inputs
K = input(63, 'K Value for kNN Model |5..n|', minval=5)
ind = input('All', 'Indicator', options=['RSI','ROC','CCI','MOM','All'])
fast = input(14, 'Fast Period |1..n|', minval=1)
slow = input(28, 'Slow Period |2..n|', minval=2)
ftype = input('Both','Filter Signals by', options=['Volatility','Volume','Both','None'])
holding_p = input(1, 'Holding Period |1..n|', minval=1)
tthres = input(99.9, 'Time Threshold |0.1..100.0|', minval=0.0, maxval=100.0, step=0.1)
//-------------------- Global Variables
var int BUY = 1
var int SELL = -1
var int HOLD = 0
var int hp_counter = 0
var float k = floor(sqrt(K))
//-------------------- Custom Functions
cAqua(g) => g>9?#0080FFff:g>8?#0080FFe5:g>7?#0080FFcc:g>6?#0080FFb2:g>5?#0080FF99:g>4?#0080FF7f:g>3?#0080FF66:g>2?#0080FF4c:g>1?#0080FF33:#00C0FF19
cPink(g) => g>9?#FF0080ff:g>8?#FF0080e5:g>7?#FF0080cc:g>6?#FF0080b2:g>5?#FF008099:g>4?#FF00807f:g>3?#FF008066:g>2?#FF00804c:g>1?#FF008033:#FF008019
volumeBreak(thres) =>
rsivol = rsi(volume, 14)
osc = hma(rsivol, 10)
osc > thres
volatilityBreak(volmin, volmax) => atr(volmin) > atr(volmax)
scale(x, p) => (x - lowest(x, p)) / (highest(x, p) - lowest(x, p)) //-- scale to the range of [0..1]
//-------------------- Logic
// 4 pairs of predictor indicators, long and short each
rs = rsi(close, slow), rf = rsi(close, fast)
cs = cci(close, slow), cf = cci(close, fast)
os = roc(close, slow), of = roc(close, fast)
// added mom as a feature:
// it requires scaling to the range of [0,...,100]
// the choice of 63 is arbitrary, needs optimizing
ms = scale(mom(close, slow), 63) * 100, mf = scale(mom(close, fast), 63) * 100
// TOADD or TOTRYOUT:
// cmo(close, slow), cmo(close, fast)
// mfi(close, slow), mfi(close, fast)
// mom(close, slow), mom(close, fast)
f1 = ind=='RSI' ? rs : ind=='ROC' ? os : ind=='CCI' ? cs : ind=='MOM' ? ms : avg(rs, os, cs, ms)
f2 = ind=='RSI' ? rf : ind=='ROC' ? of : ind=='CCI' ? cf : ind=='MOM' ? mf : avg(rf, of, cf, mf)
// Classification data, what happens on the next bar
class = close[1]<close[0] ? SELL: close[1]>close[0] ? BUY : HOLD
// Training data, normalized to the range of [0,...,100]
var feature1 = array.new_float(0) // [0,...,100]
var feature2 = array.new_float(0) // ...
var directions = array.new_int(0) // [-1; +1]
// Result data
var predictions = array.new_int(0)
var prediction = 0.
var signal = HOLD
// Store everything in arrays. Features represent a square 100 x 100 matrix,
// whose row-colum intersections represent class labels, showing historic directions
array.push(feature1, f1)
array.push(feature2, f2)
array.push(directions, class)
// Ucomment the followng statement (if barstate.islast) and tab everything below
// between BOBlock and EOBlock marks to see just the recent several signals gradually
// showing up, rather than all the preceding signals
//if barstate.islast
//==BOBlock
// Core logic of the algorithm
size = array.size(directions)
maxdist = -999.
// Loop through the training arrays, getting distances and corresponding directions.
for i=0 to size-1
// Calculate the euclidean distance of current point to all historic points,
// here the metric used might as well be a manhattan distance or any other.
d = sqrt(pow(f1 - array.get(feature1, i), 2) + pow(f2 - array.get(feature2, i), 2))

if d > maxdist
maxdist := d
if array.size(predictions) >= k
array.shift(predictions)
array.push(predictions, array.get(directions, i))

//==EOBlock
// Note: in this setup there's no need for distances array (i.e. array.push(distances, d)),
// but the drawback is that a sudden max value may shadow all the subsequent values.
// One of the ways to bypass this is to:
// 1) store d in distances array,
// 2) calculate newdirs = bubbleSort(distances, directions), and then
// 3) take a slice with array.slice(newdirs) from the end

// Get the overall prediction of k nearest neighbours
prediction := array.sum(predictions)

// Now that we got a prediction for the next market move, we need to make use of this prediction and
// trade it. The returns then will show if everything works as predicted.
// Over here is a simple long/short interpretation of the prediction,
// but of course one could also use the quality of the prediction (+5 or +1) in some sort of way,
// ex. for position sizing.
tbase = (time - time[1]) / 1000
tcurr = (timenow - time_close[1]) / 1000
barlife = tcurr / tbase
filter = ftype=='Volatility' ? volatilityBreak(1, 10)
: ftype=='Volume' ? volumeBreak(49)
: ftype=='Both' ? volatilityBreak(1, 10) and volumeBreak(49)
: true

signal := prediction > 0 and barlife > tthres and filter ? BUY : prediction < 0 and barlife > tthres and filter ? SELL : nz(signal[1]) // HOLD
changed = change(signal)
hp_counter := changed ? 0 : hp_counter + 1
startLongTrade = changed and signal==BUY
startShortTrade = changed and signal==SELL
endLongTrade = (changed and signal==SELL) or (signal==BUY and hp_counter==holding_p and not changed)
endShortTrade = (changed and signal==BUY) or (signal==SELL and hp_counter==holding_p and not changed)
//-------------------- Rendering
plotshape(startLongTrade ? low : na, 'Buy', shape.labelup, location.belowbar, cAqua(prediction*5), size=size.small) // color intensity correction
plotshape(startShortTrade ? high : na, 'Sell', shape.labeldown, location.abovebar, cPink(-prediction*5), size=size.small)
plot(endLongTrade ? high : na, 'StopBuy', cAqua(6), 2, plot.style_cross)
plot(endShortTrade ? low : na, 'StopSell', cPink(6), 2, plot.style_cross)
//-------------------- Notification
if changed and signal==BUY
alert("Buy Alert", alert.freq_once_per_bar) // alert.freq_once_per_bar_close
if changed and signal==SELL
alert("Sell Alert", alert.freq_once_per_bar)

alertcondition(startLongTrade, "Buy Alert", "Go Long!")
alertcondition(startShortTrade, "Sell Alert", "Go Short!")
//-------------------- Backtesting
show_info = input(true, '===Information===')
lot_size = input(0.01, 'Lot Size', options=[0.01,0.1,0.2,0.3,0.5,1,2,3,5,10,20,30,50,100,1000])
bidask = (open+high+low)/3
var float start_long_trade = bidask
var float long_trades = 0.
var float start_short_trade = bidask
var float short_trades = 0.
var int wins = 0
var int trade_count = 0
if startLongTrade
start_long_trade := bidask
if endLongTrade
ldiff = (bidask - start_long_trade)
wins := ldiff > 0 ? 1 : 0
long_trades := ldiff * lot_size
trade_count := 1
if startShortTrade
start_short_trade := bidask
if endShortTrade
sdiff = (start_short_trade - bidask)
wins := sdiff > 0 ? 1 : 0
short_trades := sdiff * lot_size
trade_count := 1

cumreturn = cum(long_trades) + cum(short_trades) //-- cumulative return
totaltrades = cum(trade_count)
totalwins = cum(wins)
totallosses = totaltrades - totalwins == 0 ? 1 : totaltrades - totalwins
//------------------- Information
var label lbl = na
info = 'K Value: ' + tostring(K, '#') + ' (' + tostring(k, '#.##') + ')'
+ '\nHPeriod: ' + tostring(holding_p, '#')
+ '\nCR=' + tostring(cumreturn, '#.#')
+ '\nTrades: ' + tostring(totaltrades, '#')
+ '\nWin/Loss: ' + tostring(totalwins/totallosses, '#.##')
+ '\nWinrate: ' + tostring(totalwins/totaltrades, '#.#%')
+ '\nBar Time: ' + tostring(barlife, '#.#%')
if show_info and barstate.islast
lbl := label.new(bar_index, ohlc4, info, xloc.bar_index, yloc.price,
color.new(color.blue, 100), label.style_label_left, color.black, size.small, text.align_left)
label.delete(lbl[1])
arrays can't handle by TOS. However, try below my trials. Can give good signals.

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at
#// © capissimo
#study("Machine Learning: kNN-based Strategy (update)", '', true, precision=4
#// kNN-based Strategy (FX and Crypto)
# converted by Sam4Cok@Samer800    - 09/2023 - Not Exact Conversion.
#//-------------------- Inputs
input sampleSize = 200;
input kValue     = 63;#,    'K Value for kNN Model |5..n|'
input Indicator  = {"RSI", "ROC", "CCI", "MOM", default "All"};# 'Indicator'
input FastPeriod = 14;#    'Fast Period |1..n|'
input SlowPeriod = 28;#    'Slow Period |2..n|'
input FilterType = {"Volatility", "Volume", default "Both" , "None"};#'Filter Signals by
input HoldingPeriod  = 5;#,     'Holding Period |1..n|

def na = Double.NaN;
def barConfrimed = !isNaN(close);
def k  = Floor(Sqrt(kValue));
def size = sampleSize;
DefineGlobalColor("uphi", CreateColor(0,128,255));
DefineGlobalColor("upmd", CreateColor(0,89,177));
DefineGlobalColor("uplo", CreateColor(0,49,98));
DefineGlobalColor("dnhi", CreateColor(255,0,128));
DefineGlobalColor("dnmd", CreateColor(177,0,89));
DefineGlobalColor("dnlo", CreateColor(98,0,49));

Script dCol {
input g = 0;
    def cAqua = if g >= 7 then 2 else
                if g > 4 then 1 else 0;
    plot out = cAqua;
}
script nCCI {
    input price = close;
    input length = 14;
    def linDev = LinDev(price, length);
    def avg = Average(price, length);
    def CCI = if linDev then (price - avg) / linDev / 0.015 else 0;
    plot out = CCI;
}
script scale {
    input x = close;
    input p = 63;
    def hh = Highest(x, p);
    def ll = Lowest(x, p);
    def scale = (x - ll) / (hh - ll);# //-- scale to the range of [0..1]
    plot out = scale;
}
#volumeBreak(thres) => 
def rsivol = RSI(Price = volume, Length = 14);
def hVol   = HullMovingAvg(rsivol, 10);
def volumeBreak = hVol > 49;
#VolatilityBreak(volmin, volmax) =>
def volmin = ATR(Length = 1);
def volmax = ATR(Length = 10);
def VolatilityBreak = volmin > volmax;

def filt;
Switch (FilterType) {
Case "Volatility" :
    filt = volatilityBreak;
Case "Volume" :
    filt = volumeBreak;
Case "None" :
    filt = yes;
Default :
    filt = (volatilityBreak and volumeBreak);
}
def filter = filt;
#//-------------------- Logic
#// 4 pairs of predictor indicators, long and short each

def rs = RSI(Price = close, Length = SlowPeriod);
def rf = RSI(Price = close, Length = FastPeriod);
def cs = nCCI(close, SlowPeriod);
def cf = nCCI(close, FastPeriod);
def os = RateOfChange(Price = close, Length = SlowPeriod);
def of = RateOfChange(Price = close, Length = FastPeriod);
#// added mom as a feature:
#// it requires scaling to the range of [0,...,100]
#// the choice of 63 is arbitrary, needs optimizing
def momLow = close - close[SlowPeriod];
def momFast = close - close[FastPeriod];
def ms = scale(momLow, 63) * 100;
def mf = scale(momFast, 63) * 100;

#// TOADD or TOTRYOUT:
def AvgS = (rs + os + cs + ms) / 4;
def AvgF = (rf + of + cf + mf) / 4;

def ind1;def ind2;
Switch (Indicator) {
Case "RSI" :
    ind1 = rs;
    ind2 = rf;
Case "ROC" :
    ind1 = os;
    ind2 = of;
Case "CCI" :
    ind1 = cs;
    ind2 = cf;
Case "MOM" :
    ind1 = ms;
    ind2 = mf;
Default    :
    ind1 = AvgS;
    ind2 = AvgF;
}

def f1 = ind1;
def f2 = ind2;

#// Classification data, what happens on the next bar
def class = if close[1]<close[0] then -1 else
            if close[1]>close[0] then  1 else 0;

def maxdis = fold i=0 to size with p=-999 do
    Max(p, sqrt(power(f1 - GetValue(f1,size-i),2) + power(f2 - GetValue(f2,size-i), 2)));
def maxdist = maxdis;
def val; def cnt;
if maxdist > maxdist[1] {
    cnt = if cnt[1] >= k then 0 else cnt[1] + 1;
    val = if cnt then val[1] + class else class[1];
    } else {
    cnt = cnt[1];
    val = val[1];
}
#def tt = fold j=0 to size with q do
#         if maxdist[j] > GetValue(maxdist, j + 1) then
#         fold j1 = j to j + k with q1=class do
#         if GetValue(maxdist, j1) > GetValue(maxdist, j1 + 1) then
#         q1 + GetValue(class, j1) else  q1 else  GetValue(class, j);

#// Get the overall prediction of k nearest neighbours
def prediction = val;   

def sig = if prediction > 0 and barConfrimed and filter then 1 else
          if prediction < 0 and barConfrimed and filter then -1 else sig[1];
def signal = sig;
def changed = (signal-signal[1]);
def hp_counter = if changed then 0 else hp_counter[1] + 1;

def startLongTrade  = changed and signal==1;
def startShortTrade = changed and signal==-1;
def entr  = (open+high+low)/3;
def bidask = entr[-1];
def hh = highest(bidask, 5);
def ll = lowest(bidask, 5);
def tr = TrueRange(hh, bidask, ll);
def nATR = WildersAverage(tr, 14);

def minB = nATR;#(bidask - ll + nATR) /2;
def minS = nATR;#(hh - bidask + nATR) /2;

def stopL   = if startLongTrade then bidask - minB else stopL[1];
def profitL = if startLongTrade then bidask + minB * 1.5 else profitL[1];
def stopS   = if startShortTrade then bidask + minS else stopS[1];
def profitS = if startShortTrade then bidask - minS * 1.5 else profitS[1];

def condL = startShortTrade or
            ((close crosses below stopL) or (high crosses above profitL));
def condS = startLongTrade or
            ((close crosses Above stopS) or (low crosses below profitS));
def inTradeLong; def inTradeShort;
if startLongTrade {
    inTradeLong  = yes;
    inTradeShort = no;
    } else
if startShortTrade {
    inTradeLong  = no;
    inTradeShort = yes;
    } else {
    inTradeLong  = inTradeLong[1];
    inTradeShort = inTradeShort[1];
}
def endLongTrade  = #!inTradeLong and inTradeLong[1];
                    (startShortTrade ) or
                   (!changed and signal==1 and hp_counter==HoldingPeriod);
def endShortTrade = #!inTradeShort and inTradeShort[1];
                    (startLongTrade ) or
                    (!changed and signal==-1 and hp_counter==HoldingPeriod);

def colUp = dCol(prediction * 5);
def colDn = dCol(-prediction * 5);
AddChartBubble(startLongTrade, low, "Buy", if colUp==2 then GlobalColor("uphi") else
               if colUp==1 then GlobalColor("upmd") else GlobalColor("uplo"), no);
AddChartBubble(startShortTrade, high, "Sell", if colDn==2 then GlobalColor("dnhi") else
               if colDn==1 then GlobalColor("dnmd") else GlobalColor("dnlo"));

plot exitLong = if endLongTrade then high else na;    # 'StopBuy'
plot exitShort = if endShortTrade then low else na;   # 'StopSell'
exitLong.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
exitShort.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
exitLong.SetDefaultColor(GlobalColor("upmd"));
exitShort.SetDefaultColor(GlobalColor("dnmd"));
#//-------------------- Backtesting

input show_info = yes;     # '===Information==='
input lot_size  = 0.01;    # 'Lot Size'

def bar = BarNumber();
def start_long_trade;
def long_trades;
def start_short_trade;
def short_trades;
def wins;
def trade_count;
def diff;
#def sdiff;
if !show_info {
    start_long_trade = na;
    } else
if startLongTrade {
    start_long_trade = bidask;
    } else {
    start_long_trade = if start_long_trade[1] then start_long_trade[1] else bidask;
}
if !show_info {
    start_short_trade = na;
    } else
if startShortTrade {
    start_short_trade = bidask;
    } else {
    start_short_trade = if start_short_trade[1] then start_short_trade[1] else bidask;
}

if endLongTrade and bar > 0{
    diff         = (bidask - start_long_trade);
    long_trades  = long_trades[1] + diff * lot_size;
    short_trades = short_trades[1];
    wins         = if diff > 0 then wins[1] + 1 else wins[1];
    trade_count  = trade_count[1] + 1;
    } else
if endShortTrade and bar > 0 {
    diff         = (start_short_trade - bidask);
    long_trades  = long_trades[1];
    short_trades = short_trades[1] + diff * lot_size ;
    wins         = if diff > 0 then wins[1] + 1 else wins[1];
    trade_count  = trade_count[1] + 1;
    } else {
    diff         = 0;
    long_trades  = long_trades[1];
    short_trades = short_trades[1];
    wins         = wins[1];
    trade_count  = trade_count[1];
}
    
def cumreturn = (long_trades) + (short_trades);
def totaltrades = (trade_count);
def totalwins   = (wins);
def totallosses = if totaltrades - totalwins == 0 then 1 else totaltrades - totalwins;
def kVal = Round(k, 0);
def Return  = Round(cumreturn, 2);
def winLoss = Round(totalwins/totallosses, 2);
def winPer  = Round(totalwins/totaltrades, 2) * 100;

AddLabel(show_info, "K Value: " + kValue + "(" + kVal + ")" +
                    " HPeriod: " + "(" + HoldingPeriod + ")", Color.WHITE);
AddLabel(show_info, "CR= " + "(" + Return + ")",
        if Return>0 then Color.GREEN else if Return<0 then Color.RED else Color.GRAY);
AddLabel(show_info, "Trades: "   + "(" + totaltrades + ")", Color.WHITE);
AddLabel(show_info, "Win/Loss: " + "(" + winLoss + ")",
        if winLoss>1 then Color.GREEN else if winLoss<1 then Color.RED else Color.GRAY);
AddLabel(show_info, "Winrate: "  + "(" + winPer + "%)",
        if winPer>50 then Color.GREEN else if winPer<50 then Color.RED else Color.GRAY);

#-- End o fCode
 
@samer800 thank you for looking into this and working out a conversion. I'll give it a try now and see how it looks. I really appreciate it, and attempting workarounds given the array limitations.
 
Once again thanks @samer800, I went in and checked to see how it gives signals against the TradingView code, and unfortunately it seems to miss or reverse a number of signals. I guess it might not be possible to code in ThinkScript due to the lack of array capability. Just thought I'd report back on how it works compared to the original code for anyone interested. It's a shame since the original script really does seem to spot the trend relatively accurately. I appreciate your giving it a go though.
 
arrays can't handle by TOS. However, try below my trials. Can give good signals.

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at
#// © capissimo
#study("Machine Learning: kNN-based Strategy (update)", '', true, precision=4
#// kNN-based Strategy (FX and Crypto)
# converted by Sam4Cok@Samer800    - 09/2023 - Not Exact Conversion.
#//-------------------- Inputs
input sampleSize = 200;
input kValue     = 63;#,    'K Value for kNN Model |5..n|'
input Indicator  = {"RSI", "ROC", "CCI", "MOM", default "All"};# 'Indicator'
input FastPeriod = 14;#    'Fast Period |1..n|'
input SlowPeriod = 28;#    'Slow Period |2..n|'
input FilterType = {"Volatility", "Volume", default "Both" , "None"};#'Filter Signals by
input HoldingPeriod  = 5;#,     'Holding Period |1..n|

def na = Double.NaN;
def barConfrimed = !isNaN(close);
def k  = Floor(Sqrt(kValue));
def size = sampleSize;
DefineGlobalColor("uphi", CreateColor(0,128,255));
DefineGlobalColor("upmd", CreateColor(0,89,177));
DefineGlobalColor("uplo", CreateColor(0,49,98));
DefineGlobalColor("dnhi", CreateColor(255,0,128));
DefineGlobalColor("dnmd", CreateColor(177,0,89));
DefineGlobalColor("dnlo", CreateColor(98,0,49));

Script dCol {
input g = 0;
    def cAqua = if g >= 7 then 2 else
                if g > 4 then 1 else 0;
    plot out = cAqua;
}
script nCCI {
    input price = close;
    input length = 14;
    def linDev = LinDev(price, length);
    def avg = Average(price, length);
    def CCI = if linDev then (price - avg) / linDev / 0.015 else 0;
    plot out = CCI;
}
script scale {
    input x = close;
    input p = 63;
    def hh = Highest(x, p);
    def ll = Lowest(x, p);
    def scale = (x - ll) / (hh - ll);# //-- scale to the range of [0..1]
    plot out = scale;
}
#volumeBreak(thres) =>
def rsivol = RSI(Price = volume, Length = 14);
def hVol   = HullMovingAvg(rsivol, 10);
def volumeBreak = hVol > 49;
#VolatilityBreak(volmin, volmax) =>
def volmin = ATR(Length = 1);
def volmax = ATR(Length = 10);
def VolatilityBreak = volmin > volmax;

def filt;
Switch (FilterType) {
Case "Volatility" :
    filt = volatilityBreak;
Case "Volume" :
    filt = volumeBreak;
Case "None" :
    filt = yes;
Default :
    filt = (volatilityBreak and volumeBreak);
}
def filter = filt;
#//-------------------- Logic
#// 4 pairs of predictor indicators, long and short each

def rs = RSI(Price = close, Length = SlowPeriod);
def rf = RSI(Price = close, Length = FastPeriod);
def cs = nCCI(close, SlowPeriod);
def cf = nCCI(close, FastPeriod);
def os = RateOfChange(Price = close, Length = SlowPeriod);
def of = RateOfChange(Price = close, Length = FastPeriod);
#// added mom as a feature:
#// it requires scaling to the range of [0,...,100]
#// the choice of 63 is arbitrary, needs optimizing
def momLow = close - close[SlowPeriod];
def momFast = close - close[FastPeriod];
def ms = scale(momLow, 63) * 100;
def mf = scale(momFast, 63) * 100;

#// TOADD or TOTRYOUT:
def AvgS = (rs + os + cs + ms) / 4;
def AvgF = (rf + of + cf + mf) / 4;

def ind1;def ind2;
Switch (Indicator) {
Case "RSI" :
    ind1 = rs;
    ind2 = rf;
Case "ROC" :
    ind1 = os;
    ind2 = of;
Case "CCI" :
    ind1 = cs;
    ind2 = cf;
Case "MOM" :
    ind1 = ms;
    ind2 = mf;
Default    :
    ind1 = AvgS;
    ind2 = AvgF;
}

def f1 = ind1;
def f2 = ind2;

#// Classification data, what happens on the next bar
def class = if close[1]<close[0] then -1 else
            if close[1]>close[0] then  1 else 0;

def maxdis = fold i=0 to size with p=-999 do
    Max(p, sqrt(power(f1 - GetValue(f1,size-i),2) + power(f2 - GetValue(f2,size-i), 2)));
def maxdist = maxdis;
def val; def cnt;
if maxdist > maxdist[1] {
    cnt = if cnt[1] >= k then 0 else cnt[1] + 1;
    val = if cnt then val[1] + class else class[1];
    } else {
    cnt = cnt[1];
    val = val[1];
}
#def tt = fold j=0 to size with q do
#         if maxdist[j] > GetValue(maxdist, j + 1) then
#         fold j1 = j to j + k with q1=class do
#         if GetValue(maxdist, j1) > GetValue(maxdist, j1 + 1) then
#         q1 + GetValue(class, j1) else  q1 else  GetValue(class, j);

#// Get the overall prediction of k nearest neighbours
def prediction = val; 

def sig = if prediction > 0 and barConfrimed and filter then 1 else
          if prediction < 0 and barConfrimed and filter then -1 else sig[1];
def signal = sig;
def changed = (signal-signal[1]);
def hp_counter = if changed then 0 else hp_counter[1] + 1;

def startLongTrade  = changed and signal==1;
def startShortTrade = changed and signal==-1;
def entr  = (open+high+low)/3;
def bidask = entr[-1];
def hh = highest(bidask, 5);
def ll = lowest(bidask, 5);
def tr = TrueRange(hh, bidask, ll);
def nATR = WildersAverage(tr, 14);

def minB = nATR;#(bidask - ll + nATR) /2;
def minS = nATR;#(hh - bidask + nATR) /2;

def stopL   = if startLongTrade then bidask - minB else stopL[1];
def profitL = if startLongTrade then bidask + minB * 1.5 else profitL[1];
def stopS   = if startShortTrade then bidask + minS else stopS[1];
def profitS = if startShortTrade then bidask - minS * 1.5 else profitS[1];

def condL = startShortTrade or
            ((close crosses below stopL) or (high crosses above profitL));
def condS = startLongTrade or
            ((close crosses Above stopS) or (low crosses below profitS));
def inTradeLong; def inTradeShort;
if startLongTrade {
    inTradeLong  = yes;
    inTradeShort = no;
    } else
if startShortTrade {
    inTradeLong  = no;
    inTradeShort = yes;
    } else {
    inTradeLong  = inTradeLong[1];
    inTradeShort = inTradeShort[1];
}
def endLongTrade  = #!inTradeLong and inTradeLong[1];
                    (startShortTrade ) or
                   (!changed and signal==1 and hp_counter==HoldingPeriod);
def endShortTrade = #!inTradeShort and inTradeShort[1];
                    (startLongTrade ) or
                    (!changed and signal==-1 and hp_counter==HoldingPeriod);

def colUp = dCol(prediction * 5);
def colDn = dCol(-prediction * 5);
AddChartBubble(startLongTrade, low, "Buy", if colUp==2 then GlobalColor("uphi") else
               if colUp==1 then GlobalColor("upmd") else GlobalColor("uplo"), no);
AddChartBubble(startShortTrade, high, "Sell", if colDn==2 then GlobalColor("dnhi") else
               if colDn==1 then GlobalColor("dnmd") else GlobalColor("dnlo"));

plot exitLong = if endLongTrade then high else na;    # 'StopBuy'
plot exitShort = if endShortTrade then low else na;   # 'StopSell'
exitLong.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
exitShort.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
exitLong.SetDefaultColor(GlobalColor("upmd"));
exitShort.SetDefaultColor(GlobalColor("dnmd"));
#//-------------------- Backtesting

input show_info = yes;     # '===Information==='
input lot_size  = 0.01;    # 'Lot Size'

def bar = BarNumber();
def start_long_trade;
def long_trades;
def start_short_trade;
def short_trades;
def wins;
def trade_count;
def diff;
#def sdiff;
if !show_info {
    start_long_trade = na;
    } else
if startLongTrade {
    start_long_trade = bidask;
    } else {
    start_long_trade = if start_long_trade[1] then start_long_trade[1] else bidask;
}
if !show_info {
    start_short_trade = na;
    } else
if startShortTrade {
    start_short_trade = bidask;
    } else {
    start_short_trade = if start_short_trade[1] then start_short_trade[1] else bidask;
}

if endLongTrade and bar > 0{
    diff         = (bidask - start_long_trade);
    long_trades  = long_trades[1] + diff * lot_size;
    short_trades = short_trades[1];
    wins         = if diff > 0 then wins[1] + 1 else wins[1];
    trade_count  = trade_count[1] + 1;
    } else
if endShortTrade and bar > 0 {
    diff         = (start_short_trade - bidask);
    long_trades  = long_trades[1];
    short_trades = short_trades[1] + diff * lot_size ;
    wins         = if diff > 0 then wins[1] + 1 else wins[1];
    trade_count  = trade_count[1] + 1;
    } else {
    diff         = 0;
    long_trades  = long_trades[1];
    short_trades = short_trades[1];
    wins         = wins[1];
    trade_count  = trade_count[1];
}
  
def cumreturn = (long_trades) + (short_trades);
def totaltrades = (trade_count);
def totalwins   = (wins);
def totallosses = if totaltrades - totalwins == 0 then 1 else totaltrades - totalwins;
def kVal = Round(k, 0);
def Return  = Round(cumreturn, 2);
def winLoss = Round(totalwins/totallosses, 2);
def winPer  = Round(totalwins/totaltrades, 2) * 100;

AddLabel(show_info, "K Value: " + kValue + "(" + kVal + ")" +
                    " HPeriod: " + "(" + HoldingPeriod + ")", Color.WHITE);
AddLabel(show_info, "CR= " + "(" + Return + ")",
        if Return>0 then Color.GREEN else if Return<0 then Color.RED else Color.GRAY);
AddLabel(show_info, "Trades: "   + "(" + totaltrades + ")", Color.WHITE);
AddLabel(show_info, "Win/Loss: " + "(" + winLoss + ")",
        if winLoss>1 then Color.GREEN else if winLoss<1 then Color.RED else Color.GRAY);
AddLabel(show_info, "Winrate: "  + "(" + winPer + "%)",
        if winPer>50 then Color.GREEN else if winPer<50 then Color.RED else Color.GRAY);

#-- End o fCode
Hi. I've been using the older version of this code shortly after you posting it (03/2023) and I found it quite useful. It shows a cleaner trend pattern.

Older code below.

Code:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © capissimo
#https://www.tradingview.com/v/3lZg4gmr/
#indicator("Machine Learning: kNN (New Approach)",
# Converted and mod by Sam4Cok@Samer800    - 03/2023
#//-- Inputs
input BarColor = yes;
input ShowLabel = yes;
input ShowOutcomes  = {"Line", "Predict", default "Both"};    # 'Show Outcomes'
input UseChartTimeframe = yes;
input Resolution    = AggregationPeriod.FIVE_MIN;    # 'Resolution'
input filterType = {"Volatility", "Volume", "Regime", "True Range", "All", default "None"}; # 'Filter Signals by'
input PredictionCalc = {Default "Average", "Rational Quadratic", "gaussian"};
input VolumeThreshold = 49;
input regimeThreshold = -0.1;
input usePrice   = yes;    # 'Use Price Data for Signal Generation?')
input Lag = 2;
input NoOfDataPoints = 10;     # 'No of Data Points'
input NoOfNearestNeighbors = 100;    # 'No of Nearest Neighbors'
input AdjustPrediction = yes;    # 'Adjust Prediction'
input NonRepainting    = no;     # 'Non-Repainting'
input addOn = {"None", "Pivot Point", default "Z-Score"};    # 'Add-On'
input PivotPointLag  = 5;                 # 'Pivot Point Lag'
input zScoreLag  = 20;                # 'Z-Score Lag'

#---
def na = Double.NaN;
def src = ohlc4;    # 'Projection Base'
def agg = GetAggregationPeriod();
def Rep = if NonRepainting then 1 else 0;
def last = IsNaN(close[-Rep]);# and isNaN(close[-2]);
def TF = if UseChartTimeframe then agg else Resolution;
def k = NoOfNearestNeighbors;
def Pvt = addOn == addOn."Pivot Point";
def zsc = addOn == addOn."Z-Score";
def curve   = ShowOutcomes == ShowOutcomes."Line";
def Predict = ShowOutcomes == ShowOutcomes."Predict";
def Both    = ShowOutcomes == ShowOutcomes."Both";
def Avg = PredictionCalc==PredictionCalc."Average";
def kernel = PredictionCalc==PredictionCalc."Rational Quadratic";
def h = if UseChartTimeframe then high[Rep] else high(Period = TF)[Rep];
def l = if UseChartTimeframe then low[Rep] else low(Period = TF)[Rep];
def c = if UseChartTimeframe then close[Rep] else close(Period = TF)[Rep];
def v = if UseChartTimeframe then volume[Rep] else volume(Period = TF)[Rep];

#--- Color
DefineGlobalColor("green" , CreateColor(0, 128, 255));
DefineGlobalColor("Red"   , CreateColor(255, 0, 128));
DefineGlobalColor("c_green" , CreateColor(0,153,136));
DefineGlobalColor("c_red"  , CreateColor(204,51,17));
#rationalQuadratic(series float _src, simple int _lookback, simple float _relativeWeight, simple int startAtBar) =>
script rationalQuadratic {
    input _src = close;
    input _lookback = 8;
    input _relativeWeight = 8;
    input startAtBar = 25;
    def _currentWeight;# = 0.
    def _cumulativeWeight;# = 0.
    def size = if !IsNaN(_src) then size[1] + 1 else size[1];
    def _size = if size >= 2000 then 1900 else size;
    _currentWeight =  fold i = 0 to _size + startAtBar with p do
        p + GetValue(_src, i) * (Power(1 + (Power(i, 2) / ((Power(_lookback, 2) * 2 * _relativeWeight))), -_relativeWeight));
    _cumulativeWeight =  fold i1 = 0 to _size + startAtBar with p1 do
        p1 +  (Power(1 + (Power(i1, 2) / ((Power(_lookback, 2) * 2 * _relativeWeight))), -_relativeWeight));
    def yhat = _currentWeight / _cumulativeWeight;
    plot out = yhat;
}
#gaussian(series float _src, simple int _lookback, simple int startAtBar) =>
script gaussian {
    input _src = close;
    input _lookback = 8;
    input startAtBar = 25;
    def _currentWeight;# = 0.
    def _cumulativeWeight;# = 0.
    def size = if !IsNaN(_src) then size[1] + 1 else size[1];
    def _size = if size >= 2000 then 1900 else size;
    _currentWeight = fold i = 0 to _size + startAtBar with q do
         q +  GetValue(_src, i) * Exp(-Power(i, 2) / (2 * Power(_lookback, 2)));
    _cumulativeWeight = fold i1 = 0 to _size + startAtBar with q1 do
         q1 + Exp(-Power(i1, 2) / (2 * Power(_lookback, 2)));
    def yhat = _currentWeight / _cumulativeWeight;
    plot out = yhat;
}
#minimax(ds, p, min, max) =>  // normalize to price
script minimax {
    input ds = close;
    input p = 10;
    input min = low;
    input max = high;#  // normalize to price
    def hi = Highest(ds, p);
    def lo = Lowest(ds, p);
    def minimax = (max - min) * (ds - lo) / (hi - lo) + min;
    plot out = minimax;
}
#volumeBreak(thres) =>
def rsivol   = RSI(Price = v, Length = 14);
def osc      = HullMovingAvg(rsivol, 10);
def volumeBreak = osc > VolumeThreshold;           
#volatilityBreak(volmin, volmax) =>
def tr     = TrueRange(h, c, l);
def atrMin = WildersAverage(tr, 1);
def atrMax = WildersAverage(tr, 10);
def volatilityBreak = atrMin > atrMax;
# @regime_filter
def value1;# = 0.0
def value2;# = 0.0
def klmf;# = 0.0
    value1 = 0.2 * (src - src[1]) + 0.8 * (value1[1]);
    value2 = 0.1 * (high - low) + 0.8 * (value2[1]);
def omega = AbsValue(value1 / value2);
def alpha = (-power(omega,2) + sqrt(power(omega, 4) + 16 * power(omega,2))) / 8;
    klmf = alpha * src + (1 - alpha) * (klmf[1]);
def absCurveSlope = AbsValue(klmf - klmf[1]);
def exponentialAverageAbsCurveSlope = 1.0 * ExpAverage(absCurveSlope, 200);
def normalized_slope_decline = (absCurveSlope - exponentialAverageAbsCurveSlope) / exponentialAverageAbsCurveSlope;
def regime = normalized_slope_decline >= regimeThreshold;
def trFilt = atr(Length=1) > atr(Length=10);
def all = volatilityBreak and volumeBreak and Regime and trFilt;

def filter = if filterType == filterType."Volatility" then volatilityBreak else
             if filterType == filterType."Volume" then volumeBreak else
             if filterType == filterType."Regime" then Regime else
             if filterType == filterType."True Range" then trFilt else
             if filterType == filterType."All" then all else yes;
#--- Logic
def nearest_neighbors;

def d = fold i = 0 to NoOfDataPoints - 1 with p do
        AbsValue(c[i] - GetValue(c, i + 1));

def size = fold i1 = 0 to NoOfDataPoints  - 1  with p1 do
        if !IsNaN(d[i1]) then p1 + 1 else p1;

def new_neighbor = fold i2 = 0 to NoOfDataPoints - 1 with p2 do
                   if d[i2] < Min(d[i2], If(size[i2] > k, k, 0)) then GetValue(c, i2 + 1) else c[i2];

nearest_neighbors = fold i3 = 0 to NoOfDataPoints - 1 with p3 do
                        GetValue(new_neighbor, -i3);

def predAvg = Average(nearest_neighbors, NoOfDataPoints);
def predRQ = rationalQuadratic(nearest_neighbors, NoOfDataPoints, NoOfDataPoints, NoOfNearestNeighbors);
def loss   = gaussian(nearest_neighbors, NoOfDataPoints, NoOfNearestNeighbors);

def prediction = if Avg then predAvg else if kernel then predRQ else loss;
def synth_ds = Log(AbsValue(Power(C, 2) - 1) + .5);
def synth = synth_ds;

def scaled_loss = minimax(prediction, NoOfDataPoints - Lag, Lowest(synth, NoOfDataPoints), Highest(synth, NoOfDataPoints));
def scaled_pred = minimax(prediction, NoOfDataPoints, Lowest(synth, NoOfDataPoints), Highest(synth, NoOfDataPoints));

#-- signals
def signal =  if usePrice then
              if synth < scaled_loss and filter then -1 else
              if synth > scaled_loss and filter then 1 else signal[1] else
              if (scaled_loss crosses below scaled_pred) and filter then -1 else
              if (scaled_loss crosses above scaled_pred) and filter then 1 else signal[1];
def changed = (signal - signal[1]);
def hp_counter = if changed then 0 else hp_counter[1] + 1;

def startLongTrade  = changed and signal > 0;
def startShortTrade = changed and signal < 0;

#-- Pred
def dir  = if prediction < c[!AdjustPrediction] then 1 else
           if prediction > c[!AdjustPrediction] then -1 else 0;
def ordinary_color = dir;
def ph = if h == Highest(h, PivotPointLag) then h else 0;
def pl = if l == Lowest(l, PivotPointLag)  then l else 0;
def pivot_color = if ph and dir ==  1 then 1 else
                  if pl and dir == -1 then -1 else 0;
#zscore_color(data, LAGZ, dir) =>
def zs = (C - Average(C, zScoreLag)) / StDev(C, zScoreLag);
def zsCon = zs / (zScoreLag / 5);
def zscore_color = if zsCon > 0 and dir == 1 then 1 else
                   if zsCon < 0 and dir == -1 then -1 else 0;
#//-- Logic

#def nn     = nearest_neighbors;
def pred   = prediction;
def clr    = if zsc then zscore_color else
             if Pvt then pivot_color else ordinary_color;

#//-- Visuals

plot kNNCurve = if IsNaN(close) then na else if (curve or Both) then pred else na;#, 'kNN Curve'
kNNCurve.SetLineWeight(2);
kNNCurve.AssignValueColor(if clr > 0 then GlobalColor("green") else
                          if clr < 0 then GlobalColor("red") else Color.DARK_GRAY);

plot Predc = if last and last[Rep + 1] and (Predict or Both) then src[2] else na;
Predc.AssignValueColor(if clr[2] > 0 then GlobalColor("green") else
                       if clr[2] < 0 then GlobalColor("red") else Color.DARK_GRAY);
Predc.SetPaintingStrategy(PaintingStrategy.POINTS);
Predc.SetLineWeight(3);

#--- Labels
AddLabel(ShowLabel, if clr > 0 then "Prediction: UP" else
                   if clr < 0 then "Prediction: Down" else "Prediction: Nutral",
                   if clr > 0 then Color.GREEN else
                   if clr < 0 then GlobalColor("red") else Color.DARK_GRAY);
#-- Bar Colors
AssignPriceColor(if !BarColor then Color.CURRENT else
                 if clr > 0 then GlobalColor("c_green") else
                 if clr < 0 then GlobalColor("c_red") else Color.DARK_GRAY);
#-- Bubbles

##AddChartBubble(startLongTrade, l, "L", GlobalColor("c_green"), no);
##AddChartBubble(startShortTrade, h, "S", GlobalColor("c_red"), yes);

#--- END CODE

# https://usethinkscript.com/threads/machine-learning-knn-new-approach-for-thinkorswim.14810/

Quick question, is there a way to make a daily scan of this where it will trigger on the first green after a minimum of 3 reds?

Thanks in advanced.
 
Hi. I've been using the older version of this code shortly after you posting it (03/2023) and I found it quite useful. It shows a cleaner trend pattern.

Older code below.

Code:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © capissimo
#https://www.tradingview.com/v/3lZg4gmr/
#indicator("Machine Learning: kNN (New Approach)",
# Converted and mod by Sam4Cok@Samer800    - 03/2023
#//-- Inputs
input BarColor = yes;
input ShowLabel = yes;
input ShowOutcomes  = {"Line", "Predict", default "Both"};    # 'Show Outcomes'
input UseChartTimeframe = yes;
input Resolution    = AggregationPeriod.FIVE_MIN;    # 'Resolution'
input filterType = {"Volatility", "Volume", "Regime", "True Range", "All", default "None"}; # 'Filter Signals by'
input PredictionCalc = {Default "Average", "Rational Quadratic", "gaussian"};
input VolumeThreshold = 49;
input regimeThreshold = -0.1;
input usePrice   = yes;    # 'Use Price Data for Signal Generation?')
input Lag = 2;
input NoOfDataPoints = 10;     # 'No of Data Points'
input NoOfNearestNeighbors = 100;    # 'No of Nearest Neighbors'
input AdjustPrediction = yes;    # 'Adjust Prediction'
input NonRepainting    = no;     # 'Non-Repainting'
input addOn = {"None", "Pivot Point", default "Z-Score"};    # 'Add-On'
input PivotPointLag  = 5;                 # 'Pivot Point Lag'
input zScoreLag  = 20;                # 'Z-Score Lag'

#---
def na = Double.NaN;
def src = ohlc4;    # 'Projection Base'
def agg = GetAggregationPeriod();
def Rep = if NonRepainting then 1 else 0;
def last = IsNaN(close[-Rep]);# and isNaN(close[-2]);
def TF = if UseChartTimeframe then agg else Resolution;
def k = NoOfNearestNeighbors;
def Pvt = addOn == addOn."Pivot Point";
def zsc = addOn == addOn."Z-Score";
def curve   = ShowOutcomes == ShowOutcomes."Line";
def Predict = ShowOutcomes == ShowOutcomes."Predict";
def Both    = ShowOutcomes == ShowOutcomes."Both";
def Avg = PredictionCalc==PredictionCalc."Average";
def kernel = PredictionCalc==PredictionCalc."Rational Quadratic";
def h = if UseChartTimeframe then high[Rep] else high(Period = TF)[Rep];
def l = if UseChartTimeframe then low[Rep] else low(Period = TF)[Rep];
def c = if UseChartTimeframe then close[Rep] else close(Period = TF)[Rep];
def v = if UseChartTimeframe then volume[Rep] else volume(Period = TF)[Rep];

#--- Color
DefineGlobalColor("green" , CreateColor(0, 128, 255));
DefineGlobalColor("Red"   , CreateColor(255, 0, 128));
DefineGlobalColor("c_green" , CreateColor(0,153,136));
DefineGlobalColor("c_red"  , CreateColor(204,51,17));
#rationalQuadratic(series float _src, simple int _lookback, simple float _relativeWeight, simple int startAtBar) =>
script rationalQuadratic {
    input _src = close;
    input _lookback = 8;
    input _relativeWeight = 8;
    input startAtBar = 25;
    def _currentWeight;# = 0.
    def _cumulativeWeight;# = 0.
    def size = if !IsNaN(_src) then size[1] + 1 else size[1];
    def _size = if size >= 2000 then 1900 else size;
    _currentWeight =  fold i = 0 to _size + startAtBar with p do
        p + GetValue(_src, i) * (Power(1 + (Power(i, 2) / ((Power(_lookback, 2) * 2 * _relativeWeight))), -_relativeWeight));
    _cumulativeWeight =  fold i1 = 0 to _size + startAtBar with p1 do
        p1 +  (Power(1 + (Power(i1, 2) / ((Power(_lookback, 2) * 2 * _relativeWeight))), -_relativeWeight));
    def yhat = _currentWeight / _cumulativeWeight;
    plot out = yhat;
}
#gaussian(series float _src, simple int _lookback, simple int startAtBar) =>
script gaussian {
    input _src = close;
    input _lookback = 8;
    input startAtBar = 25;
    def _currentWeight;# = 0.
    def _cumulativeWeight;# = 0.
    def size = if !IsNaN(_src) then size[1] + 1 else size[1];
    def _size = if size >= 2000 then 1900 else size;
    _currentWeight = fold i = 0 to _size + startAtBar with q do
         q +  GetValue(_src, i) * Exp(-Power(i, 2) / (2 * Power(_lookback, 2)));
    _cumulativeWeight = fold i1 = 0 to _size + startAtBar with q1 do
         q1 + Exp(-Power(i1, 2) / (2 * Power(_lookback, 2)));
    def yhat = _currentWeight / _cumulativeWeight;
    plot out = yhat;
}
#minimax(ds, p, min, max) =>  // normalize to price
script minimax {
    input ds = close;
    input p = 10;
    input min = low;
    input max = high;#  // normalize to price
    def hi = Highest(ds, p);
    def lo = Lowest(ds, p);
    def minimax = (max - min) * (ds - lo) / (hi - lo) + min;
    plot out = minimax;
}
#volumeBreak(thres) =>
def rsivol   = RSI(Price = v, Length = 14);
def osc      = HullMovingAvg(rsivol, 10);
def volumeBreak = osc > VolumeThreshold;         
#volatilityBreak(volmin, volmax) =>
def tr     = TrueRange(h, c, l);
def atrMin = WildersAverage(tr, 1);
def atrMax = WildersAverage(tr, 10);
def volatilityBreak = atrMin > atrMax;
# @regime_filter
def value1;# = 0.0
def value2;# = 0.0
def klmf;# = 0.0
    value1 = 0.2 * (src - src[1]) + 0.8 * (value1[1]);
    value2 = 0.1 * (high - low) + 0.8 * (value2[1]);
def omega = AbsValue(value1 / value2);
def alpha = (-power(omega,2) + sqrt(power(omega, 4) + 16 * power(omega,2))) / 8;
    klmf = alpha * src + (1 - alpha) * (klmf[1]);
def absCurveSlope = AbsValue(klmf - klmf[1]);
def exponentialAverageAbsCurveSlope = 1.0 * ExpAverage(absCurveSlope, 200);
def normalized_slope_decline = (absCurveSlope - exponentialAverageAbsCurveSlope) / exponentialAverageAbsCurveSlope;
def regime = normalized_slope_decline >= regimeThreshold;
def trFilt = atr(Length=1) > atr(Length=10);
def all = volatilityBreak and volumeBreak and Regime and trFilt;

def filter = if filterType == filterType."Volatility" then volatilityBreak else
             if filterType == filterType."Volume" then volumeBreak else
             if filterType == filterType."Regime" then Regime else
             if filterType == filterType."True Range" then trFilt else
             if filterType == filterType."All" then all else yes;
#--- Logic
def nearest_neighbors;

def d = fold i = 0 to NoOfDataPoints - 1 with p do
        AbsValue(c[i] - GetValue(c, i + 1));

def size = fold i1 = 0 to NoOfDataPoints  - 1  with p1 do
        if !IsNaN(d[i1]) then p1 + 1 else p1;

def new_neighbor = fold i2 = 0 to NoOfDataPoints - 1 with p2 do
                   if d[i2] < Min(d[i2], If(size[i2] > k, k, 0)) then GetValue(c, i2 + 1) else c[i2];

nearest_neighbors = fold i3 = 0 to NoOfDataPoints - 1 with p3 do
                        GetValue(new_neighbor, -i3);

def predAvg = Average(nearest_neighbors, NoOfDataPoints);
def predRQ = rationalQuadratic(nearest_neighbors, NoOfDataPoints, NoOfDataPoints, NoOfNearestNeighbors);
def loss   = gaussian(nearest_neighbors, NoOfDataPoints, NoOfNearestNeighbors);

def prediction = if Avg then predAvg else if kernel then predRQ else loss;
def synth_ds = Log(AbsValue(Power(C, 2) - 1) + .5);
def synth = synth_ds;

def scaled_loss = minimax(prediction, NoOfDataPoints - Lag, Lowest(synth, NoOfDataPoints), Highest(synth, NoOfDataPoints));
def scaled_pred = minimax(prediction, NoOfDataPoints, Lowest(synth, NoOfDataPoints), Highest(synth, NoOfDataPoints));

#-- signals
def signal =  if usePrice then
              if synth < scaled_loss and filter then -1 else
              if synth > scaled_loss and filter then 1 else signal[1] else
              if (scaled_loss crosses below scaled_pred) and filter then -1 else
              if (scaled_loss crosses above scaled_pred) and filter then 1 else signal[1];
def changed = (signal - signal[1]);
def hp_counter = if changed then 0 else hp_counter[1] + 1;

def startLongTrade  = changed and signal > 0;
def startShortTrade = changed and signal < 0;

#-- Pred
def dir  = if prediction < c[!AdjustPrediction] then 1 else
           if prediction > c[!AdjustPrediction] then -1 else 0;
def ordinary_color = dir;
def ph = if h == Highest(h, PivotPointLag) then h else 0;
def pl = if l == Lowest(l, PivotPointLag)  then l else 0;
def pivot_color = if ph and dir ==  1 then 1 else
                  if pl and dir == -1 then -1 else 0;
#zscore_color(data, LAGZ, dir) =>
def zs = (C - Average(C, zScoreLag)) / StDev(C, zScoreLag);
def zsCon = zs / (zScoreLag / 5);
def zscore_color = if zsCon > 0 and dir == 1 then 1 else
                   if zsCon < 0 and dir == -1 then -1 else 0;
#//-- Logic

#def nn     = nearest_neighbors;
def pred   = prediction;
def clr    = if zsc then zscore_color else
             if Pvt then pivot_color else ordinary_color;

#//-- Visuals

plot kNNCurve = if IsNaN(close) then na else if (curve or Both) then pred else na;#, 'kNN Curve'
kNNCurve.SetLineWeight(2);
kNNCurve.AssignValueColor(if clr > 0 then GlobalColor("green") else
                          if clr < 0 then GlobalColor("red") else Color.DARK_GRAY);

plot Predc = if last and last[Rep + 1] and (Predict or Both) then src[2] else na;
Predc.AssignValueColor(if clr[2] > 0 then GlobalColor("green") else
                       if clr[2] < 0 then GlobalColor("red") else Color.DARK_GRAY);
Predc.SetPaintingStrategy(PaintingStrategy.POINTS);
Predc.SetLineWeight(3);

#--- Labels
AddLabel(ShowLabel, if clr > 0 then "Prediction: UP" else
                   if clr < 0 then "Prediction: Down" else "Prediction: Nutral",
                   if clr > 0 then Color.GREEN else
                   if clr < 0 then GlobalColor("red") else Color.DARK_GRAY);
#-- Bar Colors
AssignPriceColor(if !BarColor then Color.CURRENT else
                 if clr > 0 then GlobalColor("c_green") else
                 if clr < 0 then GlobalColor("c_red") else Color.DARK_GRAY);
#-- Bubbles

##AddChartBubble(startLongTrade, l, "L", GlobalColor("c_green"), no);
##AddChartBubble(startShortTrade, h, "S", GlobalColor("c_red"), yes);

#--- END CODE

# https://usethinkscript.com/threads/machine-learning-knn-new-approach-for-thinkorswim.14810/

Quick question, is there a way to make a daily scan of this where it will trigger on the first green after a minimum of 3 reds?

Thanks in advanced.
Thanks for sharing, this one seems to give much better signals, I wonder why the new/upgraded one seems to give such different results. @samer800 did both too.

@Musk335im3, where is that code on this usethinkscript? I couldn't find it anywhere else here.

Regarding the scan, I don't think it'd be possible just due to the script being too complex.
 
Thanks for sharing, this one seems to give much better signals, I wonder why the new/upgraded one seems to give such different results. @samer800 did both too.

@Musk335im3, where is that code on this usethinkscript? I couldn't find it anywhere else here.

Regarding the scan, I don't think it'd be possible just due to the script being too complex.
Hi.

I think I got this code within this thread when it was first created and I think the OP subsequently edited it. I just don't know when or can't confirm.

As it has been working with me since first posted I didn't bother modifying (nor I am capable of doing it).

I scan version of this would be really great, IMO.
 
Thread starter Similar threads Forum Replies Date
J Repaints Machine Learning: Logistic Regression For ThinkOrSwim Custom 2

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
499 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top