Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
28 kB
4
Indexable
Never
//@version=5
strategy("CBA Grid Backtester", overlay=true, max_lines_count=500, initial_capital=1000)

int version = 1

// Input parameters
upper_limit = input.price(title="Upper Limit", defval=100.0)
lower_limit = input.price(title="Lower Limit", defval=60.0)
num_grids = input.int(title="Number of Grids", defval=20, minval=5, maxval=100)
START_DATE = input.time(timestamp("2019-01-01"), title="Start Date", group="Date Range", tooltip="Configure this date to the present day when enabling automation to receive the most recent alerts.")

ENABLE_TAKE_PROFIT = input.bool(false, "Take Profit", tooltip = "Configure Take profit option to close the bot when the price moves in the market direction and reaches the specified price. If the price is reached, the bot sells all the Quote currency used and stops further operations.")
TAKE_PROFIT_PRICE = input.price(1000, "  Take Profit Price")

ENABLE_TAKE_PROFIT_PERC = input.bool(false, "Take Profit Percentage", tooltip = "Configure Take profit option to close the bot when the price moves in the market direction and reaches the specified profit percentage. If the price is reached, the bot sells all the Quote currency used and stops further operations.")
TAKE_PROFIT_PERC = input.float(5, title="  Take Profit Percentage")

ENABLE_STOP_LOSS = input.bool(false, "Stop Loss", tooltip = "Configure Stop Loss options to close the bot when the price moves against the chosen direction. If the price reaches a specified Stop Loss level, the bot sells all the Quote currency used and stops further operations.")
STOP_LOSS_PRICE = input.price(500, "  Stop Loss Price")

ENABLE_STOP_LOSS_PERC = input.bool(false, "Stop Loss Percentage", tooltip = "Configure Stop Loss options to close the bot when the price moves against the chosen direction. If the price reaches a specified Stop Loss level, the bot sells all the Quote currency used and stops further operations.")
STOP_LOSS_PERC = input.float(5, title="  Stop Loss Percentage")

ENABLE_TRAINLING_UP = input.bool(false, "Trailing Up", tooltip = "If enabled, the bot will move the Take Profit price up as the price increases. This option only works when the Take Profit option is enabled.")
ENABLE_TRAINLING_DOWN = input.bool(false, "Trailing Down", tooltip = "If enabled, the bot will move the Stop Loss price down as the price decreases. This option only works when the Stop Loss option is enabled.")

// Exchange fee (adjust as needed)
exchange_fee_pct = 0.001  // Assuming 0.1% fee

f_calculate_grid_step_perc(upper_limit, lower_limit, num_grids) =>
    base_step = math.pow(upper_limit / lower_limit, 1 / num_grids) - 1
    adjusted_step = base_step * (1 - 2 * exchange_fee_pct)  // Adjusting by 2 * exchange_fee_pct
    adjusted_step * 100  // Convert to percentage

// Calculate grid levels and sizes
grid_step_perc = f_calculate_grid_step_perc(upper_limit, lower_limit, num_grids)
var float grid_investment = na // will calculate later strategy.initial_capital / num_grids

// Define a custom type for grid levels
type GridLevel
    float price
    line level_line
    string static_order_id
    string dynamic_order_id

// Define a custom type for grid state
type GridState
    float no_fee_zone_upper_level
    float no_fee_zone_lower_level
    int dynamic_order_counter
    float upper_limit
    float lower_limit

// Initialize the GridState
var GridState grid_state = GridState.new(na, na, 0, upper_limit, lower_limit)

// Initialize variables
var GridLevel[] buy_levels = array.new<GridLevel>()
var GridLevel[] sell_levels = array.new<GridLevel>()
var bool is_initialized = false
var bool initial_buy_executed = false
var bool bot_ended = false
var int end_time = na

// Function to generate lines for take profit and stop loss
f_generate_tp_sl_lines() =>
    if ENABLE_TAKE_PROFIT
        tp_line = line.new(bar_index, TAKE_PROFIT_PRICE, bar_index + 1, TAKE_PROFIT_PRICE, 
             extend=extend.both, color=color.green, width = 2)
    
    if ENABLE_STOP_LOSS
        sl_line = line.new(bar_index, STOP_LOSS_PRICE, bar_index + 1, STOP_LOSS_PRICE, 
             extend=extend.both, color=color.red, width = 2)

