Indicator · Pine Script v4 · Own pane

2 bit number test Neural Network - JD

by JorisDuyck

This indicator tests a simple neural network for recognizing 2-bit numbers in Pine Script.

View on GitHub

GitHub stars2on the repository
Pine versionv4older, still runs
Lines of code1,031
Settings2inputs
LicenceMIT
Last update5 years ago25 Feb 2021

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

1,031 lines of Pine Script v4 from 2 bit number test Neural Network - JD.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

2 bit number test Neural Network - JD.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Joris Duyck

//@version=4
study("2 bit number test Neural Network -  JD")
//{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The arrays provided in Pinescript are linear 1D strucures that can be seen either as a large vertical stack or
// a horizontal row containing a list of values, colors, bools,..
// 
// With the FUNCTIONS in this script the 1D ARRAY LIST can be CONVERTED INTO A 2D MATRIX form
// 
// 
///////////////////////////////////////////
/// BASIC INFO ON THE MATRIX STRUCTURE: ///
///////////////////////////////////////////
// 
// The matrix is set up as an 2D structure and is devided in ROWS and COLUMNS.
//  following the standard mathematical notation:
//
//      a 3 x 4 matrix =          4 columns
//                                 0 1 2 3  column index
//                              0 [a b c d]
//                       3 rows 1 [e f g h]
//                              2 [i j k l]
//                            row
//                           index
//
// With the use of some purpose-built functions, values can be placed or retrieved in a specific column of a certain row
//  this can be done by intuitively using row_nr and column_nr coördinates,
//  without having to worry on what exact index of the Pine array this value is located (the functions do these conversions for you)
//
//
// the syntax I propose for the 2D Matrix array has the following structure:
// 
//  - the array starts with 2 VALUES describing the DIMENSION INFORMATION, (rows, columns)
//      these are ignored in the actual calculations and serve as a metadata header (similar to the "location, time,... etc." data that is stored in photo files)
//      so the array always carries it's own info about the nr. of rows and columns and doesn't need is seperate "info" file!
//
//      To stay consistent with the standard Pinescript (array and [lookback]) indexing:
//      - indexes for sheets and columns start from 0 (first) and run up to the (total nr of sheets or columns) - 1
//      - indexes for rows also start from 0 (most recent, cfr.[lookback]) and run up to the (total nr of rows) - 1
// 
//  - this 2 value metadata header is followed by the actual df data
//      the actual data array can consist of (100,000 - 2) usable items,
//      
//      In a theoretical example, you can have a matrix with almost 20,000 rows with each 5 columns of data (eg. open, high, low, close, volume) in it!!!
//
///////////////////////////////////
/// SCHEMATIC OF THE STRUCTURE: ///
///////////////////////////////////
//
////// (metadata header with dimensions info)
//
//                (0)             (1)            (array index)
//       [nr_of_rows/records, nr_of_columns,
//
//
////// (actual matrix array data)
//  
//                  0             1             2               3                   column_index
//
//                 (2)           (3)           (4)             (5)            (array index)
//        0    record0_val0, record0_val1, record0_val2, record0_val3, ...,
//      
//                 (6)           (7)           (8)             (9)            (array index)
//        1    record1_val0, record1_val1, record1_val2, record1_val3, ...,
//      
//                 (10)          (11)          (12)            (13)            (array index)
//        2    record2_val0, record2_val1, record2_val2, record2_val3, ...,
//      
//        3    ...
//
// row_index
//
////////////////////////////////////
/// DATA MANIPULATION FUNCTIONS: ///
////////////////////////////////////
//
// A set of functions are implemented to write info to and retrieve info from the dataframe.
//  Of course the possibilities are not limited to the functions here, these were written because they were needed for the script!
//  A whole list of other functions can be easily written for other manipulation purposes.
//  The ones written in the script are 2D versions of most of the functions that are provided for normal 1D arrays.
//
//  Feel free to use the functions library below in your scripts! A little shoutout would be nice, of course!!
//
//
///////////////////////////////////////////////////////////////////////
/// LIST OF FUNCTIONS contained in this script:                     ///
/// (many other can of course be written, using the same structure) ///
///////////////////////////////////////////////////////////////////////
//
// - INFO functions
//      * get the number of COLUMNS
//      * get the number of ROWS
//      * get the total SIZE (number of columns, number of rows)
// 
// - INITIALISATION and SET functions (commands to build the 2D matrix)
//      * MATRIX INITIALISATION function, builds 2D matrix with dimensional metadata/size in first 2 values //
//          a new matrix array is built (cfr. the conventions I propose above) containing a certain nr of rows and columns
//      * function to SET a single value in a certain row/lookback period and column
//
// - GET functions (to retrieve info from the 2D matrix)
//      * function to GET/retrieve a single VALUE from a certain row/lookback period and column
//      * function to cut of the metadata header and return the array body (as an array)
//      * function to GET/retrieve the values from a ROW/RECORD from a certain row/lookback period, the values are returned as an array
//
// - 1D - 2D COORDINATE CONVERSION FUNCTIONS (handy with for loop indexes) ///
//      * function to get the ROW INDEX in a 2D matrix from the 1D array index
//      * function to get the COLUMN INDEX in a 2D matrix from the 1D array index
//      * function to get (row, column) coordinates in a 2D matrix from the 1D array index
//      * function to get the 1D array index from (row, column) coordinates in a 2D matrix
//
// - Matrix MANIPULATION functions
//      * function to ADD a ROW/RECORD on the TOP of the array, shift the whole list one down and REMOVE the OLDEST row/record
//          (2D version of "unshift" + "pop" but with a whole row at once)
//      * function to REMOVE one or more ROWS/RECORDS from a 2D matrix
//          (if from_row == to_row, only this row is removed)
//      * function to REMOVE one or more COLUMNS from a 2D matrix
//          (if from_column == to_column, only this column is removed)
//      * function to INSERT an ARRAY of ROWS/RECORDS at a certain row number in a 2D matrix
//      * function to INSERT an ARRAY of COLUMNS at a certain column number in a 2D matrix
//      * function to APPEND/ADD an ARRAY of ROWS/RECORDS to the BOTTOM of a 2D matrix
//      * function to APPEND/ADD an ARRAY of COLUMNS to the SIDE of a 2D matrix
//      * function to POP/REMOVE and return the last ROW/RECORD from the BOTTOM of a 2D matrix
//      * function to POP/REMOVE and return the last column from the SIDE of a 2D matrix
//
// - function to print a matrix
//      This function is mainly used for debugging purposes and displays the array as a 2D matrix notation
//
//
// Enjoy!
// JD.
//
// #NotTradingAdvice #DYOR
//
//  Disclaimer.
// I AM NOT A FINANCIAL ADVISOR.
// THESE IDEAS ARE NOT ADVICE AND ARE FOR EDUCATION PURPOSES ONLY.
// ALWAYS DO YOUR OWN RESEARCH!
//}

