Indicator · Pine Script v5 · On the chart

Machine Learning: Perceptron-Based Strategy 5 (v.2)

by capissimo

This indicator implements an artificial neural network using a single-layer perceptron model trained from scratch directly in Pine Script.

View on GitHub

GitHub stars114on the repository
Pine versionv5runs as is
Lines of code182
Settings11inputs
LicenceNone statedfile: MPL-2.0
Last update1 year ago7 Nov 2024

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

182 lines of Pine Script v5 from scripts/100-3-ML-Perceptron-Based-Strategy-[5]-(v.2).pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

100-3-ML-Perceptron-Based-Strategy-[5]-(v.2).pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © capissimo

//@version=5 
indicator('Machine Learning: Perceptron-Based Strategy [5] (v.2)', 'ML: Perceptron [5] (v.2)', true)
import TradingView/ta/7

// Perceptron-based strategy FROM SCRATCH

// Description: 

// The Learning Perceptron is the simplest possible artificial neural network  
// (ANN), consisting of just a single neuron and capable of learning a certain  
// class of binary classification problems. The idea behind ANNs is that by
// selecting good values for the weight parameters (and the bias), the ANN can 
// model the relationships between the inputs and some target.

// Generally, ANN neurons receive a number of inputs, weight each of those inputs, 
// sum the weights, and then transform that sum using a special function called 
// an activation function. The output of that activation function is then either 
// used as the prediction (in a single neuron model) or is combined with the outputs 
// of other neurons for further use in more complex models.

// The purpose of the activation function is to take the input signal (that’s the 
// weighted sum of the inputs and the bias) and turn it into an output signal. 
// Think of this activation function as firing (activating) the neuron when it 
// returns 1, and doing nothing when it returns 0. This sort of computation is 
// accomplished with a function called step function: f(z) = {1 if z > 0 else 0}. 
// This function then transforms any weighted sum of the inputs and converts it  
// into a binary output (either 1 or 0). The trick to making this useful is finding 
// (learning) a set of weights that lead to good predictions using this activation 
// function.

// Training our perceptron is simply a matter of initializing the weights to zero 
// (or random value) and then implementing the perceptron learning rule, which 
// just updates the weights based on the error of each observation with the current 
// weights. This has the effect of moving the classifier’s decision boundary in the 
// direction that would have helped it classify the last observation correctly. 
// This is achieved via a for loop which iterates over each observation, making a 
// prediction of each observation, calculating the error of that prediction and then 
// updating the weights accordingly. In this way, weights are gradually updated 
// until they converge. Each sweep through the training data is called an epoch.

// Note: The script features a custom directional movement index (DMI) and 
// trailing stops. DMI indication nearing 100 and 0 points indicates strong 
// upward and downward trends.

// Asset class: ALL 

//-- Inputs

Timeframe  = input.timeframe('1',         'Time Frame') 
Depth      = input.int      (500,         'Sample Size', 5)  
Period     = input.int      (14,          'Period', 2)  
Threshold  = input.int      (28,          'Threshold [0..100]', 0, 100)  
Fltr        = input.bool     (true,        '',              inline='flt')
Filter     = input.string   ('Volatility','Filter',         ['Volatility','Volume','Both','None'], inline='flt')
Holding    = input.int      (10,          'Holding Period', 1, tooltip='Set to 100+ to remove all the stops')
Ma         = input.bool     (false,       'Ma',             inline='b')
Barcolor   = input.bool     (true,        'Bar Color',      inline='b')
Trailing   = input.bool     (false,       'Trailing',       inline='b')
Info       = input.bool     (true,        'Info',           inline='b')

//-- Data

[Open, High, Low, Close, Volume, Time] = request.security('', Timeframe, [open, high, low, close, volume, time])

//-- Constants  

int BUY = 1, int SELL = -1, int HOLD = 0
int epochs = 5

//-- Variables

var float source     = 0
var float weight1    = 0.0   // perceptron initial weights
var float weight2    = 0.0
var float bias       = 0.0
var float errors     = 0.0
var int   signal     = HOLD
var int   hp_counter = 0     // holding period counter
var int   timebuy    = 0
var int   timesell   = 0

