Indicator · Pine Script v4 · On the chart

Machine Learning: Logistic Regression

by capissimo

This indicator implements a binary logistic regression classification model retrained on each bar using gradient descent optimization.

View on GitHub

Repaints

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

216 lines of Pine Script v4 from scripts/101-ML-Logistic-Regression-(v3).pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

101-ML-Logistic-Regression-(v3).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: Logistic Regression (v.3)', '', true)

// Multi-timeframe Strategy based on Logistic Regression algorithm

// Description: 

// This strategy uses a classic machine learning algorithm that came from statistics -
// Logistic Regression (LR).

// The first and most important thing about logistic regression is that it is not a 
// 'Regression' but a 'Classification' algorithm. The name itself is somewhat misleading. 
// Regression gives a continuous numeric output but most of the time we need the output in 
// classes (i.e. categorical, discrete). For example, we want to classify emails into “spam” or 
// 'not spam',  classify treatment into “success” or 'failure', classify statement into “right” 
// or 'wrong', classify election data into 'fraudulent vote' or 'non-fraudulent vote', 
// classify market move into 'long' or 'short' and so on. These are the examples of 
// logistic regression having a binary output (also called dichotomous). 

// You can also think of logistic regression as a special case of linear regression when the 
// outcome variable is categorical, where we are using log of odds as dependent variable. 
// In simple words, it predicts the probability of occurrence of an event by fitting data to a 
// logit function.

// Basically, the theory behind Logistic Regression is very similar to the one from Linear 
// Regression, where we seek to draw a best-fitting line over data points, but in Logistic 
// Regression, we don’t directly fit a straight line to our data like in linear regression. 
// Instead, we fit a S shaped curve, called Sigmoid, to our observations, that best 
// SEPARATES data points. Technically speaking, the main goal of building the model is to 
// find the parameters (weights) using gradient descent. 

// In this script the LR algorithm is retrained on each new bar trying to classify it 
// into one of the two categories. This is done via the logistic_regression function by
// updating the weights w in the loop that continues for iterations number of times.
// In the end the weights are passed through the sigmoid function, yielding a
// prediction.

// Mind that some assets require to modify the script's input parameters. For instance, 
// when used with BTCUSD and USDJPY, the 'Normalization Lookback' parameter should be set 
// down to 4 (2,...,5..), and optionally the 'Use Price Data for Signal Generation?' 
// parameter should be checked. The defaults were tested with EURUSD.

// Note: TradingViews's playback feature helps to see this strategy in action.
// Warning: Signals ARE repainting.

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

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

ptype      = input('Close','Price Type',                            options=['Open','High','Low','Close','HL2','OC2','OHL3','HLC3','OHLC4'])
reso       = input('',     'Resolution',                            input.resolution)
lookback   = input(3,      'Lookback Window Size |2..n| (2)',       minval=2)
nlbk       = input(2,      'Normalization Lookback |2..240| (120)', minval=2,      maxval=240)
lrate      = input(0.0009, 'Learning Rate |0.0001..0.01|',          minval=0.0001, maxval=0.01, step=0.0001)
iterations = input(1000,   'Training Iterations |50..n|',           minval=50)
ftype      = input('Volatility', 'Filter Signals by',               options=['Volatility','Volume','Both','None'])
minatr     = input(1,      'Min ATR Lag for the Filter |1..n|',     minval=1)
maxatr     = input(10,     'Max ATR Lag for the Filter |1..n|',     minval=1)
vol        = input(55,     'Volume Lag for the Filter |1..n|',      minval=1)
curves     = input(false,  'Show Loss & Prediction Curves?')
easteregg  = input(true,   'Optional Calculation?')  
useprice   = input(true,   'Use Price Data for Signal Generation?')
holding_p  = input(1,      'Holding Period |1..n|',                 minval=1)

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

var BUY = 1, var SELL = -1, var HOLD = 0
var signal     = HOLD
var hp_counter = 0

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

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

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

dot(v, w, p) => sum(v * w, p)  // dot product

sigmoid(z) => 1.0 / (1.0 + exp(-z))

logistic_regression(X, Y, p, lr, iterations) => 
    w = 0.0, loss = 0.0
    for i=1 to iterations
        hypothesis = sigmoid(dot(X, 0.0, p))  //-- prediction
        loss := -1.0 / p * (dot(dot(Y, log(hypothesis) + (1.0 - Y), p), log(1.0 - hypothesis), p)) 
        gradient = 1.0 / p * (dot(X, hypothesis - Y, p))
        w := w - lr * gradient               //-- update weights
    
    [loss, sigmoid(dot(X, w, p))]            //-- current loss & prediction

minimax(ds, p, min, max) =>  // normalize to price
    hi = highest(ds, p), lo = lowest(ds, p)
    (max - min) * (ds - lo)/(hi - lo) + min

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

ds       =  ptype=='Open'  ? open
          : ptype=='High'  ? high 
          : ptype=='Low'   ? low 
          : ptype=='Close' ? close 
          : ptype=='HL2'   ? (high+low)/2 
          : ptype=='OC2'   ? (open+close)/2 
          : ptype=='OHL3'  ? (open+high+low)/3 
          : ptype=='HLC3'  ? (high+low+close)/3 
          :                  (open+high+low+close)/4
          
