$SPY Swing Strategy

yosef

New member
Thanks @WickFlair. I already converted this to a strategy for ToS. Here is the script.

Code:
# SPY Daily Trader
# 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 initialBalance = 1000;
input atrPeriods = 10;
input lowest_close = 3;
input trend_average = 66;
input highest_close = 19;
input stop_var = 7.95;
input targetWinRate = 1;
input targetWinLoss = .50;
input useMoneyManagement = yes;

def FPL = FloatingPL();
def entry = EntryPrice();

def atrA = Average(AbsValue(close - close[1]), atrPeriods);
def atr = if atrA < 1 then 1 else atrA;

def portfolioSize = if !isNaN(FPL) then FPL + initialBalance else initialBalance;
def contractsToTrade = if useMoneyManagement then RoundDown(portfolioSize / (atr * close), 0) else 1;

AddLabel(yes, "Shares To Trade: " + contractsToTrade, color.gray);

def buyCond = close <= Lowest(close, lowest_close) and close > Average(close, trend_average);
def sellCond = close >= Highest(close, highest_close);

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

def stop_price = if BarNumber() == 1 then close else if direction crosses 0 then close - (stop_var * atr) else stop_price[1];

AddOrder(OrderType.BUY_TO_OPEN, direction crosses above 0, tradeSize = contractsToTrade, 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
    );
I load this code on tos, but dont run.Exist any problem? thanks
 

Jackie

New member
@barbaros I might be getting this thread confused with something else but wasnt there a watchlist column and scanner that you coded for this strategy or am I somehow just missing it?? Thanks!

Never mind I'm seeing it now! Now sure what happened!
 

barbaros

Administrator
Staff member
Hey Barb, I am confused isnt this only for SPY and on a daily?
However, lets look at recent performance.

TSLA intraday option turned on, 5d 3m chart, money management turned on: 2 trades / 100 win rate
JnuAMW7.png


TSLA intraday option turned on, 5d 3m chart, money management turned off: too many trades / 81% win rate
pdHW83t.png


/ES intraday option turned on, 5d 3m chart, money management turned on: no trades

/ES intraday option turned on, 5d 3m chart, money management turned off: too many trades / 83% win rate
6UCxZ5G.png


All of them are profitable.
 
Last edited:

barbaros

Administrator
Staff member
small bug fix.

Code:
# SPY Daily Trader
# 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 - added intraday option
# v1.2 - barbaros - percent profit calculation fix

input initialBalance = 1000;
input atrPeriods = 10;
input lowest_close = 3;
input trend_average = 66;
input highest_close = 19;
input stop_var = 7.95;
input targetWinRate = 1;
input targetWinLoss = .50;
input useMoneyManagement = yes;
input intradayOnly = no;

def FPL = FloatingPL();
def entry = EntryPrice();

def isTrade = !intradayOnly or (SecondsTillTime(0930) <= 0 and SecondsTillTime(1600) > 0);

def atrA = Average(AbsValue(close - close[1]), atrPeriods);
def atr = if atrA < 1 then 1 else atrA;

def portfolioSize = if !isNaN(FPL) then FPL + initialBalance else initialBalance;
def contractsToTrade = if useMoneyManagement then RoundDown(portfolioSize / (atr * close), 0) else 1;

AddLabel(yes, "Shares To Trade: " + contractsToTrade, color.gray);

def buyCond = close <= Lowest(close, lowest_close) and close > Average(close, trend_average);
def sellCond = close >= Highest(close, highest_close);

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

def stop_price = if BarNumber() == 1 then close else if direction crosses 0 then close - (stop_var * atr) else stop_price[1];

AddOrder(OrderType.BUY_TO_OPEN, isTrade and direction crosses above 0, tradeSize = contractsToTrade, name = "LONG");
AddOrder(OrderType.SELL_TO_CLOSE, !isTrade or 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) - 1) + ")  ",
        color = if portfolioSize > initialBalance
                then Color.CYAN
                else Color.MAGENTA
    );
 

quijanoj

New member
small bug fix.

Code:
# SPY Daily Trader
# 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 - added intraday option
# v1.2 - barbaros - percent profit calculation fix

input initialBalance = 1000;
input atrPeriods = 10;
input lowest_close = 3;
input trend_average = 66;
input highest_close = 19;
input stop_var = 7.95;
input targetWinRate = 1;
input targetWinLoss = .50;
input useMoneyManagement = yes;
input intradayOnly = no;