/////////////////////////////////////////////////////////////////////////////////
// Function declarations //
//{

// Psuedo random number generator, by @RicardoSantos
//{
//| -------------------------------------------------------------------------------|
var float[] seed = array.new_float(size=1, initial_value=42.0)                  //-|
f_prng(_range)=>                                                              //---|
//| pseudo random function:                                                 // O O |
    var float _return = 1.0                                                 //- V -|
    float _seed = array.get(id=seed, index=0)                                //NNNN|
    float _reseed =  271.828                                                  // A |
    _return := ((3.1416 * _return % _seed) * _reseed) % _range                // V |
    array.set(id=seed, index=0, value=(1 + (_seed * 1.618) % _range) + _return) //||
    _return                                                                    // ||
//| -------------------------------------------------------------------------------|
//}

/////////////////////////////////////////////////////////////////////////////////
///                             Matrix Functions                              ///
/////////////////////////////////////////////////////////////////////////////////
//{
/// MATRIX INFO FUNCTIONS ///
//{
// function to get total number of rows from a 2D matrix
f_matrix_get_nr_of_rows(_m) =>
//{
    _rows = int(array.get(_m, 0))
    _rows
//}

// function to get total number of columns from a 2D matrix
f_matrix_get_nr_of_columns(_m) =>
//{
    _columns = int(array.get(_m, 1))
    _columns
//}

// function to get total number of columns and rows from a 2D matrix
f_matrix_get_size(_m) =>
//{
    _rows    = int(array.get(_m, 0))
    _columns = int(array.get(_m, 1))
    [_rows, _columns]
//}
//}

/// INITIALISATION AND SET FUNCTIONS ///
//{
// 2D matrix init function, builds 2D matrix with dimensional metadata in first two values //
f_matrix_init(_nr_of_rows, _nr_of_columns, _fill) =>
//{
    _size = int(_nr_of_rows * _nr_of_columns)
    _m    = array.new_float(_size + 2, _fill)
    array.set(_m, 0, _nr_of_rows), array.set(_m, 1, _nr_of_columns)
    _m
//}

// function to set values in 2D matrix with (row index, column index) (index for rows and columns both starts at 0 !!)
f_matrix_set(_m, _row_index, _column_index, _val) =>
//{
    _columns = f_matrix_get_nr_of_columns(_m)
    array.set(_m, 2 + int((_row_index * _columns) + _column_index), _val)
//}

// function to set all elements in a 2D matrix with a value
f_matrix_fill(_m, _val) =>
//{
    array.fill(_m, _val, 2)
//}
//}

/// GET FUNCTIONS ///
//{
// function to get values from 2D matrix with (row index, column index) (index for rows and columns both starts at 0 !!)
f_matrix_get(_m, _row_index, _column_index) =>
//{
    _columns = f_matrix_get_nr_of_columns(_m)
    _val     = array.get(_m, 2 + int((_row_index * _columns) + _column_index))
    _val
//}

// function to cut of the metadata header and return the array body
f_matrix_copy_slice_body(_m, _do_slice) =>
//{  '_do_slice' variable should be set as:
//      - 'false' to only make a copy,
//         changes to the new array copy will NOT ALTER the ORIGINAL
//      - 'true' to make a slice
//         changes to the new array slice WILL(!) ALTER the ORIGINAL
    _matrix_slice = array.slice(_m, 2, array.size(_m))
    _matrix_body  = _do_slice ? _matrix_slice : array.copy(_matrix_slice)
    // for i = 0 to 1
    //     array.remove(_matrix_body, 0)
    _matrix_body
//}

// function to GET/retrieve the values from a ROW/RECORD from a certain row/lookback period, the values are returned as an array
f_matrix_get_record(_m, _row_index) =>
//{
    _nr_of_columns = f_matrix_get_nr_of_columns(_m)
    _start_index   = int(2 + _row_index * _nr_of_columns)
    _row_slice = array.slice(_m, _start_index , _start_index + _nr_of_columns)
    _record    = array.copy(_row_slice)
    _record
//}
//}

/// 1D - 2D COORDINATE CONVERSION FUNCTIONS (handy with for loop indexes) ///
//{
// function to get row nr. in a 2D matrix from 1D index (index for rows and columns both starts at 0 !!)
f_matrix_get_row_index(_m, _array_index) =>
//{
    _columns   = f_matrix_get_nr_of_columns(_m)
    _row_index = int(floor(_array_index / _columns))
    _row_index
//}

