RSI Swing Trading Strategy

barbaros

Administrator
Staff member
Original strategy from https://relaxedtrader.com/rsi-trading-strategy/

Trading rules:
  • Use two RSI values:
    • 4 day RSI (RSI 1)
    • 9 day RSI (RSI 2)
  • Wait for RSI 1 and RSI 2 to go below 40
  • When RSI 1reaches 70
    • BUY
  • When RSI 2reaches 70
    • SELL
Code:
# SPY RSI Swing Trading Strategy
# Free for use. Header credits must be included when any form of the code included in this package is used.
# v1.0 - barbaros - converted for b4signals.com

input RiskManagement = yes;
input PercentRisk = 100;
input Portfolio = 100000;

input var1 = 39;
input var2 = 4;
input var3 = 9;
input var4 = 5;
input RSI_High_Value = 70;
input RSI_Low_Value = 40;

input targetWinRate = 1;
input targetWinLoss = .50;

def atr = Average(AbsValue(close - close[1]), var1);
def RSI_1 = RSI(var2);
def RSI_2 = RSI(var3);

def SharesToTrade = if RiskManagement then RoundDown((PercentRisk * 0.01) *  Portfolio)  else 1;

def buyCond = close > Average(close, 200) and RSI_1 > RSI_High_Value and lowest(RSI_1, var4) < RSI_Low_Value and lowest(RSI_2, var4) < RSI_Low_Value;
def sellCond = RSI_2 >= RSI_High_Value;

def direction = if BarNumber() == 1 then 0
                else if direction[1] == 0 and  buyCond and SharesToTrade > 0 then 1
                else if direction[1] == 1 and sellCond then 0
                else direction[1];

AddOrder(OrderType.BUY_TO_OPEN, direction crosses above 0, tradeSize = SharesToTrade, name = "LONG");
AddOrder(OrderType.SELL_TO_CLOSE, direction crosses below 1, name = "EXIT");

#Global Scripts
def FPL = FloatingPL();
def entry = EntryPrice();
def portfolioSize = if !isNaN(FPL) then FPL + Portfolio else Portfolio;

script incrementValue {
    input condition = yes;
    input increment =  1;
    input startingValue = 0;

    def _value = CompoundValue(1,
                if condition
                then _value[1] + increment
                else _value[1], startingValue);

    plot incrementValue = _value;
}
;

# Entry Calculations.  Note: Only parses on a Strategy Chart
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];

def entryPrice = if !IsNaN(entry)
                then entry
                else entryPrice[1];

def hasEntry = !IsNaN(entry);

def isNewEntry = entryPrice != entryPrice[1];

#is active trade
def highFPL = HighestAll(FPL);
def lowFPL = LowestAll(FPL);

def fplreturn = (FPL - FPL[1]) / FPL[1];
def cumsum = Sum(fplreturn);

def highBarNumber = CompoundValue(1, if FPL == highFPL
                                    then bn
                                    else highBarNumber[1], 0);

def lowBarNumber = CompoundValue(1, if FPL == lowFPL
                                then bn
                                else lowBarNumber[1], 0);

#Win/Loss ratios
def entryBarsTemp = if hasEntry
                then bn
                else Double.NaN;

def entryBarNum = if hasEntry and isNewEntry
                then bn
                else entryBarNum[1];

def isEntryBar = entryBarNum != entryBarNum[1];

def entryBarPL = if isEntryBar
                then FPL
                else entryBarPL[1];

def exitBarsTemp = if !hasEntry
                and bn > entryBarsTemp[1]
                then bn
                else Double.NaN;

def exitBarNum = if !hasEntry and !IsNaN(exitBarsTemp[1])
                then bn
                else exitBarNum[1];

def isExitBar = exitBarNum != exitBarNum[1];

def exitBarPL = if isExitBar
            then FPL
            else exitBarPL[1];

def entryReturn = if isExitBar then exitBarPL - exitBarPL[1] else entryReturn[1];
def isWin = if isExitBar and entryReturn >= 0 then 1 else 0;
def isLoss = if isExitBar and entryReturn < 0 then 1 else 0;
def entryReturnWin = if isWin then entryReturn else entryReturnWin[1];
def entryReturnLoss = if isLoss then entryReturn else entryReturnLoss[1];
def entryFPLWins = if isWin then entryReturn else 0;
def entryFPLLosses = if isLoss then entryReturn else 0;
def entryFPLAll = if isLoss or isWin then entryReturn else 0;

