draw violated zones alos: # app.py

import requests
import pandas as pd
from flask import Flask, render_template
import plotly.graph_objs as go

app = Flask(__name__)

def get_klines(symbol, interval, limit=150):
    url = 'https://api.binance.com/api/v3/klines'
    params = {'symbol': symbol, 'interval': interval, 'limit': limit}
    response = requests.get(url, params=params)
    data = response.json()

    # Handle API response errors
    if response.status_code != 200 or not isinstance(data, list):
        print(f"Error fetching data for {symbol} {interval}: {data}")
        return pd.DataFrame()  # Return empty DataFrame

    df = pd.DataFrame(data, columns=[
        'Open Time', 'Open', 'High', 'Low', 'Close', 'Volume',
        'Close Time', 'Quote Asset Volume', 'Number of Trades',
        'Taker Buy Base Volume', 'Taker Buy Quote Volume', 'Ignore'
    ])
    numeric_columns = ['Open', 'High', 'Low', 'Close', 'Volume']
    df[numeric_columns] = df[numeric_columns].astype(float)
    df['Open Time'] = pd.to_datetime(df['Open Time'], unit='ms')
    df['Close Time'] = pd.to_datetime(df['Close Time'], unit='ms')
    df.sort_values('Open Time', inplace=True)
    df.reset_index(drop=True, inplace=True)

    return df

def find_dbr(df):
    patterns = []
    for i in range(3, len(df) - 2):
        # Implement the DBR conditions
        # Price drops
        if df['Close'][i - 2] < df['Close'][i - 3] and df['Close'][i - 1] < df['Close'][i - 2]:
            # Base (small movement)
            base_range = df['High'][i] - df['Low'][i]
            prev_range = ((df['High'][i - 1] - df['Low'][i - 1]) + (df['High'][i - 2] - df['Low'][i - 2])) / 2
            if base_range < prev_range * 0.5:
                # Rally (price increase)
                if df['Close'][i + 1] > df['Close'][i] and df['Close'][i + 2] > df['Close'][i + 1]:
                    pattern = {
                        'Type': 'DBR',
                        'Index': i,
                        'Base Start': df['Open Time'].iloc[i],
                        'Base End': df['Close Time'].iloc[i],
                        'Demand Zone High': df['High'].iloc[i],
                        'Demand Zone Low': df['Low'].iloc[i],
                        'Plot Data': df[max(i - 20, 0):min(i + 40, len(df))].reset_index(drop=True)
                    }
                    patterns.append(pattern)
    return patterns

def find_rbr(df):
    patterns = []
    for i in range(3, len(df) - 2):
        # Implement the RBR conditions
        # Price rallies
        if df['Close'][i - 2] > df['Close'][i - 3] and df['Close'][i - 1] > df['Close'][i - 2]:
            # Base (small movement)
            base_range = df['High'][i] - df['Low'][i]
            prev_range = ((df['High'][i - 1] - df['Low'][i - 1]) + (df['High'][i - 2] - df['Low'][i - 2])) / 2
            if base_range < prev_range * 0.5:
                # Rally continuation
                if df['Close'][i + 1] > df['Close'][i] and df['Close'][i + 2] > df['Close'][i + 1]:
                    pattern = {
                        'Type': 'RBR',
                        'Index': i,
                        'Base Start': df['Open Time'].iloc[i],
                        'Base End': df['Close Time'].iloc[i],
                        'Demand Zone High': df['High'].iloc[i],
                        'Demand Zone Low': df['Low'].iloc[i],
                        'Plot Data': df[max(i - 20, 0):min(i + 40, len(df))].reset_index(drop=True)
                    }
                    patterns.append(pattern)
    return patterns

def is_zone_fresh(df, index, demand_zone_high, demand_zone_low):
    # Check subsequent candles to see if the price has entered the demand zone
    zone_violated = False
    for i in range(index + 1, len(df)):
        if df['Low'].iloc[i] <= demand_zone_high and df['High'].iloc[i] >= demand_zone_low:
            # Price has re-entered the demand zone
            zone_violated = True
            break
    return not zone_violated

