INT NOT PLOTITNG SAYING NO HISTRY # -*- coding: utf-8 -*-
"""
Created on Mon Nov 11 17:03:35 2024

@author: atom
"""

import MetaTrader5 as mt5
import pandas as pd
import numpy as np
import gym
from stable_baselines3 import PPO
from gym import spaces
import matplotlib.pyplot as plt
import warnings
import datetime

warnings.filterwarnings("ignore")

if not mt5.initialize():
    print("MetaTrader5 initialization failed")
    quit()
else:
    print("MetaTrader5 initialized successfully.")

symbol = "EURUSD"
timeframe = mt5.TIMEFRAME_M15
short_window = 10
long_window = 50
sl_percent = 0.005  # Example SL percentage (0.5%)
tp_percent = 0.020  # Example TP percentage (2%)

class MATradingEnv(gym.Env):

    metadata = {'render.modes': ['human']}

    def __init__(self, symbol, timeframe, short_window, long_window, data=None):
        super(MATradingEnv, self).__init__()
        
        self.symbol = symbol
        self.timeframe = timeframe
        self.short_window = short_window
        self.long_window = long_window
        
        self.action_space = spaces.Discrete(3)
        
        self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(3,), dtype=np.float32)
        
        if data is None:
            self.data = self._fetch_data()
        else:
            self.data = data
        
        self.data['SMA_short'] = self.data['close'].rolling(window=self.short_window).mean()
        self.data['SMA_long'] = self.data['close'].rolling(window=self.long_window).mean()
        self.data.dropna(inplace=True)  

        self.reset()
    
    def _fetch_data(self):
        num_bars = 100 
        start_pos = 100  # higher values fetch older data
    
        print(f"Attempting to fetch {num_bars} bars for symbol '{self.symbol}' and timeframe '{self.timeframe}' starting from position {start_pos}.")
    
        rates = mt5.copy_rates_from_pos(self.symbol, self.timeframe, start_pos, num_bars)
        
        if rates is None or len(rates) == 0:
            print("Failed to fetch data using copy_rates_from_pos. Trying alternative method using copy_rates_range.")
            print("Latest MT5 error:", mt5.last_error())
            return self._fetch_data_range()
        
        df = pd.DataFrame(rates)
        df['time'] = pd.to_datetime(df['time'], unit='s')
        print(f"Successfully fetched {len(df)} bars of data.")
        return df

    def _fetch_data_range(self):
        utc_from = datetime.datetime(2023, 1, 1)
        utc_to = datetime.datetime.now()
        print(f"Fetching data from {utc_from} to {utc_to} for symbol '{self.symbol}' on timeframe '{self.timeframe}'.")
        
        rates = mt5.copy_rates_range(self.symbol, self.timeframe, utc_from, utc_to)
        
        if rates is None or len(rates) == 0:
            print("Failed to fetch data using copy_rates_range.")
            print("Latest MT5 error:", mt5.last_error())
            raise ValueError("No data could be fetched from MT5 using both copy_rates_from_pos and copy_rates_range.")
        
        df = pd.DataFrame(rates)
        df['time'] = pd.to_datetime(df['time'], unit='s')
        print(f"Successfully fetched {len(df)} bars of data from {utc_from} to {utc_to}.")
        return df

    def reset(self):
        self.current_step = 0
        self.position = 0  
        self.entry_price = 0.0
        self.sl = 0.0
        self.tp = 0.0
        self.balance = 10000 
        self.max_steps = len(self.data) - 1
        self.trade_history = []
        self.current_trade = None 
        return self._get_observation()

    def _get_observation(self):
        current_data = self.data.iloc[self.current_step]
        return np.array([
            current_data['close'],
            current_data['SMA_short'],
            current_data['SMA_long']
        ], dtype=np.float32)

    def step(self, action):
        reward = 0
        done = False
        info = {}
        
        current_price = self.data.iloc[self.current_step]['close']
        sma_short = self.data.iloc[self.current_step]['SMA_short']
        sma_long = self.data.iloc[self.current_step]['SMA_long']
        time = self.data.iloc[self.current_step]['time']
        
        if action == 1: 
            if self.position == 0:
                self.position = 1
                self.entry_price = current_price
                self.sl = current_price * (1 - sl_percent)
                self.tp = current_price * (1 + tp_percent)
                self.current_trade = {
                    'entry_time': time,
                    'entry_price': current_price,
                    'type': 'BUY',
                    'stop_loss': self.sl,
                    'take_profit': self.tp,
                    'exit_time': None,
                    'exit_price': None,
                    'result': None
                }
                self.trade_history.append(self.current_trade)
                print(f"{time}: Entering LONG at {self.entry_price} with SL: {self.sl}, TP: {self.tp}")
        elif action == 2: 
            if self.position == 0:
                self.position = -1
                self.entry_price = current_price
                self.sl = current_price * (1 + sl_percent)
                self.tp = current_price * (1 - tp_percent)
                self.current_trade = {
                    'entry_time': time,
                    'entry_price': current_price,
                    'type': 'SELL',
                    'stop_loss': self.sl,
                    'take_profit': self.tp,
                    'exit_time': None,
                    'exit_price': None,
                    'result': None
                }
                self.trade_history.append(self.current_trade)
                print(f"{time}: Entering SHORT at {self.entry_price} with SL: {self.sl}, TP: {self.tp}")
        elif action == 0:  # Hold
            pass  
        
        trade_closed = False
        
        if self.position == 1 and sma_short < sma_long:
            reward = current_price - self.entry_price
            self.balance += reward
            self.current_trade.update({
                'exit_time': time,
                'exit_price': current_price,
                'result': 'CROSSOVER'
            })
            print(f"{time}: Exiting LONG at {current_price}, Reward: {reward:.2f} (Crossover)")
            self.position = 0
            self.entry_price = 0.0
            self.sl = 0.0
            self.tp = 0.0
            trade_closed = True
        elif self.position == -1 and sma_short > sma_long:
            reward = self.entry_price - current_price
            self.balance += reward
            self.current_trade.update({
                'exit_time': time,
                'exit_price': current_price,
                'result': 'CROSSOVER'
            })
            print(f"{time}: Exiting SHORT at {current_price}, Reward: {reward:.2f} (Crossover)")
            self.position = 0
            self.entry_price = 0.0
            self.sl = 0.0
            self.tp = 0.0
            trade_closed = True
        
        if self.position == 1:
            if current_price <= self.sl:
                reward = current_price - self.entry_price
                self.balance += reward
                self.current_trade.update({
                    'exit_time': time,
                    'exit_price': self.sl,
                    'result': 'SL'
                })
                print(f"{time}: Stop Loss hit at {current_price} (LONG), Reward: {reward:.2f}")
                self.position = 0
                self.entry_price = 0.0
                self.sl = 0.0
                self.tp = 0.0
                trade_closed = True
            elif current_price >= self.tp:

                reward = self.tp - self.entry_price
                self.balance += reward
                self.current_trade.update({
                    'exit_time': time,
                    'exit_price': self.tp,
                    'result': 'TP'
                })
                print(f"{time}: Take Profit hit at {current_price} (LONG), Reward: {reward:.2f}")
                self.position = 0
                self.entry_price = 0.0
                self.sl = 0.0
                self.tp = 0.0
                trade_closed = True
        elif self.position == -1:
            if current_price >= self.sl:
                reward = self.entry_price - self.sl
                self.balance += reward
                self.current_trade.update({
                    'exit_time': time,
                    'exit_price': self.sl,
                    'result': 'SL'
                })
                print(f"{time}: Stop Loss hit at {current_price} (SHORT), Reward: {reward:.2f}")
                self.position = 0
                self.entry_price = 0.0
                self.sl = 0.0
                self.tp = 0.0
                trade_closed = True
            elif current_price <= self.tp:
                reward = self.entry_price - self.tp
                self.balance += reward
                self.current_trade.update({
                    'exit_time': time,
                    'exit_price': self.tp,
                    'result': 'TP'
                })
                print(f"{time}: Take Profit hit at {current_price} (SHORT), Reward: {reward:.2f}")
                self.position = 0
                self.entry_price = 0.0
                self.sl = 0.0
                self.tp = 0.0
                trade_closed = True
        
        reward -= 0.0001

        self.current_step += 1
        
        if self.current_step >= self.max_steps:
            done = True
        
        return self._get_observation(), reward, done, info

    def render(self, mode='human'):
        profit = self.balance - 10000
        print(f'Step: {self.current_step}')
        print(f'Balance: {self.balance:.2f}')
        print(f'Profit: {profit:.2f}')
        print(f'Position: {"Long" if self.position ==1 else "Short" if self.position == -1 else "None"}')
        print(f'Entry Price: {self.entry_price}')
        print(f'Stop Loss: {self.sl}')
        print(f'Take Profit: {self.tp}')

    def plot_trades(self):
        
        
        trades = pd.DataFrame(self.trade_history)
        
        fig, ax = plt.subplots(figsize=(15, 7) , dpi =1000)
        ax.plot(self.data['time'], self.data['close'], label='Close Price', alpha=0.5)
        ax.plot(self.data['time'], self.data['SMA_short'], label='SMA Short', alpha=0.9, linestyle='--')
        ax.plot(self.data['time'], self.data['SMA_long'], label='SMA Long', alpha=0.9, linestyle='--')
        
        for idx, trade in trades.iterrows():
            if trade['type'] == 'BUY':
                ax.scatter(trade['entry_time'], trade['entry_price'], marker='^', color='g', label='Buy Entry')
            else:
                ax.scatter(trade['entry_time'], trade['entry_price'], marker='v', color='r', label='Sell Entry')
            
            if trade['result'] == 'CROSSOVER':
                if trade['type'] == 'BUY':
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='o', color='b', label='Buy Exit (Crossover)')
                else:
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='o', color='c', label='Sell Exit (Crossover)')
            elif trade['result'] == 'SL':
                if trade['type'] == 'BUY':
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='x', color='k', label='Buy Stop Loss')
                else:
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='x', color='y', label='Sell Stop Loss')
            elif trade['result'] == 'TP':
                if trade['type'] == 'BUY':
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='x', color='m', label='Buy Take Profit')
                else:
                    ax.scatter(trade['exit_time'], trade['exit_price'], marker='x', color='orange', label='Sell Take Profit')
            
           
            entry_time = trade['entry_time']
            exit_time = trade['exit_time']
            if pd.isnull(entry_time) or pd.isnull(exit_time):
                continue 
            
            if trade['type'] == 'BUY':
                ax.hlines(y=trade['stop_loss'], xmin=entry_time, xmax=exit_time, colors='red', linestyles='--', linewidth=0.5, label='Stop Loss (Buy)')
                ax.hlines(y=trade['take_profit'], xmin=entry_time, xmax=exit_time, colors='green', linestyles='--', linewidth=0.5, label='Take Profit (Buy)')
            else:
                ax.hlines(y=trade['stop_loss'], xmin=entry_time, xmax=exit_time, colors='green', linestyles='--', linewidth=0.5, label='Stop Loss (Sell)')
                ax.hlines(y=trade['take_profit'], xmin=entry_time, xmax=exit_time, colors='red', linestyles='--', linewidth=0.5, label='Take Profit (Sell)')
    
        handles, labels = ax.get_legend_handles_labels()
        by_label = dict(zip(labels, handles))
        ax.legend(by_label.values(), by_label.keys())
        
        ax.set_xlabel('Time')
        ax.set_ylabel('Price')
        ax.set_title('Trade History with SL and TP Levels')
        plt.show()

env = MATradingEnv(symbol, timeframe, short_window, long_window)
model = PPO("MlpPolicy", env, verbose=1)

print("Starting training...")
model.learn(total_timesteps=10000)  
print("Training completed.")

model.save("ppo_mat_trading")
print("Model saved as 'ppo_mat_trading.zip'.")

obs = env.reset()
for _ in range(1000):
    action, _states = model.predict(obs, deterministic=True)
    obs, rewards, done, info = env.step(action)
    if done:
        break

env.plot_trades()

mt5.shutdown()