SSブログ

当日株価データ取得ロジック解説 [システムトレード]

先日公開しました当日データ取得更新マクロのロジックについて、簡単に解説いたします。なお、以下では主要部分のみを抜き出しており、変数の宣言や取得、書き出しなどは割愛しています。
当然、そのままでは実行できませんのでご注意ください。また、"<"、">"の表記については、ブログの表示崩れ防止のため、全角としています(実際は半角です)。


1:Set objXml = CreateObject("MSXML2.XMLHTTP")
2:  objXml.Open "GET", "http://stocks.finance.yahoo.co.jp _
          /stocks/detail/?code=" & stcCode, False
3:  objXml.Send

4:  If objXml.Statustext = "OK" Then
5:    xmlText = objXml.responsetext

6:    With CreateObject("VBScript.RegExp")
7:      .Pattern = ">([^<>/]+)</strong"
8:      .Global = True

9:      tagCount = .Execute(xmlText).Count
10:      ReDim xmlData(tagCount)

11:      iStart = 0

12:      For i = 0 To tagCount - 1

13:        xmlData(i) = .Execute(xmlText).Item(i)
14:        xmlData(i) = WorksheetFunction _
            .Substitute(xmlData(i), ">", "")
15:        xmlData(i) = WorksheetFunction _
            .Substitute(xmlData(i), "</strong", "")

16:        If xmlData(i) = "期間を保存する" Then iStart = i
17:        If iStart <> 0 And i - iStart > 4 Then Exit For

18:      Next i

19:    End With

20:    cellData(0, 3) = xmlData(iStart + 2)
21:    cellData(0, 4) = xmlData(iStart + 3)
22:    cellData(0, 5) = xmlData(iStart + 4)

23:  End If

24:Set objXml = Nothing


最初の3行の、objXmlに関する記述ですが、これはサイトからデータを取得する際の約束事のようなものです。誰が書いても、だいたいこんな風になると思います。
ちなみに、stcCodeには、ヤフーファイナンス上の証券コード(例えば7203.t)を設定します。

実際にサイトからソースデータを引っ張ってくるのは、3行目のobjXml.Sendの箇所です。この部分を並列処理できれば、はちべえ氏のツールのように高速処理が可能となるのですが、普通に行っただけでは残念ながら逐次処理になってしまいます。

4行目の記述は、サイトにデータが存在するかどうかの確認です。該当する証券コードが存在しない場合は、データの取得を行わずに23行目に飛んで処理を終えます。
これによって、時間の短縮と共に、余計なエラー処理に頭を悩ませる事態を回避できます。

該当する証券コードのサイトが存在する場合、5行目の記述でxmlTextにサイトのソースデータを取り込みます。
以降、このxmlTextをいろいろと加工して、必要なデータを引き出すことになります。

6行目は、データの引き出しを容易にするように、正規表現を用いるための宣言です。そして、7行目で具体的にどのようなデータを引き出すかを定義します。
この例ですと、">"と"</strong"に挟まれた、"<"と">"と"/"を含まない1文字以上の文字を探すことになります。

9行目では、6行目の条件に合う文字列の数を数えています。そして、10行目においてそれらの文字列を格納するxmlDataという配列の大きさを定義します。
これは当然、抽出した文字列の数と一致させることになります。

そして、12行目以降のループ処理において、上記の文字列の中から必要なデータを抜き出すために、xmlDataの中に文字列を一つずつ放り込んで行きます。
13行目は、i番目の文字列を抜き出し、xmlDataのi番目の箱に入れるということを表しています。

この状態では、xmlDataの中にある文字列は、全て頭に">"、お尻に"</strong"がくっついた状態になっています。そこで、これらを削除してやらなければなりません。
その処理を行っているのが、14~15行目です。

なお、これはエクセル97でも動作するように、ワークシート関数のSubstitute関数を用いていますが、エクセル2000以降のみの利用ならばReplace関数を用いても構いません。

そうやって抽出したxmlDataの中に、"期間を保存する"という文字列が見つかった場合、それが何番目のデータであるかを、16行目でiStartに設定します。
この文字列は、ヤフーファイナンスの詳細ページにおける、実在する全ての株価データページに共通して存在します。

すなわち、この"期間を保存する"という文字列は、必要なデータを探すためのアンカーの役割を果たしていることになります。
この文字列の位置を基準として、必要なデータが何番目にあるかを調べ、抽出するわけです。

17行目は公開版では記述していませんが、必要なデータを取得したらそれ以上のデータを取得しても時間の無駄になりますので、そのような場合はループ処理から抜け出すようにしています。
これによって、多少なりとも処理の高速化が図れます。

20~21行目では、そのようにして抽出したデータをcellDataという配列に書き出しています。cellDataはワークシートの特定セル範囲に1対1対応しており、他の処理と合わせて全てのデータを格納した後に、一気にワークシートに書き出します。

ちなみに、20行目のデータは"始値"、21行目は"高値"、22行目は"安値"となります。始値のデータは"期間を保存する"の2つ後、高値は3つ後、安値は4つ後にあるわけです。
5つ以上後にあるデータは不要ですから、17行目においてそれ以上のデータは取得しないようにしています。

最後に24行目で、objXmlを開放して処理を終えます。なお、現在値などは"</strong"で括れませんので、別のタグを探して同様に処理することになります。
そのやり方は、上記と全く一緒です。

基本的には、当該ページのソースを開き、必要なデータがどのタグに関連付けられているかを調べます。続いて、アンカーを探し、必要なデータがアンカーから何番目の位置にあるかを数えます。
そして、上記のロジックを用いて、必要なデータのみを抽出し、例えばcellData配列に格納します。

サイトの仕様が変更になった場合も、基本的な方法は変わりません。タグを確認し、アンカーを確認し、必要なデータがそこから何番目にあるかを確認します。
そして、それらに従来と違いがある場合は、適宜変更してやるわけです。

なお、"InternetExplorer.Application"オブジェクトを利用する場合は、サイト表示の完了を確認するためのループ処理が必要になりますが、"MSXML2.XMLHTTP"オブジェクトの場合は、3行目の処理だけで済んでしまいます。

そのため、データの取得に失敗した場合、タイムアウトエラーが出るまで処理を中断できません。"InternetExplorer.Application"オブジェクトの場合は、ループ処理の中にタイムアウト処理を入れることができたのですが、"MSXML2.XMLHTTP"オブジェクトの場合はそれができないわけです。

そのため、例えばレジストリをいじってタイムアウトエラーが出るまでの時間を短くする、などといった対策が必要となってしまいます。
もっとも、私が知らないだけで、何か別に有効な方法があるのかもしれません。

何せ、"InternetExplorer.Application"オブジェクトと比較して、"MSXML2.XMLHTTP"オブジェクトに関する情報量は極端に不足しています。
もしも何か良い方法をご存知の方がいらっしゃいましたら、お教えいただけますと幸いです。

nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

Facebook コメント

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。