base_ds  = security('', reso, ds) 
synth_ds = log(abs(pow(base_ds, 2) - 1) + .5)  //-- generate a synthetic dataset

base  = easteregg ? time    : base_ds          //-- standard and optional calculation
synth = easteregg ? base_ds : synth_ds         

[loss, prediction] = logistic_regression(base, synth, lookback, lrate, iterations) 
scaled_loss        = minimax(loss,       nlbk, lowest(base_ds, nlbk), highest(base_ds, nlbk))
scaled_prediction  = minimax(prediction, nlbk, lowest(base_ds, nlbk), highest(base_ds, nlbk))

filter =   ftype=='Volatility' ? volatilityBreak(minatr, maxatr) 
         : ftype=='Volume'     ? volumeBreak(vol) 
         : ftype=='Both'       ? volatilityBreak(minatr, maxatr) and volumeBreak(vol)
         :                       true

signal :=  useprice ? 
           base_ds < scaled_loss and filter ? SELL : base_ds > scaled_loss and filter ? BUY : nz(signal[1]) 
         : crossunder(scaled_loss, scaled_prediction) and filter ? SELL : crossover(scaled_loss, scaled_prediction) and filter ? BUY : nz(signal[1])  

changed = change(signal)
    
hp_counter := changed ? 0 : hp_counter + 1

startLongTrade  = changed and signal==BUY    
startShortTrade = changed and signal==SELL   
endLongTrade    = (signal==BUY  and hp_counter==holding_p and not changed) or (changed and signal==SELL)
endShortTrade   = (signal==SELL and hp_counter==holding_p and not changed) or (changed and signal==BUY)

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

plot(curves ? scaled_loss : na,       '', color.blue, 3)
plot(curves ? scaled_prediction : na, '', color.lime, 3)

plotshape(startLongTrade  ? low  : na, 'Buy',  shape.labelup,   location.belowbar, color.teal,   text='l', textcolor=color.white, size=size.tiny)  
plotshape(startShortTrade ? high : na, 'Sell', shape.labeldown, location.abovebar, color.maroon, text='l', textcolor=color.white, size=size.tiny)
plot(endLongTrade         ? high : na, 'StopBuy',  color.teal,   2, plot.style_cross)
plot(endShortTrade        ? low  : na, 'StopSell', color.maroon, 2, plot.style_cross)

//-------------------- Notification

if changed and signal==BUY 
    alert("Buy Alert", alert.freq_once_per_bar)  // alert.freq_once_per_bar_close
if changed and signal==SELL 
    alert("Sell Alert", alert.freq_once_per_bar)
    
alertcondition(startLongTrade,  "Buy Alert",  "Go Long!")
alertcondition(startShortTrade, "Sell Alert", "Go Short!")

//-------------------- Backtesting

show_info = input(true, '===Information===')
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]) 
useopen   = input(true, 'Use OHL3=false, Open=true in calculation')

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

bidask  = useopen ? open :(open+high+low)/3

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

if startLongTrade 
    start_long_trade := bidask 
if endLongTrade
    ldiff         = (bidask - start_long_trade)
    wins         := ldiff > 0 ? 1 : 0
    long_trades  := ldiff * lot_size   
    trade_count  := 1
if startShortTrade 
    start_short_trade := bidask
if endShortTrade
    sdiff         = (start_short_trade - bidask)
    wins         := sdiff > 0 ? 1 : 0
    short_trades := sdiff * lot_size 
    trade_count  := 1
    
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

info =  'HPeriod: '    + tostring(holding_p,             '#') 
      + '\nCR='        + tostring(cumreturn,             '#.#') 
      + '\nTrades: '   + tostring(totaltrades,           '#')
      + '\nWin/Loss: ' + tostring(totalwins/totallosses, '#.##') 
      + '\nWinrate: '  + tostring(totalwins/totaltrades, '#.#%')       
      + '\nBar Time: ' + tostring(barlife,               '#.#%')

if show_info and barstate.islast  
    lbl := label.new(bar_index, ohlc4, 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: Logistic Regression processes normalized price features through a sigmoid activation function to classify market direction and generate directional signals directly on the price chart. Users can configure the training lookback window, normalization period, learning rate, training iterations, and optional volatility or volume filters. According to the author, signals on this indicator repaint.

Details

Published by

capissimo on GitHub

Type

Indicator, Pine Script v4

Draws

On the price chart

Category

AI / machine learning, Trend

Markets

Forex, Crypto, Stocks, Oil & commodities

Timeframes

Any timeframe

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
Price TypestringCloseptype
Resolutiontimeframereso
Lookback Window Size |2..n| (2)int3lookback
Normalization Lookback |2..240| (120)int2nlbk
Learning Rate |0.0001..0.01|float0.0009lrate
Training Iterations |50..n|int1000iterations
Filter Signals bystringVolatilityftype
Min ATR Lag for the Filter |1..n|int1minatr
Max ATR Lag for the Filter |1..n|int10maxatr
Volume Lag for the Filter |1..n|int55vol
Show Loss & Prediction Curves?boolfalsecurves
Optional Calculation?booltrueeasteregg
Show all 17 settings
SettingTypeDefaultVariable
Use Price Data for Signal Generation?booltrueuseprice
Holding Period |1..n|int1holding_p
===Information===booltrueshow_info
Lot Sizefloat0.01lot_size
Use OHL3=false, Open=true in calculationbooltrueuseopen
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