0% found this document useful (0 votes)
56 views12 pages

01 - MichaelHarris - WinningPatterns - Ipynb - Colab

Uploaded by

Trung Hòa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
56 views12 pages

01 - MichaelHarris - WinningPatterns - Ipynb - Colab

Uploaded by

Trung Hòa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
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