2014年9月14日日曜日

pythonで東証の全銘柄一覧取得メモ

xldrとやらを使ってexcelのファイルを読み込んだときのメモ。

まずは以下からダウンロードしてインストール。
https://pypi.python.org/pypi/xlrd

ファイルを展開してpython setup.py installを実行した。

そんで、まずは東証の次のページからexcelの銘柄一覧をurllib使って取得。
http://www.tse.or.jp/market/data/listed_companies/index.html

そのあと読み込んんだデータからxldrを使ってコード、銘柄名、業種コードを取得して
それらをcsv形式にしてまとめた一覧を標準出力に書き出した。

コード
#!/usr/bin/python
# -*- coding: utf-8 -*-

import xlrd
import urllib

def readlist(t, url):
    fd = urllib.urlopen(url)
    content = fd.read()
    fd.close()

    book = xlrd.open_workbook(file_contents=content)
    sheet = book.sheet_by_index(0)

    for n in range(1, sheet.nrows):
        row = sheet.row(n)
        day = int(row[0].value)
        code = int(row[1].value)
        name = row[2].value.encode('utf_8')
        sector = int(row[3].value) if len(row) > 3 else ""
        print ",".join([str(code), name, str(sector), t])

if __name__ == '__main__':
    urls = {
        "市場第一部(内国株)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje6000003l9u4.xls",
        "市場第一部(外国株)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023aym.xls",
        "市場第二部": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023aza.xls",
        "マザーズ(内国株)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023azg.xls",
        "マザーズ(外国株)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023azm.xls",
        "REIT・ベンチャーファンド・カントリーファンド": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023b04.xls",
        "ETF・ETN": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023azy.xls",
        "PRO Market": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje60000023azq.xls",
        "JASDAQ(グロース)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje6000002t00f.xls",
        "JASDAQ(スタンダード)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje6000003uzjd.xls",
        "JASDAQ(スタンダード・外国株)": "http://www.tse.or.jp/market/data/listed_companies/b7gje60000023aiz-att/b7gje6000003v04x.xls"}

    for t, url in urls.items():
        readlist(t, url)
出力結果
1301,極洋,50,市場第一部(内国株)
1332,日本水産,50,市場第一部(内国株)
1333,マルハニチロ,50,市場第一部(内国株)
1352,ホウスイ,6050,市場第一部(内国株)
1377,サカタのタネ,50,市場第一部(内国株)
1379,ホクト,50,市場第一部(内国株)
1414,ショーボンドホールディングス,2050,市場第一部(内国株)
1417,ミライト・ホールディングス,2050,市場第一部(内国株)
1419,タマホーム,2050,市場第一部(内国株)
1420,サンヨーホームズ,2050,市場第一部(内国株)
1514,住石ホールディングス,1050,市場第一部(内国株)
1515,日鉄鉱業,1050,市場第一部(内国株)
1518,三井松島産業,1050,市場第一部(内国株)
1605,国際石油開発帝石,1050,市場第一部(内国株)
1606,日本海洋掘削,1050,市場第一部(内国株)
1662,石油資源開発,1050,市場第一部(内国株)
1663,K&Oエナジーグループ,1050,市場第一部(内国株)
1712,ダイセキ環境ソリューション,2050,市場第一部(内国株)
      :

2014年7月5日土曜日

MessageFormatで勝手にカンマが付く

javaのMessageFormatクラスで数値を表示したとき、3桁ごとに勝手にカンマが付きます。
        String msg = MessageFormat.format("{0}", 100000);
        System.out.println(msg);
実行結果
100,000
この結果はロケールにも依存してます。 デフォルトのLocaleをロシアにすると、スペースだけ入ります。 他にもカンマの代わりにピリオドを使う国もあるみたいです。
        Locale.setDefault(new Locale("ru"));
        String msg = MessageFormat.format("{0}", 100000);
        System.out.println(msg);
出力結果はこうなります。
100 000
Locale依存でもあるし、カンマを付けたくないときは次の2種類の方法でできるようです。

・数値をStringにする
ググるとまず出てきたのがこの方法です。

        String msg = MessageFormat.format("{0}", String.valueOf(100000));
        System.out.println(msg);
文字列を表示するので当然勝手にフォーマットされなません。
100000

・数値のフォーマット方法を指定する
APIドキュメント見ると、{0}のところに追加でフォーマットを指定できるようです。
 {ArgumentIndex , FormatType , FormatStyle }
