Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

// This source code is subject to the terms of the Mozilla

Public License 2.0 at https://mozilla.org/MPL/2.0/


// © ceocodes

//@version=5
indicator(")", '', true, format=format.price, precision=2,
timeframe="", timeframe_gaps=true)

// Forex Algorithm is a very robust and simple method for


data classification and prediction. It is very
// effective if the training data is large. However, it is
distinguished by difficulty at
// determining its main parameter, K (a number of nearest
neighbors), beforehand. The
// computation cost is also quite high because we need to
compute distance of each instance
// to all training samples. Nevertheless, in algorithmic
trading KNN is reported to perform
// on a par with such techniques as SVM and Random Forest. It
is also widely used in the area
// of data science.

// The input data is just a long series of prices over time


without any particular features.
// The value to be predicted is just the next bar's price.
The way that this problem is
// solved for both nearest neighbor techniques and for some
other types of prediction
// algorithms is to create training records by taking, for
instance, 10 consecutive prices
// and using the first 9 as predictor values and the 10th as
the prediction value.
// Doing this way, given 100 data points in your time series
you could create 10 different
// training records. It's possible to create even more
training records than 10 by creating
// a new record starting at every data point. For instance,
you could take the first 10 data
// points and create a record. Then you could take the 10
consecutive data points starting at
// the second data point, the 10 consecutive data points
starting at the third data point, etc.

// By default, shown are only 10 initial data points as


predictor values and the 6th as the
// prediction value.

// Here is a step-by-step workthrough on how to compute K


nearest neighbors (KNN) algorithm for
// quantitative data:

// 1. Determine parameter K = number of nearest neighbors.


// 2. Calculate the distance between the instance and all the
training samples. As we are
// dealing with one-dimensional distance, we simply take
absolute value from the instance to
// value of x (| x – v |).
// 3. Rank the distance and determine nearest neighbors based
on the K'th minimum distance.
// 4. Gather the values of the nearest neighbors.
// 5. Use average of nearest neighbors as the prediction
value of the instance.

// The original logic of the algorithm was slightly modified,


and as a result at approx. N=17
// the resulting curve nicely approximates that of the
sma(20). See the description below.
// Beside the sma-like MA this algorithm also gives you a
hint on the direction of the next bar
// move.

//-- Inputs

TF = input.timeframe('5', 'Resolution',
['1','3','5','10','15','30','45','60','120','180','240','480'
,'D','W','M'])
N = input.int (10, '# of Data Points [2:n]',
2)
K = input.int (100, '# of Nearest Neighbors
(K) [1:252]', 1, 252)
ADJ = input.bool (true, 'Adjust Prediction',
inline='b')
REP = input.bool (false, 'Non-Repainting',
inline='b')
ADDON = input.string ('Z-Score', 'Add-On',
['None','Pivot Point','Z-Score'])
LAGP = input.int (5, 'Pivot Point Lag [2:n] if
selected', 2)
LAGZ = input.int (20, 'Z-Score Lag [2:n] if
selected', 2)
DISP = input.string ('Both', 'Show Outcomes',
['Curve','Predict','Both'])
ODS = input.source (hlcc4, 'Projection Base')

//-- Functions

knn(data) => //-- calculate nearest neighbors (if any)


nearest_neighbors = array.new_float(0)
distances = array.new_float(0)

for i = 0 to N-1
float d = math.abs(data[i] - data[i+1])
//-- euclidean will do just as well
// float d = math.sqrt(math.pow(data[i] - data[i+1],
2))
array.push(distances, d)
int size = array.size(distances)

//-- The original logic was too funky, imho :-)


// float new_neighbor = d<array.min(distances,
size>K?K:0)?data[i+1]:0
// if new_neighbor > 0
// array.push(nearest_neighbors, new_neighbor)
//-- The following logic reasonably smooths the
outcome!
float new_neighbor = d<array.min(distances, size>K?
K:0)?data[i+1]:data[i]
array.push(nearest_neighbors, new_neighbor)

nearest_neighbors
predict(neighbors, data) => //-- predict the expected price
and calculate next bar's direction
float prediction = array.avg(neighbors)
int direction = prediction < data[ADJ?0:1] ? 1 :
prediction > data[ADJ?0:1] ? -1 : 0
[prediction, direction]

green(g) => g>9 ? #006400 : g>8 ? #1A741A : g>7 ? #338333 :


g>6 ? #4D934D : g>5 ? #66A266 : g>4 ? #80B280 : g>3 ? #99C199
: g>2 ? #B3D1B3 : g>1? #CCE0CC : #E6F0E6
red(g) => g>9 ? #E00000 : g>8 ? #E31A1A : g>7 ? #E63333 :
g>6 ? #E94D4D : g>5 ? #EC6666 : g>4 ? #F08080 : g>3 ? #F39999
: g>2 ? #F6B3B3 : g>1? #F9CCCC : #FCE6E6

ordinary_color(dir) =>
dir==1?green(9):dir==-1?red(9):na

pivot_color(h,l, p, dir) =>


ph = ta.highestbars(h, LAGP)==0 ? h : na
pl = ta.lowestbars(l, LAGP)==0 ? l : na
ph and dir==1 ? green(9) : pl and dir==-1 ? red(9):na

zscore_color(data, p, dir) =>


zs = (data - ta.sma(data, p)) / ta.stdev(data, p) //
standardize
zs/(p/5)>0 and dir==1 ? green(9) : zs/(p/5)<0 and dir==-1
? red(9) : na

//-- Logic

rep = REP?1:0
[O,H,L,C] = request.security('', TF,
[open,high[rep],low[rep],close[rep]])
nn = knn(C)
[pred,dir] = predict(nn, C)
clr = ADDON=='Z-Score'?zscore_color(C, LAGZ,
dir):ADDON=='Pivot Point'?pivot_color(H,L,LAGP,
dir):ordinary_color(dir)
//-- Visuals

//plot(ta.sma(close,20))
plot(DISP=='Curve' or DISP=='Both' ? pred : na, 'kNN
Curve', clr, 3, offset=0)
plot(DISP=='Predict' or DISP=='Both' ? ODS : na,
'Prediction', clr, 5, plot.style_circles, offset=2,
show_last=1)

You might also like