Strategy · Pine Script v5 · On the chart

Imbalance Strategy

by creatidy· code credited to Marlborough76

A stock strategy that combines a trend template with relative strength against a reference index.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code311
Settings9inputs
LicenceGPL-3.0
Last update3 years ago10 Aug 2023

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 strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

311 lines of Pine Script v5 from Strategies/Imbalance Strategy.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.

Imbalance Strategy.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Marlborough76

//@version=5
// indicator("Imbalace Indicator", overlay=true)
strategy("Imbalace Strategy", overlay=true,
     initial_capital=1000000, 
    //  commission_type=strategy.commission.cash_per_contract, 
     commission_type=strategy.commission.cash_per_contract,
     commission_value=0.01,
     default_qty_type = strategy.percent_of_equity,
     default_qty_value = 100)

FromYear  = input.int(defval = 2019, title = "From Year", minval = 2000)
FromMonth = input.int(defval = 1, title = "From Month", minval = 1, maxval = 12)
Months    = input.int(defval = 120, title = "Months Ahead", minval = 1)
ToYear    = FromYear + int(Months / 12)              // input.int(defval = 9999, title = "To Year", minval = 2017)
ToMonth   = (Months + FromMonth) % 12                // input.int(defval = 1, title = "To Month", minval = 1, maxval = 12)
start     = timestamp(FromYear, FromMonth, 1, 0, 0)  // backtest start window
finish    = timestamp(ToYear, ToMonth, 1, 0, 0)      // backtest finish window
window() => 
    time >= start and time <= finish ? true : false // create function "within window of time"

/////////////////////////////////////
// Common code
percentile = input.int(defval = 95, title="Impulse Percentile", minval=0, maxval=99)
max_channel_size = input.int(defval = 8, title="Max Channel Size [%]", minval=0, maxval=99) * 0.01
tolerance = input.float(defval = 0.1, title="Tolerance [%]", minval=0, maxval=99, step=0.1) * 0.01

