P&L Max Drawdown

Kevin N

Member
Hello, I need some code help. This can be applied to the bottom of any strategy and is super helpful.

I was surfing this site the past couple days and came across a posters strategy he was using that contained some really nice P&L info.
https://usethinkscript.com/threads/...acktesting-data-utility-for-thinkorswim.1624/

I'm able to use this in all my strategies to give me some good insight. One thing is was missing, a max loss count and a max draw down in dollars. I'm trying to modify this but after several hours I'm stumped. Can someone take a look and see if you can tell me what I'm doing wrong. I noted the area I'm working in with "My Add". It always returns 1, I thought I was incrementing based on losers in a row, but apparently not. I have not started on the Max Drawdown label yet. Thanks in advance

Code:
### Use this below any script to give Win/Loss info ###

input showStats = yes;

#Globals
def nan = Double.NaN;
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];

#Inputs
input fplTargetWinLoss = .50;
#hint fplTargetWinLoss: sets the target winlossRatio (in percent) which determines display colors of the W/L label.

input fplTargetWinRate = 1;
#hint fplTargetWinRate: sets the target winRate (float) which determines display colors of the WinRate label;

input fplHidePrice = no;
#hint fplHidePrice: hide's the underlying price graph. \nDefault is no.

input fplHideFPL = yes;
#hint fplHideFPL: hide's the underlying P&L graph.\nDefault is yes.

#temp input var references
def targetWinLoss = fplTargetWinLoss;
def targetWinRate = fplTargetWinRate;
def hidePrice = fplHidePrice;
def hideFPL = fplHideFPL;

#hide chart candles
HidePricePlot(hidePrice);

#Plot default Floating P&L
plot FPL = FPL();
FPL.SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
FPL.DefineColor("Positive and Up", Color.GREEN);
FPL.DefineColor("Positive and Down", Color.DARK_GREEN);
FPL.DefineColor("Negative and Down", Color.RED);
FPL.DefineColor("Negative and Up", Color.DARK_RED);
FPL.AssignValueColor(if FPL >= 0
                        then if FPL > FPL[1]
                        then FPL.Color("Positive and Up")
                        else FPL.Color("Positive and Down")
                        else if FPL < FPL[1]
                        then FPL.Color("Negative and Down")
                        else FPL.Color("Negative and Up"));
FPL.SetHiding(hideFPL);

plot ZeroLine = if IsNaN(close)
            then nan
            else 0;
ZeroLine.SetDefaultColor(Color.GRAY);
ZeroLine.SetHiding(hideFPL);

#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 entry = EntryPrice();

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 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 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 / entryCount;
def avgReturn = TotalSum(entryFPLAll) / entryCount;
def avgWin = TotalSum(entryFPLWins) / winCount;
def avgLoss = TotalSum(entryFPLLosses) / lossCount;

# My Add -----------------------------------------
# This is the area I can't seem to understand what I'm doing wrong

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def maxLossCount  = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
 
AddLabel(showStats,
        text = "Max Loss Count: " + maxLossCount +
            "  ",
        color = color.ORANGE
        );

# End My Add -------------------------------------

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

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

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

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

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

Regards, Kevin
 
Last edited by a moderator:
Solution
@Kevin N
Threw the the whole code into an existing Donchian Strat.
We were resetting on the wrong line.
isloss already gets reset earlier in the code, so only 1 or 0 was getting passed to tmpMaxLossCount.
So after fixing that, you have two options for maxLossCount, either highest number of losses in a row or highest number of losses in a row since the last win.

Code:
# test -----------------------------------------
#def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def tmpMaxLossCount = if iswin then 0 else if isLoss then tmpMaxLossCount[1] + 1 else tmpMaxLossCount[1];

#Use this line to see highest amount of sequential losses.#
#def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else...
Hello, I need some code help. This can be applied to the bottom of any strategy and is super helpful.

I was surfing this site the past couple days and came across a posters strategy he was using that contained some really nice P&L info. I'm able to use this in all my strategies to give me some good insight. One thing is was missing, a max loss count and a max draw down in dollars. I'm trying to modify this but after several hours I'm stumped. Can someone take a look and see if you can tell me what I'm doing wrong. I noted the area I'm working in with "My Add". It always returns 1, I thought I was incrementing based on losers in a row, but apparently not. I have not started on the Max Drawdown label yet. Thanks in advance

Code:
### Use this below any script to give Win/Loss info ###

