-
Notifications
You must be signed in to change notification settings - Fork 3
/
macd_example.py
149 lines (120 loc) · 5.19 KB
/
macd_example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import logging
import numpy as np
import pandas as pd
from mikasa import BT, DataSeries, MACDIndicator
import ccxt
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
exchange = ccxt.binance()
# create strategy for backtesting
class MACDBT(BT):
trade_amount = 0.005
indicators = [MACDIndicator()]
def add_indicators(self, indicators=None):
self.dataseries.add_indicators(indicators=self.indicators)
if indicators is not None:
self.dataseries.add_indicators(indicators=indicators)
# set up how to process each bar
def process_bar(self):
d = self.dataseries
if np.isnan(d[0].macd):
return
if d[0].macd > 0 > d[-1].macd:
self.buy(d[0].close, self.get_trade_amount(d[0].close))
class HyperSearch:
result = []
def get_best_run(self):
best_run = sorted(self.result, key=lambda x: x[0])[-1]
return best_run
def get_params(self):
return {
"pair": ["BTC/USDT", "ETH/USDT"],
"timeperiod": ["5m", "1h", "1d"],
"macd": {"short_period": range(2, 12), "long_period": range(3, 30), "signal_period": range(4, 16)},
}
def run(self):
params = self.get_params()
for pair in params["pair"]:
for timeperiod in params["timeperiod"]:
ohlcv = exchange.fetch_ohlcv(pair, timeframe=timeperiod, limit=300)
df = pd.DataFrame(ohlcv, columns=["datetime", "open", "high", "low", "close", "volume"])
df["datetime"] = pd.to_datetime(df["datetime"], unit="ms")
macd_params = params["macd"]
# create DataSeries instance
for short_period in macd_params["short_period"]:
for long_period in macd_params["long_period"]:
for signal_period in macd_params["signal_period"]:
logger.info(
f"Backtesting params: {pair=} {timeperiod=}"
f" {short_period=} {long_period=} {signal_period=}"
)
ds = DataSeries(df)
bt = MACDBT(ds, balance=1000.0, verbose=False)
bt.add_indicators(
indicators=[
MACDIndicator(
short_period=short_period,
long_period=long_period,
signal_period=signal_period,
)
]
)
# run backtesting
bt.run()
logger.info(f"Profit: ${bt.get_profit():.2f}")
logger.info(f"ROI: ${bt.get_roi() * 100:.2f}%")
self.result.append(
(
bt.get_roi(),
bt.get_profit(),
{
"pair": pair,
"timeperiod": timeperiod,
"macd": {
"short_period": short_period,
"long_period": long_period,
"signal_period": signal_period,
},
},
)
)
def backtest_best_run(short_period, long_period, signal_period):
# upload and map data from CSV
ohlcv = exchange.fetch_ohlcv(
best_params["pair"],
timeframe=best_params["timeperiod"],
limit=300,
)
df = pd.DataFrame(ohlcv, columns=["datetime", "open", "high", "low", "close", "volume"])
df["datetime"] = pd.to_datetime(df["datetime"], unit="ms")
# create DataSeries instance
ds = DataSeries(df)
bt = MACDBT(ds, balance=1000.0)
bt.add_indicators(
indicators=[
MACDIndicator(
short_period=short_period,
long_period=long_period,
signal_period=signal_period,
)
]
)
# run backtesting
bt.run()
logger.info(f"Profit: ${bt.get_profit():.2f}")
logger.info(f"ROI: ${bt.get_roi() * 100:.2f}%")
# plot data and indicators
bt.plot(title=f'{best_params["pair"]} ({best_params["timeperiod"]})')
if __name__ == "__main__":
hyper_search = HyperSearch()
hyper_search.run()
best_run = hyper_search.get_best_run()
logger.info(f"Best run: profit={best_run[1]:.2f}")
logger.info(f"Best run: ROI={best_run[0] * 100.:.2f}")
best_params = best_run[2]
logger.info(f"Best params: {best_run=}")
macd_best_params = best_params["macd"]
short_period = macd_best_params["short_period"]
long_period = macd_best_params["long_period"]
signal_period = macd_best_params["signal_period"]
backtest_best_run(short_period, long_period, signal_period)