Imbalance Strategy.pine
Copy
// 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)
Show all 311 lines