def FPL = FloatingPL();
def entry = EntryPrice();

def isTrade = !intradayOnly or (SecondsTillTime(0930) <= 0 and SecondsTillTime(1600) > 0);

def atrA = Average(AbsValue(close - close[1]), atrPeriods);
def atr = if atrA < 1 then 1 else atrA;

def portfolioSize = if !isNaN(FPL) then FPL + initialBalance else initialBalance;
def contractsToTrade = if useMoneyManagement then RoundDown(portfolioSize / (atr * close), 0) else 1;

AddLabel(yes, "Shares To Trade: " + contractsToTrade, color.gray);

def buyCond = close <= Lowest(close, lowest_close) and close > Average(close, trend_average);
def sellCond = close >= Highest(close, highest_close);

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

def stop_price = if BarNumber() == 1 then close else if direction crosses 0 then close - (stop_var * atr) else stop_price[1];

AddOrder(OrderType.BUY_TO_OPEN, isTrade and direction crosses above 0, tradeSize = contractsToTrade, name = "LONG");
AddOrder(OrderType.SELL_TO_CLOSE, !isTrade or 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) - 1) + ")  ",
        color = if portfolioSize > initialBalance
                then Color.CYAN
                else Color.MAGENTA
    );


Thanks for converting this strategy. I would like to ask if it's possible to set multiple partial exit orders. Like a Take Profit 1 (partial 1), Take Profit 2 (partial 2)... until the Sell to Close order is reached. The Partial close orders would depend on a signal definition, let's say def PartialClose = [something];, and if we can create an input value, let's say input MaxClosing = 4;, which would be the max numbers of partial closing orders until the (STC) Sell to Close order is reached... or whichever comes first. So, if we set 4 partial orders, the first partial close order would be 1/4, then 2/4 until closing the order. Or if the STC comes at where it is on the 3/4 partial closing order then close, again whichever comes first until closing the order.
 

barbaros

Administrator
Staff member
Thanks for converting this strategy. I would like to ask if it's possible to set multiple partial exit orders. Like a Take Profit 1 (partial 1), Take Profit 2 (partial 2)... until the Sell to Close order is reached. The Partial close orders would depend on a signal definition, let's say def PartialClose = [something];, and if we can create an input value, let's say input MaxClosing = 4;, which would be the max numbers of partial closing orders until the (STC) Sell to Close order is reached... or whichever comes first. So, if we set 4 partial orders, the first partial close order would be 1/4, then 2/4 until closing the order. Or if the STC comes at where it is on the 3/4 partial closing order then close, again whichever comes first until closing the order.
It should be possible but needs a little more complexity in the script.
 

quijanoj

New member
It should be possible but needs a little more complexity in the script.
can you write an example of how the AddOrder would be using the Partial close option, please? I have Googled and there is no info about partial close orders using thinkscript strategies.
 

barbaros

Administrator
Staff member
can you write an example of how the AddOrder would be using the Partial close option, please? I have Googled and there is no info about partial close orders using thinkscript strategies.
When opening a position, you would open with the order size you want to have. When exiting, you would exit partial as it hits certain conditions.

Here is the definition of the AddOrder function. https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Others/AddOrder

You would be passing in the tradeSize parameter to tell it how many shares you want it to trade.
 

quijanoj

New member
When opening a position, you would open with the order size you want to have. When exiting, you would exit partial as it hits certain conditions.

Here is the definition of the AddOrder function. https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Others/AddOrder

You would be passing in the tradeSize parameter to tell it how many shares you want it to trade.
This question is not related to this strategy at all but wanted to share maybe it can be helpful for others...

I am working on a strategy, I would like that the BTO signals start at the same place as the BTO arrows plot, not one bar after it plots...
Asqy80G.png


can you please help me? thanks
 

barbaros

Administrator
Staff member
This question is not related to this strategy at all but wanted to share maybe it can be helpful for others...

I am working on a strategy, I would like that the BTO signals start at the same place as the BTO arrows plot, not one bar after it plots...
Asqy80G.png


can you please help me? thanks
Entering at the signal bars is not realistic. You will need to wait for the bar to close in order to put your order in because the signals car repaint in the same bar. Usually, backtesting is done with the open price of the following bar of the signals bar.
 
Top