Equity Trade Risk Manager
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Amphibiantrading

//@version=5
indicator("Trade Risk Manager", overlay = true)

//----------settings----------//
var g0      = 'Account & Risk Settings'
actSize     = input.int(100000, 'Account Size', inline = '1', group = g0, confirm = true)
portRisk    = input.string('0.25%', 'Equity Risk', ['0.25%', '0.50%', '0.75%'], inline = '1', group = g0, confirm = true)
customRisk  = input.bool(false, 'Custom Equity Risk', inline = '2', group = g0, confirm = true)
crNum       = input.float(0.75, ' ', inline ='2', group = g0, tooltip = 'If using a custom portfolio risk amount, enter here. Must turn on this setting to use', confirm = true)
useMax      = input.bool(false, 'Max Position Size', inline = '3', group = g0, confirm = true)
maxPos      = input.float(10, ' ', inline = '3', group = g0, confirm = true, tooltip = 'If the recommended position size is greater than this % of the total portfolio when calculating the number of shares to buy, selecting this setting will cap the position size at fixed amount.' )
what        = input.string('Shares to Buy', 'Calculate', ['Shares to Buy', 'Stop Loss'], group = g0, confirm = true)
fract       = input.bool(false, 'Use Fractional Shares', group = g0)

var g1      = 'Price Levels'
entryPrice  = input.float(0.0, 'Entry Price', inline = '1', group = g1, confirm = true)
currPrice   = input.bool(false, 'or Use Current Price', inline = '1', group = g1, confirm = true)
stopPrice   = input.float(0.0, 'Stop Price', inline = '2', group = g1, confirm = true)
useM        = input.bool(false, 'or Use Major Level', inline = '2', group = g1, confirm = true)
autoStop    = input.string('Low of Day', 'Major Levels', ['Low of Day', 'Swing Low', '% ATR from LOD', 'High of Day', 'Swing High', '% ATR from HOD'], inline = '3', group = g1, confirm = true)
owned       = input.int(0, 'Shares Owned', group = g1, confirm = true)

var g2      = 'Major Levels'
swingLB     = input.int(2, 'Pivot Lenth', group = g2, confirm = true)
atrLen      = input.int(14, 'ATR Length', inline = '1', group = g2, confirm = true)
atrPer      = input.float(1, 'Multiplier', inline = '1', group = g2, confirm = true)

var g3      = 'Display Settings'
showStop    = input.bool(true, 'Show Stop Loss on Chart', group = g3)
yPos        = input.string('Top', 'Table Position ', options = ['Top', 'Middle', 'Bottom'], inline = '1',  group= g3)
xPos        = input.string('Right', ' ', options = ['Right','Center', 'Left'], inline = '1',  group = g3)
txtSize     = input.string('Normal', 'Text Size', options = ['Small','Normal','Large','Huge'], inline = '2', group = g3)
txtCol      = input.color(color.black, 'Text Color', inline = '2', group = g3)
bgCol       = input.color(color.white, 'Table Background Color', group = g3)


//----------udt----------//
type pivot
    float p
    int b 

//----------switch----------//
numSwitch = switch portRisk
    '0.25%' => .0025
    '0.50%' => .0050
    '0.75%' => .0075

txtSizer = switch txtSize
    'Small'  => size.small
    'Normal' => size.normal
    'Large'  => size.large
    'Huge'   => size.huge

//----------variables----------//
var table data = table.new(str.lower(yPos) + '_' + str.lower(xPos), 1,4, bgcolor = color.new(color.white,100))
line stopLine = na
label stopLabel = na
var swingLow = pivot.new(na,na)
var swingHigh = pivot.new(na,na)


//----------calculations----------//
pl = ta.pivotlow(swingLB,swingLB)
ph = ta.pivothigh(swingLB,swingLB)
atr = ta.atr(atrLen)

if pl
    swingLow.p := low[swingLB]
    swingLow.b := bar_index[swingLB]
if ph
    swingHigh.p := high[swingLB]
    swingHigh.b := bar_index[swingLB]

lod         = request.security(syminfo.ticker, 'D', low)
hod         = request.security(syminfo.ticker, 'D', high)
totalRisk   = customRisk ? actSize * (crNum/100) : actSize * numSwitch 
pivot       = currPrice ? close : entryPrice
stop        = useM ? autoStop == 'Low of Day' ? lod : autoStop == 'Swing Low' ? swingLow.p : autoStop == '% ATR from LOD' ? lod - (atr*atrPer) : 
                 autoStop == 'High of Day' ? hod : autoStop == 'Swing High' ? swingHigh.p : hod + (atr*atrPer) : stopPrice
shares      = fract ? math.round(totalRisk / (pivot - stop),2) : math.ceil(totalRisk / (pivot - stop))
sl          = pivot - totalRisk / owned
posSize     = what == 'Shares to Buy' ? shares * pivot : owned * pivot

if posSize > (actSize * (maxPos/100)) and useMax and what == 'Shares to Buy'
    shares      := fract ? math.round((actSize * (maxPos/100)) / pivot,2) : math.ceil((actSize * (maxPos/100)) / pivot)
    posSize     := what == 'Shares to Buy' ? shares * pivot : owned * pivot
    totalRisk   := (pivot - stop) * shares
else if posSize < 0 and posSize < (actSize * (maxPos/100) * -1) and useMax and what == 'Shares to Buy'
    shares      := fract ? math.round((actSize * (maxPos/100)) / pivot * -1,2) : math.ceil((actSize * (maxPos/100)) / pivot * -1)
    posSize     := what == 'Shares to Buy' ? shares * pivot : owned * pivot
    totalRisk   := (pivot - stop) * shares


//----------data table----------//
if barstate.islast
    data.cell(0,0, ' ')
    data.cell(0,1, 'Dollar Risk: ' + str.tostring(totalRisk, '$#,###.##'), text_halign = text.align_left, bgcolor = bgCol, text_color = txtCol, text_size = txtSizer)
    data.cell(0,2, 'Position Size: ' + str.tostring(posSize, '$#,###.##'), text_halign = text.align_left, bgcolor = bgCol, text_color = txtCol, text_size = txtSizer)
    if what == 'Shares to Buy'
        data.cell(0,3, 'Shares to buy: ' + str.tostring(shares), text_halign = text.align_left, bgcolor = bgCol, text_color = txtCol, text_size = txtSizer)
    else 
        data.cell(0,3, 'Stop Loss: $' + str.tostring(sl, format.mintick), text_halign = text.align_left, bgcolor = bgCol, text_color = txtCol, text_size = txtSizer)
    if what == 'Stop Loss' and showStop
        (stopLine[1]).delete(), (stopLabel[1]).delete()
        stopLabel := label.new(bar_index+6, sl, 'Stop: $' + str.tostring(sl, format.mintick), color = color.new(color.white,100), style = label.style_none, textcolor = txtCol)
        stopLine := line.new(bar_index, sl, bar_index+1, sl, extend = extend.right, color = color.red)
    else if what == 'Shares to Buy' and showStop
        (stopLine[1]).delete(), (stopLabel[1]).delete()
        stopLabel := label.new(bar_index+6, stop, 'Stop: $' + str.tostring(stop, format.mintick), color = color.new(color.white,100), style = label.style_none, textcolor = txtCol)
        stopLine := line.new(autoStop == 'Swing Low' ? swingLow.b : autoStop == 'Swing High' ? swingHigh.b : bar_index, stop , bar_index+1, stop, extend = extend.right, color = color.red)


