0% found this document useful (0 votes)
32 views

Indicator TLP

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views

Indicator TLP

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 8

// This source code is subject to the terms of the Mozilla Public License 2.

0 at
https://mozilla.org/MPL/2.0/
// Sửa đổi trên code gốc của © meomeo105
// © meomeo105
//@version=5
indicator('TLP Swing Chart V2', shorttitle='TLP Swing V2', overlay=true,
max_lines_count=500)

//-----Input-------
customTF = input.timeframe(defval="",title = "Show Other TimeFrame")
showTLP = input.bool(false, 'Show TLP', inline = "TLP1")
colorTLP = input.color(color.aqua, '', inline = "TLP1")
showSTLP = input.bool(true, 'Show TLP Swing', inline = "Swing1")
colorSTLP = input.color(color.aqua, '', inline = "Swing1")
showLabel = input.bool(true, 'Show Label TimeFrame')
lineSTLP = input.string(title="",options=["(─)", "(╌)", "(┈)"],defval="(─)", inline
= "Swing1")
lineStyleSTLP = lineSTLP == "(┈)" ? line.style_dotted : lineSTLP == "(╌)" ?
line.style_dashed : line.style_solid

//IOSB
IOSB = "TLPInOutSideBarSetting"
ISB = input(true,group =IOSB, title="showISB")
colorISB = input.color(color.rgb(250, 171, 0), inline = "ISB")
OSB = input(true,group =IOSB, title="showOSB")
colorOSB = input.color(color.rgb(56, 219, 255), inline = "OSB")

ZoneColor = input(defval = color.new(color.orange, 90),group =IOSB, title =


"Background Color")
BorderColor = input(defval = color.new(color.orange, 100),group =IOSB, title =
"Border Color")

/////////////////
var aCZ = array.new_float(0)

float highest = high[1]


float lowest = low[1]

if (array.size(aCZ) > 0)
highest := array.get(aCZ, 0)
lowest := array.get(aCZ, 1)

insideBarCondtion = low >= lowest and low <= highest and high >= lowest and high <=
highest

if ( insideBarCondtion == true )
array.push(aCZ, high[1])
array.push(aCZ, low[1])

if( array.size(aCZ) >= 2 and insideBarCondtion == false )


float maxCZ = array.max(aCZ)
float minCZ = array.min(aCZ)
box.new(bar_index - (array.size(aCZ) / 2) - 1, maxCZ, bar_index - 1, minCZ,
bgcolor = ZoneColor, border_color = BorderColor)
array.clear(aCZ)

//////////////////////////Global//////////////////////////
var arrayLineTemp = array.new_line()
// Funtion
f_resInMinutes() =>
_resInMinutes = timeframe.multiplier * (
timeframe.isseconds ? 1. / 60. :
timeframe.isminutes ? 1. :
timeframe.isdaily ? 1440. :
timeframe.isweekly ? 10080. :
timeframe.ismonthly ? 43800. : na)
// Converts a resolution expressed in minutes into a string usable by "security()"
f_resFromMinutes(_minutes) =>
_minutes < 1 ? str.tostring(math.round(_minutes*60)) + "S" :
_minutes < 60 ? str.tostring(math.round(_minutes)) + "m" :
_minutes < 1440 ? str.tostring(math.round(_minutes/60)) + "H" :
_minutes < 10080 ? str.tostring(math.round(math.min(_minutes / 1440,
7))) + "D" :
_minutes < 43800 ? str.tostring(math.round(math.min(_minutes /
10080, 4))) + "W" :
str.tostring(math.round(math.min(_minutes / 43800, 12))) + "M"
f_tfRes(_res,_exp) =>
request.security(syminfo.tickerid,_res,_exp,lookahead=barmerge.lookahead_on)
var label labelError = label.new(bar_index, high, text = "", color = #00000000,
textcolor = color.white,textalign = text.align_left)
sendError(_mmessage) =>
label.set_xy(labelError, bar_index + 3, close[1])
label.set_text(labelError, _mmessage)

