Bayesian Trend Indicator
Updated
June 3, 2024
TradingView

For free use on the TradingView platform

Bayesian Trend Indicator

Overview:

In probability theory and statistics, Bayes' theorem (alternatively Bayes' law or Bayes' rule), named after Thomas Bayes, describes the probability of an event, based on prior knowledge of conditions that might be related to the event.

The "Bayesian Trend Indicator" is a sophisticated technical analysis tool designed to assess the direction of price trends in financial markets. It combines the principles of Bayesian probability theory with moving average analysis to provide traders with a comprehensive understanding of market sentiment and potential trend reversals.

At its core, the indicator utilizes multiple moving averages, including the Exponential Moving Average (EMA), Simple Moving Average (SMA), Double Exponential Moving Average (DEMA), and Volume Weighted Moving Average (VWMA). These moving averages are calculated based on user-defined parameters such as length and gap length, allowing traders to customize the indicator to suit their trading strategies and preferences.

The indicator begins by calculating the trend for both fast and slow moving averages using a Smoothed Gradient Signal Function. This function assigns a numerical value to each data point based on its relationship with historical data, indicating the strength and direction of the trend.


// Smoothed Gradient Signal Function 
sig(float src, gap)=>
    ta.ema(source >= src[gap]   ? 1   : 
     source >= src[gap-1] ? 0.9 :
     source >= src[gap-2] ? 0.8 :
     source >= src[gap-3] ? 0.7 :
     source >= src[gap-4] ? 0.6 :
     source >= src[gap-5] ? 0.5 :
     source >= src[gap-6] ? 0.4 :
     source >= src[gap-7] ? 0.3 :
     source >= src[gap-8] ? 0.2 :
     source >= src[gap-9] ? 0.1 :
      0, 4)

Next, the indicator calculates prior probabilities using the trend information from the slow moving averages and likelihood probabilities using the trend information from the fast moving averages. These probabilities represent the likelihood of an uptrend or downtrend based on historical data.


// Define prior probabilities using moving averages
prior_up = (ema_trend + sma_trend + dema_trend + vwma_trend) / 4
prior_down = 1 - prior_up

// Define likelihoods using faster moving averages
likelihood_up = (ema_trend_fast + sma_trend_fast + dema_trend_fast + vwma_trend_fast) / 4
likelihood_down = 1 - likelihood_up

Using Bayes' theorem, the indicator then combines the prior and likelihood probabilities to calculate posterior probabilities, which reflect the updated probability of an uptrend or downtrend given the current market conditions. These posterior probabilities serve as a key signal for traders, informing them about the prevailing market sentiment and potential trend reversals.


// Calculate posterior probabilities using Bayes' theorem
posterior_up = prior_up * likelihood_up 
                             / 
               (prior_up * likelihood_up + prior_down * likelihood_down)
                 

Key Features:

◆ The trend direction:

To visually represent the trend direction, the indicator colors the bars on the chart based on the posterior probabilities. Bars are colored green to indicate an uptrend when the posterior probability is greater than 0.5 (>50%), while bars are colored red to indicate a downtrend when the posterior probability is less than 0.5 (<50%).

◆ Dashboard on the chart

Additionally, the indicator displays a dashboard on the chart, providing traders with detailed information about the probability of an uptrend, as well as the trends for each type of moving average. This dashboard serves as a valuable reference for traders to monitor trend strength and make informed trading decisions.

◆ Probability labels and signals:

Furthermore, the indicator includes probability labels and signals, which are displayed near the corresponding bars on the chart. These labels indicate the posterior probability of a trend, while small diamonds above or below bars indicate crossover or crossunder events when the posterior probability crosses the 0.5 threshold (50%).The posterior probability of a trend

Crossover or Crossunder events

◆ User Inputs

  • Source:
    Description: Defines the price source for the indicator's calculations. Users can select between different price values like close, open, high, low, etc.
  • MA's Length:
    Description: Sets the length for the moving averages used in the trend calculations. A larger length will smooth out the moving averages, making the indicator less sensitive to short-term fluctuations.
  • Gap Length Between Fast and Slow MA's:
    Description: Determines the difference in lengths between the slow and fast moving averages. A higher gap length will increase the difference, potentially identifying stronger trend signals.
  • Gap Signals:
    Description: Defines the gap used for the smoothed gradient signal function. This parameter affects the sensitivity of the trend signals by setting the number of bars used in the signal calculations.

