0% found this document useful (0 votes)
1 views

Pine script-2

The document is a Pine Script code for a trading indicator that combines various filters such as EMA, RSI, Hull, and Supertrend for Lorentzian classification and a no-repaint strategy. It includes settings for user-defined inputs, feature engineering, and machine learning components to enhance trading signals. The script also features visual elements for plotting buy and sell signals based on the specified filters and conditions.
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

Pine script-2

The document is a Pine Script code for a trading indicator that combines various filters such as EMA, RSI, Hull, and Supertrend for Lorentzian classification and a no-repaint strategy. It includes settings for user-defined inputs, feature engineering, and machine learning components to enhance trading signals. The script also features visual elements for plotting buy and sell signals based on the specified filters and conditions.
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

//@version=5

indicator('Lorentzian and NO-REPAINT', overlay=true, precision=4,


max_labels_count=500)

use_ema1 = input(true, "Use EMA filter", group="Filters for Lorentzian


Classification")
use_rsi1 = input(true, "Use RSI filter", group="Filters for Lorentzian
Classification")
use_hma1 = input(true, "Use Hull filter", group="Filters for Lorentzian
Classification")
use_st1 = input(true, "Use Supertrend filter", group="Filters for Lorentzian
Classification")
use_ema2 = input(true, "Use EMA filter", group="Filters for NO-REPAINT")
use_rsi2 = input(true, "Use RSI filter", group="Filters for NO-REPAINT")
use_hma2 = input(true, "Use Hull filter", group="Filters for NO-REPAINT")
use_st2 = input(true, "Use Supertrend filter", group="Filters for NO-REPAINT")

ema = ta.ema(input(close,"Source",group="EMA"),input(10,"Length",group="EMA"))
plot(ema, "EMA", color=color.white)
// study("RSI Cloud by Wilson", "RSI Cloud")

length1 = input.int(defval=14, minval=1, title='RSI Length', group="RSI Cloud")


length2 = input.int(defval=9, minval=2, title='MA Length', group="RSI Cloud")
src1 = input(close, title='RSI Source', group="RSI Cloud")
rsi = ta.rsi(src1, length1)
type = input.string(defval='SMA', options=['SMA', 'EMA', 'WMA', 'VWMA', 'HullMA',
'ALMA'], title='MA Type', group="RSI Cloud")
almaOffset = input.float(0.85, title='ALMA Offset', group="RSI Cloud")
almaSigma = input.int(6, minval=0, title='ALMA Sigma', group="RSI Cloud")
maplot = type == 'SMA' ? ta.sma(rsi, length2) : type == 'EMA' ? ta.ema(rsi,
length2) : type == 'WMA' ? ta.wma(rsi, length2) : type == 'VWMA' ? ta.vwma(rsi,
length2) : type == 'HullMA' ? ta.wma(2 * ta.wma(rsi, length2 / 2) - ta.wma(rsi,
length2), math.round(math.sqrt(length2))) : type == 'ALMA' ? ta.alma(rsi, length2,
almaOffset, almaSigma) : na
// diffp = (rsi - maplot) / maplot * 100
// diffn = (maplot - rsi) / maplot * 100

// //@version=5
// indicator("Hull Butterfly Oscillator [LuxAlgo]", "Hull Butterfly Oscillator
[LuxAlgo]")
//-----------------------------------------------------------------------------}
//Settings
//----------------------------------------------------a-------------------------{
lengthh = input(14, group="Hull Butterfly Oscillator")

mult = input(2., 'Levels Multiplier', group="Hull Butterfly Oscillator")

srch = input(close, group="Hull Butterfly Oscillator")

//Style
bull_css_0 = input.color(color.new(#0cb51a, 50), 'Bullish Gradient'
, inline = 'inline0'
, group = 'Hull Butterfly Oscillator')

bull_css_1 = input.color(#0cb51a, ''


, inline = 'inline0'
, group = 'Hull Butterfly Oscillator')

bear_css_0 = input.color(color.new(#ff1100, 50), 'Bearish Gradient'


, inline = 'inline1'
, group = 'Hull Butterfly Oscillator')

bear_css_1 = input.color(#ff1100, ''


, inline = 'inline1'
, group = 'Hull Butterfly Oscillator')

//-----------------------------------------------------------------------------}
//Normalization variables
//-----------------------------------------------------------------------------{
var short_len = int(lengthh / 2)
var hull_len = int(math.sqrt(lengthh))

var den1 = short_len * (short_len + 1) / 2


var den2 = lengthh * (lengthh + 1) / 2
var den3 = hull_len * (hull_len + 1) / 2

//-----------------------------------------------------------------------------}
//Hull coefficients
//-----------------------------------------------------------------------------{
var lcwa_coeffs = array.new_float(hull_len, 0)
var hull_coeffs = array.new_float(0)

if barstate.isfirst
//Linearly combined WMA coeffs
for i = 0 to lengthh-1
sum1 = math.max(short_len - i, 0)
sum2 = lengthh - i

array.unshift(lcwa_coeffs, 2 * (sum1 / den1) - (sum2 / den2))

//Zero padding of linearly combined WMA coeffs


for i = 0 to hull_len-2
array.unshift(lcwa_coeffs, 0)

//WMA convolution of linearly combined WMA coeffs


for i = hull_len to array.size(lcwa_coeffs)-1
sum3 = 0.
for j = i-hull_len to i-1
sum3 += array.get(lcwa_coeffs, j) * (i - j)

array.unshift(hull_coeffs, sum3 / den3)

//-----------------------------------------------------------------------------}
//Hull squeeze oscillator
//-----------------------------------------------------------------------------{
var os = 0
var len = array.size(hull_coeffs)-1
hma = 0.
inv_hma = 0.

for i = 0 to len
hma += srch[i] * array.get(hull_coeffs, i)
inv_hma += srch[len-i] * array.get(hull_coeffs, i)
hso = hma - inv_hma

cmean = ta.cum(math.abs(hso)) / bar_index * mult

os := ta.cross(hso, cmean) or ta.cross(hso, -cmean) ? 0


: hso < hso[1] and hso > cmean ? -1
: hso > hso[1] and hso < -cmean ? 1
: os

//-----------------------------------------------------------------------------}
//Plot
//-----------------------------------------------------------------------------{
//Colors
css0 = color.from_gradient(hso, 0, cmean, bull_css_0, bull_css_1)
css1 = color.from_gradient(hso, -cmean, 0, bear_css_1, bear_css_0)
css = hso > 0 ? css0 : css1

// //Oscillator line/histogram
// plot(hso, 'Hull Butterfly', css
// , style = plot.style_histogram)

atrPeriod = input.int(10, "ATR Length", minval = 1, group="Supertrend")


factor = input.float(3.0, "Factor", minval = 0.01, step = 0.01,
group="Supertrend")

[supertrend, directionc] = ta.supertrend(factor, atrPeriod)

supertrend := barstate.isfirst ? na : supertrend


upTrend = plot(directionc < 0 ? supertrend : na, "ST - Up Trend", color =
color.green, style = plot.style_linebr)
downTrend = plot(directionc < 0 ? na : supertrend, "ST - Down Trend", color =
color.red, style = plot.style_linebr)
bodyMiddle = plot(barstate.isfirst ? na : (open + close) / 2, "ST - Body
Middle",display = display.none)

fill(bodyMiddle, upTrend, color.new(color.green, 90), fillgaps = false)


fill(bodyMiddle, downTrend, color.new(color.red, 90), fillgaps = false)

ema_buy1 = use_ema1?low>ema:true
ema_sell1 = use_ema1?high<ema:true

rsi_buy1 = use_rsi1?rsi>maplot:true
rsi_sell1 = use_rsi1?rsi<maplot:true

hma_buy1 = use_hma1?hso>0:true
hma_sell1 = use_hma1?hso<=0:true

st_buy1 = use_st1 ? directionc==-1:true


st_sell1 = use_st1 ? directionc==1:true
filt_buy1 = ema_buy1 and rsi_buy1 and hma_buy1 and st_buy1
filt_sell1 = ema_sell1 and rsi_sell1 and hma_sell1 and st_sell1

ema_buy2 = use_ema2?low>ema:true
ema_sell2 = use_ema2?high<ema:true
rsi_buy2 = use_rsi2?rsi>maplot:true
rsi_sell2 = use_rsi2?rsi<maplot:true
hma_buy2 = use_hma2?hso>0:true
hma_sell2 = use_hma2?hso<=0:true
st_buy2 = use_st2 ? directionc==-1:true
st_sell2 = use_st2 ? directionc==1:true

filt_buy2 = ema_buy2 and rsi_buy2 and hma_buy2 and st_buy2


filt_sell2 = ema_sell2 and rsi_sell2 and hma_sell2 and st_sell2

srcn = input(hl2, 'Price Data', group="NO REPAINT")


length = input(13, 'Lookback Window (originally = 24)', group="NO REPAINT")
showcross = input(true, 'Show labels?', group="NO REPAINT")
k = input(true, 'Use Kahlman Smoother?', group="NO REPAINT")
gain = input.float(1., 'Gain for the Smoother', step=.001, group="NO REPAINT")
o = input(true, 'Offset by 1 candle?', group="NO REPAINT")

hma1(x, p) =>
ta.wma(2 * ta.wma(x, p / 2) - ta.wma(x, p), math.round(math.sqrt(p)))
hma3(x, p) =>
per = p / 2
ta.wma(ta.wma(x, per / 3) * 3 - ta.wma(x, per / 2) - ta.wma(x, per), per)

kahlman(x, g) =>
kf = 0.0
dk = x - nz(kf[1], x)
smooth = nz(kf[1], x) + dk * math.sqrt(g * 2)
velo = 0.0
velo := nz(velo[1], 0) + g * dk
kf := smooth + velo
kf

a = k ? kahlman(hma1(srcn, length), gain) : hma1(srcn, length)


b = k ? kahlman(hma3(close, length), gain) : hma3(close, length)
c = b > a ? color.new(color.lime,75) : color.new(color.red,75)
long = b>a and b[1]<a[1] and filt_buy2
short = a>b and a[1]<b[1] and filt_sell2

fill(plot(a, color=c, linewidth=1), plot(b, color=c, linewidth=1), color=c)


plotshape(showcross and long ? a : na, location=location.belowbar,
style=shape.labelup, color=color.new(color.green, 0), size=size.tiny, text='B',
textcolor=color.new(color.white, 0), offset=o ? -1 : 0)
plotshape(showcross and short ? a : na, location=location.abovebar,
style=shape.labeldown, color=color.new(color.red, 0), size=size.tiny, text='S',
textcolor=color.new(color.white, 0), offset=o ? -1 : 0)

// indicator('Machine Learning: Lorentzian Classification', 'Lorentzian


Classification', true, precision=4, max_labels_count=500)

import jdehorty/MLExtensions/2 as ml
import jdehorty/KernelFunctions/2 as kernels
type Settings
float source
int neighborsCount
int maxBarsBack
int featureCount
int colorCompression
bool showExits
bool useDynamicExits

type Label
int long
int short
int neutral

type FeatureArrays
array<float> f1
array<float> f2
array<float> f3
array<float> f4
array<float> f5

type FeatureSeries
float f1
float f2
float f3
float f4
float f5

type MLModel
int firstBarIndex
array<int> trainingLabels
int loopSize
float lastDistance
array<float> distancesArray
array<int> predictionsArray
int prediction

type FilterSettings
bool useVolatilityFilter
bool useRegimeFilter
bool useAdxFilter
float regimeThreshold
int adxThreshold

type Filter
bool volatility
bool regime
bool adx

// ==========================
// ==== Helper Functions ====
// ==========================

series_from(feature_string, _close, _high, _low, _hlc3, f_paramA, f_paramB) =>


switch feature_string
"RSI" => ml.n_rsi(_close, f_paramA, f_paramB)
"WT" => ml.n_wt(_hlc3, f_paramA, f_paramB)
"CCI" => ml.n_cci(_close, f_paramA, f_paramB)
"ADX" => ml.n_adx(_high, _low, _close, f_paramA)
get_lorentzian_distance(int i, int featureCount, FeatureSeries featureSeries,
FeatureArrays featureArrays) =>
switch featureCount
5 => math.log(1+math.abs(featureSeries.f1 - array.get(featureArrays.f1,
i))) +
math.log(1+math.abs(featureSeries.f2 - array.get(featureArrays.f2,
i))) +
math.log(1+math.abs(featureSeries.f3 - array.get(featureArrays.f3,
i))) +
math.log(1+math.abs(featureSeries.f4 - array.get(featureArrays.f4,
i))) +
math.log(1+math.abs(featureSeries.f5 - array.get(featureArrays.f5,
i)))
4 => math.log(1+math.abs(featureSeries.f1 - array.get(featureArrays.f1,
i))) +
math.log(1+math.abs(featureSeries.f2 - array.get(featureArrays.f2,
i))) +
math.log(1+math.abs(featureSeries.f3 - array.get(featureArrays.f3,
i))) +
math.log(1+math.abs(featureSeries.f4 - array.get(featureArrays.f4,
i)))
3 => math.log(1+math.abs(featureSeries.f1 - array.get(featureArrays.f1,
i))) +
math.log(1+math.abs(featureSeries.f2 - array.get(featureArrays.f2,
i))) +
math.log(1+math.abs(featureSeries.f3 - array.get(featureArrays.f3,
i)))
2 => math.log(1+math.abs(featureSeries.f1 - array.get(featureArrays.f1,
i))) +
math.log(1+math.abs(featureSeries.f2 - array.get(featureArrays.f2,
i)))

// Settings Object: General User-Defined Inputs


Settings settings =
Settings.new(
input.source(title='Source', defval=close, group="Lorentzian : General
Settings", tooltip="Source of the input data"),
input.int(title='Neighbors Count', defval=8, group="Lorentzian : General
Settings", minval=1, maxval=100, step=1, tooltip="Number of neighbors to
consider"),
input.int(title="Max Bars Back", defval=2000, group="Lorentzian : General
Settings"),
input.int(title="Feature Count", defval=5, group="Feature Engineering",
minval=2, maxval=5, tooltip="Number of features to use for ML predictions."),
input.int(title="Color Compression", defval=1, group="Lorentzian : General
Settings", minval=1, maxval=10, tooltip="Compression factor for adjusting the
intensity of the color scale."),
input.bool(title="Show Default Exits", defval=false, group="Lorentzian : General
Settings", tooltip="Default exits occur exactly 4 bars after an entry signal. This
corresponds to the predefined length of a trade during the model's training
process.", inline="exits"),
input.bool(title="Use Dynamic Exits", defval=false, group="Lorentzian : General
Settings", tooltip="Dynamic exits attempt to let profits ride by dynamically
adjusting the exit threshold based on kernel regression logic.", inline="exits")
)

// Trade Stats Settings


// Note: The trade stats section is NOT intended to be used as a replacement for
proper backtesting. It is intended to be used for calibration purposes only.
showTradeStats = input.bool(true, 'Show Trade Stats', tooltip='Displays the trade
stats for a given configuration. Useful for optimizing the settings in the Feature
Engineering section. This should NOT replace backtesting and should be used for
calibration purposes only. Early Signal Flips represent instances where the model
changes signals before 4 bars elapses; high values can indicate choppy (ranging)
market conditions.', group="Lorentzian : General Settings")
useWorstCase = input.bool(false, "Use Worst Case Estimates", tooltip="Whether to
use the worst case scenario for backtesting. This option can be useful for creating
a conservative estimate that is based on close prices only, thus avoiding the
effects of intrabar repainting. This option assumes that the user does not enter
when the signal first appears and instead waits for the bar to close as
confirmation. On larger timeframes, this can mean entering after a large move has
already occurred. Leaving this option disabled is generally better for those that
use this indicator as a source of confluence and prefer estimates that demonstrate
discretionary mid-bar entries. Leaving this option enabled may be more consistent
with traditional backtesting results.", group="Lorentzian : General Settings")

// Settings object for user-defined settings


FilterSettings filterSettings =
FilterSettings.new(
input.bool(title="Use Volatility Filter", defval=true, tooltip="Whether to use
the volatility filter.", group="Filters"),
input.bool(title="Use Regime Filter", defval=true, group="Filters",
inline="regime"),
input.bool(title="Use ADX Filter", defval=false, group="Filters", inline="adx"),
input.float(title="Threshold", defval=-0.1, minval=-10, maxval=10, step=0.1,
tooltip="Whether to use the trend detection filter. Threshold for detecting
Trending/Ranging markets.", group="Filters", inline="regime"),
input.int(title="Threshold", defval=20, minval=0, maxval=100, step=1,
tooltip="Whether to use the ADX filter. Threshold for detecting Trending/Ranging
markets.", group="Filters", inline="adx")
)

// Filter object for filtering the ML predictions


Filter filter =
Filter.new(
ml.filter_volatility(1, 10, filterSettings.useVolatilityFilter),
ml.regime_filter(ohlc4, filterSettings.regimeThreshold,
filterSettings.useRegimeFilter),
ml.filter_adx(settings.source, 14, filterSettings.adxThreshold,
filterSettings.useAdxFilter)
)

// Feature Variables: User-Defined Inputs for calculating Feature Series.


f1_string = input.string(title="Feature 1", options=["RSI", "WT", "CCI", "ADX"],
defval="RSI", inline = "01", tooltip="The first feature to use for ML
predictions.", group="Feature Engineering")
f1_paramA = input.int(title="Parameter A", tooltip="The primary parameter of
feature 1.", defval=14, inline = "02", group="Feature Engineering")
f1_paramB = input.int(title="Parameter B", tooltip="The secondary parameter of
feature 2 (if applicable).", defval=1, inline = "02", group="Feature Engineering")
f2_string = input.string(title="Feature 2", options=["RSI", "WT", "CCI", "ADX"],
defval="WT", inline = "03", tooltip="The second feature to use for ML
predictions.", group="Feature Engineering")
f2_paramA = input.int(title="Parameter A", tooltip="The primary parameter of
feature 2.", defval=10, inline = "04", group="Feature Engineering")
f2_paramB = input.int(title="Parameter B", tooltip="The secondary parameter of
feature 2 (if applicable).", defval=11, inline = "04", group="Feature Engineering")
f3_string = input.string(title="Feature 3", options=["RSI", "WT", "CCI", "ADX"],
defval="CCI", inline = "05", tooltip="The third feature to use for ML
predictions.", group="Feature Engineering")
f3_paramA = input.int(title="Parameter A", tooltip="The primary parameter of
feature 3.", defval=20, inline = "06", group="Feature Engineering")
f3_paramB = input.int(title="Parameter B", tooltip="The secondary parameter of
feature 3 (if applicable).", defval=1, inline = "06", group="Feature Engineering")
f4_string = input.string(title="Feature 4", options=["RSI", "WT", "CCI", "ADX"],
defval="ADX", inline = "07", tooltip="The fourth feature to use for ML
predictions.", group="Feature Engineering")
f4_paramA = input.int(title="Parameter A", tooltip="The primary parameter of
feature 4.", defval=20, inline = "08", group="Feature Engineering")
f4_paramB = input.int(title="Parameter B", tooltip="The secondary parameter of
feature 4 (if applicable).", defval=2, inline = "08", group="Feature Engineering")
f5_string = input.string(title="Feature 5", options=["RSI", "WT", "CCI", "ADX"],
defval="RSI", inline = "09", tooltip="The fifth feature to use for ML
predictions.", group="Feature Engineering")
f5_paramA = input.int(title="Parameter A", tooltip="The primary parameter of
feature 5.", defval=9, inline = "10", group="Feature Engineering")
f5_paramB = input.int(title="Parameter B", tooltip="The secondary parameter of
feature 5 (if applicable).", defval=1, inline = "10", group="Feature Engineering")

// FeatureSeries Object: Calculated Feature Series based on Feature Variables


featureSeries =
FeatureSeries.new(
series_from(f1_string, close, high, low, hlc3, f1_paramA, f1_paramB), // f1
series_from(f2_string, close, high, low, hlc3, f2_paramA, f2_paramB), // f2
series_from(f3_string, close, high, low, hlc3, f3_paramA, f3_paramB), // f3
series_from(f4_string, close, high, low, hlc3, f4_paramA, f4_paramB), // f4
series_from(f5_string, close, high, low, hlc3, f5_paramA, f5_paramB) // f5
)

// FeatureArrays Variables: Storage of Feature Series as Feature Arrays Optimized


for ML
// Note: These arrays cannot be dynamically created within the FeatureArrays Object
Initialization and thus must be set-up in advance.
var f1Array = array.new_float()
var f2Array = array.new_float()
var f3Array = array.new_float()
var f4Array = array.new_float()
var f5Array = array.new_float()
array.push(f1Array, featureSeries.f1)
array.push(f2Array, featureSeries.f2)
array.push(f3Array, featureSeries.f3)
array.push(f4Array, featureSeries.f4)
array.push(f5Array, featureSeries.f5)

// FeatureArrays Object: Storage of the calculated FeatureArrays into a single


object
featureArrays =
FeatureArrays.new(
f1Array, // f1
f2Array, // f2
f3Array, // f3
f4Array, // f4
f5Array // f5
)
// Label Object: Used for classifying historical data as training data for the ML
Model
Label direction =
Label.new(
long=1,
short=-1,
neutral=0
)

// Derived from General Settings


maxBarsBackIndex = last_bar_index >= settings.maxBarsBack ? last_bar_index -
settings.maxBarsBack : 0

// EMA Settings
useEmaFilter = input.bool(title="Use EMA Filter", defval=false, group="Filters",
inline="ema")
emaPeriod = input.int(title="Period", defval=200, minval=1, step=1,
group="Filters", inline="ema", tooltip="The period of the EMA used for the EMA
Filter.")
isEmaUptrend = useEmaFilter ? close > ta.ema(close, emaPeriod) : true
isEmaDowntrend = useEmaFilter ? close < ta.ema(close, emaPeriod) : true
useSmaFilter = input.bool(title="Use SMA Filter", defval=false, group="Filters",
inline="sma")
smaPeriod = input.int(title="Period", defval=200, minval=1, step=1,
group="Filters", inline="sma", tooltip="The period of the SMA used for the SMA
Filter.")
isSmaUptrend = useSmaFilter ? close > ta.sma(close, smaPeriod) : true
isSmaDowntrend = useSmaFilter ? close < ta.sma(close, smaPeriod) : true

// Nadaraya-Watson Kernel Regression Settings


useKernelFilter = input.bool(true, "Trade with Kernel", group="Kernel Settings",
inline="kernel")
showKernelEstimate = input.bool(true, "Show Kernel Estimate", group="Kernel
Settings", inline="kernel")
useKernelSmoothing = input.bool(false, "Enhance Kernel Smoothing", tooltip="Uses a
crossover based mechanism to smoothen kernel color changes. This often results in
less color transitions overall and may result in more ML entry signals being
generated.", inline='1', group='Kernel Settings')
h = input.int(8, 'Lookback Window', minval=3, tooltip='The number of bars used for
the estimation. This is a sliding value that represents the most recent historical
bars. Recommended range: 3-50', group="Kernel Settings", inline="kernel")
r = input.float(8., 'Relative Weighting', step=0.25, tooltip='Relative weighting of
time frames. As this value approaches zero, the longer time frames will exert more
influence on the estimation. As this value approaches infinity, the behavior of the
Rational Quadratic Kernel will become identical to the Gaussian kernel. Recommended
range: 0.25-25', group="Kernel Settings", inline="kernel")
x = input.int(25, "Regression Level", tooltip='Bar index on which to start
regression. Controls how tightly fit the kernel estimate is to the data. Smaller
values are a tighter fit. Larger values are a looser fit. Recommended range: 2-25',
group="Kernel Settings", inline="kernel")
lag = input.int(2, "Lag", tooltip="Lag for crossover detection. Lower values result
in earlier crossovers. Recommended range: 1-2", inline='1', group='Kernel
Settings')

// Display Settings
showBarColors = input.bool(true, "Show Bar Colors", tooltip="Whether to show the
bar colors.", group="Display Settings")
showBarPredictions = input.bool(defval = true, title = "Show Bar Prediction
Values", tooltip = "Will show the ML model's evaluation of each bar as an
integer.", group="Display Settings")
useAtrOffset = input.bool(defval = false, title = "Use ATR Offset", tooltip = "Will
use the ATR offset instead of the bar prediction offset.", group="Display
Settings")
barPredictionsOffset = input.float(0, "Bar Prediction Offset", minval=0,
tooltip="The offset of the bar predictions as a percentage from the bar high or
close.", group="Display Settings")

// =================================
// ==== Next Bar Classification ====
// =================================

// This model specializes specifically in predicting the direction of price action


over the course of the next 4 bars.
// To avoid complications with the ML model, this value is hardcoded to 4 bars but
support for other training lengths may be added in the future.
src = settings.source
y_train_series = src[4] < src[0] ? direction.short : src[4] > src[0] ?
direction.long : direction.neutral
var y_train_array = array.new_int(0)

// Variables used for ML Logic


var predictions = array.new_float(0)
var prediction = 0.
var signal = direction.neutral
var distances = array.new_float(0)

array.push(y_train_array, y_train_series)

lastDistance = -1.0
size = math.min(settings.maxBarsBack-1, array.size(y_train_array)-1)
sizeLoop = math.min(settings.maxBarsBack-1, size)

if bar_index >= maxBarsBackIndex //{


for i = 0 to sizeLoop //{
d = get_lorentzian_distance(i, settings.featureCount, featureSeries,
featureArrays)
if d >= lastDistance and i%4 //{
lastDistance := d
array.push(distances, d)
array.push(predictions, math.round(array.get(y_train_array, i)))
if array.size(predictions) > settings.neighborsCount //{
lastDistance := array.get(distances,
math.round(settings.neighborsCount*3/4))
array.shift(distances)
array.shift(predictions)
//}
//}
//}
prediction := array.sum(predictions)
//}

// ============================
// ==== Prediction Filters ====
// ============================

// User Defined Filters: Used for adjusting the frequency of the ML Model's
predictions
filter_all = filter.volatility and filter.regime and filter.adx
// Filtered Signal: The model's prediction of future price movement direction with
user-defined filters applied
signal := prediction > 0 and filter_all ? direction.long : prediction < 0 and
filter_all ? direction.short : nz(signal[1])

// Bar-Count Filters: Represents strict filters based on a pre-defined holding


period of 4 bars
var int barsHeld = 0
barsHeld := ta.change(signal) ? 0 : barsHeld + 1
isHeldFourBars = barsHeld == 4
isHeldLessThanFourBars = 0 < barsHeld and barsHeld < 4

// Fractal Filters: Derived from relative appearances of signals in a given time


series fractal/segment with a default length of 4 bars
isDifferentSignalType = ta.change(signal)
isEarlySignalFlip = ta.change(signal) and (ta.change(signal[1]) or
ta.change(signal[2]) or ta.change(signal[3]))
isBuySignal = signal == direction.long and isEmaUptrend and isSmaUptrend
isSellSignal = signal == direction.short and isEmaDowntrend and isSmaDowntrend
isLastSignalBuy = signal[4] == direction.long and isEmaUptrend[4] and
isSmaUptrend[4]
isLastSignalSell = signal[4] == direction.short and isEmaDowntrend[4] and
isSmaDowntrend[4]
isNewBuySignal = isBuySignal and isDifferentSignalType
isNewSellSignal = isSellSignal and isDifferentSignalType

c_green = color.new(#009988, 20)


c_red = color.new(#CC3311, 20)
transparent = color.new(#000000, 100)
yhat1 = kernels.rationalQuadratic(settings.source, h, r, x)
yhat2 = kernels.gaussian(settings.source, h-lag, x)
kernelEstimate = yhat1
// Kernel Rates of Change
bool wasBearishRate = yhat1[2] > yhat1[1]
bool wasBullishRate = yhat1[2] < yhat1[1]
bool isBearishRate = yhat1[1] > yhat1
bool isBullishRate = yhat1[1] < yhat1
isBearishChange = isBearishRate and wasBullishRate
isBullishChange = isBullishRate and wasBearishRate
// Kernel Crossovers
bool isBullishCrossAlert = ta.crossover(yhat2, yhat1)
bool isBearishCrossAlert = ta.crossunder(yhat2, yhat1)
bool isBullishSmooth = yhat2 >= yhat1
bool isBearishSmooth = yhat2 <= yhat1
// Kernel Colors
color colorByCross = isBullishSmooth ? c_green : c_red
color colorByRate = isBullishRate ? c_green : c_red
color plotColor = showKernelEstimate ? (useKernelSmoothing ? colorByCross :
colorByRate) : transparent
plot(kernelEstimate, color=plotColor, linewidth=2, title="Kernel Regression
Estimate")
// Alert Variables
bool alertBullish = useKernelSmoothing ? isBullishCrossAlert : isBullishChange
bool alertBearish = useKernelSmoothing ? isBearishCrossAlert : isBearishChange
// Bullish and Bearish Filters based on Kernel
isBullish = useKernelFilter ? (useKernelSmoothing ? isBullishSmooth :
isBullishRate) : true
isBearish = useKernelFilter ? (useKernelSmoothing ? isBearishSmooth :
isBearishRate) : true

// ===========================
// ==== Entries and Exits ====
// ===========================

// Entry Conditions: Booleans for ML Model Position Entries


startLongTrade = isNewBuySignal and isBullish and isEmaUptrend and isSmaUptrend and
filt_buy1
startShortTrade = isNewSellSignal and isBearish and isEmaDowntrend and
isSmaDowntrend and filt_sell1

// Dynamic Exit Conditions: Booleans for ML Model Position Exits based on Fractal
Filters and Kernel Regression Filters
lastSignalWasBullish = ta.barssince(startLongTrade) < ta.barssince(startShortTrade)
lastSignalWasBearish = ta.barssince(startShortTrade) < ta.barssince(startLongTrade)
barsSinceRedEntry = ta.barssince(startShortTrade)
barsSinceRedExit = ta.barssince(alertBullish)
barsSinceGreenEntry = ta.barssince(startLongTrade)
barsSinceGreenExit = ta.barssince(alertBearish)
isValidShortExit = barsSinceRedExit > barsSinceRedEntry
isValidLongExit = barsSinceGreenExit > barsSinceGreenEntry
endLongTradeDynamic = (isBearishChange and isValidLongExit[1])
endShortTradeDynamic = (isBullishChange and isValidShortExit[1])

// Fixed Exit Conditions: Booleans for ML Model Position Exits based on a Bar-Count
Filters
endLongTradeStrict = ((isHeldFourBars and isLastSignalBuy) or
(isHeldLessThanFourBars and isNewSellSignal and isLastSignalBuy)) and
startLongTrade[4]
endShortTradeStrict = ((isHeldFourBars and isLastSignalSell) or
(isHeldLessThanFourBars and isNewBuySignal and isLastSignalSell)) and
startShortTrade[4]
isDynamicExitValid = not useEmaFilter and not useSmaFilter and not
useKernelSmoothing
endLongTrade = settings.useDynamicExits and isDynamicExitValid ?
endLongTradeDynamic : endLongTradeStrict
endShortTrade = settings.useDynamicExits and isDynamicExitValid ?
endShortTradeDynamic : endShortTradeStrict

// =========================
// ==== Plotting Labels ====
// =========================

// Note: These will not repaint once the most recent bar has fully closed. By
default, signals appear over the last closed bar; to override this behavior set
offset=0.
plotshape(startLongTrade ? low : na, 'Buy', shape.labelup, location.belowbar,
color=ml.color_green(prediction), size=size.small, offset=0)
plotshape(startShortTrade ? high : na, 'Sell', shape.labeldown, location.abovebar,
ml.color_red(-prediction), size=size.small, offset=0)
plotshape(endLongTrade and settings.showExits ? high : na, 'StopBuy', shape.xcross,
location.absolute, color=#3AFF17, size=size.tiny, offset=0)
plotshape(endShortTrade and settings.showExits ? low : na, 'StopSell',
shape.xcross, location.absolute, color=#FD1707, size=size.tiny, offset=0)

// ================
// ==== Alerts ====
// ================
// // Separate Alerts for Entries and Exits
// alertcondition(startLongTrade, title='Open Long ▲', message='LDC Open Long ▲ |
{{ticker}}@{{close}} | ({{interval}})')
// alertcondition(endLongTrade, title='Close Long ▲', message='LDC Close Long ▲ |
{{ticker}}@{{close}} | ({{interval}})')
// alertcondition(startShortTrade, title='Open Short ▼', message='LDC Open Short |
{{ticker}}@{{close}} | ({{interval}})')
// alertcondition(endShortTrade, title='Close Short ▼', message='LDC Close Short ▼
| {{ticker}}@{{close}} | ({{interval}})')

// // Combined Alerts for Entries and Exits


// alertcondition(startShortTrade or startLongTrade, title='Open Position ▲▼',
message='LDC Open Position ▲▼ | {{ticker}}@{{close}} | ({{interval}})')
// alertcondition(endShortTrade or endLongTrade, title='Close Position ▲▼',
message='LDC Close Position ▲▼ | {{ticker}}@[{{close}}] | ({{interval}})')

// // Kernel Estimate Alerts


// alertcondition(condition=alertBullish, title='Kernel Bullish Color Change',
message='LDC Kernel Bullish ▲ | {{ticker}}@{{close}} | ({{interval}})')
// alertcondition(condition=alertBearish, title='Kernel Bearish Color Change',
message='LDC Kernel Bearish ▼ | {{ticker}}@{{close}} | ({{interval}})')

// =========================
// ==== Display Signals ====
// =========================

atrSpaced = useAtrOffset ? ta.atr(1) : na


compressionFactor = settings.neighborsCount / settings.colorCompression
c_pred = prediction > 0 ? color.from_gradient(prediction, 0, compressionFactor,
#787b86, #009988) : prediction <= 0 ? color.from_gradient(prediction, -
compressionFactor, 0, #CC3311, #787b86) : na
c_label = showBarPredictions ? c_pred : na
c_bars = showBarColors ? color.new(c_pred, 50) : na
x_val = bar_index
y_val = useAtrOffset ? prediction > 0 ? high + atrSpaced: low - atrSpaced :
prediction > 0 ? high + hl2*barPredictionsOffset/20 : low -
hl2*barPredictionsOffset/30
label.new(x_val, y_val, str.tostring(prediction), xloc.bar_index, yloc.price,
color.new(color.white, 100), label.style_label_up, c_label, size.normal,
text.align_left)
barcolor(showBarColors ? color.new(c_pred, 50) : na)

// =====================
// ==== Backtesting ====
// =====================

// The following can be used to stream signals to a backtest adapter


backTestStream = switch
startLongTrade => 1
endLongTrade => 2
startShortTrade => -1
endShortTrade => -2
plot(backTestStream, "Backtest Stream", display=display.none)

// The following can be used to display real-time trade stats. This can be a useful
mechanism for obtaining real-time feedback during Feature Engineering. This does
NOT replace the need to properly backtest.
// Note: In this context, a "Stop-Loss" is defined instances where the ML Signal
prematurely flips directions before an exit signal can be generated.
[totalWins, totalLosses, totalEarlySignalFlips, totalTrades, tradeStatsHeader,
winLossRatio, winRate] = ml.backtest(high, low, open, startLongTrade, endLongTrade,
startShortTrade, endShortTrade, isEarlySignalFlip, maxBarsBackIndex, bar_index,
settings.source, useWorstCase)

init_table() =>
c_transparent = color.new(color.black, 100)
table.new(position.top_right, columns=2, rows=7,
frame_color=color.new(color.black, 100), frame_width=1, border_width=1,
border_color=c_transparent)

update_table(tbl, tradeStatsHeader, totalTrades, totalWins, totalLosses,


winLossRatio, winRate, stopLosses) =>
c_transparent = color.new(color.black, 100)
table.cell(tbl, 0, 0, tradeStatsHeader, text_halign=text.align_center,
text_color=color.gray, text_size=size.normal)
table.cell(tbl, 0, 1, 'Winrate', text_halign=text.align_center,
bgcolor=c_transparent, text_color=color.gray, text_size=size.normal)
table.cell(tbl, 1, 1, str.tostring(totalWins / totalTrades, '#.#%'),
text_halign=text.align_center, bgcolor=c_transparent, text_color=color.gray,
text_size=size.normal)
table.cell(tbl, 0, 2, 'Trades', text_halign=text.align_center,
bgcolor=c_transparent, text_color=color.gray, text_size=size.normal)
table.cell(tbl, 1, 2, str.tostring(totalTrades, '#') + ' (' +
str.tostring(totalWins, '#') + '|' + str.tostring(totalLosses, '#') + ')',
text_halign=text.align_center, bgcolor=c_transparent, text_color=color.gray,
text_size=size.normal)
table.cell(tbl, 0, 5, 'WL Ratio', text_halign=text.align_center,
bgcolor=c_transparent, text_color=color.gray, text_size=size.normal)
table.cell(tbl, 1, 5, str.tostring(totalWins / totalLosses, '0.00'),
text_halign=text.align_center, bgcolor=c_transparent, text_color=color.gray,
text_size=size.normal)
table.cell(tbl, 0, 6, 'Early Signal Flips', text_halign=text.align_center,
bgcolor=c_transparent, text_color=color.gray, text_size=size.normal)
table.cell(tbl, 1, 6, str.tostring(totalEarlySignalFlips, '#'),
text_halign=text.align_center, bgcolor=c_transparent, text_color=color.gray,
text_size=size.normal)

if showTradeStats
var tbl = ml.init_table()
if barstate.islast
update_table(tbl, tradeStatsHeader, totalTrades, totalWins, totalLosses,
winLossRatio, winRate, totalEarlySignalFlips)

alertcondition(long, 'NO-REPAINT : Buy')


alertcondition(short, 'NO-REPAINT : Sell')

alertcondition(startLongTrade , "Lorentzian : Buy")


alertcondition(startShortTrade , "Lorentzian : Sell")

You might also like