BASED ON THESE REQUIREMNTS BUILD THE REST OF THE MODEL. IT SHOULD BE SIMPLE WE CAN COMPLEXITY LATER FOXS ON MAING THE AYERS INPUTS OUTPUTS CORRECT import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import pickle
import logging
from ta.volatility import AverageTrueRange, BollingerBands
from ta.momentum import RSIIndicator
from ta.trend import MACD, ADXIndicator
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.layers import (
    Input,
    Dense,
    Dropout,
    MultiHeadAttention,
    LayerNormalization,
    GlobalAveragePooling1D,
)
from tensorflow.keras.models import Model
import tensorflow as tf
from binance.client import Client

# Suppress TensorFlow warnings for clarity
logging.getLogger("tensorflow").setLevel(logging.ERROR)

def load_data(client, symbol, interval='1m', limit=1000):
    """
    Fetch historical kline data for a given symbol.
    """
    try:
        historicals = client.get_klines(symbol=symbol, interval=interval, limit=limit)
        data = []
        for kl in historicals:
            open_time = pd.to_datetime(kl[0], unit='ms')
            open_price = float(kl[1])
            high = float(kl[2])
            low = float(kl[3])
            close = float(kl[4])
            volume = float(kl[5])
            data.append([open_time, open_price, high, low, close, volume])
        df = pd.DataFrame(data, columns=['open_time', 'open', 'high', 'low', 'close', 'volume'])
        df.set_index('open_time', inplace=True)
        return df
    except Exception as e:
        print(f"Error fetching data for {symbol}: {e}")
        return pd.DataFrame()

def add_technical_indicators(df):
    """
    Add technical indicators to the DataFrame.
    """
    # RSI
    rsi = RSIIndicator(close=df['close'], window=14)
    df['RSI'] = rsi.rsi()
    
    # MACD
    macd = MACD(close=df['close'], window_slow=26, window_fast=12, window_sign=9)
    df['MACD'] = macd.macd()
    df['MACD_signal'] = macd.macd_signal()
    df['MACD_diff'] = macd.macd_diff()
    
    # ATR
    atr = AverageTrueRange(high=df['high'], low=df['low'], close=df['close'], window=14)
    df['ATR'] = atr.average_true_range()
    
    # Bollinger Bands Width
    bollinger = BollingerBands(close=df['close'], window=20, window_dev=2)
    df['BB_upper'] = bollinger.bollinger_hband()
    df['BB_lower'] = bollinger.bollinger_lband()
    df['BB_width'] = (df['BB_upper'] - df['BB_lower']) / df['close']
    
    # ADX
    adx = ADXIndicator(high=df['high'], low=df['low'], close=df['close'], window=14)
    df['ADX'] = adx.adx()
    
    # Drop initial rows with NaN values
    df.dropna(inplace=True)
    return df

def classify_market_environments(df):
    """
    Classify market environments into numerical categories for model training.
    """
    # Volatility Classification
    df['ATR_mavg'] = df['ATR'].rolling(window=14).mean()
    df['ATR_vol'] = np.where(df['ATR'] > 1.2 * df['ATR_mavg'], 'High',
                             np.where(df['ATR'] < 0.8 * df['ATR_mavg'], 'Low', 'Medium'))
    
    df['BB_mavg'] = df['BB_width'].rolling(window=20).mean()
    df['BB_vol'] = np.where(df['BB_width'] > 1.2 * df['BB_mavg'], 'High',
                            np.where(df['BB_width'] < 0.8 * df['BB_mavg'], 'Low', 'Medium'))
    
    df['daily_return'] = df['close'].pct_change()
    df['RV'] = df['daily_return'].rolling(window=20).std() * np.sqrt(252)
    rv_80 = df['RV'].quantile(0.8)
    rv_20 = df['RV'].quantile(0.2)
    df['RV_vol'] = np.where(df['RV'] > rv_80, 'High',
                            np.where(df['RV'] < rv_20, 'Low', 'Medium'))
    
    df['Volatility'] = df[['ATR_vol', 'BB_vol', 'RV_vol']].mode(axis=1)[0]
    
    df['Trend'] = np.where(
        (df['MACD'] > df['MACD_signal']) & (df['MACD'] > 0), 'Bullish',
        np.where(
            (df['MACD'] < df['MACD_signal']) & (df['MACD'] < 0), 'Bearish', 'Neutral'
        )
    )
    
    df['Trend_strength'] = np.where(df['ADX'] > 25, 'Strong', 'Weak')
    
    df['Market_Environment'] = df.apply(
        lambda row: f"{row['Volatility']} Vol/{row['Trend']}" if row['Trend_strength'] == 'Strong' else f"{row['Volatility']} Vol/Neutral",
        axis=1
    )

    # Encode categorical data to numeric
    label_encoders = {}
    for column in ['ATR_vol', 'BB_vol', 'RV_vol', 'Volatility', 'Trend', 'Trend_strength', 'Market_Environment']:
        le = LabelEncoder()
        df[column] = le.fit_transform(df[column].astype(str))
        label_encoders[column] = le  # Save encoder for each column if you need to decode later

    return df, label_encoders  # Returning encoders in case needed