f_calculate_grid_levels() =>
    if grid_step_perc <= 0.1
        runtime.error("Unable to setup grid: Use less grid lines or increase the grid span.")
    current_price = close
    no_fee_zone_lower = current_price * (1 - exchange_fee_pct)
    no_fee_zone_upper = current_price * (1 + exchange_fee_pct + grid_step_perc / 100)
    
    //label.new(bar_index, high, "grid_step_perc: " + str.tostring(grid_step_perc, "#.##") + "%")
    
    local_buy_levels = array.new<GridLevel>()
    local_sell_levels = array.new<GridLevel>()
    
    current_level = lower_limit
    lower_grid_placed = false
    for i = 0 to num_grids - 1
        if current_level > no_fee_zone_lower and current_level < no_fee_zone_upper and lower_grid_placed
            current_level := current_level * (1 + grid_step_perc / 100)
            continue
        
        level_line = line.new(bar_index, current_level, bar_index+1, current_level, extend=extend.both, color=current_level < close ? color.green : color.red)
        new_level = GridLevel.new(current_level, level_line)
        
        if close <= current_level
            local_sell_levels.push(new_level)
        else
            local_buy_levels.unshift(new_level)

        if current_level <= current_price
            lower_grid_placed := true
        
        current_level := math.min(upper_limit, current_level * (1 + grid_step_perc / 100))
    
    total_levels = local_buy_levels.size() + local_sell_levels.size()
    my_grid_investment = strategy.initial_capital / total_levels

    // here set up the order
    int j = 0
    while j < local_buy_levels.size()
        level = local_buy_levels.get(j)
        level.static_order_id := "Initial Grid Buy " + str.tostring(j)
        strategy.order(level.static_order_id, strategy.long, qty=my_grid_investment / level.price, limit=level.price)
        j += 1

    j := 0
    while j < local_sell_levels.size()
        level = local_sell_levels.get(j)
        level.static_order_id := "Initial Grid Sell " + str.tostring(j)
        strategy.order(level.static_order_id, strategy.short, qty=my_grid_investment / level.price, limit=level.price)
        j += 1
    if local_buy_levels.size() == 0 and local_sell_levels.size() == 0
        runtime.error("Unable to setup grid: Use less grid lines or increase the grid span.")

    local_no_fee_zone_lower_level = local_buy_levels.size() > 0 ? local_buy_levels.get(0).price : na
    local_no_fee_zone_upper_level = local_sell_levels.size() > 0 ? local_sell_levels.get(0).price : na
    [local_buy_levels, local_sell_levels, local_no_fee_zone_lower_level, local_no_fee_zone_upper_level, my_grid_investment]


if time >= START_DATE and not is_initialized
    [new_buy_levels, new_sell_levels, new_no_fee_zone_lower, new_no_fee_zone_upper, my_grid_investment] = f_calculate_grid_levels()
    buy_levels := new_buy_levels
    sell_levels := new_sell_levels
    grid_state.no_fee_zone_lower_level := new_no_fee_zone_lower
    grid_state.no_fee_zone_upper_level := new_no_fee_zone_upper
    grid_investment := my_grid_investment
    f_generate_tp_sl_lines()
    is_initialized := true

// Initial buy order
if is_initialized and not initial_buy_executed and not na(grid_state.no_fee_zone_lower_level) and not na(grid_state.no_fee_zone_upper_level)
    sell_levels_count = sell_levels.size()
    initial_buy_amount = grid_investment * sell_levels_count
    entry_amount = initial_buy_amount / close
    strategy.entry("Initial Buy", strategy.long, qty=entry_amount)
    initial_buy_executed := true

f_is_outside_no_fee_zone(price1, price2, current_price) =>
    no_fee_zone_lower = current_price * (1 - exchange_fee_pct)
    no_fee_zone_upper = current_price * (1 + exchange_fee_pct + grid_step_perc / 100)
    price_diff = math.abs(price1 - price2)
    no_fee_zone_size = no_fee_zone_upper - no_fee_zone_lower
    price_diff >= no_fee_zone_size

f_remove_grid_level(GridLevel level) =>
    level.level_line.delete()
    if not na(level.static_order_id)
        strategy.cancel(level.static_order_id)
    if not na(level.dynamic_order_id)
        strategy.cancel(level.dynamic_order_id)