In summary, the "Bayesian Trend Indicator" is a powerful tool that leverages Bayesian probability theory and moving average analysis to help traders identify trend direction, assess market sentiment, and make informed trading decisions in various financial markets.


// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ChartPrime

//@version=5
indicator('Bayesian Trend Indicator [ChartPrime]', shorttitle = "Bayesian Trend [ChartPrime]", overlay=true, max_labels_count = 100)

// ---------------------------------------------------------------------------------------------------------------------}
// 𝙐𝙎𝙀𝙍 𝙄𝙉𝙋𝙐𝙏𝙎

// ---------------------------------------------------------------------------------------------------------------------{
float source    = input(hlc3, title='Source', group = "Settings")
int length      = input.int(60, title="MA's Length", group = "Settings")

int gap_length  = input.int(20, "Gap Length Between Fast And Slow MA's", 
                             tooltip = "Determines the difference in lengths between the slow and fast moving averages. 
                             A higher gap length will increase the difference, potentially identifying stronger trend signals"
                             )
int gap         = input.int(10, "Gap Signals", minval = 10, 
                             tooltip = "Defines the gap used for the smoothed gradient signal function. 
                             This parameter affects the sensitivity of the trend signals by setting the number of bars used in the signal calculations."
                             )

color colorUp = #0fac16
color colorDn = #c51212


// ---------------------------------------------------------------------------------------------------------------------}
// 𝙄𝙉𝘿𝙄𝘾𝘼𝙏𝙊𝙍 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎
// ---------------------------------------------------------------------------------------------------------------------{
// Calculate moving averages
ema_  = ta.ema(source, length)
sma_  = ta.sma(source, length)
dema_ = ta.ema(2 * ta.ema(source, length) - ta.ema(ta.ema(source, length), length), length)
vwma_ = ta.vwma(source, length)

// Calculate faster moving averages with lower length
ema_fast  = ta.ema(source, length-gap_length)
sma_fast  = ta.sma(source, length-gap_length)
dema_fast = ta.ema(2 * ema_fast - ta.ema(ema_fast, length-gap_length), length-gap_length)
vwma_fast = ta.vwma(source, length-gap_length)

// Smoothed Gradient Signal Function 
sig(float src, gap)=>
    ta.ema(
     source >= src[gap]   ? 1   : 
     source >= src[gap-1] ? 0.9 :
     source >= src[gap-2] ? 0.8 :
     source >= src[gap-3] ? 0.7 :
     source >= src[gap-4] ? 0.6 :
     source >= src[gap-5] ? 0.5 :
     source >= src[gap-6] ? 0.4 :
     source >= src[gap-7] ? 0.3 :
     source >= src[gap-8] ? 0.2 :
     source >= src[gap-9] ? 0.1 :
      0, 4
      )

// Calculate trend for each faster moving average
ema_trend_fast  = sig(ema_fast, gap)
sma_trend_fast  = sig(sma_fast, gap)
dema_trend_fast = sig(dema_fast, gap)
vwma_trend_fast = sig(vwma_fast, gap)

// Calculate trend for each moving average
ema_trend       = sig(ema_, gap)
sma_trend       = sig(sma_, gap)
dema_trend      = sig(dema_, gap)
vwma_trend      = sig(vwma_, gap)

// Define prior probabilities using moving averages
prior_up   = (ema_trend + sma_trend + dema_trend + vwma_trend) / 4
prior_down = 1 - prior_up

// Define likelihoods using faster moving averages
likelihood_up   = (ema_trend_fast + sma_trend_fast + dema_trend_fast + vwma_trend_fast) / 4
likelihood_down = 1 - likelihood_up

// Calculate posterior probabilities using 𝘽𝙖𝙮𝙚𝙨❜ 𝙩𝙝𝙚𝙤𝙧𝙚𝙢
posterior_up =                  prior_up * likelihood_up 
                                         / 
               (prior_up * likelihood_up + prior_down * likelihood_down)
                 
