Advanced PineConnector Template

This lesson breaks down the source code to my Advanced PineConnector script template which includes the majority of PineConnector functionality inbuilt right into the Pine code.

Check out my other free lessons!

Source Code

Change Notes:

2nd December 2023

  • Fixed ATR multiplier not overriding fixed pip SL/TP when Use Pip-Based SL & TP setting was selected
  • Fixed Exit Reasons still sending TP to PineConnector when selected


8th December 2023:

  • Fixed ATR multiplier not sending the correct pips to PineConnector
  • Fixed ATR trailing stop still using TP
  • Added swing high/low input setting


// 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=5
strategy("PineConnector Template Code", overlay=true,
     initial_capital=10000,
     currency=currency.USD,
     default_qty_type=strategy.fixed,
     default_qty_value=100000)

// Strategy Settings
var const string GROUP_STRATEGY = "Your Strategy Settings"
STRATEGY_SL_DISTANCE    = input.float(title="Stop Loss Distance", defval=5, minval=0, group=GROUP_STRATEGY, tooltip="Distance in pips or ATR multiplier to place your SL", display=display.none)
STRATEGY_SL_ANCHOR      = input.string(title="SL Anchor Price", defval="Close", options=["Close","High/Low"], group=GROUP_STRATEGY, tooltip="Which price to calculate SL distance from", display=display.none)
STRATEGY_SL_LOOKBACK    = input.int(title="SL High/low Lookback", defval=1, group=GROUP_STRATEGY, tooltip="How many bars to look back for high/low anchor price", display=display.none)
STRATEGY_ATR_MULTIPLIER = input.float(title="ATR Multiplier", defval=0, minval=0, group=GROUP_STRATEGY, tooltip="14-period ATR multiplier for stop loss distance - set to 0 to use fixed pips instead", display=display.none)
STRATEGY_RISK_REWARD    = input.float(title="Profit Risk:Reward", defval=1, minval=0, group=GROUP_STRATEGY, tooltip="Your risk:reward profile for taking profit", display=display.none)
STRATEGY_BREAK_EVEN     = input.float(title="Break-Even Risk:Reward", defval=0, minval=0, group=GROUP_STRATEGY, tooltip="Your risk:reward profile for triggering your Stop Loss to move to break-even (set to 0 to disable)", display=display.none)
STRATEGY_TRAIL_STOP     = input.float(title="Trailing Stop Distance", defval=0,  minval=0, group=GROUP_STRATEGY, tooltip="Your risk:reward profile for triggering your Trailing Stop (set to 0 to disable)", display=display.none)
STRATEGY_EXIT_HCLC      = input.bool(title="Exit on Higher-Close/Lower-Close", defval=false, group=GROUP_STRATEGY, tooltip="If enabled, the script will exit on a higher/lower close after take-profit price is hit", display=display.none)
STRATEGY_EXIT_EXHAUST   = input.bool(title="Exit on Opposite Color Bar", defval=false, group=GROUP_STRATEGY, tooltip="If enabled, the script will exit on a bullish/bearish bar in the opposite direction of trade after price is hit", display=display.none)