// Dynamic orders (moving with exchange fee zone)
f_update_dynamic_orders_high(GridState state) =>
    bool changed = false
    if high >= state.no_fee_zone_upper_level and sell_levels.size() > 0
        changed := true
        current_price = state.no_fee_zone_upper_level
        f_remove_grid_level(sell_levels.get(0))
        sell_levels.remove(0)
        
        if sell_levels.size() > 0
            state.no_fee_zone_upper_level := sell_levels.get(0).price
        else
            state.no_fee_zone_upper_level := na

        state.no_fee_zone_lower_level := state.no_fee_zone_lower_level * (1 + grid_step_perc / 100)        
        if f_is_outside_no_fee_zone(na(state.no_fee_zone_upper_level) ? state.upper_limit : state.no_fee_zone_upper_level, na(state.no_fee_zone_lower_level) ? state.lower_limit : state.no_fee_zone_lower_level, current_price)
            state.no_fee_zone_lower_level := na(state.no_fee_zone_lower_level) ? state.lower_limit : state.no_fee_zone_lower_level
            GridLevel new_buy_level = GridLevel.new(state.no_fee_zone_lower_level, line.new(bar_index, state.no_fee_zone_lower_level, bar_index+1, state.no_fee_zone_lower_level, extend=extend.both, color=color.green))
            new_buy_level.dynamic_order_id := "Dynamic Buy " + str.tostring(state.dynamic_order_counter)
            buy_levels.unshift(new_buy_level)
            strategy.order(new_buy_level.dynamic_order_id, strategy.long, qty=grid_investment / state.no_fee_zone_lower_level, limit=state.no_fee_zone_lower_level)
            //label.new(bar_index, high, "Dynamic Buy " + str.tostring(state.dynamic_order_counter) + " @ " + str.tostring(state.no_fee_zone_lower_level) + "\n\n\n\n")
            state.dynamic_order_counter += 1
        else if na(state.no_fee_zone_upper_level)
            if buy_levels.get(0).price < state.upper_limit
                next_buy_level = buy_levels.get(0).price * (1 + grid_step_perc / 100)
                new_buy_level = GridLevel.new(next_buy_level, line.new(bar_index, next_buy_level, bar_index+1, next_buy_level, extend=extend.both, color=color.green))
                new_buy_level.dynamic_order_id := "Dynamic Buy " + str.tostring(state.dynamic_order_counter)
                buy_levels.unshift(new_buy_level)
                strategy.order(new_buy_level.dynamic_order_id, strategy.long, qty=grid_investment / next_buy_level, limit=next_buy_level)
                state.dynamic_order_counter += 1
        // else
        //     no_fee_zone_lower = current_price * (1 - exchange_fee_pct)
        //     no_fee_zone_upper = current_price * (1 + exchange_fee_pct + grid_step_perc / 100)
        //     no_fee_zone_size = no_fee_zone_upper - no_fee_zone_lower
        //     up_prc = na(state.no_fee_zone_upper_level) ? upper_limit : state.no_fee_zone_upper_level
        //     dn_prc = na(state.no_fee_zone_lower_level) ? state.lower_limit : state.no_fee_zone_lower_level
        //     label.new(bar_index, high, "price_diff: " + str.tostring(up_prc - dn_prc) +
        //      "\n no_fee_zone_size: " + str.tostring(no_fee_zone_size) + "\n\n\n\n")

    changed

