"import MetaTrader5 as mt5
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import datetime
import time
import pytz

# Initialize MT5 connection
if not mt5.initialize():
    print("initialize() failed")
    mt5.shutdown()
    exit()

# Get all symbols available
all_symbols = mt5.symbols_get()
btc_symbols = [sym.name for sym in all_symbols if 'BTC' in sym.name]
print("Available BTC symbols:")
print(btc_symbols)

# Choose the correct symbol
symbol = 'BTCUSD'  # Replace with your broker's symbol for Bitcoin

# Ensure the symbol is available
symbol_info = mt5.symbol_info(symbol)
if symbol_info is None:
    print(f"Symbol {symbol} not found, cannot proceed")
    mt5.shutdown()
    exit()

# If the symbol is unavailable in Market Watch, add it
if not symbol_info.visible:
    print(f"{symbol} is not visible, trying to make it visible")
    if not mt5.symbol_select(symbol, True):
        print(f"symbol_select({symbol}) failed, exit")
        mt5.shutdown()
        exit()

# Choose the timeframe and number of bars
timeframe = mt5.TIMEFRAME_M5  # 5-minute timeframe
bars = 500  # Number of bars to fetch

# Get rates from MT5
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, bars)

# Check if rates are retrieved
if rates is None or len(rates) == 0:
    print(f"No rates retrieved for symbol {symbol}.")
    mt5.shutdown()
    exit()

# Create DataFrame
df = pd.DataFrame(rates)

# Correct timestamp conversion
df['timestamp'] = pd.to_datetime(df['time'], unit='s', utc=True)

# Replace 'Your_Timezone' with your actual timezone string
user_timezone = 'UTC'  # Replace with your timezone string

# Validate the timezone
if user_timezone not in pytz.all_timezones:
    print(f"Invalid timezone: '{user_timezone}'. Please use a valid timezone string from pytz.all_timezones.")
    mt5.shutdown()
    exit()

df['timestamp'] = df['timestamp'].dt.tz_convert(user_timezone)

# Verify data
print("Data sample:")
print(df[['timestamp', 'open', 'high', 'low', 'close']].head())
print(df[['timestamp', 'open', 'high', 'low', 'close']].tail())

# Check for unrealistic price levels and adjust if necessary
price_adjustment_factor = 1  # Set to the appropriate value if needed

# If the price difference is significant, adjust the price
if df['close'].mean() > 100000:  # Example threshold
    price_adjustment_factor = 1000  # Adjust this factor based on the data
    print(f"Adjusting prices by dividing by {price_adjustment_factor} due to high price levels.")
    df['open'] = df['open'] / price_adjustment_factor
    df['high'] = df['high'] / price_adjustment_factor
    df['low'] = df['low'] / price_adjustment_factor
    df['close'] = df['close'] / price_adjustment_factor
else:
    print("Price levels are within expected range; no adjustment needed.")

# Initialize variables for ZigZag calculation
zigzag_points = []
last_pivot_idx = None
last_pivot_type = None  # 'top' or 'bottom'
direction = None  # 'up' or 'down'

# Variables to track the highest high and lowest low in the current swing
swing_high_idx = None
swing_low_idx = None

# Iterate over the DataFrame to identify tops and bottoms
for i in range(1, len(df)):
    current_candle = df.iloc[i]
    prev_candle = df.iloc[i - 1]

    if direction is None:
        # Determine the initial direction based on the first two candles
        if current_candle['close'] > prev_candle['close']:
            direction = 'up'
            swing_low_idx = i - 1
            swing_high_idx = i - 1  # Initialize swing high index
        else:
            direction = 'down'
            swing_high_idx = i - 1
            swing_low_idx = i - 1  # Initialize swing low index
        continue

    if direction == 'up':
        # Update swing high
        if swing_high_idx is None or current_candle['high'] > df.iloc[swing_high_idx]['high']:
            swing_high_idx = i

        # Rule 1: Mark a top when a candle has lower highs and lows
        if current_candle['high'] < prev_candle['high'] and current_candle['low'] < prev_candle['low']:
            # Mark the highest high since the last bottom
            last_pivot_idx = swing_high_idx
            last_pivot_type = 'top'
            zigzag_points.append((df.iloc[last_pivot_idx]['timestamp'], df.iloc[last_pivot_idx]['high']))
            direction = 'down'
            swing_high_idx = None  # Reset swing high index
            swing_low_idx = i  # Start tracking new swing low
        else:
            # Adjust bottom if a lower low occurs
            if last_pivot_type == 'bottom' and current_candle['low'] < df.iloc[last_pivot_idx]['low']:
                last_pivot_idx = i  # Update last pivot index
                # Adjust the last bottom in the zigzag_points
                if zigzag_points and zigzag_points[-1][1] != df.iloc[last_pivot_idx]['low']:
                    zigzag_points[-1] = (df.iloc[last_pivot_idx]['timestamp'], df.iloc[last_pivot_idx]['low'])
    elif direction == 'down':
        # Update swing low
        if swing_low_idx is None or current_candle['low'] < df.iloc[swing_low_idx]['low']:
            swing_low_idx = i

        # Rule 1: Mark a bottom when a candle has higher highs and lows
        if current_candle['high'] > prev_candle['high'] and current_candle['low'] > prev_candle['low']:
            # Mark the lowest low since the last top
            last_pivot_idx = swing_low_idx
            last_pivot_type = 'bottom'
            zigzag_points.append((df.iloc[last_pivot_idx]['timestamp'], df.iloc[last_pivot_idx]['low']))
            direction = 'up'
            swing_low_idx = None  # Reset swing low index
            swing_high_idx = i  # Start tracking new swing high
        else:
            # Adjust top if a higher high occurs
            if last_pivot_type == 'top' and current_candle['high'] > df.iloc[last_pivot_idx]['high']:
                last_pivot_idx = i  # Update last pivot index
                # Adjust the last top in the zigzag_points
                if zigzag_points and zigzag_points[-1][1] != df.iloc[last_pivot_idx]['high']:
                    zigzag_points[-1] = (df.iloc[last_pivot_idx]['timestamp'], df.iloc[last_pivot_idx]['high'])

# Convert zigzag points to a DataFrame
zigzag_df = pd.DataFrame(zigzag_points, columns=['timestamp', 'price'])

# Display ZigZag points
print("ZigZag Points:")
print(zigzag_df)

# Analyze Liquidity After Breakouts
# We'll analyze the liquidity after the price crosses the pivot points

# Initialize lists to store analysis results
breakout_analysis = []

for idx in range(len(zigzag_df)-1):
    pivot_time = zigzag_df.loc[idx, 'timestamp']
    pivot_price = zigzag_df.loc[idx, 'price']
    pivot_type = 'top' if idx % 2 != 0 else 'bottom'  # Assuming alternation between tops and bottoms

    # Find the index in df corresponding to the pivot time
    pivot_idx = df.index[df['timestamp'] == pivot_time]
    if pivot_idx.empty:
        continue
    pivot_idx = pivot_idx[0]

    # Look ahead to find if a breakout occurred
    look_ahead_period = 5  # Number of candles to look ahead
    end_idx = min(pivot_idx + look_ahead_period, len(df)-1)

    breakout_occurred = False
    breakout_candle_idx = None

    for i in range(pivot_idx+1, end_idx+1):
        if pivot_type == 'top':
            # Check if price crosses above the pivot price
            if df.loc[i, 'close'] > pivot_price:
                breakout_occurred = True
                breakout_candle_idx = i
                break
        elif pivot_type == 'bottom':
            # Check if price crosses below the pivot price
            if df.loc[i, 'close'] < pivot_price:
                breakout_occurred = True
                breakout_candle_idx = i
                break

    if breakout_occurred and breakout_candle_idx is not None:
        # Measure liquidity after breakout
        analysis_period = 5  # Number of candles to analyze after breakout
        start_idx = breakout_candle_idx + 1
        end_idx = min(start_idx + analysis_period, len(df))

        post_breakout_df = df.iloc[start_idx:end_idx]
        total_volume = post_breakout_df['tick_volume'].sum()
        average_volume = post_breakout_df['tick_volume'].mean()

        # Compare to average volume over the whole dataset
        overall_avg_volume = df['tick_volume'].mean()

        liquidity_strength = average_volume / overall_avg_volume  # Ratio indicating strength

        breakout_analysis.append({
            'pivot_time': pivot_time,
            'pivot_price': pivot_price,
            'pivot_type': pivot_type,
            'breakout_time': df.loc[breakout_candle_idx, 'timestamp'],
            'liquidity_strength': liquidity_strength,
            'total_volume': total_volume
        })