// function to get column nr. in a 2D matrix from 1D index (index for rows and columns both starts at 0 !!)
f_matrix_get_column_index(_m, _array_index) =>
//{
    _columns      = f_matrix_get_nr_of_columns(_m)
    _column_index = int(_array_index % _columns)
    _column_index
//}

// function to get (row, column) coordinates in 2D matrix from 1D index (index starts at 0 and does not include the header!!)
f_matrix_get_row_column_index(_m, _array_index) =>
//{
    _columns = f_matrix_get_nr_of_columns(_m)
    _row     = int(floor(_array_index / _columns))
    _column  = int(      _array_index % _columns)
    [_row, _column]
//}

// function to get 1D index from (row, column) coordinates in 2D matrix (index for row and column both starts at 0 !! Index starts at 0 and does not include the header!!)
f_matrix_get_array_index(_m, _row_index, _column_index) =>
//{
    _columns = f_matrix_get_nr_of_columns(_m)
    _array_index = int(_row_index * _column_index + _column_index)
    _array_index
//}
//}

/// MANIPULATION FUNCTIONS ///
//{
// function to ADD a ROW/RECORD on the TOP of a sheet, shift the whole list one down and REMOVE the OLDEST row/record
//          (2D version of "unshift" + "pop" but with a whole row at once)
f_matrix_add_row(_m, _insert_array) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    [_rows_insert_array, _columns_insert_array] = f_matrix_get_size(_insert_array)
    _size_insert_array = _columns_insert_array * _rows_insert_array
    if _columns == _columns_insert_array
        _insert_array_body  = f_matrix_copy_slice_body(_insert_array, false)
        for index = (_size_insert_array - 1) to 0
            array.insert(_m, 2, array.get(_insert_array_body, index))
            array.pop(_m)
        array.set(_m, 0, _rows + _rows_insert_array)
    _m
//}

// function to remove one or more rows/records from a 2D matrix (if from_row = to_row, only this row is removed)
f_matrix_remove_rows(_m, _from_row, _to_row) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    if not(_from_row == 0 and _to_row == _rows - 1) and not(_to_row < _from_row)
        _start_remove_index = 2 + _from_row * _columns
        for i = 1 to (min(_rows - 1, _to_row) - _from_row + 1) * _columns
            array.remove(_m, max(_start_remove_index, 2))
        array.set(_m, 0, _rows - (min(_rows - 1, _to_row) - _from_row) - 1)
    _m
//}

// function to remove one or more columns from a 2D matrix (if from_column = to_column, only this column is removed)
f_matrix_remove_columns(_m, _from_column, _to_column) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    if not(_from_column == 0 and _to_column == _columns - 1) and not(_to_column < _from_column)
        for _row_nr = (_rows - 1)  to 0
            _start_remove_index = 2 + _row_nr * _columns + _from_column
            for i = _from_column to _to_column
                array.remove(_m, max(_start_remove_index, 2))
        array.set(_m, 1, _columns - (min(_columns, _to_column) - _from_column) - 1)
    _m
//}

// function to insert an array of rows/records at a certain row number in a 2D matrix
f_matrix_insert_array_of_rows(_m, _insert_array, _from_row) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    [_rows_insert_array, _columns_insert_array] = f_matrix_get_size(_insert_array)
    _size_insert_array = _columns_insert_array * _rows_insert_array
    if _columns == _columns_insert_array
        _insert_array_body  = f_matrix_copy_slice_body(_insert_array, false)
        _start_insert_index = 2 + min(_rows, _from_row) * _columns
        for index = (_size_insert_array - 1) to 0
            array.insert(_m, _start_insert_index, array.get(_insert_array_body, index))
        array.set(_m, 0, _rows + _rows_insert_array)
    _m
//}

// function to insert an array of columns at a certain column number in a 2D matrix
f_matrix_insert_array_of_columns(_m, _insert_array, _from_column) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    [_rows_insert_array, _columns_insert_array] = f_matrix_get_size(_insert_array)
    _size_insert_array = _columns_insert_array * _rows_insert_array
    if _rows == _rows_insert_array
        for _row_nr = (_rows - 1)  to 0
            _start_insert_index = 2 + _row_nr * _columns + min(_columns - 1, _from_column)
            for index = 0 to (_columns_insert_array - 1)
                array.insert(_m,
                 max(_start_insert_index, 2),
                  array.get(_insert_array, int(2 + (_size_insert_array - 1) - index - ((_rows_insert_array - 1) - _row_nr) * _columns_insert_array)))
        array.set(_m, 1, _columns + _columns_insert_array)
    _m
//}

// function to append/add an array of rows/records to the bottom of a 2D matrix
f_matrix_append_array_of_rows(_m, _append_array) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    [_rows_append_array, _columns_append_array] = f_matrix_get_size(_append_array)
    if _columns == _columns_append_array
        _append_array_body = f_matrix_copy_slice_body(_append_array, false)
        array.concat(_m, _append_array_body)
        array.set(_m, 0, _rows + _rows_append_array)
    _m
//}

// function to append/add an array of columns to the side of a 2D matrix
f_matrix_append_array_of_columns(_m, _append_array) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    [_rows_append_array, _columns_append_array] = f_matrix_get_size(_append_array)
    _size_append_array = _columns_append_array * _rows_append_array
    if _rows == _rows_append_array
        for _row_nr = (_rows - 1)  to 0
            _start_append_index = 2 + _row_nr * _columns + _columns
            for index = 0 to (_columns_append_array - 1)
                array.insert(_m,
                 max(_start_append_index, 2),
                  array.get(_append_array, int(2 + (_size_append_array - 1) - index - ((_rows_append_array - 1) - _row_nr) * _columns_append_array)))
        array.set(_m, 1, _columns + _columns_append_array)
    _m
