今までのあらすじ。
誰かが言った。
人生の悲劇は2つしかない。
- ひとつは、金のない悲劇
- もうひとつは、金のある悲劇
「ユダヤ人大富豪の教え」の著書・本田健氏は言った。
お金持ちになるには5つの道しかない。
- 1つめは、親から財産や会社を受け継ぐ
- 2つめは、遺産として財産や会社を受け継ぐ
- 3つめめは、大企業で圧倒的な出世をする
- 4つめは、自分でビジネスを興す
- 5つめは、投資で財産を増やす
サラリーマンは3~5が目指すべき目標。
ただ、3は役員レベル(年収3000万~5000万円)。
4の起業ならどうだ?
ベンチャーキャピタルに「ビジョン・信念が無い奴は一生無理」だと否定された。
で、今は5の投資。
システムトレード完全自動化に向けて「Protraの自動起動・自動実行・自動終了」の改良が前回完了した。
暫くは正しく動いていることを確認する目的で、バックテスト結果のメール送信を実装してみる。
最終的に作りたい自動売買の流れは下記のとおり。
完全自動化に向けて着々と進んでいる・・・気はする。
Proxyサーバを経由してメールを送信する
「python STMP メール送信」とかでググると色々とヒットするが、Proxyを利用した場合のメール送信情報は少ない。
が、ドンピシャリなサイトを見つけた。
なお、メールのメッセージ作成は「email.mime.text」を利用した。
1 2 3 4 5 |
# Create message msg = MIMEText(MESSAGE) msg['Subject'] = SUBJECT msg['From'] = FROM_ADDR msg['To'] = TO_ADDR |
ファイルを読み込みTailを返す
バックテストして明日買う銘柄が決まれば、その情報をメールで送信したい。
買う銘柄情報は「lasttrading.txt」というファイル名で出力されるので、その終わりの数十行だけ取り出してみよう。
これも、そのままのスクリプトが落ちていた。
実売買するには、銘柄コードや購入代金等の抽出が必要となるが、今回は取り出すだけに留める。
タスクスケジューラを利用した定期実行
Windowsなので、タスクスケジューラを利用してBATファイルを呼び出すのが自然だろう。
「基本タスクの設定」→「名前:自動システムトレード 」→「毎週」
登録するBATファイルは次のようなものだ。
1 2 3 4 5 6 |
cd C:\Users\HOGE\Desktop\stock\Protra Protra.cli.exe PtSim.cli.exe cd C:\Users\HOGE\Desktop\stock\auto\sbictrl python sendmail.py rem pause |
これで毎日、深夜0時に実行開始して、実行完了後に結果をメールする。
土日は取引無いので実行しない。
その他、実売買に向けては検討項目は多くありそうだ。
Yahoo! JAPAN公式サービス以外からのアクセスも有効にする
実行すると次のエラーが出た。
1 |
"raise SMTPServerDisconnected("Connection unexpectedly closed")" |
Yahoo!メールの設定画面 ( IMAP/POP/SMTPアクセスとメール転送のページ ) で、「Yahoo! JAPAN公式サービス以外からのアクセスも有効にする」を選択する。
これでメール受信が可能になる。
まとめ
自動メールが届くようになったので、システムトレードに飽きていてもメールは見る事になる。
次は作りかけの実売買部分の自動化だ。
暖かくなると、また釣りとか生き物散策がメインになりそうなので、今のうちに作っておきたい。
でも、肝心の勝てるストラテジーが無いんだよなー。
過去の日記を読み直すと2007年から検討始めてるから14年経過してしまった・・・・。
【2020.02.04】 YahooメールのSTMP仕様が変わったので追記。
ソースコード
ファイルの最後の20行を読み込んで、指定のメールアドレスにProxy経由でメールを送信するスクリプトは次のようになる。
色々なサイトからサンプルコードを持ってきて、繋いだだけだ。
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 150 151 152 153 154 155 156 157 158 159 |
import smtplib import socket from email.mime.text import MIMEText #################################################### # # Setting # #################################################### # Proxy PROXY_HOST = "" PROXY_PORT = "" # STMP YOUR_EMAIL_ADDRESS = "" YOUR_PASSWORD = "" STMP_HOST = "smtp.mail.yahoo.co.jp" STMP_PORT = "587" # E-Mail FROM_ADDR = "" TO_ADDR = "" SUBJECT = "Latest Information" MESSAGE = "" # File Path PATH = "..\..\\Protra\\data\\log\\lasttrading.txt" LINE = 20 #################################################### def recvline(sock): """Receives a line.""" stop = 0 line = '' while True: i = sock.recv(1) if i.decode('UTF-8') == '\n': stop = 1 line += i.decode('UTF-8') if stop == 1: print('Stop reached.') break print('Received line: %s' % line) return line class ProxySMTP(smtplib.SMTP): """Connects to a SMTP server through a HTTP proxy.""" def __init__(self, host='', port=0, p_address='',p_port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): """Initialize a new instance. If specified, `host' is the name of the remote host to which to connect. If specified, `port' specifies the port to which to connect. By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised if the specified `host' doesn't respond correctly. If specified, `local_hostname` is used as the FQDN of the local host. By default, the local hostname is found using socket.getfqdn(). """ self.p_address = p_address self.p_port = p_port self.timeout = timeout self.esmtp_features = {} self.default_port = smtplib.SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: raise IOError(code, msg) if local_hostname is not None: self.local_hostname = local_hostname else: # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and # if that can't be calculated, that we should use a domain literal # instead (essentially an encoded IP address like [A.B.C.D]). fqdn = socket.getfqdn() if '.' in fqdn: self.local_hostname = fqdn else: # We can't find an fqdn hostname, so use a domain literal addr = '127.0.0.1' try: addr = socket.gethostbyname(socket.gethostname()) except socket.gaierror: pass self.local_hostname = '[%s]' % addr smtplib.SMTP.__init__(self) def _get_socket(self, port, host, timeout): # This makes it simpler for SMTP to use the SMTP connect code # and just alter the socket connection bit. print('Will connect to:', (host, port)) print('Connect to proxy.') new_socket = socket.create_connection((self.p_address,self.p_port), timeout) s = "CONNECT %s:%s HTTP/1.1\r\n\r\n" % (port,host) s = s.encode('UTF-8') new_socket.sendall(s) print('Sent CONNECT. Receiving lines.') for x in range(2): recvline(new_socket) print('Connected.') return new_socket # Get line N from end of file def tail(f, lines=20): total_lines_wanted = lines BLOCK_SIZE = 1024 f.seek(0, 2) block_end_byte = f.tell() lines_to_go = total_lines_wanted block_number = -1 blocks = [] while lines_to_go > 0 and block_end_byte > 0: if (block_end_byte - BLOCK_SIZE > 0): f.seek(block_number*BLOCK_SIZE, 2) blocks.append(f.read(BLOCK_SIZE)) else: f.seek(0,0) blocks.append(f.read(block_end_byte)) lines_found = blocks[-1].count(b'\n') lines_to_go -= lines_found block_end_byte -= BLOCK_SIZE block_number -= 1 all_read_text = b''.join(reversed(blocks)) return b'\n'.join(all_read_text.splitlines()[-total_lines_wanted:]) def main(): # Both port 25 and 587 work for SMTP conn = ProxySMTP(host=STMP_HOST, port=STMP_PORT, p_address=PROXY_HOST, p_port=PROXY_PORT) conn.ehlo() # if STARTTLS extension supports by server #conn.starttls() conn.ehlo() r, d = conn.login(YOUR_EMAIL_ADDRESS, YOUR_PASSWORD) print('Login reply: %s' % r) # Create message f = open(PATH, 'rb') msg = MIMEText(MESSAGE + tail(f, LINE).decode('utf-8')) msg['Subject'] = SUBJECT msg['From'] = FROM_ADDR msg['To'] = TO_ADDR print('Send email.') conn.sendmail(FROM_ADDR, [TO_ADDR], msg.as_string()) print('Success.') conn.close() if __name__ == '__main__': main() |