How To Change CANDLE COLORS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - Bar Wick & Border Color", overlay=true)
bullCandle = close > open
plotcandle(bullCandle ? open : na, bullCandle ? high : na, bullCandle ? low : na, bullCandle ? close : na,
 color=color.green, wickcolor=color.blue, bordercolor=color.lime)
plotcandle(bullCandle ? na : open, bullCandle ? na : high, bullCandle ? na : low, bullCandle ? na : close,
color=color.maroon, wickcolor=color.orange, bordercolor=color.red)

How To Use LABELS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - Drawing Variable Values", overlay=true)

// Calculate difference between 50 EMA and 100 EMA
variableValue = (ema(close, 100) - ema(close, 50)) / syminfo.mintick

// Create a label
labelText = tostring(variableValue)
ourLabel = label.new(x=bar_index, y=na, text=labelText, yloc=yloc.belowbar, color=color.green, textcolor=color.white,
 style=label.style_label_up, size=size.normal)

label.delete(ourLabel[1])

How To SPLIT ALERTS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - How To Split Alerts", overlay=true)

// Get user input
longAlerts = input(title="Trigger Long Alerts", type=input.bool, defval=true)
shortAlerts = input(title="Trigger Short Alerts", type=input.bool, defval=true)

// Detect candle patterns
bullishCandle = close > open
bearishCandle = close < open
plotshape(bullishCandle, color=color.green, style=shape.arrowup, location=location.belowbar)
plotshape(bearishCandle, color=color.red, style=shape.arrowdown, location=location.abovebar)

// Trigger alerts
alertcondition((bullishCandle and longAlerts) or (bearishCandle and shortAlerts), title="Alert!", message="Alert for {{ticker}}")

Alerts & TIME SESSIONS

Watch Lesson

Trigger Alerts OUTSIDE Time Session

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - Alerts & Afterhours", overlay=true)

// Get user input
preMarket = input(title="Pre-market", type=input.session, defval="0400-0930")
afterMarket = input(title="After-market", type=input.session, defval="1600-2000")

// Create function for detecting if current bar falls within specified time period
InSession(sess) => na(time(timeframe.period, sess)) == false

// Check if the current bar falls within pre-market or after-market hours
isAfterClose = InSession(afterMarket)
isPreOpen = InSession(preMarket)
isAfterHours = isAfterClose or isPreOpen

// Change bar color if bar falls within after hours time
barcolor(isAfterHours ? color.black : na)

// Trigger alert ONLY IF bar is outside of after hours time
alertTrigger = close >= open
alertcondition(alertTrigger and not isAfterHours, title="Alert title", message="Alert message")

Trigger Alerts WITHIN Time Session

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - Alerts & Time Session", overlay=true)

// Get user input
session = input(title="Time session", type=input.session, defval="0930-1030")

// Create function for detecting if current bar falls within specified time period
InSession(sess) => na(time(timeframe.period, sess)) == false

// Check if the current bar falls within our session
isInSession = InSession(session)

// Change bar color if bar falls within session
barcolor(isInSession ? color.black : na)

// Trigger alert ONLY IF bar is within session
alertTrigger = close >= open
alertcondition(alertTrigger and isInSession, title="Alert title", message="Alert message")

MERGING Stochastic & RSI

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - Stochastic & RSI")

// Get user input
kInput = input(title="K Length", type=input.integer, defval=14)
dInput = input(title="D Length", type=input.integer, defval=3)
rsiLength = input(title="RSI Length", type=input.integer, defval=14)
obLevel = input(title="Overbought Threshold", type=input.float, defval=80)
osLevel = input(title="Oversold Threshold", type=input.float, defval=20)

// Calculate our stochastic
rsi = rsi(close, rsiLength)
k = 100 * ((close - lowest(low, kInput)) / (highest(high, kInput) - lowest(low, kInput)))
d = sma(k, dInput)

// Draw data to chart
plot(obLevel, color=color.red, linewidth=2, title="Overbought")
plot(osLevel, color=color.green, linewidth=2, title="Oversold")
plot(rsi, color=rsi > obLevel ? color.red : rsi < osLevel ? color.green : color.black, linewidth=2)
plot(k, color=color.purple, title="K")
plot(d, color=color.orange, title="D")

Creating A Stochastic BASED ON RSI

Watch Lesson

// Calculate our stochastic
rsi = rsi(close, rsiLength)
k = 100 * ((rsi - lowest(rsi, kInput)) / (highest(rsi, kInput) - lowest(rsi, kInput)))
d = sma(k, dInput)

How To Use EMA FILTERS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study("PSMC - EMA Confluence Filter", overlay=true)

// Get user input
emaLength1 = input(title="EMA 1 Length", type=input.integer, defval=50)
emaLength2 = input(title="EMA 2 Length", type=input.integer, defval=100)
emaLookback = input(title="EMA Lookback", type=input.integer, defval=3)
maxBarsBeyondEMA = input(title="Max Bars Beyond EMA", type=input.integer, defval=1)

// Get EMAs
ema1 = ema(close, emaLength1)
ema2 = ema(close, emaLength2 == 0 ? 1 : emaLength2)

// EMA Breach Check
barsAboveEMA = 0
barsBelowEMA = 0

// Count candles beyond the EMA
for i = 0 to emaLookback
    if close[i] > ema1
        barsAboveEMA := barsAboveEMA + 1
    if close[i] < ema1
        barsBelowEMA := barsBelowEMA + 1

// Get Filters
longFilter = close > ema1 and (ema1 > ema2 or emaLength2 == 0) and barsBelowEMA <= maxBarsBeyondEMA
shortFilter = close < ema1 and (ema1 < ema2 or emaLength2 == 0) and barsAboveEMA <= maxBarsBeyondEMA

// Detect entry reasons
longEntry = longFilter and close >= open[1] and close[1] <= open[1]
shortEntry = shortFilter and close <= open[1] and close[1] >= open[1]

// Plot EMAs
plot(ema1, color=close > ema1 ? color.green : color.red, linewidth=2)
plot(emaLength2 == 0 ? na : ema2, color=color.blue, linewidth=3)

// Plot Entry Signals
plotshape(longEntry ? 1 : na, style=shape.arrowup, color=color.green, location=location.belowbar)
plotshape(shortEntry ? 1 : na, style=shape.arrowdown, color=color.red)

How To Detect TRADING SETUPS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading

//@version=4
study(title="PSMC - Setup Detection", shorttitle="www.pinescriptmastery.com", overlay=true)

// Get user input
rsiLength = input(title="RSI Length", type=input.integer, defval=14)
rsiOB = input(title="RSI Overbought", type=input.float, defval=70.0)
rsiOS = input(title="RSI Oversold", type=input.float, defval=30.0)

// Get RSI values & check condition
rsi = rsi(close, rsiLength)
rsiBullish = rsi <= rsiOS or rsi[1] <= rsiOS
rsiBearish = rsi >= rsiOB or rsi[1] >= rsiOB

// Detect candlestick pattern
bullishEngulfing = close >= open[1] and close[1] <= open[1]
bearishEngulfing = close <= open[1] and close[1] >= open[1]

// Detect trading setups
bullishSetup = rsiBullish and bullishEngulfing
bearishSetup = rsiBearish and bearishEngulfing

// Draw data to chart
plotshape(bullishSetup ? 1 : na, style=shape.arrowup, color=color.green, location=location.belowbar, title="Bullish Signal")
plotshape(bearishSetup ? 1 : na, style=shape.arrowdown, color=color.red, location=location.abovebar, title="Bearish Signal")

// Trigger alerts
alertcondition(condition=bullishSetup or bearishSetup, title="RSI Setup Alert!", message="RSI Trading Setup Detected For: {{ticker}}")

