VBAHaskell ユーティリティを使ってみる
先日の記事VBAHaskell ユーティリティ群で書いたユーリティティモジュールは、その後いろいろ関数を追加し、記事にも反映した。
サンプルとして、このところ動きの激しい株価データにごく簡単なデータ処理をしてみよう。
まずYahoo!ファイナンスのページから、日経平均株価の時系列データをExcelシートにコピペする。
このデータをもとに、前日比で大きく動いたレコードを抽出し、前日比の列を追加して表示する。
まずは配列変数へデータを取り込む。セル範囲を指定してValueプロパティを取得すれば勝手に配列になってくれる。
' データ取り込み m = [O2:S41].Value
次に前日比を計算する。対象は「終値」の列だ。直近の日付が上になっているので、単に引き算すれば(当日値 - 前日値)となる。
行番号や列番号を指定するとき、配列のLBoundのことを気にするのは煩わしい。selectCol_b は、実際の LBound に関わりなくゼロ始まりと解釈して列を抽出する関数であり、これを使って「終値」の列番号を「4」と指定する。
adjacent_op はユーティリティ群に追加した関数で、隣り合う2項に対する演算を行うものだ。これにマイナス関数「p_minus」を渡して差分が計算できる。(当然要素数はひとつ少なくなる。)
' 前日比の列 dif = adjacent_op(p_minus, selectCol_b(m,4))
前日比の絶対値が400円を超えるものにフラグを立てよう。今作った dif 配列を「絶対値が400超」という関数でマップしてやればいい。
下の p_greater(p_abs, 400) という関数オブジェクトは見てすぐ理解できるだろう。(dumpFun 関数を使えばその構造を表示できる。)
mapF に これと dif を渡してやればフラグが作れる。
' フラグの列 : Abs(***) > 400 であれば 1、そうでなければ 0 a = mapF(p_greater(p_abs, 400), dif)
最後にやるのは、もとのデータの横に前日比の列を追加してフラグの立った行だけを抽出することだ。
前日比の列は元の行数より要素が1つ少ないので、ダミーとして"NA"という文字列を最後にくっつける。これには1次元配列(またはスカラー)を結合する関数 catV を使う。
2次元配列の列方向への結合関数 catC(CはcolumnのC)と行方向のフィルタリング関数 filterR 関数を組み合わせれば目的のものができる。
printM filterR(catC(m, catV(dif, "NA")), a) 2016/01/29 17155.06 17638.93 16767.09 17518.3 476.849999999999 2016/01/27 16949.19 17242.27 16947.95 17163.92 455.019999999997 2016/01/26 16833.13 16839.52 16652.26 16708.9 -402.009999999998 2016/01/22 16336.72 16993.96 16332.45 16958.53 941.269999999999 2016/01/20 17030.28 17031.32 16387.61 16416.19 -632.18 2016/01/14 17384.93 17393.83 16944.41 17240.95 -474.68 2016/01/13 17449.12 17717.75 17414.55 17715.63 496.670000000002 2016/01/12 17470.93 17546.57 17184.78 17218.96 -479 2016/01/07 18139.77 18172.04 17767.34 17767.34 -423.98 2016/01/04 18818.58 18951.12 18394.43 18450.98 -582.73 2015/12/16 18868.2 19054.89 18859.11 19049.91 484.009999999998 2015/12/04 19616.52 19660.9 19444.54 19504.48 -435.420000000002
浮動小数の誤差が出てカッコ悪いので、フォーマットを整えよう。
' 配列 dif を Format(, "0,00") でマップしておく printM filterR(catC(m, catV(mapF(p_format(, "0.00"),dif), "NA")), a) 2016/01/29 17155.06 17638.93 16767.09 17518.3 476.85 2016/01/27 16949.19 17242.27 16947.95 17163.92 455.02 2016/01/26 16833.13 16839.52 16652.26 16708.9 -402.01 2016/01/22 16336.72 16993.96 16332.45 16958.53 941.27 2016/01/20 17030.28 17031.32 16387.61 16416.19 -632.18 2016/01/14 17384.93 17393.83 16944.41 17240.95 -474.68 2016/01/13 17449.12 17717.75 17414.55 17715.63 496.67 2016/01/12 17470.93 17546.57 17184.78 17218.96 -479.00 2016/01/07 18139.77 18172.04 17767.34 17767.34 -423.98 2016/01/04 18818.58 18951.12 18394.43 18450.98 -582.73 2015/12/16 18868.2 19054.89 18859.11 19049.91 484.01 2015/12/04 19616.52 19660.9 19444.54 19504.48 -435.42
まとめると、4行でできた。
m = [O2:S41].Value dif = adjacent_op(p_minus, selectCol_b(m,4)) a = mapF(p_greater(p_abs, 400), dif) printM filterR(catC(m, catV(mapF(p_format(, "0.00"),dif), "NA")), a)
(1/31 追記)
フォーマットを整えるためのもう少し汎用的な方法を追加した。
上の出力は小数点以下1桁の数字と2桁の数字が混在している。2桁に揃えるために、関数を列毎に適用させる columnWise_change とフォーマット指定を文字列で与える splitStr2Funs を組み合わせて以下のように書ける。(最新版の misc_utility が必要)
m = [O2:S41].Value dif = adjacent_op(p_minus, selectCol_b(m,-1)) a = mapF(p_greater(p_abs, 400), dif) m2 = filterR(catC(m, catV(dif, "NA")), a) columnWise_change m2, splitStr2Funs("\\s0.00\s0.00\s0.00\s0.00\s0.00", p_str2ConvertFun, "\") printM m2 2016/01/29 17155.06 17638.93 16767.09 17518.30 476.85 2016/01/27 16949.19 17242.27 16947.95 17163.92 455.02 2016/01/26 16833.13 16839.52 16652.26 16708.90 -402.01 2016/01/22 16336.72 16993.96 16332.45 16958.53 941.27 2016/01/20 17030.28 17031.32 16387.61 16416.19 -632.18 2016/01/14 17384.93 17393.83 16944.41 17240.95 -474.68 2016/01/13 17449.12 17717.75 17414.55 17715.63 496.67 2016/01/12 17470.93 17546.57 17184.78 17218.96 -479.00 2016/01/07 18139.77 18172.04 17767.34 17767.34 -423.98 2016/01/04 18818.58 18951.12 18394.43 18450.98 -582.73 2015/12/16 18868.20 19054.89 18859.11 19049.91 484.01 2015/12/04 19616.52 19660.90 19444.54 19504.48 -435.42
columnWise_change の第1引数は対象配列、第2引数は列ごとに適用する変換関数の配列だ。
splitStr2Funs は "\s0.00\s0.00\s0.00\s0.00\s0.00" のような文字列を区切り文字(ここでは第3引数の'\')で分けて第2引数に渡す。
第2引数の str2ConvertFun は個々の文字列("s0.00" など)を変換関数に変換する。例えば"s0.0000" だったら p_format(, "0.0000") になる。
長いので実際に使うときはまとめて1関数にしてしまえばいい。