Position calculator [krazke]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © krazke

//@version=5
indicator("Position calculator", overlay = true)

// MARK: - Constants

LIQUIDATION_PERCENT = 100.0
LIQUIDATION_SL_PRICE_GAP = 3.0 // In percent
DIRECTION_G_TITLE = "Direction"
POSITION_G_TITLE = "Position"

// MARK: - Types

type LeaverageResult
    int leaverage
    float liquidation_price

// MARK: - Functions

f_liquidation_price(src, is_long, percent) =>
    p = is_long ? -percent : percent
    liquidation_price = src * (1.0 + p / 100.0)

f_normalized_float(value) =>
    int precision = str.length(str.tostring(syminfo.mintick))-2
    pow = math.pow(10, precision)
    int(value * pow) / pow

f_find_nearest_liquidation(stop_loss, max_leverage, is_long, src) =>
    float nearest_liquidation_price = na
    float nearest_diff = na
    int leaverage = na
    
    for i = 1 to max_leverage
        liquidation_percent = LIQUIDATION_PERCENT / i
        liquidation_price = f_liquidation_price(src, is_long, liquidation_percent)

        // Calculate the absolute difference between the stop loss and liquidation price
        diff = math.abs(stop_loss - liquidation_price)

        // Update nearest liquidation price if it's closer
        if (na(nearest_liquidation_price) or diff < nearest_diff)
            nearest_liquidation_price := liquidation_price
            nearest_diff := diff
            leaverage := i

    LeaverageResult.new(leaverage, nearest_liquidation_price)

// MARK: - Inputs

is_long = input(true, title = "LONG", group = DIRECTION_G_TITLE)
is_fixed_entry = input(true, title = "FIXED ENTRY", inline = "0", group = POSITION_G_TITLE)
fixed_entry = input.float(1630.0, title = "", minval = 0.00000000001, step = 1.0, inline = "0", group = POSITION_G_TITLE)
stop_loss = input.float(1600.0, title = "Stop loss", minval = 0.000000001, step = 1.0, group = POSITION_G_TITLE)
potential_loss = input.float(50.0, title = "Potential loss (USD)", minval = 1.0, step = 1.0, group = POSITION_G_TITLE)
max_leaverage = input.int(50, title = "Max leaverage", minval = 0, step = 1, group = POSITION_G_TITLE)

// MARK: - Global Properties

var table dealTable = table.new(position.bottom_right, 2, 8, bgcolor = color.gray, frame_width = 2, frame_color = color.black, border_width = 1, border_color = color.black)
var int leaverage = 1
var float liquidation_price = 0.0
var float sl_lq_diff = 9999999999999.0
var float margin = 100.0

// MARK: - Local Properties

src = is_fixed_entry ? fixed_entry : close

// MARK: - Calculate Leaverage

for i = 1 to max_leaverage
    liquidation_percent = LIQUIDATION_PERCENT / i
    _liquidation_price = f_liquidation_price(src, is_long, liquidation_percent)

    if is_long
        // diff = _liquidation_price - stop_loss
        // if diff < 0 and diff < sl_lq_diff and _liquidation_price > 0
        //     leaverage := i
        //     sl_lq_diff := diff
        //     liquidation_price := _liquidation_price
        diff = (100.0 - (_liquidation_price * 100.0) / stop_loss)
        if diff > 0 and diff <= LIQUIDATION_SL_PRICE_GAP
            leaverage := i
            break
    else 
        diff = ((_liquidation_price * 100.0) / stop_loss - 100.0)
        if diff > 0 and diff <= LIQUIDATION_SL_PRICE_GAP
            leaverage := i
            break
// leaverage_result = f_find_nearest_liquidation(stop_loss, max_leaverage, is_long, src)
// leaverage := leaverage_result.leaverage
// liquidation_price := leaverage_result.liquidation_price
    
// MARK: - Calculate Margin Size

e_sl_diff_percent = math.abs(math.abs((stop_loss * 100) / src) - 100.0)
stop_loss_roe = e_sl_diff_percent * leaverage
margin := (potential_loss * 100) / stop_loss_roe

// MARK: - Calculate Liquidation Price

liquidation_percent = LIQUIDATION_PERCENT / leaverage
liquidation_price := is_long ? src * (1.0 - liquidation_percent / 100.0) : src * (1.0 + liquidation_percent / 100.0)

// MARK: - Plots

red_color = color.red
green_color = color.green
clear_color = color.new(red_color, 100)
target_index = bar_index + 10

entry_line = line.new(bar_index, src, target_index, src, extend=extend.left, color=green_color)
entry_label = label.new(target_index, src, 'ENTRY: ' + str.tostring(f_normalized_float(src)), textcolor=green_color, color=clear_color, style=label.style_label_left)
stop_loss_line = line.new(bar_index, stop_loss, target_index, stop_loss, extend=extend.left, color=red_color)
stop_loss_label = label.new(target_index, stop_loss, 'STOP: ' + str.tostring(f_normalized_float(stop_loss)), textcolor=red_color, color=clear_color, style=label.style_label_left)
liquidation_loss_line = line.new(bar_index, liquidation_price, target_index, liquidation_price, extend=extend.left, color=red_color, width = 3)
liquidation_loss_label = label.new(target_index, liquidation_price, 'LIQUIDATION: ~' + str.tostring(f_normalized_float(liquidation_price)), textcolor=red_color, color=clear_color, style=label.style_label_left)

line.delete (entry_line[1])
label.delete(entry_label[1])
line.delete (stop_loss_line[1])
label.delete(stop_loss_label[1])
line.delete (liquidation_loss_line[1])
label.delete(liquidation_loss_label[1])

// MARK: - Table Setup

if barstate.isfirst
    table.cell(dealTable, 0, 0, "D", tooltip = "Position direction")
    table.cell(dealTable, 0, 1, "E", tooltip = "Entry price")
    table.cell(dealTable, 0, 2, "M", tooltip = "Margin size (USD)")
    table.cell(dealTable, 0, 3, "P", tooltip = "Position size with included leaverage (USD)")
    table.cell(dealTable, 0, 4, "L", tooltip = "Leaverage size")
    table.cell(dealTable, 0, 5, "SL", tooltip = "Stop loss price (USD)")
    table.cell(dealTable, 0, 6, "LP", tooltip = "Liquidation price (USD)")
    table.cell(dealTable, 0, 7, "PL", tooltip = "Potential loss size (USD)")

if barstate.islast
    position_direction_str = is_long ? "LONG" : "SHORT"
    entry_price_str = str.tostring(f_normalized_float(src)) + "$"
    margin_str = str.tostring(f_normalized_float(margin)) + "$"
    position_size_str = str.tostring(f_normalized_float(margin * leaverage)) + "$"
    leaverage_str = str.tostring(f_normalized_float(leaverage))
    stop_loss_str = str.tostring(f_normalized_float(stop_loss)) + "$"
    liquidation_price_str = str.tostring(f_normalized_float(liquidation_price)) + "$"
    potential_loss_str = str.tostring(f_normalized_float(potential_loss)) + "$"
    table.cell(dealTable, 1, 0, position_direction_str)
    table.cell(dealTable, 1, 1, entry_price_str)
    table.cell(dealTable, 1, 2, margin_str)
    table.cell(dealTable, 1, 3, position_size_str)
    table.cell(dealTable, 1, 4, leaverage_str)
    table.cell(dealTable, 1, 5, stop_loss_str)
    table.cell(dealTable, 1, 6, liquidation_price_str)
    table.cell(dealTable, 1, 7, potential_loss_str)
