Point and Figure (PnF) Chart For ThinkOrSwim

drasp

Member
The author states:
This is live and non-repainting Point and Figure Charting tool.

Point and Figure method is over 150 years old. It consist of columns that represent filtered price movements. Time is not a factor on P&F chart but as you can see with this script P&F chart created on time chart.

P&F chart provide several advantages, some of them are filtering insignificant price movements and noise, focusing on important price movements and making support/resistance levels much easier to identify.

If you are new to Point & Figure Chart then you better get some information about it before using this tool. There are very good web sites and books.
6GLO7mD.png


Options in the Script

Box size is one of the most important part of Point and Figure Charting. Chart price movement sensitivity is determined by the Point and Figure scale. Large box sizes see little movement across a specific price region, small box sizes see greater price movement on P&F chart. There are four different box scaling with this tool: Traditional, Percentage, Dynamic (ATR), or User-Defined

4 different methods for Box size can be used in this tool.
User Defined: The box size is set by user. A larger box size will result in more filtered price movements and fewer reversals. A smaller box size will result in less filtered price movements and more reversals.

ATR: Box size is dynamically calculated by using ATR, default period is 20.

Percentage: uses box sizes that are a fixed percentage of the stock's price. If percentage is 1 and stock’s price is $100 then box size will be $1

Traditional: uses a predefined table of price ranges to determine what the box size should be.
Price Range Box Size
Under 0.25 0.0625
0.25 to 1.00 0.125
1.00 to 5.00 0.25
5.00 to 20.00 0.50
20.00 to 100 1.0
100 to 200 2.0
200 to 500 4.0
500 to 1000 5.0
1000 to 25000 50.0
25000 and up 500.0

Default value is “ATR”, you may use one of these scaling method that suits your trading strategy.

If ATR or Percentage is chosen then there is rounding algorithm according to mintick value of the security. For example if mintick value is 0.001 and box size (ATR/Percentage) is 0.00124 then box size becomes 0.001.

And also while using dynamic box size (ATR or Percentage), box size changes only when closing price changed.

Reversal : It is the number of boxes required to change from a column of Xs to a column of Os or from a column of Os to a column of Xs. Default value is 3 (most used). For example if you choose reversal = 2 then you get the chart similar to Renko chart.

Source: Closing price or High-Low prices can be chosen as data source for P&F charting.

The OP states:
This may be a long shot, but I think I'll give it a try anyways.
Is it possible to convert this indicator into thinkorswim?
https://www.tradingview.com/script/wcl6LYEE-Point-and-Figure-PnF-Chart/
 
Last edited by a moderator:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

This may be a long shot, but I think I'll give it a try anyways.
Is it possible to convert this indicator into thinkorswim?

I copied the source here from tradingview

Code:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LonesomeTheBlue
//
//@version=4
study("Point and Figure (PnF) Chart", overlay=true, max_bars_back=5000)
mode =input(title = "[PNF] Method", defval = 'ATR', options=['User Defined', 'ATR', 'Traditional', 'Percentage'])
modevalue = input(title ="[PNF] Atr Period", defval = 20, minval = 1)
boxsize = input(title ="[PNF] Box Size", defval = 10.0, minval = 0.000000000000001)
percentagebs = input(title ="[PNF] Percentage %", defval = 0.1, minval = 0.00001)
reversal = input(3, title = "[PNF] Reversal", minval = 1)
source =input(defval = "hl", title = "[PNF] Source", options=['close', 'hl'])
showpnfstyle =input(title = "[PNF] Chart Style As", defval = 'Area', options=['Candle', 'Area', 'Dont Show'])
pnfchartstyle =input(title = "[PNF] X/O Column Style", defval = 'Only Last Xs/Os', options=['From Beginning of Column', 'Only Last Xs/Os'])
breakoutcolor = input(defval = 'Lime/Red', title = "[DISPLAY] Color Theme", options =['Green/Red', 'Yellow/Blue', 'White/Yellow', 'Orange/Blue', 'Lime/Red', 'Blue/Red'])
changebarcol = input(true, title = "[DISPLAY] Change Bar Colors")
showbreakout = input(true, title = "[DISPLAY] Show Breakouts")
showecctarget = input(false, title = "[TARGET] Show Horizontal Count Targets")
maxnumhc = 20 //input(title ="[TARGET] Max columns for HC", defval=20, minval = 10, maxval = 50)
showvertarget = input(false, title = "[TARGET] Show Vertical Count Targets")

