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

//@version=5

// @description Provides functions that wrap the built in TradingView strategy functions so you can seemlessly integrate with Plurex Signal automation.
// NOTE: Be sure to set your strategy close_entries_rule="ANY" and pyramiding=20 or some other amount appropriate to your strategy in order to have multiple entries.
library("PlurexSignal")

SHORT_SL_ID = "s-sl"
LONG_SL_ID = "l-sl"

// @function Build a Plurex market string from a base and quote asset symbol.
// @returns A market string that can be used in Plurex Signal messages.
export plurexMarket(string base, string quote) => base + "-" + quote

// @function Builds Plurex market string from the syminfo
// @returns A market string that can be used in Plurex Signal messages.
export tickerToPlurexMarket() => plurexMarket(syminfo.basecurrency, syminfo.currency)

// @function Builds Plurex Signal Message json to be sent to a Signal webhook
// @param secret The secret for your Signal on plurex
// @param action The action of the message. One of [LONG, SHORT, CLOSE_LONGS, CLOSE_SHORTS, CLOSE_ALL, CLOSE_LAST_LONG, CLOSE_LAST_SHORT, CLOSE_FIRST_LONG, CLOSE_FIRST_SHORT].
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @returns A json string message that can be used in alerts to send messages to Plurex.
export simpleMessage(string secret, string action, string marketOverride = "") =>
    market = marketOverride != "" ? marketOverride : tickerToPlurexMarket()
    "{\"secret\": \""+secret+"\", \"action\": \""+action+"\", \"market\": \""+market+"\"}"

// @function Open a new long entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export long(string secret, string marketOverride = "", series float qty = 1) =>
    longID = str.format("l{0}", time(""))
    strategy.entry(longID, strategy.long, qty=qty, alert_message=simpleMessage(secret=secret, action="LONG", marketOverride=marketOverride))

// @function Open a new long entry. Wraps strategy function and sends plurex message as an alert. Also sets a gobal stop loss for full open position
// @param secret The secret for your Signal on plurex
// @param stop The trigger price for the stop loss. See strategy.exit documentation
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export longAndSetStopLoss(string secret, float stop, string marketOverride = "", series float qty = 1) =>
    longID = str.format("l{0}", time(""))
    strategy.cancel(SHORT_SL_ID)
    strategy.entry(longID, strategy.long, qty=qty, alert_message=simpleMessage(secret=secret, action="LONG", marketOverride=marketOverride))
    strategy.exit(LONG_SL_ID, stop=stop, alert_message = simpleMessage(secret=secret, action="CLOSE_LONGS", marketOverride=marketOverride))

// @function Open a new long entry. Wraps strategy function and sends plurex message as an alert. Also sets a gobal trailing stop loss for full open position. You must set one of trail_price or trail_points.
// @param secret The secret for your Signal on plurex
// @param trail_offset See strategy.exit documentation
// @param trail_price See strategy.exit documentation
// @param trail_points See strategy.exit documentation
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export longAndSetTrailingStopLoss(string secret, float trail_offset, float trail_price = na, float trail_points = na, string marketOverride = "", series float qty = 1) =>
    longID = str.format("l{0}", time(""))
    strategy.cancel(SHORT_SL_ID)
    strategy.entry(longID, strategy.long, qty=qty, alert_message=simpleMessage(secret=secret, action="LONG", marketOverride=marketOverride))
    strategy.exit(LONG_SL_ID,  trail_offset = trail_offset, trail_price = trail_price, trail_points = trail_points, alert_message = simpleMessage(secret=secret, action="CLOSE_LONGS", marketOverride=marketOverride))
    

// @function Open a new short entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export short(string secret, string marketOverride = "", series float qty = 1) =>
    shortID = str.format("s{0}", time(""))
    strategy.entry(shortID, strategy.short, qty=qty, alert_message=simpleMessage(secret=secret, action="SHORT", marketOverride=marketOverride))

// @function Open a new short entry. Wraps strategy function and sends plurex message as an alert. Also sets a gobal stop loss for full open position
// @param secret The secret for your Signal on plurex
// @param stop The trigger price for the stop loss. See strategy.exit documentation
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export shortAndSetStopLoss(string secret, float stop, string marketOverride = "", series float qty = 1) =>
    shortID = str.format("s{0}", time(""))
    strategy.cancel(LONG_SL_ID)
    strategy.entry(shortID, strategy.short, qty=qty, alert_message=simpleMessage(secret=secret, action="SHORT", marketOverride=marketOverride))
    strategy.exit(SHORT_SL_ID, stop=stop, alert_message = simpleMessage(secret=secret, action="CLOSE_SHORTS", marketOverride=marketOverride))

