Tips

IT技術系Tips

ブラック・ショールズ式を実装してみた(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)

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

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

postgreSQLのインポートとエクスポート

エクスポート

定義のみ

pg_dump -U postgres -f schema.sql -C -F p -v -s my_schema_name

複数社にパッケージを納品する場合などに使用する。
バックアップとしてエクスポートする場合には、データも含める必要があるので、このオプションの組み合わせだけじゃダメ。

オプション 意味 備考
-U postgres DBのpostgresユーザーで処理を行う。 OSのユーザーではなくDBのユーザー。-Uで指定しない場合、OSでログイン中のユーザー名で、処理しようと試みる。
-f schema.sql 出力するファイル名。
-C create database構文を含める。
-F p 出力形式をplain(SQL)にする。 現地でインポートに失敗した場合に対処しやすいためお勧め
-v 進行状況やエラーを出力する。 導入時に標準出力とエラー出力をリダイレクトしてファイルに保存できるためお勧め。
-s my_schema_name エクスポートするスキーマ名を指定する。 これを指定しないと、publicスキーマとかも出力されるっぽい。

インポート

標準出力、エラー出力に吐かれたログをlog.txtに記録しつつインポート

"c:\Program Files\PostgreSQL\9.2\bin\psql.exe" -U postgres < schema.sql 2>&1 > log.txt

数学わかんねーからプログラムでズルしてみた 微分編(Python:Sympy)

微分ってなんぞ?

知るわきゃねーだろ!
コンビニの会計で使うくらい一般的になって出なおせや!

Wikipediaを読む

数学、とくに解析学における微分法(びぶんほう、differentiation, derivation)は、
空間やその上に定義される関数・写像を各点の近傍で考え、
その局所的な振舞いを調べることによって、それらの特徴を記述する方法である。

微分法 - Wikipedia

ふむ、局所的な振る舞いが空間で写像するわけだな。
振る舞い関数の近傍を記述する方法であると。

はい、お手上げ!

とりあえず微分する

In [4]: diff(3*x, x)
Out[4]: 3

変数が一つなので、何も指定しなくても良い。

In [3]: diff(x**2)
Out[3]: 2⋅x

定数は消える。

In [3]: diff(x**2 + 10000)
Out[3]: 2⋅x


こっからは偏微分(変数が2個以上あると、一部だけ微分するので偏微分というらしい)

In [7]: a = x**2 * sin(x + y)

In [8]: a
Out[8]: 
 2           
x ⋅sin(x + y)

In [9]: diff(a, x)
Out[9]: 
 2                            
x ⋅cos(x + y) + 2⋅x⋅sin(x + y)

In [10]: diff(a, y)
Out[10]: 
 2           
x ⋅cos(x + y)

変数が2つあるので、明示的に何で微分するか渡す必要がある。
第2引数を渡さないとエラー。


なにやら正解っぽいのが出たが、これっぽっちも微分がなんたるかを理解していない。
ググったところ、ぐにゃぐにゃしてるグラフのある一点での傾きを求めるものっぽい。

さっき定数が消えたのは、傾きと関係ないからか?

newton_methodなるものが、微分使ってがんばるらしいのでやってみた。



newton_methodとは

りんごが落ちそうな雰囲気が漂ってる。
Newton-Raphson method(ニュートン・ラフソン法)とも呼ばれるらしい。
名称はアイザック・ニュートンとジョセフ・ラフソンに由来するらしいが、ラフソンさん省略されることがあるとかかわいそう。

Wikipediaを読む

方程式系を数値計算によって解くための反復法による求根アルゴリズムの1つである。

http://ja.wikipedia.org/wiki/%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%88%E3%83%B3%E6%B3%95

方程式系のってなんだよって。
細かいことは気にせず先に進もう。

やってみる

Wikipediasqrt(2)の近似値の求め方が書いてあったので、こいつを題材にしよう。

1.41421356(ヒトヨヒトヨニヒトミゴロ)を求めるのが目標。
9桁までそれっぽくでりゃいいっしょ。

In [1]: sqrt(2)
Out[1]: 
   ___