green50 = color.new(#44FF24, 60)
red50 = color.new(#FF4424, 50)

/////////////////////////////////
// Averages
///////////////////////////////////////

smma(src, length) =>
    smma =  0.0
    smma := na(smma[1]) ? ta.sma(src, length) : (smma[1] * (length - 1) + src) / length
    smma

weekly = timeframe.isweekly ? 1 : 5
smma_week = smma(close, 4 * weekly)
smma_short = smma(close, 10 * weekly)
smma_mid = smma(close, 30 * weekly)
smma_long = smma(close, 40 * weekly)
lowest = ta.lowest(low, 52 * weekly)
highest = ta.highest(high, 52 * weekly)


/////////////////////////////////////
// 

ref_input = input("GPW:WIG", title="Reference")
up_color = input(color.green, title="Strength Color")
down_color = input(color.red, title="Weakness Color")
oneYear = 52*weekly

stock = request.security(syminfo.tickerid, timeframe.period, close)
ref = array.pop(str.split(syminfo.tickerid,":")) != ref_input ? request.security(ref_input, timeframe.period, close) : stock

// use more recent quarters if data for full year is not available
quarter_perf(data, n) =>
    i = n
    refCandle = i*oneYear/4
    baseCandle = (i-1)*oneYear/4
    while (not data[refCandle] and i > 1) 
        i := i - 1
        refCandle := i*oneYear/4
        baseCandle := (i-1)*oneYear/4
    
    ta.roc(data[baseCandle], refCandle)

// first quarter is weighted more
stock_performance = 0.4*quarter_perf(stock,1) + 0.2*quarter_perf(stock,2) + 0.2*quarter_perf(stock,3) + 0.2*quarter_perf(stock,4)
ref_performance = 0.4*quarter_perf(ref,1) + 0.2*quarter_perf(ref,2) + 0.2*quarter_perf(ref,3) + 0.2*quarter_perf(ref,4)
zero_line = 0
rs = stock_performance - ref_performance

up_trend = true
// Stock price is above MA 150 and 200
// MA 150 is above MA 200
up_trend := smma_mid > smma_long ? up_trend : false
// MA 200 is trending at least 1 month(22 days)
up_trend := ta.lowest(smma_long, 4*weekly+1) == smma_long[4*weekly] ? up_trend : false
// MA 50 is above both MA 150 and MA 200
up_trend := smma_short > smma_mid ? up_trend : false
up_trend := smma_week > smma_short ? up_trend : false
// The current stock price is trading  above MA 50
up_trend := close > smma_short ? up_trend : false
// Current stock price is 30% above 52 weeks low
up_trend := close > lowest * 1.30 ? up_trend : false
// Current Price is within 25% of 52 week high
up_trend := close > highest * 0.75 ? up_trend : false
// RS Ratings more than 70
// TODO
up_trend := rs > 4.0 ? up_trend : false

down_trend = true
down_trend := smma_mid < smma_long ? down_trend : false
down_trend := ta.highest(smma_long, 4*weekly+1) == smma_long[4*weekly] ? down_trend : false
down_trend := smma_short < smma_mid ? down_trend : false
down_trend := smma_week < smma_short ? down_trend : false
down_trend := close < smma_short ? down_trend : false
down_trend := close < highest * 0.75 ? down_trend : false
down_trend := close < lowest * 1.30 ? down_trend : false
down_trend := rs < -4.0 ? down_trend : false

/////////////////////////
// Volume
    
bar_size = math.abs(close[1] - close)
bar_size_volume = bar_size * nz(volume, 1)
percentile_close = ta.percentile_nearest_rank(bar_size_volume, 40*weekly, percentile)
sma_volume = ta.sma(volume, 10 * weekly)

/////////////////////////
// Variables

bool up_imbalance = na
bool down_imbalance = na
bool big_move_up = false
bool big_move_down = false
int up_imbalance_bar_index = na
int down_imbalance_bar_index = na
float up_imbalance_high = na
float up_imbalance_low = na
float down_imbalance_high = na
float down_imbalance_low = na
float up_imbalance_highest = na
float up_imbalance_lowest = na
float down_imbalance_highest = na
float down_imbalance_lowest = na
int lastX = na
float lastHY = na
float lastLY = na
float up_stop_limit = na
float up_limit = na
float up_stop_margin = na

up_imbalance_high := up_imbalance_high[1]
up_imbalance_low := up_imbalance_low[1]
up_imbalance_bar_index := up_imbalance_bar_index[1]
down_imbalance_high := down_imbalance_high[1]
down_imbalance_low := down_imbalance_low[1]
down_imbalance_bar_index := down_imbalance_bar_index [1]
lastX := lastX[1]
lastHY := lastHY[1]
lastLY := lastLY[1]
up_stop_limit := up_stop_limit[1]
up_limit := up_limit[1]
up_stop_margin := up_stop_margin[1]

/////////////////////////////////
// Big move detection
if (na(volume) and bar_size > percentile_close) or (not na(volume) and bar_size_volume > percentile_close)
    if close > open
        big_move_up := true 
    else
        big_move_down := true

//////////////////////////////////
// Imbalance detection

top_imbalance = (low[2] <= open[1] and high[0] >= close[1]) or low[1] > high
top_imbalancesize = low[2] - high[0]
down_imbalance := top_imbalance and top_imbalancesize > 0
if down_imbalance
    red_box = box.new(left=bar_index[1], top=low[2], right=bar_index[0], bottom=high[0])
    box.set_bgcolor(red_box, red50)
    box.set_border_color (red_box, red50)
    down_imbalance_high := not na(up_imbalance_low) and up_imbalance_low < high[0] ? na : down_imbalance_high[1] ? down_imbalance_high[1] : low[2] 
    down_imbalance_low := not na(up_imbalance_low) and up_imbalance_low < high[0] ? na : high[0]
    down_imbalance_bar_index := bar_index
bottom_imbalance = (high[2] >= open[1] and low[0] <= close[1]) or high[1] < low
bottom_imbalancesize = low[0] - high[2]
up_imbalance := bottom_imbalance and bottom_imbalancesize > 0
if up_imbalance
    green_box = box.new(left=bar_index[1], top=low[0], right=bar_index[0], bottom=high[2])
    box.set_bgcolor(green_box, green50)
    box.set_border_color (green_box, green50)
    up_imbalance_high := not na(down_imbalance_high) and down_imbalance_high > low[0] ? na : low[0]
    up_imbalance_low := not na(down_imbalance_high) and down_imbalance_high > low[0] ? na : up_imbalance_low[1] ? up_imbalance_low[1] : high[2]
    up_imbalance_bar_index := bar_index
down_imbalance_high := high > down_imbalance_high or bar_index > down_imbalance_bar_index + 10 * weekly ? na : down_imbalance_high
down_imbalance_low := na(down_imbalance_high) ? na : high > down_imbalance_low ? high : down_imbalance_low
up_imbalance_low := low < up_imbalance_low or bar_index > up_imbalance_bar_index + 10 * weekly ? na : up_imbalance_low
up_imbalance_high := na(up_imbalance_low) ? na : low < up_imbalance_high ? low : up_imbalance_high

//////////////////////////
// Calculate KC

tr_range = math.max(high - low, math.abs(high - close[1]), math.abs(low - close[1]))
sma_range = ta.percentile_nearest_rank(tr_range, 20 * weekly, 50) //ta.sma(tr_range, sma_length)
upperKC = smma_short + sma_range * 1.5
lowerKC = smma_short - sma_range * 1.5
// plot(upperKC)
// plot(lowerKC)

///////////////////////////////////////////////////
// Consolidation zone
consolidation_length = 15
candle_high = open > close ? (high + open) / 2 : (high + close) / 2
candle_low = open < close ? (low + open) / 2 : (low + close) / 2
candle_highest = ta.highest(candle_high, consolidation_length)
candle_lowest = ta.lowest(candle_low, consolidation_length)
up_stop_margin := (candle_highest - candle_lowest) / 2
up_stop_limit := candle_lowest + up_stop_margin
up_limit := candle_highest + up_stop_margin

if (candle_highest - candle_lowest > upperKC - lowerKC) or (candle_highest - candle_lowest) / candle_highest > max_channel_size
    candle_highest := na
    candle_lowest := na
    up_stop_margin := up_stop_margin[1]
    up_stop_limit := up_stop_limit[1]
    up_limit := up_limit[1]
if not na(candle_highest[1])
    candle_highest := candle_highest[1]
    candle_lowest := candle_lowest[1]
    up_stop_margin := up_stop_margin[1]
    up_stop_limit := up_stop_limit[1]
    up_limit := up_limit[1]
if not na(candle_highest[1]) and (high > candle_highest[1] * (1+tolerance) or low < candle_lowest[1] * (1-tolerance))
    candle_highest := na
    candle_lowest := na
    up_stop_margin := up_stop_margin[1]
    up_stop_limit := up_stop_limit[1]
    up_limit := up_limit[1]
if strategy.position_size > 0
    up_stop_margin := up_stop_margin[1]
    up_stop_limit := up_stop_limit[1]
    up_limit := up_limit[1]

line line1 = na
line line2 = na
line line3 = na
line line4 = na
line line5 = na
if not na(candle_highest[1]) and na(candle_highest)
    if lastX < bar_index[consolidation_length]
        line1 := line.new(bar_index[consolidation_length], candle_highest[1], bar_index, candle_highest[1], color=color.new(color.blue,60))
        line3 := line.new(bar_index[consolidation_length], candle_lowest[1], bar_index, candle_lowest[1], color=color.new(color.blue,60))
        line5 := line.new(bar_index[consolidation_length], (candle_highest[1] + candle_lowest[1]) / 2, bar_index, (candle_highest[1] + candle_lowest[1]) / 2, color=color.new(color.blue,60))
    else
        line1 := line.new(lastX, candle_highest[1], bar_index, candle_highest[1], color=color.new(color.blue,60))
        line2 := line.new(lastX, candle_lowest[1], bar_index, candle_lowest[1], color=color.new(color.blue,60))
        line3 := line.new(lastX, lastHY, lastX, candle_highest[1], style=line.style_dotted, color=color.new(color.blue,60))
        line4 := line.new(lastX, lastLY, lastX, candle_lowest[1], style=line.style_dotted, color=color.new(color.blue,60))
        line5 := line.new(lastX, (candle_highest[1] + candle_lowest[1]) / 2, bar_index, (candle_highest[1] + candle_lowest[1]) / 2, color=color.new(color.blue,60))
    lastX := bar_index[1]
    lastHY := candle_highest[1]
    lastLY := candle_lowest[1]

////////////////////////////////////////
// Momentum
int up_bar = close > close[1] ? 1 : 0
bool momentum = up_bar and math.sum(up_bar, 15) >= 12 and close > close[14] * 1.2 and sma_volume > sma_volume[14] * 1.25

////////////////////////////////////////
// Warnings
bool lower_lows = na
lower_lows := (up_trend or up_trend[1] or up_trend[2]) and low < low[1] and low[1] < low[2] and low[2] < low[3] and not (close > 0.5 * (high + low) and volume > sma_volume)
bool close_bl_20 = (up_trend or up_trend[1] or up_trend[2]) and close < smma_week and close[1] >= smma_week[1]

////////////////////////////////////////
// Strategy
int entry_bar_index = na
entry_bar_index := strategy.position_size == 0 ? 0 : entry_bar_index[1]

if window() and strategy.position_size == 0
    if up_trend and not na(candle_highest)
        strategy.entry("L", direction=strategy.long, limit=up_limit, stop=(up_stop_limit + up_stop_margin) * (1 + tolerance) )
        entry_bar_index := bar_index
    else
        strategy.cancel("L")
// plot((up_stop_limit + up_stop_margin) * 1.01)
if strategy.position_size > 0
    if (not up_trend and bar_index >= entry_bar_index + 15) or momentum
        strategy.cancel_all()
        strategy.close("L")
    else
        new_stop_limit = smma_week - up_stop_margin
        up_stop_limit := new_stop_limit > up_stop_limit and new_stop_limit < strategy.position_avg_price ? new_stop_limit : new_stop_limit > up_stop_limit and new_stop_limit >= strategy.position_avg_price ? (strategy.position_avg_price > smma_short ? strategy.position_avg_price : smma_short) : up_stop_limit
        if close <= up_stop_limit
            strategy.exit("LS", from_entry="L", stop=up_stop_limit)
        else
            strategy.cancel("LS")
// plot(up_stop_limit)

////////////////////////////////////////
// Plot functions

bar_color = close > close[1] ? (close > 0.5 * (high + low) ? color.green : color.teal) : (close < 0.5 * (high + low) ? color.red : color.olive)
barcolor(bar_color)
plot1 = plot(smma_week, style=plot.style_linebr, color=up_trend ? color.new(color.green, 50) : down_trend ? color.new(color.red, 70) : color.new(color.gray, 70))
plot2 = plot(smma_short, style=plot.style_linebr, color=up_trend ? color.new(color.green, 50) : down_trend ? color.new(color.red, 70) : color.new(color.gray, 70))
fill(plot1, plot2, color=up_trend ? color.new(color.green, 80) : down_trend ? color.new(color.red, 80) : color.new(color.gray, 95))

plot(smma_mid, style=plot.style_linebr, color=color.new(color.blue, 70))
plot(smma_long, style=plot.style_linebr, color=color.new(color.yellow, 70))

plot(candle_highest*(1+tolerance), color=color.new(color.blue,70), style=plot.style_linebr, linewidth=1)
plot(candle_highest, color=up_trend ? #00FF00 : color.blue, style=plot.style_linebr, linewidth=2)
plot((candle_highest + candle_lowest) / 2, color=color.new(color.blue,60), style=plot.style_linebr, linewidth=1)
plot(candle_lowest, color=down_trend ? #FF0000 : color.blue, style=plot.style_linebr, linewidth=2)
plot(candle_lowest*(1-tolerance), color=color.new(color.blue,70), style=plot.style_linebr, linewidth=1)

plotshape(big_move_up, style=shape.triangleup,location=location.belowbar, color=color.new(color.teal, 50), size = size.tiny)
plotshape(big_move_down, style=shape.triangledown,location=location.abovebar, color=color.new(color.olive, 50), size = size.tiny)
plotshape(momentum, style=shape.diamond,location=location.abovebar, color=color.new(color.white, 50), size = size.tiny)
plotshape(lower_lows or close_bl_20, style=shape.flag,location=location.belowbar, color=lower_lows and close_bl_20 ? color.red : color.new(color.red, 50), size = size.tiny)

Overview

Imbalance Strategy builds smoothed moving averages scaled for daily or weekly charts, 52-week high and low, and an IBD-style relative strength measure against a reference symbol. Settings cover a backtest window by start year, start month and length, an impulse percentile, a maximum channel size and a tolerance percent. Orders size to the full equity by default with a small per-share commission. Only the first part of the code is visible, so exact entry and exit rules are not described here.

Details

Published by

creatidy on GitHub

Code credit

Marlborough76, as written in the script's header

Type

Strategy, Pine Script v5

Draws

On the price chart

Category

Trend, Oscillators & momentum

Markets

Stocks

Timeframes

H4 and above

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
From Yearint2019FromYear
From Monthint1FromMonth
Months Aheadint120Months
Impulse Percentileint95percentile
Max Channel Size [%]int8max_channel_size
Tolerance [%]float0.1tolerance
ReferencestringGPW:WIGref_input
Strength Colorcolorcolor.greenup_color
Weakness Colorcolorcolor.reddown_color
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

330 stars

2 EMA/SMA + RSI Strategy [Alorse] combines three configurable moving averages with a short-period Relative Strength Index filter. It plots fast, slow, and trend moving averages on the price chart. Long entries trigger when the fast moving average is above the

Strategy v4 TrendOscillators & momentum
Updated 2 months ago · None stated GitHub repository of 2 EMA/SMA + RSI Strategy [Alorse]

Acrypto - Weighted Strategy

by AlbertoCuadra
318 stars

This strategy plots on the price chart and opens long or short positions when a weighted score from MACD, Stochastic RSI, RSI, Supertrend and a moving-average crossover exceeds a user-set trigger. Each component has its own weight and candle delay. Entries can

Strategy v5 TrendOscillators & momentum
Updated 3 years ago · Custom licence GitHub repository of Acrypto - Weighted Strategy
285 stars

Mean Reversion Strategy is an overlay strategy that identifies pullbacks using a long-term EMA, RSI, and candlestick patterns. It generates long signals when a bullish engulfing candle forms below the EMA while RSI is oversold, and short signals when a bearish

Strategy v4 Mean reversionCandlestick patterns
Updated 3 years ago · None stated GitHub repository of Mean Reversion Strategy
218 stars

This strategy generates trading signals based on a selectable momentum engine, supporting MACD, RSI, Stochastic, or Rate of Change. Entries trigger on signal crosses, zero-line crosses, or threshold crosses, with an optional moving average trend filter. Risk m

Strategy v6 Oscillators & momentumTrend
Updated 3 months ago · None stated GitHub repository of Momentum Strategy Template

255 EMA Strategy

by hasnocool
106 stars

255 EMA Strategy combines an exponential moving average with Average True Range bands and standard MACD crossovers to generate entry signals. Drawn directly on the price chart, it plots the central 255 EMA along with upper and lower volatility envelopes. Trade

Strategy v4 Moving averagesOscillators & momentum
Updated 2 years ago · GPL-3.0 GitHub repository of 255 EMA Strategy

More strategys

Trade Your Charts With a Regulated Broker

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

Compare brokers