input showStats = yes;

#Globals
def nan = Double.NaN;
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];

#Inputs
input fplTargetWinLoss = .50;
#hint fplTargetWinLoss: sets the target winlossRatio (in percent) which determines display colors of the W/L label.

input fplTargetWinRate = 1;
#hint fplTargetWinRate: sets the target winRate (float) which determines display colors of the WinRate label;

input fplHidePrice = no;
#hint fplHidePrice: hide's the underlying price graph. \nDefault is no.

input fplHideFPL = yes;
#hint fplHideFPL: hide's the underlying P&L graph.\nDefault is yes.

#temp input var references
def targetWinLoss = fplTargetWinLoss;
def targetWinRate = fplTargetWinRate;
def hidePrice = fplHidePrice;
def hideFPL = fplHideFPL;

#hide chart candles
HidePricePlot(hidePrice);

#Plot default Floating P&L
plot FPL = FPL();
FPL.SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
FPL.DefineColor("Positive and Up", Color.GREEN);
FPL.DefineColor("Positive and Down", Color.DARK_GREEN);
FPL.DefineColor("Negative and Down", Color.RED);
FPL.DefineColor("Negative and Up", Color.DARK_RED);
FPL.AssignValueColor(if FPL >= 0
                        then if FPL > FPL[1]
                        then FPL.Color("Positive and Up")
                        else FPL.Color("Positive and Down")
                        else if FPL < FPL[1]
                        then FPL.Color("Negative and Down")
                        else FPL.Color("Negative and Up"));
FPL.SetHiding(hideFPL);

plot ZeroLine = if IsNaN(close)
            then nan
            else 0;
ZeroLine.SetDefaultColor(Color.GRAY);
ZeroLine.SetHiding(hideFPL);

#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 entry = EntryPrice();

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 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 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 / entryCount;
def avgReturn = TotalSum(entryFPLAll) / entryCount;
def avgWin = TotalSum(entryFPLWins) / winCount;
def avgLoss = TotalSum(entryFPLLosses) / lossCount;

# My Add -----------------------------------------
# This is the area I can't seem to understand what I'm doing wrong

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def maxLossCount  = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
 
AddLabel(showStats,
        text = "Max Loss Count: " + maxLossCount +
            "  ",
        color = color.ORANGE
        );

# End My Add -------------------------------------

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

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

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

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

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

Regards, Kevin

if you want to find how many times a trade closed in a loss, on the chart,
( when isloss = 1 )

delete these 2 lines

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;

def maxLossCount = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];


add this

def maxLossCount = if isLoss then LossCount[1] + 1 else LossCount[1];
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

if you want to find how many times a trade closed in a loss, on the chart,
( when isloss = 1 )

delete these 2 lines

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;

def maxLossCount = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];


add this

def maxLossCount = if isLoss then LossCount[1] + 1 else LossCount[1];
Thanks for the response, but this will only count the total losers for the entire strategy, there is no reset mechanism (eg: else 0). For example, lets see we have 3 losses since the last winner, and 3 is the most losses we've had in a row... Then I'm trying to see 3 as my maxLossCount.

Let me explain what I think SHOULD be happening.

# if this bar is a loss, then we add 1 to the last tmpMaxLossCount[1], which should set tmpMaxLossCount[0] to 1, if this bar is not a loss, we reset to zero.

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;

# If the last trade was a loser and this trade is a loser, we verify that by seeing if tmpMaxLossCount is greater than the previous tmpMaxLossCount[1]. If it is greater, we store that number in maxLossCount, otherwise we retain the max losses in a row by assigning the last maxLossCount[1] to the current maxLossCount.

def maxLossCount = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

Not sure if that clears things up or makes it worse..... LOL. Thanks :)
 
Thanks for the response, but this will only count the total losers for the entire strategy, there is no reset mechanism (eg: else 0). For example, lets see we have 3 losses since the last winner, and 3 is the most losses we've had in a row... Then I'm trying to see 3 as my maxLossCount.

Let me explain what I think SHOULD be happening.

# if this bar is a loss, then we add 1 to the last tmpMaxLossCount[1], which should set tmpMaxLossCount[0] to 1, if this bar is not a loss, we reset to zero.

def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;

# If the last trade was a loser and this trade is a loser, we verify that by seeing if tmpMaxLossCount is greater than the previous tmpMaxLossCount[1]. If it is greater, we store that number in maxLossCount, otherwise we retain the max losses in a row by assigning the last maxLossCount[1] to the current maxLossCount.