def calculate_leg_data(df):
    """
    Calculate leg data: current and previous leg percent change and length.
    """
    df['percent_delta'] = df['close'].pct_change()
    df = df.reset_index(drop=True)
    
    previous_leg_change = 0
    previous_leg_length = 0
    current_leg_change = 0
    current_leg_length = 0
    
    previous_changes = []
    previous_lengths = []
    current_changes = []
    current_lengths = []
    
    for i in range(len(df)):
        if i == 0:
            current_leg_change = 0
            current_leg_length = 0
        else:
            percent_delta = df.at[i, 'percent_delta']
            if current_leg_length == 0:
                current_leg_change = percent_delta
                current_leg_length = 1
            else:
                if (current_leg_change > 0 and percent_delta > 0) or (current_leg_change < 0 and percent_delta < 0):
                    current_leg_change += percent_delta
                    current_leg_length += 1
                else:
                    previous_leg_change = current_leg_change
                    previous_leg_length = current_leg_length
                    current_leg_change = percent_delta
                    current_leg_length = 1
        previous_changes.append(previous_leg_change)
        previous_lengths.append(previous_leg_length)
        current_changes.append(current_leg_change)
        current_lengths.append(current_leg_length)
    
    df['previous_leg_change'] = previous_changes
    df['previous_leg_length'] = previous_lengths
    df['current_leg_change'] = current_changes
    df['current_leg_length'] = current_lengths
    
    df.drop(columns=['percent_delta'], inplace=True)
    return df

def classify_percent_change(df):
    """
    Classify percent changes into 7 categories.
    """
    df['percent_change'] = df['close'].pct_change()
    df.dropna(inplace=True)
    
    percentiles = df['percent_change'].quantile([0.05, 0.20, 0.40, 0.60, 0.80, 0.95]).to_dict()
    
    def classify(x, p):
        if x < p[0.05]:
            return 'Down a Lot'
        elif x < p[0.20]:
            return 'Down Moderate'
        elif x < p[0.40]:
            return 'Down a Little'
        elif x < p[0.60]:
            return 'No Change'
        elif x < p[0.80]:
            return 'Up a Little'
        elif x < p[0.95]:
            return 'Up Moderate'
        else:
            return 'Up a Lot'
    
    df['percent_change_classification'] = df['percent_change'].apply(lambda x: classify(x, percentiles))
    return df

def encode_and_scale(df, label_encoders=None, scalers=None):
    """
    Encode categorical features and scale numerical features.
    """
    if label_encoders is None:
        label_encoders = {}
    if scalers is None:
        scalers = {}
    
    # 1. Encode Categorical Input Features
    categorical_features = ['percent_change_classification', 'Market_Environment']
    for col in categorical_features:
        le = LabelEncoder()
        df[f'{col}_encoded'] = le.fit_transform(df[col].astype(str))
        label_encoders[col] = le  # Save the encoder for future use
    
    # 2. Encode Categorical Target Features (if applicable)
    # In this case, 'leg_direction' is binary (0 or 1), so no encoding is needed.
    
    # 3. Scale Numerical Features
    numerical_features = [
        'RSI', 'MACD', 'MACD_signal', 'ATR', 'BB_width',
        'previous_leg_change', 'previous_leg_length',
        'current_leg_change', 'current_leg_length'
    ]
    
    scaler = StandardScaler()
    df[numerical_features] = scaler.fit_transform(df[numerical_features])
    scalers['numerical'] = scaler  # Save the scaler for future use
    
    # 4. Scale Regression Targets
    # For this two-output model, we're excluding regression targets.
    # If needed in the future, scaling can be applied here.
    
    return df, label_encoders, scalers

