修订版 | bcd96f0d7d235c34951e5811a398b0edcd2c46fc (tree) |
---|---|
时间 | 2023-02-25 12:36:05 |
作者 | kazuhiro_kondow <simauma.circus@gmai...> |
Commiter | kazuhiro_kondow |
setting.ini
角度制限を一時的に解除
exchange_rate_info
Logを整理
テクニカル指標の判定を1つ前も再評価
exchange_rate_info
position_mng
trade_mng
市場が開いてないときは動作抑制
@@ -0,0 +1,226 @@ | ||
1 | +{ | |
2 | + "cells": [ | |
3 | + { | |
4 | + "cell_type": "code", | |
5 | + "execution_count": 8, | |
6 | + "metadata": {}, | |
7 | + "outputs": [ | |
8 | + { | |
9 | + "name": "stdout", | |
10 | + "output_type": "stream", | |
11 | + "text": [ | |
12 | + "u: [0.0016 0.0012]\n", | |
13 | + "v: [0.0014 0.0014]\n", | |
14 | + "vector angle1:8.130102354156005\n", | |
15 | + "u: [-0.0014 -0.0021]\n", | |
16 | + "v: [-0.0018 -0.0018]\n", | |
17 | + "vector angle2:11.309932474020227\n" | |
18 | + ] | |
19 | + } | |
20 | + ], | |
21 | + "source": [ | |
22 | + "# vector angle\n", | |
23 | + "# ベクトルのなす角を用いてMACDのCrossOver判定について改良を試みる\n", | |
24 | + "# 参考文献\n", | |
25 | + "# https://hiraocafe.com/note/2lineanglevec.html\n", | |
26 | + "# https://www.mathpython.com/numpy-vector-angle\n", | |
27 | + "# 誤検知のLogから検証\n", | |
28 | + "\n", | |
29 | + "import numpy as np\n", | |
30 | + "from numpy import linalg as LA\n", | |
31 | + "\n", | |
32 | + "# 2023-02-22 17:31:04,931 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-6]: MACD: 0.0042, MACDSignal: 0.0002\n", | |
33 | + "# 2023-02-22 17:31:04,932 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-5]: MACD: 0.0035, MACDSignal: 0.0008\n", | |
34 | + "# 2023-02-22 17:31:04,932 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-4]: MACD: 0.0029, MACDSignal: 0.0012\n", | |
35 | + "# 2023-02-22 17:31:04,933 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-3]: MACD: 0.0022, MACDSignal: 0.0014\n", | |
36 | + "# 2023-02-22 17:31:04,933 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-2]: MACD: 0.0016, MACDSignal: 0.0014\n", | |
37 | + "# 2023-02-22 17:31:04,934 14620 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-1]: MACD: 0.0012, MACDSignal: 0.0014\n", | |
38 | + "# 2023-02-22 17:31:04,934 14620 MainThread exchange_rate_info.py:237 set_technical_indicators [DEBUG]: vector angle:8.130102354156005\n", | |
39 | + "# 2023-02-22 17:31:04,935 14620 MainThread exchange_rate_info.py:240 set_technical_indicators [DEBUG]: befor turning point:True\n", | |
40 | + "# 2023-02-22 17:31:04,935 14620 MainThread exchange_rate_info.py:252 set_technical_indicators [DEBUG]: Cross down.\n", | |
41 | + "# 2023-02-22 17:31:04,936 14620 MainThread exchange_rate_info.py:300 set_technical_indicators [INFO]: Technical Indicator: DeadCross.\n", | |
42 | + "\n", | |
43 | + "# 2023-02-23 03:45:04,653 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-6]: MACD: -0.0009, MACDSignal: -0.0024\n", | |
44 | + "# 2023-02-23 03:45:04,653 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-5]: MACD: -0.0006, MACDSignal: -0.0021\n", | |
45 | + "# 2023-02-23 03:45:04,654 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-4]: MACD: -0.0008, MACDSignal: -0.0019\n", | |
46 | + "# 2023-02-23 03:45:04,654 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-3]: MACD: -0.0014, MACDSignal: -0.0018\n", | |
47 | + "# 2023-02-23 03:45:04,655 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-2]: MACD: -0.0021, MACDSignal: -0.0018\n", | |
48 | + "# 2023-02-23 03:45:04,656 5892 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-1]: MACD: -0.0027, MACDSignal: -0.002\n", | |
49 | + "# 2023-02-23 03:45:04,656 5892 MainThread exchange_rate_info.py:237 set_technical_indicators [DEBUG]: vector angle:4.112228844718369\n", | |
50 | + "# 2023-02-23 03:45:04,657 5892 MainThread exchange_rate_info.py:240 set_technical_indicators [DEBUG]: befor turning point:True\n", | |
51 | + "# 2023-02-23 03:45:04,658 5892 MainThread exchange_rate_info.py:294 set_technical_indicators [DEBUG]: Re-evaluation Cross down.\n", | |
52 | + "# 2023-02-23 03:45:04,658 5892 MainThread exchange_rate_info.py:300 set_technical_indicators [INFO]: Re-evaluation Technical Indicator: DeadCross.\n", | |
53 | + "\n", | |
54 | + "def vector_angle(u: np.ndarray, v: np.ndarray):\n", | |
55 | + " print(f'u: {u}')\n", | |
56 | + " print(f'v: {v}')\n", | |
57 | + " i = np.inner(u, v)\n", | |
58 | + " n = LA.norm(u) * LA.norm(v)\n", | |
59 | + " c = i / n\n", | |
60 | + " return np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0)))\n", | |
61 | + "\n", | |
62 | + "# 値のスケールに対して角度が大きい印象\n", | |
63 | + "# 入力値を標準化して調整できないか試みる\n", | |
64 | + "m1 = np.array([0.0016, 0.0012])\n", | |
65 | + "s1 = np.array([0.0014, 0.0014])\n", | |
66 | + "m2 = np.array([-0.0014, -0.0021])\n", | |
67 | + "s2 = np.array([-0.0018, -0.0018])\n", | |
68 | + "\n", | |
69 | + "print(f'vector angle1:{vector_angle(m1, s1)}')\n", | |
70 | + "\n", | |
71 | + "print(f'vector angle2:{vector_angle(m2, s2)}')\n" | |
72 | + ] | |
73 | + }, | |
74 | + { | |
75 | + "cell_type": "code", | |
76 | + "execution_count": 9, | |
77 | + "metadata": {}, | |
78 | + "outputs": [ | |
79 | + { | |
80 | + "name": "stdout", | |
81 | + "output_type": "stream", | |
82 | + "text": [ | |
83 | + "v1 array:[0.0016 0.0012 0.0014 0.0014]\n", | |
84 | + "v2 array:[-0.0014 -0.0021 -0.0018 -0.0018]\n", | |
85 | + "v1 nomalize array:[1. 0. 0.5 0.5]\n", | |
86 | + "v2 nomalize array:[1. 0. 0.42857143 0.42857143]\n", | |
87 | + "u: [1. 0.]\n", | |
88 | + "v: [0.5 0.5]\n", | |
89 | + "v1 normalize vector angle1:45.00000000000001\n", | |
90 | + "u: [1. 0.]\n", | |
91 | + "v: [0.42857143 0.42857143]\n", | |
92 | + "v2 normalize vector angle1:45.0\n" | |
93 | + ] | |
94 | + } | |
95 | + ], | |
96 | + "source": [ | |
97 | + "\n", | |
98 | + "# 値を母集団とする標準化(nの標準化)\n", | |
99 | + "# https://note.nkmk.me/python-list-ndarray-dataframe-normalize-standardize/\n", | |
100 | + "v1 = np.append(m1, s1)\n", | |
101 | + "v2 = np.append(m2, s2)\n", | |
102 | + "\n", | |
103 | + "print(f'v1 array:{v1}')\n", | |
104 | + "print(f'v2 array:{v2}')\n", | |
105 | + "\n", | |
106 | + "nom_v1 = (v1 - v1.min()) / (v1.max() - v1.min())\n", | |
107 | + "nom_v2 = (v2 - v2.min()) / (v2.max() - v2.min())\n", | |
108 | + "\n", | |
109 | + "print(f'v1 nomalize array:{nom_v1}')\n", | |
110 | + "print(f'v2 nomalize array:{nom_v2}')\n", | |
111 | + "\n", | |
112 | + "print(f'v1 normalize vector angle1:{vector_angle(nom_v1[:2], nom_v1[-2:])}')\n", | |
113 | + "print(f'v2 normalize vector angle1:{vector_angle(nom_v2[:2], nom_v2[-2:])}')\n", | |
114 | + "\n" | |
115 | + ] | |
116 | + }, | |
117 | + { | |
118 | + "cell_type": "code", | |
119 | + "execution_count": 10, | |
120 | + "metadata": {}, | |
121 | + "outputs": [ | |
122 | + { | |
123 | + "name": "stdout", | |
124 | + "output_type": "stream", | |
125 | + "text": [ | |
126 | + "v1 array:[0.0016 0.0012 0.0014 0.0014]\n", | |
127 | + "v2 array:[-0.0014 -0.0021 -0.0018 -0.0018]\n", | |
128 | + "v1 standard array:[ 1.41421356 -1.41421356 0. 0. ]\n", | |
129 | + "v2 standard array:[ 1.50755672 -1.30654916 -0.10050378 -0.10050378]\n", | |
130 | + "u: [ 1.41421356 -1.41421356]\n", | |
131 | + "v: [0. 0.]\n", | |
132 | + "v1 standard vector angle1:nan\n", | |
133 | + "u: [ 1.50755672 -1.30654916]\n", | |
134 | + "v: [-0.10050378 -0.10050378]\n", | |
135 | + "v2 standard vector angle1:94.08561677997483\n" | |
136 | + ] | |
137 | + }, | |
138 | + { | |
139 | + "name": "stderr", | |
140 | + "output_type": "stream", | |
141 | + "text": [ | |
142 | + "C:\\Users\\user1\\AppData\\Local\\Temp\\ipykernel_9192\\3331901012.py:38: RuntimeWarning: invalid value encountered in double_scalars\n", | |
143 | + " c = i / n\n" | |
144 | + ] | |
145 | + } | |
146 | + ], | |
147 | + "source": [ | |
148 | + "print(f'v1 array:{v1}')\n", | |
149 | + "print(f'v2 array:{v2}')\n", | |
150 | + "\n", | |
151 | + "std_v1 = (v1 - v1.mean()) / v1.std()\n", | |
152 | + "std_v2 = (v2 - v2.mean()) / v2.std()\n", | |
153 | + "\n", | |
154 | + "print(f'v1 standard array:{std_v1}')\n", | |
155 | + "print(f'v2 standard array:{std_v2}')\n", | |
156 | + "\n", | |
157 | + "print(f'v1 standard vector angle1:{vector_angle(std_v1[:2], std_v1[-2:])}')\n", | |
158 | + "print(f'v2 standard vector angle1:{vector_angle(std_v2[:2], std_v2[-2:])}')\n", | |
159 | + "\n" | |
160 | + ] | |
161 | + }, | |
162 | + { | |
163 | + "cell_type": "code", | |
164 | + "execution_count": 14, | |
165 | + "metadata": {}, | |
166 | + "outputs": [ | |
167 | + { | |
168 | + "name": "stdout", | |
169 | + "output_type": "stream", | |
170 | + "text": [ | |
171 | + "u: [-0.13 -0.127]\n", | |
172 | + "v: [-0.1292 -0.1288]\n", | |
173 | + "vector angle3: 0.5799613582311788\n", | |
174 | + "u: [-0.133 -0.127]\n", | |
175 | + "v: [-0.1291 -0.1288]\n", | |
176 | + "vector angle4: 1.255326857283915\n" | |
177 | + ] | |
178 | + } | |
179 | + ], | |
180 | + "source": [ | |
181 | + "\n", | |
182 | + "# 一つ飛ばしではどうか?\n", | |
183 | + "# 2023-02-24 00:26:04,788 13660 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-3]: MACD: -0.133, MACDSignal: -0.1291\n", | |
184 | + "# 2023-02-24 00:26:04,789 13660 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-2]: MACD: -0.13, MACDSignal: -0.1292\n", | |
185 | + "# 2023-02-24 00:26:04,789 13660 MainThread exchange_rate_info.py:208 set_technical_indicators [DEBUG]: num[-1]: MACD: -0.127, MACDSignal: -0.1288\n", | |
186 | + "\n", | |
187 | + "m3 = np.array([-0.13, -0.127])\n", | |
188 | + "s3 = np.array([-0.1292, -0.1288])\n", | |
189 | + "\n", | |
190 | + "print(f'vector angle3: {vector_angle(m3, s3)}')\n", | |
191 | + "\n", | |
192 | + "m4 = np.array([-0.133, -0.127])\n", | |
193 | + "s4 = np.array([-0.1291, -0.1288])\n", | |
194 | + "\n", | |
195 | + "print(f'vector angle4: {vector_angle(m4, s4)}')\n" | |
196 | + ] | |
197 | + } | |
198 | + ], | |
199 | + "metadata": { | |
200 | + "kernelspec": { | |
201 | + "display_name": "venv", | |
202 | + "language": "python", | |
203 | + "name": "python3" | |
204 | + }, | |
205 | + "language_info": { | |
206 | + "codemirror_mode": { | |
207 | + "name": "ipython", | |
208 | + "version": 3 | |
209 | + }, | |
210 | + "file_extension": ".py", | |
211 | + "mimetype": "text/x-python", | |
212 | + "name": "python", | |
213 | + "nbconvert_exporter": "python", | |
214 | + "pygments_lexer": "ipython3", | |
215 | + "version": "3.10.9" | |
216 | + }, | |
217 | + "orig_nbformat": 4, | |
218 | + "vscode": { | |
219 | + "interpreter": { | |
220 | + "hash": "3434ed70bd0ce2eb2bb8ac6e97f0ebaa4c4b8adeb56c97e7db5709836a4a2d70" | |
221 | + } | |
222 | + } | |
223 | + }, | |
224 | + "nbformat": 4, | |
225 | + "nbformat_minor": 2 | |
226 | +} |
@@ -36,7 +36,7 @@ Allowablespread = 0.01 | ||
36 | 36 | # 1銭は0.01円 |
37 | 37 | OpenMergin = 0.007 |
38 | 38 | # 利益確定(円) |
39 | -ProfitTaking = 0.15 | |
39 | +ProfitTaking = 0.125 | |
40 | 40 | # 損切(円) |
41 | 41 | LossCut = 0.265 |
42 | 42 |
@@ -49,4 +49,4 @@ SlowEMAperiod = 56 | ||
49 | 49 | # シグナルの期間 |
50 | 50 | Signalperiod = 10 |
51 | 51 | # 交差角度閾値 |
52 | -CrossingAngleThreshold = 0.576 | |
52 | +CrossingAngleThreshold = 0.0 |
@@ -77,6 +77,9 @@ class ExchangeRateInfo(): | ||
77 | 77 | |
78 | 78 | return ret |
79 | 79 | |
80 | +# 2023-02-24 02:25:04,702 13660 num[-2]: MACD: 0.0215, MACDSignal: 0.0215 | |
81 | +# 2023-02-24 02:25:04,703 13660 num[-1]: MACD: 0.0209, MACDSignal: 0.0214 | |
82 | +# 不発の事象があるため、< から <= に修正 | |
80 | 83 | def __crossover(self, series1: np.ndarray, series2: np.ndarray) -> bool: |
81 | 84 | """指標値列の交差判定 |
82 | 85 | """ |
@@ -85,7 +88,7 @@ class ExchangeRateInfo(): | ||
85 | 88 | np.isnan(series2[-1]) or \ |
86 | 89 | np.isnan(series2[-2]): |
87 | 90 | raise ValueError('Nan is included in the value.') |
88 | - return series1[-2] < series2[-2] and series1[-1] > series2[-1] | |
91 | + return series1[-2] <= series2[-2] and series1[-1] > series2[-1] | |
89 | 92 | |
90 | 93 | def __vector_angle(self, u: np.ndarray, v: np.ndarray): |
91 | 94 | if np.isnan(u[-1]) or \ |
@@ -233,30 +236,34 @@ class ExchangeRateInfo(): | ||
233 | 236 | |
234 | 237 | # 指標判定 |
235 | 238 | v_angle = self.__vector_angle(macd[-2:], macdsignal[-2:]) |
236 | - msg = f'vector angle:{v_angle}' | |
237 | - logger.debug(msg) | |
238 | 239 | |
239 | 240 | msg = f'befor turning point:{s.turning_point}' |
240 | 241 | logger.debug(msg) |
241 | 242 | |
242 | 243 | if self.__crossover(macd[-2:], macdsignal[-2:]): |
243 | - logger.debug('Cross up.') | |
244 | + msg = ( | |
245 | + 'CrossOver up.' | |
246 | + f' vector angle:{v_angle}' | |
247 | + ) | |
244 | 248 | if s.turning_point is not True and v_angle > self.__angle: |
245 | 249 | # GoldenCross 上昇転換サイン |
246 | 250 | s.technical_indicator = DEF.TECHNICAL_GOLDEN_CROSS |
247 | 251 | s.turning_point = True |
248 | - msg = 'Technical Indicator: GoldenCross.' | |
252 | + msg = msg + ' Technical Indicator: GoldenCross.' | |
249 | 253 | else: |
250 | - logger.debug('Already judged goldencross.') | |
254 | + msg = msg + ' Already judged goldencross.' | |
251 | 255 | elif self.__crossover(macdsignal[-2:], macd[-2:]): |
252 | - logger.debug('Cross down.') | |
256 | + msg = ( | |
257 | + 'CrossOver down.' | |
258 | + f' vector angle:{v_angle}' | |
259 | + ) | |
253 | 260 | if s.turning_point is not False and v_angle > self.__angle: |
254 | 261 | # DeadCross 降下転換サイン |
255 | 262 | s.technical_indicator = DEF.TECHNICAL_DEAD_CROSS |
256 | 263 | s.turning_point = False |
257 | - msg = 'Technical Indicator: DeadCross.' | |
264 | + msg = msg + ' Technical Indicator: DeadCross.' | |
258 | 265 | else: |
259 | - logger.debug('Already judged deadcross.') | |
266 | + msg = msg + ' Already judged deadcross.' | |
260 | 267 | elif macd[-1] > 0.0: |
261 | 268 | # 上昇トレンド |
262 | 269 | s.technical_indicator = DEF.TECHNICAL_UPTREND |
@@ -269,6 +276,7 @@ class ExchangeRateInfo(): | ||
269 | 276 | # いずれにも該当しない |
270 | 277 | s.technical_indicator = DEF.TECHNICAL_UNCHANGED |
271 | 278 | msg = 'Technical Indicator: Unchanged.' |
279 | + logger.info(msg) | |
272 | 280 | |
273 | 281 | # 過去指標の再判定 |
274 | 282 | # 2023-02-22 02:17:04 num[-3]: MACD: 0.0278, MACDSignal: 0.0248 > |
@@ -283,21 +291,36 @@ class ExchangeRateInfo(): | ||
283 | 291 | if s.technical_indicator == DEF.TECHNICAL_UPTREND or \ |
284 | 292 | s.technical_indicator == DEF.TECHNICAL_DOWNTREND or \ |
285 | 293 | s.technical_indicator == DEF.TECHNICAL_UNCHANGED: |
294 | + | |
295 | + # 角度再計算 | |
296 | + v_angle = self.__vector_angle(macd[-3:-1], macdsignal[-3:-1]) | |
297 | + | |
286 | 298 | if self.__crossover(macd[-3:-1], macdsignal[-3:-1]): |
287 | - logger.debug('Re-evaluation Cross up.') | |
299 | + msg = ( | |
300 | + 'Re-evaluation Cross up.' | |
301 | + f' vector angle:{v_angle}' | |
302 | + ) | |
288 | 303 | if s.turning_point is not True and v_angle > self.__angle: |
289 | 304 | # GoldenCross 上昇転換サイン |
290 | 305 | s.technical_indicator = DEF.TECHNICAL_GOLDEN_CROSS |
291 | 306 | s.turning_point = True |
292 | - msg = 'Re-evaluation Technical Indicator: GoldenCross.' | |
307 | + msg = msg + ' Technical Indicator: GoldenCross.' | |
308 | + else: | |
309 | + msg = msg + ' Already judged goldencross.' | |
310 | + logger.info(msg) | |
293 | 311 | elif self.__crossover(macdsignal[-3:-1], macd[-3:-1]): |
294 | - logger.debug('Re-evaluation Cross down.') | |
312 | + msg = ( | |
313 | + 'Re-evaluation Cross down.' | |
314 | + f' vector angle:{v_angle}' | |
315 | + ) | |
295 | 316 | if s.turning_point is not False and v_angle > self.__angle: |
296 | 317 | # DeadCross 降下転換サイン |
297 | 318 | s.technical_indicator = DEF.TECHNICAL_DEAD_CROSS |
298 | 319 | s.turning_point = False |
299 | - msg = 'Re-evaluation Technical Indicator: DeadCross.' | |
300 | - logger.info(msg) | |
320 | + msg = msg + ' Technical Indicator: DeadCross.' | |
321 | + else: | |
322 | + msg = msg + ' Already judged deadcross.' | |
323 | + logger.info(msg) | |
301 | 324 | |
302 | 325 | msg = f'after turning point:{s.turning_point}' |
303 | 326 | logger.debug(msg) |
@@ -318,11 +341,13 @@ class ExchangeRateInfo(): | ||
318 | 341 | def execute(self): |
319 | 342 | """処理実行 |
320 | 343 | """ |
344 | + s = Setting() | |
321 | 345 | |
322 | 346 | # 市場チェック |
323 | 347 | _ = self.check_market() |
324 | 348 | |
325 | - # テクニカル分析指標を設定 | |
326 | - _ = self.set_technical_indicators() | |
349 | + if s.is_market_open: | |
350 | + # テクニカル分析指標を設定 | |
351 | + _ = self.set_technical_indicators() | |
327 | 352 | |
328 | 353 | return |
@@ -38,6 +38,10 @@ class PositionMng(): | ||
38 | 38 | try: |
39 | 39 | s = Setting() |
40 | 40 | |
41 | + # 市場フラグ確認 | |
42 | + if not s.is_market_open: | |
43 | + return | |
44 | + | |
41 | 45 | # ポジション取得 |
42 | 46 | positions = self.__get_position() |
43 | 47 |
@@ -300,8 +300,12 @@ class TradeMng: | ||
300 | 300 | # 未決注文の全解除 |
301 | 301 | _ = self.__remove_order() |
302 | 302 | |
303 | + # 市場フラグ確認 | |
304 | + if not s.is_market_open: | |
305 | + return | |
306 | + | |
303 | 307 | # order可否フラグを確認 |
304 | - if not Setting().ready_to_order: | |
308 | + if not s.ready_to_order: | |
305 | 309 | return |
306 | 310 | |
307 | 311 | # tickを取得できない場合はorderしない |
@@ -320,7 +324,7 @@ class TradeMng: | ||
320 | 324 | return |
321 | 325 | |
322 | 326 | # テクニカル指標から注文タイミングを判定 |
323 | - volume = Setting().orderable_lot | |
327 | + volume = s.orderable_lot | |
324 | 328 | if s.technical_indicator == DEF.TECHNICAL_GOLDEN_CROSS: |
325 | 329 | # 成行で買い注文を出す |
326 | 330 | buy_price = ask |