Revision | 0627e54111783317fc221b1997836a81e6466750 (tree) |
---|---|
Time | 2023-02-11 11:48:53 |
Author | kazuhiro_kondow <simauma.circus@gmai...> |
Commiter | kazuhiro_kondow |
macdについてcrossoverの角度要素を検討
@@ -0,0 +1,64 @@ | ||
1 | +import MetaTrader5 as mt5 | |
2 | +import datetime as dt | |
3 | +import pytz | |
4 | + | |
5 | + | |
6 | +cp = 'USDJPY' | |
7 | +mt5.initialize() | |
8 | +mt5.copy_rates_from_pos(cp, mt5.TIMEFRAME_M1, 0, 1) | |
9 | + | |
10 | +# 日本時間の8:58に取得 | |
11 | +# array([(1675994280, 131.517, 131.518, 131.516, 131.516, 6, 3, 0)], | |
12 | +# dtype=[('time', '<i8'), ('open', '<f8'), ('high', '<f8'), ('low', '<f8'), ('close', '<f8'), ('tick_volume', '<u8'), ('spread', '<i4'), ('real_volume', '<u8')]) | |
13 | + | |
14 | +# ローカルタイムスタンプとして扱うと2時間ずれる | |
15 | +dt.datetime.fromtimestamp(1675994280) | |
16 | +# datetime.datetime(2023, 2, 10, 10, 58) | |
17 | + | |
18 | +# UTCとして扱うとこのようになる | |
19 | +dt.datetime.utcfromtimestamp(1675994280) | |
20 | +# datetime.datetime(2023, 2, 10, 1, 58) | |
21 | + | |
22 | +# なので以下のようにして日本時間に変換する | |
23 | +# 日本のtimezone | |
24 | +tz_local = pytz.timezone('Etc/GMT-9') | |
25 | +# OANDAサーバのtimezone | |
26 | +tz_oanda = pytz.timezone('Etc/GMT-2') | |
27 | + | |
28 | +tz_oanda.localize(dt.datetime.utcfromtimestamp(1675994280)) | |
29 | +# datetime.datetime(2023, 2, 10, 1, 58, tzinfo=<StaticTzInfo 'Etc/GMT-2'>) | |
30 | + | |
31 | +tz_oanda.localize(dt.datetime.utcfromtimestamp(1675994280)).astimezone(tz_local) | |
32 | +# datetime.datetime(2023, 2, 10, 8, 58, tzinfo=<StaticTzInfo 'Etc/GMT-9'>) | |
33 | + | |
34 | +# dataframeの場合は次の通り | |
35 | + | |
36 | +local_to = dt.datetime( | |
37 | + now.year, | |
38 | + now.month, | |
39 | + now.day, | |
40 | + 0, | |
41 | + 0, | |
42 | + 0, | |
43 | + tzinfo=tz_local | |
44 | +) | |
45 | +local_from = local_to - dt.timedelta(days=30) | |
46 | + | |
47 | +rate_to = local_to.astimezone(tz_oanda) | |
48 | +rate_from = local_from.astimezone(tz_oanda) | |
49 | + | |
50 | +# レートを取得 | |
51 | +cp = 'USDJPY' | |
52 | +mt5.initialize() | |
53 | +rates = mt5.copy_rates_range(cp, mt5.TIMEFRAME_M1, rate_from, rate_to) | |
54 | + | |
55 | +df = pd.DataFrame(rates) | |
56 | + | |
57 | +# timeカラムをdatetime型に変換 | |
58 | +df.time = pd.to_datetime(df['time'], unit='s') | |
59 | +# timeカラムをindexに時系列インデックスとして割り当て | |
60 | +df.index = pd.DatetimeIndex(df.time, name='Date') | |
61 | +# インデックスのTimeZoneをUTCに設定 | |
62 | +df.index = df.index.tz_localize(dt.timezone.utc) | |
63 | +# インデックスのTimeZoneをLovalに変換 | |
64 | +df.index = df.index.tz_convert(tz_local) |
@@ -0,0 +1,247 @@ | ||
1 | +# 元ネタ | |
2 | +# https://qiita.com/Fujinoinvestor/items/780b138e441531860e60 | |
3 | + | |
4 | +# crossoverにangle要素を追加してどのように結果が変わるか検証する | |
5 | +# 比較対象はbacktesting_fx_M1_2.pyの結果 | |
6 | +# UserWarning: Searching for best of 7200 configurations. | |
7 | +# Processing time: 11776.894 | |
8 | +# Start 2022-10-04 03:57:00 | |
9 | +# End 2022-12-30 23:54:00 | |
10 | +# Duration 87 days 19:57:00 | |
11 | +# Exposure Time [%] 85.284329 | |
12 | +# Equity Final [$] 10644.792312 | |
13 | +# Equity Peak [$] 10896.238091 | |
14 | +# Return [%] 6.447923 | |
15 | +# Buy & Hold Return [%] -9.405472 | |
16 | +# Return (Ann.) [%] 26.162524 | |
17 | +# Volatility (Ann.) [%] 10.079171 | |
18 | +# Sharpe Ratio 2.595702 | |
19 | +# Sortino Ratio 5.504483 | |
20 | +# Calmar Ratio 7.157977 | |
21 | +# Max. Drawdown [%] -3.655017 | |
22 | +# Avg. Drawdown [%] -0.110736 | |
23 | +# Max. Drawdown Duration 22 days 13:17:00 | |
24 | +# Avg. Drawdown Duration 0 days 06:13:00 | |
25 | +# # Trades 871 | |
26 | +# Win Rate [%] 22.962113 | |
27 | +# Best Trade [%] 0.540564 | |
28 | +# Worst Trade [%] -0.085376 | |
29 | +# Avg. Trade [%] 0.010165 | |
30 | +# Max. Trade Duration 3 days 01:51:00 | |
31 | +# Avg. Trade Duration 0 days 02:23:00 | |
32 | +# Profit Factor 1.167371 | |
33 | +# Expectancy [%] 0.01031 | |
34 | +# SQN 1.276678 | |
35 | +# _strategy MACDCross4(n1=28... | |
36 | +# _equity_curve ... | |
37 | +# _trades Size Entry... | |
38 | +# MACDCross4(n1=28,n2=53,ns=15) | |
39 | + | |
40 | +import os | |
41 | +import talib as ta | |
42 | +from backtesting.lib import crossover | |
43 | +from backtesting import Backtest | |
44 | +from backtesting import Strategy | |
45 | +import pandas as pd | |
46 | +import time | |
47 | + | |
48 | +# 現在ディレクトリ取得 | |
49 | +cwd = os.getcwd() | |
50 | + | |
51 | +# get data | |
52 | +data_path = os.path.join( | |
53 | + cwd, | |
54 | + 'csv', | |
55 | + 'USDJPY_M1_202210040357_202212302354.csv' | |
56 | +) | |
57 | + | |
58 | +# csvがtab区切りなのでreat_tableを使う | |
59 | +df = pd.read_table( | |
60 | + data_path | |
61 | +) | |
62 | + | |
63 | +# DataFrameのカラム名をbacktesting向けに修正 | |
64 | +df = df.rename( | |
65 | + columns={ | |
66 | + "<DATE>": "Date", | |
67 | + "<TIME>": "Time", | |
68 | + "<OPEN>": "Open", | |
69 | + "<HIGH>": "High", | |
70 | + "<LOW>": "Low", | |
71 | + "<CLOSE>": "Close", | |
72 | + "<TICKVOL>": "Volume", | |
73 | + "<VOL>": "not_use", | |
74 | + "<SPREAD>": "Spread", | |
75 | + } | |
76 | +) | |
77 | + | |
78 | +# 日付に時間文字列を結合 | |
79 | +df.Date = df['Date'] + ' ' + df['Time'] | |
80 | + | |
81 | +# Dateカラムをdatetime型に変換 | |
82 | +df.Date = pd.to_datetime(df['Date'], format='%Y.%m.%d %H:%M:%S') | |
83 | + | |
84 | +# indexをDateカラムに設定 | |
85 | +df = df.set_index('Date') | |
86 | + | |
87 | +# 必要なカラムのみ取得 | |
88 | +data = df.loc[:, ['Open', 'High', 'Low', 'Close', 'Volume']] | |
89 | + | |
90 | + | |
91 | +def MACD(close, n1, n2, ns): | |
92 | + macd, macdsignal, macdhist = ta.MACD( | |
93 | + close, fastperiod=n1, slowperiod=n2, signalperiod=ns) | |
94 | + return macd, macdsignal | |
95 | + | |
96 | + | |
97 | +# 下記記事を参考にStrategyを修正 | |
98 | +# https://mmorley.hatenablog.com/entry/fx_backtesting01 | |
99 | + | |
100 | +class MACDCross(Strategy): | |
101 | + # 短期EMAの期間 | |
102 | + n1 = 28 | |
103 | + # 長期EMAの期間 | |
104 | + n2 = 53 | |
105 | + # シグナル(MACDのSMA)の期間 | |
106 | + ns = 15 | |
107 | + # angleの閾値 | |
108 | + crossover_angle = 0.5 | |
109 | + | |
110 | + def init(self): | |
111 | + self.macd, self.macdsignal = self.I( | |
112 | + MACD, self.data.Close, self.n1, self.n2, self.ns) | |
113 | + | |
114 | + # チャートデータの行ごとに呼び出される | |
115 | + # tp(take profit)利確する価格 | |
116 | + # sl(stop losst)損切りする価格 | |
117 | + def next(self): | |
118 | + # macdがsignalを上回った時 | |
119 | + if crossover(self.macd, self.macdsignal) and self.macd[-1] < 0.0: | |
120 | + # 買いオーダー | |
121 | + self.buy( | |
122 | + tp=self.data.Close[-1] + 0.5, | |
123 | + sl=self.data.Close[-1] - 0.1 | |
124 | + ) | |
125 | + | |
126 | + # signalがmacdを上回った時 | |
127 | + elif crossover(self.macdsignal, self.macd) and self.macd[-1] > 0.0: | |
128 | + # 売りオーダー | |
129 | + self.sell( | |
130 | + tp=self.data.Close[-1] - 0.5, | |
131 | + sl=self.data.Close[-1] + 0.1 | |
132 | + ) | |
133 | + | |
134 | +# まずはStrategyが少し異なる(比較元はmacdの0以上、以下を判定してなかった)ので、その検証 | |
135 | + | |
136 | + | |
137 | +# バックテストを設定 | |
138 | +bt = Backtest( | |
139 | + # チャートデータ | |
140 | + data, | |
141 | + # 売買戦略 | |
142 | + MACDCross, | |
143 | + # 最初の所持金 | |
144 | + cash=10000, | |
145 | + # 取引手数料(為替価格に対する倍率で指定、為替価格100円でcommission=0.0005なら0.05円) | |
146 | + # OANDAの場合0.3〜0.9銭=0.003~0.009円 | |
147 | + commission=0.00009, | |
148 | + # レバレッジ倍率の逆数(0.5で2倍レバレッジ) | |
149 | + margin=1.0, | |
150 | + # True:現在の終値で取引,False:次の時間の始値で取引 | |
151 | + trade_on_close=True | |
152 | +) | |
153 | + | |
154 | +s_time = time.perf_counter() | |
155 | +# バックテスト実行 | |
156 | +output = bt.run() | |
157 | +e_time = time.perf_counter() | |
158 | +# 経過時間を出力(秒) | |
159 | +p_time = round((e_time - s_time), 3) | |
160 | +print(f'Processing time: {p_time}') | |
161 | + | |
162 | +# 実行結果(データ) | |
163 | +print(output) | |
164 | + | |
165 | +# とても駄目 | |
166 | +# Processing time: 5.412 | |
167 | +# Start 2022-10-04 03:57:00 | |
168 | +# End 2022-12-30 23:54:00 | |
169 | +# Duration 87 days 19:57:00 | |
170 | +# Exposure Time [%] 80.680482 | |
171 | +# Equity Final [$] 9033.372661 | |
172 | +# Equity Peak [$] 10078.256653 | |
173 | +# Return [%] -9.666273 | |
174 | +# Buy & Hold Return [%] -9.405472 | |
175 | +# Return (Ann.) [%] -33.651759 | |
176 | +# Volatility (Ann.) [%] 5.827159 | |
177 | +# Sharpe Ratio 0.0 | |
178 | +# Sortino Ratio 0.0 | |
179 | +# Calmar Ratio 0.0 | |
180 | +# Max. Drawdown [%] -11.131486 | |
181 | +# Avg. Drawdown [%] -0.272737 | |
182 | +# Max. Drawdown Duration 85 days 20:48:00 | |
183 | +# Avg. Drawdown Duration 1 days 17:17:00 | |
184 | +# # Trades 822 | |
185 | +# Win Rate [%] 22.262774 | |
186 | +# Best Trade [%] 0.399431 | |
187 | +# Worst Trade [%] -0.085376 | |
188 | +# Avg. Trade [%] -0.002357 | |
189 | +# Max. Trade Duration 3 days 10:04:00 | |
190 | +# Avg. Trade Duration 0 days 02:35:00 | |
191 | +# Profit Factor 0.964156 | |
192 | +# Expectancy [%] -0.002238 | |
193 | +# SQN -2.511314 | |
194 | +# _strategy MACDCross | |
195 | +# _equity_curve ... | |
196 | +# _trades Size Entry... | |
197 | +# dtype: object | |
198 | + | |
199 | +# 最適化 | |
200 | +s_time = time.perf_counter() | |
201 | +output2 = bt.optimize( | |
202 | + n1=range(20, 40, 1), | |
203 | + n2=range(40, 60, 1), | |
204 | + ns=range(2, 20, 1), | |
205 | + maximize='SQN', | |
206 | + method='grid' | |
207 | +) | |
208 | +e_time = time.perf_counter() | |
209 | +# 経過時間を出力(秒) | |
210 | +p_time = round((e_time - s_time), 3) | |
211 | +print(f'Processing time: {p_time}') | |
212 | +print(output2) | |
213 | +print(output2._strategy) | |
214 | + | |
215 | +# Processing time: 36708.622 | |
216 | +# Start 2022-10-04 03:57:00 | |
217 | +# End 2022-12-30 23:54:00 | |
218 | +# Duration 87 days 19:57:00 | |
219 | +# Exposure Time [%] 78.989816 | |
220 | +# Equity Final [$] 9818.920317 | |
221 | +# Equity Peak [$] 10081.403521 | |
222 | +# Return [%] -1.810797 | |
223 | +# Buy & Hold Return [%] -9.405472 | |
224 | +# Return (Ann.) [%] -7.448111 | |
225 | +# Volatility (Ann.) [%] 7.25267 | |
226 | +# Sharpe Ratio 0.0 | |
227 | +# Sortino Ratio 0.0 | |
228 | +# Calmar Ratio 0.0 | |
229 | +# Max. Drawdown [%] -4.752928 | |
230 | +# Avg. Drawdown [%] -0.310453 | |
231 | +# Max. Drawdown Duration 50 days 07:50:00 | |
232 | +# Avg. Drawdown Duration 2 days 10:29:00 | |
233 | +# # Trades 727 | |
234 | +# Win Rate [%] 20.770289 | |
235 | +# Best Trade [%] 0.399431 | |
236 | +# Worst Trade [%] -0.085338 | |
237 | +# Avg. Trade [%] 0.002205 | |
238 | +# Max. Trade Duration 3 days 10:02:00 | |
239 | +# Avg. Trade Duration 0 days 02:33:00 | |
240 | +# Profit Factor 1.036753 | |
241 | +# Expectancy [%] 0.002341 | |
242 | +# SQN -0.429096 | |
243 | +# _strategy MACDCross(n1=37,... | |
244 | +# _equity_curve ... | |
245 | +# _trades Size Entry... | |
246 | +# dtype: object | |
247 | +# MACDCross(n1=37,n2=46,ns=18) |
@@ -0,0 +1,245 @@ | ||
1 | +# 元ネタ | |
2 | +# https://qiita.com/Fujinoinvestor/items/780b138e441531860e60 | |
3 | + | |
4 | +# 過去90日のrateを取得してbacktestingを実行する | |
5 | + | |
6 | +import talib as ta | |
7 | +from backtesting.lib import crossover | |
8 | +from backtesting import Backtest | |
9 | +from backtesting import Strategy | |
10 | +import pandas as pd | |
11 | +import datetime as dt | |
12 | +import pytz | |
13 | +import MetaTrader5 as mt5 | |
14 | +import numpy as np | |
15 | +from numpy import linalg as LA | |
16 | + | |
17 | +# 本日日付 | |
18 | +now = dt.datetime.now() | |
19 | +# 日本のtimezone | |
20 | +tz_local = pytz.timezone('Etc/GMT-9') | |
21 | +# OANDAサーバのtimezone | |
22 | +tz_oanda = pytz.timezone('Etc/GMT-2') | |
23 | + | |
24 | +local_to = dt.datetime( | |
25 | + now.year, | |
26 | + now.month, | |
27 | + now.day, | |
28 | + 0, | |
29 | + 0, | |
30 | + 0, | |
31 | + tzinfo=tz_local | |
32 | +) | |
33 | +local_from = local_to - dt.timedelta(days=90) | |
34 | + | |
35 | +rate_to = local_to.astimezone(tz_oanda) | |
36 | +rate_from = local_from.astimezone(tz_oanda) | |
37 | + | |
38 | +# レートを取得 | |
39 | +cp = 'USDJPY' | |
40 | +mt5.initialize() | |
41 | +rates = mt5.copy_rates_range(cp, mt5.TIMEFRAME_M1, rate_from, rate_to) | |
42 | + | |
43 | +df = pd.DataFrame(rates) | |
44 | + | |
45 | +# timeカラムをdatetime型に変換 | |
46 | +df.time = pd.to_datetime(df['time'], unit='s') | |
47 | +# timeカラムをindexに時系列インデックスとして割り当て | |
48 | +df.index = pd.DatetimeIndex(df.time, name='Date') | |
49 | +# インデックスのTimeZoneをUTCに設定 | |
50 | +df.index = df.index.tz_localize(dt.timezone.utc) | |
51 | +# インデックスのTimeZoneをLovalに変換 | |
52 | +df.index = df.index.tz_convert(tz_local) | |
53 | + | |
54 | +# DataFrameのカラム名をbacktesting向けに修正 | |
55 | +df = df.rename( | |
56 | + columns={ | |
57 | + "time": "Date", | |
58 | + "open": "Open", | |
59 | + "high": "High", | |
60 | + "low": "Low", | |
61 | + "close": "Close", | |
62 | + "tick_volume": "Volume", | |
63 | + "spread": "Spread", | |
64 | + "real_volume": "not_use", | |
65 | + } | |
66 | +) | |
67 | + | |
68 | +# 必要なカラムのみ取得 | |
69 | +data = df.loc[:, ['Open', 'High', 'Low', 'Close', 'Volume']] | |
70 | + | |
71 | + | |
72 | +def MACD(close, n1, n2, ns): | |
73 | + macd, macdsignal, macdhist = ta.MACD( | |
74 | + close, fastperiod=n1, slowperiod=n2, signalperiod=ns) | |
75 | + return macd, macdsignal | |
76 | + | |
77 | + | |
78 | +# 下記記事を参考にStrategyを修正 | |
79 | +# https://mmorley.hatenablog.com/entry/fx_backtesting01 | |
80 | + | |
81 | +class MACDCross(Strategy): | |
82 | + # 短期EMAの期間 | |
83 | + n1 = 28 | |
84 | + # 長期EMAの期間 | |
85 | + n2 = 53 | |
86 | + # シグナル(MACDのSMA)の期間 | |
87 | + ns = 15 | |
88 | + # angleの閾値 | |
89 | + crossover_angle = 0.0 | |
90 | + | |
91 | + def init(self): | |
92 | + self.macd, self.macdsignal = self.I( | |
93 | + MACD, self.data.Close, self.n1, self.n2, self.ns) | |
94 | + | |
95 | + def vector_angle(self, u: np.ndarray, v: np.ndarray): | |
96 | + i = np.inner(u, v) | |
97 | + n = LA.norm(u) * LA.norm(v) | |
98 | + c = i / n | |
99 | + return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0))) | |
100 | + | |
101 | + # チャートデータの行ごとに呼び出される | |
102 | + # tp(take profit)利確する価格 | |
103 | + # sl(stop losst)損切りする価格 | |
104 | + def next(self): | |
105 | + # macdがsignalを上回った時 | |
106 | + if crossover(self.macd, self.macdsignal) and \ | |
107 | + self.macd[-1] < 0.0 and \ | |
108 | + self.vector_angle( | |
109 | + self.macd[-2:], | |
110 | + self.macdsignal[-2:] | |
111 | + ) > self.crossover_angle: | |
112 | + # 買いオーダー | |
113 | + self.buy( | |
114 | + tp=self.data.Close[-1] + 0.5, | |
115 | + sl=self.data.Close[-1] - 0.1 | |
116 | + ) | |
117 | + | |
118 | + # signalがmacdを上回った時 | |
119 | + elif crossover(self.macdsignal, self.macd) and \ | |
120 | + self.macd[-1] > 0.0 and \ | |
121 | + self.vector_angle( | |
122 | + self.macd[-2:], | |
123 | + self.macdsignal[-2:] | |
124 | + ) > self.crossover_angle: | |
125 | + # 売りオーダー | |
126 | + self.sell( | |
127 | + tp=self.data.Close[-1] - 0.5, | |
128 | + sl=self.data.Close[-1] + 0.1 | |
129 | + ) | |
130 | + | |
131 | +# まずはStrategyが少し異なる(比較元はmacdの0以上、以下を判定してなかった)ので、その検証 | |
132 | + | |
133 | + | |
134 | +# バックテストを設定 | |
135 | +bt = Backtest( | |
136 | + # チャートデータ | |
137 | + data, | |
138 | + # 売買戦略 | |
139 | + MACDCross, | |
140 | + # 最初の所持金 | |
141 | + cash=10000, | |
142 | + # 取引手数料(為替価格に対する倍率で指定、為替価格100円でcommission=0.0005なら0.05円) | |
143 | + # OANDAの場合0.3〜0.9銭=0.003~0.009円 | |
144 | + commission=0.00009, | |
145 | + # レバレッジ倍率の逆数(0.5で2倍レバレッジ) | |
146 | + margin=1.0, | |
147 | + # True:現在の終値で取引,False:次の時間の始値で取引 | |
148 | + trade_on_close=True | |
149 | +) | |
150 | + | |
151 | +s_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
152 | +# バックテスト実行 | |
153 | +output = bt.run() | |
154 | +e_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
155 | +# 経過時間を出力(秒) | |
156 | +p_time = round((e_time - s_time), 0) | |
157 | +print(f'Processing time(sec): {p_time}') | |
158 | + | |
159 | +# 実行結果(データ) | |
160 | +print(output) | |
161 | + | |
162 | +# Processing time(sec): 16.0 | |
163 | +# Start 2022-11-14 09:00... | |
164 | +# End 2023-02-11 00:00... | |
165 | +# Duration 88 days 15:00:00 | |
166 | +# Exposure Time [%] 79.312882 | |
167 | +# Equity Final [$] 9613.15298 | |
168 | +# Equity Peak [$] 10130.710517 | |
169 | +# Return [%] -3.86847 | |
170 | +# Buy & Hold Return [%] -5.877446 | |
171 | +# Return (Ann.) [%] -11.649176 | |
172 | +# Volatility (Ann.) [%] 7.002821 | |
173 | +# Sharpe Ratio 0.0 | |
174 | +# Sortino Ratio 0.0 | |
175 | +# Calmar Ratio 0.0 | |
176 | +# Max. Drawdown [%] -8.675607 | |
177 | +# Avg. Drawdown [%] -0.269104 | |
178 | +# Max. Drawdown Duration 77 days 02:20:00 | |
179 | +# Avg. Drawdown Duration 1 days 14:35:00 | |
180 | +# # Trades 888 | |
181 | +# Win Rate [%] 20.833333 | |
182 | +# Best Trade [%] 0.383547 | |
183 | +# Worst Trade [%] -0.087276 | |
184 | +# Avg. Trade [%] 0.002029 | |
185 | +# Max. Trade Duration 3 days 10:04:00 | |
186 | +# Avg. Trade Duration 0 days 02:09:00 | |
187 | +# Profit Factor 1.032843 | |
188 | +# Expectancy [%] 0.002176 | |
189 | +# SQN -0.824697 | |
190 | +# _strategy MACDCross | |
191 | +# _equity_curve ... | |
192 | +# _trades Size Entry... | |
193 | +# dtype: object | |
194 | + | |
195 | +# 最適化して検証 | |
196 | +# 時間がかかりすぎるのでangleのみ最適化 | |
197 | +s_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
198 | +output2 = bt.optimize( | |
199 | + # n1=range(20, 40, 1), | |
200 | + # n2=range(40, 60, 1), | |
201 | + # ns=range(10, 30, 1), | |
202 | + crossover_angle=[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], | |
203 | + maximize='SQN', | |
204 | + method='grid' | |
205 | +) | |
206 | +e_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
207 | +# 経過時間を出力(秒) | |
208 | +p_time = round((e_time - s_time), 0) | |
209 | +print(f'Processing time(sec): {p_time}') | |
210 | +print(output2) | |
211 | +print(output2._strategy) | |
212 | + | |
213 | +# Processing time(sec): 132.0 | |
214 | +# Start 2022-11-14 09:00... | |
215 | +# End 2023-02-11 00:00... | |
216 | +# Duration 88 days 15:00:00 | |
217 | +# Exposure Time [%] 29.644473 | |
218 | +# Equity Final [$] 10306.515571 | |
219 | +# Equity Peak [$] 10399.114836 | |
220 | +# Return [%] 3.065156 | |
221 | +# Buy & Hold Return [%] -5.877446 | |
222 | +# Return (Ann.) [%] 10.297861 | |
223 | +# Volatility (Ann.) [%] 5.746197 | |
224 | +# Sharpe Ratio 1.792118 | |
225 | +# Sortino Ratio 3.735854 | |
226 | +# Calmar Ratio 2.387603 | |
227 | +# Max. Drawdown [%] -4.313055 | |
228 | +# Avg. Drawdown [%] -0.120288 | |
229 | +# Max. Drawdown Duration 65 days 17:52:00 | |
230 | +# Avg. Drawdown Duration 0 days 17:15:00 | |
231 | +# # Trades 312 | |
232 | +# Win Rate [%] 20.512821 | |
233 | +# Best Trade [%] 1.057665 | |
234 | +# Worst Trade [%] -0.08725 | |
235 | +# Avg. Trade [%] 0.009701 | |
236 | +# Max. Trade Duration 2 days 10:13:00 | |
237 | +# Avg. Trade Duration 0 days 02:36:00 | |
238 | +# Profit Factor 1.149254 | |
239 | +# Expectancy [%] 0.009877 | |
240 | +# SQN 0.925784 | |
241 | +# _strategy MACDCross(crosso... | |
242 | +# _equity_curve ... | |
243 | +# _trades Size Entry... | |
244 | +# dtype: object | |
245 | +# MACDCross(crossover_angle=3.5) |
@@ -0,0 +1,246 @@ | ||
1 | +# 元ネタ | |
2 | +# https://qiita.com/Fujinoinvestor/items/780b138e441531860e60 | |
3 | + | |
4 | +# 過去90日のrateを取得してbacktestingを実行する | |
5 | +# セオリーからGoldenCross,DeadCross判定に | |
6 | +# macdの0.0以上、以下を外した場合の方が | |
7 | +# backtesting_fx_M1_5.pyと比較して | |
8 | +# Backtestingの結果が良かった | |
9 | + | |
10 | +import talib as ta | |
11 | +from backtesting.lib import crossover | |
12 | +from backtesting import Backtest | |
13 | +from backtesting import Strategy | |
14 | +import pandas as pd | |
15 | +import datetime as dt | |
16 | +import pytz | |
17 | +import MetaTrader5 as mt5 | |
18 | +import numpy as np | |
19 | +from numpy import linalg as LA | |
20 | + | |
21 | +# 本日日付 | |
22 | +now = dt.datetime.now() | |
23 | +# 日本のtimezone | |
24 | +tz_local = pytz.timezone('Etc/GMT-9') | |
25 | +# OANDAサーバのtimezone | |
26 | +tz_oanda = pytz.timezone('Etc/GMT-2') | |
27 | + | |
28 | +local_to = dt.datetime( | |
29 | + now.year, | |
30 | + now.month, | |
31 | + now.day, | |
32 | + 0, | |
33 | + 0, | |
34 | + 0, | |
35 | + tzinfo=tz_local | |
36 | +) | |
37 | +local_from = local_to - dt.timedelta(days=90) | |
38 | + | |
39 | +rate_to = local_to.astimezone(tz_oanda) | |
40 | +rate_from = local_from.astimezone(tz_oanda) | |
41 | + | |
42 | +# レートを取得 | |
43 | +cp = 'USDJPY' | |
44 | +mt5.initialize() | |
45 | +rates = mt5.copy_rates_range(cp, mt5.TIMEFRAME_M1, rate_from, rate_to) | |
46 | + | |
47 | +df = pd.DataFrame(rates) | |
48 | + | |
49 | +# timeカラムをdatetime型に変換 | |
50 | +df.time = pd.to_datetime(df['time'], unit='s') | |
51 | +# timeカラムをindexに時系列インデックスとして割り当て | |
52 | +df.index = pd.DatetimeIndex(df.time, name='Date') | |
53 | +# インデックスのTimeZoneをUTCに設定 | |
54 | +df.index = df.index.tz_localize(dt.timezone.utc) | |
55 | +# インデックスのTimeZoneをLovalに変換 | |
56 | +df.index = df.index.tz_convert(tz_local) | |
57 | + | |
58 | +# DataFrameのカラム名をbacktesting向けに修正 | |
59 | +df = df.rename( | |
60 | + columns={ | |
61 | + "time": "Date", | |
62 | + "open": "Open", | |
63 | + "high": "High", | |
64 | + "low": "Low", | |
65 | + "close": "Close", | |
66 | + "tick_volume": "Volume", | |
67 | + "spread": "Spread", | |
68 | + "real_volume": "not_use", | |
69 | + } | |
70 | +) | |
71 | + | |
72 | +# 必要なカラムのみ取得 | |
73 | +data = df.loc[:, ['Open', 'High', 'Low', 'Close', 'Volume']] | |
74 | + | |
75 | + | |
76 | +def MACD(close, n1, n2, ns): | |
77 | + macd, macdsignal, macdhist = ta.MACD( | |
78 | + close, fastperiod=n1, slowperiod=n2, signalperiod=ns) | |
79 | + return macd, macdsignal | |
80 | + | |
81 | + | |
82 | +# 下記記事を参考にStrategyを修正 | |
83 | +# https://mmorley.hatenablog.com/entry/fx_backtesting01 | |
84 | + | |
85 | +class MACDCross(Strategy): | |
86 | + # 短期EMAの期間 | |
87 | + n1 = 28 | |
88 | + # 長期EMAの期間 | |
89 | + n2 = 53 | |
90 | + # シグナル(MACDのSMA)の期間 | |
91 | + ns = 15 | |
92 | + # angleの閾値 | |
93 | + crossover_angle = 0.0 | |
94 | + | |
95 | + def init(self): | |
96 | + self.macd, self.macdsignal = self.I( | |
97 | + MACD, self.data.Close, self.n1, self.n2, self.ns) | |
98 | + | |
99 | + def vector_angle(self, u: np.ndarray, v: np.ndarray): | |
100 | + i = np.inner(u, v) | |
101 | + n = LA.norm(u) * LA.norm(v) | |
102 | + c = i / n | |
103 | + return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0))) | |
104 | + | |
105 | + # チャートデータの行ごとに呼び出される | |
106 | + # tp(take profit)利確する価格 | |
107 | + # sl(stop losst)損切りする価格 | |
108 | + def next(self): | |
109 | + # macdがsignalを上回った時 | |
110 | + if crossover(self.macd, self.macdsignal) and \ | |
111 | + self.vector_angle( | |
112 | + self.macd[-2:], | |
113 | + self.macdsignal[-2:] | |
114 | + ) > self.crossover_angle: | |
115 | + # 買いオーダー | |
116 | + self.buy( | |
117 | + tp=self.data.Close[-1] + 0.5, | |
118 | + sl=self.data.Close[-1] - 0.1 | |
119 | + ) | |
120 | + | |
121 | + # signalがmacdを上回った時 | |
122 | + elif crossover(self.macdsignal, self.macd) and \ | |
123 | + self.vector_angle( | |
124 | + self.macd[-2:], | |
125 | + self.macdsignal[-2:] | |
126 | + ) > self.crossover_angle: | |
127 | + # 売りオーダー | |
128 | + self.sell( | |
129 | + tp=self.data.Close[-1] - 0.5, | |
130 | + sl=self.data.Close[-1] + 0.1 | |
131 | + ) | |
132 | + | |
133 | + | |
134 | +# バックテストを設定 | |
135 | +bt = Backtest( | |
136 | + # チャートデータ | |
137 | + data, | |
138 | + # 売買戦略 | |
139 | + MACDCross, | |
140 | + # 最初の所持金 | |
141 | + cash=10000, | |
142 | + # 取引手数料(為替価格に対する倍率で指定、為替価格100円でcommission=0.0005なら0.05円) | |
143 | + # OANDAの場合0.3〜0.9銭=0.003~0.009円 | |
144 | + commission=0.00009, | |
145 | + # レバレッジ倍率の逆数(0.5で2倍レバレッジ) | |
146 | + margin=1.0, | |
147 | + # True:現在の終値で取引,False:次の時間の始値で取引 | |
148 | + trade_on_close=True | |
149 | +) | |
150 | + | |
151 | +s_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
152 | +# バックテスト実行 | |
153 | +output = bt.run() | |
154 | +e_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
155 | +# 経過時間を出力(秒) | |
156 | +p_time = round((e_time - s_time), 0) | |
157 | +print(f'Processing time(sec): {p_time}') | |
158 | + | |
159 | +# 実行結果(データ) | |
160 | +print(output) | |
161 | + | |
162 | +# Processing time(sec): 20.0 | |
163 | +# Start 2022-11-14 09:00... | |
164 | +# End 2023-02-11 00:00... | |
165 | +# Duration 88 days 15:00:00 | |
166 | +# Exposure Time [%] 84.418508 | |
167 | +# Equity Final [$] 10681.733506 | |
168 | +# Equity Peak [$] 10725.062947 | |
169 | +# Return [%] 6.817335 | |
170 | +# Buy & Hold Return [%] -5.877446 | |
171 | +# Return (Ann.) [%] 23.66191 | |
172 | +# Volatility (Ann.) [%] 9.973056 | |
173 | +# Sharpe Ratio 2.372584 | |
174 | +# Sortino Ratio 4.343607 | |
175 | +# Calmar Ratio 6.480834 | |
176 | +# Max. Drawdown [%] -3.65106 | |
177 | +# Avg. Drawdown [%] -0.124067 | |
178 | +# Max. Drawdown Duration 42 days 14:15:00 | |
179 | +# Avg. Drawdown Duration 0 days 07:42:00 | |
180 | +# # Trades 1041 | |
181 | +# Win Rate [%] 24.207493 | |
182 | +# Best Trade [%] 1.057665 | |
183 | +# Worst Trade [%] -0.087407 | |
184 | +# Avg. Trade [%] 0.012589 | |
185 | +# Max. Trade Duration 2 days 08:09:00 | |
186 | +# Avg. Trade Duration 0 days 02:07:00 | |
187 | +# Profit Factor 1.202623 | |
188 | +# Expectancy [%] 0.012749 | |
189 | +# SQN 1.205884 | |
190 | +# _strategy MACDCross | |
191 | +# _equity_curve ... | |
192 | +# _trades Size Entr... | |
193 | +# dtype: object | |
194 | + | |
195 | + | |
196 | +# 最適化して検証 | |
197 | +# 時間がかかりすぎるのでangleのみ最適化 | |
198 | +s_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
199 | +output2 = bt.optimize( | |
200 | + # n1=range(20, 40, 1), | |
201 | + # n2=range(40, 60, 1), | |
202 | + # ns=range(10, 30, 1), | |
203 | + crossover_angle=[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], | |
204 | + maximize='SQN', | |
205 | + method='grid' | |
206 | +) | |
207 | +e_time = dt.datetime.timestamp(dt.datetime.utcnow()) | |
208 | +# 経過時間を出力(秒) | |
209 | +p_time = round((e_time - s_time), 0) | |
210 | +print(f'Processing time(sec): {p_time}') | |
211 | +print(output2) | |
212 | +print(output2._strategy) | |
213 | + | |
214 | +# Processing time(sec): 163.0 | |
215 | +# Start 2022-11-14 09:00... | |
216 | +# End 2023-02-11 00:00... | |
217 | +# Duration 88 days 15:00:00 | |
218 | +# Exposure Time [%] 48.076332 | |
219 | +# Equity Final [$] 10675.172967 | |
220 | +# Equity Peak [$] 10707.548153 | |
221 | +# Return [%] 6.75173 | |
222 | +# Buy & Hold Return [%] -5.877446 | |
223 | +# Return (Ann.) [%] 22.986772 | |
224 | +# Volatility (Ann.) [%] 7.923884 | |
225 | +# Sharpe Ratio 2.900947 | |
226 | +# Sortino Ratio 7.140729 | |
227 | +# Calmar Ratio 6.643383 | |
228 | +# Max. Drawdown [%] -3.4601 | |
229 | +# Avg. Drawdown [%] -0.112675 | |
230 | +# Max. Drawdown Duration 44 days 09:11:00 | |
231 | +# Avg. Drawdown Duration 0 days 09:08:00 | |
232 | +# # Trades 495 | |
233 | +# Win Rate [%] 21.212121 | |
234 | +# Best Trade [%] 1.057665 | |
235 | +# Worst Trade [%] -0.087566 | |
236 | +# Avg. Trade [%] 0.012992 | |
237 | +# Max. Trade Duration 2 days 06:53:00 | |
238 | +# Avg. Trade Duration 0 days 02:11:00 | |
239 | +# Profit Factor 1.200226 | |
240 | +# Expectancy [%] 0.01317 | |
241 | +# SQN 1.600122 | |
242 | +# _strategy MACDCross(crosso... | |
243 | +# _equity_curve ... | |
244 | +# _trades Size Entry... | |
245 | +# dtype: object | |
246 | +# MACDCross(crossover_angle=3.5) |
@@ -0,0 +1,47 @@ | ||
1 | +# vector angle | |
2 | +# ベクトルのなす角を用いてMACDのCrossOver判定について改良を試みる | |
3 | +# 参考文献 | |
4 | +# https://hiraocafe.com/note/2lineanglevec.html | |
5 | +# https://www.mathpython.com/numpy-vector-angle | |
6 | +import numpy as np | |
7 | +from numpy import linalg as LA | |
8 | + | |
9 | + | |
10 | +def vector_angle(u: np.array, v: np.array): | |
11 | + i = np.inner(u, v) | |
12 | + n = LA.norm(u) * LA.norm(v) | |
13 | + c = i / n | |
14 | + return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0))) | |
15 | + | |
16 | + | |
17 | +u = np.array([3, 4]) | |
18 | +v = np.array([-4, 3]) | |
19 | +print(vector_angle(u, v)) # 90.0 | |
20 | + | |
21 | +# テストケース | |
22 | +# 2023-02-03 13:24:02,027 | |
23 | +# num[-2]: MACD: 0.002432, MACDSignal: 0.003394 | |
24 | +# num[-1]: MACD: 0.00243, MACDSignal: 0.003274 | |
25 | +# Technical Indicator: Consider it a DeadCross. | |
26 | +u1 = np.array([0.00243, 0.002432]) | |
27 | +v1 = np.array([0.003274, 0.003394]) | |
28 | +print(vector_angle(u1, v1)) | |
29 | +# 1.0074377034490547 | |
30 | + | |
31 | +# 2023-02-03 13:25:02,727 | |
32 | +# num[-2]: MACD: 0.002782, MACDSignal: 0.003317 | |
33 | +# num[-1]: MACD: 0.003056, MACDSignal: 0.003285 | |
34 | +# Technical Indicator: Consider it a DeadCross. | |
35 | +u2 = np.array([0.003056, 0.002782]) | |
36 | +v2 = np.array([0.003285, 0.003317]) | |
37 | +print(vector_angle(u2, v2)) | |
38 | +# 2.964852801558037 | |
39 | + | |
40 | +# 2023-02-03 13:42:02,638 | |
41 | +# num[-2]: MACD: 0.007748, MACDSignal: 0.007773 | |
42 | +# num[-1]: MACD: 0.006698, MACDSignal: 0.007639 | |
43 | +# Technical Indicator: Consider it a DeadCross. | |
44 | +u3 = np.array([0.007748, 0.007773]) | |
45 | +v3 = np.array([0.006698, 0.007639]) | |
46 | +print(vector_angle(u3, v3)) | |
47 | +# 3.6628990024599957 |
@@ -0,0 +1,120 @@ | ||
1 | +# vector angle | |
2 | +# ベクトルのなす角を用いてMACDのCrossOver判定について改良を試みる | |
3 | +# 参考文献 | |
4 | +# https://hiraocafe.com/note/2lineanglevec.html | |
5 | +# https://www.mathpython.com/numpy-vector-angle | |
6 | +# 過去データ検証 | |
7 | +import MetaTrader5 as mt5 | |
8 | +import talib as ta | |
9 | +import numpy as np | |
10 | +from datetime import datetime | |
11 | +from datetime import timedelta | |
12 | +import pytz | |
13 | +from numpy import linalg as LA | |
14 | + | |
15 | + | |
16 | +def vector_angle(u: np.ndarray, v: np.ndarray): | |
17 | + i = np.inner(u, v) | |
18 | + n = LA.norm(u) * LA.norm(v) | |
19 | + c = i / n | |
20 | + return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0))) | |
21 | + | |
22 | + | |
23 | +def crossover(series1: np.ndarray, series2: np.ndarray) -> bool: | |
24 | + """指標値列の交差判定 | |
25 | + """ | |
26 | + return series1[-2] < series2[-2] and series1[-1] > series2[-1] | |
27 | + | |
28 | + | |
29 | +mt5.initialize() | |
30 | +cp = 'USDJPY' | |
31 | +# 短期EMAの期間 | |
32 | +n1 = 28 | |
33 | +# 長期EMAの期間 | |
34 | +n2 = 53 | |
35 | +# シグナル(MACDのSMA)の期間 | |
36 | +ns = 15 | |
37 | + | |
38 | + | |
39 | +# OANDAサーバのtimezone | |
40 | +tz_oanda = pytz.timezone('Etc/GMT-2') | |
41 | +oanda_from = datetime(2023, 2, 8, 0, 0, 0, tzinfo=tz_oanda) | |
42 | +oanda_to = oanda_from + timedelta(hours=24) | |
43 | + | |
44 | +# レートを取得 | |
45 | +rates = mt5.copy_rates_range(cp, mt5.TIMEFRAME_M1, oanda_from, oanda_to) | |
46 | + | |
47 | +closes = rates['close'] | |
48 | + | |
49 | +macd, macdsignal, _ = ta.MACD( | |
50 | + closes, | |
51 | + fastperiod=n1, | |
52 | + slowperiod=n2, | |
53 | + signalperiod=ns | |
54 | +) | |
55 | + | |
56 | +macd = np.around(macd, 6) | |
57 | +macdsignal = np.around(macdsignal, 6) | |
58 | + | |
59 | +for i in range(0, (len(rates) - 1)): | |
60 | + if np.isnan(macd[i]) or np.isnan(macd[i + 1]): | |
61 | + # データがnanは何もしない | |
62 | + continue | |
63 | + if np.isnan(macdsignal[i]) or np.isnan(macdsignal[i + 1]): | |
64 | + # データがnanは何もしない | |
65 | + continue | |
66 | + macd_s = macd[i: i + 2] | |
67 | + macdsignal_s = macdsignal[i: i + 2] | |
68 | + if crossover(macd_s, macdsignal_s) and macd_s[-1] < 0.0: | |
69 | + # GoldenCross 上昇転換サイン | |
70 | + msg = 'Technical Indicator: GoldenCross.' | |
71 | + rate_time = tz_oanda.localize( | |
72 | + datetime.utcfromtimestamp(rates[i]['time']) | |
73 | + ) | |
74 | + angle = round(vector_angle(macd_s, macdsignal_s), 6) | |
75 | + print(f'{rate_time}: {angle}: {msg}') | |
76 | + elif crossover(macdsignal_s, macd_s) and macd_s[-1] > 0.0: | |
77 | + # DeadCross 降下転換サイン | |
78 | + msg = 'Technical Indicator: DeadCross.' | |
79 | + rate_time = tz_oanda.localize( | |
80 | + datetime.utcfromtimestamp(rates[i]['time']) | |
81 | + ) | |
82 | + angle = round(vector_angle(macdsignal_s, macd_s), 6) | |
83 | + print(f'{rate_time}: {angle}: {msg}') | |
84 | + | |
85 | +# angleが0.5以上を採用すれば誤判定を少しへらせるかも | |
86 | +# backtestで検証する | |
87 | + | |
88 | +# 2023-02-07 23:46:00+02:00: 0.48448: Technical Indicator: GoldenCross. | |
89 | +# 2023-02-07 23:50:00+02:00: 1.119538: Technical Indicator: GoldenCross. | |
90 | +# 2023-02-08 00:18:00+02:00: 3.135568: Technical Indicator: GoldenCross. | |
91 | +# 2023-02-08 01:00:00+02:00: 22.266663: Technical Indicator: GoldenCross. | |
92 | +# 2023-02-08 01:28:00+02:00: 0.558075: Technical Indicator: DeadCross. | |
93 | +# 2023-02-08 02:50:00+02:00: 1.175004: Technical Indicator: GoldenCross. | |
94 | +# 2023-02-08 04:15:00+02:00: 0.211562: Technical Indicator: DeadCross. | |
95 | +# 2023-02-08 04:28:00+02:00: 0.247605: Technical Indicator: DeadCross. | |
96 | +# 2023-02-08 05:36:00+02:00: 1.632956: Technical Indicator: GoldenCross. | |
97 | +# 2023-02-08 05:59:00+02:00: 3.524362: Technical Indicator: GoldenCross. | |
98 | +# 2023-02-08 06:15:00+02:00: 0.855166: Technical Indicator: GoldenCross. | |
99 | +# 2023-02-08 06:59:00+02:00: 0.940879: Technical Indicator: DeadCross. | |
100 | +# 2023-02-08 07:16:00+02:00: 2.399271: Technical Indicator: DeadCross. | |
101 | +# 2023-02-08 08:11:00+02:00: 1.337743: Technical Indicator: GoldenCross. | |
102 | +# 2023-02-08 08:43:00+02:00: 3.563947: Technical Indicator: DeadCross. | |
103 | +# 2023-02-08 09:22:00+02:00: 2.031104: Technical Indicator: DeadCross. | |
104 | +# 2023-02-08 10:08:00+02:00: 0.784882: Technical Indicator: GoldenCross. | |
105 | +# 2023-02-08 10:28:00+02:00: 0.961372: Technical Indicator: GoldenCross. | |
106 | +# 2023-02-08 11:25:00+02:00: 0.760229: Technical Indicator: GoldenCross. | |
107 | +# 2023-02-08 12:00:00+02:00: 1.235069: Technical Indicator: GoldenCross. | |
108 | +# 2023-02-08 12:41:00+02:00: 1.106239: Technical Indicator: DeadCross. | |
109 | +# 2023-02-08 13:49:00+02:00: 2.006404: Technical Indicator: GoldenCross. | |
110 | +# 2023-02-08 14:25:00+02:00: 10.711557: Technical Indicator: DeadCross. | |
111 | +# 2023-02-08 15:34:00+02:00: 0.568802: Technical Indicator: DeadCross. | |
112 | +# 2023-02-08 17:03:00+02:00: 1.336369: Technical Indicator: DeadCross. | |
113 | +# 2023-02-08 17:15:00+02:00: 0.909583: Technical Indicator: DeadCross. | |
114 | +# 2023-02-08 17:59:00+02:00: 0.832841: Technical Indicator: DeadCross. | |
115 | +# 2023-02-08 18:27:00+02:00: 4.131851: Technical Indicator: GoldenCross. | |
116 | +# 2023-02-08 19:06:00+02:00: 1.267079: Technical Indicator: GoldenCross. | |
117 | +# 2023-02-08 19:32:00+02:00: 1.267604: Technical Indicator: GoldenCross. | |
118 | +# 2023-02-08 20:17:00+02:00: 2.140756: Technical Indicator: GoldenCross. | |
119 | +# 2023-02-08 20:55:00+02:00: 2.290568: Technical Indicator: DeadCross. | |
120 | +# 2023-02-08 21:59:00+02:00: 0.812178: Technical Indicator: DeadCross. |
@@ -1,71 +0,0 @@ | ||
1 | -2022-12-15 04:59:45,523 8028 MainThread __main__:75 main [DEBUG]: set schedule. | |
2 | -2022-12-15 04:59:45,528 8028 MainThread __main__:81 main [DEBUG]: start loop. | |
3 | -2022-12-15 05:00:00,636 8028 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:00:00 Open: 135.303 High: 135.385 Low: 135.303 Close: 135.358 Volume: 313 Spread: 3 | |
4 | -2022-12-15 05:00:16,666 8028 MainThread __main__:59 check_ticks [DEBUG]: time bid ask last volume time_msc flags volume_real | |
5 | -0 2022-12-14 11:00:15 135.355 135.363 0.0 0 1671015615341 4 0.0 | |
6 | -1 2022-12-14 11:00:15 135.361 135.368 0.0 0 1671015615492 134 0.0 | |
7 | -2 2022-12-14 11:00:15 135.360 135.368 0.0 0 1671015615559 130 0.0 | |
8 | -3 2022-12-14 11:00:15 135.358 135.366 0.0 0 1671015615618 134 0.0 | |
9 | -4 2022-12-14 11:00:16 135.361 135.367 0.0 0 1671015616267 134 0.0 | |
10 | -.. ... ... ... ... ... ... ... ... | |
11 | -995 2022-12-14 11:03:50 135.327 135.332 0.0 0 1671015830632 134 0.0 | |
12 | -996 2022-12-14 11:03:50 135.326 135.332 0.0 0 1671015830731 130 0.0 | |
13 | -997 2022-12-14 11:03:52 135.326 135.331 0.0 0 1671015832092 4 0.0 | |
14 | -998 2022-12-14 11:03:52 135.325 135.331 0.0 0 1671015832200 130 0.0 | |
15 | -999 2022-12-14 11:03:52 135.324 135.331 0.0 0 1671015832526 130 0.0 | |
16 | - | |
17 | -[1000 rows x 8 columns] | |
18 | -2022-12-15 05:00:30,883 8028 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:00:00 Open: 135.303 High: 135.385 Low: 135.303 Close: 135.358 Volume: 313 Spread: 3 | |
19 | -2022-12-15 05:00:45,974 8028 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:00:00 Open: 135.303 High: 135.385 Low: 135.303 Close: 135.358 Volume: 313 Spread: 3 | |
20 | -2022-12-15 05:01:00,046 8028 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:01:00 Open: 135.357 High: 135.358 Low: 135.326 Close: 135.347 Volume: 211 Spread: 3 | |
21 | -2022-12-15 05:01:15,161 8028 MainThread __main__:59 check_ticks [DEBUG]: time bid ask last volume time_msc flags volume_real | |
22 | -0 2022-12-14 11:01:15 135.332 135.341 0.0 0 1671015675064 4 0.0 | |
23 | -1 2022-12-14 11:01:15 135.333 135.341 0.0 0 1671015675132 130 0.0 | |
24 | -2 2022-12-14 11:01:15 135.332 135.340 0.0 0 1671015675191 134 0.0 | |
25 | -3 2022-12-14 11:01:15 135.333 135.340 0.0 0 1671015675353 130 0.0 | |
26 | -4 2022-12-14 11:01:15 135.335 135.341 0.0 0 1671015675838 134 0.0 | |
27 | -.. ... ... ... ... ... ... ... ... | |
28 | -995 2022-12-14 11:05:57 135.318 135.325 0.0 0 1671015957797 134 0.0 | |
29 | -996 2022-12-14 11:05:57 135.318 135.324 0.0 0 1671015957870 4 0.0 | |
30 | -997 2022-12-14 11:05:58 135.319 135.326 0.0 0 1671015958179 134 0.0 | |
31 | -998 2022-12-14 11:05:58 135.319 135.325 0.0 0 1671015958290 4 0.0 | |
32 | -999 2022-12-14 11:05:58 135.322 135.329 0.0 0 1671015958480 134 0.0 | |
33 | - | |
34 | -[1000 rows x 8 columns] | |
35 | -2022-12-15 05:05:49,913 7540 MainThread __main__:75 main [DEBUG]: set schedule. | |
36 | -2022-12-15 05:05:49,915 7540 MainThread __main__:81 main [DEBUG]: start loop. | |
37 | -2022-12-15 05:06:00,946 7540 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:06:00 Open: 135.317 High: 135.322 Low: 135.277 Close: 135.277 Volume: 124 Spread: 3 | |
38 | -2022-12-15 05:06:15,978 7540 MainThread __main__:59 check_ticks [DEBUG]: time bid ask last volume time_msc flags volume_real | |
39 | -0 2022-12-14 11:06:15 135.302 135.309 0.0 0 1671015975199 134 0.0 | |
40 | -1 2022-12-14 11:06:15 135.302 135.306 0.0 0 1671015975250 4 0.0 | |
41 | -2 2022-12-14 11:06:15 135.302 135.309 0.0 0 1671015975309 4 0.0 | |
42 | -3 2022-12-14 11:06:15 135.301 135.308 0.0 0 1671015975364 134 0.0 | |
43 | -4 2022-12-14 11:06:15 135.300 135.306 0.0 0 1671015975459 134 0.0 | |
44 | -.. ... ... ... ... ... ... ... ... | |
45 | -995 2022-12-14 11:12:31 135.226 135.230 0.0 0 1671016351385 134 0.0 | |
46 | -996 2022-12-14 11:12:31 135.223 135.230 0.0 0 1671016351436 130 0.0 | |
47 | -997 2022-12-14 11:12:31 135.224 135.229 0.0 0 1671016351490 134 0.0 | |
48 | -998 2022-12-14 11:12:31 135.220 135.227 0.0 0 1671016351541 134 0.0 | |
49 | -999 2022-12-14 11:12:31 135.220 135.225 0.0 0 1671016351759 4 0.0 | |
50 | - | |
51 | -[1000 rows x 8 columns] | |
52 | -2022-12-15 05:06:30,201 7540 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:06:00 Open: 135.317 High: 135.322 Low: 135.277 Close: 135.277 Volume: 124 Spread: 3 | |
53 | -2022-12-15 05:06:45,296 7540 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:06:00 Open: 135.317 High: 135.322 Low: 135.277 Close: 135.277 Volume: 124 Spread: 3 | |
54 | -2022-12-15 05:08:40,838 972 MainThread __main__:76 main [DEBUG]: set schedule. | |
55 | -2022-12-15 05:08:40,843 972 MainThread __main__:82 main [DEBUG]: start loop. | |
56 | -2022-12-15 05:08:45,867 972 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:08:00 Open: 135.275 High: 135.296 Low: 135.259 Close: 135.284 Volume: 157 Spread: 3 | |
57 | -2022-12-15 05:09:00,923 972 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:09:00 Open: 135.283 High: 135.285 Low: 135.256 Close: 135.271 Volume: 140 Spread: 3 | |
58 | -2022-12-15 05:09:15,972 972 MainThread __main__:60 check_ticks [DEBUG]: time | |
59 | -2022-12-15 05:09:15,972 972 MainThread __main__:60 check_ticks [DEBUG]: bid | |
60 | -2022-12-15 05:09:15,972 972 MainThread __main__:60 check_ticks [DEBUG]: ask | |
61 | -2022-12-15 05:09:15,981 972 MainThread __main__:60 check_ticks [DEBUG]: last | |
62 | -2022-12-15 05:09:15,981 972 MainThread __main__:60 check_ticks [DEBUG]: volume | |
63 | -2022-12-15 05:09:15,982 972 MainThread __main__:60 check_ticks [DEBUG]: time_msc | |
64 | -2022-12-15 05:09:15,982 972 MainThread __main__:60 check_ticks [DEBUG]: flags | |
65 | -2022-12-15 05:09:15,983 972 MainThread __main__:60 check_ticks [DEBUG]: volume_real | |
66 | -2022-12-15 05:09:48,869 2512 MainThread __main__:75 main [DEBUG]: set schedule. | |
67 | -2022-12-15 05:09:48,875 2512 MainThread __main__:81 main [DEBUG]: start loop. | |
68 | -2022-12-15 05:10:00,907 2512 MainThread __main__:33 job [DEBUG]: rate_M1 time: 2022-12-14 11:10:00 Open: 135.271 High: 135.275 Low: 135.225 Close: 135.231 Volume: 131 Spread: 3 | |
69 | -2022-12-15 05:10:15,947 2512 MainThread __main__:59 check_ticks [DEBUG]: Empty DataFrame | |
70 | -Columns: [time, bid, ask, last, volume, time_msc, flags, volume_real] | |
71 | -Index: [] |
@@ -18,7 +18,7 @@ args=(sys.stdout,) | ||
18 | 18 | class=logging.handlers.TimedRotatingFileHandler |
19 | 19 | level=DEBUG |
20 | 20 | formatter=simple |
21 | -args=('./mt5-operator.log', 'D', 1, 10, 'utf-8') | |
21 | +args=('./mt5-operator.log', 'D', 10, 10, 'utf-8') | |
22 | 22 | |
23 | 23 | [formatters] |
24 | 24 | keys=simple |
@@ -36,9 +36,9 @@ Allowablespread = 0.01 | ||
36 | 36 | # 1銭は0.01円 |
37 | 37 | OpenMergin = 0.007 |
38 | 38 | # 利益確定(円) |
39 | -ProfitTaking = 1.0 | |
39 | +ProfitTaking = 1.5 | |
40 | 40 | # 損切(円) |
41 | -LossCut = 0.5 | |
41 | +LossCut = 0.2 | |
42 | 42 | |
43 | 43 | # テクニカル分析 |
44 | 44 | [Technical] |
@@ -2,6 +2,7 @@ | ||
2 | 2 | # テクニカル分析 |
3 | 3 | TECHNICAL_UNCHANGED = 0 |
4 | 4 | TECHNICAL_GOLDEN_CROSS = 1 |
5 | -TECHNICAL_UPTREND = 2 | |
6 | -TECHNICAL_DEAD_CROSS = 3 | |
5 | +TECHNICAL_DEAD_CROSS = 2 | |
6 | +TECHNICAL_UPTREND = 3 | |
7 | 7 | TECHNICAL_DOWNTREND = 4 |
8 | + |
@@ -163,7 +163,6 @@ class ExchangeRateInfo(): | ||
163 | 163 | count |
164 | 164 | ) |
165 | 165 | |
166 | - # for debug | |
167 | 166 | # MACDを算出 |
168 | 167 | macd, macdsignal, _ = ta.MACD( |
169 | 168 | closes, |
@@ -172,9 +171,9 @@ class ExchangeRateInfo(): | ||
172 | 171 | signalperiod=self.__ns |
173 | 172 | ) |
174 | 173 | |
175 | - # MACDの結果を端数処理(少数点以下5) | |
176 | - macd = np.around(macd, 5) | |
177 | - macdsignal = np.around(macdsignal, 5) | |
174 | + # MACDの結果を端数処理(少数点以下6) | |
175 | + macd = np.around(macd, 6) | |
176 | + macdsignal = np.around(macdsignal, 6) | |
178 | 177 | |
179 | 178 | # for debug |
180 | 179 | for i in range(-4, 0, 1): |
@@ -183,28 +182,6 @@ class ExchangeRateInfo(): | ||
183 | 182 | ) |
184 | 183 | logger.debug(msg) |
185 | 184 | |
186 | - # 最新bidを暫定終わり値としてclosesに追加 | |
187 | - # closes = np.append(closes, self.__get_latest_bid()) | |
188 | - | |
189 | - # MACDを算出 | |
190 | - # macd, macdsignal, _ = ta.MACD( | |
191 | - # closes, | |
192 | - # fastperiod=self.__n1, | |
193 | - # slowperiod=self.__n2, | |
194 | - # signalperiod=self.__ns | |
195 | - # ) | |
196 | - | |
197 | - # MACDの結果を端数処理(少数点以下4) | |
198 | - # macd = np.around(macd, 4) | |
199 | - # macdsignal = np.around(macdsignal, 4) | |
200 | - | |
201 | - # asum_macd = macd[-1] | |
202 | - # asum_macdsig = macdsignal[-1] | |
203 | - # msg = ( | |
204 | - # f'Assumption MACD: {asum_macd}, Signal: {asum_macdsig} .' | |
205 | - # ) | |
206 | - # logger.debug(msg) | |
207 | - | |
208 | 185 | # 指標判定 |
209 | 186 | if self.__crossover(macd, macdsignal) and macd[-1] < 0.0: |
210 | 187 | # GoldenCross 上昇転換サイン |
@@ -214,22 +191,24 @@ class ExchangeRateInfo(): | ||
214 | 191 | # DeadCross 降下転換サイン |
215 | 192 | s.technical_indicator = DEF.TECHNICAL_DEAD_CROSS |
216 | 193 | msg = 'Technical Indicator: DeadCross.' |
217 | - elif macd[-1] > macdsignal[-1] and macd[-1] < 0.0: | |
218 | - # 弱い上昇トレンド | |
219 | - s.technical_indicator = DEF.TECHNICAL_UPTREND | |
220 | - msg = 'Technical Indicator: Weak Uptrend.' | |
221 | - elif macd[-1] > macdsignal[-1] and macd[-1] > 0.0: | |
222 | - # 強い上昇トレンド | |
223 | - s.technical_indicator = DEF.TECHNICAL_UPTREND | |
224 | - msg = 'Technical Indicator: Strong Uptrend.' | |
225 | - elif macd[-1] < macdsignal[-1] and macd[-1] > 0.0: | |
226 | - # 弱い降下トレンド | |
227 | - s.technical_indicator = DEF.TECHNICAL_DOWNTREND | |
228 | - msg = 'Technical Indicator: Weak Downtrand.' | |
229 | - elif macd[-1] < macdsignal[-1] and macd[-1] < 0.0: | |
230 | - # 強い降下トレンド | |
231 | - s.technical_indicator = DEF.TECHNICAL_DOWNTREND | |
232 | - msg = 'Technical Indicator: Strong Downtrand.' | |
194 | + elif macd[-1] > macdsignal[-1]: | |
195 | + if macd[-1] < 0.0: | |
196 | + # 弱い上昇トレンド | |
197 | + s.technical_indicator = DEF.TECHNICAL_UPTREND | |
198 | + msg = 'Technical Indicator: Weak Uptrend.' | |
199 | + else: | |
200 | + # 強い上昇トレンド | |
201 | + s.technical_indicator = DEF.TECHNICAL_UPTREND | |
202 | + msg = 'Technical Indicator: Strong Uptrend.' | |
203 | + elif macd[-1] < macdsignal[-1]: | |
204 | + if macd[-1] > 0.0: | |
205 | + # 弱い降下トレンド | |
206 | + s.technical_indicator = DEF.TECHNICAL_DOWNTREND | |
207 | + msg = 'Technical Indicator: Weak Downtrand.' | |
208 | + else: | |
209 | + # 強い降下トレンド | |
210 | + s.technical_indicator = DEF.TECHNICAL_DOWNTREND | |
211 | + msg = 'Technical Indicator: Strong Downtrand.' | |
233 | 212 | else: |
234 | 213 | # いずれにも該当しない |
235 | 214 | s.technical_indicator = DEF.TECHNICAL_UNCHANGED |