from this script : # -*- coding: utf-8 -*-
"""EURUSD_SR_WITH_CANDLES_Backtesting.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1g-syOO2ong6jScRaLr7xxThR1PvJVZxo

# Resistance/Support AND Candles Patterns
"""

import pandas as pd
df = pd.read_csv("C:\\Users\\rozzy\\data_mt5.csv")

#Check if NA values are in data
df=df[df['tick_volume']!=0]
df.drop(['spread', 'real_volume'], axis=1, inplace=True)
df.reset_index(drop=True, inplace=True)
df.isna().sum()
df.tail()

"""# Support and Resistance FUNCTIONS"""

def support(df1, l, n1, n2): #n1 n2 before and after candle l
    for i in range(l-n1+1, l+1):
        if(df1.low[i]>df1.low[i-1]):
            return 0
    for i in range(l+1,l+n2+1):
        if(df1.low[i]<df1.low[i-1]):
            return 0
    return 1

def resistance(df1, l, n1, n2): #n1 n2 before and after candle l
    for i in range(l-n1+1, l+1):
        if(df1.high[i]<df1.high[i-1]):
            return 0
    for i in range(l+1,l+n2+1):
        if(df1.high[i]>df1.high[i-1]):
            return 0
    return 1

length = len(df)
high = list(df['high'])
low = list(df['low'])
close = list(df['close'])
open = list(df['open'])
bodydiff = [0] * length

highdiff = [0] * length
lowdiff = [0] * length
ratio1 = [0] * length
ratio2 = [0] * length

def isEngulfing(l):
    row=l
    bodydiff[row] = abs(open[row]-close[row])
    if bodydiff[row]<0.000001:
        bodydiff[row]=0.000001

    bodydiffmin = 0.002
    if (bodydiff[row]>bodydiffmin and bodydiff[row-1]>bodydiffmin and
        open[row-1]<close[row-1] and
        open[row]>close[row] and
        (open[row]-close[row-1])>=-0e-5 and close[row]<open[row-1]): #+0e-5 -5e-5
        return 1

    elif(bodydiff[row]>bodydiffmin and bodydiff[row-1]>bodydiffmin and
        open[row-1]>close[row-1] and
        open[row]<close[row] and
        (open[row]-close[row-1])<=+0e-5 and close[row]>open[row-1]):#-0e-5 +5e-5
        return 2
    else:
        return 0

def isStar(l):
    bodydiffmin = 0.0020
    row=l
    highdiff[row] = high[row]-max(open[row],close[row])
    lowdiff[row] = min(open[row],close[row])-low[row]
    bodydiff[row] = abs(open[row]-close[row])
    if bodydiff[row]<0.000001:
        bodydiff[row]=0.000001
    ratio1[row] = highdiff[row]/bodydiff[row]
    ratio2[row] = lowdiff[row]/bodydiff[row]

    if (ratio1[row]>1 and lowdiff[row]<0.2*highdiff[row] and bodydiff[row]>bodydiffmin):# and open[row]>close[row]):
        return 1
    elif (ratio2[row]>1 and highdiff[row]<0.2*lowdiff[row] and bodydiff[row]>bodydiffmin):# and open[row]<close[row]):
        return 2
    else:
        return 0

def closeResistance(l,levels,lim):
    if len(levels)==0:
        return 0
    c1 = abs(df.high[l]-min(levels, key=lambda x:abs(x-df.high[l])))<=lim
    c2 = abs(max(df.open[l],df.close[l])-min(levels, key=lambda x:abs(x-df.high[l])))<=lim
    c3 = min(df.open[l],df.close[l])<min(levels, key=lambda x:abs(x-df.high[l]))
    c4 = df.low[l]<min(levels, key=lambda x:abs(x-df.high[l]))
    if( (c1 or c2) and c3 and c4 ):
        return 1
    else:
        return 0

def closeSupport(l,levels,lim):
    if len(levels)==0:
        return 0
    c1 = abs(df.low[l]-min(levels, key=lambda x:abs(x-df.low[l])))<=lim
    c2 = abs(min(df.open[l],df.close[l])-min(levels, key=lambda x:abs(x-df.low[l])))<=lim
    c3 = max(df.open[l],df.close[l])>min(levels, key=lambda x:abs(x-df.low[l]))
    c4 = df.high[l]>min(levels, key=lambda x:abs(x-df.low[l]))
    if( (c1 or c2) and c3 and c4 ):
        return 1
    else:
        return 0

n1=2
n2=2
backCandles=30
signal = [0] * length

for row in range(backCandles, len(df)-n2):
    ss = []
    rr = []
    for subrow in range(row-backCandles+n1, row+1):
        if support(df, subrow, n1, n2):
            ss.append(df.low[subrow])
        if resistance(df, subrow, n1, n2):
            rr.append(df.high[subrow])
    #!!!! parameters
    if ((isEngulfing(row)==1 or isStar(row)==1) and closeResistance(row, rr, 150e-5) ):#and df.RSI[row]<30
        signal[row] = 1
    elif((isEngulfing(row)==2 or isStar(row)==2) and closeSupport(row, ss, 150e-5)):#and df.RSI[row]>70
        signal[row] = 2
    else:
        signal[row] = 0

df['signal']=signal

df[df['signal']==2].count()

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

def SIGNAL():
    return df.signal

#A new strategy needs to extend Strategy class and override its two abstract methods: init() and next().
#Method init() is invoked before the strategy is run. Within it, one ideally precomputes in efficient,
#vectorized manner whatever indicators and signals the strategy depends on.
#Method next() is then iteratively called by the Backtest instance, once for each data point (data frame row),
#simulating the incremental availability of each new full candlestick bar.

#Note, backtesting.py cannot make decisions / trades within candlesticks — any new orders are executed on the
#next candle's open (or the current candle's close if trade_on_close=True).
#If you find yourself wishing to trade within candlesticks (e.g. daytrading), you instead need to begin
#with more fine-grained (e.g. hourly) data.

from backtesting import Strategy

class MyCandlesStrat(Strategy):
    def init(self):
        super().init()
        self.signal1 = self.I(SIGNAL)

    def next(self):
        super().next()
        if self.signal1==2:
            sl1 = self.data.Close[-1] - 750e-4
            tp1 = self.data.Close[-1] + 600e-4
            self.buy(sl=sl1, tp=tp1)
        elif self.signal1==1:
            sl1 = self.data.Close[-1] + 750e-4
            tp1 = self.data.Close[-1] - 600e-4
            self.sell(sl=sl1, tp=tp1)

from backtesting import Backtest

bt = Backtest(df, MyCandlesStrat, cash=10_000, commission=.002)
stat = bt.run()
stat

bt.plot()

,,, pahami logika dari script sebelum ini , dan samakan logika nya dengan script berikut karena script berikut masih belum tepat dan memiliki kesalahan,perbaiki kesalahan tersebut dengan tepat dan lengkap : 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, 5000)
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.loc[:, 'long_signal'] = pd.Series(np.append([False], long_signal), index=df.index)
    df.loc[:, 'short_signal'] = pd.Series(np.append([False], short_signal), index=df.index)
    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)