Code: Select all
// Author : LonesomeTheBlue
//@version=4
study("Point and Figure (PnF) Moving Averages", overlay=true, max_bars_back=5000)
mode =input(title = "[SETUP] Method", defval = 'ATR', options=['User Defined', 'ATR', 'Traditional', 'Percentage'])
modevalue = input(title ="[SETUP] Atr Period", defval = 20, minval = 1)
boxsize = input(title ="[SETUP] Box Size", defval = 10.0, minval = 0.000000000000001)
percentagebs = input(title ="[SETUP] Percentage %", defval = 0.1, minval = 0.00001)
reversal = input(3, title = "[SETUP] Reversal", minval = 1)
source =input(defval = "close", title = "[SETUP] Source", options=['close', 'hl'])
//traditional box size calculation
tboxsize = high < 0.25 ? 0.0625 :
high < 1.00 ? 0.125 :
high < 5.00 ? 0.25 :
high < 20.0 ? 0.50 :
high < 100.0 ? 1.0 :
high < 200.0 ? 2.0 :
high < 500.0 ? 4.0 :
high < 1000.0 ? 5.0 :
high < 25000.0 ? 50.0 :
500.0 //(high >= 25000.0)
//calc atr val
conv_atr(valu)=>
a = 0
num = syminfo.mintick
s = valu
if na(s)
s := syminfo.mintick
if num < 1
for i = 1 to 20
num := num * 10
if num > 1
break
a := a +1
for x = 1 to a
s := s * 10
s := round(s)
for x = 1 to a
s := s / 10
s := s < syminfo.mintick ? syminfo.mintick : s
s
//ATR box size calculation
atrboxsize = conv_atr(atr(modevalue))
//percentage box size calculation
pboxsize = conv_atr(percentagebs * close / 100)
float box = na
box := na(box[1]) ? mode == 'ATR' ? atrboxsize : mode == 'Traditional' ? tboxsize : mode == 'Percentage' ? pboxsize : boxsize : box[1]
top = 0.0, bottom = 0.0
trend = 0
trend := barstate.isfirst ? 0 : nz(trend[1])
currentprice = 0.0
currentprice := source == 'close' ? close : trend == 1 ? high : low
float beginprice = na
beginprice := barstate.isfirst ? floor(open / box) * box : nz(beginprice[1])
iopenprice = 0.0
icloseprice = 0.0
if trend == 0 and box * reversal <= abs(beginprice - currentprice)
if beginprice > currentprice
numcell = floor(abs(beginprice - currentprice) / box)
iopenprice := beginprice
icloseprice := beginprice - numcell * box
trend := -1
if beginprice < currentprice
numcell = floor(abs(beginprice - currentprice) / box)
iopenprice := beginprice
icloseprice := beginprice + numcell * box
trend := 1
if trend == -1
nok = true
if beginprice > currentprice and box <= abs(beginprice - currentprice)
numcell = floor(abs(beginprice - currentprice) / box)
icloseprice := beginprice - numcell * box
trend := -1
beginprice := icloseprice
nok := false
else
iopenprice := iopenprice == 0 ? nz(iopenprice[1]) : iopenprice
icloseprice := icloseprice == 0 ? nz(icloseprice[1]) : icloseprice
tempcurrentprice = source == 'close' ? close : high
if beginprice < tempcurrentprice and box * reversal <= abs(beginprice - tempcurrentprice) and nok //new column
numcell = floor(abs(beginprice - tempcurrentprice) / box)
iopenprice := beginprice + box
icloseprice := beginprice + numcell * box
trend := 1
beginprice := icloseprice
else
iopenprice := iopenprice == 0 ? nz(iopenprice[1]) : iopenprice
icloseprice := icloseprice == 0 ? nz(icloseprice[1]) : icloseprice
else
if trend == 1
nok = true
if beginprice < currentprice and box <= abs(beginprice - currentprice)
numcell = floor(abs(beginprice - currentprice) / box)
icloseprice := beginprice + numcell * box
trend := 1
beginprice := icloseprice
nok := false
else
iopenprice := iopenprice == 0 ? nz(iopenprice[1]) : iopenprice
icloseprice := icloseprice == 0 ? nz(icloseprice[1]) : icloseprice
tempcurrentprice = source == 'close' ? close : low
if beginprice > tempcurrentprice and box * reversal <= abs(beginprice - tempcurrentprice) and nok //new column
numcell = floor(abs(beginprice - tempcurrentprice) / box)
iopenprice := beginprice - box
icloseprice := beginprice - numcell * box
trend := -1
beginprice := icloseprice
else
iopenprice := iopenprice == 0 ? nz(iopenprice[1]) : iopenprice
icloseprice := icloseprice == 0 ? nz(icloseprice[1]) : icloseprice
//if icloseprice changed then recalculate box size
box := change(icloseprice) ? mode == 'ATR' ? atrboxsize : mode == 'Traditional' ? tboxsize : mode == 'Percentage' ? pboxsize : boxsize : box
//PNF Moving average
matype =input(title = "[MA] MA Type", defval = 'EMA', options=['EMA', 'SMA'])
masrc = input(defval = 'Average price', title = "[MA] MA Source", options =['Average price', 'Close Price'])
pnfma1 = input(1, title="[MA] Fast Length", minval = 1)
pnfma2 = input(5, title="[MA] Slow Length", minval = 1)
fillmas = input(true, title = "[MA] Fill between MAs")
macol = input(defval = 'Lime/Blue', title = "[MA] Color Theme", options =['Lime/Blue', 'Lime/Red', 'Green/Red', 'Green/Blue', 'Blue/Red'])
masource = masrc == 'Average price' ? ((iopenprice + icloseprice) / 2) : icloseprice
countch = 0
countch := change(icloseprice) ? nz(countch[1]) + 1 : nz(countch[1])
trcnt = 0
trcnt := change(trend) ? 1 : nz(trcnt[1]) + 1
trcnt := trcnt > 4000 ? 4000 : trcnt
pnf_sma(ser, len) =>
sum = ser
nn = 1
if len > 1
for i = 0 to 4000
if trend[i] ==0 or trend[i+1] ==0
break
if trend[i] != nz(trend[i+1])
nn := nn + 1
sum := sum + ser[i+1]
if nn == len
break
_ret = nn == len ? sum / len : na
float alpha1 = 2 / (pnfma1 + 1)
float alpha2 = 2 / (pnfma2 + 1)
float pnfsma1 = na
float pnfsma2 = na
pnfsma1 := countch <= pnfma1 or matype == 'SMA' ? pnf_sma(masource, pnfma1) : alpha1 * masource + (1 - alpha1) * nz(pnfsma1[trcnt])
pnfsma2 := countch <= pnfma2 or matype == 'SMA' ? pnf_sma(masource, pnfma2) : alpha2 * masource + (1 - alpha2) * nz(pnfsma2[trcnt])
pnfm1 = pnfsma1 //floor(pnfsma1 / box) * box // in atr mode box size changes on every bar and this is problem
pnfm2 = pnfsma2 //floor(pnfsma2 / box) * box
maupcol = macol == 'Lime/Blue' or macol == 'Lime/Red' ? color.lime : macol == 'Blue/Red' ? color.blue : color.green
madowncol = macol == 'Lime/Blue' or macol == 'Green/Blue' ? color.blue : color.red
lma1 = plot(pnfm1, color = color.olive, title = "Fast Ma", linewidth = 3, editable = false)
lma2 = plot(pnfm2, color = color.maroon, title = "Slow Ma", linewidth = 3, editable = false)
fill(lma1, lma2, title = "MA Area", color =pnfm1 >= pnfm2 ? maupcol : madowncol, transp = fillmas ? 60 : 100, editable = false)
matrend = pnfm1 > pnfm2 and nz(pnfm1[1]) <= nz(pnfm2[1]) ? 1 : 0
matrend := pnfm1 < pnfm2 and nz(pnfm1[1]) >= nz(pnfm2[1]) ? -1 : matrend
alertcondition(nz(matrend[1]) == 1 and matrend == 1, title='PNF MA Trend Up', message='PNF MA Trend Up')
alertcondition(nz(matrend[1]) == -1 and matrend == -1, title='PNF MA Trend Down', message='PNF MA Trend Down')
Not sure if it can be converted though. Looks like it's actually 2 averages something like a 2 ma cross.