var label lb  = label.new(na, na, '', xloc.bar_index, yloc.price, color.black, label.style_label_left, 
                         color.white, size.normal, text.align_left, '', font.family_monospace)
var line  ln  = line.new(na, na, na, na, xloc.bar_index, extend.none, color.black)

//-- Functions

method rma(float x, int p) => ta.rma(x, p) 
method ema(float x, int p) => ta.ema(x, p) 
method linreg(float x, int p, int s=0) => ta.linreg(x, p, s) 
method mg(float x, simple int p=5) =>  // mcginley ma
    float mg = 0.0
    mg := na(mg[1]) ? x.ema(p) : mg[1] + (x - mg[1]) / (p * math.pow(x/mg[1], 4))

method dmi(float h, float l, float c, int p=20) =>  // custom directional movement index using differencing and norming
    float up    = ta.change(h)
    float down  =-ta.change(l)
    float tr    = math.max(h-l, math.abs(h-nz(c[1])), math.abs(l-nz(c[1])))
    float atr   = ta.rma(tr, p)
    float plus  = fixnan(100 * (up>down and up>0 ? up : 0).rma(p) / atr)  
    float minus = fixnan(100 * (down>up and down>0 ? down : 0).rma(p) / atr)
    float diff  = plus - minus  
    100 *  (diff - ta.lowest(diff, p)) / (ta.highest(diff, p)-ta.lowest(diff, p))  // norm
 
volumeBreak(float v, float thres) => ta.hma(ta.rsi(v, Period), 10) > thres                     

volatilityBreak(simple int volmin, simple int volmax) => ta.atr(volmin) > ta.atr(volmax)

//-- Logic

float dmi    = dmi(High, Low, Close, Period)  
float trail  = Close.linreg(8).mg(6)
float ma     = ta.sma(Close, Period)

bool filter = switch Filter
    'Volatility' => volatilityBreak(1, 10) 
    'Volume'     => volumeBreak(Volume, 49) 
    'Both'       => volatilityBreak(1, 10) and volumeBreak(Volume, 49)
    => true

source := Close[0]>Close[1] ? 1 : -1    // transform data to binary classification problem 

// Training loop (perceptron learning)
for j=1 to epochs
    for i=2 to Depth                                                        // iterate over the dataset to the specified depth
        yhat = weight1*source[i] + weight2*source[i-1] + bias > 0 ? 1 : -1  // and look into all but the latest data points
        error = source[i] - yhat       // will be either 0, 2 or -2
        weight1 := error*source[i]     // learning rules
        weight2 := error*source[i-1]
        bias := error  
    for k=2 to Depth
        preds = weight1*source[k] + weight2*source[k-1] + bias > 0 ? 1 : -1   // TODO: predict on whole training set
        errors := ta.cum(math.abs(source - preds))/2                          // calculate errors

float slope     = weight1/weight2   // alpha
float intercept = bias/weight2      // beta
float outcome   = intercept * source + slope   // now produce the output for the latest data point and classify it

//-- Signals

bool long  = outcome > 0 and dmi > 100 - Threshold and timebuy  != time_close and (Fltr ? filter : true)
bool short = outcome < 0 and dmi < Threshold       and timesell != time_close and (Fltr ? filter : true)    
bool clear = hp_counter==Holding 

signal := long ? BUY : short ? SELL : nz(signal)

bool changed = bool(ta.change(signal))

hp_counter := changed ? 0 : hp_counter + 1

bool long_condition  = changed and signal==BUY    
bool short_condition = changed and signal==SELL   
bool end_long_cond   = signal==BUY  and hp_counter==Holding and not changed 
bool end_short_cond  = signal==SELL and hp_counter==Holding and not changed 

//--Visuals

