Can one backtest using a strategy that does not execute any trades on the chart?
###------------------------------------------------------------------------------------------
# Profit and Loss Labels
#
# Fill in the 0>0 in the Create Signals section below to match your buy and sell signal conditions
#
# When using large amounts of hisorical data, P/L may take time to calculate
###------------------------------------------------------------------------------------------
input showSignals = yes; #hint showSignals: show buy and sell arrows
input LongTrades = yes; #hint...
I was not able to open these links (just a blank screen). Anyone get them to open?
I was able to use the link. Thanks.You can try this, will have to remove the commission piece most likely. Should be able to paste in the TOS report, just clear out those columns before doing so. If nothing else, might give you a start to play around with to get it where you want.
Futures Strat Report (xls)
Can one backtest using a strategy that does not execute any trades on the chart?
###------------------------------------------------------------------------------------------
# Profit and Loss Labels
#
# Fill in the 0>0 in the Create Signals section below to match your buy and sell signal conditions
#
# When using large amounts of hisorical data, P/L may take time to calculate
###------------------------------------------------------------------------------------------
input showSignals = yes; #hint showSignals: show buy and sell arrows
input LongTrades = yes; #hint LongTrades: perform long trades
input ShortTrades = yes; #hint ShortTrades: perform short trades
input showLabels = yes; #hint showLabels: show PL labels at top
input showBubbles = yes; #hint showBubbles: show PL bubbles at close of trade
input useStops = no; #hint useStops: use stop orders
input useAlerts = no; #hint useAlerts: use alerts on signals
input tradeDaytimeOnly = no; #hint tradeDaytimeOnly: (IntraDay Only) Only perform trades during hours stated
input OpenTime = 0930; #hint OpenTime: Opening time of market
input CloseTime = 1600; #hint CloseTime: Closing time of market
input UseFuturesFees = no; #hint UseFutureFees: $6 round-trip
def Begin = secondsfromTime(OpenTime);
def End = secondsTillTime(closetime);
# Only use market hours when using intraday timeframe
def isIntraDay = if getaggregationperiod() > 14400000 or getaggregationperiod()==0 then 0 else 1;
def MarketOpen = if !tradeDaytimeOnly or !isIntraDay then 1 else if tradeDaytimeOnly and isIntraDay and Begin > 0 and End > 0 then 1 else 0;
###------------------------------------------------------------------------------------------
######################################################
## Create Signals -
## FILL IN THIS SECTION
## replace 0>0 with your conditions for signals
######################################################
def PLBuySignal = if MarketOpen AND (0>0) then 1 else 0 ; # insert condition to create long position in place of the 0>0
def PLSellSignal = if MarketOpen AND (0>0) then 1 else 0; # insert condition to create short position in place of the 0>0
def PLBuyStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0<0
def PLSellStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0>0
def PLMktStop = if MarketOpen[-1] == 0 then 1 else 0; # If tradeDaytimeOnly is set, then stop at end of day
#######################################
## Maintain the position of trades
#######################################
def CurrentPosition; # holds whether flat = 0 long = 1 short = -1
if (BarNumber()==1) OR isNaN(CurrentPosition[1]) {
CurrentPosition = 0;
}else{
if CurrentPosition[1] == 0 { # FLAT
if (PLBuySignal AND LongTrades) {
CurrentPosition = 1;
} else if (PLSellSignal AND ShortTrades){
CurrentPosition = -1;
} else {
CurrentPosition = CurrentPosition[1];
}
} else if CurrentPosition[1] == 1 { # LONG
if (PLSellSignal AND ShortTrades){
CurrentPosition = -1;
} else if ((PLBuyStop and useStops) or PLMktStop or (PLSellSignal AND ShortTrades==0)){
CurrentPosition = 0;
} else {
CurrentPosition = CurrentPosition[1];
}
} else if CurrentPosition[1] == -1 { # SHORT
if (PLBuySignal AND LongTrades){
CurrentPosition = 1;
} else if ((PLSellStop and useStops) or PLMktStop or (PlBuySignal and LongTrades==0)){
CurrentPosition = 0;
} else {
CurrentPosition = CurrentPosition[1];
}
} else {
CurrentPosition = CurrentPosition[1];
}
}
def isLong = if CurrentPosition == 1 then 1 else 0;
def isShort = if CurrentPosition == -1 then 1 else 0;
def isFlat = if CurrentPosition == 0 then 1 else 0;
# If not already long and get a PLBuySignal
#Plot BuySig = if (!isLong[1] and PLBuySignal and showSignals and LongTrades) then 1 else 0;
Plot BuySig = if (((isShort[1] and LongTrades) or (isFlat[1] and LongTrades)) and PLBuySignal and showSignals) then 1 else 0;
BuySig.AssignValueColor(color.cyan);
BuySig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BuySig.SetLineWeight(5);
Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding);
Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding);
# If not already short and get a PLSellSignal
Plot SellSig = if (((isLong[1] and ShortTrades) or (isFlat[1] and ShortTrades)) and PLSellSignal and showSignals) then 1 else 0;
SellSig.AssignValueColor(color.cyan);
SellSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
SellSig.SetLineWeight(5);
Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding);
Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding);
# If long and get a PLBuyStop
Plot BuyStpSig = if (PLBuyStop and isLong[1] and showSignals and useStops) or (isLong[1] and PLMktStop) or (isLong[1] and PLSellSignal and !ShortTrades) then 1 else 0;
BuyStpSig.AssignValueColor(color.light_gray);
BuyStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BuyStpSig.SetLineWeight(3);
Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding);
Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding);
# If short and get a PLSellStop
Plot SellStpSig = if (PLSellStop and isShort[1] and showSignals and useStops) or (isShort[1] and PLMktStop) or (isShort[1] and PLBuySignal and !LongTrades) then 1 else 0;
SellStpSig.AssignValueColor(color.light_gray);
SellStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
SellStpSig.SetLineWeight(3);
Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding);
Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding);
#######################################
## Orders
#######################################
def isOrder = if ((isFlat[1] and (BuySig and LongTrades) or (SellSig and ShortTrades)) or (isLong[1] and BuyStpSig or (SellSig and ShortTrades)) or (isShort[1] and SellStpSig or (BuySig and LongTrades))) then 1 else 0 ;
def orderPrice = if (isOrder and ((BuySig and LongTrades) or (SellSig and ShortTrades))) then (if isNan(open[-1]) then close else open[-1]) else orderPrice[1];
plot OPL = if !isFlat and isLong then orderPrice else double.Nan;
OPL.AssignValueColor(color.green);
OPL.SetPaintingStrategy(PaintingStrategy.lINE);
OPL.SetStyle(Curve.SHORT_DASH);
OPL.SetLineWeight(1);
plot OPS = if !isFlat and isShort then orderPrice else double.Nan;
OPS.AssignValueColor(color.red);
OPS.SetPaintingStrategy(PaintingStrategy.lINE);
OPS.SetStyle(Curve.SHORT_DASH);
OPS.SetLineWeight(1);
def orderCount = compoundValue(1,if isNan(isOrder) or barnumber()==1 then 0 else if (BuySig or SellSig) then orderCount[1]+1 else orderCount[1],0);
#######################################
## Price and Profit
#######################################
def profitLoss;
if (!isOrder or orderPRice[1]==0){
profitLoss = 0;
} else if ((isOrder and isLong[1]) and (SellSig or BuyStpSig)){
profitLoss = (if isNan(open[-1]) then close else open[-1]) - orderPrice[1];
} else if ((isOrder and isShort[1]) and (BuySig or SellStpSig)) {
profitLoss = orderPrice[1] - (if isNan(open[-1]) then close else open[-1]);
} else {
profitLoss = 0;
}
# Total Profit or Loss
def profitLossSum = compoundValue(1, if isNaN(isOrder) or barnumber()==1 then 0 else if isOrder then profitLossSum[1] + profitLoss else profitLossSum[1], 0);
# How many trades won or lost
def profitWinners = compoundValue(1, if isNaN(profitWinners[1]) or barnumber()==1 then 0 else if isOrder and profitLoss > 0 then profitWinners[1] + 1 else profitWinners[1], 0);
def profitLosers = compoundValue(1, if isNaN(profitLosers[1]) or barnumber()==1 then 0 else if isOrder and profitLoss < 0 then profitLosers[1] + 1 else profitLosers[1], 0);
def profitPush = compoundValue(1, if isNaN(profitPush[1]) or barnumber()==1 then 0 else if isOrder and profitLoss == 0 then profitPush[1] + 1 else profitPush[1], 0);
# Current Open Trade Profit or Loss
def TradePL = If isLong then Round(((close - orderprice)/TickSize())*TickValue()) else if isShort then Round(((orderPrice - close)/TickSize())*TickValue()) else 0;
# Convert to actual dollars based on Tick Value for bubbles
def dollarProfitLoss = if orderPRice[1]==0 or isNaN(orderPrice[1]) then 0 else round((profitLoss/Ticksize())*Tickvalue());
# Closed Orders dollar P/L
def dollarPLSum = round((profitLossSum/Ticksize())*Tickvalue());
# Split profits or losses by long and short trades
def profitLong = compoundValue(1, if isNan(profitLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then profitLong[1]+dollarProfitLoss else profitLong[1],0);
def profitShort = compoundValue(1, if isNan(profitShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then profitShort[1]+dollarProfitLoss else profitShort[1],0);
def countLong = compoundValue(1, if isNaN(countLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then countLong[1]+1 else countLong[1],0);
def countShort = compoundValue(1, if isNaN(countShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then countShort[1]+1 else countShort[1],0);
# What was the biggest winning and losing trade
def biggestWin = compoundValue(1, if isNaN(biggestWin[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss > 0) and (dollarProfitLoss > biggestWin[1]) then dollarProfitLoss else biggestWin[1], 0);
def biggestLoss = compoundValue(1, if isNaN(biggestLoss[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss < 0) and (dollarProfitLoss < biggestLoss[1]) then dollarProfitLoss else biggestLoss[1], 0);
def ClosedTradeCount = if (isLong or isShort) then orderCount-1 else orderCount;
def OpenTrades = if (isLong or isShort) then 1 else 0;
def FuturesCommission = 6*ClosedTradeCount;
# What percent were winners
def PCTWin = if (OpenTrades and (TradePL < 0)) then round((profitWinners/(ClosedTradeCount+1))*100,2)
else if (OpenTrades and (TradePL > 0)) then round(((profitWinners+1)/(ClosedTradeCount+1))*100,2) else round(((profitWinners)/(ClosedTradeCount))*100,2) ;
# Average trade
def avgTrade = if (OpenTrades and (TradePL < 0)) then round(((dollarPLSum - TradePL)/(ClosedTradeCount+1)),2)
else if (OpenTrades and (TradePL > 0)) then round(((dollarPLSum + TradePL)/(ClosedTradeCount+1)),2) else round(((dollarPLSum)/(ClosedTradeCount)),2) ;
#######################################
## Create Labels
#######################################
AddLabel(showLabels and isIntraDay, if MarketOpen then "Market Open" else "Market Closed", color.white);
AddLabel(showLabels, GetSymbol()+" Tick Size: "+TickSize()+" Value: "+TickValue(), color.white);
AddLabel(showLabels and (LongTrades and ShortTrades), "Long+Short Trades", color.white);
AddLabel(showLabels and (LongTrades and !ShortTrades),"Long Trades Only", color.white);
AddLabel(showLabels and (!LongTrades and ShortTrades),"Short Trades Only", color.white);
AddLabel(showLabels and (tradeDaytimeOnly),"Daytime Only", color.white);
AddLabel(showLabels and (UseFuturesFees),"Future Fees Incl", color.white);
AddLabel(showLabels, "Closed Orders: " + ClosedTradeCount + " P/L: " + AsDollars(dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if dollarPLSum > 0 then Color.GREEN else if dollarPLSum< 0 then Color.RED else Color.GRAY);
AddLabel(if !IsNan(orderPrice) and showLabels then 1 else 0, "Closed+Open P/L: "+ AsDollars(TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if ((TradePL+dollarPLSum) > 0) then color.green else if ((TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0) < 0) then color.red else color.gray);
AddLabel(showLabels, "Avg per Trade: "+ AsDollars(avgTrade - if UseFuturesFees then 6 else 0), if avgTrade > 0 then Color.Green else if avgTrade < 0 then Color.RED else Color.GRAY);
AddLabel(showLabels, "Winners: "+ PCTWin +"%",if PCTWin > 50 then color.green else if PCTWin > 40 then color.yellow else color.gray);
AddLabel(showLabels, "MaxUp: "+ AsDollars(biggestWin) +" MaxDown: "+AsDollars(biggestLoss), color.white);
AddLabel(showLabels, "Long Profit: " +AsDollars(profitLong), if profitLong > 0 then color.green else if profitLong < 0 then color.red else color.gray);
AddLabel(showLabels, "Short Profit: " +AsDollars(profitShort), if profitShort > 0 then color.green else if profitShort < 0 then color.red else color.gray);
AddLabel(if !IsNan(CurrentPosition) and showLabels and OpenTrades then 1 else 0, "Open: "+ (If isLong then "Bought" else "Sold") + " @ "+orderPrice, color.white);
AddLabel(if !IsNan(orderPrice) and showLabels and OpenTrades then 1 else 0, "Open Trade P/L: "+ AsDollars(TradePL), if (TradePL > 0) then color.green else if (TradePl < 0) then color.red else color.gray);
#######################################
## Chart Bubbles for Profit/Loss
#######################################
AddChartBubble(showSignals and showBubbles and isOrder and isLong[1], low, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 0);
AddChartBubble(showSignals and showBubbles and isOrder and isShort[1], high, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 1);
#AssignPriceColor(if CurrentPosition == 1 then color.green else if CurrentPosition == -1 then color.red else color.gray);
Thank you JoeDV. I do not know enough to implement your suggestions but I will try.I use the following code. Place this after your study and just define what the buy and sell conditions are, set the parameters, and you should be good.
Code:###------------------------------------------------------------------------------------------ # Profit and Loss Labels # # Fill in the 0>0 in the Create Signals section below to match your buy and sell signal conditions # # When using large amounts of hisorical data, P/L may take time to calculate ###------------------------------------------------------------------------------------------ input showSignals = yes; #hint showSignals: show buy and sell arrows input LongTrades = yes; #hint LongTrades: perform long trades input ShortTrades = yes; #hint ShortTrades: perform short trades input showLabels = yes; #hint showLabels: show PL labels at top input showBubbles = yes; #hint showBubbles: show PL bubbles at close of trade input useStops = no; #hint useStops: use stop orders input useAlerts = no; #hint useAlerts: use alerts on signals input tradeDaytimeOnly = no; #hint tradeDaytimeOnly: (IntraDay Only) Only perform trades during hours stated input OpenTime = 0930; #hint OpenTime: Opening time of market input CloseTime = 1600; #hint CloseTime: Closing time of market input UseFuturesFees = no; #hint UseFutureFees: $6 round-trip def Begin = secondsfromTime(OpenTime); def End = secondsTillTime(closetime); # Only use market hours when using intraday timeframe def isIntraDay = if getaggregationperiod() > 14400000 or getaggregationperiod()==0 then 0 else 1; def MarketOpen = if !tradeDaytimeOnly or !isIntraDay then 1 else if tradeDaytimeOnly and isIntraDay and Begin > 0 and End > 0 then 1 else 0; ###------------------------------------------------------------------------------------------ ###################################################### ## Create Signals - ## FILL IN THIS SECTION ## replace 0>0 with your conditions for signals ###################################################### def PLBuySignal = if MarketOpen AND (0>0) then 1 else 0 ; # insert condition to create long position in place of the 0>0 def PLSellSignal = if MarketOpen AND (0>0) then 1 else 0; # insert condition to create short position in place of the 0>0 def PLBuyStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0<0 def PLSellStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0>0 def PLMktStop = if MarketOpen[-1] == 0 then 1 else 0; # If tradeDaytimeOnly is set, then stop at end of day ####################################### ## Maintain the position of trades ####################################### def CurrentPosition; # holds whether flat = 0 long = 1 short = -1 if (BarNumber()==1) OR isNaN(CurrentPosition[1]) { CurrentPosition = 0; }else{ if CurrentPosition[1] == 0 { # FLAT if (PLBuySignal AND LongTrades) { CurrentPosition = 1; } else if (PLSellSignal AND ShortTrades){ CurrentPosition = -1; } else { CurrentPosition = CurrentPosition[1]; } } else if CurrentPosition[1] == 1 { # LONG if (PLSellSignal AND ShortTrades){ CurrentPosition = -1; } else if ((PLBuyStop and useStops) or PLMktStop or (PLSellSignal AND ShortTrades==0)){ CurrentPosition = 0; } else { CurrentPosition = CurrentPosition[1]; } } else if CurrentPosition[1] == -1 { # SHORT if (PLBuySignal AND LongTrades){ CurrentPosition = 1; } else if ((PLSellStop and useStops) or PLMktStop or (PlBuySignal and LongTrades==0)){ CurrentPosition = 0; } else { CurrentPosition = CurrentPosition[1]; } } else { CurrentPosition = CurrentPosition[1]; } } def isLong = if CurrentPosition == 1 then 1 else 0; def isShort = if CurrentPosition == -1 then 1 else 0; def isFlat = if CurrentPosition == 0 then 1 else 0; # If not already long and get a PLBuySignal #Plot BuySig = if (!isLong[1] and PLBuySignal and showSignals and LongTrades) then 1 else 0; Plot BuySig = if (((isShort[1] and LongTrades) or (isFlat[1] and LongTrades)) and PLBuySignal and showSignals) then 1 else 0; BuySig.AssignValueColor(color.cyan); BuySig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP); BuySig.SetLineWeight(5); Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding); Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding); # If not already short and get a PLSellSignal Plot SellSig = if (((isLong[1] and ShortTrades) or (isFlat[1] and ShortTrades)) and PLSellSignal and showSignals) then 1 else 0; SellSig.AssignValueColor(color.cyan); SellSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN); SellSig.SetLineWeight(5); Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding); Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding); # If long and get a PLBuyStop Plot BuyStpSig = if (PLBuyStop and isLong[1] and showSignals and useStops) or (isLong[1] and PLMktStop) or (isLong[1] and PLSellSignal and !ShortTrades) then 1 else 0; BuyStpSig.AssignValueColor(color.light_gray); BuyStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN); BuyStpSig.SetLineWeight(3); Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding); Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding); # If short and get a PLSellStop Plot SellStpSig = if (PLSellStop and isShort[1] and showSignals and useStops) or (isShort[1] and PLMktStop) or (isShort[1] and PLBuySignal and !LongTrades) then 1 else 0; SellStpSig.AssignValueColor(color.light_gray); SellStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP); SellStpSig.SetLineWeight(3); Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding); Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding); ####################################### ## Orders ####################################### def isOrder = if ((isFlat[1] and (BuySig and LongTrades) or (SellSig and ShortTrades)) or (isLong[1] and BuyStpSig or (SellSig and ShortTrades)) or (isShort[1] and SellStpSig or (BuySig and LongTrades))) then 1 else 0 ; def orderPrice = if (isOrder and ((BuySig and LongTrades) or (SellSig and ShortTrades))) then (if isNan(open[-1]) then close else open[-1]) else orderPrice[1]; plot OPL = if !isFlat and isLong then orderPrice else double.Nan; OPL.AssignValueColor(color.green); OPL.SetPaintingStrategy(PaintingStrategy.lINE); OPL.SetStyle(Curve.SHORT_DASH); OPL.SetLineWeight(1); plot OPS = if !isFlat and isShort then orderPrice else double.Nan; OPS.AssignValueColor(color.red); OPS.SetPaintingStrategy(PaintingStrategy.lINE); OPS.SetStyle(Curve.SHORT_DASH); OPS.SetLineWeight(1); def orderCount = compoundValue(1,if isNan(isOrder) or barnumber()==1 then 0 else if (BuySig or SellSig) then orderCount[1]+1 else orderCount[1],0); ####################################### ## Price and Profit ####################################### def profitLoss; if (!isOrder or orderPRice[1]==0){ profitLoss = 0; } else if ((isOrder and isLong[1]) and (SellSig or BuyStpSig)){ profitLoss = (if isNan(open[-1]) then close else open[-1]) - orderPrice[1]; } else if ((isOrder and isShort[1]) and (BuySig or SellStpSig)) { profitLoss = orderPrice[1] - (if isNan(open[-1]) then close else open[-1]); } else { profitLoss = 0; } # Total Profit or Loss def profitLossSum = compoundValue(1, if isNaN(isOrder) or barnumber()==1 then 0 else if isOrder then profitLossSum[1] + profitLoss else profitLossSum[1], 0); # How many trades won or lost def profitWinners = compoundValue(1, if isNaN(profitWinners[1]) or barnumber()==1 then 0 else if isOrder and profitLoss > 0 then profitWinners[1] + 1 else profitWinners[1], 0); def profitLosers = compoundValue(1, if isNaN(profitLosers[1]) or barnumber()==1 then 0 else if isOrder and profitLoss < 0 then profitLosers[1] + 1 else profitLosers[1], 0); def profitPush = compoundValue(1, if isNaN(profitPush[1]) or barnumber()==1 then 0 else if isOrder and profitLoss == 0 then profitPush[1] + 1 else profitPush[1], 0); # Current Open Trade Profit or Loss def TradePL = If isLong then Round(((close - orderprice)/TickSize())*TickValue()) else if isShort then Round(((orderPrice - close)/TickSize())*TickValue()) else 0; # Convert to actual dollars based on Tick Value for bubbles def dollarProfitLoss = if orderPRice[1]==0 or isNaN(orderPrice[1]) then 0 else round((profitLoss/Ticksize())*Tickvalue()); # Closed Orders dollar P/L def dollarPLSum = round((profitLossSum/Ticksize())*Tickvalue()); # Split profits or losses by long and short trades def profitLong = compoundValue(1, if isNan(profitLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then profitLong[1]+dollarProfitLoss else profitLong[1],0); def profitShort = compoundValue(1, if isNan(profitShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then profitShort[1]+dollarProfitLoss else profitShort[1],0); def countLong = compoundValue(1, if isNaN(countLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then countLong[1]+1 else countLong[1],0); def countShort = compoundValue(1, if isNaN(countShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then countShort[1]+1 else countShort[1],0); # What was the biggest winning and losing trade def biggestWin = compoundValue(1, if isNaN(biggestWin[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss > 0) and (dollarProfitLoss > biggestWin[1]) then dollarProfitLoss else biggestWin[1], 0); def biggestLoss = compoundValue(1, if isNaN(biggestLoss[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss < 0) and (dollarProfitLoss < biggestLoss[1]) then dollarProfitLoss else biggestLoss[1], 0); def ClosedTradeCount = if (isLong or isShort) then orderCount-1 else orderCount; def OpenTrades = if (isLong or isShort) then 1 else 0; def FuturesCommission = 6*ClosedTradeCount; # What percent were winners def PCTWin = if (OpenTrades and (TradePL < 0)) then round((profitWinners/(ClosedTradeCount+1))*100,2) else if (OpenTrades and (TradePL > 0)) then round(((profitWinners+1)/(ClosedTradeCount+1))*100,2) else round(((profitWinners)/(ClosedTradeCount))*100,2) ; # Average trade def avgTrade = if (OpenTrades and (TradePL < 0)) then round(((dollarPLSum - TradePL)/(ClosedTradeCount+1)),2) else if (OpenTrades and (TradePL > 0)) then round(((dollarPLSum + TradePL)/(ClosedTradeCount+1)),2) else round(((dollarPLSum)/(ClosedTradeCount)),2) ; ####################################### ## Create Labels ####################################### AddLabel(showLabels and isIntraDay, if MarketOpen then "Market Open" else "Market Closed", color.white); AddLabel(showLabels, GetSymbol()+" Tick Size: "+TickSize()+" Value: "+TickValue(), color.white); AddLabel(showLabels and (LongTrades and ShortTrades), "Long+Short Trades", color.white); AddLabel(showLabels and (LongTrades and !ShortTrades),"Long Trades Only", color.white); AddLabel(showLabels and (!LongTrades and ShortTrades),"Short Trades Only", color.white); AddLabel(showLabels and (tradeDaytimeOnly),"Daytime Only", color.white); AddLabel(showLabels and (UseFuturesFees),"Future Fees Incl", color.white); AddLabel(showLabels, "Closed Orders: " + ClosedTradeCount + " P/L: " + AsDollars(dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if dollarPLSum > 0 then Color.GREEN else if dollarPLSum< 0 then Color.RED else Color.GRAY); AddLabel(if !IsNan(orderPrice) and showLabels then 1 else 0, "Closed+Open P/L: "+ AsDollars(TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if ((TradePL+dollarPLSum) > 0) then color.green else if ((TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0) < 0) then color.red else color.gray); AddLabel(showLabels, "Avg per Trade: "+ AsDollars(avgTrade - if UseFuturesFees then 6 else 0), if avgTrade > 0 then Color.Green else if avgTrade < 0 then Color.RED else Color.GRAY); AddLabel(showLabels, "Winners: "+ PCTWin +"%",if PCTWin > 50 then color.green else if PCTWin > 40 then color.yellow else color.gray); AddLabel(showLabels, "MaxUp: "+ AsDollars(biggestWin) +" MaxDown: "+AsDollars(biggestLoss), color.white); AddLabel(showLabels, "Long Profit: " +AsDollars(profitLong), if profitLong > 0 then color.green else if profitLong < 0 then color.red else color.gray); AddLabel(showLabels, "Short Profit: " +AsDollars(profitShort), if profitShort > 0 then color.green else if profitShort < 0 then color.red else color.gray); AddLabel(if !IsNan(CurrentPosition) and showLabels and OpenTrades then 1 else 0, "Open: "+ (If isLong then "Bought" else "Sold") + " @ "+orderPrice, color.white); AddLabel(if !IsNan(orderPrice) and showLabels and OpenTrades then 1 else 0, "Open Trade P/L: "+ AsDollars(TradePL), if (TradePL > 0) then color.green else if (TradePl < 0) then color.red else color.gray); ####################################### ## Chart Bubbles for Profit/Loss ####################################### AddChartBubble(showSignals and showBubbles and isOrder and isLong[1], low, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 0); AddChartBubble(showSignals and showBubbles and isOrder and isShort[1], high, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 1); #AssignPriceColor(if CurrentPosition == 1 then color.green else if CurrentPosition == -1 then color.red else color.gray);
This ^^^^ . You must always be aware when backtesting not just to be curve fitting. Basically, finding what worked the best based on past data, but not necessarily what will work in the future. One unusual move one way or the other in the past might make overall results look great, but the rest of the time could be a relative disaster.
I use the following code. Place this after your study and just define what the buy and sell conditions are, set the parameters, and you should be good.
Code:###------------------------------------------------------------------------------------------ # Profit and Loss Labels # # Fill in the 0>0 in the Create Signals section below to match your buy and sell signal conditions # # When using large amounts of hisorical data, P/L may take time to calculate ###------------------------------------------------------------------------------------------ input showSignals = yes; #hint showSignals: show buy and sell arrows input LongTrades = yes; #hint LongTrades: perform long trades input ShortTrades = yes; #hint ShortTrades: perform short trades input showLabels = yes; #hint showLabels: show PL labels at top input showBubbles = yes; #hint showBubbles: show PL bubbles at close of trade input useStops = no; #hint useStops: use stop orders input useAlerts = no; #hint useAlerts: use alerts on signals input tradeDaytimeOnly = no; #hint tradeDaytimeOnly: (IntraDay Only) Only perform trades during hours stated input OpenTime = 0930; #hint OpenTime: Opening time of market input CloseTime = 1600; #hint CloseTime: Closing time of market input UseFuturesFees = no; #hint UseFutureFees: $6 round-trip def Begin = secondsfromTime(OpenTime); def End = secondsTillTime(closetime); # Only use market hours when using intraday timeframe def isIntraDay = if getaggregationperiod() > 14400000 or getaggregationperiod()==0 then 0 else 1; def MarketOpen = if !tradeDaytimeOnly or !isIntraDay then 1 else if tradeDaytimeOnly and isIntraDay and Begin > 0 and End > 0 then 1 else 0; ###------------------------------------------------------------------------------------------ ###################################################### ## Create Signals - ## FILL IN THIS SECTION ## replace 0>0 with your conditions for signals ###################################################### def PLBuySignal = if MarketOpen AND (0>0) then 1 else 0 ; # insert condition to create long position in place of the 0>0 def PLSellSignal = if MarketOpen AND (0>0) then 1 else 0; # insert condition to create short position in place of the 0>0 def PLBuyStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0<0 def PLSellStop = if !useStops then 0 else if (0>0) then 1 else 0 ; # insert condition to stop in place of the 0>0 def PLMktStop = if MarketOpen[-1] == 0 then 1 else 0; # If tradeDaytimeOnly is set, then stop at end of day ####################################### ## Maintain the position of trades ####################################### def CurrentPosition; # holds whether flat = 0 long = 1 short = -1 if (BarNumber()==1) OR isNaN(CurrentPosition[1]) { CurrentPosition = 0; }else{ if CurrentPosition[1] == 0 { # FLAT if (PLBuySignal AND LongTrades) { CurrentPosition = 1; } else if (PLSellSignal AND ShortTrades){ CurrentPosition = -1; } else { CurrentPosition = CurrentPosition[1]; } } else if CurrentPosition[1] == 1 { # LONG if (PLSellSignal AND ShortTrades){ CurrentPosition = -1; } else if ((PLBuyStop and useStops) or PLMktStop or (PLSellSignal AND ShortTrades==0)){ CurrentPosition = 0; } else { CurrentPosition = CurrentPosition[1]; } } else if CurrentPosition[1] == -1 { # SHORT if (PLBuySignal AND LongTrades){ CurrentPosition = 1; } else if ((PLSellStop and useStops) or PLMktStop or (PlBuySignal and LongTrades==0)){ CurrentPosition = 0; } else { CurrentPosition = CurrentPosition[1]; } } else { CurrentPosition = CurrentPosition[1]; } } def isLong = if CurrentPosition == 1 then 1 else 0; def isShort = if CurrentPosition == -1 then 1 else 0; def isFlat = if CurrentPosition == 0 then 1 else 0; # If not already long and get a PLBuySignal #Plot BuySig = if (!isLong[1] and PLBuySignal and showSignals and LongTrades) then 1 else 0; Plot BuySig = if (((isShort[1] and LongTrades) or (isFlat[1] and LongTrades)) and PLBuySignal and showSignals) then 1 else 0; BuySig.AssignValueColor(color.cyan); BuySig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP); BuySig.SetLineWeight(5); Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding); Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding); # If not already short and get a PLSellSignal Plot SellSig = if (((isLong[1] and ShortTrades) or (isFlat[1] and ShortTrades)) and PLSellSignal and showSignals) then 1 else 0; SellSig.AssignValueColor(color.cyan); SellSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN); SellSig.SetLineWeight(5); Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding); Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding); # If long and get a PLBuyStop Plot BuyStpSig = if (PLBuyStop and isLong[1] and showSignals and useStops) or (isLong[1] and PLMktStop) or (isLong[1] and PLSellSignal and !ShortTrades) then 1 else 0; BuyStpSig.AssignValueColor(color.light_gray); BuyStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN); BuyStpSig.SetLineWeight(3); Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding); Alert(BuyStpSig and useAlerts, "Buy Stop Signal",Alert.bar,sound.Ding); # If short and get a PLSellStop Plot SellStpSig = if (PLSellStop and isShort[1] and showSignals and useStops) or (isShort[1] and PLMktStop) or (isShort[1] and PLBuySignal and !LongTrades) then 1 else 0; SellStpSig.AssignValueColor(color.light_gray); SellStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP); SellStpSig.SetLineWeight(3); Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding); Alert(SellStpSig and useAlerts, "Sell Stop Signal",Alert.bar,sound.Ding); ####################################### ## Orders ####################################### def isOrder = if ((isFlat[1] and (BuySig and LongTrades) or (SellSig and ShortTrades)) or (isLong[1] and BuyStpSig or (SellSig and ShortTrades)) or (isShort[1] and SellStpSig or (BuySig and LongTrades))) then 1 else 0 ; def orderPrice = if (isOrder and ((BuySig and LongTrades) or (SellSig and ShortTrades))) then (if isNan(open[-1]) then close else open[-1]) else orderPrice[1]; plot OPL = if !isFlat and isLong then orderPrice else double.Nan; OPL.AssignValueColor(color.green); OPL.SetPaintingStrategy(PaintingStrategy.lINE); OPL.SetStyle(Curve.SHORT_DASH); OPL.SetLineWeight(1); plot OPS = if !isFlat and isShort then orderPrice else double.Nan; OPS.AssignValueColor(color.red); OPS.SetPaintingStrategy(PaintingStrategy.lINE); OPS.SetStyle(Curve.SHORT_DASH); OPS.SetLineWeight(1); def orderCount = compoundValue(1,if isNan(isOrder) or barnumber()==1 then 0 else if (BuySig or SellSig) then orderCount[1]+1 else orderCount[1],0); ####################################### ## Price and Profit ####################################### def profitLoss; if (!isOrder or orderPRice[1]==0){ profitLoss = 0; } else if ((isOrder and isLong[1]) and (SellSig or BuyStpSig)){ profitLoss = (if isNan(open[-1]) then close else open[-1]) - orderPrice[1]; } else if ((isOrder and isShort[1]) and (BuySig or SellStpSig)) { profitLoss = orderPrice[1] - (if isNan(open[-1]) then close else open[-1]); } else { profitLoss = 0; } # Total Profit or Loss def profitLossSum = compoundValue(1, if isNaN(isOrder) or barnumber()==1 then 0 else if isOrder then profitLossSum[1] + profitLoss else profitLossSum[1], 0); # How many trades won or lost def profitWinners = compoundValue(1, if isNaN(profitWinners[1]) or barnumber()==1 then 0 else if isOrder and profitLoss > 0 then profitWinners[1] + 1 else profitWinners[1], 0); def profitLosers = compoundValue(1, if isNaN(profitLosers[1]) or barnumber()==1 then 0 else if isOrder and profitLoss < 0 then profitLosers[1] + 1 else profitLosers[1], 0); def profitPush = compoundValue(1, if isNaN(profitPush[1]) or barnumber()==1 then 0 else if isOrder and profitLoss == 0 then profitPush[1] + 1 else profitPush[1], 0); # Current Open Trade Profit or Loss def TradePL = If isLong then Round(((close - orderprice)/TickSize())*TickValue()) else if isShort then Round(((orderPrice - close)/TickSize())*TickValue()) else 0; # Convert to actual dollars based on Tick Value for bubbles def dollarProfitLoss = if orderPRice[1]==0 or isNaN(orderPrice[1]) then 0 else round((profitLoss/Ticksize())*Tickvalue()); # Closed Orders dollar P/L def dollarPLSum = round((profitLossSum/Ticksize())*Tickvalue()); # Split profits or losses by long and short trades def profitLong = compoundValue(1, if isNan(profitLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then profitLong[1]+dollarProfitLoss else profitLong[1],0); def profitShort = compoundValue(1, if isNan(profitShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then profitShort[1]+dollarProfitLoss else profitShort[1],0); def countLong = compoundValue(1, if isNaN(countLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then countLong[1]+1 else countLong[1],0); def countShort = compoundValue(1, if isNaN(countShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then countShort[1]+1 else countShort[1],0); # What was the biggest winning and losing trade def biggestWin = compoundValue(1, if isNaN(biggestWin[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss > 0) and (dollarProfitLoss > biggestWin[1]) then dollarProfitLoss else biggestWin[1], 0); def biggestLoss = compoundValue(1, if isNaN(biggestLoss[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss < 0) and (dollarProfitLoss < biggestLoss[1]) then dollarProfitLoss else biggestLoss[1], 0); def ClosedTradeCount = if (isLong or isShort) then orderCount-1 else orderCount; def OpenTrades = if (isLong or isShort) then 1 else 0; def FuturesCommission = 6*ClosedTradeCount; # What percent were winners def PCTWin = if (OpenTrades and (TradePL < 0)) then round((profitWinners/(ClosedTradeCount+1))*100,2) else if (OpenTrades and (TradePL > 0)) then round(((profitWinners+1)/(ClosedTradeCount+1))*100,2) else round(((profitWinners)/(ClosedTradeCount))*100,2) ; # Average trade def avgTrade = if (OpenTrades and (TradePL < 0)) then round(((dollarPLSum - TradePL)/(ClosedTradeCount+1)),2) else if (OpenTrades and (TradePL > 0)) then round(((dollarPLSum + TradePL)/(ClosedTradeCount+1)),2) else round(((dollarPLSum)/(ClosedTradeCount)),2) ; ####################################### ## Create Labels ####################################### AddLabel(showLabels and isIntraDay, if MarketOpen then "Market Open" else "Market Closed", color.white); AddLabel(showLabels, GetSymbol()+" Tick Size: "+TickSize()+" Value: "+TickValue(), color.white); AddLabel(showLabels and (LongTrades and ShortTrades), "Long+Short Trades", color.white); AddLabel(showLabels and (LongTrades and !ShortTrades),"Long Trades Only", color.white); AddLabel(showLabels and (!LongTrades and ShortTrades),"Short Trades Only", color.white); AddLabel(showLabels and (tradeDaytimeOnly),"Daytime Only", color.white); AddLabel(showLabels and (UseFuturesFees),"Future Fees Incl", color.white); AddLabel(showLabels, "Closed Orders: " + ClosedTradeCount + " P/L: " + AsDollars(dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if dollarPLSum > 0 then Color.GREEN else if dollarPLSum< 0 then Color.RED else Color.GRAY); AddLabel(if !IsNan(orderPrice) and showLabels then 1 else 0, "Closed+Open P/L: "+ AsDollars(TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0), if ((TradePL+dollarPLSum) > 0) then color.green else if ((TradePL+dollarPLSum - if UseFuturesFees then FuturesCommission else 0) < 0) then color.red else color.gray); AddLabel(showLabels, "Avg per Trade: "+ AsDollars(avgTrade - if UseFuturesFees then 6 else 0), if avgTrade > 0 then Color.Green else if avgTrade < 0 then Color.RED else Color.GRAY); AddLabel(showLabels, "Winners: "+ PCTWin +"%",if PCTWin > 50 then color.green else if PCTWin > 40 then color.yellow else color.gray); AddLabel(showLabels, "MaxUp: "+ AsDollars(biggestWin) +" MaxDown: "+AsDollars(biggestLoss), color.white); AddLabel(showLabels, "Long Profit: " +AsDollars(profitLong), if profitLong > 0 then color.green else if profitLong < 0 then color.red else color.gray); AddLabel(showLabels, "Short Profit: " +AsDollars(profitShort), if profitShort > 0 then color.green else if profitShort < 0 then color.red else color.gray); AddLabel(if !IsNan(CurrentPosition) and showLabels and OpenTrades then 1 else 0, "Open: "+ (If isLong then "Bought" else "Sold") + " @ "+orderPrice, color.white); AddLabel(if !IsNan(orderPrice) and showLabels and OpenTrades then 1 else 0, "Open Trade P/L: "+ AsDollars(TradePL), if (TradePL > 0) then color.green else if (TradePl < 0) then color.red else color.gray); ####################################### ## Chart Bubbles for Profit/Loss ####################################### AddChartBubble(showSignals and showBubbles and isOrder and isLong[1], low, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 0); AddChartBubble(showSignals and showBubbles and isOrder and isShort[1], high, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 1); #AssignPriceColor(if CurrentPosition == 1 then color.green else if CurrentPosition == -1 then color.red else color.gray);
You must always be aware when backtesting not just to be curve fitting. Basically, finding what worked the best based on past data, but not necessarily what will work in the future. One unusual move one way or the other in the past might make overall results look great, but the rest of the time could be a relative disaster.
Do you have a specific strategy you want to implement with that script?The question is really about the strategy report from backtesting. I have tried many strategies yielding a strategy report but if I use a simple strategy that does not take any trades or does give a strategy report how do I learn anything? I am really new at this. Thanks for being patient.
Thank you JoeDV. I do not know enough to implement your suggestions but I will try.
the author of Evidence-Based Technical Analysis, stock trader David Aronson, backtested 6,402 trading rules for his book. None of the strategies produced gains beyond what would be expected by random chance.
The ToS platform cannot provide the data to answer your question.Buy & hold.. If you bought 1 share of SPX on 1/2/1962 at the open (71.55) it would be worth 4154.87 on 4/18/2023 close. This is a 5700% gain. The duration was just over 61 years.
If I backtest a simple trend-following strategy, how would you mathematically compare the results to buy & hold? I have one I think is pretty good. Since 1/2/1962 it's had 429 trades with an average holding time of 21 days, and I'm having a hard time making an apples-to-apples comparison, in order to determine if it beats buy & hold.
If anyone has any insight or experience in this area, I would sure appreciate the help.
reply to post14Buy & hold.. If you bought 1 share of SPX on 1/2/1962 at the open (71.55) it would be worth 4154.87 on 4/18/2023 close. This is a 5700% gain. The duration was just over 61 years.
If I backtest a simple trend-following strategy, how would you mathematically compare the results to buy & hold? I have one I think is pretty good. Since 1/2/1962 it's had 429 trades with an average holding time of 21 days, and I'm having a hard time making an apples-to-apples comparison, in order to determine if it beats buy & hold.
If anyone has any insight or experience in this area, I would sure appreciate the help.
Join useThinkScript to post your question to a community of 21,000+ developers and traders.
Thread starter | Similar threads | Forum | Replies | Date |
---|---|---|---|---|
![]() |
Addorder to imported existing script for backtesting | Questions | 1 | |
B | Backtesting Iron Butterfly Credit Spread | Questions | 1 | |
T | Are There NO MTF Multi-Timeframe Strategies For BackTesting?? | Questions | 1 | |
G | Backtesting On Tick Chart | Questions | 1 | |
C | Backtesting Multiple Exits | Questions | 1 |
Start a new thread and receive assistance from our community.
useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.
We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.
If you are new, or just looking for guidance, here are some helpful links to get you started.