def maxLossCount = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

Not sure if that clears things up or makes it worse..... LOL. Thanks :)

ah, ok
if you want a win to reset the loss count to 0, then,

def maxLossCount =
if iswin then 0
else if isLoss then LossCount[1] + 1
else LossCount[1];
 
ah, ok
if you want a win to reset the loss count to 0, then,

def maxLossCount =
if iswin then 0
else if isLoss then LossCount[1] + 1
else LossCount[1];

This gives me the total losses for the duration of the Strategy (eg: 39 on what I"m looking at this moment), this is what's making my head hurt :) LOL
 
@Kevin N Shouldn't this line of your origingal code:
Code:
def maxLossCount  = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
be changed to:
Code:
def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
 
Last edited:
Shouldn't this line of your origingal code:
Code:
def maxLossCount  = if tmpMaxLossCount > tmpMaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
be changed to:
Code:
def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
This gives me 1 in maxLossCount.

Code:
def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
 
@Kevin N The code works counting highest number of losses in a row.
code.jpg


chart.jpg


If your are wanting to reset maxLossCount after every win then change:
Code:
def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
to
Code:
def maxLossCount  = if iswin then 0 else if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

code2.jpg


chart2.jpg
 
@Kevin N The code works counting highest number of losses in a row.
code.jpg


chart.jpg


If your are wanting to reset maxLossCount after every win then change:
Code:
def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
to
Code:
def maxLossCount  = if iswin then 0 else if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

code2.jpg


chart2.jpg

Thanks @Svanoy, Perhaps I'm not comprehending something on how the isLoss and isWin is created, and this may be part of the problem. I'm using the Extended P&L recently posted on this forum. When I use your suggestion, it still gives me 1, but you defined the isLoss and isWin using very clear open and close conditions. So, now this has me looking closer at the isWin and isLoss variable to see if that's where the issue might be. I marked my spot with #Test.


Code:
############################
# FPL Extended
# Extended Floating P&L study.
# Author: Eddielee394
# Version: 1.2
# inspired by FPL Dashboard script developed by Mobius
#
############################

#Hint: An extended floating P&L study to be used alongside TOS strategies for measuring hypothetical strategy performance.\nThis is a work in progress.  And may contain some bugs or other programming issues.

############################
# Instructions
# - Due to limitations with the thinkscript public api, this specific script must be added to a "strategy" study.
#   Generally best practice is to append this script to the end of your custom strategy (ensuring it runs AFTER the
#   `AddOrder()` function is called from the strategy).  A better method would be to use as a lower study but unless
#    a workaround is implemented to handle the `Entry()` function in a lower study, it can only be applied to upper strategies.
#
# - the script uses the `HidePrice()` function which will hide the actual price candles within the upper study,
#   only displaying the FPL histogram.
#
############################


############################
#    Metrics             
#  - Active Trade return %
#  - Entry Count         
#  - Winning Entry Count 
#  - Win rate             
#  - Avg return           
#  - avg win             
#  - avg loss             
#  - peak to valley dd   
#  - largest equity dd   
#  - P&L low             
#  - P&L high             
#  - Highest return     
#  - Lowest return     
############################

############################
#     Todo:               
# - Sharpe Ratio     
# - Sortino Ratio     
# - Calmar Ratio     
# - Avg trade         
#   duration             
# -Buy/hold comparison   
############################


#Globals
def nan = Double.NaN;
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];

#Inputs
input fplBegin = 0000;
#hint fplBegin: start time: the time in which then dailyHighLow profit should consider the day start.  Recommended value is 0000.

input fplTargetWinLoss = .50;
#hint fplTargetWinLoss: sets the target winlossRatio (in percent) which determines display colors of the W/L label.

input fplTargetWinRate = 1;
#hint fplTargetWinRate: sets the target winRate (float) which determines display colors of the WinRate label;

input fplHidePrice = no;
#hint fplHidePrice: hide's the underlying price graph. \nDefault is no.

input fplHideFPL = yes;
#hint fplHideFPL: hide's the underlying P&L graph.\nDefault is yes.

input fplShowEntryBubbles = no;
#hint fplShowEntryBubbles: display bubbles on the FPL showing the entry and exit P&L values

input fplEnableDebugging = no;
#hint fplEnableDebugging: displays various debugging labels and chart bubbles. \nIt's recommended to hide the price chart & set the fpl hide fpl setting to yes, when enabling.