var arrayLineChoCh = array.new_line()


var label labelTF = label.new(time, close, text = "",color = color.new(showSTLP ?
colorSTLP : colorTLP,95), textcolor = showSTLP ? colorSTLP : colorTLP,xloc =
xloc.bar_time, textalign = text.align_left)

//////////////////////////TLP//////////////////////////

var arrayXTLP = array.new_int(5,time)


var arrayYTLP = array.new_float(5,close)
var arrayLineTLP = array.new_line()
int drawLineTLP = 0

_high = high
_low = low
_close = close
_open = open
if(customTF != timeframe.period)
_high := f_tfRes(customTF,high)
_low := f_tfRes(customTF,low)
_close := f_tfRes(customTF,close)
_open := f_tfRes(customTF,open)

highPrev = _high
lowPrev = _low
// drawLineTLP => 2:Tiếp tục 1:Đảo chiều; // Outsidebar 2:Tiếp tục 3:Tiếp tục và
Đảo chiều 4 : Đảo chiều 2 lần
drawLineTLP := 0
if(_high[0] > highPrev[1] and _low[0] > lowPrev[1])
if(array.get(arrayYTLP,0) > array.get(arrayYTLP,1))
if(_high[0] <= high)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _high[0])
drawLineTLP := 2
else
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_high[0])
drawLineTLP := 1

else if(_high[0] < highPrev[1] and _low[0] < lowPrev[1])


if(array.get(arrayYTLP,0) > array.get(arrayYTLP,1))
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_low[0])
drawLineTLP := 1

else
if(_low[0] >= low)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _low[0])
drawLineTLP := 2
else if(_high[0] >= highPrev[1] and _low[0] < lowPrev[1] or _high[0] > highPrev[1]
and _low[0] <= lowPrev[1])
if(array.get(arrayYTLP,0) > array.get(arrayYTLP,1))
if(_high[0] >= array.get(arrayYTLP,0) and array.get(arrayYTLP,1) < _low[0])
if(_high[0] <= high)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _high[0])
drawLineTLP := 2
else if(_high[0] >= array.get(arrayYTLP,0) and array.get(arrayYTLP,1) >
_low[0])
if(_close < _open)
if(_high[0] <= high)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _high[0])
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_low[0])
drawLineTLP := 3

else
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_low[0])
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_high[0])
drawLineTLP := 4

else if(array.get(arrayYTLP,0) < array.get(arrayYTLP,1))


if(_low[0] <= array.get(arrayYTLP,0) and _high[0] < array.get(arrayYTLP,1))
if(_low[0] >= low)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _low[0])
drawLineTLP := 2
else if(_low[0] <= array.get(arrayYTLP,0) and _high[0] >
array.get(arrayYTLP,1))
if(_close > _open)
if(_low[0] >= low)
array.set(arrayXTLP, 0, time)
array.set(arrayYTLP, 0, _low[0])
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_high[0])
drawLineTLP := 3

else
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_high[0])
array.unshift(arrayXTLP,time)
array.unshift(arrayYTLP,_low[0])
drawLineTLP := 4

else if((_high[0] <= highPrev[1] and _low[0] >= lowPrev[1]))


highPrev := highPrev[1]
lowPrev := lowPrev[1]
if(f_resInMinutes() < f_tfRes(customTF,f_resInMinutes()) and drawLineTLP == 0)
if(array.get(arrayYTLP,0) > array.get(arrayYTLP,1))
if(array.get(arrayYTLP,0) <= high)
array.set(arrayXTLP, 0, time)
drawLineTLP := 2
else
if(array.get(arrayYTLP,0) >= low)
array.set(arrayXTLP, 0, time)
drawLineTLP := 2
if((showSTLP or showTLP) and f_resInMinutes() <=
f_tfRes(customTF,f_resInMinutes()))
if(drawLineTLP == 2)
if(array.size(arrayLineTLP) >0)