//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

upcolor = breakoutcolor == 'Green/Red' ? color.green :  breakoutcolor == 'White/Yellow' ? color.white : breakoutcolor == 'Lime/Red' ? color.lime : breakoutcolor == 'Blue/Red' ? color.blue : breakoutcolor == 'Yellow/Blue' ? color.yellow : color.orange
downcolor = breakoutcolor == 'Yellow/Blue' or breakoutcolor == 'Orange/Blue' ? color.blue : breakoutcolor == 'Green/Red' or breakoutcolor == 'Lime/Red' or breakoutcolor == 'Blue/Red'? color.red : color.yellow

oprice = pnfchartstyle == 'From Beginning of Column' ? iopenprice :
   trend == 1 ? nz(trend[1]) == 1 ? nz(icloseprice[1]) - nz(box[1]) : nz(icloseprice[1]) + nz(box[1]) :
   trend == -1 ? nz(trend[1]) == -1 ? nz(icloseprice[1]) + nz(box[1]) : nz(icloseprice[1]) - nz(box[1]) :
   nz(icloseprice[1])
oprice := oprice < 0 ? 0 : oprice

openline = plot(showpnfstyle == 'Area' and  oprice > 0? oprice : na, title = "PnF Open", color = oprice < 0 or oprice[1] < 0 ? na : color.gray, editable = false)
closeline = plot(showpnfstyle == 'Area' and icloseprice > 0 ? icloseprice : na, title = "PnF Close", color = icloseprice <= 0 or icloseprice[1] <= 0 ? na : color.gray, editable = false)
fill(openline, closeline, color = oprice <= 0 and icloseprice <=0 ? na : trend == 1 ? upcolor : downcolor, transp = 70, editable = false)
plotcandle(showpnfstyle == 'Candle' ? oprice : na, showpnfstyle == 'Candle' ? max(oprice, icloseprice) : na, showpnfstyle == 'Candle' ? min(oprice , icloseprice) : na, showpnfstyle == 'Candle'? icloseprice : na, title='PnF Candles', color = trend == 1 ? upcolor : downcolor, editable = false)

barcolor(changebarcol ? trend == 1 ? upcolor : downcolor : na, editable = false)
//keep last close/open price
float lasticloseprice = na
lasticloseprice := change(icloseprice) ? icloseprice[1] : nz(lasticloseprice[1])

// keep old columns
float chigh = na
float clow = na
ctrend = 0
chigh := change(trend) ? max(iopenprice[1], icloseprice[1]) : na
clow := change(trend) ? min(iopenprice[1], icloseprice[1]) : na
ctrend := change(trend) ? trend[1] : na

// Breakouts and Target calculation
iscatapultup()=>
    _ret = valuewhen(chigh, chigh, 3) == valuewhen(chigh, chigh, 5) and valuewhen(chigh, chigh, 1) > valuewhen(chigh, chigh, 3) and valuewhen(chigh, chigh, 1) <= valuewhen(chigh, chigh, 3) + 3 * box and valuewhen(clow, clow, 0) >= valuewhen(clow, clow, 2)

iscatapultdown()=>
    _ret = valuewhen(clow, clow, 3) == valuewhen(clow, clow, 5) and valuewhen(clow, clow, 1) < valuewhen(clow, clow, 3) and valuewhen(clow, clow, 1) >= valuewhen(clow, clow, 3) - 3 * box and valuewhen(chigh, chigh, 0) <= valuewhen(chigh, chigh, 2)
   
doubletopbreakout()=>
    _ret = trend == 1 and icloseprice > icloseprice[1] and icloseprice > valuewhen(chigh, chigh, 1) and icloseprice[1] <= valuewhen(chigh, chigh, 1)

doubletopbreakoutrisingbottom()=>
    _ret = valuewhen(clow, clow, 0) > valuewhen(clow, clow, 2)
   
doublebottombreakout()=>
    _ret = trend == -1 and icloseprice < icloseprice[1] and icloseprice < valuewhen(clow, clow, 1) and icloseprice[1] >= valuewhen(clow, clow, 1)

doubletopbreakoutdecliningtop()=>
    _ret = valuewhen(chigh, chigh, 0) < valuewhen(chigh, chigh, 2)
   
tribletopbreakout()=>
    _ret = trend == 1 and icloseprice > icloseprice[1] and icloseprice > valuewhen(chigh, chigh, 1) and icloseprice[1] <= valuewhen(chigh, chigh, 1) and valuewhen(chigh, chigh, 1) == valuewhen(chigh, chigh, 3)