How To Detect HAMMERS & STARS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading
// @version=4
study("PSMC - Hammer & Shooting Stars", overlay=true)

// Get user input
fibLevel = input(title="Fib Level", type=input.float, defval=0.333)
colorFilter = input(title="Color Must Match", type=input.bool, defval=false)

// Calculate fibonacci level for current candle
bullFib = (low - high) * fibLevel + high
bearFib = (high - low) * fibLevel + low

// Determine which price source closes or opens highest/lowest
lowestBody = close < open ? close : open
highestBody = close > open ? close : open

// Determine if we have a valid hammer or shooting star
hammerCandle = lowestBody >= bullFib and (not colorFilter or close > open)
starCandle = highestBody <= bearFib and (not colorFilter or close < open)

// Plot the signals to the chart
plotshape(hammerCandle, style=shape.arrowup, location=location.belowbar, color=color.green)
plotshape(starCandle, style=shape.arrowdown, location=location.abovebar, color=color.red)

// Trigger alerts
alertcondition(hammerCandle or starCandle, title="Hammer or Shooting Star Alert", message="{{ticker}}")

How To Detect PIERCING & CLOUD CANDLES

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading
// www.pinescriptmastery.com
// Last Updated: 24th November, 2020
// @version=4
study("PSMC - Piercing Cloud", overlay=true)

// Get user input
rsiLength = input(title="RSI Length", type=input.integer, defval=7)
rsiOB = input(title="RSI OB", type=input.float, defval=70.0)
rsiOS = input(title="RSI OS", type=input.float, defval=30.0)
margin = input(title="Pip Margin", type=input.float, defval=0.0)

// Get current RSI value
rsi = rsi(close, rsiLength)

// Detect bullish piercing line
bpc = open < close[1] and close > close[1] and close < open[1] and close[1] < open[1]

// Detect bearish dark cloud cover
dcc = open > close[1] and close > open[1] and close < close[1] and close[1] > open[1]

// Check pip distance between the candle bodies
bpcMargin = close[1] - open
dccMargin = open - close[1]

// Piercing line filter
piercingLine = (low[1] - high[1]) * 0.5 + high[1]
longPierce = close >= piercingLine
shortPierce = close <= piercingLine

// Determine if the current bar meets our conditions
longSignal = rsi[1] <= rsiOS and bpc and bpcMargin >= margin and longPierce
shortSignal = rsi[1] >= rsiOB and dcc and dccMargin >= margin and shortPierce

// Draw signals
plotshape(longSignal, style=shape.triangleup, location=location.belowbar, color=color.green, text="Long", title="Long")
plotshape(shortSignal, style=shape.triangledown, location=location.abovebar, color=color.red, text="Short", title="Short")

How to use FOOR LOOPS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Positive Bars Oscillator v1.0 / Last Modified: 25th January, 2021
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
study("Positive Bars %", overlay=false, precision=0)

// Get user input
lookback = input(title="Lookback", type=input.integer, defval=10)

// Get user input
upperLimit = input(title="Upper Limit", type=input.integer, defval=80)
lowerLimit = input(title="Lower Limit", type=input.integer, defval=20)

// Count past X positive bars (X = lookback)
positiveBars = 0
for i = (lookback - 1) to 0
    if close[i] > open[i]
        positiveBars := positiveBars + 1

// Plot limits to chart
hline(upperLimit, color=color.orange, title="Upper Limit")
hline(lowerLimit, color=color.orange, title="Lower Limit")

// Draw positive bars as %
positiveBarsPercent = (positiveBars / lookback) * 100
plot(positiveBarsPercent, color=color.blue, title="Positive Bars")

// Draw top & bottom of oscillator
plot(100, color=color.black, editable=false, title="Top")
plot(0, color=color.black, editable=false, title="Bottom")

// Trigger alerts
alertcondition(positiveBarsPercent >= upperLimit, title="PB(+) Alert", message="Positive bars has exceeded upper limit: {{plot_0}}%")
alertcondition(positiveBarsPercent <= lowerLimit, title="PB(-) Alert", message="Positive bars has exceeded lower limit: {{plot_0}}%")

How to use ARRAYS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// This script calculates the covariance and correlation coefficient between two array data sets
// @version=4
study("PSMC - Correlation Meter", overlay=false)

// Get user input 
lookback    = input(title="Lookback", type=input.integer, defval=20) 
source      = input(title="Source", type=input.source, defval=close)
reference   = input(title="Reference Market", type=input.string, defval="OANDA:SPX500USD")

// Get % change of reference data source
referenceData = security(symbol=reference, resolution=timeframe.period, expression=source)
referenceChange = ((referenceData - referenceData[1]) / referenceData[1]) * 100

// Get % change of current market
currentData = source
currentChange = ((currentData - currentData[1]) / currentData[1]) * 100

// Declare arrays
var referenceArray = array.new_float(lookback)
var currentArray = array.new_float(lookback)

// Shift (remove) the last (first entered) value from our arrays (FIFO)
array.shift(referenceArray)
array.shift(currentArray)

// Add the current values to our arrays
array.push(referenceArray, referenceChange)
array.push(currentArray, currentChange)

// Determine & plot our covariance relationship
covariance = array.covariance(currentArray, referenceArray)
plot(covariance, color=color.purple, style=plot.style_area, transp=0, title="Covariance")

// Plot our reference data
plot(referenceChange, color=color.red, style=plot.style_columns, transp=10, title="Reference Market")
plot(currentChange, color=color.blue, style=plot.style_histogram, linewidth=4, title="Current Market")

// Determine the standard deviation of our arrays
referenceDev = array.stdev(referenceArray)
currentDev = array.stdev(currentArray)
correlation = covariance / (referenceDev * currentDev)
plot(correlation, color=color.black, linewidth=2, style=plot.style_stepline, title="Correlation Strength")

// Plot reference lines
//hline(price=1.0)
//hline(price=-1.0)
//hline(price=0.0)

How to use VARIP

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
study("Tick Counter")

// Prepare tick counter variables (varip makes them persistent on real-time bar)
varip ticks = 0
varip volumeChanges = 0
varip lastPrice = close

// Check if price has changed (price tick)
if barstate.isrealtime and lastPrice != close
    ticks := ticks + 1
    lastPrice := close
    
// Check if volume has changed (trade executed at current price)
if barstate.isrealtime and lastPrice == close
    volumeChanges := volumeChanges + 1
    
// Reset counters on each new bar
if barstate.isnew
    ticks := 0
    volumeChanges := 0
    lastPrice := close
    
// Draw data to chart
plot(ticks, style=plot.style_columns, title="Price Ticks")
plot(volumeChanges, style=plot.style_histogram, color=color.purple, title="Volume Ticks")

How to CALCULATE POSITIONS SIZE

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
study("Forex Position Size Calculator", overlay=true)