line.set_xy2(array.get(arrayLineTLP,0),array.get(arrayXTLP,0),array.get(arrayYTLP,0
))
else

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,1),array.get(arrayYTLP,1),a
rray.get(arrayXTLP,0),array.get(arrayYTLP,0), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))
else if(drawLineTLP == 1)

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,1),array.get(arrayYTLP,1),a
rray.get(arrayXTLP,0),array.get(arrayYTLP,0), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))
else if(drawLineTLP == 3)
if(array.size(arrayLineTLP) >0)

line.set_xy2(array.get(arrayLineTLP,0),array.get(arrayXTLP,1),array.get(arrayYTLP,1
))
else

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,2),array.get(arrayYTLP,2),a
rray.get(arrayXTLP,1),array.get(arrayYTLP,1), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,1),array.get(arrayYTLP,1),a
rray.get(arrayXTLP,0),array.get(arrayYTLP,0), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))
else if(drawLineTLP == 4)

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,2),array.get(arrayYTLP,2),a
rray.get(arrayXTLP,1),array.get(arrayYTLP,1), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))

array.unshift(arrayLineTLP,line.new(array.get(arrayXTLP,1),array.get(arrayYTLP,1),a
rray.get(arrayXTLP,0),array.get(arrayYTLP,0), color = colorTLP,xloc =
xloc.bar_time, style = lineStyleSTLP))

//////////////////////////Swing TLP//////////////////////////
var arrayXSTLP = array.new_int(5,time)
var arrayYSTLP = array.new_float(5,close)
var arrayLineSTLP = array.new_line()
int drawLineSTLP = 0
int drawLineSTLP1 = 0

if(showSTLP)
if(math.max(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1)) <
math.min(array.get(arrayYTLP,0),array.get(arrayYTLP,1)) or
math.min(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1)) >
math.max(array.get(arrayYTLP,0),array.get(arrayYTLP,1)))
//Khởi tạo bắt đầu
drawLineSTLP1 := 5
array.set(arrayXSTLP, 0, array.get(arrayXTLP,1))
array.set(arrayYSTLP, 0, array.get(arrayYTLP,1))
array.unshift(arrayXSTLP,array.get(arrayXTLP,0))
array.unshift(arrayYSTLP,array.get(arrayYTLP,0))
// drawLineSTLP kiểm tra điểm 1 => 13:Tiếp tục có sóng hồi // 12|
19(reDraw):Tiếp tục không có sóng hồi // 14:Đảo chiều
if(array.get(arrayXTLP,0) == array.get(arrayXTLP,1))
if(array.get(arrayXSTLP,0) >= array.get(arrayXTLP,2) and
array.get(arrayYSTLP,0) != array.get(arrayYTLP,1) and ((array.get(arrayYTLP,1) >
array.get(arrayYTLP,2) and array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1)) or
(array.get(arrayYTLP,1) < array.get(arrayYTLP,2) and array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1))))
drawLineSTLP1 := 12
array.set(arrayXSTLP, 0, array.get(arrayXTLP,1))
array.set(arrayYSTLP, 0, array.get(arrayYTLP,1))
else if(array.get(arrayXSTLP,0) <= array.get(arrayXTLP,2))
if((array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1) and
array.get(arrayYTLP,1) < array.get(arrayYSTLP,1)) or (array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1) and array.get(arrayYTLP,1) > array.get(arrayYSTLP,1)))
drawLineSTLP1 := 14
array.unshift(arrayXSTLP,array.get(arrayXTLP,1))
array.unshift(arrayYSTLP,array.get(arrayYTLP,1))
else if((array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1) and
array.get(arrayYTLP,1) > array.get(arrayYSTLP,0)) or (array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1) and array.get(arrayYTLP,1) < array.get(arrayYSTLP,0)))
drawLineSTLP1 := 13
_max = math.min(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1))
_min = math.max(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1))
_max_idx = 0
_min_idx = 0
for i = 2 to array.size(arrayXTLP)
if(array.get(arrayXSTLP,0) >= array.get(arrayXTLP,i))
break
if(_min > array.get(arrayYTLP,i))
_min := array.get(arrayYTLP,i)
_min_idx := array.get(arrayXTLP,i)
if(_max < array.get(arrayYTLP,i))
_max := array.get(arrayYTLP,i)
_max_idx := array.get(arrayXTLP,i)
if(array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1))
array.unshift(arrayXSTLP,_min_idx)
array.unshift(arrayYSTLP,_min)
else if(array.get(arrayYSTLP,0) < array.get(arrayYSTLP,1))
array.unshift(arrayXSTLP,_max_idx)
array.unshift(arrayYSTLP,_max)
array.unshift(arrayXSTLP,array.get(arrayXTLP,1))
array.unshift(arrayYSTLP,array.get(arrayYTLP,1))