FormatTypeにnumberを指定すると、FrotmatStyleにDecimalFormatと同じようにフォーマットを指定できるみたいです。
        String msg = MessageFormat.format("{0,number,#}", 100000);
        System.out.println(msg);
これでカンマが付加されなくなります。
100000
この方法はここを参照しました。
http://stackoverflow.com/questions/1942118/how-do-i-format-a-long-integer-as-a-string-without-separator-in-java

2014年5月25日日曜日

#pragma packのメモ

構造体のアライメントがずれるから、#pragma packとやらを試した時のメモ。 gccでは使えるみたいだが、他のコンパイラはよくわからない。 Cは普段ほぼ使わないから難しく感じる。。
#include 

#pragma pack(push, 2)
struct s1 {
 char a[1];
 int b;
};

#pragma pack(pop)
struct s2 {
 char a[1];
 int b;
};

#pragma pack(1)
struct s3 {
 char a[1];
 int b;
};

int main() {

 printf("%d\n", sizeof(struct s1));
 printf("%d\n", sizeof(struct s2));
 printf("%d\n", sizeof(struct s3));

 return 0;
}

Syntax Highlightのバグ?でなんか最終行がおかしい・・

このコード動かすと次の結果になった。
6
8
5

eclipseにCDT入れて試すほうが苦労した・・。
build後に実行しても結果が表示されなかった。
cygwinを使う設定でプロジェクト作った環境だったのに、
結局Runの設定でcygwinのbinのパスを追加したら解決。

2014年4月6日日曜日

javaでsocketを使ってバイナリデータ送受信メモ

javaでソケットを使って、例えばint+doubleの12byteデータを複数回送受信するようなことをしてみた。これができれば、片側javaでもう片方がjava以外の場合に、任意のプロトコルデータみたいなものを決めて通信できるはず。java同士ならクラスを作ってObjectOutputStream/ObjectIutputStream使えば済むと思う。 ここでは、ByteBufferに詰め込んで送受信する方法で試したが、もっといい方法があるのかはあんまり調べてない。

サーバ側

この例ではserverSocket.accept()で待ち受け開始、クライアント着信後に12byte分読み込める状態になったらbyte[]に読み込み。 その後、ByteBufferにwrap()して、getInt(),getDouble()で各データを取り出す。一応エンディアンはbigendianにしておいた。サーバではデータを受信したら表示するだけ。

追記) doubleやfloatなどの浮動小数点型を送信する場合にはもう少し考慮が必要かも。
java同士なら問題ないけど、その他とつなぐときはIEEE754の表現に合わせるなど必要?
package test.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class server {
    private static int port = 11111;
    private static int datasize = (Integer.SIZE + Double.SIZE) / 8;

    public static void main(String[] args) throws IOException,
            InterruptedException {

        ServerSocket serverSocket = null;
        InputStream in = null;

        try {
            serverSocket = new ServerSocket(port);
            Socket socket = serverSocket.accept();
            System.out.println("connected");
            in = socket.getInputStream();
            while (!socket.isClosed()) {
                int size = in.available();
                if (size >= datasize) {
                    byte[] data = new byte[datasize];
                    in.read(data, 0, datasize);
                    ByteBuffer buf = ByteBuffer.wrap(data);
                    buf.order(ByteOrder.BIG_ENDIAN);
                    System.out.println(buf.getInt(0) + ": "
                            + buf.getDouble(Integer.SIZE / 8));
                }
                Thread.sleep(100);
            }
        } finally {
            if (in != null)
                in.close();
            if (serverSocket != null)
                serverSocket.close();
        }
    }
}

クライアント側

new Socket(hostName, port)でソケット作成。 その後、ByteBuffer.allocate(datasize)で12byteのデータ格納エリアを作り、intとdoubleの値を入れてwrite()する。これを100回繰り返し。

package test.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;

public class client {
    private static String hostname = "localhost";
    private static int port = 11111;
    private static int datasize = (Integer.SIZE + Double.SIZE)/8;

    public static void main(String[] args) throws IOException,
            InterruptedException {

        OutputStream out = null;
        try {
            out = (new Socket(hostname, port)).getOutputStream();

            for (int i = 0; i < 100; i++) {
                ByteBuffer buf = ByteBuffer.allocate(datasize);
                buf.putInt(i).putDouble(Math.random());
                out.write(buf.array());
                Thread.sleep(100);
            }
        } finally {
            if (out != null)
                out.close();
        }
    }
}



結果
connected
0: 0.4699143388898742
1: 0.2983774724033843
2: 0.12623749040407317
3: 0.19952009860520947
4: 0.10241603823568246
5: 0.6230472332876812
    :