Haskell DSLによる複数プラット...
Transcript of Haskell DSLによる複数プラット...
Haskell DSLによる複数プラットホーム・複数言語コード生成
今井 敬吾(有) ITプランニング
2012. 3. 23次世代ソフトウェアの開発支援環境(公益財団法人 科学技術交流財団) @ 愛知県立大学サテライトキャンパス
私について
(有)ITプランニング所属プログラマー(C++/Java/Obj-C/Haskell/OCaml, スマートフォン/Web開発等) / SEとして働く傍ら、
論文執筆・関数型言語の (草の根的) 普及活動に従事
名古屋大学 情報科学研究科 修了(阿草・結縁研)
2012年3月 博士(情報科学) 取得見込み並行分散計算(π計算/CCS/CSP)の関数プログラミングにおける応用を研究(していた)
2
(紹介スライド4枚)
(有)ITプランニングについて
• 金融業向けに株価/FXチャートを受託開発
• 関数型プログラミング言語を利用・業務において6年の使用経験をもつ・普及活動:セミナー講師(国立情報学研究所、(株)豆蔵)・イベント主催・
書籍執筆など
• 定理証明系Coqなど形式手法を導入
3
宣伝• 書籍 入門OCaml・Scala実践プログラミング
• スタートSML# 2012/3/25(日)14:00-@名大理1-109
• 関数型プログラミング言語SML#の勉強会
• 招待講演:大堀 淳 教授 (東北大学) ほか
• 詳しくは http://tinyurl.com/smlnagoya 参照、参加については今井( [email protected] まで)
4
• 金融業向けに株価/FXチャートを受託開発
(有)ITプランニングの製品(一部)
5
http://www.itpl.co.jp/
金融チャートとは• 投資家に、相場の客観的な分析手法を提供するツール
• テクニカル分析
• 売買シグナル
• いつでも、どこでも、どんな端末でも使いたい
6
テクニカル分析と売買シグナル
• テクニカル分析 • 売買シグナル
7
過去のデータから統計的手法を用いて未来の値動きを予測するcf. ファンダメンタルズ分析
HTML5チャート テクニカル分析計算定義書今井宜洋!
平成 24 年 1 月 31 日
1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。
MA(N,X) =1N
N!1!
i=0
R終値(X ! i)
1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。
!(N,X) =
"####$
N!1!
i=0
%R終値(X ! i) ! AV G
&R終値(X), · · · , R終値(X ! N + 1)
'(2
N
Bol(K, N, X) = MA(N, X) + K!(N, X)
1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。
Env(N,A, X) = MA(N, X) ")
1 +A
100
*
!有限会社 IT プランニング システム開発部
1
例:移動平均
赤:短期(N=5)
黄:中期(N=20)
緑:長期(N=90)
テクニカル分析で特定の条件が成立した時、売買を促すサイン
例:移動平均線の ゴールデンクロス、デッドクロス
短期線が長期線を上に交わると、上昇トレンドが続きやすい
→買いシグナル
反対に、短期線が長期線を下に交わると、下降トレンドが続きやすい
→売りシグナル
投資家に、客観的な指標を提供する
f
多様な取引プラットホーム
• Java Applet
• Windows (C++)
• Adobe Flash (ActionSctipt)
• Webブラウザ(JavaScript/HTML5)
• 携帯(docomo, SoftBank(Java)/AU(BREW))
• iPhone (Objective-C)
• Android (Java)
8
「いつでも、どこでも、どんな端末でも」の結果:
➡ 6言語, 9種類の環境で金融チャートを納品
開発/メンテナンスコストの増大
• 仕様書・テスト:「この数列は仕様通りに生成されているか?」
スクリーンショットによる既存バージョンとの比較「要求:Windows版と同じチャートを出して下さい」
• 障害管理:特定環境でバグが見つかった時「docomo携帯版の一目均衡表の計算が一日ずれている」
「Windows版のパラボリックのドテンのタイミングが他と違う」
→ 残り8環境でも不具合調査が必要
• (コスト圧力:値下げ要求、オフショアとの競合)9
コード再利用の試み• ビジネスロジック部は再利用の余地あり
(テクニカル分析や売買シグナル等)
• …が、ソースもバイナリも直接の再利用は不可:
× Cで共通ライブラリを作成 e.g. lib*.a/.so, *.dll, JNI (Java Native Interface)
→ NG : Java Applet, 携帯, Flash, ブラウザ
× Javaとネイティブ両方で動作するスクリプト言語 e.g. Python / Jython, Ruby / JRuby
→ NG : Flash, JavaScript, ブラウザ
10
テクニカル分析DSL:Haskell/Tek
• 多用途に再利用できるコード生成DSL
‣ C, Javaコード生成
‣ イミディエイト評価 (ランダム実行など)
‣ TeXドキュメント生成 (未実装)
• Haskell上の埋め込みDSL (embedded DSL)
‣ Haskellの言語機能(型推論や高階関数)の恩恵を受けられる
11
テクニカル分析DSL Haskell/Tekによる 仕様記述とコード生成
12
Haskell/Tekコード
C言語プログラム
Cコンパイラ iPhone版
Javaプログラム
JavaScriptプログラム
TeX仕様書ソース
Javaコンパイラ
Android版
イミディエイト実行
ma n i = sum_close (i-(n-1)) i candles / toFloat n
Haskell/Tekコードの例:移動平均
13
i-(n-1)日目からi日目までの終値(close)の和を
i日目における
n日移動平均とは
nで割る
float accum0 = 0.0F;
for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}i_put(series[0], i, accum0 / (float) iparam[0]);
生成されるCコード:
Haskell/Tek:
HTML5チャート テクニカル分析計算定義書今井宜洋!
平成 24 年 1 月 31 日
1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。
MA(N,X) =1N
N!1!
i=0
R終値(X ! i)
1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。
!(N,X) =
"####$
N!1!
i=0
%R終値(X ! i) ! AV G
&R終値(X), · · · , R終値(X ! N + 1)
'(2
N
Bol(K, N, X) = MA(N,X) + K!(N,X)
1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。
Env(N,A, X) = MA(N, X) ")
1 +A
100
*
!有限会社 IT プランニング システム開発部
1
例2: ボリンジャーバンド
14
sigma_i n ma i = sqrt_ (sum_iter (i - n + 1) i dist) / toFloat n where dist i = pow2_ (close_at i - ma)
bol (n,a,b) i = let_ "ma" (MA.ma n i) $ \ma -> let_ "sigma" (sigma_i n ma i) $ \sigma -> tup5 (ma + b*sigma, ma + a*sigma, ma, ma - a*sigma, ma - b*sigma)
Haskell/Tek:
HTML5チャート テクニカル分析計算定義書今井宜洋!
平成 24 年 1 月 31 日
1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。
MA(N,X) =1N
N!1!
i=0
R終値(X ! i)
1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。
!(N,X) =
"####$
N!1!
i=0
%R終値(X ! i) ! AV G
&R終値(X), · · · , R終値(X ! N + 1)
'(2
N
Bol(K, N, X) = MA(N,X) + K!(N,X)
1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。
Env(N,A, X) = MA(N,X) ")
1 +A
100
*
!有限会社 IT プランニング システム開発部
1
HTML5チャート テクニカル分析計算定義書今井宜洋!
平成 24 年 1 月 31 日
1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。
MA(N,X) =1N
N!1!
i=0
R終値(X ! i)
1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。
!(N,X) =
"####$
N!1!
i=0
%R終値(X ! i) ! AV G
&R終値(X), · · · , R終値(X ! N + 1)
'(2
N
Bol(K, N, X) = MA(N,X) + K!(N,X)
1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。
Env(N,A, X) = MA(N,X) ")
1 +A
100
*
!有限会社 IT プランニング システム開発部
1
i日目より過去n日間に関する分散σ(n,i)
ボリンジャーバンド(5つ組)
高階関数 sum_iter i j f = Σ (x is i to j) f(x)
他のテクニカル(移動平均)の呼び出し
ボリンジャーバンド:生成されるC言語コード
15
float accum0 = 0.0F;
for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}
float ma = accum0 / (float) iparam[0];float accum1 = 0.0F;
for (int i1 = i - iparam[0] + 1; i1 <= i; i1++) { float x = i_get(candles, i1).close - ma; accum1 = accum1 + x * x;}
float sigma = sqrt(accum1 / (float) iparam[0]);
i_put(series[0], i + 0, ma + fparam[1] * sigma);i_put(series[1], i + 0, ma + fparam[0] * sigma);i_put(series[2], i + 0, ma);i_put(series[3], i + 0, ma - fparam[0] * sigma);i_put(series[4], i + 0, ma - fparam[1] * sigma);
分散σ
移動平均
ボリンジャーバンド
Haskell/Tek=(現状では) 性能の良いC言語マクロ
16
float accum0 = 0.0F;
for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}
float ma = accum0 / (float) iparam[0];float accum1 = 0.0F;
for (int i1 = i - iparam[0] + 1; i1 <= i; i1++) { float x = i_get(candles, i1).close - ma; accum1 = accum1 + x * x;}
float sigma = sqrt(accum1 / (float) iparam[0]);
i_put(series[0], i + 0, ma + fparam[1] * sigma);i_put(series[1], i + 0, ma + fparam[0] * sigma);i_put(series[2], i + 0, ma);i_put(series[3], i + 0, ma - fparam[0] * sigma);i_put(series[4], i + 0, ma - fparam[1] * sigma);
移動平均のコードが展開される
bol (n,a,b) i = let_ "ma" (MA.ma n i) $ \ma -> let_ "sigma" (sigma_i n ma i) $ \sigma -> tup5 (ma + b*sigma, ma + a*sigma, ma, ma - a*sigma, ma - b*sigma)
移動平均の呼び出し
•別の見方:型チェック・高階関数(マクロ)等を備えたメタプログラミングライブラリ•値呼びと名前呼びを少し注意して区別する必要がある(やや欠点)
適用可能性
• 移動平均
• 指数平滑移動平均
• 一目均衡表
• ボリンジャーバンド
• パラボリック
• エンベロープ
• RSI
• ストキャスティクス
• DMI
• RCI
• モメンタム
• ROC
• MACD
• %Rオシレーター17
本手法により14種のテクニカル分析に対応
実装コストの減少
• 開発:15人日 ... Haskell/Tek C言語版 (iOS向け)
7人日 ... テクニカル分析1人日 ... Haskell/Tek Java版 (Android向け)
• メンテナンスコストも実感として下がっている
18
総コード行数
• Haskell 1758行(うちテクニカル分析777行, C生成部 981行)
➡生成されたC言語コード 2077行
➡生成されたJavaコード 2257行
19
Haskell/Tekの実装
なぜHaskellか1. オープンソースのパーザ/プリンタが沢山あった
• C, Java, JavaScript, ... そこそこ枯れたライブラリが多数
• 代数的データ型のおかげで構文木操作が(JavaやCより)簡単
• 今回はLanguage.C.Quote(*1)を用いた
2. EDSL との親和性が高い
• 遅延評価、関数呼び出しの構文が「軽い」、型クラス
21
(*1) language-c-quote: http://hackage.haskell.org/package/language-c-quote
実装:Language.C.Quoteの利用
• Haskellの言語拡張により、Haskellの中にCのコード断片を記述可能に
• C言語構文木の生成が手軽にできた
22
do .. (bodyExp, bodyStmts) <- .... tell [C.BlockStm [cstm| for(int $id:counter=$f ; $id:counter<=$t ; $id:counter ++) { $items:bodyStmts $items:(makeAssigns initVars bodyExp) } |] ];
C言語コード
Haskellコード
EDSLの概要• Haskell/Tekの関数群で記述したデータが、C/Javaに変換される(Haskellの全体が、CやJavaに変換できるわけではない)
• より詳細には
23
Haskell/Tekコード
C言語プログラム
実行形式(.exeなど)
Haskellコンパイラ 実行
実行
Javaプログラム
-- テクニカル記述
ma n i = sum_close (i-(n-1)) i candles / toFloat n
-- テクニカル記述をCコードとして印字
main = printCCode ma-- main = printJavaCode ma -- Java-- main = randomRun ma -- イミディエイト実行
イミディエイト実行
EDSLの実装(案1)• EDSLの構文木を表す型を定義し、そこから変換する
• 比較的普通の方法
• Tek型(中間データ構造)を定義する必要がある
24
Tek型(EDSLの構文木型)
CLanguage型
JavaLanguage型
HaskellRunner型
printCCode
printJavaCode
randomRun
Haskell/Tek関数群
EDSLの実装(案2):
タグレス実装• Kiselyovら(*2)の方法 (こちらを採用)
• 中間データ型を介さず、型クラスによって実装する
25
(*2) Finally Tagless, Partially EvaluatedTagless Staged Interpreters for Simpler Typed Languages, Journal of Functional Programming 19(5):509-543, 2009
CLanguage型
JavaLanguage型
HaskellRunner型
Haskell/Tek関数群(型クラス Lang l)
gen
gen
gen
(genをターゲットの型について多重定義)
その他の関数型DSL
参考:DSLと関数型言語(1)
LexiFi• LexiFi(*3)
• 関数プログラミングを用いて金融派生商品の契約を記述できる OCaml 内 DSL。
• デリバティブのリスク評価と契約執行を1つのDSL
記述から導出
27 LexiFi社Webページ(フランス)(*3)http://www.lexifi.com/
参考:DSLと関数型言語(2)
Paraiso• Paraiso (*4)
• 宇宙物理学シミュレーションのDSL記述より 多数の並列計算機へコンパイル
• CUDA+MPI, OpenMP
• C言語の似たような繰り返しが無くなり、記述が容易に→様々な最適化をラピッドに試せる
28(*4)http://paraiso-lang.org/wiki/index.php/Main_Page
まとめ
• C・Java向けのテクニカル分析コードを生成するHaskell上のDSLを開発
• 実装フェーズの効率化
• 「より書きやすく安全な」C言語マクロとしてのEDSL
29
今後の課題• よりGUIに近いコードの生成
• スクロール、日付計算、座標変換などまだまだDSL化できるはず
• 証明付きDSL
• 数列計算の正しさをCoqで証明する
• コード生成部にバグが無ければ、完全にバグがないコードを生成可能
30