// PineConnector Settings
var const string GROUP_PC = "PineConnector Settings"
PC_ENABLED              = input.bool(title="Use PineConnector", defval=true, group=GROUP_PC, tooltip="If accepted, when you set alert() function call then PineConnector commands will be automatically triggered by the script. Use this experimental feature at your own risk and don't use it with money you can't afford to lose", display=display.none)
PC_ID                   = input.string(title="License ID", defval="ID", group=GROUP_PC, tooltip="This is your PineConnector license ID", display=display.none)
PC_RISK                 = input.float(title="Risk Per Trade", defval=1, step=0.5, group=GROUP_PC, tooltip="This is how much to risk per trade (% of account balance OR lots - which one is used depends on your PineConnector settings)", display=display.none)
PC_ENTRY_PIPS           = input.float(title="Entry Pips", defval=0.1, minval=0, group=GROUP_PC, tooltip="Enter your pip offset for limit orders (ie. entry buy-limit/entry sell-limit)", display=display.none)
PC_SPREAD_FILTER        = input.float(title="Spread Filter", defval=0, group=GROUP_PC, tooltip="Optional Spread filter - will only execute trades if the current market Spread is below this pip amount. Zero to disable", display=display.none)
PC_BREAK_EVEN_OFFSET    = input.float(title="Break Even Offset", defval=0, group=GROUP_PC, tooltip="", display=display.none)
PC_USE_LIMIT            = input.bool(title="Use Entry Limit Order", defval=true, group=GROUP_PC, tooltip="If true a limit order will be used, if false a market order will be used", display=display.none)
PC_USE_PIP_ENTRY        = input.bool(title="Use Pip-Based Entry", defval=false, group=GROUP_PC, tooltip="If turned on and you're using a buylimit/selllimit order to enter, then pips will be sent to PineConnector - otherwise a Price value will be sent", display=display.none)
PC_USE_PIP_TARGET       = input.bool(title="Use Pip-Based SL & TP", defval=false, group=GROUP_PC, tooltip="Turn this on if you want to use a pip-based TP & SL, turn it off if you want to use a TradingView price-based TP & SL. Watch Update v3.05 course video for more info", display=display.none)
PC_OVERRIDE             = input.string(title="MetaTrader Symbol Override", defval="", group=GROUP_PC + " Optional", tooltip="Don't touch unless you really need to. This overrides the symbol sent from TradingView. Eg. if the TV symbol you're using is BTCUSDT.P and your MT broker's symbol is BTCUSDT, put BTCUSDT in here to override TV's symbol. This also overrides the prefix and suffix settings below.", display=display.none)
PC_PREFIX               = input.string(title="MetaTrader Prefix", defval="", group=GROUP_PC + " Optional", tooltip="OPTIONAL: This is your broker's MetaTrader symbol prefix", display=display.none)
PC_SUFFIX               = input.string(title="MetaTrader Suffix", defval="", group=GROUP_PC + " Optional", tooltip="OPTIONAL: This is your broker's MetaTrader symbol suffix", display=display.none)
PC_STRATEGY             = input.string(title="Strategy ID", defval="", group=GROUP_PC + " Optional", tooltip="OPTIONAL: This allows for multi-strategy setups by adding this string as a 'comment' parameter to any orders sent to PC. Useful for running multiple strategies on the same market across different timeframes or with different parameters.")
PC_DEBUG                = input.bool(title="Debug Automation Alerts", defval=true, group=GROUP_PC + " Optional", tooltip="Turns on/off label that displays what your alert message will look like if it gets sent to AutoView or PineConnector (useful for debugging errors or issues)", display=display.none)

// Prepare PineConnector Variables
var PC_VAR_SYMBOL = PC_OVERRIDE == "" ? (PC_PREFIX + syminfo.ticker + PC_SUFFIX) : PC_OVERRIDE
var PC_VAR_USE_LIMIT = PC_USE_LIMIT ? "limit" : ""
var PC_VAR_SPREAD_FILTER = PC_SPREAD_FILTER != 0 ? (",spread=" + str.tostring(PC_SPREAD_FILTER)) : ""
var PC_VAR_STRATEGY = PC_STRATEGY == "" ? "" : ",comment=\"" + PC_STRATEGY + "\""
var label PC_DEBUG_LABEL = na
var label PC_DEBUG_LABEL_TS = na

// Generate PineConnector entry alert string
PC_Entry_Alert(_direction, _entryprice, _sl, _tp, _be, _truncate=true) =>
    _format = _truncate ? "#.#####" : "#.##########"
    _price = PC_USE_LIMIT ? "price=" + str.tostring(_entryprice, _format) + "," : ""
    _tpText = _tp == 0 ? "" : "tp=" + str.tostring(_tp, _format) + ","
    _beText = _be == 0 ? "" : "betrigger=" + str.tostring(_be, _format) + ",beoffset=" + str.tostring(PC_BREAK_EVEN_OFFSET, _format) + ","
    PC_ID + "," + _direction + PC_VAR_USE_LIMIT + "," + PC_VAR_SYMBOL + "," + _price + "sl=" + str.tostring(_sl, _format) + "," + _tpText + 
     _beText + "risk=" + str.tostring(PC_RISK) + PC_VAR_SPREAD_FILTER + PC_VAR_STRATEGY