if na(posterior_up)
    posterior_up := 0

// ---------------------------------------------------------------------------------------------------------------------}
// 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉
// ---------------------------------------------------------------------------------------------------------------------{
// Bar Color Trend
trend_col = posterior_up < 0.48 
 ? color.from_gradient(posterior_up, 0, 0.48, colorDn, color.new(chart.bg_color, 20)) 
 : posterior_up > 0.52 ? color.from_gradient(posterior_up, 0.52, 1, color.new(chart.bg_color, 20), colorUp) 
 : chart.bg_color


plotcandle(open, high, low, close, 
             color       = trend_col, 
             bordercolor = trend_col, 
             wickcolor   = trend_col
             )
barcolor(trend_col)

// Table
var table tbl = table.new(position.top_right, 10, 10)

add_val(col, row, col1, row1, txt, val, val1)=>
    table.cell(tbl, col, row, txt, text_color = chart.fg_color)

    table.cell(tbl, col1, row1, str.tostring(math.round(val, 2)), 
              text_color = color.from_gradient(val, 0, 1, colorDn, colorUp))
    table.cell(tbl, col1+1, row1, str.tostring(math.round(val1, 2)), 
              text_color = color.from_gradient(val1, 0, 1, colorDn, colorUp))

if barstate.islast
    table.cell(tbl, 0, 0, "乃𝙖𝙮𝙚𝙨𝙞𝙖𝙣  𝙏𝙧𝙚𝙣𝙙  𝙄𝙣𝙙𝙞𝙘𝙖𝙩𝙤𝗿", text_color = chart.fg_color, text_size = size.large)
    table.merge_cells(tbl, 0, 0, 3, 0)
    table.cell(tbl, 0, 1, "𝗣𝗿𝗼𝗯𝗮𝗯𝗶𝗹𝗶𝘁𝘆 𝗼𝗳 𝗨𝗽 𝗧𝗿𝗲𝗻𝗱:", text_color = chart.fg_color, text_size = size.normal)
    table.cell(tbl, 1, 1, str.tostring(posterior_up*100, format = format.percent), 
                 text_color = color.from_gradient(posterior_up, 0, 1, colorDn, colorUp), 
                 text_size  = posterior_up>0.5? size.large : size.normal)

    table.merge_cells(tbl, 1, 1, 3, 1)
    table.cell(tbl, 0, 2)

    table.cell(tbl, 0, 3, "Moving Average", text_color = #4a4f5e)
    table.cell(tbl, 1, 3, "Slow",           text_color = #4a4f5e)
    table.cell(tbl, 2, 3, "Fast",           text_color = #4a4f5e)

    add_val(0, 4, 1, 4, "SMA", sma_trend, sma_trend_fast)
    add_val(0, 5, 1, 5, "EMA", ema_trend, ema_trend_fast)
    add_val(0, 6, 1, 6, "DEMA", dema_trend, dema_trend_fast)
    add_val(0, 7, 1, 7, "VWMA", vwma_trend, vwma_trend_fast)

// Probability Labels   FROM 0 TO 1 (0%-100%)
label.new(
     x         = bar_index,
     y         = posterior_up > 0.5 ? high : low,
     text      = str.tostring(math.round(posterior_up,2)), 
     style     = posterior_up > 0.5 ? label.style_label_down : label.style_label_up, 
     textcolor = color.from_gradient(posterior_up, 0, 1, colorDn, colorUp),
     color     = color(na)
     )

// Signals
plotchar(ta.crossover(posterior_up, 0.5), 
         char     = "◆", 
         location = location.belowbar, 
         size     = size.tiny, 
         color    = color.new(colorUp, 5)
         )
plotchar(ta.crossunder(posterior_up, 0.5), 
         char     = "◆", 
         location = location.abovebar,
         size     = size.tiny, 
         color    = color.new(colorDn, 5)
         )

// △▽

// ---------------------------------------------------------------------------------------------------------------------}

Get access to our Exclusive
premium indicators