米国株で学ぶPython 2-2
こんにちは。エビです。
今回のnoteは2-1の続きとなっております。読んでない方はまずこちらを!
カフェモカさんの元記事が読みたい方はこちらからどうぞ!
※この解説noteはカフェモカさんの許可をいただいて書いておりますが、カフェモカさんに監修して頂いたわけではありません。解釈違いがあるかもしれませんので予めご了承ください。
では内容に入っていきましょう!↓
前回のnoteではimport の辺りを解説いたしました。今回からはコードに入ります。上から解説してもよく分からない気がするので、自分が分かりやすいと思った順番で解説していきます。
# -*- coding: utf-8 -*-
import os
import time
import schedule
import datetime
import requests
from bs4 import BeautifulSoup
from requests_html import HTMLSession
import numpy as np
import xlwings as xw
import glob
from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver
import csv
symbol = np.full((5000),"------")
ch = np.full((5000),0)
r = np.full((5000),-9999.0)
p = np.full((5000),-9999.0)
wh52 = np.full((5000),-9999.0)
dwh52 = np.full((5000),250)
dath = np.full((5000),250)
dpivot = np.full((5000),250)
pivot = np.full((5000),-9999.0)
pflg = np.full((5000),0)
def wh52check(i):
cnt = 0
hcnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as w:
wreader = csv.reader(w)
for wrow in wreader:
cnt += 1
if cnt > 253:
hcnt = cnt-251
else:
hcnt = 2
scnt = cnt
wh52[i] = 0
cnt = 0
high = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as h:
hreader = csv.reader(h)
for hrow in hreader:
cnt += 1
if hrow[2][len(hrow[2])-1].isdecimal() is True:
if float(hrow[2]) > high:
high = float(hrow[2])
if cnt >= hcnt and float(hrow[2]) > wh52[i]:
wh52[i] = float(hrow[2])
dwh52[i] = scnt-cnt
if dwh52[i] <= 35 and wh52[i] >= high*0.99:
dpivot[i] = dwh52[i]
pivot[i] = wh52[i]
if dwh52[i] >= 10:
pflg[i] = 1
if dwh52[i] > 35 and wh52[i] >= high*0.99:
low = 99999
dlow = 0
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dwh52[i]:
if hrow[3][len(hrow[3])-1].isdecimal() is True:
if float(hrow[3]) < low:
dlow = scnt-cnt
low = float(hrow[3])
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dlow:
if hrow[2][len(hrow[2])-1].isdecimal() is True:
if float(hrow[2]) > pivot[i]:
dpivot[i] = scnt-cnt
pivot[i] = float(hrow[2])
plow = 99999
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dpivot[i]:
if hrow[3][len(hrow[3])-1].isdecimal() is True:
if float(hrow[3]) < plow:
plow = float(hrow[3])
if low >= wh52[i]*0.67 and dpivot[i] >= 10 and dpivot[i] <= int(dwh52[i]*0.5) and pivot[i] >= wh52[i]*0.9 and plow > 0.5*(pivot[i]+low):
pflg[i] = 2
def is_num(s):
try:
float(s)
except ValueError:
return False
else:
return True
def bot():
print("CWHcheck start")
i = 0
if(os.path.exists('C:\\Users\\tmp\\python\\pythonv3\\input.csv')):
with open('C:\\Users\\tmp\\python\\pythonv3\\input.csv', 'r', encoding='shift-jis') as fin:
for line in fin.readlines():
i += 1
toks = line.split('~')
symbol[i] = toks[0]
nsym = i
i = 0
if(os.path.exists('C:\\Users\\tmp\\python\\pythonv3\\52whl.csv')):
with open('C:\\Users\\tmp\\python\\pythonv3\\52whl.csv', 'r', encoding='shift-jis') as fin:
for line in fin.readlines():
i += 1
toks = line.split('~')
wh52[i] = float(toks[2])
ns2 = list(np.arange(1,nsym+1))
# Webページを取得して解析する
#========計算処理========
print('wh52check')
with ThreadPoolExecutor(4) as e:
ret = e.map(wh52check, ns2)
#=======================
f = open("C:\\Users\\tmp\\python\\pythonv3\\d52wh.csv", 'w', encoding='shift-jis')
for jj in range(1,nsym+1):
f.write(str(symbol[jj])+','+str(dwh52[jj])+','+str(dath[jj])+'\n')
f.close()
f = open("C:\\Users\\tmp\\python\\pythonv3\\pivot.csv", 'w', encoding='shift-jis')
for jj in range(1,nsym+1):
f.write(str(symbol[jj])+','+str(pflg[jj])+','+str(pivot[jj])+','+str(dpivot[jj])+'\n')
f.close()
if __name__ == '__main__':
bot()
まずカップウィズハンドルを数値で定義するという所からですね。
カップウィズハンドル
カップウィズハンドルの定義は "オニールの成長株発掘法" から引用します。
"このパターンは7週から65週かけて形成されるが、だいたいは3ヶ月~6ヶ月ほどの期間で作られる。このパターンの高値 (カップの頂点) から安値 (カップの底) の株価調整幅は、12~15%から33%である。
... 株価が少なくとも30%上昇したかどうかをまず見極め、..."
との記載があります。書籍が気になった方はこちらから。↓
今回はこの条件に合致するかを判断するようなコードとなっています。
yahoo finance 等で入手する株価のデータは1週間が5日分 (月から金) なので、7週から65週というのは 35日から325日という風に言い換えることが出来ますが65週は1年を越えますね。今回カフェモカさんのコードでは1年を超えるカップウィズハンドルは弾いています。
先ほどの言葉の定義にある通り、カップウィズハンドルを判断するためにはいくつか必要な条件があることが分かります。
それぞれの値を定義する必要があります。どのように定義すればよいでしょうか。なるべく抜けのないように定義をする必要がありますね。
コード化したりコードを解説する前に、まずは日本語で書いてみましょう。
書くべきコードはおおよそ以下の通り。
1.個別銘柄ファイルを開き、直近1年分のデータのみを利用する。
2.高値を定義。(カップの左端)
3.高値を付けた日以降で安値を定義。(カップの底)
4.安値を付けた日を起点としてカップの右側の高値を定義。(カップの右側、ハンドルの付け根)
5.条件確認。
このような流れですね。どうでしょう、いざ言葉にするとなるとわりとややこしいと感じた方が多いのではないでしょうか。これをコードにするとなると素人にはかなり至難の業です。
最後に、今回カフェモカさんがデータソースとして利用されているエクセルファイルを確認してから実際のコードに触れていきましょう。
例として $AAPL のファイルがアップされています。おそらくyahoo finance からダウンロードしたものと思われます。
今回必要なのは High の列と Low の列ですね。オニールは、出来高に関しても言及していますが、このコードではあくまでも高値、安値に絞ってあります。
High の列はCの列、LowはDの列なので、python上ではHigh の列は2番目、Lowの列は3番目になります。
解説で登場するのは次回以降ですが、重要なことですので記載しました。
お待たせしました。それでは実際にコードを見ていきましょう。
コード解説
def wh52check(i):
cnt = 0
hcnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as w:
wreader = csv.reader(w)
for wrow in wreader:
cnt += 1
if cnt > 253:
hcnt = cnt-251
else:
hcnt = 2
scnt = cnt
wh52[i] = 0
cnt = 0
high = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as h:
hreader = csv.reader(h)
for hrow in hreader:
cnt += 1
if hrow[2][len(hrow[2])-1].isdecimal() is True:
if float(hrow[2]) > high:
high = float(hrow[2])
if cnt >= hcnt and float(hrow[2]) > wh52[i]:
wh52[i] = float(hrow[2])
dwh52[i] = scnt-cnt
if dwh52[i] <= 35 and wh52[i] >= high*0.99:
dpivot[i] = dwh52[i]
pivot[i] = wh52[i]
if dwh52[i] >= 10:
pflg[i] = 1
if dwh52[i] > 35 and wh52[i] >= high*0.99:
low = 99999
dlow = 0
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dwh52[i]:
if hrow[3][len(hrow[3])-1].isdecimal() is True:
if float(hrow[3]) < low:
dlow = scnt-cnt
low = float(hrow[3])
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dlow:
if hrow[2][len(hrow[2])-1].isdecimal() is True:
if float(hrow[2]) > pivot[i]:
dpivot[i] = scnt-cnt
pivot[i] = float(hrow[2])
plow = 99999
cnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as p:
preader = csv.reader(p)
for hrow in preader:
cnt += 1
if cnt >= scnt - dpivot[i]:
if hrow[3][len(hrow[3])-1].isdecimal() is True:
if float(hrow[3]) < plow:
plow = float(hrow[3])
if low >= wh52[i]*0.67 and dpivot[i] >= 10 and dpivot[i] <= int(dwh52[i]*0.5) and pivot[i] >= wh52[i]*0.9 and plow > 0.5*(pivot[i]+low):
pflg[i] = 2
少しずつ区切って説明します。
def wh52check(i):
cnt = 0
hcnt = 0
with open('C:\\Users\\tmp\\python\\dailychartdownload\\'+str(symbol[i])+'.csv') as w:
wreader = csv.reader(w)
for wrow in wreader:
cnt += 1
if cnt > 253:
hcnt = cnt-251
else:
hcnt = 2
scnt = cnt
まず一行目のdef についてです。def はdefine の略で、関数を定義します。関数を定義するとは、長いプログラムをひとまとめにするようなイメージです。
Aという作業をしてBという作業をしてCという作業をして… この一連の作業を○○と呼ぼう!みたいなイメージです。
この一連の作業に名前を付けておくことで、次から指示を出す際に○○して!と言えばすぐ伝わりますね。今回はwh52check という名前の指示ということになります。
続いて with 文はファイルを閉じる作業まで行ってくれる便利な文です。pythonでエクセルファイルなどを扱う場合、open とclose の2つの作業を行う必要があります。それをひとまとめにしてくれるのがwith です。with とつけるだけで、出番の終わったファイルは勝手にcloseしてくれます。便利ですね。
with の行と次の行はエクセルファイルを開く操作です。open の後ろのカッコの中はファイルの住所です。この住所は人によって異なります。実際にコードを動かしたい人は、コピペだとここでエラーが出ちゃいますので要注意です!
openでcsvファイルを開いた後、読み込んだデータを wreader という変数に代入しています。
その後の for の文章は繰り返し構文でしたね。 wreader に入ったデータを wrow に入れるたびにcnt が1増えます。つまりはデータ数をカウントする構文です。今回のファイルの場合は一日のデータ (その日の始値、高値、安値、終値、出来高) が1データとなりますので、何日分のデータがあるかが分かります。
cntが253より大きい場合、すなわちデータが一年分以上あるときはカップの判定に不要な部分 (hcnt) を hcnt=cnt-251 としています。イメージはこんな感じ↓ (縦軸は株価、横軸は時間軸)
データが1年分以上あるver.
これをイメージした時に、使用するデータを「直近から251日分」とした方がこんなややこしいことしなくていいんじゃないかな?と思ったのですが、データが251日分もない銘柄の処理が出来なくなるので、こうしたひと手間を加えているものと予想されます。
データが1年分ないver.
※251日分のデータが無いのでエラーが出てしまう!
先ほどカウントした総データ数をscnt に代入してひと段落です。コードを見ていただくと分かるのですが、今後もcntは色んな所で登場します。勿論別の変数名を入れても良いのですが、カフェモカさんはcntでカウントして、数えた値を別の変数に入れるような方法を取られています。
あまりに長くなってもあまり良くないので、今回はここまでにします!
もう少し更新の頻度上げたいんですがなかなか手が進まず…(コードの解読に時間がかかってるのもあります)
またの更新をお待ちください!
最後まで読んでいただきありがとうございました!!!
ここから先は
¥ 500
この記事が気に入ったらサポートをしてみませんか?