#temp input var references
def begin = fplBegin;
def targetWinLoss = fplTargetWinLoss;
def targetWinRate = fplTargetWinRate;
def hidePrice = fplHidePrice;
def hideFPL = fplHideFPL;
def showEntryBubbles = fplShowEntryBubbles;
def enableDebugging = fplEnableDebugging;

#hide chart candles
HidePricePlot(hidePrice);

#Plot default Floating P&L
plot FPL = FPL();
FPL.SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
FPL.DefineColor("Positive and Up", Color.GREEN);
FPL.DefineColor("Positive and Down", Color.DARK_GREEN);
FPL.DefineColor("Negative and Down", Color.RED);
FPL.DefineColor("Negative and Up", Color.DARK_RED);
FPL.AssignValueColor(if FPL >= 0
                            then if FPL > FPL[1]
                            then FPL.Color("Positive and Up")
                            else FPL.Color("Positive and Down")
                            else if FPL < FPL[1]
                            then FPL.Color("Negative and Down")
                            else FPL.Color("Negative and Up"));
FPL.SetHiding(hideFPL);

plot ZeroLine = if IsNaN(close)
                then nan
                else 0;
ZeroLine.SetDefaultColor(Color.GRAY);
ZeroLine.SetHiding(hideFPL);

#Global Scripts
script calculateDrawdown {
    input plLow = 1;
    input plHigh = 1;

    def _drawdown = if plHigh == 0
                   then 0 #handles the divide by zero error
                   else (plLow - plHigh) / plHigh;
    plot calculateDrawdown = _drawdown;
}

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;
}
;

script getDurationInMins {
    input gdimBarCount = 1;

    #get the aggregation period (MS per bar)
    def aggPeriod = GetAggregationPeriod();

    #multiply length of bars by aggPeriod to determine total milliseconds then convert to minutes
    def _getDurationInMins = Floor((gdimBarCount * aggPeriod) / 60000);
    plot getDurationInMins = _getDurationInMins;
}

script formatDuration {
    input fdBarCount = 1;
    def _fdDuration = getDurationInMins(fdBarCount);
    def _formatDuration = if _fdDuration >= 60 and _fdDuration < 1440 #hours but not days
                         then 1
                         else if _fdDuration >= 1440 #days
                         then 2
                         else 0;

    plot formatDuration = _formatDuration;
}

script calculateDuration {
    input cdBarCount = 1;
    def _cdDurationFormat = formatDuration(cdBarCount);
    def _cdDuration = getDurationInMins(cdBarCount);
  
    #if minutes > hour convert to hour, else if minutes > day, then convert to days
    def _calculateDuration = if _cdDurationFormat == 1
                             then _cdDuration / 60 #convert to hours if greater than 60min but less than a day (1440)
                             else if  _cdDurationFormat == 2
                             then Ceil(_cdDuration / 1440) #convert to days if greater than 1440mins
                             else _cdDuration; #fallback to minutes

    plot calculateDuration = _calculateDuration;
}

# Entry Calculations.  Note: Only parses on a Strategy Chart
def entry = EntryPrice();

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

def hasEntry = !IsNaN(entry);

def isNewEntry = entryPrice != entryPrice[1];

#is active trade
def Active = if SecondsTillTime(begin) == 0 and
                SecondsFromTime(begin) == 0
             then 1
             else 0;

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 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 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 / entryCount;
def avgReturn = TotalSum(entryFPLAll) / entryCount;
def avgWin = TotalSum(entryFPLWins) / winCount;
def avgLoss = TotalSum(entryFPLLosses) / lossCount;

#Drawdown
def lowestLowBarNumber = HighestAll(if FPL == lowFPL then bn else 0);
def highestHighBarNumber = HighestAll(if FPL == highFPL and FPL != FPL[1] then bn else 0);
def hasPrevLow = lowestLowBarNumber < highestHighBarNumber;

def isPeak = FPL > Highest(FPL[1], 12) and FPL > Highest(FPL[-12], 12);
def isTrough = FPL < Lowest(FPL[1], 12) and FPL < Lowest(FPL[-12], 12);
def _peak = if isPeak then FPL else nan;
def _trough = if isTrough then FPL else nan;
def peak = if !IsNaN(_peak) then FPL else peak[1];
def trough = if !IsNaN(_trough) then FPL else trough[1];
def peakBN = if isPeak then bn else peakBN[1];
def troughBN = if isTrough then bn else troughBN[1];