#Counts
def entryCount = incrementValue(entryFPLAll);
def winCount = incrementValue(isWin);
def lossCount = incrementValue(isLoss);

def highestReturn = if entryReturnWin[1] > highestReturn[1]
                then entryReturnWin[1]
                else highestReturn[1];

def lowestReturn = if entryReturnLoss[1] < lowestReturn[1]
                then entryReturnLoss[1]
                else lowestReturn[1];


def winRate = winCount / lossCount;
def winLossRatio = winCount / (winCount + lossCount); # winCount / entryCount;
def avgReturn = TotalSum(entryFPLAll) / entryCount;
def avgWin = TotalSum(entryFPLWins) / winCount;
def avgLoss = TotalSum(entryFPLLosses) / lossCount;

#Labels

AddLabel(yes,
        text = "Total Trades: " + entryCount + "  ",
        color = Color.WHITE
        );

AddLabel(yes,
        text = "WinCount: " + winCount +
            " | LossCount: " + lossCount +
            " | WinRate: " + Round(winRate, 2) + "  ",
        color = if winRate >= targetWinRate
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "W/L: " + AsPercent(winLossRatio) + " ",
        color = if winLossRatio > targetWinLoss
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "AvgReturn: " + AsDollars(avgReturn) +
            " | AvgWin: " + AsDollars(avgWin) +
            " | AvgLoss: " + AsDollars(avgLoss) + "   ",
        color = if avgReturn >= 0
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "Total Profit: " + AsDollars(FPL) + "  ",
        color = if FPL > 0
                then Color.CYAN
                else Color.MAGENTA
    );

AddLabel(yes,
        text = "Final Portfolio: " + AsDollars(portfolioSize) + " (" + AsPercent(portfolioSize / Portfolio) + ")  ",
        color = if portfolioSize > Portfolio
                then Color.CYAN
                else Color.MAGENTA
    );

Author claims:
Dc3sgn0.png


From converted script tested on SPY on daily timeframe with max allowed period, since 1993:
XzAej1y.png


Using a different share size calculation:
8Ieybie.png


Code:
# SPY RSI Swing Trading Strategy
# Free for use. Header credits must be included when any form of the code included in this package is used.
# v1.0 - barbaros - converted for b4signals.com
# v1.1 - barbaros - realistic share size calculation

input useMoneyManagement = yes;
input initialBalance = 100000;

input var1 = 39;
input var2 = 4;
input var3 = 9;
input var4 = 5;
input RSI_High_Value = 70;
input RSI_Low_Value = 40;

input targetWinRate = 1;
input targetWinLoss = .50;

def atr = Average(AbsValue(close - close[1]), var1);
def RSI_1 = RSI(var2);
def RSI_2 = RSI(var3);

#def SharesToTrade = if RiskManagement then RoundDown((PercentRisk * 0.01) *  Portfolio)  else 1;
def FPL = FloatingPL();
def entry = EntryPrice();
def portfolioSize = if !isNaN(FPL) then FPL + initialBalance else initialBalance;
def SharesToTrade = if useMoneyManagement then RoundDown(portfolioSize / (atr * close), 0) else 1;

def buyCond = close > Average(close, 200) and RSI_1 > RSI_High_Value and lowest(RSI_1, var4) < RSI_Low_Value and lowest(RSI_2, var4) < RSI_Low_Value;
def sellCond = RSI_2 >= RSI_High_Value;

def direction = if BarNumber() == 1 then 0
                else if direction[1] == 0 and  buyCond and SharesToTrade > 0 then 1
                else if direction[1] == 1 and sellCond then 0
                else direction[1];

AddOrder(OrderType.BUY_TO_OPEN, direction crosses above 0, tradeSize = SharesToTrade, name = "LONG");
AddOrder(OrderType.SELL_TO_CLOSE, direction crosses below 1, name = "EXIT");

#Global Scripts
script incrementValue {
    input condition = yes;
    input increment =  1;
    input startingValue = 0;

    def _value = CompoundValue(1,
                if condition
                then _value[1] + increment
                else _value[1], startingValue);

    plot incrementValue = _value;
};

