0% found this document useful (0 votes)
35 views

01_MichaelHarris_WinningPatterns.ipynb - Colab

Uploaded by

Trung Hòa
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views

01_MichaelHarris_WinningPatterns.ipynb - Colab

Uploaded by

Trung Hòa
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

01_MichaelHarris_WinningPatterns.

ipynb - Colab 24/11/24, 13:22

 1 - Import test data

import pandas as pd
import pandas_ta as ta
from tqdm import tqdm
import os
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

tqdm.pandas()

def read_csv_to_dataframe(file_path):
df = pd.read_csv(file_path)
df["Gmt time"] = df["Gmt time"].str.replace(".000", "")
df['Gmt time'] = pd.to_datetime(df['Gmt time'], format='%d.%m.%Y %H:%M:%S')
df = df[df.High != df.Low]
df.set_index("Gmt time", inplace=True)
return df

def read_data_folder(folder_path="./data"):
dataframes = []
file_names = []
for file_name in tqdm(os.listdir(folder_path)):
if file_name.endswith('.csv'):
file_path = os.path.join(folder_path, file_name)
df = read_csv_to_dataframe(file_path)
dataframes.append(df)
file_names.append(file_name)
return dataframes, file_names

def total_signal(df, current_candle):


current_pos = df.index.get_loc(current_candle)

c1 = df['High'].iloc[current_pos] > df['Close'].iloc[current_pos]


c2 = df['Close'].iloc[current_pos] > df['High'].iloc[current_pos-2]
c3 = df['High'].iloc[current_pos-2] > df['High'].iloc[current_pos-1]
c4 = df['High'].iloc[current_pos-1] > df['Low'].iloc[current_pos]
c5 = df['Low'].iloc[current_pos] > df['Low'].iloc[current_pos-2]
c6 = df['Low'].iloc[current_pos-2] > df['Low'].iloc[current_pos-1]

if c1 and c2 and c3 and c4 and c5 and c6:


return 2

# Add the symmetrical conditions for short (go short) if needed


c1 = df['Low'].iloc[current_pos] < df['Open'].iloc[current_pos]
https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 1 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

c1 = df['Low'].iloc[current_pos] < df['Open'].iloc[current_pos]


c2 = df['Open'].iloc[current_pos] < df['Low'].iloc[current_pos-2]
c3 = df['Low'].iloc[current_pos-2] < df['Low'].iloc[current_pos-1]
c4 = df['Low'].iloc[current_pos-1] < df['High'].iloc[current_pos]
c5 = df['High'].iloc[current_pos] < df['High'].iloc[current_pos-2]
c6 = df['High'].iloc[current_pos-2] < df['High'].iloc[current_pos-1]

if c1 and c2 and c3 and c4 and c5 and c6:


return 1

return 0