def ptvDrawdown = if !hasPrevLow then calculateDrawdown(lowFPL, highFPL) else ptvDrawdown[1];
def equityDrawdown = if isTrough and trough < peak then trough - peak else equityDrawdown[1];
def equityDrawdownPercent = if isTrough and trough < peak then calculateDrawdown(trough, peak) else equityDrawdownPercent[1];
def largestEquityDrawdown = LowestAll(equityDrawdown);
def largestEquityDrawdownPercent = LowestAll(equityDrawdownPercent);

def drawdown = if hasPrevLow
               then largestEquityDrawdownPercent
               else ptvDrawdown;

# Drawdown Durations
def equityDrawdownLength = if bn >= peakBN and bn <= troughBN
                           then troughBN - peakBN
                           else equityDrawdownLength[1];

def ptvDrawdownLength = if bn >= highestHighBarNumber and bn <= lowestLowBarNumber
                        then lowestLowBarNumber - highestHighBarNumber
                        else ptvDrawdownLength[1];

def equityDrawdownDuration = calculateDuration(HighestAll(equityDrawdownLength));
def equityDrawdownDurationFormat = formatDuration(HighestAll(equityDrawdownLength));
def ptvDrawdownDuration = calculateDuration(ptvDrawdownLength);

def ptvDrawdownDurationFormat = formatDuration(ptvDrawdownLength);

#Daily profit
def Midnight = if Active then FPL else Midnight[1];
def DaysProfit = FPL - Midnight;

#Plots

AddChartBubble(!hideFPL and showEntryBubbles and isEntryBar, FPL, "Entry: " + entryBarPL + " | " + bn, Color.WHITE);
AddChartBubble(!hideFPL and showEntryBubbles and isExitBar, FPL, "Exit: " + exitBarPL,
               color = if isWin
                       then Color.LIGHT_GREEN
                       else if isLoss
                       then Color.DARK_RED
                       else Color.GRAY,
               up = no
              );

#Labels

# test -----------------------------------------
def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
#def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
def maxLossCount  = if iswin then 0 else if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];
AddLabel(yes,
         text = "MaxLossCount " + maxLossCount,
         color.ORANGE
         );
# End test -------------------------------------


AddLabel(yes,
         text = "LastEntry: " + AsPrice(entryPrice)
         );

AddLabel(hasEntry,
         text = "Current Trade % Return:  " + AsPercent(cumsum),
         color = if cumsum > 0
         then Color.GREEN
         else Color.RED
        );

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

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

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

AddLabel(yes,
        text = "HighestReturn: " +  AsDollars(highestReturn),
        color = if highestReturn > 0
                then Color.GREEN
                else Color.RED
        );

AddLabel(yes,
        text = "LowestReturn: " +  AsDollars(lowestReturn),
        color = if lowestReturn > 0
                then Color.GREEN
                else Color.RED
        );

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

AddLabel(yes,
        text = "PeakToValley DD: " +  AsPercent(drawdown) +
               " | Duration: " + ptvDrawdownDuration +
                if ptvDrawdownDurationFormat == 1
                then " hours"
                else if ptvDrawdownDurationFormat == 2
                then " days"
                else " mins" ,
        color = if drawdown > 0
                then Color.GREEN
                else Color.RED
        );


AddLabel(largestEquityDrawdown < 0,
        text = "Largest Equity DD: " +  AsDollars(largestEquityDrawdown) +
               " | Duration: " + equityDrawdownDuration +
                if equityDrawdownDurationFormat == 1
                then " hours"
                else if equityDrawdownDurationFormat == 2
                then " days"
                else " mins",
        color = if largestEquityDrawdown > 0
                then Color.GREEN
                else Color.RED
        );

AddLabel(yes,
         text = "P&L High" +
                (if enableDebugging
                then " at bar " + highBarNumber
                else "") +
                ":  " + AsDollars(highFPL),
        color = Color.GREEN
       );

AddLabel(yes,
         text = "P&L Low" +
                (if enableDebugging
                then " at bar " + lowBarNumber
                else "") +
                ":  " + AsDollars(lowFPL),
        color = Color.RED
       );

AddLabel(yes,
         text = "Days Profit: $" + DaysProfit,
         color = if DaysProfit > 0
                 then Color.GREEN
                 else Color.RED
        );

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

#debugging