//}

// function to remove the last row/record from a 2D matrix
f_matrix_pop_row(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = array.new_float()
    _start_remove_index = 2 + (_rows - 1) * _columns
    for i = 1 to _columns
        array.push(_return_array, array.get(_m, max(_start_remove_index, 2)))
        array.remove(_m, max(_start_remove_index, 2))
    array.set(_m, 0, _rows - 1)
    _return_array
//}

// function to remove and return the last column from a 2D matrix
f_matrix_pop_column(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = array.new_float()
    for _row_nr = (_rows - 1)  to 0
        _start_remove_index = 2 + _row_nr * _columns + (_columns - 1)
        array.insert(_return_array, 0, array.get(_m, max(_start_remove_index, 2)))
        array.remove(_m, max(_start_remove_index, 2))
    array.set(_m, 1, _columns - 1)
    _return_array
//}
//}

/// CALCULATION FUNCTIONS ///
//{
// function to randomize the values of a 2D matrix //
f_matrix_randomize(_m, _range) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _rnd_value = f_prng(_range)
            f_matrix_set(_m, i, j, _rnd_value)
    _m
//}

f_matrix_replace(_m, _add_m) =>
//{
    [    _rows,     _columns] = f_matrix_get_size(_m)
    [_add_rows, _add_columns] = f_matrix_get_size(_add_m)
    if _rows == _add_rows and _columns == _add_columns
        for i = 0  to _rows - 1
            for j = 0  to _columns - 1
                _add_value = f_matrix_get(_add_m, i, j)
                f_matrix_set(_m, i, j, _add_value)
    _m
//}

// function to add a certain value to every element of a 2D matrix //
f_matrix_add_value(_m, _add_value) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            f_matrix_set(_return_array, i, j, _value + _add_value)
    _return_array
    // [_rows, _columns] = f_matrix_get_size(_m)
    // for i = 0  to _rows - 1
    //     for j = 0  to _columns - 1
    //         _value = f_matrix_get(_m, i, j)
    //         f_matrix_set(_m, i, j, _value + _add_value)
    // _m
//}

f_matrix_addition(_m, _add_m) =>
//{
    [    _rows,     _columns] = f_matrix_get_size(_m)
    [_add_rows, _add_columns] = f_matrix_get_size(_add_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    if _rows == _add_rows and _columns == _add_columns
        for i = 0  to _rows - 1
            for j = 0  to _columns - 1
                _value     = f_matrix_get(    _m, i, j)
                _add_value = f_matrix_get(_add_m, i, j)
                f_matrix_set(_return_array, i, j, _value + _add_value)
    _return_array
    // [    _rows,     _columns] = f_matrix_get_size(_m)
    // [_add_rows, _add_columns] = f_matrix_get_size(_add_m)
    // if _rows == _add_rows and _columns == _add_columns
    //     for i = 0  to _rows - 1
    //         for j = 0  to _columns - 1
    //             _value     = f_matrix_get(    _m, i, j)
    //             _add_value = f_matrix_get(_add_m, i, j)
    //             f_matrix_set(_m, i, j, _value + _add_value)
    // _m
//}

f_matrix_subtraction(_m, _subtract_m) =>
//{
    [         _rows,          _columns] = f_matrix_get_size(_m)
    [_subtract_rows, _subtract_columns] = f_matrix_get_size(_subtract_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    if _rows == _subtract_rows and _columns == _subtract_columns
        for i = 0  to _rows - 1
            for j = 0  to _columns - 1
                _value          = f_matrix_get(         _m, i, j)
                _subtract_value = f_matrix_get(_subtract_m, i, j)
                f_matrix_set(_return_array, i, j, _value - _subtract_value)
    _return_array
    // [         _rows,          _columns] = f_matrix_get_size(_m)
    // [_subtract_rows, _subtract_columns] = f_matrix_get_size(_subtract_m)
    // if _rows == _subtract_rows and _columns == _subtract_columns
    //     for i = 0  to _rows - 1
    //         for j = 0  to _columns - 1
    //             _value          = f_matrix_get(         _m, i, j)
    //             _subtract_value = f_matrix_get(_subtract_m, i, j)
    //             f_matrix_set(_m, i, j, _value - _subtract_value)
    // _m
//}

// function to add a certain value to every element of a 2D matrix //
f_matrix_subtract_value(_m, _subtract_value) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            f_matrix_set(_return_array, i, j, _value - _subtract_value)
    _return_array
    // [_rows, _columns] = f_matrix_get_size(_m)
    // for i = 0  to _rows - 1
    //     for j = 0  to _columns - 1
    //         _value = f_matrix_get(_m, i, j)
    //         f_matrix_set(_m, i, j, _value - _subtract_value)
    // _m
//}

// function to scale/multiply a 2D matrix by a certain value //
f_matrix_scalar_multiply(_m, _scalar) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            f_matrix_set(_return_array, i, j, _value * _scalar)
    _return_array
    // [_rows, _columns] = f_matrix_get_size(_m)
    // for i = 0  to _rows - 1
    //     for j = 0  to _columns - 1
    //         _value = f_matrix_get(_m, i, j)
    //         f_matrix_set(_m, i, j, _value * _scalar)
    // _m
//}

// function to transpose a 2D matrices //
f_matrix_transpose(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_columns, _rows, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            f_matrix_set(_return_array, j, i, _value)
    _return_array
//}

// function for ELEMENT WISE MULTIPLICATION of 2D matrices, returns matrix c //
f_matrix_mult_elem(_a, _b) =>
//{
    [_rows_a, _columns_a] = f_matrix_get_size(_a)
    [_rows_b, _columns_b] = f_matrix_get_size(_b)
    _return_array = f_matrix_init(_rows_a, _columns_a, 0)
    if _rows_a == _rows_b and _columns_a == _columns_b
        for i = 0  to _rows_a - 1
            for j = 0  to _columns_a - 1
                _value_a = f_matrix_get( _a, i, j)
                _value_b = f_matrix_get( _b, i, j)
                f_matrix_set(_return_array, i, j, _value_a * + _value_b)
    _return_array
    // [_rows_a, _columns_a] = f_matrix_get_size(_a)
    // [_rows_b, _columns_b] = f_matrix_get_size(_b)
    // if _rows_a == _rows_b and _columns_a == _columns_b
    //     for i = 0  to _rows_a - 1
    //         for j = 0  to _columns_a - 1
    //             _value_a = f_matrix_get( _a, i, j)
    //             _value_b = f_matrix_get( _b, i, j)
    //             f_matrix_set(_a, i, j, _value_a * + _value_b)
    // _a
//}

// function for DOT PROCUCT MULTIPLICATION of 2D matrices, returns matrix c //
f_matrix_mult(_a, _b) =>
//{
    // get matrix metadata //
    [_a_row, _a_col] = f_matrix_get_size(_a), _a_size = _a_row * _a_col
    [_b_row, _b_col] = f_matrix_get_size(_b), _b_size = _b_row * _b_col
    _c_row = _a_row, _c_col = _b_col        , _c_size = _a_row * _b_col
    _c   = f_matrix_init(_a_row, _b_col, 0)
    // error check //
    if _a_col != _b_row
        array.fill(_c, 0)
    // multiplication //
    else
        _a_row_nr = 0, _a_col_nr = 0
        _b_row_nr = 0, _b_col_nr = 0
        _c_row_nr = 0, _c_col_nr = 0
        for i = 0 to (_c_size -1)
            i_val = 0.0
            _c_row_nr := floor(i / _b_col)
            // row_nr := row_nr + ((i % _b_x) == 0 ? 1 : 0)
            _c_col_nr := i % _b_col
            for j = 0 to (_a_col - 1)
                _a_row_nr :=     _c_row_nr , _a_col_nr := j % _a_col 
                _b_row_nr := j % _a_col    , _b_col_nr := _c_col_nr
                i_val := i_val + f_matrix_get(_a, _a_row_nr, _a_col_nr) * f_matrix_get(_b, _b_row_nr, _b_col_nr)
            array.set(_c, 2 + i, i_val)
    // return //
    _c
//}

// Matrix Determinants //
//{
// function to calculate the determinant of 2D matrices //
f_matrix_determinant_2x2(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    var float _determinant = na
    // error check //
    if _rows == _columns and _rows == 2
        // matrix form:
        //      |a   b|
        // det: |     |  =  a * d - c * b
        //      |c   d|
        
        _a = f_matrix_get(_m, 0, 0), _b = f_matrix_get(_m, 0, 1)
        _c = f_matrix_get(_m, 1, 0), _d = f_matrix_get(_m, 1, 1)
        _determinant := _a * _d - _c * _b
    _determinant
    
f_matrix_determinant_3x3(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    var float _determinant = na
    // error check //
    if _rows == _columns and _rows == 3
        // matrix form:
        //      |a  b  c|
        // det: |d  e  f|  =  a * e * i  +  b * f * g  +  c * d * h  -  g * e * c   - d * b * i  -  a * h * f
        //      |g  h  i| 
        _determinant := 0.0
        for i = 0 to _columns - 1
            _cofactor_matrix = array.copy(_m)
            f_matrix_remove_rows(   _cofactor_matrix, 0, 0)
            f_matrix_remove_columns(_cofactor_matrix, i, i)
            _determinant := _determinant + pow(-1, i + 1) * f_matrix_get(_m, 0, i) * f_matrix_determinant_2x2(_cofactor_matrix)
    _determinant
//}
//}

f_matrix_determinant_4x4(_m) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    var float _determinant = na
    // error check //
    if _rows == _columns and _rows == 4
        _determinant := 0.0
        for i = 0 to _columns - 1
            _cofactor_matrix = array.copy(_m)
            f_matrix_remove_rows(   _cofactor_matrix, 0, 0)
            f_matrix_remove_columns(_cofactor_matrix, i, i)
            _determinant := _determinant + pow(-1, i + 1) * f_matrix_get(_m, 0, i) * f_matrix_determinant_3x3(_cofactor_matrix)
    _determinant
//}

// function to print matrix
f_matrix_print(_m) =>
//{
    _text = "(" + tostring(array.get(_m, 0)) + "x" + tostring(array.get(_m, 1)) + ")"
    _text := _text + "\n" + "\n"+"["
    for i = 2 to array.size(_m) - 1
        _text := _text + (i == 2 ? "" : ((i - 2) % array.get(_m, 1)) == 0 ? "]" + "\n" + "[" : " ") + tostring(array.get(_m, i))
    _text := _text + "]"
//}
//}
//}
//}

//////////////////////////////
// Neural Network functions //
//////////////////////////////
//{
// ACTIVATION FUNCTIONS AND DERIVATIVES //

// function calculate the "Sigmoid" function   range = (0, 1)//
//                        S(x) = (1 / (1 + e^-x))  //
//{
f_sigmoid(_x) =>
    _S = 1 / (1 + exp(-1 *  _x))
//}

// function calculate the derivative of the "Sigmoid" function   //
//                        S'(x) = S(x) * (1 - S(x))  //
//{
f_d_sigmoid(_x) =>
    _d_S  = _x * (1 - _x)
//}

// function calculate the "tanh" function     range = (-1, 1)//
//                        _tanh(x) = (e^x - e^-x) / (e^x + e^-x)  //
//{
f_tanh(_x) =>
    _tanh = (exp(_x) -exp(-1 * _x)) / (exp(_x) + exp(-1 *  _x))
//}

// function calculate the derivative of the "tan"h function         //
//                        _tanh(x) = (e^x - e^-x) / (e^x + e^-x)  //
//{
f_d_tanh(_x) =>
    _d_tanh = (1 - pow(_x, 2))
//}

// function calculate the "ReLu" function      range = (-inf, inf)    //
//{
f_ReLu(_x) =>
    _ReLu = max(0, _x)
//}

// function calculate the derivative of the "ReLu" function         //
//{
f_d_ReLu(_x) =>
    _d_ReLu = _x < 0 ? 0 : 1
//}

// function calculate the "leaky ReLu" function     range = (-inf, inf)   //
//{
f_leaky_ReLu(_x) =>
    _leaky_ReLu = max(0.01 * _x, _x)
//}

// function calculate the derivative of the "leaky ReLu" function         //
//{
f_d_leaky_ReLu(_x) =>
    _d_leaky_ReLu = _x < 0 ? 0.01 : 1
//}

// function calculate "SoftMax" values of the output vector               //
//{
f_softmax(_m, _x) =>
    _exp_sum = 0.0
    for i = 2 to array.size(_m) - 1
        _value    = array.get(_m, i)
        _exp_sum := _exp_sum + exp(_value)
    _softmax = exp(_x) / _exp_sum
    _softmax
//}
//
// function calculate the derivative of the "SoftMax" values of the output vector //
//{
f_d_softmax(_m, _x) =>
    _exp_sum      = 0.0
    for i = 2 to array.size(_m) - 1
        _value    = array.get(_m, i)
        _exp_sum := _exp_sum + exp(_value)
    _value_exp_sum = exp(_x) * (_exp_sum - exp(_x))
    _d_softmax = _value_exp_sum / pow(_exp_sum, 2)
    _d_softmax
//}

// function to map a 2D matrices with the activation function          //
f_matrix_activation(_m, _act_fn) =>
//{
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            _activation =
             _act_fn == "Sigm"  ? f_sigmoid(_value)    :
             _act_fn == "Tanh"  ? f_tanh(_value)       :
             _act_fn == "ReLu"  ? f_ReLu(_value)       :
             _act_fn == "lReLu" ? f_leaky_ReLu(_value) : f_softmax(_m, _value)
            f_matrix_set(_return_array, i, j, _activation)
    _return_array
//}

// function to map a 2D matrices with a inverse Sigmoid function    //
//                                      S'(x) = S(x) * (1 - S(x))  //
f_matrix_inverse_activation(_m, _act_fn) =>
//{
    // inverse Sigmoid function
    // S'(x) =  S(x)  * (1 -  S(x)) 
    //         Output * (1 - Output)
    [_rows, _columns] = f_matrix_get_size(_m)
    _return_array = f_matrix_init(_rows, _columns, 0)
    for i = 0  to _rows - 1
        for j = 0  to _columns - 1
            _value = f_matrix_get(_m, i, j)
            _derivative =
             _act_fn == "Sigm"  ? f_d_sigmoid(_value)    : 
             _act_fn == "Tanh"  ? f_d_tanh(_value)       : 
             _act_fn == "ReLu"  ? f_d_ReLu(_value)       :
             _act_fn == "lReLu" ? f_d_leaky_ReLu(_value) : f_d_softmax(_m, _value)
            f_matrix_set(_return_array, i, j, _derivative)
    _return_array
//}

// Feedforward function //
f_feedforward(_Inputs, _Weights, _Bias, _act_fn) =>
//{
    /////   Output = activation fn(Input x Weights + Bias) /////
    _weighted_inputs   = f_matrix_mult(            _Weights, _Inputs)
    _biased_Output     = f_matrix_addition(_weighted_inputs,   _Bias)
    _Output_activation = f_matrix_activation(_biased_Output, _act_fn)
    _Output_activation
//}

// Backpropagation function //
f_backpropagation(_Inputs_transp, _Weights, _Bias, _Outputs, _Errors, _learning_rate, _act_fn) =>
//{
    ///// delta Bias    = learning rate x Errors x (Output x (1 - Output)                    /////
    ///// delta Weights = learning rate x Errors x (Output x (1 - Output) x Input transposed /////
    
    // learning rate x Errors
    _gradient      = f_matrix_scalar_multiply(_Errors, _learning_rate)
    
    // derivative of the activation
    _d_activation  = f_matrix_inverse_activation(_Outputs, _act_fn)
    
    // delta Bias    = learning rate x Errors x d(activation)  
    _delta_bias    = f_matrix_mult_elem(_gradient, _d_activation)
    _Bias_adj      = f_matrix_addition(     _Bias,   _delta_bias)
    f_matrix_replace(_Bias, _Bias_adj)
    
    // delta Weights = learning rate x Errors x d(activation) x Input transposed
    _delta_weights = f_matrix_mult( _delta_bias, _Inputs_transp)
    _Weights_adj   = f_matrix_addition(_Weights, _delta_weights)
    f_matrix_replace(_Weights, _Weights_adj)
    //}
//}

//}
/////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////
///                             Main Script                                   ///
///                                                                           ///
/// (inspired by "The Coding Train 10. Neural Networks - The Nature of Code") ///
/////////////////////////////////////////////////////////////////////////////////
//{

// Inputs //
training_loop = input(  5, title = "Number of Training loops", minval = 1)
learning_rate = input(0.1, title = "Learning rate", minval = 0.001, maxval = 1)

//////////////////////////////////////////////////////////////
//                      Training Data                       //
//////////////////////////////////////////////////////////////
// Demo model of 2 bit number containing:                   //
// 4 rows of data                                           //
// with 2 columns of input data and 1 column of result data //
//////////////////////////////////////////////////////////////
//          NETWORK SIZE           //
//         Number of nodes         //
/////////////////////////////////////
Input_nodes   = 2                  //
//                                 //
Hidden1_nodes = 8                  //
//                                 //
Output_nodes  = 4                  //
//                                 //
//      activation function        //
// options:                        //
// "Sigm", "Tanh",                 //
// "Relu", "lReLu", "SoftMax"      //
act_fn_I_H = "Tanh"                //
act_fn_H_O = "Tanh"                //
/////////////////////////////////////
//          column names           //
input1 = 0, input2 = 1             //
result = 2                         //
/////////////////////////////////////
//
/////////////////////
/// Training Data ///
/////////////////////
//{
Training_data_rows = 4, Training_data_columns = 3
var float[] Training_data = f_matrix_init(Training_data_rows, Training_data_columns, 0)
// set inputs
f_matrix_set(Training_data,  0, input1, 0), f_matrix_set(Training_data,  0, input2, 0), f_matrix_set(Training_data,  0, result,  0)
f_matrix_set(Training_data,  1, input1, 0), f_matrix_set(Training_data,  1, input2, 1), f_matrix_set(Training_data,  1, result,  1)
f_matrix_set(Training_data,  2, input1, 1), f_matrix_set(Training_data,  2, input2, 0), f_matrix_set(Training_data,  2, result,  2)
f_matrix_set(Training_data,  3, input1, 1), f_matrix_set(Training_data,  3, input2, 1), f_matrix_set(Training_data,  3, result,  3)
//}

//////////////////////////////////////////////////////////////
///                 NETWORK SETUP                          ///
//////////////////////////////////////////////////////////////
//{
/////////////////////
/// Input vector ///
/////////////////////
Inputs = f_matrix_init(Input_nodes, 1, 0)

///////////////////////////
/// Hidden nodes vector ///
///////////////////////////
// Set hidden matrix
var float[] Hidden1 = f_matrix_init(Hidden1_nodes, 1, 0)

///////////////////////////
/// Hidden Error vector ///
///////////////////////////
var float[] Errors_hidden = f_matrix_init(Hidden1_nodes, 1, 0)

/////////////////////
/// Output vector ///
/////////////////////
var float[] Output = f_matrix_init(Output_nodes, 1, 0)

/////////////////////
/// Target Matrix ///
/////////////////////
var float[] Targets = f_matrix_init(Output_nodes, 1, 0)

///////////////////////////
/// Output Error vector ///
///////////////////////////
var float[] Errors = f_matrix_init(Output_nodes, 1, 0)

//////////////////////////////////////////////////
/// Weights and Biases Inputs to Hidden matrix ///
//////////////////////////////////////////////////
// set weights matrix and bias vector
var float[] Weights_I_to_H = f_matrix_init(Hidden1_nodes, Input_nodes, 0)
var float[] Bias_I_to_H    = f_matrix_init(Hidden1_nodes, 1, 0)

// set weights to random values (0, 1)
if barstate.isfirst
    f_matrix_randomize(Weights_I_to_H, 1)
    f_matrix_randomize(Bias_I_to_H, 1)

///////////////////////////////////////////////////
/// Weights and Biases Hidden to Outputs matrix ///
///////////////////////////////////////////////////
// set weights matrix and bias vector
var float[] Weights_H_to_O = f_matrix_init(Output_nodes, Hidden1_nodes, 0)
var float[] Bias_H_to_O    = f_matrix_init(Output_nodes, 1, 0)

// set weights to random values
if barstate.isfirst
    f_matrix_randomize(Weights_H_to_O, 1)
    f_matrix_randomize(   Bias_H_to_O, 1)
//}

//////////////////////////////////////////////////////////////
///                 TRAINING CALCULATIONS                  ///
//////////////////////////////////////////////////////////////
//{
for i = 1 to training_loop
    //////////////////////////////////////////
    // SELECT RANDOM TRAINING DATA FROM SET //
    //////////////////////////////////////////
    // set inputs to random row from training
    random_row  = int(min(Training_data_rows, f_prng(Training_data_rows)))
    input_data1 = f_matrix_get(Training_data, random_row, input1)
    input_data2 = f_matrix_get(Training_data, random_row, input2)
    f_matrix_set(Inputs, input1, 0, input_data1)
    f_matrix_set(Inputs, input2, 0, input_data2)
    
    // transpose Input vector
    Inputs_transp = f_matrix_transpose(Inputs)
    
    // set targets to random row from training
    result_data = f_matrix_get(Training_data, random_row, result)
    f_matrix_fill(Targets, 0)
    f_matrix_set(Targets, result_data, 0, 1)
    
    /////////////////
    // FEEDFORWARD //
    /////////////////
    // calculate output vector
    Hidden1 := f_feedforward(Inputs,  Weights_I_to_H, Bias_I_to_H, act_fn_H_O)
    Output  := f_feedforward(Hidden1, Weights_H_to_O, Bias_H_to_O, act_fn_I_H)
    
    /////////////////////
    // BACKPROPAGATION //
    /////////////////////
    Hidden1_transp        := f_matrix_transpose(Hidden1)
    Weights_H_to_O_transp  = f_matrix_transpose(Weights_H_to_O)
    
    // calculate error vector
    Errors        := f_matrix_subtraction(Targets, Output)
    Errors_hidden := f_matrix_mult(Weights_H_to_O_transp, Errors)
    
    // // adjust Weights and Biases
    f_backpropagation(Hidden1_transp, Weights_H_to_O, Bias_H_to_O,  Output,        Errors, learning_rate, act_fn_H_O)
    f_backpropagation( Inputs_transp, Weights_I_to_H, Bias_I_to_H, Hidden1, Errors_hidden, learning_rate, act_fn_I_H)
//////////////////////////////////////////////////////////////
//}


// DEBUG PLOTS //
//{
if barstate.islast
    var label lbl_Training_data = na, label.delete(lbl_Training_data)
    lbl_Training_data := label.new(bar_index - 110, 0, text = "Training_data = " + f_matrix_print(Training_data), color = color.gray, textalign = text.align_left)

    var label lbl_Inputs = na, label.delete(lbl_Inputs)
    lbl_Inputs := label.new(bar_index - 100, 0, text = "random Inputs = " + f_matrix_print(Inputs), color = color.gray, textalign = text.align_left)

    var label lbl_Targets = na, label.delete(lbl_Targets)
    lbl_Targets := label.new(bar_index - 10, 0, text = "Targets = " + f_matrix_print(Targets), color = color.gray, textalign = text.align_left)

    // var label lbl_Weights_I_to_H = na, label.delete(lbl_Weights_I_to_H)
    // lbl_Weights_I_to_H := label.new(bar_index - 90, 0, text = "Weights_I_to_H = " + f_matrix_print(Weights_I_to_H), color = color.gray, textalign = text.align_left)

    // var label lbl_Bias_I_to_H = na, label.delete(lbl_Bias_I_to_H)
    // lbl_Bias_I_to_H := label.new(bar_index - 80, 0, text = "Bias_I_to_H = " + f_matrix_print(Bias_I_to_H), color = color.gray, textalign = text.align_left)
        
    var label lbl_Hidden1 = na, label.delete(lbl_Hidden1)
    lbl_Hidden1 := label.new(bar_index - 70, 0, text = "Hidden1 = " + f_matrix_print(Hidden1), color = color.gray, textalign = text.align_left)
    
    // var label lbl_Weights_H_to_O = na, label.delete(lbl_Weights_H_to_O)
    // lbl_Weights_H_to_O := label.new(bar_index - 50, 0, text = "Weights_H_to_O = " + f_matrix_print(Weights_H_to_O), color = color.gray, textalign = text.align_left)

    // var label lbl_Bias_H_to_O = na, label.delete(lbl_Bias_H_to_O)
    // lbl_Bias_H_to_O := label.new(bar_index - 40, 0, text = "Bias_H_to_O = " + f_matrix_print(Bias_H_to_O), color = color.gray, textalign = text.align_left)
        
    var label lbl_Output = na, label.delete(lbl_Output)
    lbl_Output := label.new(bar_index - 30, 0, text = "Output = " + f_matrix_print(Output), color = color.gray, textalign = text.align_left)
    
    var label lbl_Errors = na, label.delete(lbl_Errors)
    lbl_Errors := label.new(bar_index - 20, 0, text = "Errors = " + f_matrix_print(Errors), textcolor = color.black, textalign = text.align_left)

    var label lbl_Errors_hidden = na, label.delete(lbl_Errors_hidden)
    lbl_Errors_hidden := label.new(bar_index - 60, 0, text = "hidden Errors = " + f_matrix_print(Errors_hidden), textcolor = color.black, textalign = text.align_left)

//
plot(f_matrix_get(Errors, 0, 0), color = color.fuchsia)
plot(f_matrix_get(Errors, 1, 0), color = color.red)
//}
//}

Overview

2 bit number test Neural Network - JD converts linear 1D arrays into 2D matrix structures for weights, biases, and activations using custom array functions. The network trains over a user-defined number of loops at a given learning rate. Results including network outputs and errors appear as plots in a separate pane.

Details

Published by

JorisDuyck on GitHub

Type

Indicator, Pine Script v4

Draws

Separate pane below the chart

Category

AI / machine learning

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
Number of Training loopsint5training_loop
Learning ratefloat0.1learning_rate
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

Function: Decision Tree

by ricardosantos79
261 stars

Function: Decision Tree is a Pine Script v4 study that demonstrates a weighted decision-tree path sampler in a separate pane. A small pseudo-random generator reseeds itself from a stored float and picks node indices whose weights are at least the random draw.

Indicator v4 AI / machine learning
Updated 4 years ago · None stated GitHub repository of Function: Decision Tree

This indicator combines a dynamic Seasonal Random Index (SRI) with a dynamic Karobein Oscillator and a pattern-similarity search algorithm in a separate pane. It normalizes SRI into seasoned and deseasoned series, shading the area green or red to signal trend

Indicator v4 Oscillators & momentumTrend
Updated 1 year ago · None stated GitHub repository of Similarity Search, Karobein and Seasonal Random Index

This indicator plots an oscillator in a separate pane. It builds several SuperTrend series across a user-defined factor range and step, using ATR as the band width. On each bar it measures the distance between the close and each SuperTrend output, then groups

Indicator v5 TrendVolatility & bands
Updated 2 years ago · GPL-3.0 GitHub repository of AI SuperTrend Clustering Oscillator [LuxAlgo]
99 stars

This indicator applies the rectified linear unit to the difference between the selected source and a 20-period simple moving average. Positive deviations plot in green and negative deviations plot in red in a separate pane. The only input changes the price ser

Indicator v6 Moving averagesAI / machine learning
Updated 4 weeks ago · Apache-2.0 GitHub repository of Rectified Linear Unit (ReLU)

Markov State Engine classifies market conditions into six distinct regimes, including strong trends, weak trends, compression, and expansion. It evaluates historical state transitions using an exit-conditional Markov model with Laplace smoothing to estimate re

Indicator v6 AI / machine learningTrend
Updated yesterday · MIT GitHub repository of Markov State Engine [WavesUnchained]

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