• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisionba14272cef6659e472eb6a9ca8f03296d14a1e3d (tree)
Time2023-02-13 06:33:39
Authorkazuhiro_kondow <simauma.circus@gmai...>
Commiterkazuhiro_kondow

Log Message

macdの使い方を見直し
判定はGoldenCross,DeahCrossのみに変更
交差の角度要素を追加

macdパラメータを過去90日のデータからmacdの4要素で
最適化して設定
最適化はbacktesting_skoptを使用

経済指標イベントのフラグを追加
現状は機能しない

Change Summary

Incremental Difference

Binary files a/Docs/memo.ods and b/Docs/memo.ods differ
--- a/freeze.txt
+++ b/freeze.txt
@@ -1,18 +1,34 @@
11 altgraph==0.17.3
22 autopep8==2.0.0
3+Backtesting==0.3.3
4+bayesian-optimization==1.4.2
35 beautifulsoup4==4.11.1
6+bokeh==3.0.3
47 certifi==2022.12.7
58 charset-normalizer==3.0.1
9+colorama==0.4.6
10+contourpy==1.0.7
611 flake8==6.0.0
712 future==0.18.2
13+html5lib==1.1
814 idna==3.4
15+investpy==1.0.8
16+Jinja2==3.1.2
17+joblib==1.2.0
18+lxml==4.9.2
19+MarkupSafe==2.1.2
920 mccabe==0.7.0
1021 MetaTrader5==5.0.43
1122 mypy==0.991
1223 mypy-extensions==0.4.3
1324 numpy==1.23.5
25+oandapyV20==0.7.2
26+packaging==23.0
1427 pandas==1.5.2
28+pandas-datareader==0.10.0
1529 pefile==2022.5.30
30+Pillow==9.4.0
31+pyaml==21.10.1
1632 pycodestyle==2.10.0
1733 pyflakes==3.0.1
1834 pyinstaller==5.7.0
@@ -20,12 +36,22 @@ pyinstaller-hooks-contrib==2022.14
2036 python-dateutil==2.8.2
2137 pytz==2022.6
2238 pywin32-ctypes==0.2.0
39+PyYAML==6.0
2340 requests==2.28.2
2441 schedule==1.1.0
42+scikit-learn==1.2.1
43+scikit-optimize==0.9.0
44+scipy==1.10.0
2545 six==1.16.0
2646 soupsieve==2.3.2.post1
2747 style==1.1.0
48+TA-Lib==0.4.25
49+threadpoolctl==3.1.0
2850 tomli==2.0.1
51+tornado==6.2
2952 typing_extensions==4.4.0
53+Unidecode==1.3.6
3054 update==0.0.1
3155 urllib3==1.26.14
56+webencodings==0.5.1
57+xyzservices==2022.9.0
--- /dev/null
+++ b/investigation_study/for_backtesting_skopt_util.py
@@ -0,0 +1,60 @@
1+# 過去90日のrateを取得してcsvファイルを作成する
2+
3+import pandas as pd
4+import datetime as dt
5+import pytz
6+import MetaTrader5 as mt5
7+
8+# 本日日付
9+now = dt.datetime.now()
10+# 日本のtimezone
11+tz_local = pytz.timezone('Etc/GMT-9')
12+# OANDAサーバのtimezone
13+tz_oanda = pytz.timezone('Etc/GMT-2')
14+
15+local_to = dt.datetime(
16+ now.year,
17+ now.month,
18+ now.day,
19+ 0,
20+ 0,
21+ 0,
22+ tzinfo=tz_local
23+)
24+local_from = local_to - dt.timedelta(days=90)
25+
26+rate_to = local_to.astimezone(tz_oanda)
27+rate_from = local_from.astimezone(tz_oanda)
28+
29+# レートを取得
30+cp = 'USDJPY'
31+mt5.initialize()
32+rates = mt5.copy_rates_range(cp, mt5.TIMEFRAME_M1, rate_from, rate_to)
33+
34+df = pd.DataFrame(rates)
35+
36+# timeカラムをdatetime型に変換
37+df.time = pd.to_datetime(df['time'], unit='s')
38+# timeカラムをindexに時系列インデックスとして割り当て
39+df.index = pd.DatetimeIndex(df.time, name='Date')
40+# インデックスのTimeZoneをUTCに設定
41+df.index = df.index.tz_localize(dt.timezone.utc)
42+# インデックスのTimeZoneをLovalに変換
43+df.index = df.index.tz_convert(tz_local)
44+
45+# DataFrameのカラム名をbacktesting向けに修正
46+df = df.rename(
47+ columns={
48+ "time": "Date",
49+ "open": "Open",
50+ "high": "High",
51+ "low": "Low",
52+ "close": "Close",
53+ "tick_volume": "Volume",
54+ "spread": "Spread",
55+ "real_volume": "not_use",
56+ }
57+)
58+
59+# csvファイル保存
60+df.to_csv('USDJPY_1M.csv')
--- /dev/null
+++ b/investigation_study/oanda_v20_api_calendar_test.py
@@ -0,0 +1,28 @@
1+import oandapyV20
2+import oandapyV20.endpoints.forexlabs as labs
3+
4+
5+client = oandapyV20.API(access_token=...)
6+params = {
7+ "instrument": "USD_JPY",
8+ "period": 604800
9+}
10+
11+# instrument
12+# 必須 カレンダー取得対象の銘柄名。 全ての取引可能な銘柄が指定可能です。
13+# period
14+# 必須 カレンダーデータを取得する期間(秒単位)。 以下の有効な値のいずれかに合致しない値を設定した場合は、一番近い有効な値に自動的に修正されます。
15+# 有効な値:
16+
17+# 3600 - 1時間
18+# 43200 - 12時間
19+# 86400 - 1日
20+# 604800 - 1週間
21+# 2592000 - 1ヶ月
22+# 7776000 - 3ヶ月
23+# 15552000 - 6ヶ月
24+# 31536000 - 1年
25+
26+r = labs.Calendar(params=params)
27+client.request(r)
28+print(r.response)
--- a/src/config/setting.ini
+++ b/src/config/setting.ini
@@ -43,8 +43,10 @@ LossCut = 0.2
4343 # テクニカル分析
4444 [Technical]
4545 # 短期EMAの期間
46-FastEMAperiod = 28
46+FastEMAperiod = 39
4747 # 長期EMAの期間
48-SlowEMAperiod = 53
48+SlowEMAperiod = 56
4949 # シグナルの期間
50-Signalperiod = 15
50+Signalperiod = 21
51+# 交差角度閾値
52+CrossingAngleThreshold = 0.684
--- a/src/configuration.py
+++ b/src/configuration.py
@@ -6,6 +6,7 @@ import logging
66 logger = logging.getLogger()
77
88
9+# 週次イベントフラグを設置、月曜日に発生する「窓開け」リスク対策
910 class Setting(object):
1011 """アプリ設定
1112 モジュール間の状態保持機能
@@ -35,8 +36,10 @@ class Setting(object):
3536 self.__market_availability: bool = False
3637 # 口座の取引可否フラグ
3738 self.__account_availability: bool = False
38- # イベントの有無フラグ
39+ # 週次イベントの有無フラグ
3940 self.__event_availability: bool = False
41+ # 経済指標イベントの有無フラグ
42+ self.__economic_indicator_event_availability: bool = False
4043 # 最後に確認した為替レート
4144 self.__last_checked_exchange_rate: float = 0.0
4245 # 注文可能lot数
@@ -69,24 +72,36 @@ class Setting(object):
6972 self.__account_availability = value
7073
7174 @property
72- def upcoming_event(self) -> bool:
73- """イベントの有無
75+ def weekday_event(self) -> bool:
76+ """週次イベントフラグ
7477 """
7578 return self.__event_availability
7679
77- @upcoming_event.setter
78- def upcoming_event(self, value: bool = False):
80+ @weekday_event.setter
81+ def weekday_event(self, value: bool = False):
7982 self.__event_availability = value
8083
8184 @property
85+ def economic_event(self) -> bool:
86+ """経済指標イベントフラグ
87+ """
88+ return self.__economic_indicator_event_availability
89+
90+ @economic_event.setter
91+ def economic_event(self, value: bool = False):
92+ self.__economic_indicator_event_availability = value
93+
94+ @property
8295 def ready_to_order(self) -> bool:
83- # TODO:現状はイベントを避ける
96+ # 経済指標イベント以外がTrueの場合、注文可能
8497 ret = self.__event_availability and \
8598 self.__account_availability and \
99+ not self.__economic_indicator_event_availability and \
86100 self.__market_availability
87101 logger.debug(
88102 f'Market:{self.__market_availability} - '
89103 f'Event:{self.__event_availability} - '
104+ f'Economic:{self.__economic_indicator_event_availability} - '
90105 f'Account:{self.__account_availability} => '
91106 f'Ready to order?:{ret}'
92107 )
--- a/src/event_mng.py
+++ b/src/event_mng.py
@@ -62,7 +62,7 @@ class EventMng():
6262 weekday = local_date.weekday()
6363 if weekday == 6:
6464 logger.info('It Sunday is closed market.')
65- Setting().upcoming_event = False
65+ Setting().weekday_event = False
6666 elif weekday == 5:
6767 # サマータイムの期間 クローズ時間: 土曜日の午前6時
6868 if is_dst and hour_minut > 555:
@@ -70,32 +70,32 @@ class EventMng():
7070 'During daylight saving time. '
7171 'The market is closed after 6am on Saturdays.'
7272 )
73- Setting().upcoming_event = False
73+ Setting().weekday_event = False
7474 # サマータイムの期間 クローズ時間: 土曜日の午前6時前
7575 elif is_dst and hour_minut <= 555:
7676 logger.info(
7777 'During daylight saving time. '
7878 'Saturday market not closed yet.'
7979 )
80- Setting().upcoming_event = True
80+ Setting().weekday_event = True
8181 # サマータイム以外の期間 クローズ時間: 土曜日の午前7時
8282 elif not is_dst and hour_minut > 655:
8383 logger.info(
8484 'During non-summertime periods. '
8585 'The market is closed after 7am on Saturdays.'
8686 )
87- Setting().upcoming_event = False
87+ Setting().weekday_event = False
8888 elif not is_dst and hour_minut <= 655:
8989 logger.info(
9090 'During daylight saving time. '
9191 'Saturday market not closed yet.'
9292 )
93- Setting().upcoming_event = True
93+ Setting().weekday_event = True
9494 else:
9595 pass
9696 elif weekday in [4, 3, 2, 1]:
9797 logger.info('It weekday.')
98- Setting().upcoming_event = True
98+ Setting().weekday_event = True
9999 elif weekday == 0:
100100 # サマータイムの期間 オープン時間: 月曜日の午前6時
101101 if is_dst and hour_minut < 610:
@@ -103,17 +103,17 @@ class EventMng():
103103 'During daylight saving time. '
104104 'The market is closed before 6am on Mondays.'
105105 )
106- Setting().upcoming_event = False
106+ Setting().weekday_event = False
107107 # サマータイム以外の期間 オープン時間: 月曜日の午前7時
108108 elif not is_dst and hour_minut < 710:
109109 logger.info(
110110 'During non-summertime periods. '
111111 'The market is closed before 7am on Mondays.'
112112 )
113- Setting().upcoming_event = False
113+ Setting().weekday_event = False
114114 else:
115115 logger.info('It weekday.')
116- Setting().upcoming_event = True
116+ Setting().weekday_event = True
117117
118118 def __check_economic_index_event(self):
119119 """経済指標イベント確認
--- a/src/exchange_rate_info.py
+++ b/src/exchange_rate_info.py
@@ -4,6 +4,7 @@ from datetime import datetime
44 import MetaTrader5 as mt5
55 import talib as ta
66 import numpy as np
7+from numpy import linalg as LA
78 import pytz
89 import logging
910
@@ -35,6 +36,8 @@ class ExchangeRateInfo():
3536 self.__n2 = int(s['Technical']['SlowEMAperiod'])
3637 # シグナル(MACDのSMA)の期間
3738 self.__ns = int(s['Technical']['Signalperiod'])
39+ # 交差角度閾値
40+ self.__angle = float(s['Technical']['CrossingAngleThreshold'])
3841 except Exception as e:
3942 logger.error(e)
4043 raise
@@ -75,6 +78,14 @@ class ExchangeRateInfo():
7578 raise ValueError('Nan is included in the value.')
7679 return series1[-2] < series2[-2] and series1[-1] > series2[-1]
7780
81+ def __vector_angle(self, u: np.ndarray, v: np.ndarray):
82+ if np.isnan(u) or np.isnan(v):
83+ raise ValueError('Nan is included in the value.')
84+ i = np.inner(u, v)
85+ n = LA.norm(u) * LA.norm(v)
86+ c = i / n
87+ return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0)))
88+
7889 def __get_latest_bid(self) -> float:
7990 """最新bid取得
8091 """
@@ -176,39 +187,26 @@ class ExchangeRateInfo():
176187 macdsignal = np.around(macdsignal, 6)
177188
178189 # for debug
179- for i in range(-4, 0, 1):
190+ for i in range(-2, 0, 1):
180191 msg = (
181192 f'num[{i}]: MACD: {macd[i]}, MACDSignal: {macdsignal[i]}'
182193 )
183194 logger.debug(msg)
184195
185196 # 指標判定
186- if self.__crossover(macd, macdsignal) and macd[-1] < 0.0:
197+ v_angle = self.__vector_angle(macd[-2:], macdsignal[-2:])
198+ msg = f'macd vector angle:{v_angle}'
199+ if self.__crossover(macd, macdsignal) and \
200+ v_angle > self.__angle:
187201 # GoldenCross 上昇転換サイン
188202 s.technical_indicator = DEF.TECHNICAL_GOLDEN_CROSS
189203 msg = 'Technical Indicator: GoldenCross.'
190- elif self.__crossover(macdsignal, macd) and macd[-1] > 0.0:
204+ elif self.__crossover(macdsignal, macd) and \
205+ self.__vector_angle(macd[-2:], macdsignal[-2:]) > \
206+ self.__angle:
191207 # DeadCross 降下転換サイン
192208 s.technical_indicator = DEF.TECHNICAL_DEAD_CROSS
193209 msg = 'Technical Indicator: DeadCross.'
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.'
212210 else:
213211 # いずれにも該当しない
214212 s.technical_indicator = DEF.TECHNICAL_UNCHANGED
--- a/src/position_mng.py
+++ b/src/position_mng.py
@@ -48,11 +48,9 @@ class PositionMng():
4848 indicator = s.technical_indicator
4949 # 解消する対象のポジション mt5.ENUM_POSITION_TYPE
5050 position_to_be_canceled: int = -1 # -1:Undefine
51- if indicator == DEF.TECHNICAL_GOLDEN_CROSS or \
52- indicator == DEF.TECHNICAL_UPTREND:
51+ if indicator == DEF.TECHNICAL_GOLDEN_CROSS:
5352 position_to_be_canceled = mt5.POSITION_TYPE_SELL
54- elif indicator == DEF.TECHNICAL_DEAD_CROSS or \
55- indicator == DEF.TECHNICAL_DOWNTREND:
53+ elif indicator == DEF.TECHNICAL_DEAD_CROSS:
5654 position_to_be_canceled = mt5.POSITION_TYPE_BUY
5755 else:
5856 pass