╲╱ 2 

In [2]: sqrt(2).evalf(9)
Out[2]: 1.41421356

よっしゃぁ!!!
クリアぁああああ!!



じゃなくて、newton_method使わないとね、せっかくだし。



まず、平方根をグラフで表現してみる。
方程式にするとこんな感じ。
y=x^2

In [1]: plot(x**2)
Out[1]: <sympy.plotting.plot.Plot at 0x108989dd0>

f:id:kaerouka:20131221172216p:plain
x=1の時、y=1
x=1.4142... y=2
x=2の時、y=4
x=3の時、y=9 ...
となる。

で、こんなグラフ書いてどうするわけ?ってとこなんだが、どうにもならない・・・
この方程式をちょっといじれば、newton_methodで解ける形になる。

y=x^2+Cがその方程式。

Cは切片。C=-2としてプロットしてみる。

In [1]: plot(x**2 - 2, (x, -5, 5))
Out[1]: <sympy.plotting.plot.Plot at 0x106f5af10>

f:id:kaerouka:20131221175750p:plain
この関数のyに0を代入すると
0=x^2+2
x^2=-2
x=\pm \sqrt 2
となり、yが0の時に、求めたい値が出るって仕組み。

こいつをsympyで見てみると

In [1]: C = symbols('C')

In [2]: solve(x**2 - C, x)
Out[2]: 
⎡   ___    ___⎤
⎣-╲╱ C , ╲╱ C ⎦

になる。
ずれてるってレベルじゃねーぞ




ここからが本題。
Wikipediaの導入の項目を見てみる。

この方法の考え方は以下のようである:まず初めに、予想される真の解に近いと思われる値をひとつとる。
次に、そこでグラフの接線を考え、その x 切片を計算する。

http://ja.wikipedia.org/wiki/%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%88%E3%83%B3%E6%B3%95#.E5.B0.8E.E5.85.A5

予想される真の解・・・1.4142...ってわかってんだけど、今回は2にしてみる。

y=x^2 - 2のグラフと、左記方程式のx座標が2の時の接線を同時にプロットしてみる。

まず、x座標が2の時の方程式を求める。

In [5]: Eq(y, x ** 2 - 2)
Out[5]: 
     2    
y = x  - 2

微分すると

In [6]: diff(x ** 2 - 2)
Out[6]: 2⋅x

x座標が2の時の傾きは

In [8]: (2 * x).subs(x, 2)
Out[8]: 4

これぞ微分パワー!

点(2, 2)を通る傾き4の1次方程式のグラフは
bを切片とすると

In [10]: b = symbols('b')

In [11]: Eq(2, 4 * 2 + b)
Out[11]: 2 = b + 8

これをbについて解くと

In [12]: solve(Eq(2, 4 * 2 + b))
Out[12]: [-6]

※戻り値がlistなのは、解が複数ある方程式があるからね。y=x^2とか

これで傾きと切片が出せたので、1次方程式が書ける。
y=4*x-6

y=x^2 - 2と一緒にプロットすんぜ!

In [13]: plot(x**2-2, 4*x-6, (x, -4, 4))
Out[13]: <sympy.plotting.plot.Plot at 0x1078a2890>

f:id:kaerouka:20131221202840p:plain
ちなみに赤文字はmac付属のソフトでちまちま加筆してます・・・

√2に近い何かが何かというと・・・
y=4*x-6のyが0の時なので

In [31]: Eq(y, 4 * x -6)
Out[31]: y = 4⋅x - 6

In [32]: Eq(y, 4 * x -6).subs(y, 0)
Out[32]: 0 = 4⋅x - 6

In [33]: solve(Eq(y, 4 * x -6).subs(y, 0), x)
Out[33]: [3/2]

In [34]: solve(Eq(y, 4 * x -6).subs(y, 0), x)[0].evalf()
Out[34]: 1.50000000000000

ようやく出たよ\sqrt 2に近い何か!
1.5だった!!確かに1.41421356...に近い!!

Wikipediaの導入の項目の続きをを読むと