// Function to handle low price updates
f_update_dynamic_orders_low(GridState state) =>
    bool changed = false
    if low <= state.no_fee_zone_lower_level and buy_levels.size() > 0
        changed := true
        current_price = state.no_fee_zone_lower_level
        f_remove_grid_level(buy_levels.get(0))
        buy_levels.remove(0)

        if buy_levels.size() > 0
            state.no_fee_zone_lower_level := buy_levels.get(0).price
        else
            state.no_fee_zone_lower_level := na
        
        state.no_fee_zone_upper_level := state.no_fee_zone_upper_level * (1 - grid_step_perc / 100)
        if f_is_outside_no_fee_zone(na(state.no_fee_zone_upper_level) ? state.upper_limit : state.no_fee_zone_upper_level, na(state.no_fee_zone_lower_level) ? state.lower_limit : state.no_fee_zone_lower_level, current_price)
            state.no_fee_zone_upper_level := na(state.no_fee_zone_upper_level) ? state.upper_limit : state.no_fee_zone_upper_level
            GridLevel new_sell_level = GridLevel.new(state.no_fee_zone_upper_level, line.new(bar_index, state.no_fee_zone_upper_level, bar_index+1, state.no_fee_zone_upper_level, extend=extend.both, color=color.red))
            new_sell_level.dynamic_order_id := "Dynamic Sell " + str.tostring(state.dynamic_order_counter)
            sell_levels.unshift(new_sell_level)
            strategy.order(new_sell_level.dynamic_order_id, strategy.short, qty=grid_investment/state.no_fee_zone_upper_level, limit=state.no_fee_zone_upper_level)
            state.dynamic_order_counter += 1
            //label.new(bar_index, high, "outside range")

        else if na(state.no_fee_zone_lower_level)
            if sell_levels.get(0).price > state.lower_limit
                next_sell_level = sell_levels.get(0).price * (1 - grid_step_perc / 100)
                new_sell_level = GridLevel.new(next_sell_level, line.new(bar_index, next_sell_level, bar_index+1, next_sell_level, extend=extend.both, color=color.red))
                new_sell_level.dynamic_order_id := "Dynamic Sell " + str.tostring(state.dynamic_order_counter)
                sell_levels.unshift(new_sell_level)
                strategy.order(new_sell_level.dynamic_order_id, strategy.short, qty=grid_investment / next_sell_level, limit=next_sell_level)
                state.dynamic_order_counter += 1
                //label.new(bar_index, high, "fill up")
        // else
        //     no_fee_zone_lower = current_price * (1 - exchange_fee_pct)
        //     no_fee_zone_upper = current_price * (1 + exchange_fee_pct + grid_step_perc / 100)
        //     no_fee_zone_size = no_fee_zone_upper - no_fee_zone_lower
        //     up_prc = na(state.no_fee_zone_upper_level) ? upper_limit : state.no_fee_zone_upper_level
        //     dn_prc = na(state.no_fee_zone_lower_level) ? lower_limit : state.no_fee_zone_lower_level
        //     label.new(bar_index, high, "price_diff: " + str.tostring(up_prc - dn_prc) +
        //      "\n no_fee_zone_size: " + str.tostring(no_fee_zone_size) + "\n\n\n\n")
    
    changed

f_trailing_up(GridState state) =>
    if ENABLE_TRAINLING_UP and sell_levels.size() <= 1 and buy_levels.size() > 0
        float next_sell_level = na
        if sell_levels.size() > 0
            next_sell_level := sell_levels.get(0).price * (1 + grid_step_perc / 100)
        else
            next_sell_level := buy_levels.get(0).price * (1 + 2 * exchange_fee_pct + 2 * grid_step_perc / 100)
        new_sell_level = GridLevel.new(next_sell_level, line.new(bar_index, next_sell_level, bar_index+1, next_sell_level, extend=extend.both, color=color.red))
        new_sell_level.dynamic_order_id := "Dynamic Sell " + str.tostring(state.dynamic_order_counter)
        sell_levels.push(new_sell_level)
        strategy.order(new_sell_level.dynamic_order_id, strategy.short, qty=grid_investment / next_sell_level, limit=next_sell_level)
        state.dynamic_order_counter += 1
        
        last_elem = buy_levels.pop()
        f_remove_grid_level(last_elem)
        
        strategy.order("Trailing Up Buy " + str.tostring(state.dynamic_order_counter), strategy.long, qty=grid_investment / close)
        state.dynamic_order_counter += 1
        
        state.upper_limit := next_sell_level
        state.lower_limit := last_elem.price
        state.no_fee_zone_upper_level := next_sell_level
        true
    else
        false

