Tips

IT技術系Tips

分足の為替データを取得するスクリプト(Python)

ロシア語のサイトだが、アカウント作成とか面倒なことなしにデータが置いてあった。
言語の選択で英語も可。
Архив котировок Forex для ProSuite и MetaStock


いちいち手動でダウンロードして全部解凍するのがめんどいから
各ページにアクセスしてzipをダウンロードし、解凍して保存するスクリプトを書いた。
github.com

こないだ試したプログレスバー(tqdm)も使った。
kaerouka.hatenablog.com

前回はipythonから試してダメだったが、cPythonではさほど問題なかった。
少しだけ問題があって、たぶんtqdmは別スレッドで動作しているので、tqdmでプログレスバーを出す前に
標準出力に出力してるとちょっと変な動作になった。
こんな感じ。

データの配置場所のURLを収集中。
  0%|          | 0/4698 [00:00<?, ?it/s]収集完了。
データを取得中。
 31%|███       | 1464/4698 [52:19<1:56:39,  2.16s/it]

収集完了のprintは、プログレスバーを出すより前にやってるはずなんだけど、こんなんなっちゃった。
対処法がありそうだけど面倒だから放置。


プログラムの実行速度だけど、終わるまでに3時間くらいかかる。
5000個近いファイルのダウンロードになるみたいで、並列処理無しじゃこんなもんか。


2016/02/03 追記
tqdm使う前にflushしたらずれなくなった。

    print("データを取得中。")

    # tqdmが非同期で、表示がずれるためいったんflush
    stdout.flush()

    for data_url in tqdm.tqdm(urls):

並列処理しながらtqdm使ったらどうなっちゃうんだろう・・・w

数学わかんねーからプログラムでズルしてみた 1次方程式編(Python:Sympy)

最近Smiteってゲームにハマってて、これの勝率が気になった。
基本5:5で戦うゲームなんだけど、マッチングシステムがよく出来てて、長いことやってるとだいたい勝率が50%くらいになるようになってる。

現在の戦績が1190戦610勝580負。
勝率51%くらい。
さぁ、何連勝したら勝率52%になるんでしょうか!

今後の戦闘回数 = 今後の勝利回数 = xとすると、こんな感じ

(610 + x) / (1190 + x) = 0.52

sympyで書くとこう

In [1]: solve(Eq((610 + x) / (1190 + x), 0.52))
Out[1]: [18.3333333333333]

方程式は解が複数あったりもするから配列で答えが返ってくるんだね。
戦う回数に小数とか無いから切り上げて

In [2]: solve(Eq((610 + x) / (1190 + x), 0.52))[0].ceiling()
Out[2]: 19

はい、19連勝すれば勝率52%を超えます!

勝率51%の自分がストレートに19連勝できる確率は

0.51 ^ 19

これをpython(sympy)で書くと

In [3]: 0.51**19
Out[3]: 2.778646798186872e-06

指数とかよくわかんない。
新人の頃、計算結果を指数表記で出してお客さんに「こんなんわけわからんわ!」と、怒られたことがある。
わざとやったわけじゃないんだけどね、PostgreSQLの列定義をfloatにしててそのまま出力してたら出ちゃってね・・・。
なんて苦い経験があるから指数表記をやめる。

※変数aはpythonのbuiltinのfloatなんで、sympyのFloatにしてevalf使って桁数指定した。

In [4]: a=0.51**19

In [5]: Float(a).evalf(50)
Out[5]: 0.0000027786467981868720860121231563955035426261019892991

はい、まだよくわかんない。

分数にしよう。

In [6]: Rational(a)
Out[6]:
   3280447126872685
──────────────────────
1180591620717411303424


わかんねぇよ!!
つーかほんとかよこれ。
ドキュメントを見てみると
SymPy Core — SymPy 0.7.6.1 documentation

If the simpler representation of the float is desired then consider limiting the denominator to the desired value or convert the float to a string (which is roughly equivalent to limiting the denominator to 10**12):