barcolor(Barcolor ? signal==BUY?color.teal:color.red : na)
// plot(Perceptron ? outcome : na, 'Perceptron', color.blue, 2)
plot(Ma         ? ma      : na, 'Ma',         signal==BUY?color.teal:color.red, 2) 
plot(Trailing ? trail  : na, 'Trailing',   color.black, 1, plot.style_stepline)
plotshape(long_condition,  'Buy',  shape.labelup,   location.belowbar, na, 0, '🡅', color.teal, false, size.small)
plotshape(short_condition, 'Sell', shape.labeldown, location.abovebar, na, 0, '🡇', color.red, false, size.small)
plot(end_long_cond  ? High : na, 'StopBuy',  color.black, 3, plot.style_cross)
plot(end_short_cond ? Low  : na, 'StopSell', color.black, 3, plot.style_cross)
line.set_xy1(ln, bar_index, trail)
line.set_xy2(ln, bar_index+3, trail)

if Info
    label.set_xy(lb, bar_index+10, open)
    label.set_text(lb, 'DMI: ' + str.tostring(dmi, '#') + '\nerrors: ' + str.tostring(errors, '#.##'))

//-- Notification

alertcondition(long_condition,  "Buy Alert",  "Possible Long Trade")
alertcondition(short_condition, "Sell Alert", "Possible Short Trade") 
alertcondition(long_condition or short_condition, 'Reversal!', 'Time to ACT')

//-- Backtest

Overview

Machine Learning: Perceptron-Based Strategy 5 (v.2) processes price features combined with a custom directional movement index across a rolling sample window to generate directional trading signals. Users can configure sample size, threshold levels, holding periods, and optional volatility or volume filters. The indicator plots trade signals, optional trailing stop levels, moving averages, and bar coloring directly on the price chart.

Details

Published by

capissimo on GitHub

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

AI / machine learning, Trend

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Time Frametimeframe1Timeframe
Sample Sizeint500Depth
Periodint14Period
Threshold [0..100]int28Threshold
FltrbooltrueFltr
FilterstringVolatilityFilter
Holding Periodint10Holding
MaboolfalseMa
Bar ColorbooltrueBarcolor
TrailingboolfalseTrailing
InfobooltrueInfo
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

257 stars

This indicator uses a Lorentzian distance k-nearest neighbors classification algorithm to predict market direction based on up to five technical features, such as RSI, WaveTrend, CCI, and ADX. It compares current feature values against historical bar patterns

Indicator v5 AI / machine learningOscillators & momentum
Updated 6 weeks ago · None stated GitHub repository of Donald - Machine Learning Options

AI Trend Navigator

by hasnocool
106 stars

This indicator calculates a trend direction and smoothed moving average using a k-nearest neighbours (k-NN) classification algorithm directly on the main price chart. Users can select input price types, target values, neighborhood size, and smoothing periods.

Indicator v5 AI / machine learningTrend
Updated 2 years ago · GPL-3.0 GitHub repository of AI Trend Navigator

Machine Learning: Lorentzian Classification

by artificial-intelligence-edge
75 stars

An overlay indicator that applies a k-nearest-neighbors machine learning classifier using Lorentzian distance to predict price movement. It evaluates historical market features, such as RSI, WaveTrend, CCI, and ADX, to identify similar price-time patterns and

Indicator v6 AI / machine learningOscillators & momentum
Updated 2 days ago · MIT GitHub repository of Machine Learning: Lorentzian Classification
46 stars

This indicator uses a Hidden Markov Model (HMM) framework combined with an adaptive dual moving average engine and Directional Movement Index (DMI) features to identify market regimes (bullish, bearish, or ranging/chop). It calculates regime probabilities on e

Indicator v5 AI / machine learningTrend
Updated 7 weeks ago · None stated GitHub repository of HMM Enhanced: Regime Probability

This overlay indicator plots a SuperTrend-style band on the price chart using ATR length, a selectable source, and a base factor. Optional settings enable an adaptive factor driven by rate of change, a volatility filter, K-means clustering, and an LSTM layer w

Indicator v6 TrendVolatility & bands
Updated 4 months ago · MIT GitHub repository of ML SuperTrend (Ultimate) - Auto-Optimized AI with LSTM

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers