#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script para visualizar en tiempo real las velas cerradas de un par de trading en Bybit (via pybit).

Autor: Salvador Pinon
Versión: 1.0
Fecha: 2025-05-07
Licencia: MIT

Descripción:
Este script se conecta a la API unificada de Bybit (a través de la librería `pybit`) para consultar
y mostrar las últimas velas cerradas de un símbolo en el mercado spot. A medida que se cierra una
nueva vela, el script la detecta y la imprime en tiempo real.
"""


from pybit.unified_trading import HTTP
from datetime import datetime
import argparse
import time
import decimal

client = HTTP()

def get_closed_klines(symbol, interval, count):
    """
    Obtiene las últimas velas cerradas (candlesticks) para un símbolo e intervalo dado.

    Args:
        symbol (str): Par de trading (por ejemplo, 'BTCUSDT').
        interval (str): Intervalo de vela (por ejemplo, '1m', '5m', '1h').
        count (int): Número de velas a recuperar.

    Returns:
        list: Lista de velas cerradas (excluyendo la vela actual).
    """
    interval_map = {
        "1m": 1, "3m": 3, "5m": 5, "15m": 15, "30m": 30,
        "1h": 60, "2h": 120, "4h": 240, "1d": "D", "1w": "W"
    }
    if interval not in interval_map:
        raise ValueError(f"Unsupported interval: {interval}")

    response = client.get_kline(
        category="spot",
        symbol=symbol.upper(),
        interval=str(interval_map[interval]),
        limit=count + 1
    )
    klines = response['result']['list']
    klines = sorted(klines, key=lambda x: int(x[0]))  # Ordenar por tiempo
    return klines[:-1]  # Excluir la vela actual en curso

def print_kline_table(klines):
    """
    Print a formatted table of klines with timestamp, open, high, low, close, and volume.

    Parameters:
        klines (list): List of klines to display.
    """

    for kline in klines:
        # print("RAW:", kline)  # Ver el contenido original crudo de cada vela
        timestamp    = int(kline[0]) // 1000
        kline_time   = datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
        open_price   = (kline[1])
        high_price   = (kline[2])
        low_price    = (kline[3])
        close_price  = (kline[4])
        volume       = (kline[5])
        print(f"{kline_time:<20} {open_price:<20} {high_price:<20} {low_price:<20} {close_price:<20} {volume:<20}")

def wait_for_new_closed_kline(symbol, interval, last_kline_open_time):
    """
    Continuously check for a new closed kline.

    Parameters:
        symbol (str): Trading pair symbol.
        interval (str): Kline interval.
        last_kline_open_time (int): Timestamp of the last known closed kline.

    Returns:
        list: The new closed kline once it becomes available.
    """

    while True:
        new_klines = get_closed_klines(symbol, interval, 2)
        latest = new_klines[-1]
        if latest[0] != last_kline_open_time:
            return latest
        time.sleep(1)

def main():
    """
    Main function to parse arguments and display real-time closed candles for a given trading pair.
    """
    
    parser = argparse.ArgumentParser(
        description="Script that reads and displays closed candlesticks of a trading pair on Bybit in real time. "
                    "Allows specifying the symbol, timeframe, and number of initial candles to display."
    )
    parser.add_argument('--exchange', type=str, default='binance', help='Exchange Name (e.g., Binance, Bybit, Kraken, etc.)')
    parser.add_argument('--symbol',   type=str, default='BTCUSDT', help='Trading pair (e.g., BTCUSDT)')
    parser.add_argument('--interval', type=str, default='1m',      help='Candle interval (e.g., 1m, 5m, 1h)')
    parser.add_argument('--limit',    type=int, default=20,        help='Number of initial candles to display')
    parser.add_argument('--kafkamonitor',   type=str, default='',        help='Kafka Topcic to monitor')

    args = parser.parse_args()

    exchange = args.exchange
    symbol   = args.symbol.upper()
    interval = args.interval
    limit    = args.limit
    kafkamonitor = args.kafkamonitor

    print(f"Initializing with the last {limit} closed candles for {symbol} ({interval})...\n")
    klines = get_closed_klines(symbol, interval, limit)
    print_kline_table(klines)

    last_kline_open_time = klines[-1][0]
    while True:
        print(f"\nWaiting for new closed candle for {symbol} / {exchange}...\n")
        new_closed_kline = wait_for_new_closed_kline(symbol, interval, last_kline_open_time)
        print("New closed candle detected:\n")
        print_kline_table([new_closed_kline])
        last_kline_open_time = new_closed_kline[0]

if __name__ == "__main__":
    main()