// Get market point -> pip value
GetPipSize() =>
    syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

// Stops & Targets
var float StopDistanceFixedPips = STRATEGY_SL_DISTANCE * GetPipSize()
var float TradeEntryPrice = na
var float TradeStopPrice = na
var float TradeProfitPrice = na
var float TradeBreakEvenPrice = na
var float TrailStopActivatePrice = na
var bool TrailStopActivated = false
var bool SearchingForExit = false

// Get indicator values
ATR_Value = nz(ta.atr(14))

//! SIMPLE EXAMPLE STRATEGY ENTRY CODE (REPLACE WITH YOUR OWN!)
bool LongTrade = ta.rsi(close, 14) < 30 and close > open and strategy.position_size == 0
bool ShortTrade = ta.rsi(close, 14) > 70 and close < open and strategy.position_size == 0
bool UseExitReason = STRATEGY_EXIT_HCLC or STRATEGY_EXIT_EXHAUST

// Generate PineConnector Alert String with all required parameters
GenerateEntryAlertString() =>
    pcStopPips      = math.abs(close - TradeStopPrice)
    pcTargetPips    = math.abs(close - TradeProfitPrice)
    pcBreakEvenPips = math.abs(close - TradeBreakEvenPrice)
    pcEntry         = PC_USE_PIP_ENTRY ? PC_ENTRY_PIPS : TradeEntryPrice
    pcStop          = PC_USE_PIP_TARGET ? pcStopPips / GetPipSize() : TradeStopPrice
    pcTarget        = UseExitReason ? 0 : PC_USE_PIP_TARGET ? pcTargetPips / GetPipSize() : TradeProfitPrice
    pcBreakEven     = na(TradeBreakEvenPrice) ? 0 : pcBreakEvenPips
    PC_Entry_Alert(LongTrade ? "buy" : "sell", pcEntry, pcStop, pcTarget, pcBreakEven, true)

// Get Long Stop Loss
swingHigh = ta.highest(high, STRATEGY_SL_LOOKBACK)
swingLow  = ta.lowest(low, STRATEGY_SL_LOOKBACK)
GetStopPrice(bool strategy_direction) =>
    AnchorPriceSL = STRATEGY_SL_ANCHOR == "Close" ? close : (strategy_direction ? swingLow : swingHigh)
    if strategy_direction
        returnValue = AnchorPriceSL - (STRATEGY_ATR_MULTIPLIER > 0 ? (ATR_Value * STRATEGY_ATR_MULTIPLIER) : StopDistanceFixedPips)
    else
        returnValue = AnchorPriceSL + (STRATEGY_ATR_MULTIPLIER > 0 ? (ATR_Value * STRATEGY_ATR_MULTIPLIER) : StopDistanceFixedPips)

// Long Entry Code
if LongTrade and barstate.isconfirmed
    TradeStopPrice      := GetStopPrice(true)
    StopDistancePips     = close - TradeStopPrice
    TradeProfitPrice    := close + (StopDistancePips * STRATEGY_RISK_REWARD)
    TradeEntryPrice     := close
    SearchingForExit    := false
    if STRATEGY_BREAK_EVEN > 0
        TradeBreakEvenPrice := close + (StopDistancePips * STRATEGY_BREAK_EVEN)
    if STRATEGY_TRAIL_STOP > 0
        TrailStopActivated := false
        TrailStopActivatePrice := close + (StopDistancePips * STRATEGY_TRAIL_STOP)
    if PC_USE_LIMIT
        strategy.cancel_all()
    strategy.entry("Buy", strategy.long, limit=PC_USE_LIMIT ? close - (PC_ENTRY_PIPS * GetPipSize()) : na)
    if PC_ENABLED
        alert(GenerateEntryAlertString(), alert.freq_once_per_bar_close)