# Entry Calculations.  Note: Only parses on a Strategy Chart
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];

def entryPrice = if !IsNaN(entry)
                then entry
                else entryPrice[1];

def hasEntry = !IsNaN(entry);

def isNewEntry = entryPrice != entryPrice[1];

#is active trade
def highFPL = HighestAll(FPL);
def lowFPL = LowestAll(FPL);

def fplreturn = (FPL - FPL[1]) / FPL[1];
def cumsum = Sum(fplreturn);

def highBarNumber = CompoundValue(1, if FPL == highFPL
                                    then bn
                                    else highBarNumber[1], 0);

def lowBarNumber = CompoundValue(1, if FPL == lowFPL
                                then bn
                                else lowBarNumber[1], 0);

#Win/Loss ratios
def entryBarsTemp = if hasEntry
                then bn
                else Double.NaN;

def entryBarNum = if hasEntry and isNewEntry
                then bn
                else entryBarNum[1];

def isEntryBar = entryBarNum != entryBarNum[1];

def entryBarPL = if isEntryBar
                then FPL
                else entryBarPL[1];

def exitBarsTemp = if !hasEntry
                and bn > entryBarsTemp[1]
                then bn
                else Double.NaN;

def exitBarNum = if !hasEntry and !IsNaN(exitBarsTemp[1])
                then bn
                else exitBarNum[1];

def isExitBar = exitBarNum != exitBarNum[1];

def exitBarPL = if isExitBar
            then FPL
            else exitBarPL[1];

def entryReturn = if isExitBar then exitBarPL - exitBarPL[1] else entryReturn[1];
def isWin = if isExitBar and entryReturn >= 0 then 1 else 0;
def isLoss = if isExitBar and entryReturn < 0 then 1 else 0;
def entryReturnWin = if isWin then entryReturn else entryReturnWin[1];
def entryReturnLoss = if isLoss then entryReturn else entryReturnLoss[1];
def entryFPLWins = if isWin then entryReturn else 0;
def entryFPLLosses = if isLoss then entryReturn else 0;
def entryFPLAll = if isLoss or isWin then entryReturn else 0;

#Counts
def entryCount = incrementValue(entryFPLAll);
def winCount = incrementValue(isWin);
def lossCount = incrementValue(isLoss);

def highestReturn = if entryReturnWin[1] > highestReturn[1]
                then entryReturnWin[1]
                else highestReturn[1];

def lowestReturn = if entryReturnLoss[1] < lowestReturn[1]
                then entryReturnLoss[1]
                else lowestReturn[1];


def winRate = winCount / lossCount;
def winLossRatio = winCount / (winCount + lossCount); # winCount / entryCount;
def avgReturn = TotalSum(entryFPLAll) / entryCount;
def avgWin = TotalSum(entryFPLWins) / winCount;
def avgLoss = TotalSum(entryFPLLosses) / lossCount;

#Labels

AddLabel(yes,
        text = "Total Trades: " + entryCount + "  ",
        color = Color.WHITE
        );

AddLabel(yes,
        text = "WinCount: " + winCount +
            " | LossCount: " + lossCount +
            " | WinRate: " + Round(winRate, 2) + "  ",
        color = if winRate >= targetWinRate
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "W/L: " + AsPercent(winLossRatio) + " ",
        color = if winLossRatio > targetWinLoss
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "AvgReturn: " + AsDollars(avgReturn) +
            " | AvgWin: " + AsDollars(avgWin) +
            " | AvgLoss: " + AsDollars(avgLoss) + "   ",
        color = if avgReturn >= 0
                then Color.CYAN
                else Color.MAGENTA
        );

AddLabel(yes,
        text = "Total Profit: " + AsDollars(FPL) + "  ",
        color = if FPL > 0
                then Color.CYAN
                else Color.MAGENTA
    );

AddLabel(yes,
        text = "Final Portfolio: " + AsDollars(portfolioSize) + " (" + AsPercent(portfolioSize / initialBalance) + ")  ",
        color = if portfolioSize > initialBalance
                then Color.CYAN
                else Color.MAGENTA
    );
 
Top