def plot_demand_zone(pattern):
    df = pattern['Plot Data']
    symbol = pattern['Symbol']
    interval = pattern['Interval']
    demand_zone_high = pattern['Demand Zone High']
    demand_zone_low = pattern['Demand Zone Low']

    # Create a candlestick chart
    fig = go.Figure(data=[go.Candlestick(
        x=df['Open Time'],
        open=df['Open'],
        high=df['High'],
        low=df['Low'],
        close=df['Close']
    )])

    # Add a rectangle for the demand zone
    fig.add_shape(type='rect',
        x0=df['Open Time'].iloc[0],
        y0=demand_zone_low,
        x1=df['Open Time'].iloc[-1],
        y1=demand_zone_high,
        fillcolor='green',
        opacity=0.2,
        line=dict(width=0),
    )

    # Mark the base period
    base_start = pattern['Base Start']
    base_end = pattern['Base End']
    fig.add_vrect(
        x0=base_start, x1=base_end,
        fillcolor="yellow", opacity=0.3,
        layer="below", line_width=0,
    )

    # Update layout
    fig.update_layout(
        title=f"{symbol} - {interval} - {pattern['Type']}",
        xaxis_title="Time",
        yaxis_title="Price",
        xaxis_rangeslider_visible=False,
        template='plotly_dark',
        height=600,
        width=1000,
    )

    # Convert the plotly figure to HTML div
    chart_html = fig.to_html(full_html=False)

    print(f"Chart HTML generated for {symbol} {interval}")

    return chart_html

@app.route('/')
def index():
    symbols = [
        'BTCUSDT', 'ETHUSDT', 'XRPUSDT', 'DOGEUSDT', 'SOLUSDT',
        'BNBUSDT', 'SUIUSDT', 'CKBUSDT', 'FTMUSDT', 'RUNEUSDT',
        'UNIUSDT', 'AAVEUSDT', 'BCHUSDT', 'KEYUSDT', '1INCHUSDT'
    ]
    intervals = ['30m', '1h', '2h', '4h']
    all_patterns = []

    for symbol in symbols:
        for interval in intervals:
            print(f"Processing {symbol} {interval}")
            df = get_klines(symbol, interval)
            if df.empty:
                print(f"No data for {symbol} {interval}, skipping.")
                continue
            dbr_patterns = find_dbr(df)
            rbr_patterns = find_rbr(df)
            patterns = dbr_patterns + rbr_patterns
            print(f"{symbol} {interval} - Patterns found: {len(patterns)}")
            fresh_patterns = []
            for pattern in patterns:
                if is_zone_fresh(df, pattern['Index'], pattern['Demand Zone High'], pattern['Demand Zone Low']):
                    pattern['Symbol'] = symbol
                    pattern['Interval'] = interval
                    fresh_patterns.append(pattern)
                    print(f"Fresh pattern detected for {symbol} {interval} at {pattern['Base Start']}")
                else:
                    print(f"Pattern at index {pattern['Index']} for {symbol} {interval} is not fresh.")

            if fresh_patterns:
                # Sort the fresh patterns by Base Start time descending and take the most recent
                most_recent_pattern = max(fresh_patterns, key=lambda p: p['Base Start'])
                # Generate chart HTML for the most recent pattern
                chart_html = plot_demand_zone(most_recent_pattern)
                most_recent_pattern['Chart'] = chart_html
                all_patterns.append(most_recent_pattern)
                print(f"Most recent fresh pattern selected for {symbol} {interval}")
            else:
                print(f"No fresh patterns for {symbol} {interval}")

    print(f"Total fresh patterns found: {len(all_patterns)}")
    return render_template('index.html', patterns=all_patterns)

if __name__ == '__main__':
    app.run(debug=True)