Indicator · Pine Script v4 · On the chart

Machine Learning: LVQ-based Strategy

by capissimo

This indicator applies Learning Vector Quantization (LVQ), a supervised neural network competitive learning algorithm, to classify normalized market features.

View on GitHub

Repaints

GitHub stars114on the repository
Pine versionv4older, still runs
Lines of code212
Settings14inputs
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

212 lines of Pine Script v4 from scripts/102-ML-LVQ-based-Strategy-(v2).pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

102-ML-LVQ-based-Strategy-(v2).pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © capissimo

//@version=4
study('Machine Learning: LVQ-based Strategy (v.2)', '', true, precision=4, max_labels_count=200, max_bars_back=5000)

// LVQ-based Strategy (FX and Crypto)

// Description: 

// Learning Vector Quantization (LVQ) can be understood as a special case of 
// an artificial neural network, more precisely, it applies a winner-take-all 
// learning-based approach. It is based on prototype supervised learning 
// classification task and trains its weights through a competitive 
// learning algorithm.

// Algorithm:

// Initialize weights
// Train for 1 to N number of epochs
//   Select a training example
//   Compute the winning vector
//   Update the winning vector
// Classify test sample

// The LVQ algorithm offers a framework to test various indicators easily to see  
// if they have got any *predictive value*. One can easily add cog, wpr and others.
// Note: TradingViews's playback feature helps to see this strategy in action.
// The algo is tested with BTCUSD/1Hour.

// Warning: This is a preliminary version! Signals ARE repainting.
// ***Warning***: Signals LARGELY depend on hyperparams (lrate and epochs).

// Style tags: Trend Following, Trend Analysis
// Asset class: Equities, Futures, ETFs, Currencies and Commodities
// Dataset: FX Minutes/Hours+++/Days

//-------------------- Inputs

ds          = input(close, 'Dataset')
p           = input(14,    'Lookback Window |1..2160|',   minval=1, maxval=2160)
lrate       = input(0.1,   'Learning Rate |0.0001..0.1|', minval=0.0001, maxval=0.1, step=0.0001)
epochs      = input(5,     'Epochs',                      minval=1, maxval=100)
ftype       = input('Volatility','Filter Signals by',     options=['Volatility','Volume','Both','None'])
reverse     = input(false, 'Reverse Signals?')

startYear   = input(2020,  'Training Start Year',         minval=2010)
startMonth  = input(1,     'Training Start Month',        minval=1, maxval=12)
startDay    = input(1,     'Training Start Day',          minval=1, maxval=31)
stopYear    = input(2021,  'Training Stop Year',          minval=2010)
stopMonth   = input(1,     'Training Stop Month',         minval=1, maxval=12)
stopDay     = input(1,     'Training Stop Day',           minval=1, maxval=31)

//-------------------- System Variables

var BUY  = -1 
var SELL =  1 
var HOLD =  0

buy  = reverse ?  1 : -1  //-- some TFs and assets require reversing the signals!!
sell = reverse ? -1 :  1

//--------------------  Dynamic Arrays

var int wnr    = 0      // winner's signal
var int signal = HOLD

//--------------------  Regular arrays

var float[] features = array.new_float()         //-- training data
var float[] weights0 = array.new_float(3, 1.)    //-- learning vectors
var float[] weights1 = array.new_float(3, 100.)

//-------------------- Custom Functions

norm(x, p) => (x - lowest(x, p)) / (highest(x, p) - lowest(x, p))  // normalize features

getwinner(features, weights0, weights1) =>  // compute the winning vector by Euclidean distance 
    d0 = 0.
    d1 = 0.
    size = array.size(features)
    for i=0 to size-1
        d0 := d0 + pow(array.get(features, i) - array.get(weights0, i), 2) 
        d1 := d1 + pow(array.get(features, i) - array.get(weights1, i), 2) 
    d0 > d1 ? SELL : d0 < d1 ? BUY : HOLD      

update(features, weights0, weights1, w, lr) =>  // update the weight array of the winner
    size = array.size(features)
    for i=0 to size-1
        if w==sell
            array.set(weights0, i, array.get(weights0, i) + lrate * (array.get(features, i) - array.get(weights0, i))) 
        if w==buy
            array.set(weights1, i, array.get(weights1, i) + lrate * (array.get(features, i) - array.get(weights1, i))) 

volumeBreak(thres) =>  
    rsivol   = rsi(volume, 14)  
    osc      = hma(rsivol, 10)  
    osc > thres                     

volatilityBreak(volmin, volmax) => atr(volmin) > atr(volmax)

//-------------------- Logic

x = ds[barstate.ishistory ? 0 : 1]

periodStart = timestamp(startYear, startMonth, startDay, 0, 0)
periodStop  = timestamp(stopYear,  stopMonth,  stopDay, 0, 0)

filter =   ftype=='Volatility' ? volatilityBreak(1, 10) 
         : ftype=='Volume'     ? volumeBreak(49) 
         : ftype=='Both'       ? volatilityBreak(1, 10) and volumeBreak(49)
         :                       true

// The core logic of the agorithm