if(f_resInMinutes() < f_tfRes(customTF,f_resInMinutes()))


if(array.get(arrayYSTLP,0) == array.get(arrayYTLP,1) and
array.get(arrayXSTLP,0) != array.get(arrayXTLP,1))
array.set(arrayXSTLP, 0, array.get(arrayXTLP,1))
drawLineSTLP1 := 19
if(f_resInMinutes() <= f_tfRes(customTF,f_resInMinutes()))
if(drawLineSTLP1 == 12 or drawLineSTLP1 == 19)
if(array.size(arrayLineSTLP) >0)

line.set_xy2(array.get(arrayLineSTLP,0),array.get(arrayXSTLP,0),array.get(arrayYSTL
P,0))
else

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP1 == 14)

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP1 == 13)

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,2),array.get(arrayYSTLP,2
),array.get(arrayXSTLP,1),array.get(arrayYSTLP,1), color = colorSTLP,xloc =
xloc.bar_time))

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP1 == 15)
if(array.size(arrayLineSTLP) >0)

line.set_xy2(array.get(arrayLineSTLP,0),array.get(arrayXSTLP,1),array.get(arrayYSTL
P,1))
else

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,2),array.get(arrayYSTLP,2
),array.get(arrayXSTLP,1),array.get(arrayYSTLP,1), color = colorSTLP,xloc =
xloc.bar_time))

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))

// drawLineSTLP kiểm tra điểm 0 => 3:Tiếp tục có sóng hồi // 2|9(reDraw):Tiếp
tục không có sóng hồi // 4:Đảo chiều
if(array.get(arrayXSTLP,0) >= array.get(arrayXTLP,1) and
array.get(arrayYSTLP,0) != array.get(arrayYTLP,0) and ((array.get(arrayYTLP,0) >
array.get(arrayYTLP,1) and array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1)) or
(array.get(arrayYTLP,0) < array.get(arrayYTLP,1) and array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1))))
drawLineSTLP := 2
array.set(arrayXSTLP, 0, array.get(arrayXTLP,0))
array.set(arrayYSTLP, 0, array.get(arrayYTLP,0))
else if(array.get(arrayXSTLP,0) <= array.get(arrayXTLP,1))
if((array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1) and
array.get(arrayYTLP,0) < array.get(arrayYSTLP,1)) or (array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1) and array.get(arrayYTLP,0) > array.get(arrayYSTLP,1)))
drawLineSTLP := 4
array.unshift(arrayXSTLP,array.get(arrayXTLP,0))
array.unshift(arrayYSTLP,array.get(arrayYTLP,0))
else if((array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1) and
array.get(arrayYTLP,0) > array.get(arrayYSTLP,0)) or (array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1) and array.get(arrayYTLP,0) < array.get(arrayYSTLP,0)))
drawLineSTLP := 3
_max = math.min(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1))
_min = math.max(array.get(arrayYSTLP,0),array.get(arrayYSTLP,1))
_max_idx = 0
_min_idx = 0
for i = 1 to array.size(arrayXTLP)
if(array.get(arrayXSTLP,0) >= array.get(arrayXTLP,i))
break
if(_min > array.get(arrayYTLP,i))
_min := array.get(arrayYTLP,i)
_min_idx := array.get(arrayXTLP,i)
if(_max < array.get(arrayYTLP,i))
_max := array.get(arrayYTLP,i)
_max_idx := array.get(arrayXTLP,i)
if(array.get(arrayYSTLP,0) > array.get(arrayYSTLP,1))
array.unshift(arrayXSTLP,_min_idx)
array.unshift(arrayYSTLP,_min)
else if(array.get(arrayYSTLP,0) < array.get(arrayYSTLP,1))
array.unshift(arrayXSTLP,_max_idx)
array.unshift(arrayYSTLP,_max)
array.unshift(arrayXSTLP,array.get(arrayXTLP,0))
array.unshift(arrayYSTLP,array.get(arrayYTLP,0))