// @function Open a new short entry. Wraps strategy function and sends plurex message as an alert. Also sets a gobal trailing stop loss for full open position. You must set one of trail_price or trail_points.
// @param secret The secret for your Signal on plurex
// @param trail_offset See strategy.exit documentation
// @param trail_price See strategy.exit documentation.
// @param trail_points See strategy.exit documentation
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
// @param qty Corresponds to strategy.entry qty
export shortAndSetTrailingStopLoss(string secret, float trail_offset, float trail_price = na, float trail_points = na, string marketOverride = "", series float qty = 1) =>
    shortID = str.format("s{0}", time(""))
    strategy.cancel(LONG_SL_ID)
    strategy.entry(shortID, strategy.short, qty=qty, alert_message=simpleMessage(secret=secret, action="SHORT", marketOverride=marketOverride))
    strategy.exit(SHORT_SL_ID, trail_offset = trail_offset, trail_price = trail_price, trail_points = trail_points, alert_message = simpleMessage(secret=secret, action="CLOSE_SHORTS", marketOverride=marketOverride))
    
// @function Close all positions. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeAll(string secret, string marketOverride = "") =>
    strategy.close_all(alert_message=simpleMessage(secret=secret, action="CLOSE_ALL", marketOverride=marketOverride))

// @function Close all longs. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeLongs(string secret, string marketOverride = "") =>
    size = strategy.opentrades.size(strategy.opentrades-1)
    if size > 0
        strategy.close_all(alert_message=simpleMessage(secret=secret, action="CLOSE_LONGS", marketOverride=marketOverride))
            
// @function Close all shorts. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeShorts(string secret, string marketOverride = "") =>
    size = strategy.opentrades.size(strategy.opentrades-1)
    if size < 0
        strategy.close_all(alert_message=simpleMessage(secret=secret, action="CLOSE_SHORTS", marketOverride=marketOverride))
    
// @function Close last long entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeLastLong(string secret, string marketOverride = "") =>
    openTrades = strategy.opentrades
    lastID = ""
    for i = 0 to (openTrades - 1)
        tradeID = strategy.opentrades.entry_id(i)
        if str.startswith(tradeID, "l")
            lastID := tradeID
            lastID := tradeID
    if lastID != ""
        strategy.close(lastID, alert_message=simpleMessage(secret=secret, action="CLOSE_LAST_LONG", marketOverride=marketOverride))
    
// @function Close first long entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeFirstLong(string secret, string marketOverride = "") =>
    openTrades = strategy.opentrades
    for i = 0 to (openTrades - 1)
        tradeID = strategy.opentrades.entry_id(i)
        if str.startswith(tradeID, "l")
            strategy.close(tradeID, alert_message=simpleMessage(secret=secret, action="CLOSE_FIRST_LONG", marketOverride=marketOverride))
            break
    
// @function Close last short entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeLastShort(string secret, string marketOverride = "") =>
    openTrades = strategy.opentrades
    lastID = ""
    for i = 0 to (openTrades - 1)
        tradeID = strategy.opentrades.entry_id(i)
        if str.startswith(tradeID, "s")
            lastID := tradeID
    if lastID != ""
        strategy.close(lastID, alert_message=simpleMessage(secret=secret, action="CLOSE_LAST_SHORT", marketOverride=marketOverride))
    
// @function Close first short entry. Wraps strategy function and sends plurex message as an alert.
// @param secret The secret for your Signal on plurex
// @param marketOverride Optional, defaults to the syminfo for the ticker. Use the `plurexMarket` function to build your own.
export closeFirstShort(string secret, string marketOverride = "") =>
    openTrades = strategy.opentrades
    for i = 0 to (openTrades - 1)
        tradeID = strategy.opentrades.entry_id(i)
        if str.startswith(tradeID, "s")
            strategy.close(tradeID, alert_message=simpleMessage(secret=secret, action="CLOSE_FIRST_SHORT", marketOverride=marketOverride))
            break
            
 // The secret unique to your Plurex Signal. needed for each message sent to the webhook
secret = "foo"       
earliestBackTestMillis = 1663545605000  // Change this to suit your chart
if time > earliestBackTestMillis
    indexDecimal = bar_index % 56
    switch indexDecimal
        0 => closeAll(secret)
        2 => long(secret)
        4 => long(secret)
        6 => closeLastLong(secret)
        8 => closeLastLong(secret)
        10 => long(secret)
        12 => long(secret)
        14 => closeFirstLong(secret)
        16 => closeFirstLong(secret)
        18 => short(secret)
        20 => short(secret)
        22 => closeLastShort(secret)
        24 => closeLastShort(secret)
        26 => short(secret)
        28 => short(secret)
        30 => closeFirstShort(secret)
        32 => closeFirstShort(secret)
        34 => long(secret)
        36 => long(secret)
        38 => closeLongs(secret)
        40 => short(secret)
        42 => short(secret)
        44 => closeShorts(secret)
        46 => long(secret)
        48 => long(secret)
        50 => closeAll(secret)
        52 => short(secret)
        54 => short(secret)

plot(strategy.position_size)