tripletopbreakoutascending()=>
    _ret = trend == 1 and icloseprice > icloseprice[1] and icloseprice > valuewhen(chigh, chigh, 1) and icloseprice[1] <= valuewhen(chigh, chigh, 1) and valuewhen(chigh, chigh, 1) == valuewhen(chigh, chigh, 3) + box
   
triblebottombreakout()=>
    _ret = trend == -1 and icloseprice < icloseprice[1] and icloseprice < valuewhen(clow, clow, 1) and icloseprice[1] >= valuewhen(clow, clow, 1) and valuewhen(clow, clow, 1) == valuewhen(clow, clow, 3)

triplebottombreakoutdescending()=>
    _ret = trend == -1 and icloseprice < icloseprice[1] and icloseprice < valuewhen(clow, clow, 1) and icloseprice[1] >= valuewhen(clow, clow, 1) and valuewhen(clow, clow, 1) == valuewhen(clow, clow, 3) - box
   

// Extended Congestions     // horizontal count / Cohen
excontop = 0
exconlow = iopenprice // Congestion low point
indh = 1
if icloseprice > icloseprice[1] // is there move to up ?
    float hi = icloseprice[1]   // resistance level
    float lo = iopenprice       // lowest point of congestion to calculate target
    notfirsthi = false
    for x = 0 to 3000
        if not na(chigh[x])
            indh := indh + 1
            if indh > maxnumhc // arrived to column limit
                break
            if chigh[x] >= hi and ctrend[x] == trend                                                  // new and higher resistance in history? / and chigh[x] < icloseprice and ctrend[x] == trend
                hi := chigh[x]                                                  // keep new resistance
                notfirsthi := true                                              // resistance
            if chigh[x] >= icloseprice                                          // higher block?
                if hi < icloseprice and notfirsthi and ctrend[x] == -trend      // reached Os columnd and there is resistance point in congestion area
                    excontop := indh                                            // keep it
                    exconlow := lo                                              // keep lowestpoint for target calculation
                break                                                           // don't look back more
            lo := min(clow[x], lo)                                              // taking lowest point of congestion

exconbot = 0
exconhigh = icloseprice // Congestion high point
indl = 1
if icloseprice < icloseprice[1] // is there move to down ?
    float lo = icloseprice[1]   // support level
    float hi = iopenprice       // highest point of congestion to calculate target
    notfirstlo = false
    for x = 0 to 3000
        if not na(clow[x])
            indl := indl + 1    // new block of Xs or Os
            if indl > maxnumhc // arrived to column limit
                break
            if clow[x] <= lo and ctrend[x] == trend   // new and lower support in history?
                lo := clow[x]                                                   // keep new support level
                notfirstlo := true                                               // support
            if clow[x] <= icloseprice                                           // lower block?
                if lo > icloseprice and  notfirstlo and ctrend[x] == -trend  // reached Os column and there is resistance point in congestion area
                    exconbot := indl                                            // keep it
                    exconhigh := hi                                             // keep highestpoint for target calculation
                break                                                           // don't look back more
            hi := max(chigh[x], hi)                                             // taking higest point of congestion
           
ttb = tribletopbreakout()
ttbas = tripletopbreakoutascending()
tbb = triblebottombreakout()
tbbdes = triplebottombreakoutdescending()
dtb = doubletopbreakout()
dtbrb = dtb and doubletopbreakoutrisingbottom()
dbb = doublebottombreakout()
dbbdt = dbb and doubletopbreakoutdecliningtop()