このx切片の値は、予想される真の解により近いものとなるのが一般である。
以後、この値に対してそこでグラフの接線を考え、同じ操作を繰り返していく。

http://ja.wikipedia.org/wiki/%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%88%E3%83%B3%E6%B3%95#.E5.B0.8E.E5.85.A5

って書いてあるけど、最初に使ったx切片が2だね。
同じ操作を繰り返していくってのは、次はx切片を1.5にしてやってみようって事。
これを繰り返すと\sqrt 2に近づきまっせってことだ。


定式化しないと使い物にならんので、定式化する。

だが、ここでまさかの気力切れ。


あるじゃない、同じ事解説してる動画。
めっちゃわかりやすい。
しかもイケメンボイス。

さて、手を抜いたところで最後にプログラム貼り付けて終わり。

def sqrt_newton_method(value, cnt):
	 # x切片
	preval = value

	for i in range(cnt):
		preval = 1/2 * (preval + value/preval)

	return preval

if "__main__" == __name__:
	# √2を1回計算
	print(sqrt_newton_method(2, 1)) #=>1.5
	# √2を2回計算
	print(sqrt_newton_method(2, 2)) #=>1.4166666666666665
	# √2を4回計算
	print(sqrt_newton_method(2, 4)) #=>1.4142135623746899

	print()
	# √3を4回計算
	print(sqrt_newton_method(3, 4)) #=>1.7320508100147274

setup.py でインストールしたモジュールをアンインストールする(Python)

やり方

  • インストールし直す
sudo python setup.py install --record test.txt 

--recordを付けると生成したファイルの一覧をtest.txtに記載してくれる。

  • 消す
cat files.txt | sudo xargs rm -rvf

sudoを付けとかないと、うざいエラーメッセージNo.1の名をほしいままにしている
Permission deniedが顔を出すかも知れないので注意。


ファイルを読み込んで重複を削除する(Python)

ソース

In [1]: import codecs
In [2]: set([x for x in codecs.open("yakuman.txt", "r", "utf-8")])
Out[2]: 
{'九蓮宝燈\n',
 '四暗刻\n',
 '四暗刻単騎\n',
 '国士無双\n',
 '国士無双13面\n',
 '地和\n',
 '大三元\n',
 '大三元 四暗刻\n',
 '大三元 字一色\n',
 '大四喜\n',
 '大四喜 字一色\n',
 '天和\n',
 '字一色\n',
 '小四喜\n',
 '小四喜 字一色\n',
 '数え役満\n',
 '清老頭\n',
 '緑一色\n'}

In [3]: codecs.open("test.txt", "w").writelines(set([x for x in codecs.open("yakuman.txt", "r", "utf-8")]))

In [4]: cat test.txt
小四喜 字一色
大三元 字一色
大四喜
地和
国士無双
四暗刻単騎
大三元
九蓮宝燈
清老頭
国士無双13面
大三元 四暗刻
四暗刻
緑一色
字一色
天和
大四喜 字一色
数え役満
小四喜

途中でさりげなく登場してるcatは、catコマンドのalias的存在。

In [6]: %alias
Total number of aliases: 16
Out[6]: 
[('cat', 'cat'),
 ('clear', 'clear'),
 ('cp', 'cp -i'),
 ('ldir', 'ls -F -G -l %l | grep /$'),
 ('less', 'less'),
 ('lf', 'ls -F -l -G %l | grep ^-'),
 ('lk', 'ls -F -l -G %l | grep ^l'),
 ('ll', 'ls -F -l -G'),
 ('ls', 'ls -F -G'),
 ('lx', 'ls -F -l -G %l | grep ^-..x'),
 ('man', 'man'),
 ('mkdir', 'mkdir'),
 ('more', 'more'),
 ('mv', 'mv -i'),
 ('rm', 'rm -i'),
 ('rmdir', 'rmdir')]

モノホンのコマンドとして実行したい時は!catとする。
最初に!をつければ、headとかpingとか、osのコマンドが使える。

データ

四暗刻単騎
国士無双
大三元
国士無双
国士無双
小四喜
小四喜
大三元
....以下略