def prepare_sequences(df, seq_length=60, target_steps=1):
    """
    Prepare input sequences and corresponding multiple targets.

    Returns:
    - X (np.ndarray): Input sequences.
    - Y (dict): Dictionary containing multiple targets.
    """
    FEATURES = [
        'RSI', 'MACD', 'MACD_signal', 'ATR', 'BB_width',
        'previous_leg_change', 'previous_leg_length',
        'current_leg_change', 'current_leg_length',
        'Market_Environment_encoded'
    ]
    
    X = []
    Y_percent_change = []
    Y_leg_direction = []
    
    for i in range(len(df) - seq_length - target_steps + 1):
        seq = df.iloc[i:i + seq_length][FEATURES].values
        target_percent_change = df.iloc[i + seq_length]['percent_change_classification_encoded']
        target_leg_direction = 1 if df.iloc[i + seq_length]['current_leg_change'] > 0 else 0
        
        X.append(seq)
        Y_percent_change.append(target_percent_change)
        Y_leg_direction.append(target_leg_direction)
    
    X = np.array(X)
    Y = {
        'percent_change_classification': np.array(Y_percent_change),
        'leg_direction':np.array(Y_leg_direction)
    }
    
    return X, Y




if __name__ == "__main__":
    model, history = main() REQUIREMNTS FOR MODEL ### **Using the Model for Trading Signals**

### 4.1 **Model-Based Trading Logic**

- The model will be run every **15 seconds** during live deployment to make predictions.

### 4.2 **Triggering Trades Based on Predicted Percent Change**

- Use the **predicted percent change classification** to determine the direction of the next trade:
    - **Down a Lot/Moderate**: Place a **sell** order if the confidence score is high.
    - **Up a Lot/Moderate**: Place a **buy** order.
    - **No Change**: Stay in the current position or hold.

### 4.3 **Leg Data and Market Condition Analysis**

- Use the **leg data** predictions to detect potential **trend reversals** or **continuation** patterns:
    - If the model predicts a **continuation** of the current leg with a high confidence score, maintain the current trade.
    - If the model predicts a **leg reversal** (a switch from bullish to bearish), close or reverse the position.
- Analyze **market conditions** (bullish, bearish, or neutral) alongside leg data:
    - In a **bullish market**, favor **buy signals** and trade conservatively on predicted down movements.
    - In a **bearish market**, prioritize **sell signals**.
    - In a **neutral market**, only trade on **strong directional confidence** from the percent change classification.

### 4.4 **Risk Management**

- Implement stop-loss or take-profit orders based on the model's **confidence score**:
    - Higher confidence scores can allow for larger trades or a wider stop-loss range.
    - Lower confidence should trigger smaller trade sizes or tighter risk parameters.

### 4.5 **Backtesting Trading Strategies**

- Backtest multiple trading strategies using the stored **model predictions** and assess profitability and risk.
- Example strategies to test:
    - **Trend-following strategy**: Trade in the direction of the predicted leg continuation.
    - **Mean-reversion strategy**: Trade against predicted large upward or downward moves in neutral market conditions.

---

### Summary of Key Components for the Developer

1. **Data Pipeline**: Gather historical price data, compute technical indicators, and preprocess them.
2. **Model Inputs**: Price, leg data, market conditions, percent change classification, and technical indicators.
3. **Model Outputs**: Predicted price change, percent change classification, leg data predictions, and confidence scores.
4. **Training and Testing**:
    - **Walk-forward training** with daily fine-tuning.
    - **Rolling 100-day window retraining**.
5. **Trading Logic**: Use predictions to trigger trades, manage risk, and backtest strategies.

This approach will integrate a robust prediction mechanism based on market conditions, technical indicators, and advanced time-series analysis to facilitate intelligent trading decisions.

## Example table

Let's create an example table that represents a time series dataset for predicting cryptocurrency price movements, including both the **inputs** and **targets**. Each row will represent a single time step, and each column will represent a feature, including technical indicators, leg data, market conditions, and targets like price change and percent change classification.

### Example Table Structure

- **Time Step**: The timestamp or index for each row (not explicitly shown but implied).
- **Inputs**: The model inputs at each time step.
- **Targets**: The columns the model will predict.