// Extended congestion target calculation - horizontal count
float ecctarget = na
ecctarget := excontop >= 7 ? exconlow + reversal * excontop * box : exconbot >= 7 ? exconhigh - reversal * exconbot * box : ecctarget[1]
ecctarget := ecctarget > 0 ? ecctarget : ecctarget[1]
secctarget = false
valid = 0
valid := excontop >= 7 ? 1 : exconbot >= 7 ? 2 : nz(valid[1])
float keepbase = na
keepbase := excontop >= 7 ? exconlow : exconbot >= 7 ? exconhigh : nz(keepbase[1])
secctarget := excontop >= 7 or exconbot >= 7 ? true : secctarget[1]
secctarget := excontop >= 7  and ecctarget <= icloseprice ? false : exconbot >= 7 and ecctarget >= icloseprice ? false : secctarget
secctarget := ecctarget <= max(iopenprice, icloseprice) and ecctarget >= min(iopenprice, icloseprice) ? false : secctarget
secctarget := valid == 1 and icloseprice < keepbase ? false : valid == 2 and icloseprice > keepbase ? false : secctarget  // target is cancelled if price goes outside of the bases -Jeremmy Du Plessis
ecccol = ecctarget > max(iopenprice, icloseprice) ? color.blue : color.red
ecctarget := not secctarget ? na : ecctarget
plot(showecctarget ? ecctarget : na, title = "ECC Target", linewidth = 3, color = secctarget and secctarget[1] and ecctarget == nz(ecctarget[1]) ? ecccol : na, style = plot.style_linebr, editable = false)

   
// Vertical top/bottom target calculation, this works for triple top/bottom breakouts
float ddtarget = na, float dbase1 = na, float dbase2 = na
dbase1 := min(valuewhen(clow, clow,0), valuewhen(clow, clow,2))
dbase2 := max(valuewhen(chigh, chigh,0), valuewhen(chigh, chigh,2))
ddtarget := ttb or ttbas ? dbase1 + (icloseprice - iopenprice) * reversal : tbb or tbbdes ?  dbase2 -  (iopenprice - icloseprice) * reversal : ddtarget[1]
ddtarget := ddtarget > 0 ? ddtarget : ddtarget[1]
// vertical count should be calculated until column is completed
ddkeepcountup = false, ddkeepcountdown = false
ddkeepcountup := ttb or ttbas ? true : change(trend) !=0 ? false :  ddkeepcountup[1]
ddkeepcountdown := tbb or tbbdes ? true : change(trend) !=0 ? false :  ddkeepcountdown[1]
if ddkeepcountup or ddkeepcountdown
    ddtarget := ddkeepcountup ? dbase1 + (icloseprice - iopenprice) * reversal : ddkeepcountdown ?  dbase2 - (iopenprice - icloseprice) * reversal : ddtarget[1]
    ddtarget := ddtarget > 0 ? ddtarget : ddtarget[1]  
   
sddtarget = false
dvalid = 0
dvalid := ttb or ttbas ? 1 : tbb or tbbdes ? 2 : nz(dvalid[1])
float dkeepbase = na
dkeepbase := ttb or ttbas ? dbase1 : tbb or tbbdes ? dbase2 : nz(dkeepbase[1])

sddtarget := ttb or ttbas or tbb or tbbdes ? true : sddtarget[1]
sddtarget := (ttb or ttbas) and ddtarget <= icloseprice ? false : (tbb or tbbdes) and ddtarget >= icloseprice ? false : sddtarget
sddtarget := ddtarget <= max(iopenprice, icloseprice) and ddtarget >= min(iopenprice, icloseprice) ? false : sddtarget
sddtarget := dvalid == 1 and icloseprice < dkeepbase ? false : dvalid == 2 and icloseprice > dkeepbase ? false : sddtarget  // target is cancelled if price goes outside of the bases -Jeremmy Du Plessis
ddcol = ddtarget > max(iopenprice, icloseprice) ? color.maroon : color.olive
ddtarget := not sddtarget ? na : ddtarget
plot(showvertarget ? ddtarget : na, title = "Vertical Count Target", linewidth = 3, color = sddtarget and sddtarget[1] ? ddcol : na, style = plot.style_linebr, editable = false)

if excontop >= 7 and showecctarget
    label.new(bar_index, y = ecctarget, text = 'Target' + tostring(ecctarget, '#.#####'), color = color.lime, textcolor=color.black, style=label.style_labelup, yloc=yloc.price)
if exconbot >= 7 and showecctarget
    label.new(bar_index, y = ecctarget, text = 'Target' + tostring(ecctarget, '#.#####'), color = color.maroon, textcolor=color.white, style=label.style_labeldown, yloc=yloc.price)

boupcolor = color.green
bodncolor = color.red
plotshape(ttb and showbreakout, text = "Triple Top\n\n\n.", title='Triple Top',  style=shape.triangleup, color=boupcolor, textcolor=boupcolor, size = size.tiny, location=location.abovebar, transp=0, editable = false)
plotshape(ttbas and showbreakout, text = "Triple Top\nAscending\n\n.", title='Ascending Triple Top',  style=shape.triangleup, color=boupcolor, textcolor=boupcolor, size = size.tiny, location=location.abovebar, transp=0, editable = false)
plotshape(tbb and showbreakout, text = ".\n\nTriple Bottom", title='Triple Bottom', style=shape.triangledown, color=bodncolor, textcolor=bodncolor, size = size.tiny, location=location.belowbar, transp=0, editable = false)
plotshape(tbbdes and showbreakout, text = ".\n\nTriple Bottom\nDescending", title='Descending Triple Bottom', style=shape.triangledown, color=bodncolor, textcolor=bodncolor, size = size.tiny, location=location.belowbar, transp=0, editable = false)
plotshape(dtb and not dtbrb and showbreakout, text = "Simple Buy\n.", title='Simple Buy',  style=shape.triangleup, color=boupcolor, textcolor=boupcolor, size = size.tiny, location=location.abovebar, transp=0, editable = false)
plotshape(dtbrb and showbreakout, text = "Simple Buy With\nRising Bottom", title='Simple Buy with Rising Bottom',  style=shape.triangleup, color=boupcolor, textcolor=boupcolor, size = size.tiny, location=location.abovebar, transp=0, editable = false)
plotshape(dbb and not dbbdt and showbreakout, text = "Simple Sell", title='Simple Sell', style=shape.triangledown, color=bodncolor, textcolor=bodncolor, size = size.tiny, location=location.belowbar, transp=0, editable = false)
plotshape(dbbdt and showbreakout, text = "Simple Sell With\nDeclining Top", title='Simple Sell with Declining Top', style=shape.triangledown, color=bodncolor, textcolor=bodncolor, size = size.tiny, location=location.belowbar, transp=0, editable = false)
plotshape(dtb and iscatapultup() and showbreakout, text = "Catapult\n\n\n\n.", title='Catapult',  style=shape.triangleup, color=boupcolor, textcolor=boupcolor, size = size.tiny, location=location.abovebar, transp=0, editable = false)
plotshape(dbb and iscatapultdown() and showbreakout, text = ".\n\n\n\nCatapult", title='Catapult', style=shape.triangledown, color=bodncolor, textcolor=bodncolor, size = size.tiny, location=location.belowbar, transp=0, editable = false)


alertcondition(change(trend) > 0, title='PNF Trend is Up', message='PNF Trend is Up')
alertcondition(change(trend) < 0, title='PNF Trend is Down', message='PNF Trend is Down')

I'm hoping it to look something like this:


zkpa4GAD


plz help!

thanks.
check the below:

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © LonesomeTheBlue
#study("Point and Figure (PnF) Chart", overlay=true, max_bars_back=5000)

# Converted by Sam4Cok@Samer800    - 03/2024    - Not Complete Conv.

input pnfMethod = {"User Defined", default "ATR", "Traditional", "Percentage"}; # "[PNF] Method"
input AtrPeriod = 20;      # "[PNF] Atr Period"
input pnfBoxSize = 10.0;   # "[PNF] Box Size"
input pnfPercentage = 0.1; # "[PNF] Percentage %"
input pnfReversal = 3; #, title = "[PNF] Reversal", minval = 1)
input source = {"Close", default "High/Low"}; # "[PNF] Source"
input showPnfChart = yes; # "[PNF] Show Chart
input pnfchartstyle = {"From Beginning of Column", default "Only Last Xs/Os"}; # "[PNF] X/O Column Style",
input colorBars = yes; #(true, title = "[DISPLAY] Change Bar Colors")
input showBreakout = {default "Detailed Bubbles", "Arrows", "Don't Show"}; #(true, title = "[DISPLAY] Show Breakouts")

def na = Double.NaN;
def last = IsNaN(close);
def arrow = showBreakout == showBreakout."Arrows";
def bubble = showBreakout == showBreakout."Detailed Bubbles";

DefineGlobalColor("up", CreateColor(7,71,123));
DefineGlobalColor("dn", CreateColor(118,106,0));

#//traditional box size calculation
def tboxsize = if high < 0.25 then 0.0625 else
   if high < 1.00 then 0.125 else
   if high < 5.00 then 0.25 else
   if high < 20.0 then 0.50 else
   if high < 100.0 then 1.0 else
   if high < 200.0 then 2.0 else
   if high < 500.0 then 4.0 else
   if high < 1000.0 then 5.0 else
   if high < 25000.0 then 50.0 else 500.0; #  //(high >= 25000.0)

#//calc atr val
script conv_atr {
    input valu = close;
    def num = TickSize();
    def s = if (IsNaN(valu) or !valu) then TickSize() else valu;
    def a = if num < 1 then
            fold i = 1 to 20 with p while num * 10 <= 1 do
            p + 1 else a[1];
    def s1 = fold x = 1 to a + 1  with q = s do
             q * 10;
    def s2 = Round(s1, 0);
    def s3 = fold x1 = 1 to a + 1 with q1 = s2 do
            q1 / 10;
    def s0 = if s3 < TickSize() then TickSize() else s3;
    plot out = s0;
}
#//ATR box size calculation
def atrboxsize = conv_atr(ATR(Length = AtrPeriod));
#//percentage box size calculation
def pboxsize = conv_atr(pnfPercentage * close / 100);

#float box = na
def box1;
def box = if IsNaN(box1[1]) or !box1[1] then
          if pnfMethod == pnfMethod."ATR" then atrboxsize else
          if pnfMethod == pnfMethod."Traditional" then tboxsize else
          if pnfMethod == pnfMethod."Percentage" then pboxsize else pnfBoxSize else box1[1];
def trend1;
def trend = if IsNaN(trend1[1]) then 0 else trend1[1];

def iopenprice;
def icloseprice;
def numcell;
def nok;
def beginprice1;
def currentprice = if source == source."Close" then close else
                   if trend == 1 then high else low;
def beginprice = if !beginprice1[1] then Floor(open / box) * box else beginprice1[1];
def tempHi = if source == source."Close" then close else high;
def tempLo = if source == source."Close" then close else low;

if trend1[1] == 0 and box * pnfReversal <= AbsValue(beginprice - currentprice) {
    nok = nok[1];
    beginprice1 = beginprice;
    if beginprice > currentprice {
        numcell = Floor(AbsValue(beginprice - currentprice) / box);
        iopenprice = beginprice;
        icloseprice = beginprice - numcell * box;
        trend1 = -1;
    } else if beginprice < currentprice {
        numcell = Floor(AbsValue(beginprice - currentprice) / box);
        iopenprice = beginprice;
        icloseprice = beginprice + numcell * box;
        trend1 = 1;
    } else {
        numcell = 0;
        iopenprice = iopenprice[1];
        icloseprice = icloseprice[1];
        trend1 = trend;
    }
} else if trend1[1] == -1 {
    if beginprice > currentprice and box <= AbsValue(beginprice - currentprice) {
        numcell = Floor(AbsValue(beginprice - currentprice) / box);
        iopenprice = iopenprice[1];
        icloseprice = beginprice - numcell * box;
        trend1 = -1;
        beginprice1 = icloseprice;
        nok = no;
    } else if beginprice < tempHi and box * pnfReversal <= AbsValue(beginprice - tempHi) and nok[1] {
        nok = yes;
        numcell = Floor(AbsValue(beginprice - tempHi) / box);
        iopenprice = beginprice + box;
        icloseprice = beginprice + numcell * box;
        trend1 = 1;
        beginprice1 = icloseprice;
    } else {
        nok = yes;
        numcell = 0;
        iopenprice = if iopenprice[1] == 0 then iopenprice[2] else iopenprice[1];
        icloseprice = if icloseprice[1] == 0 then icloseprice[2] else icloseprice[1];
        trend1 = trend;
        beginprice1 = beginprice;
    }
} else if trend1[1] == 1 {
    if beginprice < currentprice and box <= AbsValue(beginprice - currentprice) {
        numcell = Floor(AbsValue(beginprice - currentprice) / box);
        iopenprice = iopenprice[1];
        icloseprice = beginprice + numcell * box;
        trend1 = 1;
        beginprice1 = icloseprice;
        nok = no;
    } else if beginprice > tempLo and box * pnfReversal <= AbsValue(beginprice - tempLo) and nok[1] {
        numcell = Floor(AbsValue(beginprice - tempLo) / box);
        iopenprice = beginprice - box;
        icloseprice = beginprice - numcell * box;
        trend1 = -1;
        beginprice1 = icloseprice;
        nok = yes;
    } else {
        numcell = 0;
        iopenprice = if iopenprice[1] == 0 then iopenprice[2] else iopenprice[1];
        icloseprice = if icloseprice[1] == 0 then icloseprice[2] else icloseprice[1];
        beginprice1 = beginprice;
        trend1 = trend;
        nok = yes;
    }
} else {
    nok = nok[1];
    numcell = 0;
    iopenprice = if iopenprice[1] == 0 then iopenprice[2] else iopenprice[1];
    icloseprice = if icloseprice[1] == 0 then icloseprice[2] else icloseprice[1];
    trend1 = trend;
    beginprice1 = beginprice;
}

#//if icloseprice changed then recalculate box size
box1 = if (icloseprice - icloseprice[1]) then
      if pnfMethod == pnfMethod."ATR" then atrboxsize else
      if pnfMethod == pnfMethod."Traditional" then tboxsize else
      if pnfMethod == pnfMethod."Percentage" then pboxsize else pnfBoxSize else box;

def oprice1 = if pnfchartstyle == pnfchartstyle."From Beginning of Column" then iopenprice else
   if trend1 == 1 then if trend1[1] == 1 then icloseprice[1] - box1[1] else icloseprice[1] + box1[1] else
   if trend1 == -1 then if trend1[1] == -1 then icloseprice[1] + box1[1] else icloseprice[1] - box1[1] else icloseprice[1];
def oprice = if oprice1 < 0 then 0 else oprice1;

def openline = if !last and oprice > 0 then oprice else na; # "PnF Open"
def closeline = if !last and icloseprice > 0 then icloseprice else na;

AddCloud(if showPnfChart then openline else na, closeline, GlobalColor("dn"), GlobalColor("up"), yes);

AssignPriceColor(if !colorBars then Color.CURRENT else
                 if trend1 == 1 then Color.GREEN else Color.RED);

def lasticloseprice = if (icloseprice - icloseprice[1]) then  icloseprice[1] else lasticloseprice[1];
#// keep old columns
def chigh = if (trend1 - trend1[1]) then Max(iopenprice[1], icloseprice[1]) else na;
def clow  = if (trend1 - trend1[1]) then Min(iopenprice[1], icloseprice[1]) else na;
def ctrend = if (trend1 - trend1[1]) then trend1[1] else na;

def chigh0;
def chigh1;
def chigh2;
def chigh3;
def chigh4;
def chigh5;
if !IsNaN(chigh) {
    chigh5 = chigh4[1];
    chigh4 = chigh3[1];
    chigh3 = chigh2[1];
    chigh2 = chigh1[1];
    chigh1 = chigh0[1];
    chigh0 = chigh;
} else {
    chigh5 = chigh5[1];
    chigh4 = chigh4[1];
    chigh3 = chigh3[1];
    chigh2 = chigh2[1];
    chigh1 = chigh1[1];
    chigh0 = chigh0[1];
}
def clow0;
def clow1;
def clow2;
def clow3;
def clow4;
def clow5;
if !IsNaN(clow) {
    clow5 = clow4[1];
    clow4 = clow3[1];
    clow3 = clow2[1];
    clow2 = clow1[1];
    clow1 = clow0[1];
    clow0 = clow;
} else {
    clow5 = clow5[1];
    clow4 = clow4[1];
    clow3 = clow3[1];
    clow2 = clow2[1];
    clow1 = clow1[1];
    clow0 = clow0[1];
}
#// Breakouts and Target calculation
def iscatapultup = chigh3 == chigh5 and chigh1 > chigh3 and chigh1 <= chigh3 + 3 * box1 and clow0 >= clow2;
def iscatapultdown = clow3 == clow5 and clow1 < clow3 and clow1 >= clow3 - 3 * box1 and chigh0 <= chigh2;
def doubletopbreakout = trend1 == 1 and icloseprice > icloseprice[1] and icloseprice > chigh1 and icloseprice[1] <= chigh1;
def doubletopbreakoutrisingbottom = clow0 > clow2;
def doublebottombreakout = trend1 == -1 and icloseprice < icloseprice[1] and icloseprice < clow1 and icloseprice[1] >= clow1;
def doubletopbreakoutdecliningtop = chigh0 < chigh2;
def tribletopbreakout =
    trend1 == 1 and icloseprice > icloseprice[1] and icloseprice > chigh1 and icloseprice[1] <= chigh1 and chigh1 == chigh3;
def tripletopbreakoutascending =
    trend1 == 1 and icloseprice > icloseprice[1] and icloseprice > chigh1 and icloseprice[1] <= chigh1 and chigh1 == chigh3 + box1;
def triblebottombreakout =
    trend1 == -1 and icloseprice < icloseprice[1] and icloseprice < clow1 and icloseprice[1] >= clow1 and clow1 == clow3;
def triplebottombreakoutdescending =
    trend1 == -1 and icloseprice < icloseprice[1] and icloseprice < clow1 and icloseprice[1] >= clow1 and clow1 == clow3 - box1;