#peaks & troughs
AddChartBubble(enableDebugging and isPeak, FPL,
               text = "FPL: " + FPL
                      + " | Peak: " + peak
                      + " | Trough: " + trough[-1]
                      + " | Drawdown: " + AsPercent(calculateDrawdown(trough, peak))
                      + " | PeakBN: " + peakBN
                      + " | BarNumber: " + bn,
               color = Color.LIME
              );

AddChartBubble(enableDebugging and isTrough, FPL,
               text = "FPL: " + FPL
                      + " | Peak: " + peak
                      + " | Trough: " + trough
                      + " | Drawdown: " + AsPercent(calculateDrawdown(trough, peak))
                      + " | TroughBN: " + troughBN
                      + " | BarNumber: " + bn,
              color = Color.LIGHT_RED,
              up = no
             );

AddVerticalLine(enableDebugging and isEntryBar,
                text = "EntryBarNum: " + entryBarNum
                       + " | ExitBarNum: " + exitBarNum[-1]
                       + " | BarNumber: " + bn,
                color = Color.WHITE
);

AddVerticalLine(enableDebugging and isExitBar,
                text =  "EntryBarNum: " + entryBarNum[1]
                        + " | ExitbarNum: " + exitBarNum
                        + " | BarNumber: " + bn
                        + " | EntryReturn: " + entryReturn,
                color = if isWin
                        then Color.LIGHT_GREEN
                        else if isLoss
                        then Color.LIGHT_RED
                        else Color.LIGHT_GREEN
);



Screenshot-2021-12-26-095146.png
 
@Kevin N
Threw the the whole code into an existing Donchian Strat.
We were resetting on the wrong line.
isloss already gets reset earlier in the code, so only 1 or 0 was getting passed to tmpMaxLossCount.
So after fixing that, you have two options for maxLossCount, either highest number of losses in a row or highest number of losses in a row since the last win.

Code:
# test -----------------------------------------
#def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def tmpMaxLossCount = if iswin then 0 else if isLoss then tmpMaxLossCount[1] + 1 else tmpMaxLossCount[1];

#Use this line to see highest amount of sequential losses.#
#def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

#Use this line to see hightest amount of sequential losses since the last win.#
def maxLossCount  = if tmpMaxLossCount > tmpmaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

AddLabel(yes,
         text = "MaxLossCount " + maxLossCount,
         color.ORANGE
         );
# End test -------------------------------------

Highest amount of sequential losses.
chart3.jpg


Highest amount of sequential losses since last win.
chart4.jpg
 
Solution
@Kevin N
Threw the the whole code into an existing Donchian Strat.
We were resetting on the wrong line.
isloss already gets reset earlier in the code, so only 1 or 0 was getting passed to tmpMaxLossCount.
So after fixing that, you have two options for maxLossCount, either highest number of losses in a row or highest number of losses in a row since the last win.

Code:
# test -----------------------------------------
#def tmpMaxLossCount = if isLoss then tmpMaxLossCount[1] + 1 else 0;
def tmpMaxLossCount = if iswin then 0 else if isLoss then tmpMaxLossCount[1] + 1 else tmpMaxLossCount[1];

#Use this line to see highest amount of sequential losses.#
#def maxLossCount  = if tmpMaxLossCount > maxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

#Use this line to see hightest amount of sequential losses since the last win.#
def maxLossCount  = if tmpMaxLossCount > tmpmaxLossCount[1] then tmpMaxLossCount else MaxLossCount[1];

AddLabel(yes,
         text = "MaxLossCount " + maxLossCount,
         color.ORANGE
         );
# End test -------------------------------------

Highest amount of sequential losses.
chart3.jpg


Highest amount of sequential losses since last win.
chart4.jpg
EXCELLENT! You nailed it. I knew it had to be something simple I was overlooking, but sometimes when I focus too hard on something, it's tough to figure out.

Thanks again :)
 
I'm trying to follow all of the updates to this script. Is there a complete and updated version?
Ali, I was just wanting to add a max loser count to some code provided at this link.... (Thanks Svanoy)

https://usethinkscript.com/threads/...acktesting-data-utility-for-thinkorswim.1624/

The author of the above (link) script/code has done a phenomenal job of providing stats. My goal was to see how many times a strategy lost in a row, before seeing another winner. The total losers and winners are already provided, but not losers in a row.

Hope that helps :)
 
Last edited:

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
473 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

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.

How do I get started?

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.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top