# Convert to DataFrame
breakout_df = pd.DataFrame(breakout_analysis)

# Shutdown MT5 connection
mt5.shutdown()

# Display Breakout Analysis
print("Breakout Analysis:")
print(breakout_df)

# Visualization
fig = make_subplots(
    rows=3, cols=1, shared_xaxes=True,
    vertical_spacing=0.03,
    subplot_titles=('Price Chart', 'Liquidity Strength', 'Tick Volume')
)

# Candlestick chart
fig.add_trace(
    go.Candlestick(
        x=df['timestamp'],
        open=df['open'],
        high=df['high'],
        low=df['low'],
        close=df['close'],
        name='Candlesticks'
    ),
    row=1, col=1
)

# ZigZag line
if not zigzag_df.empty:
    fig.add_trace(
        go.Scatter(
            x=zigzag_df['timestamp'],
            y=zigzag_df['price'],
            mode='lines+markers',
            line=dict(color='orange', width=2),
            marker=dict(color='blue', size=6),
            name='ZigZag'
        ),
        row=1, col=1
    )

# Liquidity Strength after Breakouts
if not breakout_df.empty:
    fig.add_trace(
        go.Bar(
            x=breakout_df['breakout_time'],
            y=breakout_df['liquidity_strength'],
            marker_color='green',
            name='Liquidity Strength'
        ),
        row=2, col=1
    )

# Tick Volume
fig.add_trace(
    go.Bar(
        x=df['timestamp'],
        y=df['tick_volume'],
        marker_color='blue',
        name='Tick Volume'
    ),
    row=3, col=1
)

# Mark Breakout Points on the Chart
for idx, row in breakout_df.iterrows():
    fig.add_trace(
        go.Scatter(
            x=[row['breakout_time']],
            y=[df.loc[df['timestamp'] == row['breakout_time'], 'close'].values[0]],
            mode='markers+text',
            marker=dict(color='red', size=10, symbol='star'),
            text=[f"Breakout ({row['pivot_type']})"],
            textposition='bottom center',
            name='Breakout Points'
        ),
        row=1, col=1
    )

# Update layout
fig.update_layout(
    title=f'{symbol} 5-Minute Chart with ZigZag and Liquidity Analysis',
    xaxis=dict(type='date'),
    xaxis2=dict(type='date'),
    xaxis3=dict(type='date'),
    yaxis_title='Price',
    yaxis2_title='Liquidity Strength',
    yaxis3_title='Tick Volume',
    xaxis_rangeslider_visible=False,
    height=1000
)

# Show the chart
fig.show()

# Provide Written Analysis
print("\nLiquidity Analysis Report:")
for idx, row in breakout_df.iterrows():
    liquidity_strength = row['liquidity_strength']
    if liquidity_strength > 1:
        strength_description = "high liquidity"
    else:
        strength_description = "low liquidity"

    print(f"Breakout of a {row['pivot_type']} at {row['breakout_time']}:")
    print(f"- Liquidity strength is {liquidity_strength:.2f} times the average, indicating {strength_description}.")
    if liquidity_strength > 1:
        print("- The liquidity conditions support the continuation of the price movement after the breakout.\n")
    else:
        print("- The liquidity conditions may not support a strong continuation; caution is advised.\n")" nesse código quero ajustes: rompimento com apenas sombras dos candles não estão sendo considerados, rompimento de sombra não deixam de ser rompimentos e quero o valor da liquidez nesses momentos tambem, outro ajuste é que a liquidez que aparece não mostra um sentido, se a liquidez está maior no sentido da compra ou venda, ajuste isso, mantenha o que esta funcionando e me mande o código completo com as alterações