if(f_resInMinutes() < f_tfRes(customTF,f_resInMinutes()))


if(array.get(arrayYSTLP,0) == array.get(arrayYTLP,0) and
array.get(arrayXSTLP,0) != array.get(arrayXTLP,0))
array.set(arrayXSTLP, 0, array.get(arrayXTLP,0))
drawLineSTLP := 9
if(f_resInMinutes() <= f_tfRes(customTF,f_resInMinutes()))
if(drawLineSTLP == 2 or drawLineSTLP == 9)
if(array.size(arrayLineSTLP) >0)

line.set_xy2(array.get(arrayLineSTLP,0),array.get(arrayXSTLP,0),array.get(arrayYSTL
P,0))
else

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP == 4)

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP == 3)

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,2),array.get(arrayYSTLP,2
),array.get(arrayXSTLP,1),array.get(arrayYSTLP,1), color = colorSTLP,xloc =
xloc.bar_time))
array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))
else if(drawLineSTLP == 5)
if(array.size(arrayLineSTLP) >0)

line.set_xy2(array.get(arrayLineSTLP,0),array.get(arrayXSTLP,1),array.get(arrayYSTL
P,1))
else

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,2),array.get(arrayYSTLP,2
),array.get(arrayXSTLP,1),array.get(arrayYSTLP,1), color = colorSTLP,xloc =
xloc.bar_time))

array.unshift(arrayLineSTLP,line.new(array.get(arrayXSTLP,1),array.get(arrayYSTLP,1
),array.get(arrayXSTLP,0),array.get(arrayYSTLP,0), color = colorSTLP,xloc =
xloc.bar_time))

///////////////////////Other//////////////////////////////////
if(f_resInMinutes() <= f_tfRes(customTF,f_resInMinutes()))
if(showSTLP)

if(showLabel and (barstate.islast or barstate.islastconfirmedhistory))


texLabel = f_resInMinutes() == f_tfRes(customTF,f_resInMinutes()) ?
f_resFromMinutes(f_resInMinutes()) :
f_resFromMinutes(f_tfRes(customTF,f_resInMinutes()))
label.set_xy(labelTF,array.get(arrayXSTLP,0),array.get(arrayYSTLP,0))
label.set_text(labelTF,texLabel)
label.set_style(labelTF,array.get(arrayYSTLP,0) <
array.get(arrayYSTLP,1) ? label.style_label_upper_right :
label.style_label_lower_right)
if(not showTLP)
arrayLineTemp := array.copy(arrayLineTLP)
for itemArray in arrayLineTemp
if(line.get_x1(itemArray) < array.get(arrayXSTLP,0))
line.delete(itemArray)
array.remove(arrayLineTLP,array.indexof(arrayLineTLP,
itemArray))
//Inside Bars - Outside Bars
insideBar() => ISB and high <= high[1] and low >= low[1] ? 1 : 0
outsideBar() => OSB and (high > high[1] and low < low[1]) ? 1 : 0

//Inside and Outside Bars


barcolor(insideBar() ? color.new(colorISB,0) : na )
barcolor(outsideBar() ? color.new(colorOSB,0) : na )

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy