Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
- // © reees
- //@version=5
- // @description Harmonic XABCD Pattern object and associated methods. Easily validate, draw, and get information about harmonic patterns. See example code at the end of the script for details.
- library("Obj_XABCD_Harmonic",true)
- import reees/TA/69 as t
- import reees/Draw/22 as draw
- import reees/Utilities/4 as u
- // @type Validation and scoring parameters for a Harmonic Pattern object (xabcd_harmonic)
- // @field pct_error Allowed % error of leg retracement ratio versus the defined harmonic ratio
- // @field pct_asym Allowed leg length/period asymmetry % (a leg is considered invalid if it is this % longer or shorter than the average length of the other legs)
- // @field types Array of pattern types to validate (1=Gartley, 2=Bat, 3=Butterfly, 4=Crab, 5=Shark, 6=Cypher)
- // @field w_e Weight of ratio % error (used in score calculation, dft = 1)
- // @field w_p Weight of PRZ confluence (used in score calculation, dft = 1)
- // @field w_d Weight of Point D / PRZ confluence (used in score calculation, dft = 1)
- export type harmonic_params
- float pct_error = 15.0
- float pct_asym = 250.0
- int[] types
- float w_e = 1.0
- float w_p = 1.0
- float w_d = 1.0
- // @function Create a harmonic parameters object (used by xabcd_harmonic object for pattern validation and scoring).
- // @param pct_error Allowed % error of leg retracement ratio versus the defined harmonic ratio
- // @param pct_asym Allowed leg length/period asymmetry % (a leg is considered invalid if it is this % longer or shorter than the average length of the other legs)
- // @param types Array of pattern types to validate (1=Gartley, 2=Bat, 3=Butterfly, 4=Crab, 5=Shark, 6=Cypher)
- // @param w_e Weight of ratio % error (used in score calculation, dft = 1)
- // @param w_p Weight of PRZ confluence (used in score calculation, dft = 1)
- // @param w_d Weight of Point D / PRZ confluence (used in score calculation, dft = 1)
- // @returns harmonic_params object instance. It is recommended to store and reuse this object for multiple xabcd_harmonic objects rather than creating new params objects unnecessarily.
- export init_params(float pct_error=15.0, float pct_asym=250.0, int[] types=na, float w_e=1, float w_p=1, float w_d=1) =>
- harmonic_params.new(pct_error,
- pct_asym,
- na(types)?array.from(1,2,3,4,5,6):types,
- w_e,
- w_p,
- w_d)
- // @type Harmonic Pattern object
- // @field bull Bullish pattern flag
- // @field tp Pattern type (1=Gartley, 2=Bat, 3=Butterfly, 4=Crab, 5=Shark, 6=Cypher)
- // @field xX Point X bar index
- // @field xY Point X price/level
- // @field aX Point A bar index
- // @field aY Point A price/level
- // @field bX Point B bar index
- // @field bY Point B price/level
- // @field cX Point C bar index
- // @field cY Point C price/level
- // @field dX Point D bar index
- // @field dY Point D price/level
- // @field r_xb XAB ratio
- // @field re_xb XAB ratio % error
- // @field r_ac ABC ratio
- // @field re_ac ABC ratio % error
- // @field r_bd BCD ratio
- // @field re_bd BCD ratio % error
- // @field r_xd XAD or XCD ratio, depending on pattern type
- // @field re_xd XAD ratio % error
- // @field score Total score
- // @field score_eAvg Avg % error
- // @field score_prz PRZ score
- // @field score_eD Point D/PRZ confluence score
- // @field prz_bN BCD retracement near
- // @field prz_bF BCD retracement far
- // @field prz_xN XAD/XCD retracement near
- // @field prz_xF XAD/XCD retracement far
- // @field t1Hit Target 1 flag
- // @field t1 Target 1 level
- // @field t2Hit Target 2 flag
- // @field t2 Target 2 level
- // @field sHit Stop flag
- // @field stop Stop level
- // @field entry Entry level
- // @field eHit Entry flag
- // @field eX Entry bar index
- // @field eY Enty price/level
- // @field pLines Pattern lines
- // @field pLabel Pattern label
- // @field pid Pattern ID
- // @field params harmonic_params for validating and scoring the pattern
- export type xabcd_harmonic
- // *** Type ***
- bool bull // Bullish flag
- int tp // Type (1=Gartley, 2=Bat, 3=Butterfly, 4=Crab, 5=Shark, 6=Cypher)
- // *** Coordinates ***
- int xX
- float xY
- int aX
- float aY
- int bX
- float bY
- int cX
- float cY
- int dX
- float dY
- // *** Values ***
- float r_xb // XAB ratio
- float re_xb // XAB ratio % error
- float r_ac // etc...
- float re_ac
- float r_bd
- float re_bd
- float r_xd // XAD or XCD, depending on pattern type
- float re_xd
- // Score
- float score // total score
- float score_eAvg // avg % error
- // float sym // leg length symmetry
- float score_prz // PRZ score
- float score_eD // Point D/PRZ confluence score
- // PRZ
- float prz_bN // BCD retracement near
- float prz_bF // BCD retracement far
- float prz_xN // XAD/XCD retracement near
- float prz_xF // XAD/XCD retracement far
- // State flags/values
- bool t1Hit // target 1 flag
- float t1 // target 1 level
- bool t2Hit // target 2 flag
- float t2 // target 2 level
- bool sHit // stop-loss flag
- float stop // stop-loss level
- float entry // entry level
- bool eHit // entry flag
- int eX // entry bar index
- float eY // entry level
- // *** Drawings ***
- line[] pLines
- label pLabel
- //
- string pid // Pattern ID
- harmonic_params params // Validation parameters
- //*******************************************************************
- // Object functions/methods
- //*******************************************************************
- // (private) Pattern ID
- pid(p) =>
- str.tostring(p.tp) + "_"
- + str.tostring(p.xX) + "_"
- + str.tostring(p.aX) + "_"
- + str.tostring(p.bX) + "_"
- + str.tostring(p.cX) + "_"
- + str.tostring(p.dX)
- // (private) Set pattern ID
- set_pid(p) =>
- p.pid := pid(p)
- // (private) Get the highest scoring pattern type. It's unlikely that a complete pattern will be valid for more than one harmonic,
- // but it's possible (especially if your validation parameters are more inclusive).
- highestScoringType(tps,params,xX,xY,aX,aY,bX,bY,cX,cY,dX,dY) =>
- int hst = na
- float hs=0.0, float hs1=0.0, float hs2=0.0, float hs3=0.0
- for tp in tps
- [eavg,asym,eD,prz,_,_,_] = t.harmonic_xabcd_score(tp+1,xX,xY,aX,aY,bX,bY,cX,cY,dX,dY)
- s = t.harmonic_xabcd_scoreTot(asym,eavg,prz,eD,tp+1,0.0,params.w_e,params.w_p,params.w_d)
- if s>hs
- hst := tp+1
- hs := s
- hs1 := eavg
- hs2 := eD
- hs3 := prz
- [hst,hs,hs1,hs2,hs3]
- validAbcd(bull,aY,bY,cY,dY) =>
- if bull
- aY > bY and cY > bY and (na(dY) or cY > dY)
- else
- aY < bY and cY < bY and (na(dY) or cY < dY)
- // @function Initialize an xabcd_harmonic object instance.
- // If the pattern is valid, an xabcd_harmonic object instance is returned. If you want to specify your
- // own validation and scoring parameters, you can do so by passing a harmonic_params object (params).
- // Or, if you prefer to do your own validation, you can explicitly pass the harmonic pattern type (tp)
- // and validation will be skipped. You can also pass in an existing xabcd_harmonic instance if you wish
- // to re-initialize it (e.g. for re-validation and/or re-scoring).
- // @param xX Point X bar index
- // @param xY Point X price/level
- // @param aX Point A bar index
- // @param aY Point A price/level
- // @param bX Point B bar index
- // @param bY Point B price/level
- // @param cX Point C bar index
- // @param cY Point C price/level
- // @param dX Point D bar index
- // @param dY Point D price/level
- // @param params harmonic_params used to validate and score the pattern. Validation will be skipped if a type (tp) is explicitly passed in.
- // @param tp Pattern type
- // @param p xabcd_harmonic object instance to initialize (optional, for re-validation/re-scoring)
- // @returns xabcd_harmonic object instance if a valid harmonic, else na
- export init(int xX=na, float xY=na, int aX=na, float aY=na, int bX=na, float bY=na, int cX=na, float cY=na,int dX=na,float dY=na,
- harmonic_params params=na, int tp=na, xabcd_harmonic p=na) =>
- xabcd_harmonic obj = p
- int validType = tp>0 and tp<7 ? tp : na
- float[] scores = array.new_float()
- par = na(params) ? init_params() : params
- // Validate XABCD pattern
- bull = xY < aY
- if validAbcd(bull,aY,bY,cY,dY) == false
- validType := na
- // Validate Harmonic pattern
- else if na(validType)
- tps = u.intToBoolArr(par.types,7)
- [f,h1,h2,h3,h4,h5,h6] =
- t.harmonic_xabcd_validate(xX,xY,aX,aY,bX,bY,cX,cY,dX,dY,par.pct_error,par.pct_asym,
- array.get(tps,1),array.get(tps,2),array.get(tps,3),array.get(tps,4),array.get(tps,5),array.get(tps,6))
- intTps = u.boolToIntArr(array.from(h1,h2,h3,h4,h5,h6))
- if array.size(intTps) == 1
- validType := array.pop(intTps)+1
- else if array.size(intTps) > 1
- [hst,s,s1,s2,s3] = highestScoringType(intTps,par,xX,xY,aX,aY,bX,bY,cX,cY,dX,dY)
- scores := array.from(s,s1,s2,s3)
- validType := hst
- else
- validType := na
- // Create object if we have a valid type (or type was explicitly passed)
- if not na(validType)
- obj := na(p) ? xabcd_harmonic.new() : p
- [xbr,xbre] = t.harmonic_xabcd_rAndE(validType,"xab",aY-bY,aY-xY)
- [acr,acre] = t.harmonic_xabcd_rAndE(validType,"abc",cY-bY,aY-bY)
- [bdr,bdre] = t.harmonic_xabcd_rAndE(validType,"bcd",cY-dY,cY-bY)
- [xdr,xdre] = t.harmonic_xabcd_rAndE(validType,"xad",aY-dY,aY-xY)
- if array.size(scores) == 0
- [eavg,asym,eD,przscore,_,cpl1,cpl2] = t.harmonic_xabcd_score(validType,xX,xY,aX,aY,bX,bY,cX,cY,dX,dY)
- s = t.harmonic_xabcd_scoreTot(asym,eavg,przscore,eD,validType,0.0,par.w_e,par.w_p,par.w_d)
- scores := array.from(s,eavg,eD,przscore)
- [bcN,bcF,xaN,xaF] = t.harmonic_xabcd_prz(validType,xY,aY,bY,cY)
- obj.bull := bull
- obj.xX := xX
- obj.xY := xY
- obj.aX := aX
- obj.aY := aY
- obj.bX := bX
- obj.bY := bY
- obj.cX := cX
- obj.cY := cY
- obj.dX := dX
- obj.dY := dY
- obj.tp := validType
- obj.r_xb := xbr
- obj.re_xb := xbre
- obj.r_ac := acr
- obj.re_ac := acre
- obj.r_bd := bdr
- obj.re_bd := bdre
- obj.r_xd := xdr
- obj.re_xd := xdre
- obj.score := array.get(scores,0)
- obj.score_eAvg := array.get(scores,1)
- obj.score_prz := array.get(scores,3)
- obj.score_eD := array.get(scores,2)
- obj.prz_bN := bcN
- obj.prz_bF := bcF
- obj.prz_xN := xaN
- obj.prz_xF := xaF
- obj.pLines := array.new_line()
- set_pid(obj)
- obj
- // *** Get/Set ***
- // @function Get the pattern name
- // @param p Instance of xabcd_harmonic object
- // @returns Pattern name (string)
- export get_name(xabcd_harmonic p) =>
- a = p.bull ? "Bullish" : "Bearish"
- b = switch p.tp
- 1 => "Gartley"
- 2 => "Bat"
- 3 => "Butterfly"
- 4 => "Crab"
- 5 => "Shark"
- 6 => "Cypher"
- => "Undefined harmonic"
- a + " " + b
- // @function Get the pattern symbol
- // @param p Instance of xabcd_harmonic object
- // @returns Pattern symbol (1 byte string)
- export get_symbol(xabcd_harmonic p) =>
- t.harmonic_xabcd_symbol(p.tp)
- // @function Get the Pattern ID. Patterns of the same type with the same coordinates will have the same Pattern ID.
- // @param p Instance of xabcd_harmonic object
- // @returns Pattern ID (string)
- export get_pid(xabcd_harmonic p) =>
- if na(p.pid)
- set_pid(p)
- p.pid
- // @function Set value for a target. Use the calc_target parameter to automatically calculate the target for a specific harmonic ratio.
- // @param p Instance of xabcd_harmonic object
- // @param target Target (1 or 2)
- // @param target_lvl Target price/level (required if calc_target is not specified)
- // @param calc_target Target to auto calculate (required if target is not specified)
- // Options: [".382 AD", ".5 AD", ".618 AD", "1.272 AD", "1.618 AD"
- // ".382 XA", ".5 XA" ,".618 XA", "1.272 XA", "1.618 XA",
- // ".382 CD", ".5 CD", ".618 CD", "1.272 CD", "1.618 CD",
- // "A", "B", "C"]
- // @returns Target price/level (float)
- export set_target(xabcd_harmonic p, int target=1, float target_lvl=na, string calc_target=".618 AD") =>
- if na(target_lvl)
- [t,_,_] = t.harmonic_xabcd_targets(p.xY,p.aY,p.bY,p.cY,p.dY,calc_target)
- if target==1
- p.t1 := t
- else
- p.t2 := t
- else
- if target==1
- p.t1 := target_lvl
- else
- p.t2 := target_lvl
- // *** Functions ***
- // @function Erase the pattern
- // @param p Instance of xabcd_harmonic object
- // @returns p
- export erase_pattern(xabcd_harmonic p) =>
- for l in p.pLines
- line.delete(l)
- p.pLines := array.new_line()
- p
- // @function Draw the pattern
- // @param p Instance of xabcd_harmonic object
- // @returns Pattern lines
- // [l1,l2,l3,l4,l5,l6]
- export draw_pattern(xabcd_harmonic p, color clr) =>
- erase_pattern(p)
- [lower,higher] = t.harmonic_xabcd_przClosest(p.prz_bN,p.prz_bF,p.prz_xN,p.prz_xF)
- float iE = na(p.dX) ? (p.bull?higher:lower) : na // potential point D for incomplete pattern
- [l1,l2,l3,l4,l5,l6] = draw.xabcd(p.xX,p.xY,p.aX,p.aY,p.bX,p.bY,p.cX,p.cY,p.dX,p.dY,iE,p.bull,color.new(clr,20),color.new(clr,20))
- p.pLines := array.from(l1,l2,l3,l4,l5,l6)
- [l1,l2,l3,l4,l5,l6]
- // @function Erase the pattern label
- // @param p Instance of xabcd_harmonic object
- // @returns p
- export erase_label(xabcd_harmonic p) =>
- if not na(p.pLabel)
- label.delete(p.pLabel)
- p
- // @function Draw the pattern label. Default text is the pattern name.
- // @param p Instance of xabcd_harmonic object
- // @param txt Label text
- // @param tooltip Tooltip text
- // @param clr Label color
- // @param txt_clr Text color
- // @returns Label
- export draw_label(xabcd_harmonic p, color clr=color.gray, color txt_clr=color.white, string txt=na, string tooltip=na) =>
- erase_label(p)
- lbstyle = p.bull ? label.style_label_up : label.style_label_down
- incLbstyle = p.bull ? label.style_label_down : label.style_label_up
- t = not na(txt) ? txt : get_name(p)
- lbl =
- if not na(p.dX) // Completed pattern
- label.new(p.dX,p.dY,text=t,textcolor=txt_clr,size=size.small,style=lbstyle,tooltip=tooltip,color=clr)
- else // Incomplete pattern
- if array.size(p.pLines)>0
- l4 = array.get(p.pLines,3)
- not na(l4) ? label.new(line.get_x2(l4),line.get_y2(l4),text=t,tooltip=tooltip,textcolor=txt_clr,size=size.small,style=lbstyle,color=clr)
- : label.new(p.cX,p.cY,text=t,tooltip=tooltip,textcolor=txt_clr,size=size.small,style=lbstyle,color=clr)
- else
- label.new(p.cX,p.cY,text=t,tooltip=tooltip,textcolor=txt_clr,size=size.small,style=lbstyle,color=clr)
- p.pLabel := lbl
- //********************************
- // Example / Test code
- //********************************
- // Use your preferred zig-zag method to get the XABCD pattern coordinates.
- // Coordinates are hard-coded here for simplicity of the example.
- // ADA 4h gartley
- var int xX = 10681
- var float xY = .344
- var int aX = 10714
- var float aY = .296
- var int bX = 10743
- var float bY = .322
- var int cX = 10752
- var float cY = .3
- var int dX = 10796
- var float dY = .329
- if bar_index == 10796
- // *** Instantiate the xabcd_harmonic ***
- // [0] Simply pass in the pattern coordinates and the pattern will be automatically validated.
- // If the pattern is valid, an xabcd_harmonic object instance is returned. If you prefer to do
- // your own validation, you can skip it by explicitly passing a type (tp) to the init() function.
- // Or, if you want to specify the validation and scoring parameters, you can do so by passing a
- // harmonic_params object to the init() function.
- pat = init(xX, xY, aX, aY, bX, bY, cX, cY, dX, dY)
- // pat = init(xX, xY, aX, aY, bX, bY, cX, cY) // pattern can be incomplete, i.e. point D not yet established
- if not na(pat)
- // *** When a valid xabcd_harmonic is initialized... ***
- // [1] We know what type of harmonic pattern we have (pat.tp field)
- name = get_name(pat) + " (" + get_symbol(pat) + ")" // get pattern name and symbol with exported functions
- u.print(name)
- // [2] PRZ levels are automatically calculated
- // e.g. pat.prz_bN, pat.prz_xN, pat.prz_bF, pat.prz_xF
- draw.level(pat.prz_bN,na(pat.dX)?pat.cX:pat.dX,length=100,padding=.5,txt="Near BC PRZ level") // illustrate near BC PRZ retracement level
- draw.level(pat.prz_xN,na(pat.dX)?pat.cX:pat.dX,length=100,padding=.5,txt="Near XA PRZ level") // illustrate near XA PRZ retracement level
- // [3] Scores are calculated to represent the quality of the harmonic pattern
- // e.g. pat.score, pat.score_prz, pat.score_eAvg, pat.score_eD
- u.print(("Leg avg retracement % error: " + str.tostring(pat.score_eAvg*100,"#.#") + "%"),position.bottom_left) // illustrate avg leg retracement % error score
- // [4] Easily draw the pattern and a label
- draw_pattern(pat, color.red)
- draw_label(pat, color.new(color.red,70))
- // [5] Set targets. You can specify the a specific target level, or have the target automatically calculated for a specific
- // harmonic retracement ratio of a pattern leg
- // e.g. ".618 AD" or "1.272 XA"
- set_target(pat, 1, calc_target=".618 AD")
- set_target(pat, 2, calc_target="1.272 XA")
- draw.level(pat.t1,na(pat.dX)?pat.cX:pat.dX,length=100,padding=.5,txt="Target 1") // illustrate target 1
- draw.level(pat.t2,na(pat.dX)?pat.cX:pat.dX,length=100,padding=.5,txt="Target 2") // illustrate target 2
- //erase_pattern(pat)
- //erase_label(pat)
- // [6] Set stop/entry values, and track trades with state flags
- // e.g. pat.stop, pat.entry, pat.sHit, pat.eHit, pat.t1Hit, pat.t2Hit
Advertisement
Add Comment
Please, Sign In to add comment