def ttb = tribletopbreakout;
def ttbas = tripletopbreakoutascending;
def tbb = triblebottombreakout;
def tbbdes = triplebottombreakoutdescending;
def dtb = doubletopbreakout;
def dtbrb = dtb and doubletopbreakoutrisingbottom;
def dbb = doublebottombreakout;
def dbbdt = dbb and doubletopbreakoutdecliningtop;


plot TripleTop = if ttb and arrow then low else na;
plot AscendingTripleTop = if ttbas and arrow then low else na;
plot TripleBottom = if tbb and arrow then high else na;
plot DescendingTripleBottom = if tbbdes and arrow then high else na;
plot SimpleBuy = if dtb and !dtbrb and arrow then low else na;
plot SimpleBuyRisingBottom = if dtbrb and arrow then low else na;
plot SimpleSell = if dbb and !dbbdt and arrow then high else na;
plot SimpleSellDecliningTop = if dbbdt and arrow then high else na;
plot CatapultUp = if dtb and iscatapultup and arrow then low else na;
plot CatapultDn = if dbb and iscatapultdown and arrow then high else na;

TripleTop.SetDefaultColor(Color.VIOLET);
AscendingTripleTop.SetDefaultColor(Color.CYAN);
SimpleBuy.SetDefaultColor(Color.VIOLET);
SimpleBuyRisingBottom.SetDefaultColor(Color.CYAN);
CatapultUp.SetDefaultColor(Color.CYAN);
TripleBottom.SetDefaultColor(Color.PLUM);
DescendingTripleBottom.SetDefaultColor(Color.MAGENTA);
SimpleSell.SetDefaultColor(Color.PLUM);
SimpleSellDecliningTop.SetDefaultColor(Color.MAGENTA);
CatapultDn.SetDefaultColor(Color.MAGENTA);

TripleTop.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
AscendingTripleTop.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
SimpleBuy.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
SimpleBuyRisingBottom.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
CatapultUp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
TripleBottom.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
DescendingTripleBottom.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
SimpleSell.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
SimpleSellDecliningTop.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
CatapultDn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);


AddChartBubble(ttb and bubble, low, "Triple Top", Color.DARK_GREEN, no); #title='Triple Top'
AddChartBubble(ttbas and bubble, low, "Triple Top\nAscending", Color.GREEN, no); # 'Ascending Triple Top'
AddChartBubble(tbb and bubble, high, "Triple Bottom", Color.PLUM); #title='Triple Bottom'
AddChartBubble(tbbdes and bubble, high, "Triple Bottom\nDescending", Color.MAGENTA);#title='Descending Triple Bottom'
AddChartBubble(dtb and !dtbrb and bubble, low, "Simple Buy", Color.DARK_GREEN, no); #title='Simple Buy'
AddChartBubble(dtbrb and bubble, low, "Rising Bottom", Color.GREEN, no); #'Simple Buy with Rising Bottom', 
AddChartBubble(dbb and !dbbdt and bubble, high, "Simple Sell", Color.PLUM); #title='Simple Sell'
AddChartBubble(dbbdt and bubble, high, "Declining Top", Color.MAGENTA); # 'Simple Sell with Declining Top'
AddChartBubble(dtb and iscatapultup and bubble, low, "Catapult", Color.CYAN, no); #title='Catapult'
AddChartBubble(dbb and iscatapultdown and bubble, high, "Catapult", Color.YELLOW); #title='Catapult'


#-- END of CODe
 
As2XI8lk
Is it possible to add the trend filter like it is described in the original post? I can’t find it in the TradingView source.

The trend filter you are requesting is called: ATRTrailingStop
It is a built-in ToS study: https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/A-B/ATRTrailingStop
that can be added to your chart.

Additionally, in the below link, you will find the many customizations that members have made to this popular study:
https://usethinkscript.com/threads/tos-atr-trailing-stop-in-thinkorswim.2095/
 
Its a complex code, can a scanner or watchlist be created for this indicator?

Yes, you are correct.
While no script is "too complex" to plot on the chart; Schwab does throttle the use of complex scripts in scans, watchlists, and conditional orders to prevent high load runs on its servers.

Many of the more complex scripts found on this forum, can only be used on charts.
They cannot be used in other widgets; such as: scans, watchlists, conditional orders, etc...
 
Thread starter Similar threads Forum Replies Date
P Decision Point Price Momentum Oscillator For ThinkOrSwim Custom 8
D Pivot Point Moving Averages For ThinkorSwim Custom 3

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
378 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top