<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>週刊（月刊？）プレカリアート &#187; 自動トレーディングへの道</title>
	<atom:link href="http://blog.neoneet.jp/category/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%93/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.neoneet.jp</link>
	<description>ニートになりそうな私が好き勝手書きます</description>
	<lastBuildDate>Sat, 24 Dec 2011 06:19:08 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>カブロボその1</title>
		<link>http://blog.neoneet.jp/2008/09/15/%e3%82%ab%e3%83%96%e3%83%ad%e3%83%9c%e3%81%9d%e3%81%ae1/</link>
		<comments>http://blog.neoneet.jp/2008/09/15/%e3%82%ab%e3%83%96%e3%83%ad%e3%83%9c%e3%81%9d%e3%81%ae1/#comments</comments>
		<pubDate>Sun, 14 Sep 2008 20:59:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[カブロボ]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=108</guid>
		<description><![CDATA[とりあえず何か簡単でいいからカブロボを作ろうということで作成してみた。 25日移動平均線の傾きの正負で短期トレンドを決める 25日線の傾きが正なら（短期）上昇トレンド、負なら短期下降トレンドと判断することにする。上昇トレンドの株は買いのみ。下降トレンドの株は空売りしかしない。 5日移動平均線の乖離率で絞り込む 上昇トレンドの銘柄は、5日移動平均線の乖離率が-3%から-7%の間にあるとき、次の取引（翌日あるいは後場）に成り行き買いで発注する。設定を変更しないとカブロボは資金の10%しか買えないので、めいっぱい買うように指示する。逆に下降トレンドの場合は5日線を3%から7%上抜いているときに空売りする。 なぜ7%かというと、あまり極端に突き抜けている場合は何かとんでもない材料があったと判断することにしたからである。 ロスカットはしないことにした デフォルトで-20%の損失で強制ロスカットになっているため、ロスカットはあえてしないことに（パラメータとして-40%の損失でロスカットにしてあるが、これが発動することはない）。 脱出条件は高値から10%以上下落したとき 色々な人のカブロボを見ていると「5%の利益で利益確定、10%の損失でロスカット」のようなものが多いように思う。しかし、これだと利益を十分に確保できないので、貪欲に利益を追求するようにした。上昇している間はずっと放置し、下落トレンド化が鮮明になると初めて売ることにする。ただし利益がマイナスの場合は売らない。 結果 ■■最終成績表■■■■■■■■■■■■■■■■■■■■ &#8211;●取引データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; 初期資産額(円)　　　　　　：50,000,000 最終資産額(円)　　　　　　：54,256,219 取引開始日　　　　　　　　：2006-01-04 取引終了日　　　　　　　　：2006-12-29 経過日数(日)　　　　　　　：359 運用日数(日)　　　　　　　：248 総トレード数　　　　　　　：120 勝ちトレード数　　　　　　：74 負けトレード数　　　　　　：46 勝率(％)　　　　　　　　　：61.67 年間平均トレード数　　　　：120 全トレード平均期間(日)　　：70 勝ちトレード平均期間(日)　：70 負けトレード平均期間(日)　：70 最長フラット期間(日)　　　：20 トータル約定金額(円)　　　：426,073,050 &#8211;●損益データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; トータル純損益(％)　　　　：8.51 勝ちトレード純利益(％)　　：27.16 負けトレード純損失(％)　　：-17.25 買いトレード純損益(％)　　：3.71 売りトレード純損益(％)　　：6.2 平均損益(％)　　　　　　　：1.42 平均利益(％)　　　　　　　：9.33 平均損失(％)　　　　　　　：-11.3 年率換算利回り(％)　　　　：8.41 最大勝ちトレード(％)　　　：42.12 最大負けトレード(％)　　　：-22.74 &#8211;●指標データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; 平均ドローダウン(％)　　　：2.51 最大ドローダウン(％)　　　：12.72 損益レシオ(倍)　　　　　　：0.98 プロフィットファクター(倍)：1.57 リスクレシオ(倍)　　　　　：0.66 年率シャープレシオ(倍)　　：0.8 年率ボラティリティ(％)　　：10.49 ■■■■■■■■■■■■■■■■■■■■■■■■■■■ 考察 最大勝ちトレードが42%なのが特徴と言える。一方で損失も大きい。設定によって小さくこつこつ、大きく負けないカブロボも可能だけれど、貪欲な利益を追求するようにした。パラメータはいろいろ調整してみた。高値から5%下がったら売るより10%くらい我慢した方が結果がよいとか、購入条件も3〜7%としたけれど、これも色々調整した結果。 パラメータの調整は自動でできるようになるといいのだけれど。]]></description>
			<content:encoded><![CDATA[				<p>とりあえず何か簡単でいいからカブロボを作ろうということで作成してみた。</p>
				<h3>25日移動平均線の傾きの正負で短期トレンドを決める</h3>
				<p>25日線の傾きが正なら（短期）上昇トレンド、負なら短期下降トレンドと判断することにする。上昇トレンドの株は買いのみ。下降トレンドの株は空売りしかしない。</p>
				<h3>5日移動平均線の乖離率で絞り込む</h3>
				<p>上昇トレンドの銘柄は、5日移動平均線の乖離率が-3%から-7%の間にあるとき、次の取引（翌日あるいは後場）に成り行き買いで発注する。設定を変更しないとカブロボは資金の10%しか買えないので、めいっぱい買うように指示する。逆に下降トレンドの場合は5日線を3%から7%上抜いているときに空売りする。</p>
				<p>なぜ7%かというと、あまり極端に突き抜けている場合は何かとんでもない材料があったと判断することにしたからである。</p>
				<h3>ロスカットはしないことにした</h3>
				<p>デフォルトで-20%の損失で強制ロスカットになっているため、ロスカットはあえてしないことに（パラメータとして-40%の損失でロスカットにしてあるが、これが発動することはない）。</p>
				<h3>脱出条件は高値から10%以上下落したとき</h3>
				<p>色々な人のカブロボを見ていると「5%の利益で利益確定、10%の損失でロスカット」のようなものが多いように思う。しかし、これだと利益を十分に確保できないので、貪欲に利益を追求するようにした。上昇している間はずっと放置し、下落トレンド化が鮮明になると初めて売ることにする。ただし利益がマイナスの場合は売らない。</p>
				<h3>結果</h3>
				<blockquote><p>
				■■最終成績表■■■■■■■■■■■■■■■■■■■■<br />
				&#8211;●取引データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
				初期資産額(円)　　　　　　：50,000,000<br />
				最終資産額(円)　　　　　　：54,256,219<br />
				取引開始日　　　　　　　　：2006-01-04<br />
				取引終了日　　　　　　　　：2006-12-29<br />
				経過日数(日)　　　　　　　：359<br />
				運用日数(日)　　　　　　　：248<br />
				総トレード数　　　　　　　：120<br />
				勝ちトレード数　　　　　　：74<br />
				負けトレード数　　　　　　：46<br />
				勝率(％)　　　　　　　　　：61.67<br />
				年間平均トレード数　　　　：120<br />
				全トレード平均期間(日)　　：70<br />
				勝ちトレード平均期間(日)　：70<br />
				負けトレード平均期間(日)　：70<br />
				最長フラット期間(日)　　　：20<br />
				トータル約定金額(円)　　　：426,073,050<br />
				&#8211;●損益データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
				トータル純損益(％)　　　　：8.51<br />
				勝ちトレード純利益(％)　　：27.16<br />
				負けトレード純損失(％)　　：-17.25<br />
				買いトレード純損益(％)　　：3.71<br />
				売りトレード純損益(％)　　：6.2<br />
				平均損益(％)　　　　　　　：1.42<br />
				平均利益(％)　　　　　　　：9.33<br />
				平均損失(％)　　　　　　　：-11.3<br />
				年率換算利回り(％)　　　　：8.41<br />
				最大勝ちトレード(％)　　　：42.12<br />
				最大負けトレード(％)　　　：-22.74<br />
				&#8211;●指標データ●&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
				平均ドローダウン(％)　　　：2.51<br />
				最大ドローダウン(％)　　　：12.72<br />
				損益レシオ(倍)　　　　　　：0.98<br />
				プロフィットファクター(倍)：1.57<br />
				リスクレシオ(倍)　　　　　：0.66<br />
				年率シャープレシオ(倍)　　：0.8<br />
				年率ボラティリティ(％)　　：10.49<br />
				■■■■■■■■■■■■■■■■■■■■■■■■■■■
				</p></blockquote>
				<h3>考察</h3>
				<p>最大勝ちトレードが42%なのが特徴と言える。一方で損失も大きい。設定によって小さくこつこつ、大きく負けないカブロボも可能だけれど、貪欲な利益を追求するようにした。パラメータはいろいろ調整してみた。高値から5%下がったら売るより10%くらい我慢した方が結果がよいとか、購入条件も3〜7%としたけれど、これも色々調整した結果。</p>
				<p>パラメータの調整は自動でできるようになるといいのだけれど。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/09/15/%e3%82%ab%e3%83%96%e3%83%ad%e3%83%9c%e3%81%9d%e3%81%ae1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>銘柄別の日足株価データの取得方法</title>
		<link>http://blog.neoneet.jp/2008/09/07/%e9%8a%98%e6%9f%84%e5%88%a5%e3%81%ae%e6%97%a5%e8%b6%b3%e6%a0%aa%e4%be%a1%e3%83%87%e3%83%bc%e3%82%bf%e3%81%ae%e5%8f%96%e5%be%97%e6%96%b9%e6%b3%95/</link>
		<comments>http://blog.neoneet.jp/2008/09/07/%e9%8a%98%e6%9f%84%e5%88%a5%e3%81%ae%e6%97%a5%e8%b6%b3%e6%a0%aa%e4%be%a1%e3%83%87%e3%83%bc%e3%82%bf%e3%81%ae%e5%8f%96%e5%be%97%e6%96%b9%e6%b3%95/#comments</comments>
		<pubDate>Sun, 07 Sep 2008 10:27:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>
		<category><![CDATA[SystemTrading]]></category>
		<category><![CDATA[Trading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=94</guid>
		<description><![CDATA[システムトレードのバックテストを行うにあたって、長期の日足データが欲しくなります。ぐぐると多くの方法があることがわかりますが、他の方が言及していない（と思われる）方法を紹介します。 HYPER SBIを使う 無料というわけにはいかないのですが、定期的にトレードしている人にとっては実質的に無料で使えるソフトHYPER SBIを使います。 メニューから時系列を選ぶ 欲しいデータを選ぶ プルダウンメニューから為替、個別銘柄、主要指標、先物、歩み値を選ぶことができます。ここでは任天堂の日足を選んで日時を1988年3月6日から2008年9月6日まで選んで「検索」を押しました。最後に「CSV出力」を選ぶとCSVでデータを入手できます。 歩み値データも取得可能 取得した歩み値データからチャートを作ってみました。別にこんなことをしなくても、楽に表示する方法はあるのだけど、テストということで。。。これは2008年9月5日の任天堂のチャートをExcelで作ってみました。]]></description>
			<content:encoded><![CDATA[				<p>システムトレードのバックテストを行うにあたって、長期の日足データが欲しくなります。ぐぐると多くの方法があることがわかりますが、他の方が言及していない（と思われる）方法を紹介します。</p>
				<h3>HYPER SBIを使う</h3>
				<p>無料というわけにはいかないのですが、定期的にトレードしている人にとっては実質的に無料で使えるソフトHYPER SBIを使います。</p>
				<h4>メニューから時系列を選ぶ</h4>
				<p><a href="http://blog.neoneet.jp/wp-content/uploads/2008/09/1.png"><img class="aligncenter size-full wp-image-95" title="1" src="http://blog.neoneet.jp/wp-content/uploads/2008/09/1.png" alt="" width="500" height="456" /></a></p>
				<h4>欲しいデータを選ぶ</h4>
				<p>プルダウンメニューから為替、個別銘柄、主要指標、先物、歩み値を選ぶことができます。ここでは任天堂の日足を選んで日時を1988年3月6日から2008年9月6日まで選んで「検索」を押しました。最後に「CSV出力」を選ぶとCSVでデータを入手できます。</p>
				<p><span style="font-weight: normal;"><img class="aligncenter size-full wp-image-96" title="2" src="http://blog.neoneet.jp/wp-content/uploads/2008/09/2.png" alt="" width="500" height="133" /></span><br />
				<a href="http://blog.neoneet.jp/wp-content/uploads/2008/09/3.png"><img class="aligncenter size-full wp-image-97" title="3" src="http://blog.neoneet.jp/wp-content/uploads/2008/09/3.png" alt="" width="480" height="257" /></a></p>
				<h4>歩み値データも取得可能</h4>
				<p>取得した歩み値データからチャートを作ってみました。別にこんなことをしなくても、楽に表示する方法はあるのだけど、テストということで。。。これは2008年9月5日の任天堂のチャートをExcelで作ってみました。</p>
				<p><a href='http://blog.neoneet.jp/wp-content/uploads/2008/09/chart.png'><img src="http://blog.neoneet.jp/wp-content/uploads/2008/09/chart.png" alt="" title="chart" width="480" height="421" class="aligncenter size-full wp-image-98" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/09/07/%e9%8a%98%e6%9f%84%e5%88%a5%e3%81%ae%e6%97%a5%e8%b6%b3%e6%a0%aa%e4%be%a1%e3%83%87%e3%83%bc%e3%82%bf%e3%81%ae%e5%8f%96%e5%be%97%e6%96%b9%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(9)</title>
		<link>http://blog.neoneet.jp/2008/05/25/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%939/</link>
		<comments>http://blog.neoneet.jp/2008/05/25/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%939/#comments</comments>
		<pubDate>Sun, 25 May 2008 13:41:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=88</guid>
		<description><![CDATA[しばらく多忙にかまけて放置していたけれど、市況がよくなってきたのでムクムクとやる気を出して、と言っても30分ほど作業をしてみた。 方針は以前作ったMonexに対して、出来高の平均の3倍の取引があれば通知をするように変更するもの。結果がどうなるかは試してみてのお楽しみ。 巡回に関するルールの変更 変更点をいくつか。まず出来高チェックなので頻繁に見る必要はなく、サーバに与える負荷を軽くすることにした。まず銘柄数をそう多くしない前提で1分おきにチェックをする。Thread.sleep()はミリ秒を与えるので、interval = 1000 * 60としている。これをchainの要素数で割った時間だけ眠らせることにした。このオブジェクトのインスタンスは自身のstaticなチェインに記録させているので、each()してやれば、あとはどんどんnewするだけで正しく巡回する。 public static void each() throws InterruptedException { Iterator it = chain.iterator(); // リストの要素数 int size = chain.size(); int wait = interval / size; while (it.hasNext()) { StockMonitor m = it.next(); m.update(); Thread.sleep(wait); } } HistoricalPricesList Priceとあるけど出来高を今回は格納している。 package utilities; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class HistoricalPricesList [...]]]></description>
			<content:encoded><![CDATA[				<p>しばらく多忙にかまけて放置していたけれど、市況がよくなってきたのでムクムクとやる気を出して、と言っても30分ほど作業をしてみた。</p>
				<p>方針は以前作ったMonexに対して、出来高の平均の3倍の取引があれば通知をするように変更するもの。結果がどうなるかは試してみてのお楽しみ。</p>
				<h3>巡回に関するルールの変更</h3>
				<p>変更点をいくつか。まず出来高チェックなので頻繁に見る必要はなく、サーバに与える負荷を軽くすることにした。まず銘柄数をそう多くしない前提で1分おきにチェックをする。Thread.sleep()はミリ秒を与えるので、interval = 1000 * 60としている。これをchainの要素数で割った時間だけ眠らせることにした。このオブジェクトのインスタンスは自身のstaticなチェインに記録させているので、each()してやれば、あとはどんどんnewするだけで正しく巡回する。</p>
				<pre class="prettyprint">
	public static void each() throws InterruptedException {
		Iterator<stockmonitor> it = chain.iterator();

		// リストの要素数
		int size = chain.size();
		int wait = interval / size;

		while (it.hasNext()) {
			StockMonitor m = it.next();
			m.update();
			Thread.sleep(wait);
		}
	}
</stockmonitor></pre>
				<h3>HistoricalPricesList</h3>
				<p>Priceとあるけど出来高を今回は格納している。</p>
				<pre class="prettyprint">
package utilities;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class HistoricalPricesList
{
	private List<integer> historical;
	private int max;

	public HistoricalPricesList( int size )
	{
		this.max = size;
		historical = new ArrayList</integer><integer>();
	}

	public void add( int value )
	{
		int size = historical.size();

		// サイズを超える場合は一番古いものを捨てる
		if( size >= max )
			historical.remove(0);

		historical.add(value);
	}

	// リストの平均を得る
	public int average()
	{
		int size = historical.size();
		int sum = 0;
		Iterator</integer><integer> it = historical.iterator();

		// ゼロによる除算回避
		if( size == 0 )
			return 0;

		while (it.hasNext())
			sum += it.next();

		return sum / size;
	}
}
</integer></pre>
				<p>つまり、ガシガシ値を放り込むと平均を取り出せるというだけ。</p>
				<h3>update()</h3>
				<p>定期的に株価や出来高を見て、平均の3倍を超える出来高が発生したら通知する。</p>
				<pre class="prettyprint">
	public void update()
	{
		try
		{
			getPrice();
			java.util.Date d = new java.util.Date();

			if( volume != previous )
			{
				previous = volume;

				int average = historical.average();
				if( volume > 3 * average )
				{
					// 出来高急増
					System.out.println(d);
					System.out.println( code );
					System.out.println( "Last Trade:" + price );
					System.out.println( "Volume:" + volume );
					System.out.println( "" );
				}

				historical.add(volume);
			}
		}
		catch (CodeNotFoundException e)
		{
		}
	}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/05/25/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%939/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(8)</title>
		<link>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%938/</link>
		<comments>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%938/#comments</comments>
		<pubDate>Mon, 03 Mar 2008 08:33:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%938/</guid>
		<description><![CDATA[データベースをExcelなど表計算ソフトで見る Rubyにsqlite3-rubyを入れてやるとRubyからSQLiteが使える。Javaよりこっちの方が手軽に思う。 #!/usr/bin/ruby require 'sqlite3' db = SQLite3::Database.new('test.db') sql = "SELECT time,price,volume FROM _5411" db.execute(sql) do &#124;row&#124; milisec = row[0].to_i milisec /= 1000 t = Time.at(milisec) a = t.to_a # print t.to_s + ", " print a[2].to_s + ":" + a[1].to_s + ":" + a[0].to_s + ", " print row[1] + ", " print row[2] [...]]]></description>
			<content:encoded><![CDATA[				<h3>データベースをExcelなど表計算ソフトで見る</h3>
				<p>Rubyに<a href="http://rubyforge.org/frs/?group_id=254&amp;release_id=9438">sqlite3-ruby</a>を入れてやるとRubyからSQLiteが使える。Javaよりこっちの方が手軽に思う。</p>
				<pre class="prettyprint">
#!/usr/bin/ruby

require 'sqlite3'

db = SQLite3::Database.new('test.db')
sql = "SELECT time,price,volume FROM _5411"
db.execute(sql) do |row|
	milisec = row[0].to_i
	milisec /= 1000
	t = Time.at(milisec)
	a = t.to_a

#	print t.to_s + ", "
	print a[2].to_s + ":" + a[1].to_s + ":" + a[0].to_s + ", "
	print row[1] + ", "
	print row[2] + "\n"
end</pre>
				<p>Javaの時刻は1970年1月1日から数えてミリ秒単位で表す。Rubyは秒単位らしいので、まず1000で割ってTime.at()で時刻オブジェクトを取得する。to_aで配列に変換すると時、分、秒を取得しやすいので変換しておく。単に人間が見るだけなら.to_sで文字列に変換してやるのがよいだろう。</p>
				<h3>結果</h3>
				<pre>
[piyo@MacBookPro ~/Source/Ruby]# ruby Monex2DB.rb
9:29:13, 4450, 630200
9:29:27, 4440, 636500
9:29:35, 4450, 637000
9:29:43, 4460, 648100
9:29:54, 4460, 648200
9:30:8, 4450, 648300
9:30:15, 4460, 651600
9:30:23, 4460, 657600
9:30:30, 4460, 663900
9:30:38, 4460, 664000
9:30:45, 4450, 692500
9:30:59, 4440, 706500
9:31:6, 4450, 716800
9:31:14, 4450, 718500
9:31:21, 4450, 718700
9:31:28, 4440, 720100
9:31:49, 4450, 730100
9:31:57, 4450, 730900
（略）</pre>
				<p>これをリダイレクトでも何でもファイルに保存すれば表計算で扱える。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%938/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(7)</title>
		<link>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%937/</link>
		<comments>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%937/#comments</comments>
		<pubDate>Mon, 03 Mar 2008 06:41:23 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e6%a0%aa%e5%bc%8f%e6%8a%95%e8%b3%87/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%937/</guid>
		<description><![CDATA[SQLiteに株価を記録する 閑話休題で、今までのプロジェクトから一部のコードを引っこ抜いてSQLiteにデータを記録してみる。 方針 株価を監視するStockMonitorクラスを作り、ここで株価をデータベースにごりごり書き込む。急落、急騰を察知したら通知する。 StockMonitorクラス staticなchainを作り、コンストラクタでthisをadd()すると、呼び出し側はnew StockMonitor();するだけでインスタンスを保持する必要がない。全てのインスタンスに対して処理を行うためにstaticなメソッドeach()を用いてchainを全部たどって必要な処理を行う。 public class StockMonitor { private static List chain = new ArrayList(); private int code; public StockMonitor(int code) { this.code = code; chain.add(this); // テーブルがないときはテーブルを作る try { Class.forName("org.sqlite.JDBC"); Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db"); Statement stat = conn.createStatement(); String sql = SQL.getSQLFromFile("CreateTable.sql"); sql = sql.replace("_PLEASE_REPLACE", "_" + code); System.out.println(sql); stat.executeUpdate(sql); } [...]]]></description>
			<content:encoded><![CDATA[				<h3>SQLiteに株価を記録する</h3>
				<p>閑話休題で、今までのプロジェクトから一部のコードを引っこ抜いてSQLiteにデータを記録してみる。</p>
				<h4>方針</h4>
				<p>株価を監視するStockMonitorクラスを作り、ここで株価をデータベースにごりごり書き込む。急落、急騰を察知したら通知する。</p>
				<h4>StockMonitorクラス</h4>
				<p>staticなchainを作り、コンストラクタでthisをadd()すると、呼び出し側はnew StockMonitor();するだけでインスタンスを保持する必要がない。全てのインスタンスに対して処理を行うためにstaticなメソッドeach()を用いてchainを全部たどって必要な処理を行う。</p>
				<pre class="prettyprint">
public class StockMonitor {
	private static List<stockmonitor> chain = new ArrayList</stockmonitor><stockmonitor>();
	private int code;

	public StockMonitor(int code) {
		this.code = code;
		chain.add(this);

		// テーブルがないときはテーブルを作る
		try {
			Class.forName("org.sqlite.JDBC");
			Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
			Statement stat = conn.createStatement();

			String sql = SQL.getSQLFromFile("CreateTable.sql");
			sql = sql.replace("_PLEASE_REPLACE", "_" + code);

			System.out.println(sql);
			stat.executeUpdate(sql);
		} catch (Exception e) {
		}
	}

	public static void each() {
		Iterator</stockmonitor><stockmonitor> it = chain.iterator();

		while (it.hasNext()) {
			StockMonitor m = it.next();
			m.update();
		}
	}

	public void update() {
		try {
			getPrice();
			writeDatabase();
			findSharpDrop();
		} catch (CodeNotFoundException e) {}
	}

</stockmonitor></pre>
				<h4>SQLをもうちょっと綺麗に書きたい</h4>
				<p>今のところSQLをStringBufferにappend()しているけれど、これは読みにくい。もう少し何とかならないのかと思ってSQLクラスを作ってみた。</p>
				<pre class="prettyprint">
public class SQL {
	// SQLファイルを読み、1行のStringに変換して返す
	public static String getSQLFromFile(String filename) {
		StringBuffer sql = new StringBuffer();

		try
		{
			FileInputStream fis = new FileInputStream(filename);
			InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
			BufferedReader br = new BufferedReader(isr);

			String line = "";
			while(( line = br.readLine()) != null )
			{
				sql.append(line);
			}

			fis.close();
			isr.close();
			fis.close();

		}
		catch (Exception e1)
		{
			e1.printStackTrace();
		}

		// タブをスペース1個に置き換える
		return sql.toString().replaceAll("\t+", " ");
	}
}</pre>
				<p>これで、SQLをファイルに書いて転がしておける。</p>
				<pre class="prettyprint">
CREATE TABLE _PLEASE_REPLACE
(
	id			INTEGER NOT NULL PRIMARY KEY,
	time		TIME,
	price		INTEGER,
	volume		INTEGER
);</pre>
				<p>とでも書いておいて、Stringメソッドのreplace()を使って&#8221;_PLEASE_REPLACE&#8221;を置き換える。</p>
				<h4>getPrice()メソッド</h4>
				<p>前回のMonexから株価引っこ抜きコードをそのまま使うが、今回は株価と出来高のみ注目する。時刻はメソッドを呼び出した側で取得することにする。JavaはSystem.currentTimeMillis()でミリ秒単位で時刻を取得できるので、これを使う。</p>
				<pre class="prettyprint">
private void getPrice() throws CodeNotFoundException {
	// 株価ページを取得
	Monex2 application = Manager.getApplication();
	String url = application.makeSeaechStockCodeURL(code);

	GetMethod get = new GetMethod(url);
	HTTP.getInstance().executeMethod(get);
	get.releaseConnection();

	// 株価コードがない
	if (HTTP.getInstance().getResult().indexOf("該当する銘柄がありません") ＞= 0) {
		throw new CodeNotFoundException();
	}

	// 大ざっぱに該当部分を切り出す
	Perl5Util pu = new Perl5Util();
	String pattern = "/＜br＞(\\(\\d\\d\\d\\d\\).*?現値.*?前比.*?売気.*?株数.*?買気.*?株数.*?始値.*?高値.*?安値.*?出来.*?)＜br＞＜br＞＜a href=\"quote.cgi?/";
	if (pu.match(pattern, HTTP.getInstance().getResult())) {
		// さらに＜br＞区切りで要素に分ける
		String result = pu.group(1);
		String[] element = result.split("＜br＞");

		// 株価を取得
		pattern = "/現値: (.*?)$/";
		if (pu.match(pattern, element[3])) {
			price = NumUtilities.toInt(pu.group(1));
		}

		// 出来高を取得
		pattern = "/出来:.*?(\\d.*)/";
		if (pu.match(pattern, element[12])) {
			volume = NumUtilities.toInt(pu.group(1));
		}
	}
}</pre>
				<h4>writeDatabase()メソッド</h4>
				<pre class="prettyprint">
	private void writeDatabase() {
		// 出来高が変わっていないときはリターン
		if (volume == previous)
			return;

		previous = volume;

		try {
			Class.forName("org.sqlite.JDBC");
			Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
			Statement stat = conn.createStatement();

			StringBuffer s = new StringBuffer();
			s.append("INSERT INTO _" + code + " VALUES(");
			s.append("NULL, ");
			s.append("'" + System.currentTimeMillis() + "', ");
			s.append("" + price + ", ");
			s.append("" + volume + " ");
			s.append("); ");

			// System.out.println(s);
			stat.executeUpdate(s.toString());
		} catch (Exception e) {}
	}</pre>
				<h4>findSharpDrop()メソッド</h4>
				<p>これはいい加減に書いたせいか、ろくに機能しなかった。寄り付きではたくさん報告するけど、ザラ場では一度も引っかかることがない。これはあとで見直す必要がありそう。原理は現在時刻からミリ秒で1分前を計算して、SQLでそれ以降のものを列挙してリストに放り込む。高値と安値の差が1%を超えている場合、急落あるいは急騰と判断することにする。</p>
				<pre class="prettyprint">
private void findSharpDrop() {
	long minute = 1000 * 60;
	long time = System.currentTimeMillis() - minute;

	try {
		Class.forName("org.sqlite.JDBC");
		Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
		Statement stat = conn.createStatement();

		String sql = "SELECT * FROM _" + code + " WHERE time > " + time + ";";
		ResultSet rs = stat.executeQuery(sql);

		List<integer> list = new ArrayList</integer><integer>();
		while (rs.next()) {
			list.add(NumUtilities.toInt(rs.getString("price")));
		}

		// コレクションを整列する
		if( list.isEmpty() != true )
		{
			Collections.sort(list);

			double min = list.get(0);
			double max = list.get(list.size()-1);				

			if( max / min > 1.01 )
			{
				System.out.println("SHARP DROP:(" + code + "):"+max+"-"+min);
			}
		}

	} catch (Exception e){}
}
</integer></pre>
				<h3>実行結果</h3>
				<p>今日の朝は暴落が酷かったので、落ち着いてから起動して、引けまで放置した。できあがったデータベース。出来高が変化しなかったときは追加しない5秒ごとの株価推移。さて、これをどう料理しようか。</p>
				<p><a href="http://blog.neoneet.jp/wp-content/uploads/2008/03/db.jpg" title="データベース"><img src="http://blog.neoneet.jp/wp-content/uploads/2008/03/db.jpg" alt="データベース" /></a></p>
				<h3>ダウンロード</h3>
				<p><a href="http://blog.neoneet.jp/wp-content/uploads/2008/03/monex.zip" title="project">project</a></p>
				<p>今回のコード一式と2008年3月2日のザラ場に起動しっぱなしにして生成したデータベースも付属します。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/03/03/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%937/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaでSQLiteを使う</title>
		<link>http://blog.neoneet.jp/2008/03/02/java%e3%81%a7sqlite%e3%82%92%e4%bd%bf%e3%81%86/</link>
		<comments>http://blog.neoneet.jp/2008/03/02/java%e3%81%a7sqlite%e3%82%92%e4%bd%bf%e3%81%86/#comments</comments>
		<pubDate>Sat, 01 Mar 2008 15:03:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0/java/java%e3%81%a7sqlite%e3%82%92%e4%bd%bf%e3%81%86/</guid>
		<description><![CDATA[株の時系列データをどう扱うか とりあえずデータベースに放り込んでみることにする。データベースの操作もうまくラッパーを作ってしまえばSQLiteだろうとMySQLだろうと使えるはず。 SQLite JDBC Driver 検索してみるとすぐに色々見つかる。Javaで使うのは面倒くさいという話もあるけど、とりあえずSQLite JDBC Driverを試す。WindowsとMac OS X向けにはJNIを使ったネイティブ版もあるけれど、せっかくJavaを使うのだからPure Javaで試してみたい。ダウンロードして解凍するとsqlitejdbc-v037-nested.jarというものが出てくるので、パスの通っているところに設置。 サンプルコード まずはSQLite JDBC Driverのサイトのコードをそのまま試す。 package main; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class SQLiteTest { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { Class.forName("org.sqlite.JDBC"); Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db"); Statement stat = conn.createStatement(); stat.executeUpdate("create [...]]]></description>
			<content:encoded><![CDATA[				<h3>株の時系列データをどう扱うか</h3>
				<p>とりあえずデータベースに放り込んでみることにする。データベースの操作もうまくラッパーを作ってしまえばSQLiteだろうとMySQLだろうと使えるはず。</p>
				<h3>SQLite JDBC Driver</h3>
				<p>検索してみるとすぐに色々見つかる。Javaで使うのは面倒くさいという話もあるけど、とりあえず<a href="http://www.zentus.com/sqlitejdbc/">SQLite JDBC Driver</a>を試す。WindowsとMac OS X向けにはJNIを使ったネイティブ版もあるけれど、せっかくJavaを使うのだからPure Javaで試してみたい。ダウンロードして解凍するとsqlitejdbc-v037-nested.jarというものが出てくるので、パスの通っているところに設置。</p>
				<h3>サンプルコード</h3>
				<p>まずはSQLite JDBC Driverのサイトのコードをそのまま試す。</p>
				<pre class="prettyprint">package main;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class SQLiteTest {

/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement stat = conn.createStatement();
stat.executeUpdate("create table people (name, occupation);");
stat.executeUpdate("insert into people values ('Gandhi', 'politics');");
stat.executeUpdate("insert into people values ('Turing', 'computers');");
stat.executeUpdate("insert into people values ('Wittgenstein', 'smartypants');");

ResultSet rs = stat.executeQuery("select * from people;");
while (rs.next()) {
System.out.println("name = " + rs.getString("name"));
System.out.println("occupation = " + rs.getString("occupation"));
}
rs.close();
conn.close();
}
}</pre>
				<h3>実行結果</h3>
				<p>なんなくビルドは通ってtest.dbというファイルが作られる。結果を確認するべく<a href="http://sourceforge.net/projects/sqlitebrowser/">SQLite Database Browser</a>でtest.dbを開く。</p>
				<p><a title="SQLite Database Browser" href="http://blog.neoneet.jp/wp-content/uploads/2008/03/dbbrowser.jpg"><img src="http://blog.neoneet.jp/wp-content/uploads/2008/03/dbbrowser.jpg" alt="SQLite Database Browser" /></a></p>
				<p>このようにちゃんとデータベースが作られている。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/03/02/java%e3%81%a7sqlite%e3%82%92%e4%bd%bf%e3%81%86/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(6)</title>
		<link>http://blog.neoneet.jp/2008/03/01/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%936/</link>
		<comments>http://blog.neoneet.jp/2008/03/01/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%936/#comments</comments>
		<pubDate>Sat, 01 Mar 2008 04:02:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%936/</guid>
		<description><![CDATA[自動トレーディングへの道がGoogleに つい最近までGoogleで「自動トレーディング」で検索すると最上位にヒットしていました。継続は力なり。でもまた下に下がっていきました。湯は熱し続けなければやがて水に戻る。 Context側を作る public interface IContext { public abstract void login( String ID, String Password ); public abstract void logout(); } とりあえずログインとログアウトのみ。続いてこれを実装する側 import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Panel; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; import org.apache.oro.text.perl.Perl5Util; public class Monex extends JFrame implements IContext, ActionListener { // 初期状態はログインされていない private IState [...]]]></description>
			<content:encoded><![CDATA[				<h3>自動トレーディングへの道がGoogleに</h3>
				<p>つい最近までGoogleで「自動トレーディング」で検索すると最上位にヒットしていました。継続は力なり。でもまた下に下がっていきました。湯は熱し続けなければやがて水に戻る。</p>
				<h3>Context側を作る</h3>
				<pre class="prettyprint">
public interface IContext
{
 public abstract void login( String ID, String Password );
 public abstract void logout();
}</pre>
				<p>とりあえずログインとログアウトのみ。続いてこれを実装する側</p>
				<pre class="prettyprint">
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import org.apache.oro.text.perl.Perl5Util;

public class Monex extends JFrame implements IContext, ActionListener {
	// 初期状態はログインされていない
	private IState state = MonexLoggedOutState.getInstance();

	private static final long serialVersionUID = 1L;

	private TextField textClock = new TextField(60);
	private TextArea textScreen = new TextArea(10, 60);
	private Button buttonLogin = new Button("ログイン");
	private Button buttonLogout = new Button("ログアウト");
	private Button buttonQuote = new Button("株価取得");
	private Button buttonExit = new Button("終了");

	private String hash = "";
	private String sid = "";
	private String id = "";

	public Monex(String title) {
		super(title);
		setBackground(Color.lightGray);
		setLayout(new BorderLayout());

		// textClock配置
		add(textClock, BorderLayout.NORTH);
		textClock.setEditable(false);

		// textScreen配置
		add(textScreen, BorderLayout.CENTER);
		textClock.setEditable(false);

		// ボタンを配置
		Panel panel = new Panel();
		panel.add(buttonLogin);
		panel.add(buttonLogout);
		panel.add(buttonQuote);
		panel.add(buttonExit);

		add(panel, BorderLayout.SOUTH);

		pack();
		setVisible(true);
		setBounds( 10, 10, 400, 200 );
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		buttonLogin.addActionListener(this);
		buttonLogout.addActionListener(this);
		buttonQuote.addActionListener(this);
		buttonExit.addActionListener(this);

		textClock.setText(state.toString());
	}

	// ボタンが押されたとき
	public void actionPerformed(ActionEvent e) {
		System.out.println(e.toString());

		if (e.getSource() == buttonLogin) {
			state.login(this, "aa", "aaa");
			return;
		}

		if (e.getSource() == buttonLogout) {
			state.logout(this);
			return;
		}

		if (e.getSource() == buttonQuote) {
			state.quote(this);
			return;
		}

		if (e.getSource() == buttonExit) {
			System.exit(0);
			return;
		}

		System.out.println("?");
	}

	// FSMを更新する
	public void update() {
		String msg = state.toString();

		System.out.println(msg);
		textClock.setText(msg);
	}

	public void changeState(IState nextState) {
		System.out.println(this.state + "から" + nextState + "へ状態が変化しました\n");
		this.state = nextState;
		textClock.setText(state.toString());
	}

	public void getStockInformation(int stockCode) {
		// TODO 自動生成されたメソッド・スタブ

	}

	public void login(String ID, String Password) {
		state.login(this, ID, Password);
	}

	public void logout() {
		state.logout(this);
	}

	public void setSessionID(String responseBody) {
		Perl5Util pu = new Perl5Util();
		String pattern = "/＜A href=\"(https://ot2.qhit.net.*?)\".*?ACCESSKEY=\"1\"/";
		if (pu.match(pattern, responseBody)) {
			String result = pu.group(1);
			pattern = "/ot2\\.qhit\\.net/(.*?)/.*?sid=(.*?)&amp;.*?&amp;id=(.*?)$/";

			if (pu.match(pattern, result)) {
				hash = pu.group(1);
				sid = pu.group(2);
				id = pu.group(3);
			}
		}
	}

	public String makeSeaechStockCodeURL(int code) {
		String url = "https://ot2.qhit.net/";
		url += hash;
		url += "/mb/quote.cgi?F=Idetail0&amp;QCODE=";
		url += code;
		url += "&amp;MKTN=T&amp;rf=r&amp;SID=&amp;ID=";
		url += id;
		url += "&amp;DM=www&amp;mode=";

		return url;
	}
}</pre>
				<h3>実行結果</h3>
				<h3><a href="http://blog.neoneet.jp/wp-content/uploads/2008/03/loggedoutstate.jpg" title="ログインしていない状態"><img src="http://blog.neoneet.jp/wp-content/uploads/2008/03/loggedoutstate.jpg" alt="ログインしていない状態" /></a></h3>
				<p>まず起動するとログインしていない状態になる。この状態を管理しているのはMonexLoggedOutStateで、このlogout()の実装は</p>
				<pre class="prettyprint">
public void logout(Monex context) {}</pre>
				<p>になっているため、ここで「ログアウト」をクリックしてもなにも起きない。代わりに「ログイン」を押すとこちらは実装されているので処理を行ってログイン状態に遷移する。ログイン時にはセッションIDかな、何か謎の文字列を記録する。この辺は「自動トレーディングへの道(5)」にある。ログインに成功すると「ログインしていませんからログインしていますへ状態が変化しました」とコンソールに出力される。</p>
				<p><a href="http://blog.neoneet.jp/wp-content/uploads/2008/03/loggedinstate.jpg" title="ログインしている状態"><img src="http://blog.neoneet.jp/wp-content/uploads/2008/03/loggedinstate.jpg" alt="ログインしている状態" /></a></p>
				<p>この状態で「ログイン」を押しても、やはり空っぽの実装なので何もしない。株価取得は動く。</p>
				<pre>
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=株価取得,when=0,modifiers=] on button1
(9433) 東証一部
ＫＤＤＩ
02/29 15:00
現在値:640000 +13000(+2.07%)
売り気配:641000(20)
買い気配:640000(855)
始値:626000
高値:644000
安値:625000
出来高:40107

(9202) 東証一部
ＡＮＡ
02/29 15:00
現在値:435 -1(-0.22%)
売り気配:436(77000)
買い気配:435(120000)
始値:433
高値:437
安値:431
出来高:3237000

(3436) 東証一部
ＳＵＭＣＯ
02/29 15:00
現在値:2375 -195(-7.58%)
売り気配:2385(10300)
買い気配:2375(11100)
始値:2490
高値:2505
安値:2370
出来高:2716300

(5411) 東証一部
ＪＦＥＨＤ
02/29 15:00
現在値:4740 +10(+0.21%)
売り気配:4750(6700)
買い気配:4730(38100)
始値:4810
高値:4820
安値:4570
出来高:5786000

(8058) 東証一部
三菱商
02/29 15:00
現在値:3270 -70(-2.09%)
売り気配:3270(114100)
買い気配:3260(99400)
始値:3240
高値:3280
安値:3200
出来高:10629100

(8316) 東証一部
三井住友
02/29 15:00
現在値:772000 -33000(-4.09%)
売り気配:772000(121)
買い気配:771000(38)
始値:785000
高値:789000
安値:762000
出来高:46122

(7974) 東証一部
任天堂
02/29 15:00
現在値:53300 -3200(-5.66%)
売り気配:53400(100)
買い気配:53300(2700)
始値:54200
高値:54400
安値:53100
出来高:46300</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/03/01/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%936/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(5)</title>
		<link>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%935/</link>
		<comments>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%935/#comments</comments>
		<pubDate>Tue, 26 Feb 2008 08:51:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%935/</guid>
		<description><![CDATA[再びMonexLoggedOutState MonexLoggedOutStateのlogin()で context.setSessionID(HTTP.getInstance().getResult()); とした。これはIContext側のクラスに（例によって&#60;を全角にしています） public void setSessionID(String responseBody) { Perl5Util pu = new Perl5Util(); String pattern = "/＜A href=\"(https://ot2.qhit.net.*?)\".*?ACCESSKEY=\"1\"/"; if (pu.match(pattern, responseBody)) { String result = pu.group(1); pattern = "/ot2\\.qhit\\.net/(.*?)/.*?sid=(.*?)&#38;.*?&#38;id=(.*?)$/"; if (pu.match(pattern, result)) { hash = pu.group(1); sid = pu.group(2); id = pu.group(3); } } } というものがある。ログイン後はURLに謎の文字列を含むものが出てくる。これを間違えると処理されず、おそらくセッションIDではないかと思う。URLもmonexではなくot2.qhit.netになる。 というわけで&#8221;https://ot2.qhit.net&#8221;を含むURLでACCESSKEYが1であるものを正規表現で抜き出して、さらにその中から意味不明の文字列を３つ取り出す。意味がわからないので、とりあえずhash, sid, idとしておく。これはログイン後の状態からmakeSeaechStockCodeURL()で利用する。 public String makeSeaechStockCodeURL(int code) { [...]]]></description>
			<content:encoded><![CDATA[				<h3>再びMonexLoggedOutState</h3>
				<p>MonexLoggedOutStateのlogin()で</p>
				<pre class="prettyprint">
context.setSessionID(HTTP.getInstance().getResult());</pre>
				<p>とした。これはIContext側のクラスに（例によって&lt;を全角にしています）</p>
				<pre class="prettyprint">public void setSessionID(String responseBody) {
	Perl5Util pu = new Perl5Util();
	String pattern = "/＜A href=\"(https://ot2.qhit.net.*?)\".*?ACCESSKEY=\"1\"/";
	if (pu.match(pattern, responseBody)) {
		String result = pu.group(1);
		pattern = "/ot2\\.qhit\\.net/(.*?)/.*?sid=(.*?)&amp;.*?&amp;id=(.*?)$/";

		if (pu.match(pattern, result)) {
			hash = pu.group(1);
			sid = pu.group(2);
			id = pu.group(3);
		}
	}
}</pre>
				<p>というものがある。ログイン後はURLに謎の文字列を含むものが出てくる。これを間違えると処理されず、おそらくセッションIDではないかと思う。URLもmonexではなくot2.qhit.netになる。</p>
				<p>というわけで&#8221;https://ot2.qhit.net&#8221;を含むURLでACCESSKEYが1であるものを正規表現で抜き出して、さらにその中から意味不明の文字列を３つ取り出す。意味がわからないので、とりあえずhash, sid, idとしておく。これはログイン後の状態からmakeSeaechStockCodeURL()で利用する。</p>
				<pre class="prettyprint">
public String makeSeaechStockCodeURL(int code) {
	String url = "https://ot2.qhit.net/";
	url += hash;
	url += "/mb/quote.cgi?F=Idetail0&amp;QCODE=";
	url += code;
	url += "&amp;MKTN=T&amp;rf=r&amp;SID=&amp;ID=";
	url += id;
	url += "&amp;DM=www&amp;mode=";

	return url;
}</pre>
				<h3>ログイン後の状態</h3>
				<p>getPrice()では</p>
				<pre class="prettyprint">
// 株価ページを取得
String url = context.makeSeaechStockCodeURL(code);
GetMethod get = new GetMethod(url);
HTTP.getInstance().executeMethod(get);
get.releaseConnection();</pre>
				<p>でHTMLを取得し、これを解析していく。GETするURLはmakeSeaechStockCodeURL()で作る。多くの情報をバラバラに管理するのは面倒くさいのでStockInformationクラスを作成する。</p>
				<pre class="prettyprint">
package utilities;

public class StockInformation
{
	private Exchange exchange;	// 取引所
	private String name;			// 銘柄
	private String date;			// 日付
	private String time;			// 時刻

	private int code;			// コード（４桁）
	private int price;			// 株価
	private int id;				// 前日比 increase-decrease;
	private double idr;			// 前日比（率）increase-decrease rate
	private int sell;			// 売り気配;
	private int sellAmount;		// 売り枚数
	private int buy;				// 買い気配;
	private int buyAmount;		// 買い枚数
	private int opening;			// 始値
	private int high;			// 高値
	private int low;				// 安値
	private int volume;			// 出来高
	private int closing;			// 終値（決まるまでは０にしておく）

	public StockInformation()
	{

	}

	// getter, setterをたくさん作る	

	public String toString()
	{
		String result = "(" + code + ") " + Exchange.name(exchange) + "\n";
		result += name + "\n";
		result += date + " " + time + "\n";

		result += "現在値:" + price;
		if( id > 0 )
			result += " +" + id + "(+" + idr + "%)\n";
		else
			result += " " + id + "(" + idr + "%)\n";

		result += "売り気配:" + sell + "(" + sellAmount + ")\n";
		result += "買い気配:" + buy + "(" + buyAmount + ")\n";
		result += "始値:" + opening + "\n";
		result += "高値:" + high + "\n";
		result += "安値:" + low + "\n";
		result += "出来高:" + volume + "\n";

		return result;
	}
}</pre>
				<p>あとはゴリゴリ正規表現を駆使してStockInformationに値を入れる。この際、面倒くさいのは&#8221;654,000&#8243;のような文字列は普通にInteger.parseInt()すると例外を投げてしまうので下処理がいる。そのためのユーティリティクラスを作る。</p>
				<pre class="prettyprint">
public class NumUtilities
{
	public static int toInt(String str)
	{
		return Integer.parseInt(trim(str));
	}

	public static double toDouble(String str)
	{
		return Double.parseDouble(trim(str));
	}

	public static String trim(String in)
	{
		char [] c = in.toCharArray();
		StringBuffer result = new StringBuffer();

		for( int i = 0; i < c.length; i++ )
			if(('0' <= c[i] &amp;&amp; c[i] <= '9') || c[i] == '-' || c[i] == '.' )
				result.append(c[i]);

		return result.toString();
	}
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%935/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(4)</title>
		<link>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%934/</link>
		<comments>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%934/#comments</comments>
		<pubDate>Tue, 26 Feb 2008 08:38:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%934/</guid>
		<description><![CDATA[ログイン中の状態 続いてログイン中の状態を表すクラス。これもIStateをimplementsして作る。IStateはclassにしておけばいいのかな、そうすればgetInstance()も基底クラスに持たせることができる。とりあえずコード（半角の&#60;&#62;を全角で書いています）： package monex; import network.HTTP; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.oro.text.perl.Perl5Util; import utilities.CodeNotFoundException; import utilities.Exchange; import utilities.NumUtilities; import utilities.StockInformation; public class MonexLoggedInState implements IState { // singleton private static IState singleton = new MonexLoggedInState(); public static IState getInstance() { return singleton; } // ログイン中、何もしない public void login(Monex context, String ID, String Password) { System.out.println("既にログイン中です"); } // [...]]]></description>
			<content:encoded><![CDATA[				<h3>ログイン中の状態</h3>
				<p>続いてログイン中の状態を表すクラス。これもIStateをimplementsして作る。IStateはclassにしておけばいいのかな、そうすればgetInstance()も基底クラスに持たせることができる。とりあえずコード（半角の&lt;&gt;を全角で書いています）：</p>
				<pre class="prettyprint">
package monex;

import network.HTTP;

import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.oro.text.perl.Perl5Util;

import utilities.CodeNotFoundException;
import utilities.Exchange;
import utilities.NumUtilities;
import utilities.StockInformation;

public class MonexLoggedInState implements IState {
	// singleton
	private static IState singleton = new MonexLoggedInState();

	public static IState getInstance() {
		return singleton;
	}

	// ログイン中、何もしない
	public void login(Monex context, String ID, String Password) {
		System.out.println("既にログイン中です");
	}

	// ログアウト処理
	public void logout(Monex context) {
		String logout = "https://www.monex.co.jp/IMode/00008F3S/imode/logout";
		GetMethod get = new GetMethod(logout);

		HTTP.getInstance().executeMethod(get);
		get.releaseConnection();

		System.out.println(HTTP.getInstance().getResult());

		context.changeState(MonexLoggedOutState.getInstance());
	}

	@Override
	public String toString() {
		return "ログインしています";
	}

	public void quote(Monex context) {
		int[] array = { 9433, 9202, 3436, 5411, 8058, 8316, 7974 };

		for (int i = 0; i ＜ array.length; i++) {
			try {
				System.out.println(getPrice(context, array[i]));
			} catch (CodeNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

	private StockInformation getPrice(Monex context, int code)
			throws CodeNotFoundException {
		StockInformation info = new StockInformation();

		// 株価ページを取得
		String url = context.makeSeaechStockCodeURL(code);
		GetMethod get = new GetMethod(url);
		HTTP.getInstance().executeMethod(get);
		get.releaseConnection();

		// 株価コードがない
		if (HTTP.getInstance().getResult().indexOf("該当する銘柄がありません") ＞= 0) {
			throw new CodeNotFoundException();
		}

		// 大ざっぱに該当部分を切り出す
		Perl5Util pu = new Perl5Util();
		String pattern = "/＜br＞(\\(\\d\\d\\d\\d\\).*?現値.*?前比.*?売気.*?株数.*?買気.*?株数.*?始値.*?高値.*?安値.*?出来.*?)＜br＞＜br＞＜a href=\"quote.cgi?/";
		if (pu.match(pattern, HTTP.getInstance().getResult())) {
			// さらに＜br＞区切りで要素に分ける
			String result = pu.group(1);
			String[] element = result.split("＜br＞");

			// 念のため表示
			// for( int i = 0; i ＜ element.length; i++ )
			// System.out.println(element[i]);

			// コードと取引所を取得
			pattern = "/\\((\\d\\d\\d\\d)\\)(.*)/";
			if (pu.match(pattern, element[0])) {
				info.setCode(NumUtilities.toInt(pu.group(1)));
				info.setExchange(Exchange.FirstSectionOfTheTokyoStockExchange);
			}

			// 銘柄を取得
			info.setName(element[1]);

			// 日付と時刻を取得
			pattern = "/＜div align=\"right\"＞\\((.*?) (.*?)\\)/";
			if (pu.match(pattern, element[2])) {
				info.setDate(pu.group(1));
				info.setTime(pu.group(2));
			}

			// 株価を取得
			pattern = "/現値: (.*?)$/";
			if (pu.match(pattern, element[3])) {
				info.setPrice(NumUtilities.toInt(pu.group(1)));
			}

			// 前日比を取得
			pattern = "/前比.*＞([\\+-]\\d.*)&amp;.*([\\+-].*)%/";
			if (pu.match(pattern, element[4])) {
				info.setId(NumUtilities.toInt(pu.group(1)));
				info.setIdr(NumUtilities.toDouble(pu.group(2)));
			}

			// 売り気配を取得
			pattern = "/売気:.*?(\\d.*)/";
			if (pu.match(pattern, element[5])) {
				info.setSell(NumUtilities.toInt(pu.group(1)));
			}

			// 売り株数を取得
			pattern = "/株数:.*?(\\d.*)/";
			if (pu.match(pattern, element[6])) {
				info.setSellAmount(NumUtilities.toInt(pu.group(1)));
			}

			// 買い気配を取得
			pattern = "/買気:.*?(\\d.*)/";
			if (pu.match(pattern, element[7])) {
				info.setBuy(NumUtilities.toInt(pu.group(1)));
			}

			// 買い株数を取得
			pattern = "/株数:.*?(\\d.*)/";
			if (pu.match(pattern, element[8])) {
				info.setBuyAmount(NumUtilities.toInt(pu.group(1)));
			}

			// 始値を取得
			pattern = "/始値:.*?(\\d.*)\\(/";
			if (pu.match(pattern, element[9])) {
				info.setOpening(NumUtilities.toInt(pu.group(1)));
			}

			// 高値を取得
			pattern = "/高値:.*?(\\d.*)\\(/";
			if (pu.match(pattern, element[10])) {
				info.setHigh(NumUtilities.toInt(pu.group(1)));
			}

			// 安値を取得
			pattern = "/安値:.*?(\\d.*)\\(/";
			if (pu.match(pattern, element[11])) {
				info.setLow(NumUtilities.toInt(pu.group(1)));
			}

			// 出来高を取得
			pattern = "/出来:.*?(\\d.*)/";
			if (pu.match(pattern, element[12])) {
				info.setVolume(NumUtilities.toInt(pu.group(1)));
			}
		}

		return info;
	}
}</pre>
				<h4>login()</h4>
				<p>ログイン済みの状態の時は何もしないで返す。そのかわりlogoutを実装することが必要。</p>
				<pre class="prettyprint">
// ログイン中、何もしない
public void login(Monex context, String ID, String Password) {
	System.out.println("既にログイン中です");
}</pre>
				<p>ログアウトは</p>
				<p>https://www.monex.co.jp/IMode/00008F3S/imode/logout</p>
				<p>をGETすればよい。特に失敗は考慮しておらず、続けて状態を遷移する。</p>
				<pre class="prettyprint">
// ログアウト処理
public void logout(Monex context) {
	String logout = "https://www.monex.co.jp/IMode/00008F3S/imode/logout";
	GetMethod get = new GetMethod(logout);

	HTTP.getInstance().executeMethod(get);
	get.releaseConnection();

	System.out.println(HTTP.getInstance().getResult());

	context.changeState(MonexLoggedOutState.getInstance());
}</pre>
				<p>ログイン中は株価を取得できる。そのためのquote()がある。これもIContextから派生（？）したクラスから呼び出す。</p>
				<pre class="prettyprint">
public void quote(Monex context) {
	int[] array = { 9433, 9202, 3436, 5411, 8058, 8316, 7974 };

	for (int i = 0; i < array.length; i++) {
		try {
			System.out.println(getPrice(context, array[i]));
		} catch (CodeNotFoundException e) {
			e.printStackTrace();
		}
	}
}</pre>
				<p>少々肥大化したのでgetPrice()に分離した。試しに株価をいくつか取得、その際の例外処理のためにCodeNotFoundExceptionクラスを作成した。戻り値はStockInformationクラス。</p>
				<pre class="prettyprint">
private StockInformation getPrice(Monex context, int code)
		throws CodeNotFoundException {
	// 略、全体のコードをご覧下さい
	}</pre>
				<p>続く。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%934/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自動トレーディングへの道(3)</title>
		<link>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%933/</link>
		<comments>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%933/#comments</comments>
		<pubDate>Mon, 25 Feb 2008 16:59:46 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[株式投資]]></category>
		<category><![CDATA[自動トレーディングへの道]]></category>
		<category><![CDATA[AutoTrading]]></category>
		<category><![CDATA[HttpClient]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%933/</guid>
		<description><![CDATA[マネックス証券にログイン Stateパターンについて調べたので、下手な考え休むに似たりということでゴリゴリコードを書いてみます。ダメダメだったら作り直す方針で。今回はマネックス証券の携帯サイト https://www.monex.co.jp/IMode/00000000/imode/login_e にログインすることを考えます。 IStateインターフェース まずインターフェースを用意します。 public interface IState { public abstract void login( Monex context, String ID, String Password ); public abstract void logout( Monex context ); public abstract void quote( Monex context ); } これもまずければあとで直す方向で。 まだログインしていない状態を表すクラス 最初にまだログインしていない状態を表すMonexLoggedOutStateを作ります。 public class MonexLoggedOutState implements IState { // singleton private static IState singleton = new MonexLoggedOutState(); public [...]]]></description>
			<content:encoded><![CDATA[				<h3>マネックス証券にログイン</h3>
				<p>Stateパターンについて調べたので、下手な考え休むに似たりということでゴリゴリコードを書いてみます。ダメダメだったら作り直す方針で。今回はマネックス証券の携帯サイト</p>
				<p align="center"><a href="http://blog.neoneet.jp/wp-admin/rtf1%20ansi%20uc0%20deff0%20fonttbl%20f0%20fnil%20Osaka;%20colortbl%20red0%20green0%20blue0;%20red255%20green255%20blue255;%20red232%20green242%20blue254;%20red42%20green0%20blue255;%20f0%20fs24%20%20fi0%20ql%20%20highlight2%20%20cf3%20https://www.monex.co.jp/IMode/00000000/imode/login_e">https://www.monex.co.jp/IMode/00000000/imode/login_e</a></p>
				<p>にログインすることを考えます。</p>
				<h4>IStateインターフェース</h4>
				<p>まずインターフェースを用意します。</p>
				<pre class="prettyprint">
public interface IState
{
	public abstract void login( Monex context, String ID, String Password );
	public abstract void logout( Monex context );
	public abstract void quote( Monex context );
}</pre>
				<p>これもまずければあとで直す方向で。</p>
				<h4>まだログインしていない状態を表すクラス</h4>
				<p>最初にまだログインしていない状態を表すMonexLoggedOutStateを作ります。</p>
				<pre class="prettyprint">
public class MonexLoggedOutState implements IState
{
	// singleton
	private static IState singleton = new MonexLoggedOutState();
	public static IState getInstance()
	{
		return singleton;
	}

	public void login( Monex context, String ID, String Password )
	{
		String login = "https://www.monex.co.jp/IMode/00000000/imode/login_e";
		PostMethod post = new PostMethod(login);

		System.out.println("ログインします");

		post.addParameter("loginid", "あなたのID");
		post.addParameter("passwd", "パスワード");

		HTTP.getInstance().executeMethod(post);
		post.releaseConnection();

		System.out.println(HTTP.getInstance().getResult());

		context.changeState(MonexLoggedInState.getInstance());
		context.setSessionID(HTTP.getInstance().getResult());

	}

	public void logout( Monex context )
	{

	}

	public String toString()
	{
		return "ログインしていません";
	}

	public void quote(Monex context)
	{

	}
}</pre>
				<h4>HTTP接続</h4>
				<p>HTTP接続にはJakarta HttpClientを利用します。それでもまだ雑多なコードを書く必要があるので、それを分離したHTTPクラスを作りました。</p>
				<pre class="prettyprint">
public class HTTP
{
	private static HTTP singleton = new HTTP();
	private HttpClient client = new HttpClient();
	private String result = "";

	private HTTP()
	{
		client.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
	}

	public static HTTP getInstance()
	{
		return singleton;
	}

	public String getResult()
	{
		return result;
	}

	public void executeMethod(HttpMethodBase method)
	{
		try
		{
			int statusCode = client.executeMethod(method);
			String characterSet = method.getResponseCharSet();
			String defaultCharacterSet = "Shift_JIS";

			// 誤判定対策
			if( characterSet.equalsIgnoreCase("ISO-8859-1"))
				characterSet = defaultCharacterSet;

			// ステータスコードのチェック
			if( statusCode != HttpStatus.SC_OK )
				System.out.println("Error" + method.getStatusLine());

			Reader in = new InputStreamReader(method.getResponseBodyAsStream(), characterSet );
			BufferedReader buffer = new BufferedReader(in);

			// 結果の取得
			String line;
			result = "";
			while(( line = buffer.readLine()) != null )
			{
				result += line;
			}

			in.close();
			buffer.close();
		}
		catch (HttpException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
		}
	}
}</pre>
				<p>これもシングルトンになっていて、getInstance()してインスタンスを取得してからexecuteMethod()を呼べば文字コードの判定とかをしてresultに格納します。resultもgetResult()で取得できます。マネックスではPOSTでログインするので、<span class="prettyprint">addParameter</span>にIDとパスワードを詰めてexecuteMethod()します。あ、例外処理してない。あとで追加します。</p>
				<h4>ログイン失敗の処理</h4>
				<p>やや手抜きだけれど、返ってきたHTMLにエラーコードが入っていたらログインできなかったとみなして、状態を遷移せずにreturnします。</p>
				<pre class="prettyprint">
		// ログイン失敗
		if( HTTP.getInstance().getResult().indexOf("NOL11015E") >= 0 )
		{
			return;
		}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2008/02/26/%e8%87%aa%e5%8b%95%e3%83%88%e3%83%ac%e3%83%bc%e3%83%87%e3%82%a3%e3%83%b3%e3%82%b0%e3%81%b8%e3%81%ae%e9%81%933/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

