多くの巷のストラテジーのバックテストを行い、有効性の検証をし続けている。
ライブラリや検証結果の詳細表示等も継続的に拡張し、バックテスト実施環境の快適化を進めている。
が、自動売買部分の開発が全く進んでない。
- 【完】SBI証券へアクセス
- 【完】購入候補銘柄の現在の株価チェック
- 【完】購入希望額に達しているかのチェック → 今はここでメール送信
- 【未】購入可能数のチェック
- 【未】信用買い
- 【未】売りの指値セット
- 【未】指値キャンセル
- 【未】(当日中の)信用売り
自動発注処理の実装は、とたんに楽しくなくなる。何故だろう。
購入銘柄候補のメールが毎日届くはずなのに、時々メールが届かない。
これで2回目だなぁ……理由をさぐるか。
エラー内容を確認する
出ているエラーを見てみると次のように出力されていた。
1 |
UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 471: illegal multibyte sequence |
どうやら、デフォルトの場合、文字のコーディングはUTF-8になるが、Windows環境を使用しているとデフォルトがcp932(Shift-JIS)でコーディングされる。
なので、プログラムにUTF-8でコーディングする様に記述を加える。
1 |
f = open(r'C:\Users\UserName\Desktop\test.json','r',encoding="utf-8") |
もしくは次のようにする(UTF-8でBOMが付く場合)。
1 |
f = open(r'C:\Users\UserName\Desktop\test.json','r',encoding="utf-8_sig") |
ここまでは、どのサイトを見ても書いてある。
悪さをしているコードを消す
何かの理由で文字コードが入ってしまっている場合もある。
そもそもUnicodeEncodeErrorの原因は、CP932へ変換できないコードが含まれているのが原因なので、その悪さをしているコードを消してしまえば解決する。
1 |
s2 =s.replace('\xa0', '') |
ただ、CP932へ変換出来ないコードを網羅的に対応するのは面倒だし漏れやすい。
その場合は、encode関数に変換出来ない場合は無視するオプションを利用するのがよい。
1 |
s.encode('cp932', "ignore") |
この情報も多くないが見つかる。
上記で解決しない場合の対応
今回エラーの出たコードはこうなっている。
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 |
import smtplib import socket from email.mime.text import MIMEText import ssl import socks # Proxy PROXY_HOST = "****" PROXY_PORT = "10080" # STMP YOUR_EMAIL_ADDRESS = "****@****.co.jp" YOUR_PASSWORD = "*****" STMP_HOST = "smtp.mail.yahoo.co.jp" STMP_PORT = "465" # E-Mail FROM_ADDR = "****@****.co.jp" TO_ADDR = "****@****.co.jp" #################################################### socks.setdefaultproxy(socks.HTTP, PROXY_HOST, int(PROXY_PORT)) socks.wrapmodule(smtplib) # In the case of SSL context = ssl.create_default_context() conn = smtplib.SMTP_SSL(STMP_HOST, int(STMP_PORT), timeout=10, context=context) r, d = conn.login(YOUR_EMAIL_ADDRESS, YOUR_PASSWORD) print('Login reply: %s' % r) # Create message msg = MIMEText("text") msg['Subject'] = "subject" msg['From'] = FROM_ADDR msg['To'] = TO_ADDR conn.sendmail(FROM_ADDR, [TO_ADDR], msg.as_string()) conn.close() |
以前作成したYahooを経由してメールを飛ばす方法だ。
ここに「open」処理なんて存在しない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Traceback (most recent call last): File "sendmail.py", line 28, in <module> conn = smtplib.SMTP_SSL(STMP_HOST, int(STMP_PORT), timeout=10, context=context) File "C:\Python38\lib\smtplib.py", line 1034, in __init__ SMTP.__init__(self, host, port, local_hostname, timeout, File "C:\Python38\lib\smtplib.py", line 253, in __init__ (code, msg) = self.connect(host, port) File "C:\Python38\lib\smtplib.py", line 339, in connect self.sock = self._get_socket(host, port, self.timeout) File "C:\Python38\lib\smtplib.py", line 1040, in _get_socket new_socket = socket.create_connection((host, port), timeout, File "C:\Python38\lib\socket.py", line 796, in create_connection sock.connect(sa) File "C:\Python38\lib\site-packages\socks.py", line 47, in wrapper return function(*args, **kwargs) File "C:\Python38\lib\site-packages\socks.py", line 809, in connect negotiate(self, dest_addr, dest_port) File "C:\Python38\lib\site-packages\socks.py", line 689, in _negotiate_HTTP status_line = fobj.readline() UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 471: illegal multibyte sequence |
こんなライブラリの奥底でデコード処理の不具合出ても修正したくない。
というより、コードを見ても何が悪いのか分からなかった……。
解決方法
まずは、次のようなスクリプトで文字コードを確認する。
1 2 |
import locale print(locale.getpreferredencoding(False)) |
結果はcp932(Shift-JIS)だった。
1 |
cp932 |
色々と解決方法をググった結果、次で回避可能だった。
1 |
python -X utf8 sendmail.py |
要するに、「-X utf8」 を python コマンドに指定することで、UTF-8 モードとしてスクリプトを呼び出す。
これは、Windows の環境変数で PYTHONUTF8 を 1 と設定することでも対応可能だ。
【付録】エラー「403: Forbidden」に対する対策
私にとってはこちらが本題。
文字コード対応は終わったが、何度もメール送信していると今度は次のようなエラーが出るようになった。
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 |
[*] Note: The HTTP proxy server may not be supported by PySocks (must be a CONNECT tunnel proxy) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "sendmail.py", line 65, in <module> main() File "sendmail.py", line 47, in main conn = smtplib.SMTP_SSL(STMP_HOST, int(STMP_PORT), timeout=10, context=context) File "C:\Python38\lib\smtplib.py", line 1034, in __init__ SMTP.__init__(self, host, port, local_hostname, timeout, File "C:\Python38\lib\smtplib.py", line 253, in __init__ (code, msg) = self.connect(host, port) File "C:\Python38\lib\smtplib.py", line 339, in connect self.sock = self._get_socket(host, port, self.timeout) File "C:\Python38\lib\smtplib.py", line 1040, in _get_socket new_socket = socket.create_connection((host, port), timeout, File "C:\Python38\lib\socket.py", line 808, in create_connection raise err File "C:\Python38\lib\socket.py", line 796, in create_connection sock.connect(sa) File "C:\Python38\lib\site-packages\socks.py", line 47, in wrapper return function(*args, **kwargs) File "C:\Python38\lib\site-packages\socks.py", line 814, in connect raise GeneralProxyError("Socket error", error) socks.GeneralProxyError: Socket error: 403: Forbidden [*] Note: The HTTP proxy server may not be supported by PySocks (must be a CONNECT tunnel proxy) |
ひとつ積んでは父のため。
ふたつ積んでは母のため。
みっつ積んではふるさとの、兄弟我が身と回向する。
日も入りあいのその頃は、地獄の鬼が現れて、我を恨むる事なかれと、くろがねの棒を伸べ、積みたる塔を押し崩す。
ガシャーン
あぁ・・・・またやり直し・・・。
これはこの世のことならず、死出の山路の裾野なる、賽の河原の物語
と書いて、過去の日記を見直すと前回のメール対応で全く同じこと書いてたわ……
403 Forbiddenエラーは、ウェブサイトが閲覧禁止になっている状態を表すHTTPステータスコード。
恐らくサーバー管理会社側が規制してしまったのかもしれない。
こりゃ、もうお手上げ!
諦めて違う方法を模索した
私のサーバに一旦POSTとして投げて、サーバー側でメール送信することにした。
最初からこうしておけば良かったわ。時間の無駄だったわ。
1 2 3 4 5 6 7 8 9 10 11 12 |
import requests path = "hoge.txt" bar = "" with open(path) as f: bar = f.read() POST_URL = "POST受信先サイト.php" response = requests.post(POST_URL, data={'subject': 'タイトル', 'message': bar}) print(response.status_code) # HTTPのステータスコード取得 print(response.text) # レスポンスのHTMLを文字列で取得 |
そしてサーバー側のPHPは次のようにする。
1 2 3 4 5 6 7 8 9 10 11 |
$detail = $_POST["message"]; $subject = $_POST["subject"]; $detail = mb_convert_encoding($detail, 'sjis-win', 'utf8'); $subject = mb_convert_encoding($subject, 'sjis-win', 'utf8'); send_mail("", "送信先メールアドレス", $detail, $subject, "送信元メールアドレス"); print("sucess!") ?> |
一週間程度経過したけど、今のところ毎日メールは届いている。
まとめ
最終的にはメールで届くのではなく発注する必要がある。
この調子だと発注失敗とか大量に出そうだな……。
嫌なのは信用買いが成功しても当日信用売りがシステムのバグで出来なかった場合。
手数料無料から始めるつもりだけど、放置してたら悲惨な状況になりそうだな。