f_trailing_down(GridState state) =>
    if ENABLE_TRAINLING_DOWN and buy_levels.size() <= 1 and sell_levels.size() > 0
        float next_buy_level = na
        if buy_levels.size() > 0
            next_buy_level := buy_levels.get(0).price * (1 - grid_step_perc / 100)
        else
            next_buy_level := sell_levels.get(0).price * (1 - 2 * exchange_fee_pct - 2 * grid_step_perc / 100)
        new_buy_level = GridLevel.new(next_buy_level, line.new(bar_index, next_buy_level, bar_index+1, next_buy_level, extend=extend.both, color=color.green))
        new_buy_level.dynamic_order_id := "Dynamic Buy " + str.tostring(state.dynamic_order_counter)
        buy_levels.unshift(new_buy_level)
        strategy.order(new_buy_level.dynamic_order_id, strategy.long, qty=grid_investment / next_buy_level, limit=next_buy_level)
        state.dynamic_order_counter += 1
        
        last_elem = sell_levels.pop()
        f_remove_grid_level(last_elem)
        
        strategy.order("Trailing Down Sell " + str.tostring(state.dynamic_order_counter), strategy.short, qty=grid_investment / close)
        state.dynamic_order_counter += 1
        
        state.upper_limit := last_elem.price
        state.lower_limit := next_buy_level
        state.no_fee_zone_lower_level := next_buy_level
        true
    else
        false


// DEBUGGING
// int bar_dir = 0
// int before_highs = 0
// int after_highs = 0
// int before_lows = 0
// int after_lows = 0
// int after_trailing_up = 0
// int after_trailing_down = 0

// Update dynamic orders on each bar
if is_initialized and not bot_ended
    if close < open
        // bar_dir := -1
        // before_highs := grid_state.dynamic_order_counter
        for i = 1 to 10
            changed = f_update_dynamic_orders_high(grid_state)
            if not changed
                break
        // after_highs := grid_state.dynamic_order_counter
        for i = 1 to 10
            changed = f_update_dynamic_orders_low(grid_state)            
            if not changed
                break
        // after_lows := grid_state.dynamic_order_counter
        f_trailing_up(grid_state)
        // after_trailing_up := grid_state.dynamic_order_counter
        f_trailing_down(grid_state)
        // after_trailing_down := grid_state.dynamic_order_counter
    else
        // bar_dir := 1
        // before_lows := grid_state.dynamic_order_counter
        for i = 1 to 10
            changed = f_update_dynamic_orders_low(grid_state)
            if not changed
                break
        // after_lows := grid_state.dynamic_order_counter
        for i = 1 to 10
            changed = f_update_dynamic_orders_high(grid_state)
            if not changed
                break
        // after_highs := grid_state.dynamic_order_counter
        f_trailing_up(grid_state)
        // after_trailing_up := grid_state.dynamic_order_counter
        f_trailing_down(grid_state)
        // after_trailing_down := grid_state.dynamic_order_counter

// Add this function to check for Take Profit and Stop Loss conditions
f_check_tp_sl() =>
    if ENABLE_TAKE_PROFIT and high >= TAKE_PROFIT_PRICE
        strategy.cancel_all()
        strategy.close_all("Take Profit")
        true
    else if ENABLE_STOP_LOSS and low <= STOP_LOSS_PRICE
        strategy.cancel_all()
        strategy.close_all("Stop Loss")
        true
    else
        false

// Modify your main strategy logic to include the Take Profit and Stop Loss check
if is_initialized and initial_buy_executed and not bot_ended
    if f_check_tp_sl()
        bot_ended := true
        end_time := time
    else if ENABLE_TAKE_PROFIT_PERC and strategy.openprofit_percent >= TAKE_PROFIT_PERC
        strategy.cancel_all()
        strategy.close_all("Take Profit Perc")
        bot_ended := true
        end_time := time
    else if ENABLE_STOP_LOSS_PERC and strategy.netprofit_percent <= (STOP_LOSS_PERC * -1)
        strategy.cancel_all()
        strategy.close_all("Stop Loss Perc")
        bot_ended := true
        end_time := time

// DEBUG
// plot(grid_state.no_fee_zone_upper_level, title = "no_fee_zone_upper_level", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(grid_state.no_fee_zone_lower_level, title = "no_fee_zone_lower_level", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(buy_levels.size(), title = "buy_levels.size()", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(sell_levels.size(), title = "sell_levels.size()", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(upper_limit, title = "upper_limit", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(lower_limit, title = "lower_limit", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(grid_step_perc, title = "grid_step_perc", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(bot_ended? 1 : 0, title = "bot_ended", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(strategy.position_avg_price, title = "strategy.position_avg_price", color=color.new(color = color.blue , transp = 0), display=display.data_window)
// plot(grid_state.dynamic_order_counter, title = "dynamic_order_counter", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(bar_dir, title = "bar_dir", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(before_highs, title = "before_highs", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(after_highs, title = "after_highs", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(before_lows, title = "before_lows", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(after_lows, title = "after_lows", color=color.new(color = color.red , transp = 0), display=display.data_window)
// plot(after_trailing_up, title = "after_trailing_up", color=color.new(color = color.green , transp = 0), display=display.data_window)
// plot(after_trailing_down, title = "after_trailing_down", color=color.new(color = color.green , transp = 0), display=display.data_window)

