VB.NETで楽天RSSから情報を取得する方法
今回はKATSでも使用している「NDde」というクラスライブラリを使って楽天RSS(Realtime Spread Sheet)から情報を取得する方法をご紹介します。楽天RSSはDDE(Dynamic Data Exchange)という昔ながらの技術を使用してデータ交換を行っています。DDEはWindows2.0の頃からある枯れた技術だそうです。.NET FrameworkはDDEをサポートしていないのですが、ネイティブなコードを書けば呼び出せます。でもそれはかなり敷居が高いです。ですが複雑な処理をラップして.NETのクラスとしてDDEを扱う事が出来るクラスライブラリ「NDde」が無償提供で存在しますので積極的に利用するべきだと思います。ダウンロードしたファイルを展開して.NETプロジェクトからNDde.dllを参照指定すれば、すぐに使用する事が出来ます。楽天RSSを使用されている方はご存知ですが、楽天RSSはMarketSpeedを立ち上げてログインしていないと使えない仕組みになっています。恐らく楽天証券の口座を開設していなかったりMarketSpeedの使用料を払っていない人が楽天RSSだけ使用する事に歯止めを掛けるためだと思っています。NDdeは楽天RSSを経由して情報を取得するので、.NETから情報を取得するためには事前に・楽天RSSを立ち上げる・MarketSpeedを立ち上げ、ログインする事が大前提になります。では実際.NETのソースから使用する部分について解説を続けます。ちなみに私はVB2005 Express Editionを使用していますのでVB2005EEベースでソースを書きます。C#やVB.NETの旧バージョンの方は読み替えて下さい。DDEを使いデータを取得する方法は大きく分けて2つあります。1つは「○○のデータを下さい」とリクエストし、データを返してもらう方法。もう1つは「○○のデータに変更があれば通知して下さい」とお願いし、データに変更があるたびにイベントを発生させてもらう方法。前者は自分から要求しない限りデータをもらえないので、例えば現在の株価などを調べるとなるとループを回して定期的に要求し、今の株価が何円なのか取得する必要があります。その方法でも実現可能なのですが、全く値動きしていないかも知れないデータを要求するのは無駄ですし「定期的」のインターバルの長短によって精度とパフォーマンスのトレードオフを考慮しなければならないので大変です。なので前者は銘柄名や市場名、あるいは「前日終値」など不変データを取得する時に使用するのが適切だと思います。逆に後者はリアルタイム情報の取得に適しています。DDEに対し「現在値(株価)の監視を開始して」と命令すると、その銘柄の株価に変更があった時にイベントが発生します。なのでこちらが一定のタイミングで「今何円か」と聞く必要なく、イベントハンドラに「株価が変更された時の処理」を記述するだけでよくなります。これはVBやC#の利点だと思うので是非使いたい機能です。前置きはこのぐらいにして実際のコードを紹介します。NDdeにはNDde.Client.DdeClientというクラスがあり、このクラスを使って情報を取得します。DDEにはサービス名、トピック名というものがありますが、楽天RSSに置き換えて考えるとサービス名は「RSS」、トピック名は「銘柄コード.市場コード(9898.Tなど)」です。DdeClientのコンストラクタにはこの2つを指定しないといけません。つまり、扱う銘柄の数だけDdeClientのインスタンスを生成する事になります。Dim ddeClient As DdeClient = New DdeClient("RSS", "9898.T")のような感じです(こうやって名前空間を省略して記述するには、ソースの先頭に「Imports NDde.Client」が必要です)。では早速、このDDEクライアントで9898.T(サハダイヤモンド)の株価を取得してみましょう。Dim byteData as Byte() = ddeClient.Request("現在値", 1, 6000)これでOKです。第二引数の「1」はお作法だと思ってもらって結構です。「6000」はタイムアウトのミリ秒で、この設定だと1分間までは応答を待つ事になっています。もっとも、この処理に1分掛かってるようじゃ明らかに異常ですが(汗)。ただこのままだと問題があります。返って来るデータがバイト配列です。扱い辛いですよね。データを文字列で返してくれるシグニチャ(メソッドと引数の組み合わせ)もあるのですが、それは使わずバイト配列を返してくれるこのメソッドを使用する事をお勧めします。株価なら良いのですが、銘柄名称などの2バイト文字を取得する時、文字列で取得すると気持ち良く文字化けしてくれます(笑)。何故なら楽天RSSは文字コードをShift-JISで返すようなので、.NETのUnicodeとは文字コードが異なるからです。化けてしまったデータはもうどうしようもないので、バイト配列でもらって自分でエンコードしてやる必要があるんです。具体的にはEncoding.Default.GetString(byteData, 0, byteData.Length - 1)と書けます(こうやって名前空間を省略して記述するには、ソースの先頭に「Imports System.Text」が必要です)。また、楽天RSSから取得される数値データには余計な文字を含むものが多いです。例えば株価を取得しているのに「150.00」など。文字列で取得してこんなのが返って来ても不便です。見栄えよくするため、CInt(price)で整数型に変換してやると良いでしょう。ただ現在値など、ザラ場開始前に取得すると空文字("")を返してくるものは要注意です。0円ではなく、まだ値がない状態です。その時にはCIntで変換を掛けると異常終了しますので考慮が必要です。続いて、2つ目の方法(変更を通知してもらう方法)を試してみましょう。変更を通知してもらうメソッドはDdeClientのStartAdviseメソッドです。Subなので戻り値はありません。ddeClient.StartAdvise("現在値", 1, 6000)と記述します。こうする事によって、DDEクライアントの「現在値(株価)」に変更があった時にclientの「Adviseイベント」が発生します。そのイベントはVBで拾わないといけません。でも定期的に「イベントが発生したかな?」などと調査するのではなく「イベントハンドラを追加する」という作業を行います。AddHandler ddeClient.Advise, AddressOf Client_Adviseと記述したとします。すると、ddeClientインスタンスでAdviseイベントが発生すると、Client_Adviseというメソッドが起動されるようになります(メソッド名の「Client_Advise」は任意)。この記述を書かないと発生したイベントは拾えないので、注意が必要です。私もハマッたのですが、ddeClient.StartAdvise("現在値", 1, 6000)AddHandler ddeClient.Advise, AddressOf Client_Adviseという2行を書いてやると、1行目を処理してから2行目を処理するまでの間に発生したイベントは拾えません!つまり開始した直後のイベントが無視される可能性があるのです。なので、イベントハンドラの登録が先だという事に注意して下さい。AddHandler ddeClient.Advise, AddressOf Client_AdviseddeClient.StartAdvise("現在値", 1, 6000)ちなみに、他の項目の監視を開始して変更が発生した時でもイベントは「Advise」1つだけだという事に注目です。つまり複数項目を監視させている場合にはイベントハンドラ中で「どの項目に変更があったのか」を判断する必要があるのです。では、AddHandler ddeClient.Advise, AddressOf Client_Adviseclient.StartAdvise("現在値", 1, 6000)client.StartAdvise("高値", 1, 6000)client.StartAdvise("安値", 1, 6000)と書いた時に、どうやって変更通知を処理するかについて説明します。イベントハンドラメソッドは、名前は何でも良いのですが引数の型や数はイベントの規則に従っている必要があります。NDdeClient.Adviseイベントの引数はNDde.Client.DdeAdviseEventArgsですが、これは従うしか無いのでお作法だと思ってこう記述します。Private Sub Client_Advise(ByVal sender As Object, ByVal e As DdeAdviseEventArgs) : :End Subこの引数が非常に重要です。senderの実体はDdeClientクラスのインスタンスです。DdeClientにキャストしてやれば、Topicプロパティの値を見る事によって「どの銘柄に変更があったのか」を知る事が出来ます。Dim client as DdeClient = DirectCast(sender, DdeClient)Dim topic as String = client.Topic監視する銘柄が複数で、それらに全く同じイベントハンドラを割り当てる場合は無くてはならないものです。次に、監視銘柄のどの項目に変更があったか知る必要があります。それはもう1つの引数であるeを使います。「e.Item」が項目名ですので、例えばIf e.Item.Equals("現在値") Then '現在値に変更があった時の処理Else :という判断が可能になります。また変更されたデータそのものは「e.Data」で、バイト配列です。DdeClient.Request()メソッドで返って来るバイト配列と同じように扱います。長くなりましたが、以上がNDdeというクラスライブラリを使ってVB.NETから楽天RSS経由で株式情報を取得する方法です。エラーハンドリングやその他必要な情報を省略して本当に基本的な部分しか書いてませんが参考になる方にはなるのでは、と思います。私はもちろんこれらをベタで書いている訳ではなく、使いやすい部品としてDdeManagerというユーティリティクラスを作成しています。もし「欲しい!」という方がいらっしゃれば連絡下さい。いかなる不具合が発生しても保証しないという条件付きで、無償で提供します(笑)。「いや、今後の開発の為に是非寄付させて欲しい」という奇特な方がいらっしゃれば遠慮なくお申し出下さい。それも大歓迎ですよw