def add_total_signal(df):
df['TotalSignal'] = df.progress_apply(lambda row: total_signal(df, row.name), a
return df

def add_pointpos_column(df, signal_column):


"""
Adds a 'pointpos' column to the DataFrame to indicate the position of support a

Parameters:
df (DataFrame): DataFrame containing the stock data with the specified SR colum
sr_column (str): The name of the column to consider for the SR (support/resista

Returns:
DataFrame: The original DataFrame with an additional 'pointpos' column.
"""
def pointpos(row):
if row[signal_column] == 2:
return row['Low'] - 1e-4
elif row[signal_column] == 1:
return row['High'] + 1e-4
else:
return np.nan

df['pointpos'] = df.apply(lambda row: pointpos(row), axis=1)


return df

def plot_candlestick_with_signals(df, start_index, num_rows):


"""
Plots a candlestick chart with signal points.

Parameters:
df (DataFrame): DataFrame containing the stock data with 'Open', 'High', 'Low',
start_index (int): The starting index for the subset of data to plot.
num_rows (int): The number of rows of data to plot.

Returns:
None
https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 2 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

None
"""
df_subset = df[start_index:start_index + num_rows]

fig = make_subplots(rows=1, cols=1)

fig.add_trace(go.Candlestick(x=df_subset.index,
open=df_subset['Open'],
high=df_subset['High'],
low=df_subset['Low'],
close=df_subset['Close'],
name='Candlesticks'),
row=1, col=1)

fig.add_trace(go.Scatter(x=df_subset.index, y=df_subset['pointpos'], mode="mark


marker=dict(size=10, color="MediumPurple", symbol='cir
name="Entry Points"),
row=1, col=1)

fig.update_layout(
width=1200,
height=800,
plot_bgcolor='black',
paper_bgcolor='black',
font=dict(color='white'),
xaxis=dict(showgrid=False, zeroline=False),
yaxis=dict(showgrid=False, zeroline=False),
showlegend=True,
legend=dict(
x=0.01,
y=0.99,
traceorder="normal",
font=dict(
family="sans-serif",
size=12,
color="white"
),
bgcolor="black",
bordercolor="gray",
borderwidth=2
)
)

fig.show()

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 3 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

folder_path = "./data_forex"
dataframes, file_names = read_data_folder(folder_path)

for i, df in enumerate(dataframes):
print("working on dataframe ", i, "...")
df = add_total_signal(df)
df = add_pointpos_column(df, "TotalSignal")
dataframes[i] = df # Update the dataframe in the list

100%|██████████| 7/7 [00:00<00:00, 107.98it/s]


working on dataframe 0 ...
100%|██████████| 2197/2197 [00:00<00:00, 8472.59it/s]
working on dataframe 1 ...
100%|██████████| 2197/2197 [00:00<00:00, 8605.00it/s]
working on dataframe 2 ...
100%|██████████| 2196/2196 [00:00<00:00, 8468.74it/s]
working on dataframe 3 ...
100%|██████████| 2195/2195 [00:00<00:00, 8597.16it/s]
working on dataframe 4 ...
100%|██████████| 2197/2197 [00:00<00:00, 8604.85it/s]
working on dataframe 5 ...
100%|██████████| 2197/2197 [00:00<00:00, 8471.94it/s]
working on dataframe 6 ...
100%|██████████| 2184/2184 [00:00<00:00, 8487.76it/s]

sum([frame["TotalSignal"].value_counts() for frame in dataframes], start=0)

TotalSignal
0 15208.0
1 NaN
2 154.0
Name: count, dtype: float64

plot_candlestick_with_signals(dataframes[0], start_index=300, num_rows=355)

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 4 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

from backtesting import Strategy


from backtesting import Backtest

def SIGNAL():
return df.TotalSignal

class MyStrat(Strategy):
mysize = 0.1 # Trade size
slperc = 0.04
tpperc = 0.02

def init(self):
super().init()
self.signal1 = self.I(SIGNAL) # Assuming SIGNAL is a function that returns

def next(self):
super().next()

if self.signal1 == 2 and not self.position:


# Open a new long position with calculated SL and TP
current_close = self.data.Close[-1]
sl = current_close - self.slperc * current_close # SL at 4% below the
tp = current_close + self.tpperc * current_close # TP at 2% above the
self.buy(size=self.mysize, sl=sl, tp=tp)

# elif self.signal1 == 1 and not self.position:


# # Open a new short position, setting SL based on a strategy-specific
# current_close = self.data.Close[-1]
# sl = current_close + self.slperc * current_close # SL at 4% below th
# tp = current_close - self.tpperc * current_close # TP at 2% above th
# self.sell(size=self.mysize, sl=sl, tp=tp)

f:\Python\Lib\site-packages\tqdm\auto.py:21: TqdmWarning:

IProgress not found. Please update jupyter and ipywidgets. See https://ipywidge

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 5 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

results = []
heatmaps = []

for df in dataframes:
bt = Backtest(df, MyStrat, cash=5000, margin=1/5, commission=0.0002)
stats, heatmap = bt.optimize(slperc=[i/100 for i in range(1, 8)],
tpperc=[i/100 for i in range(1, 8)],
maximize='Return [%]', max_tries=3000,
random_state=0,
return_heatmap=True)
results.append(stats)
heatmaps.append(heatmap)

agg_returns = sum([r["Return [%]"] for r in results])


num_trades = sum([r["# Trades"] for r in results])
max_drawdown = min([r["Max. Drawdown [%]"] for r in results])
avg_drawdown = sum([r["Avg. Drawdown [%]"] for r in results]) / len(results)

win_rate = sum([r["Win Rate [%]"] for r in results]) / len(results)


best_trade = max([r["Best Trade [%]"] for r in results])
worst_trade = min([r["Worst Trade [%]"] for r in results])
avg_trade = sum([r["Avg. Trade [%]"] for r in results]) / len(results)
#max_trade_duration = max([r["Max. Trade Duration"] for r in results])
#avg_trade_duration = sum([r["Avg. Trade Duration"] for r in results]) / len(result

print(f"Aggregated Returns: {agg_returns:.2f}%")


print(f"Number of Trades: {num_trades}")
print(f"Maximum Drawdown: {max_drawdown:.2f}%")
print(f"Average Drawdown: {avg_drawdown:.2f}%")
print(f"Win Rate: {win_rate:.2f}%")
print(f"Best Trade: {best_trade:.2f}%")
print(f"Worst Trade: {worst_trade:.2f}%")
print(f"Average Trade: {avg_trade:.2f}%")
#print(f"Maximum Trade Duration: {max_trade_duration} days")
#print(f"Average Trade Duration: {avg_trade_duration:.2f} days")

Aggregated Returns: 27.34%


Number of Trades: 92
Maximum Drawdown: -7.14%
Average Drawdown: -1.08%
Win Rate: 55.87%
Best Trade: 6.98%
Worst Trade: -7.02%
Average Trade: 0.75%

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 6 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

equity_curves = [stats['_equity_curve']['Equity'] for stats in results]


max_length = max(len(equity) for equity in equity_curves)

# Pad each equity curve with the last value to match the maximum length
padded_equity_curves = []
for equity in equity_curves:
last_value = equity.iloc[-1]
padding = [last_value] * (max_length - len(equity))
padded_equity = equity.tolist() + padding
padded_equity_curves.append(padded_equity)

equity_df = pd.DataFrame(padded_equity_curves).T

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 7 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

import matplotlib.pyplot as plt

equity_df.plot(kind='line', figsize=(10, 6), legend=True).set_facecolor('black')


plt.gca().spines['bottom'].set_color('black')
plt.gca().spines['left'].set_color('black')
plt.gca().tick_params(axis='x', colors='black')
plt.gca().tick_params(axis='y', colors='black')
plt.gca().set_facecolor('black')
plt.legend(file_names)

<matplotlib.legend.Legend at 0x289b7409290>
5800
AUDUSD_Candlestick_1_D_BID_06.06.2017-15.06.2024.csv
EURUSD_Candlestick_1_D_BID_06.06.2017-15.06.2024.CSV
GBPUSD_Candlestick_1_D_BID_06.06.2017-15.06.2024.csv
5600- NZDUSD_Candlestick_1_D_BID_06.06.2017-15.06.2024.CSV
USDCHF_Candlestick_1D_BID_06.06.2017-15.06.2024.CSV
USDJPY_Candlestick_1_D_BID_06.06.2017-15.06.2024.cSV
XAUUSD_Candlestick_1_D_BID_06.06.2017-15.06.2024.csv
5400-

5200-

5000

4800-

500 1000 1500

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 8 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

[r["Return [%]"] for r in results]

[3.0818825046799976,
-2.5188213194800118,
13.53912743511999,
-1.5689230771600342,
3.6504297886800483,
10.508764060000031,
0.6493776159999834]

names

['QQQ.USUSD_Candlestick_1_D_BID_26.01.2017-06.07.2024.csv',
'SPY.USUSD_Candlestick_1_D_BID_16.02.2017-06.07.2024.csv',
'VXX.USUSD_Candlestick_1_D_BID_16.02.2017-06.07.2024.csv']

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 9 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

import seaborn as sns


import matplotlib.pyplot as plt

# Convert multiindex series to dataframe


heatmap_df = heatmaps[1].unstack()
plt.figure(figsize=(10, 8))
sns.heatmap(heatmap_df, annot=True, cmap='viridis', fmt='.0f')
plt.show()

-0 7 10 15 20 19

2 7 12 12 17 20 21

3 13 19 22 22 24 31
s/perc

4
3 11 16 18 19 21 27

2 11 14 15 17 19 25

6 17 20 26 31 30 33

8 23 28 38 42 39 48

0.01 0.02 0.03 0.04 0.05 0.06 0.07


tpperc

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 10 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

results[1]

Start 2017-02-16 00:00:00


End 2024-07-05 00:00:00
Duration 2696 days 00:00:00
Exposure Time [%] 59.450727
Equity Final [$] 7392.299264
Equity Peak [$] 7392.299264
Return [%] 47.845985
Buy & Hold Return [%] 136.312126
Return (Ann.) [%] 5.44928
Volatility (Ann.) [%] 5.126902
Sharpe Ratio 1.06288
Sortino Ratio 1.604569
Calmar Ratio 0.473129
Max. Drawdown [%] -11.517527
Avg. Drawdown [%] -0.650602
Max. Drawdown Duration 695 days 00:00:00
Avg. Drawdown Duration 20 days 00:00:00
# Trades 20
Win Rate [%] 80.0
Best Trade [%] 8.383023
Worst Trade [%] -7.555252
Avg. Trade [%] 4.122038
Max. Trade Duration 219 days 00:00:00
Avg. Trade Duration 79 days 00:00:00
Profit Factor 4.241353
Expectancy [%] 4.273493
SQN 3.184003
_strategy MyStrat(slperc=0...
_equity_curve ...
_trades Size EntryB...
dtype: object

Start coding or generate with AI.

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 11 of 12
01_MichaelHarris_WinningPatterns.ipynb - Colab 24/11/24, 13:22

https://colab.research.google.com/drive/1kU07kZymWt1_E0eI3J8GGO5FCCTsk-YO#scrollTo=EfJaT46L0bCu Page 12 of 12

You might also like