if barstate.islastconfirmedhistory
    transparent = color.new(#131722, transp = 0)
    color1 = color.white
    quote = syminfo.currency

    var table tab1 = table.new(position = position.top_right, columns = 15, rows = 15, bgcolor=transparent, frame_color = transparent,frame_width =  0,border_color = transparent,border_width = 0)
    table.cell(tab1, 0, 1, 'CBA Grid Backtester' , text_halign = text.align_left,  text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 1, str.tostring(version, '#.0') , text_halign = text.align_right, text_size= size.normal, text_color=color1)

    table.cell(tab1, 0, 2, "Grid Step %", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 2, str.tostring(grid_step_perc, "#.##") +  "%", text_halign = text.align_right, text_size= size.normal, text_color=color1)

    grid_range = ((upper_limit - lower_limit) / upper_limit) * 100
    table.cell(tab1, 0, 3, "Grid Range", text_halign = text.align_left, text_size= size.normal,  text_color=color1)
    table.cell(tab1, 1, 3, str.tostring(grid_range, "#.##") +  "%", text_halign = text.align_right, text_size= size.normal, text_color=color1)

    current_value = strategy.equity
    table.cell(tab1, 0, 4, "Current Value", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 4, str.tostring(current_value, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)

    total_pnl = strategy.netprofit
    table.cell(tab1, 0, 5, "Total PNL", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 5, str.tostring(total_pnl, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)

    portfolio_profit_pct = (current_value / strategy.initial_capital - 1) * 100
    table.cell(tab1, 0, 6, "Total PNL %", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 6, str.tostring(portfolio_profit_pct, "#.##") + "%", text_halign = text.align_right, text_size= size.normal, text_color=color1)

    // bot_profit = strategy.grossprofit
    // table.cell(tab1, 0, 7, "Bot Profit", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 7, str.tostring(bot_profit, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)
    
    // bot_profit := strategy.grossprofit_percent
    // table.cell(tab1, 0, 8, "Bot Profit %", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 8, str.tostring(bot_profit, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)

    days_elapsed = ((na(end_time) ? time : end_time) - START_DATE) / (1000 * 60 * 60 * 24)
    avg_daily_profit = total_pnl / days_elapsed
    table.cell(tab1, 0, 9, "Avg. Daily", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 9, str.tostring(avg_daily_profit, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)

    avg_daily_percent = (math.pow(1 + portfolio_profit_pct / 100, 1 / days_elapsed) - 1) * 100
    table.cell(tab1, 0, 10, "Avg. Daily %", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 10, str.tostring(avg_daily_percent, "#.##") + "%", text_halign = text.align_right, text_size= size.normal, text_color=color1)

    table.cell(tab1, 0, 11, "Total Days Traded", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    table.cell(tab1, 1, 11, str.tostring(days_elapsed, "#"), text_halign = text.align_right, text_size= size.normal, text_color=color1)


    // Additional statistics
    // total_trades = strategy.closedtrades
    // table.cell(tab1, 0, 10, "Total Trades", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 10, str.tostring(total_trades), text_halign = text.align_right, text_size= size.normal, text_color=color1)

    // win_rate = strategy.wintrades / total_trades * 100
    // table.cell(tab1, 0, 11, "Win Rate", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 11, str.tostring(win_rate, "#.##") + "%", text_halign = text.align_right, text_size= size.normal, text_color=color1)

    // profit_factor = strategy.grossprofit / math.abs(strategy.grossloss)
    // table.cell(tab1, 0, 12, "Profit Factor", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 12, str.tostring(profit_factor, "#.##"), text_halign = text.align_right, text_size= size.normal, text_color=color1)

    // max_drawdown = strategy.max_drawdown
    // table.cell(tab1, 0, 13, "Max Drawdown", text_halign = text.align_left, text_size= size.normal, text_color=color1)
    // table.cell(tab1, 1, 13, str.tostring(max_drawdown, "#,###.##") + " " + quote, text_halign = text.align_right, text_size= size.normal, text_color=color1)
Leave a Comment