// Collect training data (i.e. features)
f1 = rsi(x, p)  //-- alt: use norm function to unify data to a common range of |0,..,100|
f2 = cci(x, p)  //--      if it has differing ranges
f3 = roc(x, p)

// Train the model using particular training period
if time >= periodStart and time <= periodStop    
    array.clear(features)
    array.push(features, f1)
    array.push(features, f2)
    array.push(features, f3)

    for i=1 to epochs 
        w = getwinner(features, weights0, weights1)  
        update(features, weights0, weights1, w, lrate)  //-- this is 'the act of learning'

// Classify new input sample
if time > periodStop                            
    array.clear(features)
    array.push(features, f1)
    array.push(features, f2)
    array.push(features, f3)
    wnr := getwinner(features, weights0, weights1)

// Generate signal
signal := wnr==SELL and filter ? sell : wnr==BUY and filter ? buy : nz(signal[1])  

changed = change(signal)

startLongTrade  = changed and signal==BUY
startShortTrade = changed and signal==SELL
endLongTrade    = changed and signal==SELL 
endShortTrade   = changed and signal==BUY  

//-------------------- Rendering

plotshape(startLongTrade  ? low  : na, 'Buy',  shape.labelup,   location.belowbar, color.blue, size=size.small)
plotshape(startShortTrade ? high : na, 'Sell', shape.labeldown, location.abovebar, color.red,  size=size.small)
plot(endLongTrade         ? high : na, 'StopBuy',  color.blue, 2, plot.style_cross)
plot(endShortTrade        ? low  : na, 'StopSell', color.red,  2, plot.style_cross)

//-------------------- Alerting

alertcondition(startLongTrade,  'Buy',  'Go long!')
alertcondition(startShortTrade, 'Sell', 'Go short!') 
alertcondition(startLongTrade or startShortTrade, 'Alert', 'Deal Time!')

//-------------------- Backtesting (TODO)

lot_size  = input(0.01, 'Lot Size', options=[0.01,0.1,0.2,0.3,0.5,1,2,3,5,10,20,30,50,100,1000]) 

ohl3 = (open+high+low)/3

var float start_long_trade  = 0.  
var float long_trades       = 0.
var float start_short_trade = 0.  
var float short_trades      = 0.
var int   wins              = 0
var int   trade_count       = 0

if startLongTrade 
    start_long_trade := ohl3 
if endLongTrade
    trade_count  := 1
    ldiff = (ohl3 - start_long_trade)
    wins         := ldiff > 0 ? 1 : 0
    long_trades  := ldiff * lot_size   
if startShortTrade 
    start_short_trade := ohl3
if endShortTrade
    trade_count  := 1
    sdiff = (start_short_trade - ohl3)
    wins         := sdiff > 0 ? 1 : 0
    short_trades := sdiff * lot_size 
    
cumreturn   = cum(long_trades) + cum(short_trades)  //-- cumulative return 
totaltrades = cum(trade_count)
totalwins   = cum(wins)  
totallosses = totaltrades - totalwins == 0 ? 1 : totaltrades - totalwins

//-------------------- Information

var label lbl = na

tbase = (time - time[1]) / 1000
tcurr = (timenow - time_close[1]) / 1000

info =  'CR='          + tostring(cumreturn,             '#.#') 
      + '\nTrades: '   + tostring(totaltrades,           '#')
      + '\nWin/Loss: ' + tostring(totalwins/totallosses, '#.##') 
      + '\nWinrate: '  + tostring(totalwins/totaltrades, '#.#%') 
      + '\nBar Time: ' + tostring(tcurr / tbase,         '#.#%')

if input(true, 'Show Information?') and barstate.islast  
    lbl := label.new(bar_index, close, info, xloc.bar_index, yloc.price, 
                     color.new(color.blue, 100), label.style_label_left, color.black, size.small, text.align_left)
    label.delete(lbl[1])

Overview

Machine Learning: LVQ-based Strategy determines winning prototype vectors using Euclidean distance and continuously updates weights across specified training epochs. Buy and sell signals are generated directly on the price chart with optional volatility or volume filters. Key inputs control the learning rate, epochs, lookback window, and date ranges. Signals repaint on live bars.

Details

Published by

capissimo on GitHub

Type

Indicator, Pine Script v4

Draws

On the price chart

Category

AI / machine learning, Trend

Markets

Crypto, Forex

Timeframes

M15-H1

Risk Notes

  • Signals can change on the live bar or after it closes (repainting)

Settings

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

SettingTypeDefaultVariable
Datasetsourcecloseds
Lookback Window |1..2160|int14p
Learning Rate |0.0001..0.1|float0.1lrate
Epochsint5epochs
Filter Signals bystringVolatilityftype
Reverse Signals?boolfalsereverse
Training Start Yearint2020startYear
Training Start Monthint1startMonth
Training Start Dayint1startDay
Training Stop Yearint2021stopYear
Training Stop Monthint1stopMonth
Training Stop Dayint1stopDay
Show all 14 settings
SettingTypeDefaultVariable
Lot Sizefloat0.01lot_size
Show Information?booltrueShow Information?
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