//Revised 18/03/2016 //Introduced Stretch and deleted Weak Close //EOD daily Mean Reversion Strategy long only system modified from Connors and Alvarez. The buy set up uses 3 down days and RSI(2) oversold condition. The system is meant to be run without an Index filter. Exit is on either an overbought RSI(2) condition, after a fixed number of days or an initial percentage stop. The system will be traded on IBs platform using $6 entry and exit commission and using an initial start up capital of 25k. The system is to be used on ASX stocks in the range of 25c to $25 with a minimum 7 day turnover of 250k Slippage on entry and exit has been taken as 0.5% each way and buys and sells use the open price. _SECTION_BEGIN( "Historical Database Testing" ); //==================================================================== //Historical Database Testing //==================================================================== ASXList = ParamList( "ASX Historical Watchlist:", "1: Off|2: ASX 20|3: ASX 50|4: ASX 100|5: ASX 200|6: ASX 300|7: ASX All Ordinaries|8: ASX Small Ordinaries|9: ASX Emerging Companies|10: Excluding ASX 300|11: In XAO but Exc ASX 100|12: Exc XAO", 0 ); HistDB = 1;//set to 1 to start if( ASXList == "1: Off" ) HistDB = 1; if( ASXList == "2: ASX 20" ) HistDB = IsIndexConstituent( "$XTL" ); if( ASXList == "3: ASX 50" ) HistDB = IsIndexConstituent( "$XFL" ); if( ASXList == "4: ASX 100" ) HistDB = IsIndexConstituent( "$XTO" ); if( ASXList == "5: ASX 200" ) HistDB = IsIndexConstituent( "$XJO" ); if( ASXList == "6: ASX 300" ) HistDB = IsIndexConstituent( "$XKO" ); if( ASXList == "7: ASX All Ordinaries" ) HistDB = IsIndexConstituent( "$XAO" ); if( ASXList == "8: ASX Small Ordinaries" ) HistDB = IsIndexConstituent( "$XKO" ) AND NOT IsIndexConstituent( "$XTO" ); if( ASXList == "9: ASX Emerging Companies" ) HistDB = IsIndexConstituent( "$XEC" ); if( ASXList == "10: Excluding ASX 300" ) HistDB = IsIndexConstituent( "$XKO" ) == 0; if( ASXList == "11: In XAO but Exc ASX 100" ) HistDB = IsIndexConstituent( "$XAO" )AND NOT IsIndexConstituent( "$XTO" ); if( ASXList == "12: Exc XAO" ) HistDB = IsIndexConstituent( "$XAO" ) == 0; //-------------------------------------------------------------------- HDBFilter = HistDB; //==================================================================== _SECTION_END(); _SECTION_BEGIN("Optional Price Filter and TO Filter"); //==================================================================== //Price and Volume Filters //==================================================================== PriceTog = ParamToggle("Price Filter","Off|On",1); PF = ParamField("Price Field",6); MinSP = Param("Minimum Share Price - $",0.25,0.00,1000,0.01); MaxSP = Param("Maximum Share Price - $",25,0.00,2000,0.01); MinMaxSP = PF >= MinSP AND PF <= MaxSP; PriceFilt = IIf(PriceTog,MinMaxSP,1); //-------------------------------------------------------------------- TOTog = ParamToggle("Turnover Filter","Off|On",1); Turnover = PF*V; MinTO = Param("Minimum Turnover - $",250000,0,10000000,1000); TOMA = Param("Turnover MA",7,1,200,1); AveTO = EMA(Turnover,TOMA); TOFilter = AveTO > MinTO AND Turnover > MinTO; TOFilt = IIf(TOTog,TOFilter,1); //-------------------------------------------------------------------- OptFilt = PriceFilt AND TOFilt; //==================================================================== _SECTION_END(); _SECTION_BEGIN("Index Filter"); //==================================================================== //Index Filter //==================================================================== IndexTog = ParamToggle("Index Filter","On|Off",1); IndexCode = ParamStr("Index Symbol","$XAO"); Index = Foreign(IndexCode,"C"); IndMA = Param("Index Filter MA",150,2,10000,1); IndexFiltUp = Index > MA(Index,IndMA); IndexUp = IIf(IndexTog,1,IndexFiltUp); //==================================================================== _SECTION_END(); //==================================================================== //Universe Filter //==================================================================== List = Paramlist("Universe Filter:","1:Off|2:Resources|3:Industrials",0); UniverseFilter = 1; If (List == "1:Off") UniverseFilter = 1; If (List == "2:Resources") UniverseFilter = InGics("10") OR InGics("151040"); If (List == "3:Industrials") UniverseFilter = InGics("10")==0 OR InGics("151040")==0; //==================================================================== _SECTION_END(); //==================================================================== //Entry and Exit Rules //==================================================================== EntryRSIlevel = Param("Entry RSI level",25,10,40,5); ExitRSIlevel = Param("Exit RSI level",75,60,100,5); EntryRSI = EntryRSIlevel; ExitRSI = ExitRSIlevel; RSIPeriod = 2; Low3RSIBars = 3; function ParamOptimize(pname,defaultval,minv,maxv,step) { return Optimize(pname,Param(pname,defaultval,minv,maxv,step),minv,maxv,step); } ATRp = Param("Limit Price: ATR period",10,1,20,1); //ATRp = ParamOptimize("Limit Price: ATR period",5,1,10,1); ATRmulti = Param("Limit Price: ATR Multi",0.5,0,1.5,.1); //ATRmulti = ParamOptimize("Limit Price: ATR Multi",0.5,0.25,1.5,0.25); ATRVal = ATR(ATRp)*ATRmulti; BuyLimP = L - ATRval; //stretch TickLo = IIf(L<0.10,0.001,IIf(L<2.00,0.005,0.01)); BuyLimVal = round(BuyLimP/TickLo); BuyLim = BuyLimVal * TickLo; CurrentRSI = RSI(RSIPeriod); Multiple3DayLowRSI = Sum(CurrentRSI < EntryRSI, Low3RSIBars) == Low3RSIBars; //RSI(2) MA(C,MALongPeriod); //Close above long term MA CloseBelowShortTermMA = C < MA(C,MAShortPeriod); //Close below short term MA Volatility = abs(C-Ref(C,-1))>= 0.5*ATR(10) AND abs(C-Ref(C,-1))<= 2*ATR(10); //Limit volatility to between these limits WideRangeDay = ATR(1)>=2*ATR(10); OnLastTwoBarsOfDelistedSecurity = BarIndex() >= (LastValue(BarIndex()) -1) AND !IsNull(GetFnData("DelistingDate")); OnSecondLastBarOfDelistedSecurity = BarIndex() == (LastValue(BarIndex()) -1) AND !IsNull(GetFnData("DelistingDate")); BuySetUp = ThreeDaysDown AND CloseBelowShortTermMA AND CloseAboveLongTermMA AND IndexUp AND OptFilt AND Volatility; LE = Ref(BuySetUp,-1) AND L <= Ref(BuyLim,-1) AND NOT OnLastTwoBarsOfDelistedSecurity; //Long Entry slippage = Param("slippage %",.5,0,2,.5); //slippage LEPrice = Min(O,ref(BuyLim,-1)); LExPrice = IIf(O*(1-slippage/100) ExitRSI OR WideRangeDay; //Exit signal LEx = Ref(SellSetup,-1); //Long Exit //-------------------------------------------------------------------- //Stops //-------------------------------------------------------------------- Short = Cover = False; ExitBars = Param("# Exit Bars",20,2,100,1); //ExitBars = ParamOptimize("# Exit Bars",15,2,30,2); StopLossPercentage = Param("% Hard Stop Loss",20,0,100,1); //Stop Loss StopLossMultiplier = Param("Stop Loss Multiplier",1,0.1,1,0.1); //==================================================================== //Looping //==================================================================== Buy = 0; Sell = 0; LPriceAtBuy = 0; LBIT = 0; FlagExit = 0; MaxLossPrice = Null; //==================================================================== for( j = 1; j < BarCount; j++ ) { if( LPriceAtBuy == 0 AND LE[j] ) { Buy[j] = True; LPriceAtBuy = LEPrice[j]; BuyPrice[j] = LEPrice[j]; MaxLossPrice[j] = LPriceAtBuy * ( 1 - StopLossPercentage / 100 ); LBIT[j] = 1; if( LBIT[j] > 1 AND LEx[j] OR OnSecondLastBarOfDelistedSecurity[j] ) { Sell[j] = True; SellPrice[j] = LExPrice[j]; LPriceAtBuy = 0; } if( LBIT[j] > 1 AND L[j - 1] <= MaxLossPrice[j - 1] ) { Sell[j] = True; SellPrice[j] = LExPrice[j]; LPriceAtBuy = 0; } } else if( LPriceAtBuy > 0 ) { LBIT[j] = LBIT[j - 1] + 1; MaxLossPrice[j] = MaxLossPrice[j - 1]; if( LBIT[j] == ExitBars OR OnSecondLastBarOfDelistedSecurity[j] ) //Exit trade after a certain number of bars { FlagExit[j] = True; } if( LBIT[j] > 1 AND LBIT[j] > ExitBars/2 ) { MaxLossPrice[j] = LPriceAtBuy * ( 1 - StopLossMultiplier*StopLossPercentage / 100 ); } if( LBIT[j] > ExitBars ) { Sell[j] = True; SellPrice[j] = LExPrice[j]; LPriceAtBuy = 0; } if( LBIT[j] > 1 AND L[j - 1] <= MaxLossPrice[j - 1] ) { Sell[j] = True; SellPrice[j] = LExPrice[j]; LPriceAtBuy = 0; } if( LBIT[j] > 1 AND LEx[j]) { Sell[j] = True; SellPrice[j] = LExPrice[j]; LPriceAtBuy = 0; } } } //==================================================================== MaxExit = FlagExit; StopLossExit = L <= MaxLossPrice; LESetup = IIf(LBIT==0 OR Sell==1,BuySetUp,0); //Long Entry Set Up LExSetup = IIf(LBIT>0 AND Sell==0,(SellSetup OR FlagExit OR StopLossExit),0); //Long Exit Set Up //-------------------------------------------------------------------- Filter = Buy OR Sell OR LESetUp OR LExSetup OR LBIT>0; AddTextColumn(WriteIf(LESetup,"Buy Setup",""),"Entry Signal",1.2,colorDefault,IIf(LESetup,colorBrightGreen,colorDefault),130); AddTextColumn(WriteIf(LExSetup,"Exit Setup",""),"Exit Signal",1.2,colorDefault,IIf(LExSetup,colorRed,colorDefault),100); AddTextColumn(WriteIf(Buy,"Buy",""),"Today's Entries",1.2,colorDefault,IIf(Buy,colorGreen,colorDefault),130); AddTextColumn(WriteIf(Sell,"Sell",""),"Today's Exits",1.2,colorDefault,IIf(Sell,colorRed,colorDefault),130); AddColumn(LBIT,"LBIT",1.0); SetSortColumns(-3,-4,-5,-6,1); /*Filter = 1; AddColumn(BuySetUp,"Buy Setup",1); AddColumn(Buy,"Buy",1); AddColumn(StopLossExit, "Sell Setup",1); AddColumn(Sell,"Sell",1);*/ //==================================================================== //Interpretation Window //==================================================================== //"Stop Level: "+NumToStr(StopLossExit,1.3); "3 Lower Closes: "+WriteIf(Multiple3DownDays==1,"Yes","No"); "3 Day Low RSI: "+WriteIf(Multiple3DayLowRSI==1,"Yes","No"); //printf( "BuyStop: " + NumToStr(BuyStop,1.3) + "n" ); ""; "Bars In Trade: "+NumToStr(LBIT,1); "Wide range bar > 1.0 : "+NumToStr(ATR(1)/(2*ATR(10)),1.3); "Trail Stop: "+NumToStr(MaxLossPrice,1.3); //==================================================================== _SECTION_BEGIN("Chart Plotting"); //==================================================================== SetChartOptions(0,chartShowArrows|chartShowDates); _N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) )); ChartType = ParamList("Chart Type","OHLC Bar|Candle|Line",0); SetChartBkColor(ParamColor("Background Colour",colorwhite)); UpColour = ParamColor("Bar/Candle Up Colour",colorGreen); DownColour = ParamColor("Bar/Candle Down Colour",colorRed); Colour1 = IIf(C > Ref(C,-1),UpColour,DownColour); Colour2 = IIf(C > O,UpColour,DownColour); Colour3 = ParamColor("Line Chart Colour",colorRed); TextColour = ParamColor("Text Colour",colorblack); if(ChartType == "OHLC Bar") ChartOption = styleBar; if(ChartType == "Candle") ChartOption = styleCandle; if(ChartType == "Line") ChartOption = styleLine; if(ChartType == "OHLC Bar") ColourOption = Colour1; if(ChartType == "Candle") ColourOption = Colour2; if(ChartType == "Line") ColourOption = Colour3; //-------------------------------------------------------------------- Plot(Close,"Close",ColourOption,styleNoTitle|ChartOption|ParamStyle("Chart Style")); GraphXSpace = 10; Plot(MaxLossPrice,"Stop Loss",ParamColor("Stop Loss Colour",colorBlue),ParamStyle("Stop Loss Style",styleLine)); PlotShapes(shapehollowUpArrow*LESetup,colorGreen,0,L,-40); //plots an arrow for a setup bar PlotShapes(shapehollowdownArrow*LExSetup,colorRed,0,H,-40); //plots an arrow for an exit bar PlotShapes(shapeHollowSmallSquare*Buy,TextColour,0,BuyPrice,0); //plots a small hollow square right at the buy price PlotShapes(shapeHollowSmallSquare*Sell,TextColour,0,SellPrice,0); //plots a small hollow square right at the sell price //-------------------------------------------------------------------- FirstVisibleBar = Status("FirstVisibleBar"); LastVisibleBar = Status("LastVisibleBar"); for( b = Firstvisiblebar; b <= Lastvisiblebar AND b < BarCount; b++) { if(Buy[b]) PlotText("\n Buy\n "+NumToStr(BuyPrice[b],1.3),b,BuyPrice[b]*0.9985,TextColour); else if(Sell[b]) PlotText("\n Sell\n "+NumToStr(SellPrice[b],1.3),b,SellPrice[b]*0.9985, TextColour); } //==================================================================== _SECTION_END(); _SECTION_BEGIN("Backtesting"); //===================================================================== //options in automatic analysis settings //===================================================================== SetTradeDelays(0,0,0,0); SetOption("UsePrevBarEquityForPosSizing",True); Capital = Param("Initial Equity $",25000,1000,1000000,100); SetOption("InitialEquity",Capital); MaxPos = Param("Maximum Open Positions",10,1,100,1); SetOption("MaxOpenPositions",MaxPos); SetOption("AllowSameBarExit",False); SetOption("AllowPositionShrinking", False ); SetOption("InterestRate",0); SetOption("Minshares",1); SetOption("MinPosValue",1); SetOption("CommissionMode",2); //Fixed Dollar Amount SetOption("CommissionAmount",6); //Use IB commision rates SetOption("AccountMargin",100); PositionScore = mtRandom(); //--------------------------------------------------------------------- ""; "Position Sizing Method:" ; PosSizeMethod = ParamList("Position Sizing Method:","Fixed $ Total Position Size|Fixed % of Portfolio Equity",1); FPAmount = Param("Fixed % of Portfolio Equity",10,1,100,1); FDAmount = Param("Fixed $ Total Position Size",5000,100,100000,100); if(PosSizeMethod == "Fixed $ Total Position Size") SetPositionSize(FDAmount,spsValue); if(PosSizeMethod == "Fixed % of Portfolio Equity") SetPositionSize(FPAmount,spsPercentOfEquity); //==================================================================== _SECTION_END();