// Short Entry Code
if ShortTrade and barstate.isconfirmed
    TradeStopPrice      := GetStopPrice(false)
    StopDistancePips     = TradeStopPrice - close
    TradeProfitPrice    := close - (StopDistancePips * STRATEGY_RISK_REWARD)
    TradeEntryPrice     := close
    SearchingForExit    := false
    if STRATEGY_BREAK_EVEN > 0
        TradeBreakEvenPrice := close - (StopDistancePips * STRATEGY_BREAK_EVEN)
    if STRATEGY_TRAIL_STOP > 0
        TrailStopActivated := false
        TrailStopActivatePrice := close - (StopDistancePips * STRATEGY_TRAIL_STOP)
    if PC_USE_LIMIT
        strategy.cancel_all()
    strategy.entry("Sell", strategy.short, limit=PC_USE_LIMIT ? close + (PC_ENTRY_PIPS * GetPipSize()) : na)
    if PC_ENABLED
        alert(GenerateEntryAlertString(), alert.freq_once_per_bar_close)

// Update trade entry price to match TradingView strategy tester 
if strategy.position_size != 0
    if TradeEntryPrice != strategy.position_avg_price
        TradeEntryPrice := strategy.position_avg_price

// Long Strategy Management Code
if strategy.position_size > 0
    // Long Break-Even Code (break-even order is handled directly by PC so no need for alert)
    if not na(TradeBreakEvenPrice) and high >= TradeBreakEvenPrice and TradeStopPrice < TradeEntryPrice
        TradeStopPrice := TradeEntryPrice + (PC_BREAK_EVEN_OFFSET * GetPipSize())
        TradeBreakEvenPrice := na

    // Long Trailing Stop Activation Code
    if STRATEGY_TRAIL_STOP > 0 and high >= TrailStopActivatePrice
        TrailStopActivated := true

    // Long Exit Reason Activation Code
    if high >= TradeProfitPrice
        if UseExitReason
            SearchingForExit := true
        if PC_USE_LIMIT // Ensure pending entry limit order is cancelled if target is hit in case entry order was not filled
            strategy.cancel("Buy")
            if PC_ENABLED
                alert(PC_ID + ",cancellong," + PC_VAR_SYMBOL + PC_STRATEGY, alert.freq_once_per_bar)

    // Confirmed Bar Code
    if barstate.isconfirmed

        //! SIMPLE EXAMPLE EXIT DETECTION CODE (REPLACE WITH YOUR OWN!)
        bool ExitTrade = false
        if SearchingForExit
            if STRATEGY_EXIT_HCLC and close < low[1]
                ExitTrade := true
            if STRATEGY_EXIT_EXHAUST and close < open
                ExitTrade := true

        // Long Exit Alert
        if ExitTrade
            strategy.close("Buy")
            if PC_ENABLED
                alert(PC_ID + ",closelong," + PC_VAR_SYMBOL + PC_VAR_STRATEGY, alert.freq_once_per_bar)
        
        // Long Trailing Stop Code
        LongStopLoss = GetStopPrice(true)
        if TrailStopActivated and LongStopLoss > TradeStopPrice
            TradeStopPrice := LongStopLoss
            NEW_SL = PC_USE_PIP_TARGET ? math.abs(TradeStopPrice - close) / GetPipSize() : TradeStopPrice
            string alertMessage = PC_ID + ",newsltplong," + PC_VAR_SYMBOL + ",sl=" + str.tostring(NEW_SL) + PC_VAR_STRATEGY
            if PC_ENABLED
                alert(alertMessage, alert.freq_once_per_bar_close)

            // Debug alert message label
            PC_DEBUG_LABEL_TS := label.new(bar_index, high + (GetPipSize() * 10), alertMessage, color=color.white)
            label.delete(PC_DEBUG_LABEL_TS[1])