ふむ、文字列にするか分母を制限しろとか書いてある。

In [7]: Rational(str(b))
Out[7]:
   277864679818687
─────────────────────
100000000000000000000

そろそろ自分が何をしたいのかわかんなくなってきた。

あー、そうだ。
勝率51%の自分がストレートに19連勝できる確率は「1/1000 くらい!」とか適当な感じで表して嘆きたかったんだ。

もういいよ。

In [3]: 0.51**19
Out[3]: 2.778646798186872e-06

なんだから

3/100万くらいっしょ?
それとも分母を制限してこんな感じのがまし?

In [8]: ra = Rational(str(b))
In [9]: ra.limit_denominator(1/a)
Out[9]: 1/359887

最初からわかってたけど、sympy使いこなしてないならwindows付属の関数電卓と紙でやったほうが断然早いよね。
でもlimit_denominatorはちょっと好き。
この関数見つけたのは嬉しい。

簡単にプログレスバーを表示できるtqdmを使ってみた(Python)

この記事の最初で紹介されてたから使ってみた。
postd.cc

こんなふうに書くと

for item in tqdm(items):
    process(item)

こんな感じで進捗を表示してくれるらしい。

18%|█████████                               | 9/50 [00:09<;00:41,  1.00it/s

リアルタイムで進捗を見たいなら、やっぱipythonとか使うよね。
やってみた。

In [5]: for i in tqdm.tqdm(range(10)):
   ...:     sleep(.1)
   ...:
 10%|笆遺毎笆遺毎笆遺毎笆遺毎笆・                                                                         | 1/10 [00:00<
 20%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆・
 30%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆・
 40%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺柾
 50%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
 60%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
 70%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
 80%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆・               | 8/10 [00:00<00:
 90%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆・       |
100%|笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎
笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎笆遺毎

In [6]:

\(^o^)/

相変わらずwindowsでipython使ってなんかやると文字化けで面倒なことになる。
前にコマンドプロンプトのコードページ変えたり、pythonの標準出力の文字コード変えたりとか試したけど結局ダメだった記憶が・・・。
たぶん今回の問題も無理なんだろう。

2016/02/02 追記
cPythonならそこそこうまくいった。
kaerouka.hatenablog.com

Sublime Text3でバイト数を表示するプラグイン作った

Codecs33をPackagesに入れないとダメ。
https://github.com/seanliang/Codecs33
あと、ConverToUTF8が入ってた方が嬉しい。

例のごとくOS X 10.9で動作確認。
winは知らない。

こんなイメージ
f:id:kaerouka:20140401235447p:plain

ソース→導入方法→雑記の流れで行きます。

ソース

import sublime, sublime_plugin
import codecs


class ByteLen(sublime_plugin.EventListener):

    def __init__(self):
        # statusに表示表辞書のkey
        self.status_key = 'bytes'
        # エンコーディングが取得できない場合に使用するエンコーディング
        self.default_encodings = ['cp932', 'utf-8']
        # エラー用
        unknown = '?'

    def on_selection_modified_async(self, view):
        text = ''
        for sel in view.sel():
            text += view.substr(sel)

        if not text:
            view.erase_status(self.status_key)
            return

        try:
            # origin_encodingは、ConvertToUTF8プラグインが指定している。
            n = len(codecs.encode(text, view.get_status('origin_encoding')))
        except:
            try:
                # 無理ならデフォルト
                for enc in self.default_encodings:
                    try:
                        n = len(codecs.encode(text, enc))
                    except:
                        pass
                    
                    # バイト数が取得できればelse句に進まずに正常終了
                    if n:
                        break
                else:
                    n = unknown
            except:
                n = unknown

        view.set_status(self.status_key, str(n) + ' bytes')

導入

ソースをbyte_len.pyという名前で、Sublime Text3の基本設定から辿れるPackagesフォルダにぶちこむだけ。
再起動位は必要かも。わかんない。
f:id:kaerouka:20140401235915p:plain
選択した箇所のバイト数が、左下のステータスバーに表示されるようになる。

雑記

なんでこんなプラグイン作ったかって、固定長のファイルを作りたかったからですよ。
レガシーなシステムとのやりとりって、未だに固定長だったりするわけで。
商品コード→38バイト目から30バイト
商品名→68バイト目から100バイト
みたいな仕様で渡ってくるデータが普通にあんの。

行の最後はCRLFで終わったりするんだけど、その前は必ず数字の2が入る!
とかそうゆう謎ルールがあったりする。

で、Sublimeさんは、選択した文字数はカウントしてくれても、バイト数はカウントしてくれない。
困るので作った。
秀丸サクラエディタだと、最初が0バイト目だったり1バイト目だったりして
何がなんだかわからんくなった記憶があったから、このプラグインは選択したバイト数の合計って形にした。

日本語周りでいろいろと足りなさすぎぜSublimeさん・・・

ソースのsublime開発周りを軽く解説

こんかいはsublime_plugin.EventListenerを継承して
on_selection_modified_async関数を実装することで、「何かを選択したらプラグインが動く」みたいなことしてる。
似たような関数でon_selection_modifiedってのがあるんだけど、こっちはまずい。
1文字ずつ連続して選択肢たりするとエラーメッセージと共に落ちる。
on_selection_modified_asyncは別スレッドで実行してくれるらしいので軽快に動作するみたい。
on_selection_modifiedの方は使い道がわからん。

左下のステータスバー関連の関数はこれら。

  1. set_status(key, value)
  2. get_status(key)
  3. erase_status(key)
  4. overwrite_status()
  5. set_overwrite_status(enabled)

ステータスバーに出てるエンコードするのに使った文字コードが欲しかったから
それを取ろうと思ったけど、keyがわからないから取れない。
こうゆうのマジ困る。
しかたないからConvertToUTF8のソース見てキー探してきたorz。

ちなみにencoding()の方はまともに動作しないから使ってない。
ConvertToUTF8使ってるからかしらんけど、いきなりWestern (Windows 1252)とか出てくる。
Sublime Text3の、ファイル→エンコードを指定して上書き保存の一覧に出てくるような文字列。

ブラック・ショールズ式を実装してみた(Python:Sympy)

勉強がてらに作ってみた。
参考にしたサイトは↓
http://www.findai.com/kouza/4009opt.html

とりあえずソース

ソース

import datetime
from sympy.mpmath import log, sqrt, exp
from sympy.statistics import Normal


def black_scholes(原資産, ストライク, 金利, ボラティリティ, 満期日=None, 基準日=None, 期間=0, 配当=0,
                  ポジション=True, コールプット区分=True, 想定元本=1):
    """ ブラック・ショールズ式。
    株価 or 通貨(通貨オプション) or 先物 or 債権 の価格を計算する。
    期間 または 満期日と基準日の組み合わせ の、どちらかが必須。

    満期日と基準日を指定する場合
    2000/07/01 - 2000/01/01 と 2001/01/01 - 2000/7/1 では
    日数が異なるため、期間に違いが出る事に注意。

    @param 原資産: 株価 or 通貨(通貨オプション) or 先物 or 債権 の価格。
    @param ストライク: 権利行使価格。
    @param 金利: リスクフリーレート。百分率。1% なら 0.01を指定。
    @param ボラティリティ: 標準偏差、予想変動率。
    @param 満期日: datetime型。基準日とセットで使用する。例:datetime.strptime("2015-01-01", "%Y-%m-%d")
    @param 基準日: datetime型。満期日とセットで使用する。例:datetime.strptime("2015-01-01", "%Y-%m-%d")
    @param 期間: 数値。1ヶ月なら1/12、2ヶ月なら2/12。5年なら5。
    @param 配当: 株価:配当率、通貨:外国金利、先物:安全利子率、債権:クーポンレート。
    ヨーロピアンコール・オプションの場合、初期値の0で良い。
    @param ポジション: boolean。買い:True、売り:False
    @param コールプット区分: boolean。買う権利:True、売る権利:False
    @param 想定元本: 計算の最後の係数。1ならコールプット価格そのものが算出される。
    @return: 資産価値
    """
    if not 期間 and (満期日 is None or 基準日 is None):
        raise "期間 または 満期日と基準日の両方 を指定して下さい。"

    t = 期間 if 期間 else (満期日 - 基準日).days / 365
    q = 配当
    S = 原資産
    N = lambda d: Normal(0, 1).cdf(d)
    r = 金利
    k = ストライク
    σ = ボラティリティ

    d1 = (log(S / k) + (r - q + (0.5 * σ ** 2)) * t) / (σ * sqrt(t))
    d2 = d1 - σ * sqrt(t)

    C = exp(-q * t) * S * N(d1) - exp(-r * t) * k * N(d2)

    # 売り買いで値反転
    C = C if ポジション else C * -1

    # コールプット区分。ポジションと同じ扱い。
    C = C if コールプット区分 else C * -1

    C *= 想定元本

    return C.evalf()

Sympy

Sympyが特に活躍したのはここ

N = lambda d: Normal(0, 1).cdf(d)

平均が0で分散値が1になる正規分布を作って、正規累積分布関数として使う。
もし業務で金融系の関数書きまくるなら、この正規累積分布関数はやたらめったらいろんなとこで使われると思うから
↑のとこだけ関数の外に出しちゃってもいい。

実行速度だけど、Normal(0, 1)の時点では初期化が走るだけだから
関数の中で使おうが外出しにしようが大差無い。
↓はNormalの初期化のとこのソース

    def __init__(self, mu, sigma):
        self.mu = sympify(mu)
        self.sigma = sympify(sigma)

一応計測してみる

#----------- in -----------#
import timeit


t = timeit.Timer("N = lambda d: Normal(0, 1).cdf(d);N(3.1987)", "from sympy.statistics import Normal")
print(min(t.repeat(3, 10000)))

t2 = timeit.Timer("N(3.1987)", "from sympy.statistics import Normal;N = lambda d: Normal(0, 1).cdf(d)")
print(min(t2.repeat(3, 10000)))


#----------- out -----------#
1.1081136350985616
1.1075455570826307

やっぱり変わらない。
定数ってゆうのが気になるよね。
ランダムにした。

#----------- in -----------#

import timeit


t = timeit.Timer("N = lambda d: Normal(0, 1).cdf(d);N(random.random())", "from sympy.statistics import Normal;import random")
print(min(t.repeat(3, 10000)))

t2 = timeit.Timer("N(random.random())", "from sympy.statistics import Normal;N = lambda d: Normal(0, 1).cdf(d);import random")
print(min(t2.repeat(3, 10000)))


#----------- out -----------#
17.53592729999218
17.445876146899536

うん、ほとんどrandom.random()の実行時間だね。


雑記

いやはや、言葉の意味が難しいね。
ストライクとか想定元本とか知らんし。
計算自体は正規累積分布関数とかsympyに入ってるし難しくはなかったけど。

Pythonでコーディングする時はPycharm使ってるんだけど、警告を示す下線出まくりね。
f:id:kaerouka:20140327095735p:plain
薄いけど、日本語の変数名の下に波線出てる。
ただでさえ言葉の意味がわからんのに、英語使ったり、アルファベット1文字とかにしたら更に分けわなんなくなるから
引数の変数名に日本語使ってみたけど、普通に書いてるつもりが
multi spaces after keyword
とか言われたりするし。

Argument name should be lowercase って警告も出まくり。
日本語にlowerもくそもねーよ。
もし金融関連を扱うなら、IDEの設定がっつり見直すとか、変数周りの規約的なの考えないとダメかも。

Sublime Text3でコードポイントを表示するプラグイン作ってみた(sjis対応版)

前回作ったプラグインを改善して、sjiseuc-jpも加えた。
os x 10.9.2、sublime text3のみ動作確認済み。
f:id:kaerouka:20140325040418p:plain
sjisってゆうのはphpでいうところのsjis-win、javaでいうところのms932のこと。
euc-jpは・・・・

今回も、ソース→導入方法→愚痴の流れでいこうかと。

ソース

import sublime, sublime_plugin
import codecs


class CodePoint3Command(sublime_plugin.TextCommand):
    def run(self, edit):
        pos = self.view.sel()[0].begin()
        c = self.view.substr(pos)

        d = [
        ("SJIS:\t\t\t", "".join([hex(x)[2:] for x in codecs.encode(c, "cp932")]).upper())
        ,("UTF-8:\t\t", "".join([hex(x)[2:] for x in c.encode('utf-8')]).upper())
        ,("EUC-JP:\t", "".join([hex(x)[2:] for x in codecs.encode(c, "euc_jp", "ignore")]).upper())
        ,("Unicode:\t", hex(ord(c)).upper()[2:].zfill(4))
        ]

        text = "Sample:\t" + c + "\n\n" \
        	+ "".join([x[0] + "0x" + x[1] + "\n" for x in d])

        sublime.message_dialog(text)

導入

前回とまったく同じなので、そちら参照。

Codecs33に依存しています。
sublime text 3でsjisを扱うためにConvertToUTF8を入れている人は多いと思いますが
ConvertToUTF8導入時にCodecs33は入れてるはずなので、このプラグインを使いたいという奇特な方は、既にCodecs33は入ってると思います。

愚痴

さぁてやってまいりました、メインコンテンツ。
euc_jpのエンコードのソース。

,("EUC-JP:\t", "".join([hex(x)[2:] for x in codecs.encode(c, "euc_jp", "ignore")]).upper())

第3引数に"ignore"って指定してるのね。
encodeの第3引数は、errorsを指定するところ。
もうね・・・変換できないとか言うわけですよ、Pythonさんが。
何が変換できないかって?

外字です。

外字ってゆうのは、wikipedia外字ページにあるように、Unicodeの、U+E000〜U+F8FF、U+000F0000〜U+000FFFFD、U+00100000〜U+0010FFFDの範囲に割り当てられる文字の事。

あー、意味わかんねーと思うかもしれないけど、金融機関なんかは自分のところで外字フォント作って、わけわからん漢字を割り当ててたりするのね。
例えば、U+E000だったら「髙」(はしご高)が表示されるようにしよー!みたいな感じで、独自のフォントを作ってる。
「髙」はjisには無くて、扱えない(もしくは昔は扱えなかった)ところもあるからこんな感じになってる。

で、codecs.encodeで使える文字コードの一覧を見ると、EUC関連は3つあるけど、全滅。

UnicodeEncodeError: 'euc_jisx0213' codec can't encode character '\ue000' in position 0: illegal multibyte sequence

私の心境
f:id:kaerouka:20140325045621j:plain
ザッケローニ監督
画像の出典:nikkansports.com

しょーがないからignore指定して、変換できなかったら諦めてこうした。
f:id:kaerouka:20140325050012p:plain

どーーーーしても変換したいなら変換テーブルとか自分で定義して

try:
    eucjp_c=codecs.encode(c, "euc_jp", "ignore")
except UnicodeEncodeError:
    eucjp_c=自分で変換処理

みたいに書くんだろうけど、さすがにだるいよね。
だって、私がEUCとか使ったの10年前くらいが最後だし・・・さよならEUC

ちなみに、秀丸文字コード表示機能をパクってこの機能を作ってみたわけだけど
秀丸だと、UnicodeのE000がEUCでFFA1になってる。
f:id:kaerouka:20140325050744p:plain
私が期待するのはeucJP-msのF5A1。
う~む、EUC恐るべし。

そういや触れてなかったけどサロゲートペア・・・
気づかなかったことにしよう。

Sublime Text3でコードポイントを表示するプラグイン作ってみた

機能

UnicodeUTF-8のコードポイントを表示する。
f:id:kaerouka:20140309205049p:plain
SJISEUC-JPも欲しいって?
それはね・・・後述します・・・。

2014/03/25追記
sjis, euc-jp対応版があるので、使いたい人はそちらがおすすめ。
Sublime Text3でコードポイントを表示するプラグイン作ってみた(sjis対応版) - Tips
os x 10.9.2、sublime text3のみ動作確認済み。

コード

code_point.py

import sublime, sublime_plugin

class CodePointCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        pos = self.view.sel()[0].begin()
        c = self.view.substr(pos)

        d = [
        ("UTF-8:\t\t", "".join([hex(x)[2:] for x in c.encode('utf-8')]).upper()), 
        ("Unicode:\t", hex(ord(c)).upper()[2:])
        ]

        text = "Sample:\t" + c + "\n\n" \
        	+ "".join([x[0] + "0x" + x[1] + "\n" for x in d])

        sublime.message_dialog(text)

使い方

スクリプトを保存

/Users/anonymous/Library/Application Support/Sublime Text 3/Packages/
に、適当な名前でディレクトリを作ります。
anonymousの箇所はアカウント名です。
kaeroukaというディレクトリにしておきます。

ソースをcode_point.pyとして
/Users/anonymous/Library/Application Support/Sublime Text 3/Packages/kaerouka
に保存します。

コマンドパレットに登録

/Users/anonymous/Library/Application Support/Sublime Text 3/Packages/User

User.sublime-commands
という名前でファイルを作ります。
中身は

[
	{ "caption": "code_point", "command": "code_point"}
]

です。

これで、Shift + Command + Pでコマンドパレットを開き
code_pointと入力すると機能が使えます。

ショートカットに登録

Sublime Text > Preferences から、ユーザー用のキーマップファイルを開き、下記のjsonコードをコピペします。

	//コードポイント表示
	{ "keys": ["f2"], "command": "code_point" },

これで、f2を押すと機能が使えます。
デフォルトではf2を押すと、next_bookmakコマンドが起動されますが、私は使わないので上書きしちゃってます。

愚痴

ほんとはSJISくらいは表示したかったんだけど、できなかったんだよねー。

c.encode('utf-8')

は、問題ない。

c.encode('sjis')

は、エラーになる。
エラーの内容はこれ。

LookupError: unknown encoding: shift_jis

なぜか?

Sublime TextのPythonインタプリタって、OSにインストール済みのPython使ってるわけじゃなくて
組み込みのやつなんだってさ。
しかも、独自ビルドしてるっぽくて、JapaneseCodecs入れてないみたいなのね。
JapaneseCodecsはずいぶん昔のバージョンで本家に組み込まれたはずなんだけど、Sublime Textに組み込まれてるPythonインタプリタには入ってないみたい。
悲しい・・・。
でもSublime Text3はベースをPython2からPython3にしたみたいだし、そのうち日本語周りもマシになるんじゃないかなーと期待してる。

2014/03/16 追記
sublime textでsjisを扱う場合、convertToUTF8ってゆうプラグイン使うけど、
sublime test3の場合、Codecs33なるパッケージも一緒に入れる。
こいつ使えばsjisもいけちゃう・・・?
sjisガー!sjisガー!って言ってるけど、実際エンコードで指定するのはcp932だけども。

もう1個愚痴。

このソース

        d = [
        ("UTF-8:\t\t", "".join([hex(x)[2:] for x in c.encode('utf-8')]).upper()), 
        ("Unicode:\t", hex(ord(c)).upper()[2:])
        ]

このソースで、項目名に当たるところに「:\t\t」とかベタ打ちしてあるけど、これにも残念な理由があって
プロポーショナルフォント使ってるから、

        c.ljust(20)

とかやってもずれるんだよね。

なんかいい解決方法ないかな〜(チラッ