| Time Step | Open | High | Low | Close | Heikin Ashi Close | RSI | MACD Line | Donchian Upper | Donchian Lower | ATR | Leg Percent Change (Current) | Leg Length (Current) | Leg Percent Change (Previous) | Leg Length (Previous) | Market Condition | SPY | VIX | Nadaraya-Watson | Percent Change | Percent Change Class | **Target: Predicted Price** | **Target: Percent Change Class** | **Target: Leg Direction** | **Target: Leg Length** |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 00:00:00 | 1.00 | 1.02 | 0.98 | 1.01 | 1.005 | 55 | 0.002 | 1.02 | 0.98 | 0.05 | -0.5% | 20 | +1.5% | 50 | Bullish | 420 | 18 | 1.01 | +0.1% | Up a Little | 1.012 | Up a Little | +0.05 | 5 |
| 00:00:05 | 1.01 | 1.03 | 0.99 | 1.02 | 1.015 | 58 | 0.003 | 1.03 | 0.99 | 0.06 | +0.5% | 25 | -0.5% | 20 | Bullish | 421 | 17 | 1.02 | +0.15% | Up Moderate | 1.025 | Up Moderate | +0.10 | 10 |
| 00:00:10 | 1.02 | 1.05 | 1.00 | 1.03 | 1.025 | 60 | 0.005 | 1.04 | 1.00 | 0.07 | +1.0% | 30 | -0.5% | 20 | Bullish | 422 | 16 | 1.03 | +1.0% | Up a Lot | 1.038 | Up a Lot | +0.15 | 15 |
| 00:00:15 | 1.03 | 1.06 | 1.01 | 1.04 | 1.035 | 62 | 0.008 | 1.05 | 1.01 | 0.08 | +1.5% | 35 | -1.0% | 30 | Bullish | 423 | 15 | 1.04 | +1.5% | Up a Lot | 1.045 | Up a Lot | +0.20 | 20 |
| 00:00:20 | 1.04 | 1.08 | 1.02 | 1.05 | 1.045 | 65 | 0.010 | 1.06 | 1.02 | 0.09 | +2.0% | 40 | -1.0% | 30 | Bullish | 424 | 14 | 1.05 | +2.0% | Up a Lot | 1.056 | Up a Lot | +0.25 | 25 |

### Explanation of Each Column:

### **Inputs:**

1. **Price Data**:
    - **Open, High, Low, Close**: Standard OHLC values for the currency at each time step.
    - **Heikin Ashi Close**: The Heikin Ashi transformation of the closing price for smoothing price movements.
2. **Technical Indicators**:
    - **RSI (Relative Strength Index)**: Measures momentum, indicating overbought or oversold conditions.
    - **MACD Line**: Moving Average Convergence Divergence, a trend-following momentum indicator.
    - **Donchian Upper, Donchian Lower**: Upper and lower bounds of Donchian channels, which track volatility.
    - **ATR (Average True Range)**: Measures volatility, indicating how much an asset’s price moves, on average, during a set time period.
    - **Nadaraya-Watson Envelope**: A smoothed moving average that adapts to volatility.
3. **Leg Data**:
    - **Leg Percent Change (Current)**: The percent change for the current price leg (magnitude and direction).
    - **Leg Length (Current)**: The number of time steps the current leg has persisted in the same direction.
    - **Leg Percent Change (Previous)**: The percent change for the previous leg (magnitude and direction).
    - **Leg Length (Previous)**: The length of the previous leg before the direction changed.
4. **Market Conditions**:
    - **Market Condition**: Bullish, neutral, or bearish, based on overall market analysis using SPY, VIX, and other metrics.
    - **SPY, VIX**: S&P 500 ETF and Volatility Index data as additional inputs that reflect market sentiment and volatility.
5. **Percent Change**:
    - **Percent Change**: The raw percent change in price from the previous time step.
    - **Percent Change Class**: A discrete classification of percent change (one of 7 classes: Down a Lot, Down Moderate, Down a Little, No Change, Up a Little, Up Moderate, Up a Lot).

---

### **Targets:**

1. **Target: Predicted Price**: The predicted normalized price for the next time step.
2. **Target: Percent Change Class**: The predicted classification of percent change for the next time step (from the 7-level discrete classification).
3. **Target: Leg Direction**: The predicted percent change for the current leg (which includes both direction and magnitude).
4. **Target: Leg Length**: The predicted length of the current leg for the next 18 time steps.

---

### Example Time Step Explanation:

For the row at time step **00:00:00**:

- **Inputs**:
    - The close price is **1.01**.
    - The current leg is showing a **0.5%** percent change over the last **20** time steps, meaning the price has been moving downward slightly.
    - The previous leg had a **+1.5%** percent change over **50** time steps, so the prior move was bullish.
    - The market is currently **bullish**, as indicated by external factors such as SPY and VIX.
- **Targets**:
    - The model should predict that the next price will be **1.012** (a slight increase).
    - The next percent change will fall into the **Up a Little** classification (between +0.1% and +0.5%).
    - The leg is expected to continue moving upward, with a **leg direction** percent change of **+0.05%** over the next **5** time steps.