// Short Strategy Management Code
if strategy.position_size < 0
    // Short Break-Even Code (break-even order is handled directly by PC so no need for alert)
    if not na(TradeBreakEvenPrice) and low <= TradeBreakEvenPrice and TradeStopPrice > TradeEntryPrice
        TradeStopPrice := TradeEntryPrice - (PC_BREAK_EVEN_OFFSET * GetPipSize())
        TradeBreakEvenPrice := na

    // Short Trailing Stop Activation Code
    if STRATEGY_TRAIL_STOP > 0 and low <= TrailStopActivatePrice
        TrailStopActivated := true

    // Short Exit Reason Activation Code
    if low <= TradeProfitPrice
        if UseExitReason
            SearchingForExit := true
        if PC_USE_LIMIT // Ensure pending entry limit order is cancelled if target is hit in case entry order was not filled
            strategy.cancel("Buy")
            if PC_ENABLED
                alert(PC_ID + ",cancelshort," + PC_VAR_SYMBOL + PC_STRATEGY, alert.freq_once_per_bar)

    // Confirmed Bar Code
    if barstate.isconfirmed

        //! SIMPLE EXAMPLE EXIT DETECTION CODE (REPLACE WITH YOUR OWN!)
        bool ExitTrade = false
        if SearchingForExit
            if STRATEGY_EXIT_HCLC and close > high[1]
                ExitTrade := true
            if STRATEGY_EXIT_EXHAUST and close > open
                ExitTrade := true

        // Long Exit Alert
        if ExitTrade
            strategy.close("Sell")
            if PC_ENABLED
                alert(PC_ID + ",closeshort," + PC_VAR_SYMBOL + PC_VAR_STRATEGY, alert.freq_once_per_bar)

        // Short Trailing Stop Code
        ShortStopLoss = GetStopPrice(false)
        if TrailStopActivated and ShortStopLoss < TradeStopPrice
            TradeStopPrice := ShortStopLoss
            NEW_SL = PC_USE_PIP_TARGET ? math.abs(TradeStopPrice - close) / GetPipSize() : TradeStopPrice
            string alertMessage = PC_ID + ",newsltpshort," + PC_VAR_SYMBOL + ",sl=" + str.tostring(NEW_SL) + PC_VAR_STRATEGY
            if PC_ENABLED
                alert(alertMessage, alert.freq_once_per_bar_close)

            // Debug alert message label
            PC_DEBUG_LABEL_TS := label.new(bar_index, high + (GetPipSize() * 10), alertMessage, color=color.white)
            label.delete(PC_DEBUG_LABEL_TS[1])

// Trigger SL/TP Orders
strategy.exit("Long Exit", "Buy", stop=TradeStopPrice, limit=UseExitReason ? na : TradeProfitPrice)
strategy.exit("Short Exit", "Sell", stop=TradeStopPrice, limit=UseExitReason ? na : TradeProfitPrice)

// Display automation alert string on last valid trade - for debugging purposes
if PC_DEBUG and ((LongTrade and barstate.isconfirmed) or (ShortTrade and barstate.isconfirmed))
    debugString = "Automation is not enabled!"
    if PC_ENABLED
        debugString := GenerateEntryAlertString()
    PC_DEBUG_LABEL := label.new(bar_index, high + (GetPipSize() * 10), debugString, color=color.white)
    label.delete(PC_DEBUG_LABEL[1])

// Draw trade info to chart
plot(strategy.position_size != 0 ? TradeStopPrice : na, "SL", color=color.red, linewidth=1, style=plot.style_linebr)
plot(strategy.position_size != 0 and not SearchingForExit ? TradeProfitPrice : na, "TP", color=color.green, linewidth=1, style=plot.style_linebr)
plot(strategy.position_size != 0 and STRATEGY_BREAK_EVEN != 0 ? TradeBreakEvenPrice : na, "BE", color=color.blue, linewidth=1, style=plot.style_linebr)
plot(strategy.position_size != 0 and not TrailStopActivated ? TrailStopActivatePrice : na, "TS", color=color.orange, linewidth=1, style=plot.style_linebr)