ABRÍ UNA CUENTA CON MI ENLACE PARA ACCEDER A INFORMES DIARIOS EN FORMATO DE AUDIO DE WHATSAPP Y PLANILLAS DE CÁLCULO. HACE CLIC EN EL BROKER QUE MAS TE GUSTE.
🎯 Unite a mi canal de YouTube por solo $4mil Pesos
Accedé a contenido exclusivo y recibí mi informe financiero completo, donde analizo oportunidades reales del mercado con una mirada clara.
Ideal para inversores que quieren información directa, útil y sin vueltas.
📥 ¡HACE CLIC EN EL LOGO y Sumate hoy y empezá a tomar decisiones con fundamento!
//@version=5
indicator("Luna Indicator Signal", overlay=true, max_bars_back = 1)
// ====== Activación del Indicador ======
is_enabled1 = input(true, "Enable Indicator 1", group="Main settings")
is_enabled2 = input(false, "Enable Indicator 2", group="Main settings")
// ====== Q-Trend - Configuración 1 ======
// Inputs Config 1
src1 = input(close, "Source", group="Config 1")
p1 = input.int(200, "Trend period", group="Config 1", tooltip="Changes STRONG signals' sensitivity.", minval=1)
atr_p1 = input.int(14, "ATR Period", group="Config 1", minval=1)
mult1 = input.float(1.0, "ATR Multiplier", step=0.1, group="Config 1", tooltip="Changes sensitivity: higher period = higher sensitivity.")
mode1 = input.string("Type A", "Signal mode", options=["Type A", "Type B"], group="Config 1")
use_ema_smoother1 = input.string("No", "Smooth source with EMA?", options=["Yes", "No"], group="Config 1")
src_ema_period1 = input(3, "EMA Smoother period", group="Config 1")
color_bars1 = input(true, "Color bars?", group="Config 1")
show_tl1 = input(true, "Show trend line?", group="Config 1")
signals_view1 = input.string("All", "Signals to show", options=["All", "Buy/Sell", "Strong", "None"], group="Config 1")
signals_shape1 = input.string("Labels", "Signal's shape", options=["Labels", "Arrows"], group="Config 1")
buy_col1 = input(color.green, "Buy colour", group="Config 1", inline="BS1")
sell_col1 = input(color.red, "Sell colour", group="Config 1", inline="BS1")
// Calculations Config 1
src1 := use_ema_smoother1 == "Yes" ? ta.ema(src1, src_ema_period1) : src1
h1 = ta.highest(src1, p1)
l1 = ta.lowest(src1, p1)
d1 = h1 - l1
ls1 = ""
m1 = (h1 + l1) / 2
m1 := bar_index > p1 ? m1[1] : m1
atr1 = ta.atr(atr_p1)[1]
epsilon1 = mult1 * atr1
change_up1 = (mode1 == "Type B" ? ta.cross(src1, m1 + epsilon1) : ta.crossover(src1, m1 + epsilon1)) or src1 > m1 + epsilon1
change_down1 = (mode1 == "Type B" ? ta.cross(src1, m1 - epsilon1) : ta.crossunder(src1, m1 - epsilon1)) or src1 < m1 - epsilon1
sb1 = open < l1 + d1 / 8 and open >= l1
ss1 = open > h1 - d1 / 8 and open <= h1
strong_buy1 = sb1 or sb1[1] or sb1[2] or sb1[3] or sb1[4]
strong_sell1 = ss1 or ss1[1] or ss1[2] or ss1[3] or ss1[4]
m1 := (change_up1 or change_down1) and m1 != m1[1] ? m1 : change_up1 ? m1 + epsilon1 : change_down1 ? m1 - epsilon1 : nz(m1[1], m1)
ls1 := change_up1 ? "B" : change_down1 ? "S" : ls1[1]
colour1 = ls1 == "B" ? buy_col1 : sell_col1
buy_shape1 = signals_shape1 == "Labels" ? shape.labelup : shape.triangleup
sell_shape1 = signals_shape1 == "Labels" ? shape.labeldown : shape.triangledown
// Plottings Config 1
plot(is_enabled1 and show_tl1 ? m1 : na, "Trend Line 1", colour1, 3)
// Signals Config 1
plotshape(is_enabled1 and signals_shape1 == "Labels" and (signals_view1 == "All" or signals_view1 == "Buy/Sell") and change_up1 and ls1[1] != "B" and not strong_buy1, "Buy signal", color=colour1, style=buy_shape1, location=location.belowbar, size=size.normal, text="BUY", textcolor=color.white)
plotshape(is_enabled1 and signals_shape1 == "Labels" and (signals_view1 == "All" or signals_view1 == "Buy/Sell") and change_down1 and ls1[1] != "S" and not strong_sell1, "Sell signal", color=colour1, style=sell_shape1, size=size.normal, text="SELL", textcolor=color.white)
plotshape(is_enabled1 and signals_shape1 == "Labels" and (signals_view1 == "All" or signals_view1 == "Strong") and change_up1 and ls1[1] != "B" and strong_buy1, "Strong Buy signal", color=colour1, style=buy_shape1, location=location.belowbar, size=size.normal, text="RAKATE", textcolor=color.white)
plotshape(is_enabled1 and signals_shape1 == "Labels" and (signals_view1 == "All" or signals_view1 == "Strong") and change_down1 and ls1[1] != "S" and strong_sell1, "Strong Sell signal", color=colour1, style=sell_shape1, size=size.normal, text="A la CHOTA", textcolor=color.white)
// ====== Q-Trend - Configuración 2 ======
// Inputs Config 2
src2 = input(close, "Source", group="Config 2")
p2 = input.int(100, "Trend period", group="Config 2", tooltip="Changes STRONG signals' sensitivity.", minval=1)
atr_p2 = input.int(10, "ATR Period", group="Config 2", minval=1)
mult2 = input.float(1.5, "ATR Multiplier", step=0.1, group="Config 2", tooltip="Changes sensitivity: higher period = higher sensitivity.")
mode2 = input.string("Type A", "Signal mode", options=["Type A", "Type B"], group="Config 2")
use_ema_smoother2 = input.string("No", "Smooth source with EMA?", options=["Yes", "No"], group="Config 2")
src_ema_period2 = input(3, "EMA Smoother period", group="Config 2")
color_bars2 = input(true, "Color bars?", group="Config 2")
show_tl2 = input(true, "Show trend line?", group="Config 2")
signals_view2 = input.string("All", "Signals to show", options=["All", "Buy/Sell", "Strong", "None"], group="Config 2")
signals_shape2 = input.string("Labels", "Signal's shape", options=["Labels", "Arrows"], group="Config 2")
buy_col2 = input(color.blue, "Buy colour", group="Config 2", inline="BS2")
sell_col2 = input(color.orange, "Sell colour", group="Config 2", inline="BS2")
// Calculations Config 2
src2 := use_ema_smoother2 == "Yes" ? ta.ema(src2, src_ema_period2) : src2
h2 = ta.highest(src2, p2)
l2 = ta.lowest(src2, p2)
d2 = h2 - l2
ls2 = ""
m2 = (h2 + l2) / 2
m2 := bar_index > p2 ? m2[1] : m2
atr2 = ta.atr(atr_p2)[1]
epsilon2 = mult2 * atr2
change_up2 = (mode2 == "Type B" ? ta.cross(src2, m2 + epsilon2) : ta.crossover(src2, m2 + epsilon2)) or src2 > m2 + epsilon2
change_down2 = (mode2 == "Type B" ? ta.cross(src2, m2 - epsilon2) : ta.crossunder(src2, m2 - epsilon2)) or src2 < m2 - epsilon2
sb2 = open < l2 + d2 / 8 and open >= l2
ss2 = open > h2 - d2 / 8 and open <= h2
strong_buy2 = sb2 or sb2[1] or sb2[2] or sb2[3] or sb2[4]
strong_sell2 = ss2 or ss2[1] or ss2[2] or ss2[3] or ss2[4]
m2 := (change_up2 or change_down2) and m2 != m2[1] ? m2 : change_up2 ? m2 + epsilon2 : change_down2 ? m2 - epsilon2 : nz(m2[1], m2)
ls2 := change_up2 ? "B" : change_down2 ? "S" : ls2[1]
colour2 = ls2 == "B" ? buy_col2 : sell_col2
buy_shape2 = signals_shape2 == "Labels" ? shape.labelup : shape.triangleup
sell_shape2 = signals_shape2 == "Labels" ? shape.labeldown : shape.triangledown
// Plottings Config 2
plot(is_enabled2 and show_tl2 ? m2 : na, "Trend Line 2", colour2, 3)
// Signals Config 2
plotshape(is_enabled2 and signals_shape2 == "Labels" and (signals_view2 == "All" or signals_view2 == "Buy/Sell") and change_up2 and ls2[1] != "B" and not strong_buy2, "Buy signal", color=colour2, style=buy_shape2, location=location.belowbar, size=size.normal, text="BUY", textcolor=color.white)
plotshape(is_enabled2 and signals_shape2 == "Labels" and (signals_view2 == "All" or signals_view2 == "Buy/Sell") and change_down2 and ls2[1] != "S" and not strong_sell2, "Sell signal", color=colour2, style=sell_shape2, size=size.normal, text="SELL", textcolor=color.white)
plotshape(is_enabled2 and signals_shape2 == "Labels" and (signals_view2 == "All" or signals_view2 == "Strong") and change_up2 and ls2[1] != "B" and strong_buy2, "Strong Buy signal", color=colour2, style=buy_shape2, location=location.belowbar, size=size.normal, text="RAKATE", textcolor=color.white)
plotshape(is_enabled2 and signals_shape2 == "Labels" and (signals_view2 == "All" or signals_view2 == "Strong") and change_down2 and ls2[1] != "S" and strong_sell2, "Strong Sell signal", color=colour2, style=sell_shape2, size=size.normal, text="A la CHOTA", textcolor=color.white)
// ====== Q-Trend ======
// Inputs
src = input(close, "Source", group = "Main settings")
p = input.int(200, "Trend period", group = "Main settings", tooltip = "Changes STRONG signals' sensitivity.", minval = 1)
atr_p = input.int(14, "ATR Period", group = "Main settings", minval = 1)
mult = input.float(1.0, "ATR Multiplier", step = 0.1, group = "Main settings", tooltip = "Changes sensitivity: higher period = higher sensitivity.")
mode = input.string("Type A", "Signal mode", options = ["Type A", "Type B"], group = "Mode")
use_ema_smoother = input.string("No", "Smooth source with EMA?", options = ["Yes", "No"], group = "Source")
src_ema_period = input(3, "EMA Smoother period", group = "Source")
color_bars = input(true, "Color bars?", group = "Addons")
show_tl = input(true, "Show trend line?", group = "Addons")
signals_view = input.string("All", "Signals to show", options = ["All", "Buy/Sell", "Strong", "None"], group = "Signal's Addon")
signals_shape = input.string("Labels", "Signal's shape", options = ["Labels", "Arrows"], group = "Signal's Addon")
buy_col = input(color.green, "Buy colour", group = "Signal's Addon", inline = "BS")
sell_col = input(color.red, "Sell colour", group = "Signal's Addon", inline = "BS")
// Calculations
src := use_ema_smoother == "Yes" ? ta.ema(src, src_ema_period) : src
h = ta.highest(src, p)
l = ta.lowest(src, p)
d = h - l
ls = ""
m = (h + l) / 2
m := bar_index > p ? m[1] : m
atr = ta.atr(atr_p)[1]
epsilon = mult * atr
change_up = (mode == "Type B" ? ta.cross(src, m + epsilon) : ta.crossover(src, m + epsilon)) or src > m + epsilon
change_down = (mode == "Type B" ? ta.cross(src, m - epsilon) : ta.crossunder(src, m - epsilon)) or src < m - epsilon
sb = open < l + d / 8 and open >= l
ss = open > h - d / 8 and open <= h
strong_buy = sb or sb[1] or sb[2] or sb[3] or sb[4]
strong_sell = ss or ss[1] or ss[2] or ss[3] or ss[4]
m := (change_up or change_down) and m != m[1] ? m : change_up ? m + epsilon : change_down ? m - epsilon : nz(m[1], m)
ls := change_up ? "B" : change_down ? "S" : ls[1]
colour = ls == "B" ? buy_col : sell_col
buy_shape = signals_shape == "Labels" ? shape.labelup : shape.triangleup
sell_shape = signals_shape == "Labels" ? shape.labeldown : shape.triangledown
// Plottings
plot(show_tl ? m : na, "Trend Line", colour, 3)
// Signals
plotshape(signals_shape == "Labels" and (signals_view == "All" or signals_view == "Buy/Sell") and change_up and ls[1] != "B" and not strong_buy, "Buy signal", color = colour, style = buy_shape , location = location.belowbar, size = size.normal, text = "BUY", textcolor = color.white)
plotshape(signals_shape == "Labels" and (signals_view == "All" or signals_view == "Buy/Sell") and change_down and ls[1] != "S" and not strong_sell, "Sell signal", color = colour, style = sell_shape, size = size.normal, text = "SELL", textcolor = color.white)
plotshape(signals_shape == "Labels" and (signals_view == "All" or signals_view == "Strong") and change_up and ls[1] != "B" and strong_buy, "Strong Buy signal", color = colour, style = buy_shape , location = location.belowbar, size = size.normal, text = "RAKATE", textcolor = color.white)
plotshape(signals_shape == "Labels" and (signals_view == "All" or signals_view == "Strong") and change_down and ls[1] != "S" and strong_sell, "Strong Sell signal", color = colour, style = sell_shape, size = size.normal, text = "A la CHOTA", textcolor = color.white)
// ====== Moving Averages ======
// Inputs para las EMAs
EMA_1 = input.int(10, minval=1, maxval=500, title="1° EMA Period")
EMA_2 = input.int(20, minval=1, maxval=500, title="2° EMA Period")
EMA_3 = input.int(55, minval=1, maxval=500, title="3° EMA Period")
EMA_4 = input.int(100, minval=1, maxval=500, title="4° EMA Period")
// Cálculo de las EMAs
EMA1 = ta.ema(close, EMA_1)
EMA2 = ta.ema(close, EMA_2)
EMA3 = ta.ema(close, EMA_3)
EMA4 = ta.ema(close, EMA_4)
// Graficar las EMAs
plot(EMA1, color=color.rgb(245, 50, 50), linewidth=1, title="1° Exponential Moving Average")
plot(EMA2, color=color.new(#11fbff, 0), linewidth=1, title="2° Exponential Moving Average")
plot(EMA3, color=color.new(#49ff32, 0), linewidth=1, title="3° Exponential Moving Average")
plot(EMA4, color=color.new(#fffe46, 0), linewidth=1, title="4° Exponential Moving Average")
// Inputs para las SMAs
SMA_1 = input.int(50, minval=1, maxval=500, title="1° SMA Period")
SMA_2 = input.int(200, minval=1, maxval=500, title="2° SMA Period")
// Cálculo de las SMAs
SMA1 = ta.sma(close, SMA_1)
SMA2 = ta.sma(close, SMA_2)
// Graficar las SMAs
plot(SMA1, color=color.new(#11fbff, 0), linewidth=1, title="1° Simple Moving Average")
plot(SMA2, color=color.new(#fc0017, 0), linewidth=1, title="2° Simple Moving Average")
// Inputs para las WMAs
WMA_1 = input.int(50, minval=1, maxval=500, title="1° WMA Period")
WMA_2 = input.int(200, minval=1, maxval=500, title="2° WMA Period")
// Cálculo de las WMAs
WMA1 = ta.wma(close, WMA_1)
WMA2 = ta.wma(close, WMA_2)
// Graficar las WMAs
plot(WMA1, color=color.rgb(47, 50, 236), linewidth=1, title="1° Weighted Moving Average")
plot(WMA2, color=color.new(#fc0017, 0), linewidth=1, title="2° Weighted Moving Average")
// Graficar el precio de cierre
plot(close, color=color.new(#808080, 0), linewidth=1, title="Closing Price")
import algotraderdev/contrast/1
//#region Inputs & Constants
const string VOLUME_PROFILE = 'Volume Profile'
const string MARKET_PROFILE = 'Market Profile / TPO'
string MODE = input.string(
VOLUME_PROFILE,
'Mode',
options = [VOLUME_PROFILE, MARKET_PROFILE],
tooltip = 'This setting determines the mode in which the indicator operates.\n\n' +
'Volume Profile (Default Mode): In this mode, the volume of each bar is taken into consideration to construct ' +
'the profile.\n\n' +
'Market Profile (a.k.a. Time Price Opportunity): In this mode, volume data is disregarded. This indicator ' +
'analyzes the price distribution solely over time.\n\n' +
'NOTE: in case the ticker does not have any volume data, this indicator uses the `Market Profile` mode.')
const string RANGE_GROUP = 'TIME RANGE'
const string VISIBLE_RANGE = 'Visible Range'
const string ANCHORED_RANGE = 'Anchored Range'
const string ALL_RANGE = 'All Range'
string RANGE_MODE = input.string(
VISIBLE_RANGE,
'Range Mode',
options = [VISIBLE_RANGE, ANCHORED_RANGE, ALL_RANGE],
tooltip = 'This setting determines the start time of the volume profile calculation.\n\n' +
'Visible Range (Default Mode): In this mode, the volume profile calculation begins at the time of the ' +
'left-most bar displayed in the current viewport. As the user scrolls through the viewport, the volume profile ' +
'updates automatically.\n\n' +
'Anchored Range: This mode allows the user to set the start time either by using the "Anchor Time" input box ' +
'below or by dragging the anchor line on the chart.\n\n' +
'All Range: In this mode, the volume profile calculation is based on all the historical bars available in the ' +
'chart.',
group = RANGE_GROUP)
int ANCHORED_TIME = input.time(
timestamp('2023-01-01T12:00:00'),
'Anchor Time',
tooltip = 'The start time of the volume profile calculation. This setting is only used when the "Range Mode" above ' +
'is set to "Anchored Range".',
group = RANGE_GROUP)
const string GRANULARITY_GROUP = 'GRANULARITY'
int NUM_ROWS = input.int(
300,
'Number of Rows',
minval = 100,
maxval = 2500,
step = 100,
tooltip = 'The number of rows to display in the volume profile histogram (Max 2500)',
group = GRANULARITY_GROUP,
display = display.none)
int MAX_LTF_BARS = input.int(
5000,
'Max Lower Timeframe Bars',
minval = 1000,
step = 1000,
tooltip = 'The max number of lower timeframe bars to use for the volume profile calculation.\n\n' +
'NOTE: The higher the number, the more time and memory the calculation needs. If you encounter a time limit ' +
'or memory limit error, please try lowering the number here.',
group = GRANULARITY_GROUP)
bool USE_SECOND_BASED_TIMEFRAMES = input.bool(
false,
'Use Second-Based Timeframes',
tooltip = 'Whether to use second-based timeframes (e.g. 1 second, 5 seconds) when the chart\'s current timeframe ' +
'is low (e.g. 5 minutes).\n\n' +
'NOTE: second-based timeframes are only supported if you\'re subscribed to the TradingView Premium Plan and ' +
'above.',
group = GRANULARITY_GROUP)
const string APPEARANCE_GROUP = 'APPEARANCE'
int HORIZONTAL_OFFSET = input.int(
20,
'Horizontal Offset',
step = 5,
tooltip = 'The distance, measured in the number of bars, between the last bar in the chart and the left of the ' +
'volume profile histogram.',
group = APPEARANCE_GROUP,
display = display.none)
int MAX_WIDTH = input.int(
80,
'Max Width',
maxval = 500,
minval = 10,
step = 10,
tooltip = 'The maximum width, measured in number of bars, for the volume profile histogram.',
group = APPEARANCE_GROUP,
display = display.none)
int HEIGHT_PERCENTAGE_PER_ROW = input.int(
40,
'Height % per Row',
minval = 1,
maxval = 100,
tooltip = 'The height of each volume profile histogram row, measured as the percentage of the price range ' +
'of each price bucket.',
group = APPEARANCE_GROUP,
display = display.none)
bool SHOW_DELTA = input.bool(
false,
'Show Volume Delta',
tooltip = 'Whether to show Volume Delta (the net difference between buying and selling volume).',
group = APPEARANCE_GROUP,
display = display.none)
const string COLOR_GROUP = 'COLOR'
color COLOR = input.color(#5d606b77, 'Default', group = COLOR_GROUP)
color BUY_COLOR = input.color(#00bcd480, 'Buy Volume', group = COLOR_GROUP)
color SELL_COLOR = input.color(#e91e6380, 'Sell Volume', group = COLOR_GROUP)
color POC_COLOR = input.color(color.yellow, 'POC (Point of Control)', group = COLOR_GROUP)
color VAH_COLOR = input.color(color.blue, 'VAH (Value Area High)', group = COLOR_GROUP)
color VAL_COLOR = input.color(color.blue, 'VAL (Value Area Low)', group = COLOR_GROUP)
const string KEY_PRICES_GROUP = 'POC & Value Area'
int VALUE_AREA_PERCENT = input.int(
70,
'Value Area Percent',
minval = 1,
maxval = 100,
tooltip = 'The percentage of the total trading volume that\'s considered as the value area.',
group = KEY_PRICES_GROUP,
display = display.none)
bool DISPLAY_VA = input.bool(
true,
'Display VAH/VAL',
group = KEY_PRICES_GROUP,
display = display.none)
bool DISPLAY_POC = input.bool(
true,
'Display POC',
group = KEY_PRICES_GROUP,
display = display.none)
bool EXTEND_LEFT = input.bool(
true,
'Extend Key Price Lines to the Left',
tooltip = 'Whether to extend the key price lines (POC, VAH, VAL) to the left of the chart.',
group = KEY_PRICES_GROUP)
int BASE_OFFSET = HORIZONTAL_OFFSET + MAX_WIDTH
int LABEL_OFFSET = BASE_OFFSET + 2
int START_TIME = switch RANGE_MODE
VISIBLE_RANGE => chart.left_visible_bar_time
ANCHORED_RANGE => ANCHORED_TIME
ALL_RANGE => 0
// If second-based timeframe is enabled, then set the minimal timeframe to 1 second.
// Otherwise, set it to 60 seconds (1 minute).
int MIN_TIMEFRAME_IN_SECONDS = USE_SECOND_BASED_TIMEFRAMES ? 1 : 60
//#endregion
//#region Utils
// @function Identifies the index of the max value in the array.
// @param a The array to find max index for.
// @returns The index of the max value in the array.
maxIndex(float[] a) =>
if a.size() == 0
na
float max = a.first()
int maxIndex = 0
for [i, v] in a
if v > max
max := v
maxIndex := i
maxIndex
//#endregion
//#region Candle
const int DIRECTION_NONE = 0
const int DIRECTION_BUY = 1
const int DIRECTION_SELL = -1
// @type The candle object holds the required information for each candle in the chart.
// @field high The `high` of the candle.
// @field low The `low` of the candle.
// @field volume The `volume` of the candle.
// @field direction Any of DIRECTION_NONE, DIRECTION_BUY, or DIRECTION_BUY.
type Candle
float high
float low
float volume = 1
int direction
//#endregion
//#region Marker
// @type The Marker type is for highlighting a specific price point in the volume profile.
// @field poly The polyline for highlighting the price point. Note that we're using a `polyline` instead of `line`
// here since there seems to be bug in TradingView that prevents a `line` to be overlaid on top of a `polyline`.
// @field extendedLine A line at the price level that extends to the left of the screen.
// @field label Label for this marker.
type Marker
polyline poly
line extendedLine
label label
// @function Sets the properties of the marker.
// @param name The name of the marker. This is also displayed as part of the label text.
// @param left The bar index of the left x coordinate of the volume profile row.
// @param right The bar index of the right x coordinate of the volume profile row.
// @param price The price / y-coordinate of the marker.
// @param bg The background color of the marker.
// @param height The height of the volume profile row.
method set(Marker this, string name, int left, int right, float price, color bg, float height) =>
// Create a polyline to highlight the row.
if not na(this.poly)
this.poly.delete()
float bottom = price - height / 2
float top = bottom + height
chart.point[] points = array.from(
chart.point.from_index(left, bottom),
chart.point.from_index(left, top),
chart.point.from_index(right, top),
chart.point.from_index(right, bottom))
this.poly := polyline.new(points, line_color = bg, fill_color = bg)
// Create a dotted line and extend it to the left.
if not na(this.extendedLine)
this.extendedLine.delete()
if EXTEND_LEFT
this.extendedLine := line.new(
x1 = left,
y1 = price,
x2 = right,
y2 = price,
extend = extend.left,
style = line.style_dotted,
color = bg)
// Create a label to the right of the row.
if na(this.label)
this.label.delete()
string txt = str.format('{0}: {1}', name, math.round_to_mintick(price))
this.label := label.new(
x = bar_index + LABEL_OFFSET,
y = price,
text = txt,
style = label.style_label_left,
size = size.small,
color = bg,
textcolor = bg.contrast(0.6))
this
//#endregion
//#region VP
// @type The VP (Volume Profile) type is responsible for calculating and visualizing the distribution of
// volumes at various price points.
// @field candles The stored candles based on which the distribution will be calculated.
// @field minPrice The minimum price for all the stored candles.
// @field maxPrice The maximum price for all the stored candles.
// @field step The price difference between adjacent price buckets.
// @field poly The polyline that's used to draw the histogram of the volume profile.
// @field buyPoly The polyline that's used to draw the histogram of the buying volume.
// @field sellPoly The polyline that's used to draw the histogram of the selling volume.
// @field markers Markers that highlight POC, VAH, and VAL.
type VP
Candle[] candles
float minPrice
float maxPrice
float step
polyline poly
polyline buyPoly
polyline sellPoly
map<string, Marker> markers
// @function Initializes a new VP instance.
// @returns The initialized VP instance.
method init(VP this) =>
this.candles := array.new<Candle>()
this.markers := map.new<string, Marker>()
this
// @function Gets the bucket index for the given price.
// @param price The price to get index for.
// @returns The bucket index for the price.
method getBucketIndex(VP this, float price) =>
math.min(math.floor((price - this.minPrice) / this.step), NUM_ROWS - 1)
// @function Gets the bucketed price for the given index
// @param index The bucket index.
// @returns The average price for the bucket.
method getBucketedPrice(VP this, int index) =>
(index + 0.5) * this.step + this.minPrice
// @function Highlights a specific price / volume bucket.
// @param name The name of the label.
// @param index The index of the bucket to highlight.
// @param left The x coordinate of the left endpoint of the volume profile.
// @param bg The background highlight color.
// @param height The height of each row.
method mark(VP this, string name, float price, int left, color bg, float height) =>
int right = bar_index + BASE_OFFSET
Marker marker = this.markers.get(name)
if na(marker)
marker := Marker.new().set(name = name, left = left, right = right, price = price, bg = bg, height = height)
// @function Stores a candle for it to be analyzed later.
// Note that this method is expected to be called on every tick. The actual calculation of VP is deferred to only when
// the last bar in the chart is reached, as an optimization.
// @param candle The candle to store.
method store(VP this, Candle candle) =>
this.candles.push(candle)
this.minPrice := na(this.minPrice) ? candle.low : math.min(this.minPrice, candle.low)
this.maxPrice := na(this.maxPrice) ? candle.high : math.max(this.maxPrice, candle.high)
this.step := (this.maxPrice - this.minPrice) / NUM_ROWS
// @function Draws a histogram for the given coordinates.
// @param xs The x-coordinates for the left of the histogram rows.
// @param baseX The x-coordinate for the base of the histogram.
// @param step The step / delta between adjacent price points.
// @param height The height for each row.
// @param color The color for the histogram.
// @returns The drawn polyline.
method drawHistogram(VP this, int[] xs, int baseX, float step, float height, color color) =>
// Construct the polyline points.
chart.point[] points = array.new<chart.point>()
float gap = (step - height) / 2
for [i, x] in xs
float lo = i * step + gap + this.minPrice
float hi = lo + height
points.push(chart.point.from_index(index = baseX, price = lo))
points.push(chart.point.from_index(index = x, price = lo))
points.push(chart.point.from_index(index = x, price = hi))
points.push(chart.point.from_index(index = baseX, price = hi))
polyline.new(points, closed = true, line_color = color, fill_color = color)
// @function Calculates the distribution and visualizes it on the chart.
method update(VP this) =>
// Calculate the step size for each bucket.
float step = (this.maxPrice - this.minPrice) / NUM_ROWS
// Loop through the candles and populate the distribution array.
float[] dist = array.new_float(NUM_ROWS, 0)
float[] deltaDist = array.new_float(NUM_ROWS, 0)
for c in this.candles
// Calculate the start and end index of the buckets to fill the volume.
int start = this.getBucketIndex(c.low)
int end = this.getBucketIndex(c.high)
int buckets = end - start + 1
float vol = c.volume / buckets
for i = start to end
dist.set(i, dist.get(i) + vol)
deltaDist.set(i, deltaDist.get(i) + vol * c.direction)
float maxVol = dist.max()
// Calculate the x coordinate for each row.
int baseX = bar_index + BASE_OFFSET
int[] xs = array.new_int()
for vol in dist
int width = math.round(vol / maxVol * MAX_WIDTH)
int x = baseX - width
xs.push(x)
float height = HEIGHT_PERCENTAGE_PER_ROW / 100 * step
// Draw the histogram.
if not na(this.poly)
this.poly.delete()
this.poly := this.drawHistogram(xs, baseX, step, height, COLOR)
// Draw the delta histograms.
if SHOW_DELTA
int[] buyXs = array.new_int()
int[] sellXs = array.new_int()
for vol in deltaDist
int width = math.round(math.abs(vol) / maxVol * MAX_WIDTH)
int x = baseX - width
buyXs.push(vol > 0 ? x : baseX)
sellXs.push(vol < 0 ? x : baseX)
if not na(this.buyPoly)
this.buyPoly.delete()
this.buyPoly := this.drawHistogram(buyXs, baseX, step, height, BUY_COLOR)
if not na(this.sellPoly)
this.sellPoly.delete()
this.sellPoly := this.drawHistogram(sellXs, baseX, step, height, SELL_COLOR)
// Calculate the cumulative distribution.
float[] cumdist = dist.copy()
for i = 1 to cumdist.size() - 1
cumdist.set(i, cumdist.get(i - 1) + cumdist.get(i))
float totalVolume = cumdist.last()
// Highlight VAH and VAL.
if DISPLAY_VA
float valPercentile = (100 - VALUE_AREA_PERCENT) / 100 / 2
float vahPercentile = 1 - valPercentile
int valIndex = cumdist.binary_search_leftmost(totalVolume * valPercentile)
this.mark(
name = 'VAL',
price = this.getBucketedPrice(valIndex),
left = xs.get(valIndex),
bg = VAL_COLOR,
height = height)
int vahIndex = cumdist.binary_search_leftmost(totalVolume * vahPercentile)
this.mark(
name = 'VAH',
price = this.getBucketedPrice(vahIndex),
left = xs.get(vahIndex),
bg = VAH_COLOR,
height = height)
// Highlight POC.
if DISPLAY_POC
int pocIndex = maxIndex(dist)
this.mark(
name = 'POC',
price = this.getBucketedPrice(pocIndex),
left = xs.get(pocIndex),
bg = POC_COLOR,
height = height)
// Create another vertical polyline to mask the rightmost pixel of the volume profile, so that the minimum
// width for each price bucket can be 0 rather than 1.
chart.point maxPoint = chart.point.from_index(index = baseX, price = this.maxPrice)
chart.point minPoint = chart.point.from_index(index = baseX, price = this.minPrice)
polyline.new(array.from(maxPoint, minPoint), line_color = chart.bg_color)
//#endregion
//#region main
var VP vp = VP.new().init()
// @function Returns a lower timeframe string given the multiplier.
// @param multiplier The multiplier to use.
// @returns The timeframe string.
ltf(simple int multiplier) =>
timeframe.from_seconds(math.max(MIN_TIMEFRAME_IN_SECONDS, math.round(timeframe.in_seconds() / multiplier)))
simple string ltf1 = timeframe.period
simple string ltf2 = ltf(2)
simple string ltf4 = ltf(4)
simple string ltf8 = ltf(8)
simple string ltf16 = ltf(16)
// Checks a list of lower timeframes to see which one should be used for the volume profile calculation.
// NOTE: unfortunately we cannot use a for-loop to go through an array of timeframe strings since the timeframe
// parameter in `request.security_lower_tf` has to be an `simple string` whereas the type for items in array is
// always `series`, even if the array itself is marked as `const` or `simple`.
bool canProcess = time >= START_TIME and (last_bar_index - bar_index) < MAX_LTF_BARS
bool cp1 = canProcess
bool cp2 = request.security(syminfo.tickerid, ltf2, canProcess)
bool cp4 = request.security(syminfo.tickerid, ltf4, canProcess)
bool cp8 = request.security(syminfo.tickerid, ltf8, canProcess)
bool cp16 = request.security(syminfo.tickerid, ltf16, canProcess)
// A list of candidate candles in various timeframes.
int dir = switch
close > open => DIRECTION_BUY
close < open => DIRECTION_SELL
=> DIRECTION_NONE
float vol = MODE == VOLUME_PROFILE ? nz(volume, 100) : 100
Candle candle = Candle.new(high, low, vol, dir)
Candle[] c1 = array.from(candle)
Candle[] c2 = request.security_lower_tf(syminfo.tickerid, ltf2, candle, ignore_invalid_timeframe = true)
Candle[] c4 = request.security_lower_tf(syminfo.tickerid, ltf4, candle, ignore_invalid_timeframe = true)
Candle[] c8 = request.security_lower_tf(syminfo.tickerid, ltf8, candle, ignore_invalid_timeframe = true)
Candle[] c16 = request.security_lower_tf(syminfo.tickerid, ltf16, candle, ignore_invalid_timeframe = true)
var string ltf = na
if na(ltf)
ltf := switch
cp16 => ltf16
cp8 => ltf8
cp4 => ltf4
cp2 => ltf2
cp1 => ltf1
Candle[] cs = switch ltf
ltf1 => c1
ltf2 => c2
ltf4 => c4
ltf8 => c8
ltf16 => c16
if not na(cs)
for c in cs
vp.store(c)
if barstate.islast
vp.update()
//#endregion
//@version=4
study(title="Lovo Indicator", shorttitle="Lovo Indicator", overlay=false)
// KONCORDE
showkoncorde = true
deltaKon = -100 // Ajuste de desfase Koncorde a -100
calc_mfi(length) => rsi(sum(volume * (change(hlc3) <= 0 ? 0 : hlc3), length), sum(volume * (change(hlc3) >= 0 ? 0 : hlc3), length))
tprice = ohlc4
lengthEMA = 255
m = 15
pvim = ema(pvi, m)
pvimax = highest(pvim, 90)
pvimin = lowest(pvim, 90)
oscp = (pvi - pvim) * 100 / (pvimax - pvimin)
nvim = ema(nvi, m)
nvimax = highest(nvim, 90)
nvimin = lowest(nvim, 90)
azul = (nvi - nvim) * 100 / (nvimax - nvimin)
xmf = calc_mfi(14)
mult = 2.0
basis = sma(tprice, 25)
dev = mult * stdev(tprice, 25)
upper = basis + dev
lower = basis - dev
OB1 = (upper + lower) / 2.0
OB2 = upper - lower
BollOsc = ((tprice - OB1) / OB2) * 100
xrsi = rsi(tprice, 14)
calc_stoch(src, length, smoothFastD) => sma(100 * (src - lowest(low, length)) / (highest(high, length) - lowest(low, length)), smoothFastD)
stoc = calc_stoch(tprice, 21, 3)
marron = (xrsi + xmf + BollOsc + (stoc / 3)) / 2
verde = marron + oscp
media = ema(marron, m)
// Configuración inicial de Koncorde
vl = plot(showkoncorde ? na : verde + deltaKon, color=#66FF66, style=plot.style_area, histbase=deltaKon, linewidth=2, title="Koncorde - verde") // Apagado por defecto
ml = plot(showkoncorde ? na : marron + deltaKon, color=#FFCC99, style=plot.style_area, histbase=deltaKon, linewidth=2, title="Koncorde - marrón") // Apagado por defecto
al = plot(iff(showkoncorde, azul + deltaKon, na), color=#00FFFF, style=plot.style_area, histbase=deltaKon, linewidth=2, title="Koncorde - azul")
// RSI
showrsi = true
deltaRSI = 0 // Desfase de RSI/STOCH en 0
multip = 5 // Escalado RSI/STOCH en 5
lengthRSI = 14 // Periodo RSI en 14
RSIMain = (rsi(close, lengthRSI) - 50)
hline(iff(showrsi, 0 + deltaRSI, na), color=color.yellow, linestyle=hline.style_dashed, linewidth=1)
hline(iff(showrsi, -20 * multip + deltaRSI, na), color=color.green, linestyle=hline.style_dashed)
hline(iff(showrsi, 20 * multip + deltaRSI, na), color=color.red, linestyle=hline.style_dashed)
rsiPlot = plot(iff(showrsi, RSIMain * multip + deltaRSI, na), color=color.white, linewidth=1) // Cambiado a blanco y línea fina
// Inputs para el cálculo de la Beta
activoReferente = "SPY"
length = 60
// Función para calcular el retorno logarítmico
return_log(src) =>
log(src / src[1])
// Solicitar datos del instrumento y el benchmark con la temporalidad deseada
instrument = security(syminfo.tickerid, timeframe.period, close)
benchmark = security(activoReferente, timeframe.period, close)
// Cálculos de retorno logarítmico
inst_return = return_log(instrument)
bench_return = return_log(benchmark)
// Cálculos de promedios
avg_inst_return = sma(inst_return, length)
avg_bench_return = sma(bench_return, length)
// Cálculo de la covarianza y beta
sum = 0.0
for idx = 0 to length - 1
inst_variance = inst_return[idx] - avg_inst_return
bench_variance = bench_return[idx] - avg_bench_return
sum := sum + (inst_variance * bench_variance)
covariance = sum / (length - 1)
marketVariance = variance(bench_return, length)
beta = covariance / marketVariance
// Cálculo del Contado con Liquidación (CCL)
t = timeframe.isweekly ? "W" : "D"
p1 = security("(BCBA:AAPL)*20/NASDAQ:AAPL", t, close)
p2 = security("(BCBA:TSLA)*15/NASDAQ:TSLA", t, close)
p3 = security("(BCBA:GGAL)*10/NASDAQ:GGAL", t, close)
p4 = security("(BCBA:MELI)*120/NASDAQ:MELI", t, close)
p5 = security("(BCBA:AMZN)*144/NASDAQ:AMZN", t, close)
ccl = (p1 + p2 + p3 + p4 + p5) / 5
// Crear tabla para mostrar DANIEL y PESALOVO
var table betaCclTable = table.new(position.bottom_right, 2, 2, bgcolor=color.black, border_color=color.white)
if bar_index % 10 == 0 // Actualiza cada 10 barras para no sobrecargar el gráfico
table.cell(betaCclTable, 0, 0, "DANIEL", bgcolor=color.blue, text_color=color.white)
table.cell(betaCclTable, 0, 1, tostring(beta, "#.##"), bgcolor=color.black, text_color=color.white)
table.cell(betaCclTable, 1, 0, "PESALOVO", bgcolor=color.blue, text_color=color.white)
table.cell(betaCclTable, 1, 1, "$" + tostring(ccl, "#.##"), bgcolor=color.black, text_color=color.white)