Channel Take Profit Tool for Alertatron
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jordanfray

//@version=5
indicator("Channel Take Profit", overlay=true)
import jordanfray/threengine_global_automation_library/95 as bot

// Colors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
green                           = color.new(#2DBD85,0)
lightGreen                      = color.new(#2DBD85,90)
red                             = color.new(#E02A4A,0)
blue                            = color.new(#00A5FF,0)
lightBlue                       = color.new(#00A5FF,90)
white                           = color.new(#ffffff,0)
gray                            = color.new(#AAAAAA,0)
transparent                     = color.new(#ffffff,100)


//  Tooltips
offsetTip                       = "How far away from the line do you want to trigger Alertatron to close the trade? \n\n Default: 1%"
amountToCloseTip                = "What percentage of the open postiion do you want to close? \n\n Default: 50%"
alertatronSecretTip             = "The key that is configured in Alertatron that selects which exchange integration you want to use."
exchangeTooltip                 = "Pick the exchange that your Alertatron API Secret is configured to. This is used to get the right divider between the pair and the base currency."
exchangeCurrencyOverrideTip     = "If you want to use a different base currency than the current chart, you can override it here. Be sure it matches the exchange base currency. \n \n Do not include the currency/symbol divider in this."
exchangeCurrencySymbolTip       = "If you want to use a different symbol than the current chart, you can override it here. Be sure it matches the exchange symbol. \n \n Do not include the currency/symbol divider in this."


//  Inputs
mainLineX1                      = input.time(defval=timestamp("01 Jan 2022 00:00"), title="x1", group="Channel Coordinates", confirm=true, inline="point1")
mainLineY1                      = input.price(defval=0.0, title="y1", group="Channel Coordinates", confirm=true, inline="point1")
mainLineX2                      = input.time(defval=timestamp("01 Jan 2022 00:00"), title="x2", confirm=true, group="Channel Coordinates", inline="point2")
mainLineY2                      = input.price(defval=0.0, title="y2", group="Channel Coordinates", confirm=true, inline="point2")
lineOffset                      = input.float(defval=1.0, title="Offset (%)", group="Channel Coordinates", tooltip=offsetTip)

amoutToClose                    = input.int(defval=50, title="Amount to Close (%)", step=5, group="Exit Settings", tooltip=amountToCloseTip)


tradeAutomationExchange         = input.string(defval="ByBit", options=["ByBit", "FTX.us"], title="Exchange", group="Alertatron Settings", tooltip=exchangeTooltip)
tradeAutomationSecret           = input.string(defval="", title="Alertatron API Secret", group="Alertatron Settings", tooltip=alertatronSecretTip)
tradeAutomationCurrencyOverride = input.string(defval="", title="Currency Override", group="Alertatron Settings", tooltip=exchangeCurrencyOverrideTip)
tradeAutomationSymbolOverride   = input.string(defval="", title="Symbol Override", group="Alertatron Settings", tooltip=exchangeCurrencySymbolTip)

showDebugTable                  = input.bool(defval=false, title="Show Debug Table", group="Testing")


//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  S T R A T E G Y  C A L C U L A T I O N S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

//  Calulate y-axis locations for top and bottom lines
var float topLineY1             = (mainLineY1 + (mainLineY1*(lineOffset/100)))
var float topLinwY2             = (mainLineY2 + (mainLineY2*(lineOffset/100)))
var float bottomLineY1          = (mainLineY1 - (mainLineY1*(lineOffset/100)))
var float bottomLineY2          = (mainLineY2 - (mainLineY2*(lineOffset/100)))

//  Calculate the change between point 1 and 2
chartTimeframeInMinutes         = timeframe.in_seconds(timeframe.period)/60
yDelta                          = mainLineY2 - mainLineY1 // price
xDelta                          = ((mainLineX2 - mainLineX1)/60000)/chartTimeframeInMinutes // bars
changePerBar                    = yDelta/xDelta // price change per bar (aka slope)

//  Set initial values of 
var float maingLineLoc          = mainLineY1
var float bottomLineLoc         = (mainLineY1 - (mainLineY1*(lineOffset/100)))
var float topLineLoc            = (mainLineY1 + (mainLineY1*(lineOffset/100)))

//  Subtract the slope from each line's y-axis location each bar beyond the point 1
if time > mainLineX1
    maingLineLoc                += changePerBar
    bottomLineLoc               += changePerBar
    topLineLoc                  += changePerBar


//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  P L O T S  A N D  L I N E S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

//  Plot all three lines but only show the main line
lowerThreshold                  = plot(bottomLineLoc, title="Lower Threshold", editable=false, display=display.status_line + display.price_scale)
mainLine                        = plot(maingLineLoc, title="Main Line", color=ta.change(maingLineLoc) ? blue : transparent, linewidth=2, editable=false, display=display.status_line + display.pane + display.price_scale)
upperThreshold                  = plot(topLineLoc, title="Upper Threshold", editable=false, display=display.status_line + display.price_scale)

//  Plot the upper and lower line so they extend beyond the current bar
if barstate.islastconfirmedhistory
    topLine                     = line.new(x1=mainLineX1, y1=topLineY1, x2=mainLineX2, y2=topLinwY2, color=blue, width=1, xloc=xloc.bar_time, style=line.style_solid, extend=extend.right)
    bottomLine                  = line.new(x1=mainLineX1, y1=bottomLineY1, x2=mainLineX2, y2=bottomLineY2, color=blue, width=1, xloc=xloc.bar_time, style=line.style_solid, extend=extend.right)
    channelBackground           = linefill.new(topLine, bottomLine, lightBlue)
 
 
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  C L O S E  T H E  T R A D E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

//  Exit Criteria
closeLong                       = ta.crossover(high, bottomLineLoc)
closeShort                      = ta.crossunder(low, topLineLoc)

// Check to see if currency or symbol should be overridden 
string baseCurrency             = na
string symbol                   = na

if tradeAutomationCurrencyOverride != ""
    baseCurrency := tradeAutomationCurrencyOverride
else
    baseCurrency := bot.getBaseCurrency()
if tradeAutomationSymbolOverride != ""
    symbol := tradeAutomationSymbolOverride
else
    symbol := bot.getChartSymbol()

//  Get alert message
var string exitLongAlertMessage = bot.getAlertatronAlertMessageMarketClosePercentOfPosition(secret=tradeAutomationSecret, symbol=symbol, baseCurrency=baseCurrency, pairDivider=bot.getPairDividerForExchange(tradeAutomationExchange), percent=amoutToClose, side="sell")
var string exitShortAlertMessage = bot.getAlertatronAlertMessageMarketClosePercentOfPosition(secret=tradeAutomationSecret, symbol=symbol, baseCurrency=baseCurrency, pairDivider=bot.getPairDividerForExchange(tradeAutomationExchange), percent=amoutToClose, side="buy")

//  Close the trade
var int alertTriggered = 0

if closeLong and time > mainLineX2
    if alertTriggered == 0 
        alert(message=exitLongAlertMessage, freq=alert.freq_once_per_bar)
    alertTriggered += 1
    
if closeShort and time > mainLineX2
    if alertTriggered == 0
        alert(message=exitShortAlertMessage, freq=alert.freq_once_per_bar)
    alertTriggered += 1

//  Display shapes when when exit criteria is met
plotshape(time > mainLineX2 and alertTriggered <=1 ? closeLong : na, title="Above Bottom Line", style=shape.triangleup, location=location.abovebar, color=green, display=display.pane)
plotshape(time > mainLineX2 and alertTriggered <=1 ? closeShort : na, title="Below Top Line", style=shape.triangledown, location=location.belowbar, color=red, display=display.pane)


//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  D E B U G   M O D E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

if showDebugTable
    var table debug = table.new(position=position.bottom_left, columns=2, rows=100, bgcolor=gray, border_color=gray, border_width=2)
    
    rowCount = 0
    table.cell(debug, 0, rowCount, text="exitLongAlertMessage: ", text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)
    table.cell(debug, 1, rowCount, text=str.tostring(exitLongAlertMessage), text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)
    
    rowCount += 1
    table.cell(debug, 0, rowCount, text="exitShortAlertMessage: ", text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)
    table.cell(debug, 1, rowCount, text=str.tostring(exitShortAlertMessage), text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)
    
    rowCount += 1
    table.cell(debug, 0, rowCount, text="alertTriggered: ", text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)
    table.cell(debug, 1, rowCount, text=str.tostring(alertTriggered), text_color=white, text_halign=text.align_left,  bgcolor=gray, text_size=size.small)