{ FindPrediction strategy This strategy is designed to help find the best set of indicators for predicting a trend pattern on intraday data, as defined by the function GetTrendPattern. The procedure is to use the TS optimizer to iterate through the combinations of indicators, as determined by the inputs to this strategy. The inputs c1,..., c6 should be set during the optimization to take on the values -1, 0, and 1. The values 1 and -1 determine the sign of the indicator, which is used to identify both up and down trends. A value of zero removes the indicator from consideration. For each iteration, the strategy computes the accuracy of the prediction. After the optimization, the results can be copied to a spreadsheet and sorted by prediction accuracy to find the best set of indicators. Mike Bryant Breakout Futures www.BreakoutFutures.com Copyright 2009 Breakout Futures } Input: c1 (0), { Coefficient of indicator 1 } c2 (0), { Coefficient of indicator 2 } c3 (0), { Coefficient of indicator 3 } c4 (0), { Coefficient of indicator 4 } c5 (0), { Coefficient of indicator 5 } c6 (0), { Coefficient of indicator 6 } NMA1 (10), { Length of moving average 1 } NMA2 (50), { Length of moving average 2 } NMA3 (135), { Length of moving average 3 } NATR (27), { Period for average true range } NRnge (30), { Period for computing average daily range } RngeFr (0.6); { Fraction of daily range } Var: SessLen (0), { Length in minutes of trading session } Time1Thrd(0), { Time of end of 1st third of session } Time2Thrd(0), { Time of end of 2nd third of session } NBarsDay (0), { Number of bars per day } minTrend (0), { minimum required daily change for "trend" } AveCO (0), { Average close - open } ACOPrior (0), { Value of AveCO on prior day } DayRnge (0), { Most recent day's close - open } DRPrior (0), { Prior day's DayRnge } MovAve1 (0), { Value of moving average 1 } MA1Prior (0), { Value of moving average 1 on prior day } MovAve2 (0), { Value of moving average 2 } MA2Prior (0), { Value of moving average 2 on prior day } MovAve3 (0), { Value of moving average 3 } MA3Prior (0), { Value of moving average 3 on prior day } ATR (0), { Average true range } ATRPrior (0), { Value of ATR on prior day } TRPrior (0), { Prior day's true range } PatVal (0), { Pattern number } PatCount (0), { Number of occurances of pattern PatID } DayCount (0), { Number of days examined } Cond1L (False), { Condition 1, up trend } Cond1S (False), { Condition 1, down trend } Cond2L (False), { Condition 2, up trend } Cond2S (False), { Condition 2, down trend } Cond3L (False), { Condition 3, up trend } Cond3S (False), { Condition 3, down trend } Cond4L (False), { Condition 4, up trend } Cond4S (False), { Condition 4, down trend } Cond5L (False), { Condition 5, up trend } Cond5S (False), { Condition 5, down trend } Cond6L (False), { Condition 6, up trend } Cond6S (False), { Condition 6, down trend } SumCondL (False), { Summary of conditions for up trend } SumCondS (False), { Summary of conditions for down trend } Score (0), { Accuracy of neural network prediction } FalsePos (0), { Number of false positives: predicted pattern when not present } FalseNeg (0); { Number of false negatives: didn't predict pattern when present } Array: OThird[3](0), { Open prices for each third of day } HThird[3](0), { High prices for each third of day } LThird[3](99999999), { Low prices for each third of day } CThird[3](0); { Close prices for each third of day } { Calculate indicator values } ATR = Average(TrueRange, NATR); MovAve1 = Average(C, NMA1); MovAve2 = Average(C, NMA2); MovAve3 = Average(C, NMA3); { Initialize some variables on 1st bar } If BarNumber = 1 then Begin SessLen = AbsValue(TimeToMinutes(SessionEndTime(0,1)) - TimeToMinutes(SessionStartTime(0,1))); Time1Thrd = CalcTime(SessionStartTime(0,1), SessLen/3.); Time2Thrd = CalcTime(SessionStartTime(0,1), (2. * SessLen/3.)); If BarInterval > 0 then NBarsDay = SessLen/BarInterval; End; { Calculations on first bar of new day } If date <> date[1] or BarNumber = 1 then Begin DayRnge = AbsValue(CloseD(1) - OpenD(1)); { range of prior day } { Calculate the minimum required move for a trend based on average daily range } AveCO = GetAveDayRange(NRnge); minTrend = RngeFr * AveCO; {Print("AveCO = ", AveCO, " minTrend = ", minTrend);} { Obtain O, H, L, C of each third of day } Value1 = GetDayThirds(Time1Thrd, Time2Thrd, NBarsDay, OThird, HThird, LThird, CThird); End; { Initialize prior values of indicators } If BarNumber = 1 then Begin MA1Prior = MovAve1; MA2Prior = MovAve2; MA3Prior = MovAve3; DRPrior = DayRnge; ACOPrior = AveCO; ATRPrior = ATR; TRPrior = TrueRange; End; { Evaluate indicators to obtain prediction on prior day } If date <> date[1] then Begin { Use indicator values from day prior to one we're trying to predict } MovAve1 = MA1Prior; MovAve2 = MA2Prior; MovAve3 = MA3Prior; ATR = ATRPrior; { Pattern on prior day; we want to predict this } PatVal = GetTrendPattern(OThird, HThird, LThird, CThird, minTrend); { See if we can predict pattern or absence of pattern } DayCount = DayCount + 1; If AbsValue(PatVal) > 0 then PatCount = PatCount + 1; { Construct indicators and evaluate } Cond1L = TRUE; Cond1S = TRUE; If AbsValue(c1) > 0 then Begin Cond1L = c1 * (CloseD(2) - MovAve1) > 0; Cond1S = -c1 * (CloseD(2) - MovAve1) > 0; End; Cond2L = TRUE; Cond2S = TRUE; If AbsValue(c2) > 0 then Begin Cond2L = c2 * (CloseD(2) - MovAve2) > 0; Cond2S = -c2 * (CloseD(2) - MovAve2) > 0; End; Cond3L = TRUE; Cond3S = TRUE; If AbsValue(c3) > 0 then Begin Cond3L = c3 * (CloseD(2) - MovAve3) > 0; Cond3S = -c3 * (CloseD(2) - MovAve3) > 0; End; Cond4L = TRUE; Cond4S = TRUE; If AbsValue(c4) > 0 then Begin Cond4L = c4 * (DRPrior - ACOPrior) > 0; Cond4S = -c4 * (DRPrior - ACOPrior) > 0; End; Cond5L = TRUE; Cond5S = TRUE; If AbsValue(c5) > 0 then Begin Cond5L = c5 * (CloseD(2) - CloseD(3)) > 0; Cond5S = -c5 * (CloseD(2) - CloseD(3)) > 0; End; Cond6L = TRUE; Cond6S = TRUE; If AbsValue(c6) > 0 then Begin { Cond6L = c6 * (TRPrior - ATR) > 0; Cond6S = -c6 * (TRPrior - ATR) > 0; } Cond6L = c6 * (CloseD(2) - OpenD(2)) > 0; Cond6S = -c6 * (CloseD(2) - OpenD(2)) > 0; End; SumCondL = Cond1L and Cond2L and Cond3L and Cond4L and Cond5L and Cond6L; SumCondS = Cond1S and Cond2S and Cond3S and Cond4S and Cond5S and Cond6S; If PatVal > 0 then Begin { Long pattern present so see if we predict its presence } If SumCondL then Score = Score + 1 { Correct prediction } Else FalseNeg = FalseNeg + 1; { False negative } End Else If PatVal < 0 then Begin { Short pattern present so see if we predict its presence } If SumCondS then Score = Score + 1 { Correct prediction } Else FalseNeg = FalseNeg + 1; { False negative } End Else Begin { Pattern not present, so see if we don't predict it } If SumCondL = False and SumCondS = False then Score = Score + 1 { Correct prediction } Else FalsePos = FalsePos + 1; { False positive } End; {Print("Date: ", Date[1]:0:0, " Pattern: ", PatVal:0:0); } { Calculate indicator values at end of prior day } MA1Prior = MovAve1[1]; MA2Prior = MovAve2[1]; MA3Prior = MovAve3[1]; ACOPrior = AveCO; DRPrior = DayRnge; TRPrior = TrueRange[1]; ATRPrior = ATR[1]; End; If LastBarOnChart then Begin If DayCount > 0 then Score = 100 * Score/DayCount; If PatCount > 0 then FalseNeg = 100 * FalseNeg/PatCount; If (DayCount - PatCount) > 0 then FalsePos = 100 * FalsePos/(DayCount - PatCount); Print("FindPrediction (c1 c2 c3 c4 c5 c6 Score FNeg FPos DayCount PatCount):,", c1:0:0, ",", c2:0:0, ",", c3:0:0, ",", c4:0:0, ",", c5:0:0, ",", c6:0:0, ",", Score:0:2, ",", FalseNeg:0:1, ",", FalsePos:0:1, ",", DayCount:0:0, ",", PatCount:0:0); End; {----------------------------------------------------------------------------------------------------------------} { TrendPredict strategy This strategy uses the results of the FindPrediction strategy to place trades when the indicator conditions predict a trending day will occur. The prediction is based on the results of FindPrediction, which finds the combination of indicator values that best predicts the occurance of a trend pattern on the next day. The trend pattern is defined by function GetTrendPattern. Mike Bryant Breakout Futures www.BreakoutFutures.com Copyright 2009 Breakout Futures } Input: c1 (0), { Coefficient of indicator 1 } c2 (0), { Coefficient of indicator 2 } c3 (0), { Coefficient of indicator 3 } c4 (0), { Coefficient of indicator 4 } c5 (0), { Coefficient of indicator 5 } c6 (0), { Coefficient of indicator 6 } NMA1 (10), { Length of moving average 1 } NMA2 (50), { Length of moving average 2 } NMA3 (135), { Length of moving average 3 } NATR (27), { Period for average true range } NRnge (30), { Period for computing average daily range } RngeFr (0.6); { Fraction of daily range } Var: minTrend (0), { minimum required daily change for "trend" } AveCO (0), { Average close - open } DayRnge (0), { Most recent day's close - open } MovAve1 (0), { Value of moving average 1 } MovAve2 (0), { Value of moving average 2 } MovAve3 (0), { Value of moving average 3 } ATR (0), { Average true range } Cond1L (False), { Condition 1, up trend } Cond1S (False), { Condition 1, down trend } Cond2L (False), { Condition 2, up trend } Cond2S (False), { Condition 2, down trend } Cond3L (False), { Condition 3, up trend } Cond3S (False), { Condition 3, down trend } Cond4L (False), { Condition 4, up trend } Cond4S (False), { Condition 4, down trend } Cond5L (False), { Condition 5, up trend } Cond5S (False), { Condition 5, down trend } Cond6L (False), { Condition 6, up trend } Cond6S (False), { Condition 6, down trend } SumCondL (False), { Summary of conditions for up trend } SumCondS (False), { Summary of conditions for down trend } StopPr (0), { Stop price } ii (0); { Loop counter } { Calculate indicator values } ATR = Average(TrueRange, NATR)[1]; MovAve1 = Average(C, NMA1)[1]; MovAve2 = Average(C, NMA2)[1]; MovAve3 = Average(C, NMA3)[1]; { Calculations on first bar of new day } If date <> date[1] or BarNumber = 1 then Begin DayRnge = AbsValue(CloseD(1) - OpenD(1)); { range of prior day } { Calculate the minimum required move for a trend based on average daily range } AveCO = GetAveDayRange(NRnge); minTrend = RngeFr * AveCO; {Print("AveCO = ", AveCO, " minTrend = ", minTrend);} End; { Evaluate indicators and place trade } If date <> date[1] then Begin { Construct indicators and evaluate } Cond1L = TRUE; Cond1S = TRUE; If AbsValue(c1) > 0 then Begin Cond1L = c1 * (C[1] - MovAve1) > 0; Cond1S = -c1 * (C[1] - MovAve1) > 0; End; Cond2L = TRUE; Cond2S = TRUE; If AbsValue(c2) > 0 then Begin Cond2L = c2 * (C[1] - MovAve2) > 0; Cond2S = -c2 * (C[1] - MovAve2) > 0; End; Cond3L = TRUE; Cond3S = TRUE; If AbsValue(c3) > 0 then Begin Cond3L = c3 * (C[1] - MovAve3) > 0; Cond3S = -c3 * (C[1] - MovAve3) > 0; End; Cond4L = TRUE; Cond4S = TRUE; If AbsValue(c4) > 0 then Begin Cond4L = c4 * (DayRnge - AveCO) > 0; Cond4S = -c4 * (DayRnge - AveCO) > 0; End; Cond5L = TRUE; Cond5S = TRUE; If AbsValue(c5) > 0 then Begin Cond5L = c5 * (C[1] - CloseD(2)) > 0; Cond5S = -c5 * (C[1] - CloseD(2)) > 0; { Cond5L = c5 * (TrueRange[1] - ATR) > 0; Cond5S = -c5 * (TrueRange[1] - ATR) > 0; } End; Cond6L = TRUE; Cond6S = TRUE; If AbsValue(c6) > 0 then Begin Cond6L = c6 * (C[1] - OpenD(1)) > 0; Cond6S = -c6 * (C[1] - OpenD(1)) > 0; End; SumCondL = Cond1L and Cond2L and Cond3L and Cond4L and Cond5L and Cond6L; SumCondS = Cond1S and Cond2S and Cond3S and Cond4S and Cond5S and Cond6S; { Place long/short trade if indicators predict long/short trend pattern } If SumCondL then Begin Buy next bar at market; StopPr = open - minTrend; End Else If SumCondS then Begin Sell short next bar at market; StopPr = open + minTrend; End; End; Sell next bar at StopPr stop; Buy to cover next bar at StopPr stop; SetExitOnClose; {----------------------------------------------------------------------------------------------------------------} { Function GetAveDayRange Calculate the average daily close minus open (range). This function is intended to be called on the first bar of each day on intraday data. Mike Bryant Breakout Futures www.BreakoutFutures.com Copyright 2009 Breakout Futures } Inputs: NRnge (NumericSimple); { Number of days to average over } Var: AveCO(0), { average C - O } ii (0); { loop counter } If date <> date[1] or BarNumber = 1 then Begin { Calculate the average daily close - open price change } AveCO = 0; For ii = 1 to NRnge Begin AveCO = AveCO + AbsValue(CloseD(ii) - OpenD(ii)); { Print("ii = ", ii:0:0, " CloseD = ", CloseD(ii), " OpenD = ", OpenD(ii)); } End; If NRnge > 0 then AveCO = AveCO/NRnge; End; GetAveDayRange = AveCO; {----------------------------------------------------------------------------------------------------------------} { Function GetDayThirds Calculate open, high, low, and close of each third of day on intraday data. This function is intended to be called on the first bar of each day on intraday data. Returns 0 if data is not intraday; 1 otherwise. Results are passed through function inputs OThird, HThird, LThird and CThird. Mike Bryant Breakout Futures www.BreakoutFutures.com Copyright 2009 Breakout Futures } Inputs: Time1Thrd (NumericSimple), { Time at 1/3 of day from open } Time2Thrd (NumericSimple), { Time at 2/3 of day from open } NBarsDay (NumericSimple), { Number of bars in day } OThird[n1](NumericArrayRef), { Open prices for each third of day } HThird[n2](NumericArrayRef), { High prices for each third of day } LThird[n3](NumericArrayRef), { Low prices for each third of day } CThird[n4](NumericArrayRef); { Close prices for each third of day } Var: Done (false), { loop flag } ii (0); { Loop counter } If date <> date[1] or BarNumber = 1 then Begin { Loop backwards until start of prior session; record O, H, L, C of each third of day } Done = false; For ii = 0 to 2 Begin LThird[ii] = 99999999; HThird[ii] = 0; End; CThird[2] = C[1]; // Close of last 3rd of day ii = 1; While ii <= NBarsDay + 1 and Done = false Begin { Record high and low of last third of day } If Time[ii] > Time2Thrd then Begin If Low[ii] < LThird[2] then LThird[2] = Low[ii]; If High[ii] > HThird[2] then HThird[2] = High[ii]; End Else If Time[ii] <= Time2Thrd and Time[ii - 1] > Time2Thrd then Begin CThird[1] = C[ii]; // Close of middle 3rd of day OThird[2] = O[ii - 1]; // Open of last 3rd of day If Low[ii] < LThird[1] then LThird[1] = Low[ii]; If High[ii] > HThird[1] then HThird[1] = High[ii]; End { Record high and low of middle third of day } Else If Time[ii] <= Time2Thrd and Time[ii] > Time1Thrd then Begin If Low[ii] < LThird[1] then LThird[1] = Low[ii]; If High[ii] > HThird[1] then HThird[1] = High[ii]; End Else If Time[ii] <= Time1Thrd and Time[ii - 1] > Time1Thrd then Begin CThird[0] = C[ii]; // Close of 1st 3rd of day OThird[1] = O[ii - 1]; // Open of middle 3rd of day If Low[ii] < LThird[0] then LThird[0] = Low[ii]; If High[ii] > HThird[0] then HThird[0] = High[ii]; End { Record high and low of first third of day } Else If Time[ii] <= Time1Thrd and Time[ii] > SessionStartTime(0,1) then Begin If Low[ii] < LThird[0] then LThird[0] = Low[ii]; If High[ii] > HThird[0] then HThird[0] = High[ii]; End; if Date[ii] <> Date[ii + 1] then Done = true; ii = ii + 1; End; OThird[0] = O[ii - 1]; // Open of first 3rd of day End; If NBarsDay < 1 or BarType > 1 then GetDayThirds = 0 Else GetDayThirds = 1; {----------------------------------------------------------------------------------------------------------------} { Function GetTrendPattern Look for trending pattern. Return: 1 -> up trend pattern -1 -> down trend pattern 0 -> pattern not found Mike Bryant Breakout Futures www.BreakoutFutures.com Copyright 2009 Breakout Futures } Inputs: OThird[n1](NumericArrayRef), { Open prices for each third of day } HThird[n2](NumericArrayRef), { High prices for each third of day } LThird[n3](NumericArrayRef), { Low prices for each third of day } CThird[n4](NumericArrayRef), { Close prices for each third of day } minTrend (NumericSimple); { Min point change to define a trend } Var: DayL(0), { Low of day } DayH(0); { High of day } DayL = minList(LThird[0], LThird[1], LThird[2]); DayH = maxList(HThird[0], HThird[1], HThird[2]); GetTrendPattern = 0; If (CThird[2] - OThird[0]) >= minTrend then Begin { Possible up trend pattern } If (OThird[0] - DayL) < minTrend and (DayH - CThird[2]) < minTrend and AbsValue(CThird[0] - OThird[0]) < (CThird[2] - OThird[0]) and AbsValue(CThird[2] - OThird[2]) < (CThird[2] - OThird[0]) then GetTrendPattern = 1; End Else If (OThird[0] - CThird[2]) >= minTrend then Begin { Possible down trend pattern } If (DayH - OThird[0]) < minTrend and (CThird[2] - DayL) < minTrend and AbsValue(CThird[0] - OThird[0]) < (OThird[0] - CThird[2]) and AbsValue(CThird[2] - OThird[2]) < (OThird[0] - CThird[2]) then GetTrendPattern = -1; End;