I want to write some code for picking up "double tops / double bottoms" in tradestation? anybody can share some "double tops / double bottoms" code for me, thanks
I found a post here . https://futures.io/multicharts/1433...r-multicharts-tradestation-one-available.html It maybe a good start for me. I need to read more code. I want to add more code to this example code, considering if the bar is strong or not , I don't know if it is a good idea.
There is viable code for this in Mark Conway's Professional Stock Trading Book - he is very skilled at translating pattern recognition to code i.e. the essence of what a pattern really is for it to be coded. Another not so good in Pruitts Building Winning trading systems with TS. Try Googling Markos Katsanos to see if anything on his website. Key point is don't try and get too geometrically/eyeball precise with the code - keep it slightly fuzzy - you have to code for the very essence of what a patter is and accept there will be many alerts for patterns that fit the code but not your expectations.
These might need some non library functions if so get back to me with name. Conway double top Inputs: LookbackBars(20), Strength(4), RangeFactor(0.3), MALength(50); Variables: DTBar(-1), DTLine(-1), AlertString(""); DTBar = AcmeDoubleTop(LookbackBars, Strength, RangeFactor); If DTBar <> -1 Then Begin DTLine = TL_New(Date[0], Time[0], High, Date[DTBar], Time[DTBar], High); If DTLine >= 0 Then Begin TL_SetColor(DTLine, Magenta); TL_SetSize(DTLine, 1); End; AlertString = "Acme Double Top"; If DMIPlus(LookbackBars) > DMIMinus(LookbackBars) Then Condition1 = AbsValue(Low - Average(Close, MALength)) <= RangeFactor * Volatility(LookbackBars) Else If DMIPlus(LookbackBars) < DMIMinus(LookbackBars) Then Condition1 = AbsValue(High - Average(Close, MALength)) <= RangeFactor * Volatility(LookbackBars); If Condition1 Then AlertString = AlertString + " Near " + NumToStr(MALength, 0) + " Bar Moving Average"; If AlertEnabled or Condition1 Then Alert(AlertString); End; ======================================================= conway double bottom Inputs: LookbackBars(20), Strength(4), RangeFactor(0.3), MALength(50); Variables: DBBar(-1), DBLine(-1), AlertString(""); DBBar = AcmeDoubleBottom(LookbackBars, Strength, RangeFactor); If DBBar <> -1 Then Begin DBLine = TL_New(Date[0], Time[0], Low, Date[DBBar], Time[DBBar], Low); If DBLine >= 0 Then Begin TL_SetColor(DBLine, Magenta); TL_SetSize(DBLine, 1); End; AlertString = "Acme Double Bottom"; If DMIPlus(LookbackBars) > DMIMinus(LookbackBars) Then Condition1 = AbsValue(Low - Average(Close, MALength)) <= RangeFactor * Volatility(LookbackBars) Else If DMIPlus(LookbackBars) < DMIMinus(LookbackBars) Then Condition1 = AbsValue(High - Average(Close, MALength)) <= RangeFactor * Volatility(LookbackBars); If Condition1 Then AlertString = AlertString + " Near " + NumToStr(MALength, 0) + " Bar Moving Average"; If AlertEnabled or Condition1 Then Alert(AlertString); End; ===================================================== Pruitt Dbl btm Vars: state(0),tenDayATR(0),barCount(0),firstLowPivot(0); Vars: secLowPivot(0),firstLowPivotPos(0),secLowPivotPos(0); tenDayATR= AvgTrueRange(10); if(Low[1] =Lowest(Low[1],20) and state = 0 and Low > Low[1]) then begin state = 1; barCount = 0; firstLowPivot = Low[1]; firstLowPivotPos = barNumber; end; if(state = 1) then begin barCount = barCount + 1; if(High[1] = Highest(High[1],5) and High < High[1]) then begin state = 2; barCount = barCount - 1; {subtract one bar - we will add one in state 2} end; if(Low < firstLowPivot) then state = 0; end; if(state = 2)then begin barcount = barCount + 1; if(barCount > 30) then state = 0; {pattern not completed within 30 bars} if(Low[2]>Low[1] and Low > Low[1] and (Low[1] < firstLowPivot + tenDayATR and Low[1] > firstLowPivot - tenDayATR)) then begin state = 3; secLowPivot = Low[1]; secLowPivotPos = barNumber; barCount = barCount - 1; end; end; if(state = 3) then begin barCount = barCount + 1; if(barCount > 30) then state = 0; if(High > secLowPivot + 2*tenDayAtr) then state = 4; if(Low < secLowPivot) then state = 0; end; if(state = 4) then begin Plot1[BarNumber - firstLowPivotPos+1](firstLowPivot,"DoubleBottom"); Plot2[BarNumber - secLowPivotPos+1](secLowPivot,"DoubleBottom"); state = 0; {Job is done - start over} end; =================================================== Pruitt dbl top (maybe I did the reversal on this) Vars: state(0),tenDayATR(0),barCount(0),firstLowPivot(0); Vars: secLowPivot(0),firstLowPivotPos(0),secLowPivotPos(0); tenDayATR= AvgTrueRange(10); if(Low[1] =Lowest(Low[1],20) and state = 0 and Low > Low[1]) then begin state = 1; barCount = 0; firstLowPivot = Low[1]; firstLowPivotPos = barNumber; end; if(state = 1) then begin barCount = barCount + 1; if(High[1] = Highest(High[1],5) and High < High[1]) then begin state = 2; barCount = barCount - 1; {subtract one bar - we will add one in state 2} end; if(Low < firstLowPivot) then state = 0; end; if(state = 2)then begin barcount = barCount + 1; if(barCount > 30) then state = 0; {pattern not completed within 30 bars} if(Low[2]>Low[1] and Low > Low[1] and (Low[1] < firstLowPivot + tenDayATR and Low[1] > firstLowPivot - tenDayATR)) then begin state = 3; secLowPivot = Low[1]; secLowPivotPos = barNumber; barCount = barCount - 1; end; end; if(state = 3) then begin barCount = barCount + 1; if(barCount > 30) then state = 0; if(High > secLowPivot + 2*tenDayAtr) then state = 4; if(Low < secLowPivot) then state = 0; end; if(state = 4) then begin Plot1[BarNumber - firstLowPivotPos+1](firstLowPivot,"DoubleBottom"); Plot2[BarNumber - secLowPivotPos+1](secLowPivot,"DoubleBottom"); state = 0; {Job is done - start over} end; ===================================================== Misc DBL bottom (don't think I ever tested this) Inputs: Length(100), MinStrength(3), MaxStrength(10), NoticeBar(2), MinPctRunToBottom(20), NeckLineBreak(1), ThinFan(1), BottomColor(Blue); variables: msg(""), ret_val(0), indicator_name("WBottom"), MySwingStrength(0), FoundIt(false), MyBottomColor(0); Variables: F1(0.618), F2(0.786), F3(1.27), F4(1.618), P1Bar(-1), { Peak Bar 1 } P2Bar(-1), { Peak Bar 2 } T1Bar(-1), { Trough Bar 1 } T2Bar(-1), { Trough Bar 2 } P1(0.0), P2(0.0), T1(0.0), T2(0.0), PTValid(False), HLValid(False), InZone(False), GD(0.0), XA(0.0), AB(0.0), BC(0.0), CD(0.0), AD(0.0), C1(False), C2(False), C3(False), C4(False), ABdXA(0.0), BCdAB(0.0), CDdBC(0.0), ADdXA(0.0), TL1(-1), TL2(-1), TL3(-1), TL4(-1), TL5(-1), TL6(-1), TLsize(1); { Find 2 swing highs and 2 swing lows (i.e. peak bars and trough bars). Note that we allow for the strength of the most recent swing to be different so that "early detection" can be dialed in. In a "W" bottom, the time order of the peaks and troughs will be: P2 T2 P1 T1 } FoundIt = False; for MySwingStrength = MaxStrength downto MinStrength begin {MyBottomColor = MySwingStrength + 6;} { add 6 to get past both green and red for contrast } MyBottomColor = MySwingStrength ; T1Bar = -1 ; P1Bar = SwingHighBar(1, High, MySwingStrength, Length); { most recent swing high } P2Bar = SwingHighBar(2, High, MySwingStrength, Length); { 2nd most recent swing high } {T1Bar = SwingLowBar(1, Low, MySwingStrength, Length); { most recent swing low }} Value1 = Pivot( Low, Length, MySwingStrength, NoticeBar, 1, -1, T1, T1Bar ) ; T2Bar = SwingLowBar(1, Low, MySwingStrength, Length)[T1Bar]; { 2nd most recent swing low } If P1Bar <> -1 and P2Bar <> -1 and T1Bar <> -1 and T2Bar <> -1 Then Begin { Test for "W" bottom } T2 = Low[T2Bar]; P2 = High[P2Bar]; T1 = Low[T1Bar]; P1 = High[P1Bar]; GD = High; { verify peak-trough-peak-trough sequence that forms a "W" } PTValid = T1Bar < P1Bar and P1Bar < T2Bar and T2Bar < P2Bar; { verify 2nd peak below first, and 2nd trough above first } HLValid = T1 > T2 and P1 < P2 and T1 < P1; {InZone = GD > P1 and GD < P2 and T2 <= Lowest(Low, P2Bar);} { verify T2 was the lowest point in the formation, and rise from T1 has begun } InZone = GD > T1 and GD < P2 and T2 <= Lowest(Low, P2Bar); { verify minimum percentage run to bottom } InZone = InZone and T2 < (P2 - PercentOf(P2,MinPctRunToBottom)) ; if NeckLineBreak = 1 then InZone = InZone and close > P1 ; if ThinFan = 1 then InZone = InZone and close > close[1] ; If PTValid and HLValid and InZone Then Begin {msg = "W hit" + " MySwingStrength: " + NumToStr(MySwingStrength,0) + " T1Bar: " + NumToStr(T1Bar,0) ; ret_val = SBJ_pmsg( indicator_name, msg);} if NeckLineBreak = 1 then Alert("W bottom complete"); XA = P2 - T2; AB = P1 - T2; BC = P1 - T1; CD = GD - T1; AD = GD - T2; { This commented out code is from the Gartley 222, and shows one way of performing further analysis on a "W" } { ABdXA = AB / XA; {AB should be 61.8% of XA} C1 = ABdXA > F1 - Tolerance and ABdXA < F1 + Tolerance; BCdAB = BC / AB; {BC should be 61.8-78.6% of AB} C2 = BCdAB > F1 - Tolerance and BCdAB < F2 + Tolerance; CDdBC = CD / BC; {CD should be 127-161.8% of BC} C3 = CDdBC > F3 - Tolerance and CDdBC < F4 + Tolerance; ADdXA = AD / XA; {AD should be 78.6% of XA} C4 = ADdXA > F2 - Tolerance and ADdXA < F2 + Tolerance; } { if the proportions are correct, to within Tolerance, plot the formation } {If C1 and C2 and C3 and C4 Then Begin} If True Then Begin TL1 = TL_New(Date[P2Bar], Time[P2Bar], P2, Date[T2Bar], Time[T2Bar], T2); If TL1 >= 0 Then Begin TL_SetColor(TL1, MyBottomColor); TL_SetStyle(TL1, Tool_Solid); TL_SetSize(TL1, TLsize); End; TL2 = TL_New(Date[T2Bar], Time[T2Bar], T2, Date[P1Bar], Time[P1Bar], P1); If TL2 >= 0 Then Begin TL_SetColor(TL2, MyBottomColor); TL_SetStyle(TL2, Tool_Solid); TL_SetSize(TL2, TLsize); End; TL3 = TL_New(Date[P1Bar], Time[P1Bar], P1, Date[T1Bar], Time[T1Bar], T1); If TL3 >= 0 Then Begin TL_SetColor(TL3, MyBottomColor); TL_SetStyle(TL3, Tool_Solid); TL_SetSize(TL3, TLsize); End; TL4 = TL_New(Date[T1Bar], Time[T1Bar], T1, Date, Time, GD); If TL4 >= 0 Then Begin TL_SetColor(TL4, MyBottomColor); TL_SetStyle(TL4, Tool_Dotted); TL_SetSize(TL4, TLsize); End; End; End; End; End; ====================================================== Misc DBL Top Inputs: Length(100), MinStrength(3), MaxStrength(10), NoticeBar(2), MinPctRunToTop(50), NeckLineBreak(1), ThinFan(1), TopColor(Red); variables: msg(""), ret_val(0), indicator_name("MTop"), MySwingStrength(0), FoundIt(false), MyTopColor(0); Variables: F1(0.618), F2(0.786), F3(1.27), F4(1.618), P1Bar(-1), { Peak Bar 1 } P2Bar(-1), { Peak Bar 2 } T1Bar(-1), { Trough Bar 1 } T2Bar(-1), { Trough Bar 2 } P1(0.0), P2(0.0), T1(0.0), T2(0.0), PTValid(False), HLValid(False), InZone(False), GD(0.0), XA(0.0), AB(0.0), BC(0.0), CD(0.0), AD(0.0), C1(False), C2(False), C3(False), C4(False), ABdXA(0.0), BCdAB(0.0), CDdBC(0.0), ADdXA(0.0), TL1(-1), TL2(-1), TL3(-1), TL4(-1), TL5(-1), TL6(-1), TLsize(1); { Find 2 swing highs and 2 swing lows (i.e. peak bars and trough bars). Note that we allow for the strength of the most recent swing to be different so that "early detection" can be dialed in. In an "M" top the time order of peaks and troughs will be: T2 P2 T1 P1 .} FoundIt = False; {for MySwingStrength = MinStrength to MaxStrength begin} for MySwingStrength = MaxStrength downto MinStrength begin {MyTopColor = MySwingStrength + 6;} { add 6 to get past both green and red for contrast } MyTopColor = mod(MySwingStrength,16) ; { modulo needed to accomodate very large SwingStrengths } {P1Bar = SwingHighBar(1, High, MySwingStrength, Length); { most recent swing high }} Value1 = Pivot( High, Length, MySwingStrength, NoticeBar, 1, 1, P1, P1Bar ) ; P2Bar = SwingHighBar(1, High, MySwingStrength, Length)[P1Bar]; { 2nd most recent swing high } T1Bar = SwingLowBar(1, Low, MySwingStrength, Length); { most recent swing low } T2Bar = SwingLowBar(2, Low, MySwingStrength, Length); { 2nd most recent swing low } If P1Bar <> -1 and P2Bar <> -1 and T1Bar <> -1 and T2Bar <> -1 Then Begin { Test for "M" top } T2 = Low[T2Bar]; P2 = High[P2Bar]; T1 = Low[T1Bar]; P1 = High[P1Bar]; GD = Low; { verify trough-peak-trough-peak sequence that forms an "M" } PTValid = P1Bar < T1Bar and T1Bar < P2Bar and P2Bar < T2Bar; { verify 2nd peak below first, and 2nd trough above first } HLValid = P1 < P2 and T1 > T2 and P1 > T1; {InZone = GD < T1 and GD > T2 and P2 >= Highest(High, T2Bar);} { verify P2 was the highest point in the formation, and decline from P1 has begun } InZone = GD < P1 and GD > T2 and P2 >= Highest(High, T2Bar); { verify minimum percentage run to top } InZone = InZone and P2 > (T2 + PercentOf(T2,MinPctRunToTop)) ; { verify move below neckline } if NeckLineBreak = 1 then InZone = InZone and close < T1 ; if ThinFan = 1 then InZone = InZone and close < close[1] ; If PTValid and HLValid and InZone Then Begin FoundIt = True; if NeckLineBreak = 1 then Alert("M Top complete"); XA = P2 - T2; AB = P2 - T1; BC = P1 - T1; CD = P1 - GD; AD = P2 - GD; { This commented out code is from the Gartley 222, and shows one way of performing further analysis on an "M" } { ABdXA = AB / XA; {AB should be 61.8% of XA} C1 = ABdXA > F1 - Tolerance and ABdXA < F1 + Tolerance; BCdAB = BC / AB; {BC should be 61.8-78.6% of AB} C2 = BCdAB > F1 - Tolerance and BCdAB < F2 + Tolerance; CDdBC = CD / BC; {CD should be 127-161.8% of BC} C3 = CDdBC > F3 - Tolerance and CDdBC < F4 + Tolerance; ADdXA = AD / XA; {AD should be 78.6% of XA} C4 = ADdXA > F2 - Tolerance and ADdXA < F2 + Tolerance; } { if the proportions are correct, to within Tolerance, plot the formation } {If C1 and C2 and C3 and C4 Then Begin} If True Then Begin TL1 = TL_New(Date[T2Bar], Time[T2Bar], T2, Date[P2Bar], Time[P2Bar], P2); If TL1 >= 0 Then Begin TL_SetColor(TL1, MyTopColor); TL_SetStyle(TL1, Tool_Solid); TL_SetSize(TL1, TLsize); End; TL2 = TL_New(Date[P2Bar], Time[P2Bar], P2, Date[T1Bar], Time[T1Bar], T1); If TL2 >= 0 Then Begin TL_SetColor(TL2, MyTopColor); TL_SetStyle(TL2, Tool_Solid); TL_SetSize(TL2, TLsize); if MinStrength = MaxStrength then begin Value1 = Text_New(Date[P2Bar], Time[P2Bar], low[P2Bar], NumToStr(MySwingStrength,0)) ; Text_SetColor(value1, MyTopColor); end; End; TL3 = TL_New(Date[T1Bar], Time[T1Bar], T1, Date[P1Bar], Time[P1Bar], P1); If TL3 >= 0 Then Begin TL_SetColor(TL3, MyTopColor); TL_SetStyle(TL3, Tool_Solid); TL_SetSize(TL3, TLsize); End; TL4 = TL_New(Date[P1Bar], Time[P1Bar], P1, Date, Time, GD); If TL4 >= 0 Then Begin TL_SetColor(TL4, MyTopColor); TL_SetStyle(TL4, Tool_Solid); TL_SetSize(TL4, TLsize); End; End; End; End; {if FoundIt then MySwingStrength = 0 ; } { found the pattern, we're done } End;
This TradeStation code is now all open source: https://github.com/mrconway/TradeStation The book is online here: https://gumroad.com/products/hLicK