# Range Trader
# Author Kevin N 10-11-22 21:55
def CCI = reference CCI();
def nan = Double.NaN;
#plot trend = MovingAverage(AverageType.EXPONENTIAL, 100);
input tradeOpenRange = no;
input marketOpenTime = 0930;
input openRangeMinutes = 15;
input tradeCloseRange = no;
input marketCloseTime = 1530;
input closeRangeMinutes = 90;
input useGoFlat = yes;
input goFlatTime1 = 0815;
input goFlatTime2 = 1550;
input debug = yes;
input closeLabelOn = yes;
input useWaitBars = yes;
input waitBars = 10;
input useVariableSlope = yes;
input varMA = 150;
input varSlopeBars = 20;
input varSlopeAngle = .100;
input useLossCount = no;
input useMultiplyContracts = no;
input maxLossWait = 3;
input maxContracts = 8;
input contractsMultiplier = 2;
input usePriceRange = no;
input topRange = 3800;
input bottomRange = 3700;
input stopType = {default "Opposite Bar", Points, Strategy};
input stopPoints = 5;
input tradingHours = {default Both, Regular, GlobeX};
plot varMovAvg;
varMovAvg = MovingAverage(AverageType.EXPONENTIAL, close, varMA);
###################################
# Fractal Chaos
###################################
input sequenceCount = 1;
def maxSideLength = sequenceCount + 10;
def upRightSide = fold i1 = 1 to maxSideLength + 1 with count1 while count1 != sequenceCount and count1 != -1 do
if GetValue(high, -i1) > high or (GetValue(high, -i1) == high and count1 == 0) then -1
else if GetValue(high, -i1) < high then count1 + 1 else count1;
def upLeftSide = fold i2 = 1 to maxSideLength + 1 with count2 while count2 != sequenceCount and count2 != -1 do
if GetValue(high, i2) > high or (GetValue(high, i2) == high and count2 >= 1) then -1
else if GetValue(high, i2) < high then count2 + 1 else count2;
def downRightSide = fold i3 = 1 to maxSideLength + 1 with count3 while count3 != sequenceCount and count3 != -1 do
if GetValue(low, -i3) < low or (GetValue(low, -i3) == low and count3 == 0) then -1
else if GetValue(high, -i3) > low then count3 + 1 else count3;
def downLeftSide = fold i4 = 1 to maxSideLength + 1 with count4 while count4 != sequenceCount and count4 != -1 do
if GetValue(low, i4) < low or (GetValue(low, i4) == low and count4 >= 1) then -1
else if GetValue(low, i4) > low then count4 + 1 else count4;
def fractalUp = if upRightSide == sequenceCount and upLeftSide == sequenceCount then high else fractalUp[1];
def fractalDown = if downRightSide == sequenceCount and downLeftSide == sequenceCount then low else fractalDown[1];
plot UpFractal = fractalUp;
plot DownFractal = fractalDown;
###################################
# Time Related Stuff
###################################
def RTH = if (SecondsFromTime(0930) > 0 and SecondsTillTime(1800) > 0, 1, 0);
def ONH = if SecondsFromTime(1800) == 0
then high
else if
!RTH and high > ONH[1]
then high
else ONH[1];
def ONL = if SecondsFromTime(1800) == 0
then low
else if
!RTH and low < ONL[1]
then low
else ONL[1];
def firstMinute = if SecondsFromTime(0930) < 60 then 1 else 0;
def openRangeTime = if SecondsFromTime(0930) < 60 * openRangeMinutes then 1 else 0;
def ORHigh = if firstMinute
then high
else if openRangeTime
and high > ORHigh[1]
then high
else ORHigh[1];
def ORLow = if firstMinute
then low
else if openRangeTime
and low < ORLow[1]
then low
else ORLow[1];
###################################
# Buy/Sell Conditions
###################################
def buyCondition = if (close > fractalUp and close > ORHigh, 1, 0);
def sellCondition = if (close < fractalDown and close < ORLow, 1, 0);
###################################
# Conditions
###################################
def waitBarsCondition = if (buyCondition
and useWaitBars
and high > highest(close[1], waitBars)
or sellCondition
and useWaitBars
and low < lowest(close[1], waitBars)
or !useWaitBars, 1, 0);
def openRangeCondition = if tradeOpenRange
or secondsTillTime(marketOpenTime) >= 0 and !tradeOpenRange
or secondsFromTime(marketOpenTime) > 60 * openRangeMinutes and !tradeOpenRange
then 1
else 0;
def closeRangeCondition = if tradeCloseRange
or secondsTillTime(marketCloseTime) >= 0 and !tradeCloseRange
or secondsFromTime(marketCloseTime) > 60 * closeRangeMinutes and !tradeCloseRange
then 1
else 0;
# def goFlatTimes = if SecondsTillTime(goFlatTime1) == 0 or SecondsTillTime(goFlatTime2) == 0 then 1 else 0;
def goFlatTimes = if useGoFlat
and secondsFromTime(goFlatTime1) > 0
and secondsFromTime(goFlatTime1) <= 60 * 15
or useGoFlat
and secondsFromTime(goFlatTime2) > 0
and secondsFromTime(goFlatTime2) <= 60 * 15
then 1
else 0;
def priceRangeCondition = if (usePriceRange
and close > topRange
or usePriceRange
and close < bottomRange
or !usePriceRange, 1, 0);
def varMovAvgSlopeCondition = if (useVariableSlope
and buyCondition
and (varMovAvg - varMovAvg[varSlopeBars]) / varSlopeBars > varSlopeAngle
or sellCondition
and (varMovAvg - varMovAvg[varSlopeBars]) / varSlopeBars < -varSlopeAngle
or !useVariableSlope, 1, 0);
def maxLossCount;
# def contracts = 1;
def tmpContracts = if maxLossCount[1] != maxLossCount[2]
and maxLossCount[1] >= maxLossWait
then maxLossCount[1]
else maxLossCount[2];
def contractsCalc = if useMultiplyContracts
and tmpContracts >= maxLossWait
then tmpContracts * contractsMultiplier
else if maxLossCount[1] <= 1
then 1
else 1;
def lossCountCondition = if useLossCount
and tmpContracts >= maxLossWait
or !useLossCount then 1 else 0;
def contracts = if contractsCalc > maxContracts then maxContracts else contractsCalc;
# Hours To Trade ----------------------
def selectedHours;
switch (tradingHours) {
case Both:
selectedHours = 1;
case Regular:
selectedHours = if (SecondsFromTime(marketOpenTime) > 0 and SecondsTillTime(1600) > 0, 1, 0);
case GlobeX:
selectedHours = if (SecondsFromTime(marketOpenTime) > 0 and SecondsTillTime(1600) > 0, 0, 1);
}
def buySignal = if ( buyCondition
and waitBarsCondition
and openRangeCondition
and closeRangeCondition
and selectedHours
and varMovAvgSlopeCondition
and priceRangeCondition
, 1, 0);
def sellSignal = if ( sellCondition
and waitBarsCondition
and openRangeCondition
and closeRangeCondition
and selectedHours
and varMovAvgSlopeCondition
and priceRangeCondition
, 1, 0);
def closeAllCondition = if (useGoFlat and goFlatTimes, 1, 0);
# End Conditions --------------------
def bought = if bought[1] != bought[2]
and buySignal
then 1
else if bought[1] != bought[2]
and sellSignal then -1 else bought[1];
def sellToClose = buyCondition;
def buyToClose = sellCondition;
def ahk = 0;
def isLong = if buySignal then 1 else if sellSignal then 0 else isLong[1];
def isShort = if sellSignal then 1 else if buySignal then 0 else isShort[1];
def useLong = 1;
def useShort = 1;
def hasEntry1 = 0;
def closeLong;
def closeShort;
switch (stopType) {
case "Opposite Bar":
closeLong = if (isLong and close < open, 1, 0);
closeShort = if (isShort and close > open, 1, 0);
case Strategy:
closeLong = if (isLong and close < fractalDown, 1, 0);
closeShort = if (isShort and close > fractalUp, 1, 0);
case Points:
closeLong = if (EntryPrice() and low < highest(high, 10) - stopPoints, 1, 0);
closeShort = if (EntryPrice() and high > lowest(low, 10) + stopPoints, 1, 0);
}
#ORDERS
AddOrder(type = OrderType.BUY_TO_OPEN, buySignal, open[-1], tradeSize = Contracts, tickcolor = Color.GREEN, arrowcolor = Color.GREEN, name = "Long");
AddOrder(type = OrderType.SELL_TO_CLOSE, closeLong, open[-1], tradeSize = Contracts, name = "Close", tickcolor = Color.GRAY, arrowcolor = Color.GRAY);
AddOrder(type = OrderType.SELL_TO_OPEN, sellSignal, open[-1], tradeSize = Contracts, name = "Short", tickcolor = Color.RED, arrowcolor = Color.RED);
AddOrder(type = OrderType.BUY_TO_CLOSE, closeShort, open[-1], tradeSize = Contracts, name = "Close", tickcolor = Color.GRAY, arrowcolor = Color.GRAY);
AddOrder(type = OrderType.Sell_TO_CLOSE, closeAllCondition, price = close, tickcolor = Color.ORANGE, arrowcolor = Color.ORANGE, name = "Go Flat");
# Alerts
Alert(if (buySignal, 1, 0), "Buy", Alert.BAR, Sound.Bell);
Alert(if (sellSignal[1], 1, 0), "Close", Alert.BAR, Sound.Bell);
# End Alerts
###################################################################################################
# Labels
# IMPORTANT - do not allow two signals to display at the same time or AHK will get stuck in a loop.
# Looks Odd, but we want the spacing to be the same for the blank labels for AutoHotKey
# if you are NOT using AutoHotKey to manage your trades, these lables are not needed.
###################################################################################################
#Debug
AddLabel(0,
" "
, Color.BLUE); # Use to debug
#------------------------------------
# Go Flat ---------------------------
#------------------------------------
def goFlatLabel = if useGoFlat and goFlatTimes then 1 else 0;
AddLabel(if (goFlatLabel[1], 1, 0),
" "
, Color.BLUE);
#------------------------------------
# Buy Signal ------------------------
#------------------------------------
def buySignalLabel;
if (ahk) {
buySignalLabel = if (buySignal and useLong and !sellToClose and !hasEntry1 and !goFlatLabel
or buySignal and useLong and isNan(sellToClose) and isNan(hasEntry1) and !goFlatLabel, 1, 0);
} else {
buySignalLabel = buySignal and !sellSignal;
}
AddLabel(if (lossCountCondition and buySignalLabel[1], 1, 0),
if debug then
"BuySignal "
else
" "
, Color.WHITE);
#------------------------------------
# Close The Trade --------------
#------------------------------------
def closeLongTradeLabel;
if (ahk) {
closeLongTradeLabel = if (closeLabelOn and closeLong
or closeLabelOn and closeShort, 1, 0);
} else {
closeLongTradeLabel = if (closeLabelOn and closeLong
or closeLabelOn and closeShort, 1, 0);
}
AddLabel(if (closeLongTradeLabel[1], 1, 0),
if debug then
"Close Trade "
else
" "
, Color.BLUE);
#------------------------------------
# Sell Short ------------------------
#------------------------------------
def sellSignalLabel;
if (ahk) {
sellSignalLabel = if (sellSignal and useShort and !buyToClose and !hasEntry1 and !goFlatLabel
or sellSignal and useShort and isNan(buyToClose) and isNan(hasEntry1) and !goFlatLabel, 1, 0);
} else {
sellSignalLabel = sellSignal and !buySignal;
}
AddLabel(if (lossCountCondition and sellSignalLabel[1], 1, 0),
if debug then
"SellSignal "
else
" "
, Color.DARK_ORANGE);
#------------------------------------
#No Trade (PlaceHolder) -------------
#------------------------------------
def placeHolderLabel;
if (ahk) {
placeHolderLabel = !sellSignal and !buySignal and !closeLongTradeLabel and !goFlatLabel;
} else {
placeHolderLabel = !sellSignal and !buySignal and !closeLongTradeLabel and !goFlatLabel;
}
AddLabel(if (placeHolderLabel[1], 1, 0),
" "
, Color.BLACK);
#------------------------------------
# Status Label ----------------------
#------------------------------------
AddLabel(if (hasEntry1, 1, 0),
" "
, Color.PLUM);
#####################################
# Debug
#####################################
AddLabel(if (debug, 1, 0),
"isLong: " + isLong
, Color.Gray);
AddLabel(if (debug, 1, 0),
"isShort: " + isShort
, Color.Gray);
AddLabel(if (debug, 1, 0),
"CCI: " + CCI
, Color.Gray);
# AddLabel(if (debug, 1, 0),
# "close_order: " + close_order
# , Color.Gray);
AddLabel(if (debug, 1, 0),
"Stop Type: " + stopType
, Color.Gray);
AddLabel(if (debug, 1, 0),
"Hours: " + tradingHours
, Color.Gray);
AddLabel(if (debug, 1, 0),
"Loss Cnt: " + maxLossCount[1]
, Color.Gray);
AddLabel(if (debug, 1, 0),
"FPL: " + FPL()
, Color.Gray);
# AddLabel(if (debug, 1, 0),
# "Sec From Time: " + secondsFromTime(goFlatTime2)
# , Color.Gray);
# AddLabel(if (debug, 1, 0),
# "Sec Till Time: " + secondsTillTime(goFlatTime2)
# , Color.Gray);
# AddLabel(if (debug, 1, 0),
# "GoFlatLabel: " + !goFlatLabel
# , Color.Gray);
def tRange = if usePriceRange then topRange else ONH;
def bRange = if usePriceRange then bottomRange else ONL;
AddCloud(tRange, bRange, Color.LIGHT_GRAY, Color.BLACK);
plot openRangeHigh = if RTH then ORHigh else 0;
plot openRangeLow = if RTH then ORLow else 0;
openRangeLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
openRangeLow.SetDefaultColor(Color.YELLOW);
openRangeLow.SetLineWeight(1);
openRangeHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
openRangeHigh.SetDefaultColor(Color.YELLOW);
openRangeHigh.SetLineWeight(1);
############################
# FPL Extended
# Extended Floating P&L study.
# Author: Eddielee394
# Version: 1.2
# inspired by FPL Dashboard script developed by Mobius
# Found At: https://usethinkscript.com/threads/extended-floating-profit-loss-backtesting-data-utility-for-thinkorswim.1624/
############################
#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
input showStats = no;
def bn = if !IsNaN(close) and !IsNaN(close[1]) and !IsNaN(close[-1]) then BarNumber() else bn[1];
#Inputs
def fplBegin = 0000;
#hint fplBegin: start time: the time in which then dailyHighLow profit should consider the day start. Recommended value is 0000.
def fplTargetWinLoss = .50;
#hint fplTargetWinLoss: sets the target winlossRatio (in percent) which determines display colors of the W/L label.
def fplTargetWinRate = 1;
#hint fplTargetWinRate: sets the target winRate (float) which determines display colors of the WinRate label;
def fplHidePrice = no;
#hint fplHidePrice: hide's the underlying price graph. \nDefault is no.
def fplHideFPL = yes;
#hint fplHideFPL: hide's the underlying P&L graph.\nDefault is yes.
def fplShowEntryBubbles = no;
#hint fplShowEntryBubbles: display bubbles on the FPL showing the entry and exit P&L values
def 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 entry = if ahk then avgPrice else EntryPrice(); # used with Kevin AHK script
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 lossCountCondition and isWin then entryReturn else entryReturnWin[1];
def entryReturnLoss = if lossCountCondition and isLoss then entryReturn else entryReturnLoss[1];
def entryFPLWins = if lossCountCondition and isWin then entryReturn else 0;
def entryFPLLosses = if lossCountCondition and isLoss then entryReturn else 0;
def entryFPLAll = if isLoss or isWin then entryReturn else 0;
#Counts
def isWinC = if isWin and lossCountCondition then 1 else 0;
def isLossC = if isLoss and lossCountCondition then 1 else 0;
def entryFPLAllC = if entryFPLAll and lossCountCondition then 1 else 0;
def entryCount = incrementValue(entryFPLAllC);
def winCount = incrementValue(isWinC);
def lossCount = incrementValue(isLossC);
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(entryFPLAllC) / 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 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.#
# defining up top. >= will keep going until we hit another loser, != will reset after one win and wait for x losers.
maxLossCount = if tmpMaxLossCount >= tmpMaxLossCount[1] then tmpMaxLossCount else maxLossCount[1];
# AddLabel(debug,
# text = "MaxLossCount " + maxLossCount,
# Color.ORANGE
# );
AddChartBubble(if (maxLossCount[0] != maxLossCount[1] and maxLossCount > 0 , 1, 0), low[3], maxLossCount, if useLossCount and maxLossCount <= maxLossWait then color.RED else color.YELLOW, no);
# End test -------------------------------------
AddLabel(showStats,
text = "LastEntry: " + AsPrice(entryPrice)
);
AddLabel(showStats and hasEntry,
text = "Current Trade % Return: " + AsPercent(cumsum),
color = if cumsum > 0
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "Total Trades: " + entryCount,
color = Color.WHITE
);
AddLabel(showStats,
text = "WinCount: " + winCount +
" | LossCount: " + lossCount +
" | WinRate: " + winRate,
color = if winRate >= targetWinRate
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "W/L: " + AsPercent(winLossRatio),
color = if winLossRatio > targetWinLoss
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "HighestReturn: " + AsDollars(highestReturn),
color = if highestReturn > 0
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "LowestReturn: " + AsDollars(lowestReturn),
color = if lowestReturn > 0
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "AvgReturn: " + AsDollars(avgReturn) +
" | AvgWin: " + AsDollars(avgWin) +
" | AvgLoss: " + AsDollars(avgLoss),
color = if avgReturn >= 0
then Color.LIGHT_GREEN
else Color.RED
);
AddLabel(showStats,
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(showStats and 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(showStats,
text = "P&L High" +
(if enableDebugging
then " at bar " + highBarNumber
else "") +
": " + AsDollars(highFPL),
color = Color.GREEN
);
AddLabel(showStats,
text = "P&L Low" +
(if enableDebugging
then " at bar " + lowBarNumber
else "") +
": " + AsDollars(lowFPL),
color = Color.RED
);
AddLabel(showStats,
text = "Days Profit: $" + DaysProfit,
color = if DaysProfit > 0
then Color.GREEN
else Color.RED
);
AddLabel(showStats,
text = "Total Profit: " + AsDollars(if useLossCount then avgWin * winCount else 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
);