import numpy as np
import pandas as pd
from backtesting import Strategy, Backtest
import talib
import MetaTrader5 as mt5

if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    mt5.shutdown()

symbol = 'XAUUSDm'
timeframe = mt5.TIMEFRAME_M5
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 10000)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
df.set_index('time', inplace=True)
df.drop(['spread', 'real_volume'], axis=1, inplace=True)   
print(df)

def macd(df):
    df = df.copy()
    macd, signal, hist = talib.MACD(df['close'], fastperiod=12, slowperiod=26, signalperiod=9)  # Corrected
    if macd.iloc[-1] > signal.iloc[-1]:
        return "Buy"
    elif macd.iloc[-1] < signal.iloc[-1]:
        return "Sell"
        
def twin_range_filter(df):
    df = df.copy()
    close = df['close']
    def smoothrng(x, t, m):
        wper = t * 2 - 1
        avrng = talib.EMA(np.abs(x.diff()), timeperiod=t)
        smoothrng = talib.EMA(avrng, timeperiod=wper) * m
        return smoothrng
    per1, mult1, per2, mult2 = 27, 1.6, 55, 2.0
    smrng1 = smoothrng(close, per1, mult1)
    smrng2 = smoothrng(close, per2, mult2)
    smrng = (smrng1 + smrng2) / 2
    def rngfilt(x, r):
        rngfilt = x.copy()
        for i in range(1, len(x)):
            prev_val = rngfilt.iloc[i-1]
            if x.iloc[i] > prev_val:
                rngfilt.iloc[i] = max(prev_val, x.iloc[i] - r.iloc[i])
            else:
                rngfilt.iloc[i] = min(prev_val, x.iloc[i] + r.iloc[i])
        return rngfilt
    filt = rngfilt(close, smrng)
    STR = filt + smrng
    STS = filt - smrng
    FUB = [STR.iloc[0]]
    FLB = [STS.iloc[0]]
    for i in range(1, len(df)):
        FUB.append(STR.iloc[i] if (STR.iloc[i] < STR.iloc[i-1]) or (close.iloc[i-1] > FUB[i-1]) else FUB[i-1])
        FLB.append(STS.iloc[i] if (STS.iloc[i] > STS.iloc[i-1]) or (close.iloc[i-1] < FLB[i-1]) else FLB[i-1])
    FUB = np.array(FUB)
    FLB = np.array(FLB)
    TRF = [FUB[0]]
    for i in range(1, len(df)):
        last_trf = TRF[-1]
        if (last_trf == FUB[i-1] and close.iloc[i] <= FUB[i]) or (last_trf == FLB[i-1] and close.iloc[i] <= FLB[i]):
            TRF.append(FUB[i])
        elif (last_trf == FUB[i-1] and close.iloc[i] >= FUB[i]) or (last_trf == FLB[i-1] and close.iloc[i] >= FLB[i]):
            TRF.append(FLB[i])
        else:
            TRF.append(FUB[i])
    TRF = np.array(TRF)
    long_signal = (close > np.roll(TRF, 1))[1:]
    short_signal = (close < np.roll(TRF, 1))[1:]
    df['TRF'] = TRF
    df['long_signal'] = np.append([False], long_signal)
    df['short_signal'] = np.append([False], short_signal)
    if df.iloc[-1]['long_signal']:
        return "Buy"
    elif df.iloc[-1]['short_signal']:
        return "Sell"
    
def detect_engulfing(df):
    df = df.copy()
    for i in range(1, len(df)):
        current = df.iloc[i].copy()
        previous = df.iloc[i-1].copy()
        if np.abs(current['open'] - previous['close']) > 0.005:
            current['open'] = previous['close']
        if previous['open'] > previous['close'] and \
        current['close'] > current['open'] and \
        current['close'] >= previous['open'] and \
        previous['close'] >= current['open'] and \
        current['close'] - current['open'] > previous['open'] - previous['close']:
            return "Buy"
        elif previous['close'] > previous['open'] and \
        current['open'] > current['close'] and \
        current['open'] >= previous['close'] and \
        previous['open'] >= current['close'] and \
        current['open'] - current['close'] > previous['close'] - previous['open']:
            return "Sell"
        else:
            return None
        
df['signal'] = None

for row in range(len(df)):
    macd_signal = macd(df.iloc[:row+1])
    trf_signal = twin_range_filter(df.iloc[:row+1])
    engulfing_signal = detect_engulfing(df.iloc[:row+1])

    if macd_signal == "Sell" and trf_signal == "Buy" and engulfing_signal == "Buy":
        df.at[row, 'signal'] = 1 
    elif macd_signal == "Buy" and trf_signal == "Sell" and engulfing_signal == "Sell":
        df.at[row, 'signal'] = 2
    else:
        df.at[row, 'signal'] = 0

count_sell_signals = df[df['signal'] == 2].shape[0]
print("Jumlah sinyal sell:", count_sell_signals)

df.columns = ['Local time', 'Open', 'High', 'Low', 'Close', 'Volume', 'signal']
df = df.iloc[100:200]
print(df)

# class ChubbStrategy(Strategy):
#     def init(self):
#         self.macd_signal = self.I(self.macd)
#         self.trf_signal = self.I(self.twin_range_filter)
#         self.engulfing_signal = self.I(self.detect_engulfing)
        
#     def next(self):
#         # Check for bullish engulfing condition
#         if self.macd_signal == "Sell" and self.trf_signal == "Buy" and self.engulfing_signal == "Bullish Engulfing":
#             self.buy()

#         # Check for bearish engulfing condition
#         elif self.macd_signal == "Buy" and self.trf_signal == "Sell" and self.engulfing_signal == "Bearish Engulfing":
#             self.sell()


# bt = Backtest(df, ChubbStrategy, cash=10000, commission=0.0)

# # Run the backtest
# stats = bt.run()

# # Print the performance statistics
# print(stats)