Java Archive
自動トレーディングへの道(6)
- 2008-03-01 (土)
- Java | プログラミング | 株式投資 | 自動トレーディングへの道
自動トレーディングへの道が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 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=(.*?)&.*?&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&QCODE=";
url += code;
url += "&MKTN=T&rf=r&SID=&ID=";
url += id;
url += "&DM=www&mode=";
return url;
}
}
実行結果
まず起動するとログインしていない状態になる。この状態を管理しているのはMonexLoggedOutStateで、このlogout()の実装は
public void logout(Monex context) {}
になっているため、ここで「ログアウト」をクリックしてもなにも起きない。代わりに「ログイン」を押すとこちらは実装されているので処理を行ってログイン状態に遷移する。ログイン時にはセッションIDかな、何か謎の文字列を記録する。この辺は「自動トレーディングへの道(5)」にある。ログインに成功すると「ログインしていませんからログインしていますへ状態が変化しました」とコンソールに出力される。
この状態で「ログイン」を押しても、やはり空っぽの実装なので何もしない。株価取得は動く。
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=株価取得,when=0,modifiers=] on button1 (9433) 東証一部 KDDI 02/29 15:00 現在値:640000 +13000(+2.07%) 売り気配:641000(20) 買い気配:640000(855) 始値:626000 高値:644000 安値:625000 出来高:40107 (9202) 東証一部 ANA 02/29 15:00 現在値:435 -1(-0.22%) 売り気配:436(77000) 買い気配:435(120000) 始値:433 高値:437 安値:431 出来高:3237000 (3436) 東証一部 SUMCO 02/29 15:00 現在値:2375 -195(-7.58%) 売り気配:2385(10300) 買い気配:2375(11100) 始値:2490 高値:2505 安値:2370 出来高:2716300 (5411) 東証一部 JFEHD 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
NetBeans 6.0
これはいいかも知れない。以前、ちょっとだけ使ってEclipseと比較してこれはダメだなと安易に決めてしまったのだけど、GUIビルダだけでも使おうとNetBeans 6.0.1をインストールしてみた。
マイコミジャーナルに「ついに登場! NetBeans 6.0 – その新機能を徹底解剖する」という記事がある。大ざっぱなことはこれでわかる。
さっきインストールしたばかりだけど、少し使ってみようと思う。
自動トレーディングへの道(5)
- 2008-02-26 (火)
- Java | プログラミング | 株式投資 | 自動トレーディングへの道
再びMonexLoggedOutState
MonexLoggedOutStateのlogin()で
context.setSessionID(HTTP.getInstance().getResult());
とした。これはIContext側のクラスに(例によって<を全角にしています)
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=(.*?)&.*?&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になる。
というわけで”https://ot2.qhit.net”を含むURLでACCESSKEYが1であるものを正規表現で抜き出して、さらにその中から意味不明の文字列を3つ取り出す。意味がわからないので、とりあえずhash, sid, idとしておく。これはログイン後の状態からmakeSeaechStockCodeURL()で利用する。
public String makeSeaechStockCodeURL(int code) {
String url = "https://ot2.qhit.net/";
url += hash;
url += "/mb/quote.cgi?F=Idetail0&QCODE=";
url += code;
url += "&MKTN=T&rf=r&SID=&ID=";
url += id;
url += "&DM=www&mode=";
return url;
}
ログイン後の状態
getPrice()では
// 株価ページを取得 String url = context.makeSeaechStockCodeURL(code); GetMethod get = new GetMethod(url); HTTP.getInstance().executeMethod(get); get.releaseConnection();
でHTMLを取得し、これを解析していく。GETするURLはmakeSeaechStockCodeURL()で作る。多くの情報をバラバラに管理するのは面倒くさいのでStockInformationクラスを作成する。
package utilities;
public class StockInformation
{
private Exchange exchange; // 取引所
private String name; // 銘柄
private String date; // 日付
private String time; // 時刻
private int code; // コード(4桁)
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; // 終値(決まるまでは0にしておく)
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;
}
}
あとはゴリゴリ正規表現を駆使してStockInformationに値を入れる。この際、面倒くさいのは”654,000″のような文字列は普通にInteger.parseInt()すると例外を投げてしまうので下処理がいる。そのためのユーティリティクラスを作る。
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] && c[i] <= '9') || c[i] == '-' || c[i] == '.' )
result.append(c[i]);
return result.toString();
}
}
Home > Java
- Search
- Feeds
- Meta
