// Get user input
accountBalance  = input(title="Account Balance", type=input.float, defval=10000.0, step=100, group="AutoView Oanda Settings", tooltip="Your Oanda account balance (optional - used for automation through AutoView plugin)")
accountCurrency = input(title="Account Currency", type=input.string, defval="USD", options=["AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "NZD", "USD"], group="AutoView Oanda Settings", tooltip="Your Oanda account currency (optional - used for automation through AutoView plugin)")
riskPerTrade    = input(title="Risk Per Trade %", type=input.float, defval=1.0, step=0.5, group="AutoView Oanda Settings", tooltip="Your risk per trade as a % of your account balance (optional - used for automation through AutoView plugin)")

// Get current ATR
atr = atr(14)

// Custom function to convert pips into whole numbers
toWhole(number) =>
    return = atr < 1.0 ? (number / syminfo.mintick) / (10 / syminfo.pointvalue) : number
    return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return * 100 : return

//------------- DETERMINE POSITION SIZE -------------//
// Check if our account currency is the same as the base or quote currency (for risk $ conversion purposes)
accountSameAsCounterCurrency = accountCurrency == syminfo.currency
accountSameAsBaseCurrency = accountCurrency == syminfo.basecurrency

// Check if our account currency is neither the base or quote currency (for risk $ conversion purposes)
accountNeitherCurrency = not accountSameAsCounterCurrency and not accountSameAsBaseCurrency

// Get currency conversion rates if applicable
conversionCurrencyPair = accountSameAsCounterCurrency ? syminfo.tickerid : accountNeitherCurrency ? accountCurrency + syminfo.currency : accountCurrency + syminfo.currency
conversionCurrencyRate = security(symbol=syminfo.type == "forex" ? conversionCurrencyPair : "AUDUSD", resolution="D", expression=close)

// Calculate position size
getPositionSize(stopLossSizePoints) =>
    riskAmount = (accountBalance * (riskPerTrade / 100)) * (accountSameAsBaseCurrency or accountNeitherCurrency ? conversionCurrencyRate : 1.0)
    riskPerPoint = (stopLossSizePoints * syminfo.pointvalue)
    positionSize = syminfo.type == "forex" ? ((riskAmount / riskPerPoint) / syminfo.mintick) : 0
    round(positionSize)
//------------- END POSITION SIZE CODE -------------//

// Detect setup
var inLongTrade = false
var riskReward = 1.0
var tradeStop = 0.0
var tradeStopDistance = 0.0
var tradeTarget = 0.0
var tradeSize = 0
longSetup = low == lowest(low, 15) and close >= open[1] and close[1] < open[1] and open >= low[1]

// Calculate stops & targets
if longSetup and not inLongTrade
    tradeStop := low - atr
    tradeStopDistance := close - tradeStop
    tradeTarget := close + (tradeStopDistance * riskReward)
    tradeSize := getPositionSize(toWhole(tradeStopDistance) * 10)
    inLongTrade := true
    
// Exit trade when appropriate
if inLongTrade and (high >= tradeTarget or low <= tradeStop)
    inLongTrade := false

// Draw setup info
plotshape(longSetup, color=color.green, style=shape.triangleup, location=location.belowbar, title="Long Setup")
plot(inLongTrade ? tradeStop : na, color=color.red, style=plot.style_linebr, title="Trade Stop")
plot(inLongTrade ? tradeTarget : na, color=color.green, style=plot.style_linebr, title="Trade Target")

// Draw position size
plot(inLongTrade ? tradeStopDistance : na, color=color.gray, transp=100, title="Trade Stop Distance")
plot(inLongTrade ? tradeSize : na, color=color.purple, transp=100, title="Position Size")

Automating a STRATEGY SCRIPT

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// Last Updated: 26th May, 2021
// @version=4
strategy("Hammers & Stars Strategy YouTube", shorttitle="HSS", overlay=true)

// Get user input
stopMultiplier   = input(title="Stop Loss ATR", type=input.float, defval=1.0, tooltip="Stop loss multiplier (x ATR)", group="Strategy Settings")
rr               = input(title="R:R", type=input.float, defval=1.0, tooltip="Risk:Reward profile", group="Strategy Settings")
fibLevel         = input(title="Fib Level", type=input.float, defval=0.333, tooltip="Used to calculate upper/lower third of candle. (For example, setting it to 0.5 will mean hammers must close >= 50% mark of the total candle size)", group="Strategy Settings")
oandaDemo        = input(title="Use Oanda Demo?", type=input.bool, defval=false, tooltip="If turned on then oandapractice broker prefix will be used for AutoView alerts (demo account). If turned off then live account will be used", group="AutoView Oanda Settings")
limitOrder       = input(title="Use Limit Order?", type=input.bool, defval=true, tooltip="If turned on then AutoView will use limit orders. If turned off then market orders will be used", group="AutoView Oanda Settings")
gtdOrder         = input(title="Days To Leave Limit Order", type=input.integer, minval=0, defval=2, tooltip="This is your GTD setting (good til day)", group="AutoView Oanda Settings")
accountBalance   = input(title="Account Balance", type=input.float, defval=1000.0, step=100, tooltip="Your account balance (used for calculating position size)", group="AutoView Oanda Settings")
accountCurrency  = input(title="Account Currency", type=input.string, defval="USD", options=["AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "NZD", "USD"], tooltip="Your account balance currency (used for calculating position size)", group="AutoView Oanda Settings")
riskPerTrade     = input(title="Risk Per Trade %", type=input.float, defval=2.0, step=0.5, tooltip="Your risk per trade as a % of your account balance", group="AutoView Oanda Settings")

// Filter Settings
// ATR Filter
atrMinFilterSize = input(title=">= ATR Filter", type=input.float, defval=0.0, minval=0.0, tooltip="Minimum size of entry candle compared to ATR", group="Filters")
atrMaxFilterSize = input(title="<= ATR Filter", type=input.float, defval=3.0, minval=0.0, tooltip="Maximum size of entry candle compared to ATR", group="Filters")
// EMA Filter
emaFilterLength = input(title="EMA Filter Length", type=input.integer, defval=0, tooltip="EMA Length for filtering trades (set to zero to disable)", group="Filters")
// Date Filter
startTime = input(title="Start Date Filter", defval=timestamp("01 Jan 1000 13:30 +0000"), type=input.time, tooltip="Date & time to begin trading from", group="Filters")
endTime = input(title="End Date Filter", defval=timestamp("1 Jan 2099 19:30 +0000"), type=input.time, tooltip="Date & time to stop trading", group="Filters")
// Time Filter
timeSession = input(title="Time Session To Ignore Trades", type=input.session, defval="0600-0915", group="Filters", tooltip="Time session to ignore trades")
useTimeFilter = input(title="Use Time Session Filter", type=input.bool, defval=false, group="Filters", tooltip="Turns on/off time session filter")

// Get ATR
atr = atr(14)

// Check ATR Filter
atrMinFilter = high - low >= (atrMinFilterSize * atr) or atrMinFilterSize == 0.0
atrMaxFilter = high - low <= (atrMaxFilterSize * atr) or atrMaxFilterSize == 0.0
atrFilter = atrMinFilter and atrMaxFilter

// Check EMA Filter
ema = emaFilterLength == 0 ? na : ema(close, emaFilterLength)
emaLongFilter = emaFilterLength == 0 or (close > ema and not na(ema))
emaShortFilter = emaFilterLength == 0 or (close < ema and not na(ema))

// Check Date Filter
dateFilter = time >= startTime and time <= endTime

// Check Time Filter
isInSession(sess) => na(time(timeframe.period, sess)) == false
timeFilter = (useTimeFilter and not isInSession(timeSession)) or not useTimeFilter

// Merge Filters
longFilters = atrFilter and emaLongFilter and dateFilter and timeFilter
shortFilters = atrFilter and emaShortFilter and dateFilter and timeFilter
bgcolor(color=(useTimeFilter and isInSession(timeSession)) or not dateFilter or not atrFilter ? color.red : na, transp=70, title="Filter Colorr")

// Calculate the 33.3% fibonacci level for current candle
bullFib = (low - high) * fibLevel + high
bearFib = (high - low) * fibLevel + low

// Determine which price source closes or opens highest/lowest
lowestBody = close < open ? close : open
highestBody = close > open ? close : open

// Determine if we have a valid setup
validHammer = lowestBody >= bullFib and close != open and not na(atr) and longFilters
validStar = highestBody <= bearFib and close != open and not na(atr) and shortFilters

// Check if we have confirmation for our setup
validLong = validHammer and strategy.position_size == 0 and barstate.isconfirmed
validShort = validStar and strategy.position_size == 0 and barstate.isconfirmed

//------------- DETERMINE POSITION SIZE -------------//
// Get account inputs
var broker = oandaDemo ? "oandapractice" : "oanda"
var tradePositionSize = 0.0
var pair = syminfo.basecurrency + "/" + syminfo.currency

// Check if our account currency is the same as the base or quote currency (for risk $ conversion purposes)
accountSameAsCounterCurrency = accountCurrency == syminfo.currency
accountSameAsBaseCurrency = accountCurrency == syminfo.basecurrency

// Check if our account currency is neither the base or quote currency (for risk $ conversion purposes)
accountNeitherCurrency = not accountSameAsCounterCurrency and not accountSameAsBaseCurrency

// Get currency conversion rates if applicable
conversionCurrencyPair = accountSameAsCounterCurrency ? syminfo.tickerid : accountNeitherCurrency ? accountCurrency + syminfo.currency : accountCurrency + syminfo.currency
conversionCurrencyRate = security(symbol=syminfo.type == "forex" ? conversionCurrencyPair : "AUDUSD", resolution="D", expression=close)

// Calculate position size
getPositionSize(stopLossSizePoints) =>
    riskAmount = (accountBalance * (riskPerTrade / 100)) * (accountSameAsBaseCurrency or accountNeitherCurrency ? conversionCurrencyRate : 1.0)
    riskPerPoint = (stopLossSizePoints * syminfo.pointvalue)
    positionSize = syminfo.type == "forex" ? ((riskAmount / riskPerPoint) / syminfo.mintick) : 0
    round(positionSize)
    
// Custom function to convert pips into whole numbers
toWhole(number) =>
    return = atr(14) < 1.0 ? (number / syminfo.mintick) / (10 / syminfo.pointvalue) : number
    return := atr(14) >= 1.0 and atr(14) < 100.0 and syminfo.currency == "JPY" ? return * 100 : return
//------------- END POSITION SIZE CODE -------------//

// Set up our GTD (good-til-date) order info
gtdTime = time + (gtdOrder * 1440 * 60 * 1000) // 86,400,000ms per day
gtdYear = year(gtdTime)
gtdMonth = month(gtdTime)
gtdDay = dayofmonth(gtdTime)
gtdString = " dt=" + tostring(gtdYear) + "-" + tostring(gtdMonth) + "-" + tostring(gtdDay)

// Calculate our stops & targets
stopSize = atr * stopMultiplier
longStopPrice = low < low[1] ? low - stopSize : low[1] - stopSize
longStopDistance = close - longStopPrice
longTargetPrice = close + (longStopDistance * rr)
shortStopPrice = high > high[1] ? high + stopSize : high[1] + stopSize
shortStopDistance = shortStopPrice - close
shortTargetPrice = close - (shortStopDistance * rr)

// Save stops & targets for the current trade
var tradeStopPrice = 0.0
var tradeTargetPrice = 0.0

// Detect valid long setups & trigger alerts
if validLong
    tradeStopPrice := longStopPrice
    tradeTargetPrice := longTargetPrice
    tradePositionSize := getPositionSize(toWhole(longStopDistance) * 10)
    // Trigger AutoView long alert
    alert(message="e=" + broker + " b=long"
     + " q=" + tostring(tradePositionSize) 
     + " s=" + pair
     + " t=" + (limitOrder ? "limit fp=" + tostring(close) : "market")
     + " fsl=" + tostring(tradeStopPrice)
     + " ftp=" + tostring(tradeTargetPrice)
     + (gtdOrder != 0 and limitOrder ? gtdString : ""),
     freq=alert.freq_once_per_bar_close)

// Detect valid short setups & trigger alerts
if validShort
    tradeStopPrice := shortStopPrice
    tradeTargetPrice := shortTargetPrice
    tradePositionSize := getPositionSize(toWhole(shortStopDistance) * 10)
    // Trigger AutoView short alert
    alert(message="e=" + broker + " b=short"
     + " q=" + tostring(tradePositionSize) 
     + " s=" + pair
     + " t=" + (limitOrder ? "limit fp=" + tostring(close) : "market")
     + " fsl=" + tostring(tradeStopPrice)
     + " ftp=" + tostring(tradeTargetPrice) 
     + (gtdOrder != 0 and limitOrder ? gtdString : ""),
     freq=alert.freq_once_per_bar_close)

// Enter trades whenever a valid setup is detected
strategy.entry(id="Long", long=strategy.long, when=validLong)
strategy.entry(id="Short", long=strategy.short, when=validShort)

// Exit trades whenever our stop or target is hit
strategy.exit(id="Long Exit", from_entry="Long", limit=tradeTargetPrice, stop=tradeStopPrice, when=strategy.position_size > 0)
strategy.exit(id="Short Exit", from_entry="Short", limit=tradeTargetPrice, stop=tradeStopPrice, when=strategy.position_size < 0)

// Draw trade data
plot(emaFilterLength == 0 ? na : ema, color=close > ema ? color.green : color.red, title="EMA Filter")
plot(strategy.position_size != 0 or validLong or validShort ? tradeStopPrice : na, title="Trade Stop Price", color=color.red, style=plot.style_linebr, transp=0)
plot(strategy.position_size != 0 or validLong or validShort ? tradeTargetPrice : na, title="Trade Target Price", color=color.green, style=plot.style_linebr, transp=0)
//plot(strategy.position_size != 0 or validLong or validShort ? tradePositionSize : na, title="Trade Position Size", color=color.purple, style=plot.style_linebr, transp=100)

// Draw price action setup arrows
plotshape(validLong ? 1 : na, style=shape.triangleup, location=location.belowbar, color=color.green, title="Bullish Setup")
plotshape(validShort ? 1 : na, style=shape.triangledown, location=location.abovebar, color=color.red, title="Bearish Setup")

Sending PINECONNECTOR COMMANDS

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
strategy("PineConnector Strategy Test", overlay=true)

// PineConnector Settings
pc_id = input(title="License ID", defval="1234567890123", type=input.string, group="PineConnector Settings", tooltip="This is your PineConnector license ID")
pc_risk = input(title="Risk Per Trade", defval=1, step=0.5, type=input.float, group="PineConnector Settings", tooltip="This is how much to risk per trade (if set to %, use whole numbers)")
pc_prefix = input(title="MetaTrader Prefix", defval="", type=input.string, group="PineConnector Settings", tooltip="This is your broker's MetaTrader symbol prefix")
pc_suffix = input(title="MetaTrader Suffix", defval="", type=input.string, group="PineConnector Settings", tooltip="This is your broker's MetaTrader symbol suffix")
pc_limit = input(title="Use Limit Order?", defval=true, type=input.bool, group="PineConnector Settings", tooltip="If true a limit order will be used, if false a market order will be used")

// Generate PineConnector alert string
var symbol = pc_prefix + syminfo.ticker + pc_suffix
var limit = pc_limit ? "limit" : ""
price = pc_limit ? "price=" + tostring(close) + "," : ""
pc_entry_alert(direction, price, sl, tp) =>
    pc_id + "," + direction + "," + symbol + "," + price + "sl=" + tostring(sl) + ",tp=" + tostring(tp) + ",risk=" + tostring(pc_risk)

// See if this bar's time happened on/after start date (to stop script taking too many trades)
afterStartDateFilter = time >= timestamp(syminfo.timezone, 2021, 7, 1, 0, 0)

// Test long command
longCondition = close > high[1] and afterStartDateFilter
var longStop = 0.0
var longTarget = 0.0
if longCondition and barstate.isconfirmed and strategy.position_size == 0
    longStop := low
    longTarget := close + syminfo.mintick * 100
    alert_string = pc_entry_alert("buy" + limit, price, longStop, longTarget)
    alert(alert_string, alert.freq_once_per_bar_close)
    strategy.entry("Long", strategy.long, comment=alert_string)

// Test short command
shortCondition = close < low[1] and afterStartDateFilter
var shortStop = 0.0
var shortTarget = 0.0
if shortCondition and barstate.isconfirmed and strategy.position_size == 0
    shortStop := high
    shortTarget := close - syminfo.mintick * 100
    alert_string = pc_entry_alert("sell" + limit, price, shortStop, shortTarget)
    alert(alert_string, alert.freq_once_per_bar_close)
    strategy.entry("Short", strategy.short, comment=alert_string)
    
// Exit mock trades
strategy.exit(id="Long Exit", from_entry="Long", limit=longTarget, stop=longStop, when=strategy.position_size > 0)
strategy.exit(id="Short Exit", from_entry="Short", limit=shortTarget, stop=shortStop, when=strategy.position_size < 0)

FTB Strategy for PineConnector

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / PineScriptMastery
// FTB Strategy (PineConnector Version)
// Last Updated: 21st July, 2021
// @version=4
strategy("[2021] FTB Strategy", shorttitle="FTB", overlay=true, calc_on_order_fills=true, initial_capital=10000, default_qty_value=100000)

// Risk Settings
var g_risk      = "Risk Settings"
pips            = input(title="Stop Pips", type=input.float, defval=2.0, group=g_risk, tooltip="How many pips above high to put stop loss")
rr              = input(title="Risk:Reward", type=input.float, defval=1.0, group=g_risk, tooltip="This determines the risk:reward profile of the setup")
// Filters
var g_filter    = "Filter Settings"
timezone        = input(title="Timezone", type=input.session, defval="0200-0700", group=g_filter, tooltip="Which timezone to search for FTB signals in")
days            = input(title="Days To Trade", defval="13457", group=g_filter, tooltip="Which days to trade this strategy on (Monday & Friday disabled by default)")
useRsiFilter    = input(title="RSI OB/OS?", type=input.bool, defval=true, group=g_filter, tooltip="If true then the RSI must be considered overbought before a signal is valid")
useCloseFilter  = input(title="Previous Bar Must Be Bullish?", type=input.bool, defval=false, group=g_filter, tooltip="If true then the previous bar must have closed bullish")
useHighFilter   = input(title="High Filter", type=input.bool, defval=false, group=g_filter, tooltip="If true then the signal bar must be the highest bar over X bars")
highLookback    = input(title="High Lookback", type=input.integer, defval=10, group=g_filter, tooltip="This is for setting the High Filter lookback distance")
fib             = input(title="Candle Close %", defval=0.5, group=g_filter, tooltip="For identifying shooting star candles (0.5 = must close <= 50% mark of candle size)")
rsiLen          = input(title="RSI Length", type=input.integer, defval=3, group=g_filter, tooltip="RSI length")
rsiOB           = input(title="RSI OB", type=input.float, defval=70.0, group=g_filter, tooltip="RSI overbought threshold")
// PineConnector Settings
var g_pc        = "PineConnector Settings"
pc_id           = input(title="License ID", defval="YOUR_ID", type=input.string, group=g_pc, tooltip="This is your PineConnector license ID")
pc_risk         = input(title="Risk Per Trade", defval=1, step=0.5, type=input.float, group=g_pc, tooltip="This is how much to risk per trade (% of balance or lots)")
pc_prefix       = input(title="MetaTrader Prefix", defval="", type=input.string, group=g_pc, tooltip="This is your broker's MetaTrader symbol prefix")
pc_suffix       = input(title="MetaTrader Suffix", defval="", type=input.string, group=g_pc, tooltip="This is your broker's MetaTrader symbol suffix")
pc_spread       = input(title="Spread", defval=0.5, type=input.float, group=g_pc, tooltip="Enter your average spread for this pair (used for offsetting limit order)")
pc_limit        = input(title="Use Limit Order?", defval=true, type=input.bool, group=g_pc, tooltip="If true a limit order will be used, if false a market order will be used")

// Generate PineConnector alert string
var symbol = pc_prefix + syminfo.ticker + pc_suffix
var limit = pc_limit ? "limit" : ""
pc_entry_alert(direction, sl, tp) =>
    price = pc_limit ? "price=" + tostring(pc_spread) + "," : ""
    pc_id + "," + direction + limit + "," + symbol + "," + price + "sl=" + tostring(sl) + ",tp=" + tostring(tp) + ",risk=" + tostring(pc_risk)

// Get RSI filter
rsiValue = rsi(close, rsiLen)
rsiFilter = not useRsiFilter or rsiValue >= rsiOB

// Check high & close filter
highFilter = not useHighFilter or high == highest(high, highLookback)
closeFilter = not useCloseFilter or close[1] > open[1]

// InSession() determines if a price bar falls inside the specified session
inSession(sess) => na(time(timeframe.period, sess + ":" + days)) == false

// Calculate 50% mark of candle size
bearFib = (high - low) * fib + low

// Check filters
filters = inSession(timezone) and closeFilter and high > high[1] and rsiFilter and highFilter and open != close

// Detect valid shooting star pinbar pattern
var takenTradeAlready = false
star = filters and close < bearFib and open < bearFib and not takenTradeAlready

// Calculate stops & targets
shortStopPrice = high + (syminfo.mintick * pips * 10)
shortStopDistance = shortStopPrice - close
shortTargetPrice = close - (shortStopDistance * rr)

// Save stops & targets for the current trade
var tradeStopPrice = 0.0
var tradeTargetPrice = 0.0

// If we detect a valid shooting star, save our stops & targets, enter short and generate alert
if star and barstate.isconfirmed
    tradeStopPrice := shortStopPrice
    tradeTargetPrice := shortTargetPrice
    takenTradeAlready := true
    alertString = pc_entry_alert("sell", tradeStopPrice, tradeTargetPrice)
    alert(alertString, alert.freq_once_per_bar_close)
    strategy.entry(id="Short", long=strategy.short, when=strategy.position_size == 0, comment=alertString)

// If we have exited the FTB session then reset our takenTradeAlready flag for the next session
if not inSession(timezone) and inSession(timezone)[1]
    takenTradeAlready := false
    
// If price has exceeded target then cancel limit order if it's still active
if pc_limit and low <= tradeTargetPrice and strategy.position_size == 0
    alert(pc_id + ",cancelshort," + symbol)
    tradeTargetPrice := na

// Draw stops & targets
plot(star ? tradeStopPrice : na, color=color.red, style=plot.style_linebr, title="SL")
plot(star ? shortTargetPrice : na, color=color.green, style=plot.style_linebr, title="TP")
// Draw short signals
plotshape(star ? 1 : na, style=shape.triangledown, color=color.red)
// Change background color to highlight detection zone
bgcolor(color=inSession(timezone) ? color.new(color.red,80) : na, title="Session")

// Exit trade whenever our stop or target is hit
strategy.exit(id="Short Exit", from_entry="Short", limit=tradeTargetPrice, stop=tradeStopPrice, when=strategy.position_size != 0)

Pinbar Strategy for PineConnector

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// Last Updated: 27th July, 2021
// @version=4
strategy("Hammers & Stars Strategy [Automated]", shorttitle="HSS", overlay=true)

// Get Strategy Settings
var g_strategy = "Strategy Settings"
stopMultiplier   = input(title="Stop Loss ATR", type=input.float, defval=1.0, tooltip="Stop loss multiplier (x ATR)", group=g_strategy)
rr               = input(title="R:R", type=input.float, defval=1.0, tooltip="Risk:Reward profile", group=g_strategy)
fibLevel         = input(title="Fib Level", type=input.float, defval=0.333, tooltip="Used to calculate upper/lower third of candle. (For example, setting it to 0.5 will mean hammers must close >= 50% mark of the total candle size)", group=g_strategy)

// Filter Settings
var g_filters = "Filter Settings"
// ATR Filter
atrMinFilterSize = input(title=">= ATR Filter", type=input.float, defval=0.0, minval=0.0, tooltip="Minimum size of entry candle compared to ATR", group=g_filters)
atrMaxFilterSize = input(title="<= ATR Filter", type=input.float, defval=3.0, minval=0.0, tooltip="Maximum size of entry candle compared to ATR", group=g_filters)
// EMA Filter
emaFilterLength = input(title="EMA Filter Length", type=input.integer, defval=20, tooltip="EMA Length for filtering trades (set to zero to disable)", group=g_filters)
emaTouchFilter = input(title="EMA Touch Filter", type=input.bool, defval=false, tooltip="Price must touch EMA", group=g_filters)
// Date Filter
startTime = input(title="Start Date Filter", defval=timestamp("01 Jan 1000 13:30 +0000"), type=input.time, tooltip="Date & time to begin trading from", group=g_filters)
endTime = input(title="End Date Filter", defval=timestamp("1 Jan 2099 19:30 +0000"), type=input.time, tooltip="Date & time to stop trading", group=g_filters)
// Time Filter
timeSession = input(title="Time Session To Ignore Trades", type=input.session, defval="0600-0915", tooltip="Time session to ignore trades", group=g_filters)
useTimeFilter = input(title="Use Time Session Filter", type=input.bool, defval=false, tooltip="Turns on/off time session filter", group=g_filters)

// Get AutoView Settings
var g_av = "AutoView Oanda Settings"
autoview         = input(title="Use AutoView?", type=input.bool, defval=false, tooltip="Turn this on to use AutoView alerts", group=g_av)
oandaDemo        = input(title="Use Oanda Demo?", type=input.bool, defval=false, tooltip="If turned on then oandapractice broker prefix will be used for AutoView alerts (demo account). If turned off then live account will be used", group=g_av)
limitOrder       = input(title="Use Limit Order?", type=input.bool, defval=true, tooltip="If turned on then AutoView will use limit orders. If turned off then market orders will be used", group=g_av)
gtdOrder         = input(title="Days To Leave Limit Order", type=input.integer, minval=0, defval=2, tooltip="This is your GTD setting (good til day)", group=g_av)
accountBalance   = input(title="Account Balance", type=input.float, defval=1000.0, step=100, tooltip="Your account balance (used for calculating position size)", group=g_av)
accountCurrency  = input(title="Account Currency", type=input.string, defval="USD", options=["AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "NZD", "USD"], tooltip="Your account balance currency (used for calculating position size)", group=g_av)
riskPerTrade     = input(title="Risk Per Trade %", type=input.float, defval=2.0, step=0.5, tooltip="Your risk per trade as a % of your account balance", group=g_av)

// PineConnector Settings
var g_pc        = "PineConnector Settings"
pineconnector   = input(title="Use PineConnector?", type=input.bool, defval=false, tooltip="Turn this on to use PineConnector alerts", group=g_pc)
pc_id           = input(title="License ID", defval="YOUR_ID", type=input.string, group=g_pc, tooltip="This is your PineConnector license ID")
pc_risk         = input(title="Risk Per Trade", defval=1, step=0.5, type=input.float, group=g_pc, tooltip="This is how much to risk per trade (% of balance or lots)")
pc_prefix       = input(title="MetaTrader Prefix", defval="", type=input.string, group=g_pc, tooltip="This is your broker's MetaTrader symbol prefix")
pc_suffix       = input(title="MetaTrader Suffix", defval="", type=input.string, group=g_pc, tooltip="This is your broker's MetaTrader symbol suffix")
pc_spread       = input(title="Spread", defval=0.5, type=input.float, group=g_pc, tooltip="Enter your average spread for this pair (used for offsetting limit order)")
pc_limit        = input(title="Use Limit Order?", defval=true, type=input.bool, group=g_pc, tooltip="If true a limit order will be used, if false a market order will be used")

// Generate PineConnector alert string
var symbol = pc_prefix + syminfo.ticker + pc_suffix
var limit = pc_limit ? "limit" : ""
pc_entry_alert(direction, sl, tp) =>
    price = pc_limit ? "price=" + tostring(pc_spread) + "," : ""
    pc_id + "," + direction + limit + "," + symbol + "," + price + "sl=" + tostring(sl) + ",tp=" + tostring(tp) + ",risk=" + tostring(pc_risk)

// Get ATR
atr = atr(14)

// Check ATR Filter
atrMinFilter = high - low >= (atrMinFilterSize * atr) or atrMinFilterSize == 0.0
atrMaxFilter = high - low <= (atrMaxFilterSize * atr) or atrMaxFilterSize == 0.0
atrFilter = atrMinFilter and atrMaxFilter

// Check EMA Filter
ema = emaFilterLength == 0 ? na : ema(close, emaFilterLength)
emaLongFilter = emaFilterLength == 0 or (close > ema and not na(ema))
emaShortFilter = emaFilterLength == 0 or (close < ema and not na(ema))
emaTouchFilterLong = (low <= ema and emaTouchFilter and close[1] > ema) or not emaTouchFilter
emaTouchFilterShort = (high >= ema and emaTouchFilter and close[1] < ema) or not emaTouchFilter

// Check Date Filter
dateFilter = time >= startTime and time <= endTime

// Check Time Filter
isInSession(sess) => na(time(timeframe.period, sess)) == false
timeFilter = (useTimeFilter and not isInSession(timeSession)) or not useTimeFilter

// Merge Filters
longFilters = atrFilter and emaLongFilter and dateFilter and timeFilter and emaTouchFilterLong
shortFilters = atrFilter and emaShortFilter and dateFilter and timeFilter and emaTouchFilterShort
bgcolor(color=(useTimeFilter and isInSession(timeSession)) or not dateFilter or not atrFilter ? color.new(color.red,70) : na, title="Filter Color")

// Calculate the 33.3% fibonacci level for current candle
bullFib = (low - high) * fibLevel + high
bearFib = (high - low) * fibLevel + low

// Determine which price source closes or opens highest/lowest
lowestBody = close < open ? close : open
highestBody = close > open ? close : open

// Determine if we have a valid setup
validHammer = lowestBody >= bullFib and close != open and not na(atr) and longFilters
validStar = highestBody <= bearFib and close != open and not na(atr) and shortFilters

// Check if we have confirmation for our setup
validLong = validHammer and strategy.position_size == 0 and barstate.isconfirmed
validShort = validStar and strategy.position_size == 0 and barstate.isconfirmed

//------------- DETERMINE POSITION SIZE -------------//
// Get account inputs
var broker = oandaDemo ? "oandapractice" : "oanda"
var tradePositionSize = 0.0
var pair = syminfo.basecurrency + "/" + syminfo.currency

// Check if our account currency is the same as the base or quote currency (for risk $ conversion purposes)
accountSameAsCounterCurrency = accountCurrency == syminfo.currency
accountSameAsBaseCurrency = accountCurrency == syminfo.basecurrency

// Check if our account currency is neither the base or quote currency (for risk $ conversion purposes)
accountNeitherCurrency = not accountSameAsCounterCurrency and not accountSameAsBaseCurrency

// Get currency conversion rates if applicable
conversionCurrencyPair = accountSameAsCounterCurrency ? syminfo.tickerid : accountNeitherCurrency ? accountCurrency + syminfo.currency : accountCurrency + syminfo.currency
conversionCurrencyRate = security(symbol=syminfo.type == "forex" ? conversionCurrencyPair : "AUDUSD", resolution="D", expression=close)

// Calculate position size
getPositionSize(stopLossSizePoints) =>
    riskAmount = (accountBalance * (riskPerTrade / 100)) * (accountSameAsBaseCurrency or accountNeitherCurrency ? conversionCurrencyRate : 1.0)
    riskPerPoint = (stopLossSizePoints * syminfo.pointvalue)
    positionSize = syminfo.type == "forex" ? ((riskAmount / riskPerPoint) / syminfo.mintick) : 0
    round(positionSize)
    
// Custom function to convert pips into whole numbers
toWhole(number) =>
    return = atr(14) < 1.0 ? (number / syminfo.mintick) / (10 / syminfo.pointvalue) : number
    return := atr(14) >= 1.0 and atr(14) < 100.0 and syminfo.currency == "JPY" ? return * 100 : return
//------------- END POSITION SIZE CODE -------------//

// Set up our GTD (good-til-date) order info
gtdTime = time + (gtdOrder * 1440 * 60 * 1000) // 86,400,000ms per day
gtdYear = year(gtdTime)
gtdMonth = month(gtdTime)
gtdDay = dayofmonth(gtdTime)
gtdString = " dt=" + tostring(gtdYear) + "-" + tostring(gtdMonth) + "-" + tostring(gtdDay)

// Calculate our stops & targets
stopSize = atr * stopMultiplier
longStopPrice = low < low[1] ? low - stopSize : low[1] - stopSize
longStopDistance = close - longStopPrice
longTargetPrice = close + (longStopDistance * rr)
shortStopPrice = high > high[1] ? high + stopSize : high[1] + stopSize
shortStopDistance = shortStopPrice - close
shortTargetPrice = close - (shortStopDistance * rr)

// Save stops & targets for the current trade
var tradeStopPrice = 0.0
var tradeTargetPrice = 0.0

// Detect valid long setups & trigger alerts
temp_positionSize = getPositionSize(toWhole(longStopDistance) * 10)
if validLong
    tradeStopPrice := longStopPrice
    tradeTargetPrice := longTargetPrice
    tradePositionSize := temp_positionSize
    // Generate PineConnector alert syntax
    pc_alert = pc_entry_alert("buy", tradeStopPrice, tradeTargetPrice)
    // Generate AutoView alert syntax
    av_alert = "e=" + broker + " b=long"
     + " q=" + tostring(tradePositionSize) 
     + " s=" + pair
     + " t=" + (limitOrder ? "limit fp=" + tostring(close) : "market")
     + " fsl=" + tostring(tradeStopPrice)
     + " ftp=" + tostring(tradeTargetPrice)
     + (gtdOrder != 0 and limitOrder ? gtdString : "")
    // Send alert to webhook
    alert(message=autoview ? av_alert : pineconnector ? pc_alert : "HSS Long Alert", freq=alert.freq_once_per_bar_close)

// Detect valid short setups & trigger alerts
temp_positionSize := getPositionSize(toWhole(shortStopDistance) * 10)
if validShort
    tradeStopPrice := shortStopPrice
    tradeTargetPrice := shortTargetPrice
    tradePositionSize := temp_positionSize
    // Generate PineConnector alert syntax
    pc_alert = pc_entry_alert("sell", tradeStopPrice, tradeTargetPrice)
    // Generate AutoView alert syntax
    av_alert = "e=" + broker + " b=short"
     + " q=" + tostring(tradePositionSize) 
     + " s=" + pair
     + " t=" + (limitOrder ? "limit fp=" + tostring(close) : "market")
     + " fsl=" + tostring(tradeStopPrice)
     + " ftp=" + tostring(tradeTargetPrice)
     + (gtdOrder != 0 and limitOrder ? gtdString : "")
    // Send alert to webhook
    alert(message=autoview ? av_alert : pineconnector ? pc_alert : "HSS Short Alert", freq=alert.freq_once_per_bar_close)

// Enter trades whenever a valid setup is detected
strategy.entry(id="Long", long=strategy.long, when=validLong)
strategy.entry(id="Short", long=strategy.short, when=validShort)

// Exit trades whenever our stop or target is hit
strategy.exit(id="Long Exit", from_entry="Long", limit=tradeTargetPrice, stop=tradeStopPrice, when=strategy.position_size > 0)
strategy.exit(id="Short Exit", from_entry="Short", limit=tradeTargetPrice, stop=tradeStopPrice, when=strategy.position_size < 0)

// Draw trade data
plot(emaFilterLength == 0 ? na : ema, color=close > ema ? color.green : color.red, title="EMA Filter")
plot(strategy.position_size != 0 or validLong or validShort ? tradeStopPrice : na, title="Trade Stop Price", color=color.new(color.red,0), style=plot.style_linebr)
plot(strategy.position_size != 0 or validLong or validShort ? tradeTargetPrice : na, title="Trade Target Price", color=color.new(color.green,0), style=plot.style_linebr)
//plot(strategy.position_size != 0 or validLong or validShort ? tradePositionSize : na, title="Trade Position Size", color=color.purple, style=plot.style_linebr, transp=100)

// Draw price action setup arrows
plotshape(validLong ? 1 : na, style=shape.triangleup, location=location.belowbar, color=color.green, title="Bullish Setup")
plotshape(validShort ? 1 : na, style=shape.triangledown, location=location.abovebar, color=color.red, title="Bearish Setup")

Daily Breakout Strategy

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
strategy("Daily Breakout Strategy", overlay=true, default_qty_value=1000000)

// Get user input
entryPips  = input(title="Entry Pips", defval=3.0, type=input.float, tooltip="How many pips above high to place entry order")
stopPips   = input(title="Stop Pips", defval=5.0, type=input.float, tooltip="Fixed pip stop loss distance")
targetPips = input(title="Target Pips", defval=10.0, type=input.float, tooltip="Fixed pip profit target distance")

// Get highs and lows
dailyHigh = security(syminfo.tickerid, "D", high)
dailyLow  = security(syminfo.tickerid, "D", low)

// Determine buy & sell point (default 3 pips/30 points above/below high/low)
buyPoint  = dailyHigh + (entryPips * 10 * syminfo.mintick)
sellPoint = dailyLow - (entryPips * 10 * syminfo.mintick)

// Determine stop loss (default 5 pips/50 points above/below buy/sell point)
stopLossLong  = buyPoint - (stopPips * 10 * syminfo.mintick)
stopLossShort = sellPoint + (stopPips * 10 * syminfo.mintick)

// Determine take profit (default 10 pips/100 points above/below buy/sell point)
takeProfitLong  = buyPoint + (targetPips * 10 * syminfo.mintick)
takeProfitShort = sellPoint - (targetPips * 10 * syminfo.mintick)

// If a new day has started and we're flat, place a buy stop & sell stop
var stopLossLongSaved = 0.0
var takeProfitLongSaved = 0.0
var stopLossShortSaved = 0.0
var takeProfitShortSaved = 0.0
newDay = change(time("D"))
if newDay
    if strategy.position_size == 0
        stopLossLongSaved := stopLossLong
        takeProfitLongSaved := takeProfitLong
        strategy.entry(id="Long", long=strategy.long, stop=buyPoint, oca_name="x", oca_type=strategy.oca.cancel)
        stopLossShortSaved := stopLossShort
        takeProfitShortSaved := takeProfitShort
        strategy.entry(id="Short", long=strategy.short, stop=sellPoint, oca_name="x", oca_type=strategy.oca.cancel)

// Exit our trade if our stop loss or take profit is hit
strategy.exit(id="Long Exit", from_entry="Long", limit=takeProfitLongSaved, stop=stopLossLongSaved)
strategy.exit(id="Short Exit", from_entry="Short", limit=takeProfitShortSaved, stop=stopLossShortSaved)

// Draw data to the chart
plot(dailyHigh, color=color.blue, linewidth=2, title="Daily High")
plot(dailyLow, color=color.blue, linewidth=2, title="Daily Low")
plot(buyPoint, color=color.purple, title="Buy Stop")
plot(stopLossLong, color=color.red, title="Long Stop Loss")
plot(takeProfitLong, color=color.green, title="Long Profit Target")
plot(sellPoint, color=color.purple, title="Sell Stop")
plot(stopLossShort, color=color.red, title="Short Stop Loss")
plot(takeProfitShort, color=color.green, title="Short Profit Target")

Discord Webhook Bot

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
study("Discord Alerts")

// Get user input
botName     = input(title="Bot Name", type=input.string, defval="TradingView", tooltip="The display name for this webhook bot")
avatarURL   = input(title="Avatar URL", type=input.string, defval="https://pbs.twimg.com/profile_images/1418656582888525833/p4fZd3KR.jpg", tooltip="Your preferred Avatar image URL")
iconURL     = input(title="Icon URL", type=input.string, defval="https://theartoftrading.com/files/discord/zentradingcircle.png", tooltip="Your preferred message icon image URL")
titleURL    = input(title="Title URL", type=input.string, defval="https://www.tradingview.com/chart/", tooltip="Where you want the title of the message to link to")
message     = input(title="Message", type=input.string, defval="", tooltip="Optional message to add before the role tag & embed info")
role        = input(title="Role ID", type=input.string, defval="", tooltip="The role ID you want to ping when this message is sent to discord (optional)")
embedColor  = input(title="Embed Color", type=input.string, defval="", tooltip="Your embed color (decimal color only - not HEX or RGB!)")
volatility  = input(title="Volatility Alerts?", type=input.bool, defval=true, tooltip="Turns on/off intraday volatility alerts")

// Declare constant variables
var ROLE_ID = role == "" ? "" : " (<@&" + role + ">)"
var ICON1_URL = syminfo.type == "forex" ? ("https://theartoftrading.com/files/discord/flags/" + syminfo.basecurrency + ".png") : iconURL
var ICON2_URL = syminfo.type == "forex" ? ("https://theartoftrading.com/files/discord/flags/" + syminfo.currency + ".png") : ""
var MARKET = syminfo.type == "forex" or syminfo.type == "crypto" ? syminfo.basecurrency : syminfo.ticker

// Get market data to send to discord
mktChange = (change(close) / close[1]) * 100
mktRSI = rsi(close, 14)

// Custom function to truncate (cut) excess decimal places
truncate(_number, _decimalPlaces) =>
    _factor = pow(10, _decimalPlaces)
    int(_number * _factor) / _factor
    
// Custom function to convert pips into whole numbers
atr = atr(14)
toWhole(_number) =>
    _return = atr < 1.0 ? (_number / syminfo.mintick) / (10 / syminfo.pointvalue) : _number
    _return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? _return * 100 : _return

// Generate discord embed JSON
getDiscordEmbedJSON(_color, _author, _title, _url, _icon_url, _icon2_url, _footer, _description) =>
    botTxt = "\"username\":\"" + botName + "\",\"avatar_url\":\"" + avatarURL + "\","
    tagTxt = message == "" and role == "" ? "" : ("\"content\":\"" + (message == "" ? "" : message + " ") + ROLE_ID + "\",")
    returnString = "{" + botTxt + tagTxt + "\"embeds\":[{\"title\":\""+_title+"\",\"url\":\""+_url+"\",\"color\":"+
      _color+",\"description\":\""+_description+"\",\"author\":{\"name\":\""+_author+
      "\",\"url\":\""+_url+"\",\"icon_url\":\""+_icon_url+"\"},\"footer\":{\"text\":\""+_footer+"\",\"icon_url\":\""+_icon2_url+"\"}}]}"

// Determine if we have a new bar starting - if so, send our Discord webhook alert
if barstate.isconfirmed
    timeframe = (timeframe.isintraday ? timeframe.period + " minute" : timeframe.isdaily ? "Daily" : timeframe.isweekly ? "Weekly" : timeframe.ismonthly ? "Monthly" : timeframe.period) + " timeframe"
    update = syminfo.ticker + " ended " + (mktChange > 0 ? "up +" : "down ") + tostring(truncate(mktChange,2)) + "% on " + timeframe + " (RSI = " + tostring(truncate(mktRSI,2)) + ")"
    gainLoss = toWhole(open - close)
    footer = "Price: " + tostring(close) + " (" + (gainLoss > 0 ? "+" : "") + tostring(gainLoss) + " pips)"
    gainColor = (embedColor != "" ? embedColor : (mktChange > 0 ? "65280" : "16711680"))
    content = getDiscordEmbedJSON(gainColor, "Market Update", syminfo.ticker, titleURL, ICON1_URL, ICON2_URL, footer, update)
    alert(content, alert.freq_once_per_bar)

// Check if we have high intraday volatility - if so, send our Discord webhook alert
if abs(mktChange) >= 10 and volatility
    timeframe = (timeframe.isintraday ? timeframe.period + " minute" : timeframe.isdaily ? "Daily" : timeframe.isweekly ? "Weekly" : timeframe.ismonthly ? "Monthly" : timeframe.period) + " timeframe"
    update = syminfo.ticker + " is " + (mktChange > 0 ? "up +" : "down ") + tostring(truncate(mktChange,2)) + "% [" + tostring(close) + "] on " + timeframe + " (RSI = " + tostring(truncate(mktRSI,2)) + ")"
    gainLoss = toWhole(open - close)
    footer = "Price: " + tostring(close) + " (" + (gainLoss > 0 ? "+" : "") + tostring(gainLoss) + " pips)"
    gainColor = (embedColor != "" ? embedColor : (mktChange > 0 ? "65280" : "16711680"))
    content = getDiscordEmbedJSON(gainColor, "High Volatility Alert", syminfo.ticker, titleURL, ICON1_URL, ICON2_URL, footer, update)
    alert(content, alert.freq_once_per_bar)      

// Prepare table
var table myTable = table.new(position.middle_right, 1, 1, border_width=1)
f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
    _cellText = _title + "\n" + _value
    table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor)

// Draw table
if barstate.islast
    f_fillCell(myTable, 0, 0, "Market:", MARKET + " (" + syminfo.type + ")", color.new(color.black,0), color.white)

How to use Tables

Watch Lesson

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ZenAndTheArtOfTrading / www.PineScriptMastery.com
// @version=4
study("Tables", overlay=true)

// Custom function to truncate (cut) excess decimal places
truncate(_number, _decimalPlaces) =>
    _factor = pow(10, _decimalPlaces)
    int(_number * _factor) / _factor

// Get display data
ema = ema(close,50)
rsi = rsi(close,14)
mktChange = (change(close) / close[1]) * 100

// Create table
var table myTable = table.new(position.top_right, 5, 2, border_width=1)

// Update table
if barstate.islast
    txt1 = "Closing Price\n" + tostring(close)
    txt2 = "Opening Price\n" + tostring(open)
    txt3 = "Pip Gain/Loss\n" + tostring(close - open)
    txt4 = "50-EMA Value\n" + tostring(truncate(ema,2))
    txt5 = "RSI Value\n" + tostring(truncate(rsi,2))
    txt6 = "Percent Change\n" + tostring(truncate(mktChange,2)) + "%"
    table.cell(myTable, 0, 0, text=txt1, bgcolor=color.black, text_color=color.white)
    table.cell(myTable, 0, 1, text=txt2, bgcolor=color.black, text_color=color.white)
    table.cell(myTable, 1, 0, text=txt3, bgcolor=color.black, text_color=color.white)
    table.cell(myTable, 1, 1, text=txt4, bgcolor=color.black, text_color=color.white)
    table.cell(myTable, 2, 0, text=txt5, bgcolor=color.black, text_color=color.white)
    table.cell(myTable, 2, 1, text=txt6, bgcolor=(mktChange > 0 ? color.green : color.red), text_color=color.white)