わたねこコーリング

野良プログラマ発、日々のアウトプット

「ジブリの呪い」を検証してみた

先日こんなツイート↓

で知ったのですが、投資家筋では有名な「ジブリの呪い」てなモノがあるそうですな。この類の事象をアノマリーと言うらしく、昨年読んだこの本(↓)でも各種アノマリーの検証例が載っており興味深かったです。

ロボット運用のプロが分析してわかった 最強の株式投資法

ロボット運用のプロが分析してわかった 最強の株式投資法

そこで、これに倣い「ジブリの呪い」を自分なりに分析してみようと思います。放映日を挟んで日経平均を信用売買して下落分の利益を狙うという方針で、何処を売買日に選んだら最も利益が見込めるのかをプログラムで集計してみます。仕様はざっくりと

  • 上記ツイート中にあるページに掲載されている放映日で、2000年以降を対象に(それ以前の日経平均データ持ってないので)。
  • 売付日は放映日とその前の営業日5日間を、買付日は放映日とその後の営業日5日間を対象に。
  • 上記売買の全組み合わせ毎にプロフィット・ファクター(総利益÷総損失、以下PF)を集計し、最大となる売買日を探す。
  • 売買は終値で。手数料とかは無視。

てな感じで。以下、得られた結果から抜粋した PF ベスト3です。

売付日 買付日 PF 勝率
0 3 1.39 53.1%
0 2 1.38 49.6%
-1 3 1.26 50.4%

つまり放映日に空売りして、その3営業日後に買い戻すのが最も良さそうです。が、PF・勝率いずれもこの数字では殆ど有意性を感じられないですね… いちおう Excel で結果の可視化もしてみます。

f:id:mariyudu:20170209214633p:plain


さて、よく調べるとこの「ジブリの呪い」、米雇用統計発表と重なると魔力を発するらしいです。という訳で、放映日を第一金曜日のものに絞って(26件ありました)再計算してみると…

売付日 買付日 PF 勝率
0 3 2.15 61.5%
-1 3 2.05 53.8%
-3 3 1.88 61.5%

f:id:mariyudu:20170209214852p:plain

ほほう、なんだかそれっぽい結果になりました。放映日か直前あたりで売り・3営業日後あたりで買うのが好成績という傾向は共通してるみたい。これならちょっと試してみようかな、という気になってしまいますw 蛇足ですが、本記事は過去のデータを集計しただけのものであり、今後を予測するものではありません。投資はあくまで自己判断・自己責任で!

PHP Trader 関数を使ってみる - ボリンジャーバンドの巻

前回の続きで、今回は trader_bbands 関数ボリンジャーバンドを算出してみます。ボリンジャーバンドは、移動平均標準偏差を重ね合わせただけの指標ですが、直観的だしトレンドやボラティリティがひと目で分かって便利なので、自分もよく使っています。

trader_bbands のコーリングシーケンスは、

trader_bbands(<株価が格納された1次元の配列>, <移動平均日数>, <+σの係数>, <-σの係数>, <移動平均の種類>)

です。株式相場では通常、25日の単純移動平均を元に計算するようです。返り値は +Nσ値・移動平均・-Nσ値が格納された2次元配列です。

それでは、前回同様、k-db.com さんから頂いた今年の日経平均日足データを元にボリンジャーバンドを算出して表示するというシナリオのサンプルプログラムです。

<?php
// CSV ファイルから株価データを読み込んで、配列に格納
$data = file('indices_I101_1d_2016.csv', FILE_IGNORE_NEW_LINES);
//見出し行を省く
unset($data[0]);
// 各行のカンマ区切りを配列に分割
$data = array_map(function($item){ return explode(',', $item); }, $data);
// 日付昇順でソート
usort($data, function($a, $b){ return ($a[0] < $b[0]) ? -1 : 1; });
// 終値だけ収集(兼実数変換)
$closePrices = array_map(function($item){ return +$item[4]; }, $data);
// 25日単純移動平均に基づくボリンジャーバンドを計算
$bbands = trader_bbands($closePrices, 25, 1, 1, TRADER_MA_TYPE_SMA);
// CSV 形式で整形・出力
echo "日付,株価,25日SMA,+1σ,-1σ\n";
foreach ($data as $n => $data) {
	echo implode(",", [
		$data[0],
		$closePrices[$n],
		@$bbands[1][$n],
		@$bbands[0][$n],
		@$bbands[2][$n],
	]) . "\n";
}

実行結果ははい、こんな感じ↓。

日付,株価,,25日SMA,+1σ,-1σ
2016-01-04,18450.98,,,
2016-01-05,18374,,,
2016-01-06,18191.32,,,
(中略)
2016-02-03,17191.25,,,
2016-02-04,17044.99,,,
2016-02-05,16819.59,,,
2016-02-08,17004.3,17296.788,17863.05,16730.525
2016-02-09,16085.44,17202.166,17765.29,16639.042
2016-02-10,15713.39,17095.742,17678.419,16513.065
(後略)

PHP Trader 関数を使ってみる - 移動平均の巻

明日からの週明け市場は日経平均1万7千円台回復か? 等と今日の産経ニュースに載ってましたが、はてさてどうなりますか。という訳でご無沙汰しております、細々とシストレなぞもすなる野良プログラマ Mariyudu です。

プログラマさんがシストレする時にどんな言語が便利なのかは知りませんが、個人的には使い慣れた PHP を使ってます。んで、PHP には株式や FX 等のテクニカル分析用の Technical Analysis for Traders という数学関数群が人知れず用意されてまして、これはどうやら TA-Lib というライブラリをラップしたもののようです。残念なことに、php.net のマニュアルはあまり親切とは言えないし、ユーザも少ないのか情報に乏しいようなので、当方が試行錯誤して使ってみた経過なぞをアウトプットしてみます。

まずインストールから。Trader 関数は PECL モジュール化されてるので、sudo pecl install trader でインスコできるでしょう(たぶん)。CentOS ユーザには Remi リポジトリに用意されているので、sudo yum --enablerepo=remi install php-pecl-trader でも OK(当方はこちら)。

今回は手始めに移動平均を算出する関数、trader_ma を使ってみます。コーリングシーケンスは

trader_ma(<株価が格納された1次元の配列>, <集計日数>, <移動平均の種類>)

となります。第三パラメータには TRADER_MA_TYPE_SMA (単純移動平均)、TRADER_MA_TYPE_EMA (指数平滑移動平均)、TRADER_MA_TYPE_WMA (加重移動平均線)等の多種が用意されています。正直、単純移動平均なら自分で書いた方が早いくらいですが、EMA や WMA はそれなりの計算手順を踏むので一発で計算できるこの関数は便利かも。返り値は、第一パラメータの配列に応じるかたちで移動平均値が格納された配列です。例えば5日移動平均だと、最低5日ぶんの直近株価データが必要なので、返り値配列のインデックス[0]〜[3]には何もセットされず、[4]から計算結果がセットされている、という感じ。

以下、サンプルプログラムです。各種株価データを提供されている、k-db.com さんの所から今年の日経平均日足データを入手して、それを元に移動平均を算出して表示するというシナリオです。

<?php
// 入手した CSV ファイルから株価データを読み込んで、配列に格納
$data = file('indices_I101_1d_2016.csv', FILE_IGNORE_NEW_LINES);
//見出し行を省く
unset($data[0]);
// 各行のカンマ区切りを配列に分割
$data = array_map(function($item){ return explode(',', $item); }, $data);
// 日付昇順でソート
usort($data, function($a, $b){ return ($a[0] < $b[0]) ? -1 : 1; });
// trader_ma の入力用に、終値だけ収集(要実数変換)
$closePrices = array_map(function($item){ return +$item[4]; }, $data);
// 5日・25日・75日の指数平滑移動平均を計算
$emas = [5 => [], 25 => [], 75 => []];
foreach ($emas as $d => &$ema) {
	$ema = trader_ma($closePrices, $d, TRADER_MA_TYPE_EMA);
}
// 出力
echo "日付,株価,5日EMA,25日EMA,75日EMA\n";
foreach ($data as $n => $data) {
	echo implode(",", [
		$data[0],
		$closePrices[$n],
		@$emas[5][$n],
		@$emas[25][$n],
		@$emas[75][$n],
	]) . "\n";
}

これを実行した結果はこんな感じ↓。

日付,株価,5日EMA,25日EMA,75日EMA
2016-01-04,18450.98,,,
2016-01-05,18374,,,
2016-01-06,18191.32,,,
2016-01-07,17767.34,,,
2016-01-08,17697.96,18096.32,,
2016-01-12,17218.96,17803.867,,
(中略)
2016-08-29,16737.49,16579.888,16517.979,16433.468
2016-08-30,16725.36,16628.379,16533.931,16441.15
2016-08-31,16887.4,16714.719,16561.121,16452.893
2016-09-01,16926.84,16785.426,16589.253,16465.365
2016-09-02,16925.68,16832.177,16615.132,16477.479

実はこれ、巷の株情報サイトに載っている値とはちょっと違っています。指数平滑移動平均は 𝑓(前日の計算結果, 当日株価) という計算式なので、理論上は過去全ての株価データを与えてやらないと正しい計算値にならないことになります。当方であれこれした所では10年分くらいのデータがあればそれ程大きな差異は出ないようですが。

ということで、また折を見てボリンジャーバンドMACD 等、他の指数計算関数も紹介してみようと思います。

Nexus7 を Factory Image で初期化する

3年程使っている Nexus7 で、Lollipop にアプデした頃からおかしな現象が見られるようになりました。日本語の特定の文字が表示されなかったり線か網がかかったような表示になるというもの。調べたら、ああそうそう、こんな感じ(↓)。

detail.chiebukuro.yahoo.co.jp

「設定」からリセットする方法だと、この不具合は解消できないようで、上記質問への回答にある「Factory Image の焼き直し」ってのを試してみることに。ネットで調べながら進めていったのですが、参考にした記事は若干古い(3〜4年前くらい)ものが多く、今では事情が違う部分もあるようなので、今回の手順を備忘録として書き残しておきます。尚、当方環境は Nexus7 (Nakasi) + Mac OSX 10.9.5 なので、異なる環境の方は適宜読み替えられたし。

手順はおおまかに以下のようになります。

  1. 手持ちのパソコンにて、Google Developers から自分の機種に合った Factory Image ファイルをダウンロードして解凍する。
  2. Factory Image の書き換えには fastboot というコマンドが必要なので、これも入手してパソコンにインストールしておく。
  3. Nexus のブートローダを起動して、パソコンに USB 接続する。
  4. パソコンにて Factory Image に同梱されていたシェルスクリプトを実行して、ブートイメージを書き換える。

まず(1)ですが、 Factory Image は機種毎に異なるものが用意されているので、自分の機種を知る必要があります。Nexus の「設定」で確認すると「Model : ME370T」とあったのですが、これは Nakasi というコードネームに該当するみたい。という訳でここから MD5 チェックサム 32624479e2f24d07fd04a2099a163604 の 5.1.1 イメージをゲット。ダブルクリックして解凍すると、中に flash-all.sh というテキストファイルがあって、これがイメージファイル書き換えのシェルスクリプトとのこと。参考にした記事にはスクリプト最終行にある

fastboot -w update image-nakasi-lmy47v.zip 

から -w を削除しておけってのがありました。どういうことかと調べたら -w はユーザデータとキャッシュファイルを消去するオプションらしく、要は自分のデータ類を残しておきたかったら -w 無しがいいよ、ということでしょう。ご尤もなので従ってみます。

次いで(2)ですが、ネットの参考記事には Android SDKインスコしろってのもあったんですが、やってみると SDK には fastboot が含まれていないようだったので、ここから入手しました。ダウンロードに同梱されている ADB-Install-Mac.sh を下記のようにターミナルから実行します。

$ sh ADB-Install-Mac.sh 
This will install ADB and Fastboot on your computer.
Root Permissions required. Please type your password.
Password: (←ここで管理者パスワードを入力)
Changed directory to /Users/yourname/Downloads/Android
Moving ADB
ADB Moved to /usr/bin/adb
moving Fastboot
Fastboot moved to /usr/bin/fastboot
You may now run Android Debug Bridge and Fastboot commands
Have a nice day.

さて、パソコン側の用意が出来たので(3)を。Nexus の電源とボリュームダウンキーを長押しして再起動し、こんな画面が表示されれば OK。
f:id:mariyudu:20150907134030p:plain

USB ケーブルで Nexus とパソコンと接続したら、いよいよ(4)のブートイメージ書き換え。ターミナルから実行した様子です(↓)。

$ sh flash-all.sh 
...
(bootloader) erasing userdata...
(bootloader) erasing userdata done
(bootloader) erasing cache...
(bootloader) erasing cache done
(bootloader) unlocking...
(bootloader) Bootloader is unlocked now.
OKAY [ 28.433s]
finished. total time: 28.433s
erasing 'boot'...
OKAY [  0.034s]
finished. total time: 0.036s
erasing 'cache'...
OKAY [  0.089s]
finished. total time: 0.089s
erasing 'recovery'...
OKAY [  0.033s]
finished. total time: 0.033s
erasing 'system'...
OKAY [  0.703s]
finished. total time: 0.703s
erasing 'userdata'...
OKAY [  4.964s]
finished. total time: 4.965s
sending 'bootloader' (2100 KB)...
OKAY [  0.303s]
writing 'bootloader'...
OKAY [  1.220s]
finished. total time: 1.523s
rebooting into bootloader...
OKAY [  0.019s]
finished. total time: 0.020s
archive does not contain 'boot.sig'
archive does not contain 'recovery.sig'
archive does not contain 'system.sig'
--------------------------------------------
Bootloader Version...: 4.23
Baseband Version.....: N/A
Serial Number........: (註:ひみつですw)
--------------------------------------------
checking product...
OKAY [  0.040s]
checking version-bootloader...
OKAY [  0.027s]
sending 'boot' (5184 KB)...
OKAY [  0.711s]
writing 'boot'...
OKAY [  0.222s]
sending 'recovery' (5738 KB)...
OKAY [  0.773s]
writing 'recovery'...
OKAY [  0.237s]
sending 'system' (649455 KB)...
OKAY [ 85.181s]
writing 'system'...
OKAY [ 36.497s]
rebooting...

finished. total time: 123.835s

実行に2分くらいかかりました。これが終わると Nexus が再起動を2回ほど繰り返して(2回目の起動時間が長かった…)、めでたく Lollipop が起動されました。不具合もちゃんと解消されたようです、ふう。

しかしこの作業、一般ユーザにはちょっとハードルが高いですよねぇ。GUI 上で実行可能な初期化ツールとか出してくれないのかしら > Google さん

D3.js でローソク足チャート描くなら TechanJS がイイ!(かもしんない)

最近、データ分析の真似事をしたくなって、どうせやるなら実益も目指せる株取引を対象に、とごにょごにょ始めたりしています。そこで必要になるのが、データの「見える化」。ローソク足チャートをベースに、諸処の分析結果を作画して「ほほー」等と言ってみたい訳ですが、まずはツール選びに一苦労。jqPlot の様に高レベルに実装されたプロダクトは使うのも簡単なのですが、そのぶんちょっとしたカスタマイズにも苦労するようです。

他の手段を調べてみると、データ分析のビジュアライズには D3.js がイイという話。けど、D3.js ってのは「グラフを簡単に描けるライブラリ」というよりはデータ分析の視覚化フレームワーク的な、非常に広範囲な利用を想定した「低レベル」な実装なんですね。なので、グラフひとつ描くにもそれなりの学習が要るみたい…「努力すんのは嫌いだしめんどっちーし楽して身につく方法はないもんかな」と調べていたら、TechanJS という D3.js ベースの財務グラフ作画ライブラリを見つけました。

開発元提供のサンプルを見て頂ければ分かるように、ローソク足チャートは序の口で、MACD・RSI・トレンド線・一目均衡表など、テクニカル分析を齧ると出てくる様々な手法の作図が用意されているようです。しかも、このライブラリは作図だけでなくデータ分析の機能も併せ持っているらしい! とっても凄そうなのですが、先ずはシンプルにローソク足チャートに移動平均線を重ね描きするという初歩の初歩にチャレンジしてみました。で、出来た図がこんな感じ(↓)。

f:id:mariyudu:20150830212210p:plain

直近100日の日経平均日足と、5日・25日・75日の移動平均線です。TechanJS はドキュメントが殆ど無いので、サンプルのコードを参考に必要に応じて削ったり足したりしながらのプログラミングでした。作画には D3.js 流儀のステップが必要で関数一発という訳には行きませんが、データをポンと渡すだけで軸の目盛を実用的に調整してくれるところが有り難いです。プログラムは JSFiddle に上げておきましたよ、と(↓)。

jsfiddle.net

なにぶん、D3.js そのものに未だ不慣れなので自由自在に使えるようになるまでは長い道のりになりそうですが、一攫千金をニンジンにがんばってみようかと。

MuseScore ver.2 のギタータブ譜機能を試してみた

全国の撥弦楽器愛好者に朗報です。オープンソース&無料の楽譜作成アプリ、MuseScore (ミューズスコア)のバージョン2が先ごろの3月にリリースされて、かねてから予告されていた待望のタブ譜機能が正式に実装されました! ギターやウクレレ、その他を多少嗜む身としては本当にグッドニュースです。音楽的な表現に慣れ親しむという意味で五線譜の楽譜を蔑ろにすべきではないと思いつつも、アコースティック・ギターなんかは変則的なチューニングを用いることが多く、どうしてもタブ譜が欲しい時があるのですよね…

という訳で、早速試してみることにしました。お題は、戦前ブルーズの巨人、ブラインド・ブレイクの「ポリス・ドッグ・ブルース」のイントロを、五線譜とタブの二段構成で作成してみるというものです。

スコア書類の作成

先ず五線譜とタブの二段形式のスコアを新規作成します。メニューから[ファイル]>[新規作成…]を選択して、表示されたダイアログにて曲名や作曲者名等を適宜入力して、ボタン[次へ]をクリック(↓)。
f:id:mariyudu:20150601202704p:plain

テンプレートの一覧から「Solo」というグループにある「Guitar + Tablature」をクリックして選択(↓)。
f:id:mariyudu:20150601202757p:plain

「ポリス・ドッグ・ブルース」はキーが D (ニ長調)なので、調号からシャープふたつを選択して、ボタン[次へ]をクリック(↓)。
f:id:mariyudu:20150601202836p:plain

拍子・小節数はデフォルトのままで、ボタン[完了]をクリック(↓)。
f:id:mariyudu:20150601202847p:plain

はい、五線譜とタブの二段スコアのひな形ができました(↓)。
f:id:mariyudu:20150601202855p:plain

チューニングの変更

この曲のギターはレギュラーチューニングではなくオープン D という、6弦から順に DADF#AD に合わせる変則チューニングなので、その設定が必要になります。タブ譜の上でマウスを右クリックして、コンテクストメニューから[譜表のプロパティ]を選択します(↓)。
f:id:mariyudu:20150601202910p:plain

このダイアログの左下あたりにあるボタン[文字列データの編集…]をクリックすると、ギターの調弦が表示されたサブダイアログが表示されます(※ヘンな表記ですが多分「弦(Strings)」が「文字列」に誤訳されているのでしょう)。この値(6弦なら E2)をダブルクリック → 表示された音符選択ダイアログで変更する値(6弦なら D2)をダブルクリック、という手順で各弦を必要に応じて調弦を変更します(↓)。
f:id:mariyudu:20150601202924p:plain

はい、この通り DADF#AD へのチューニング設定が完了(↓)。
f:id:mariyudu:20150601203027p:plain

あと、チューニングに合わせて「使用可能な音高の範囲」も設定しておいたほうが良さげ(音符入力の際にこの範囲を逸脱すると赤くエラー表示されてしまうので)。5フレットでのハーモニクス等考えると、D2 〜 D6 とかにしておけば良いかと(↓)。
f:id:mariyudu:20150601203037p:plain

音符の入力

あとは音符を入力していくだけです。タブ譜の先頭をクリックして選択状態にしておいて、メニューバーから音符入力ボタンをクリックするか、n キーを押して、音符入力モードに入ります(↓)。
f:id:mariyudu:20150601203049p:plain

音符(というかタブ譜なのでポジション番号)の入力位置が青く表示されますので、音符の種類(4分,8分etc)をメニューバーから選択してポジション番号をキー入力します。カーソルキーの←・→で左右位置が、↑・↓で弦の移動ができるので、これらの繰り返しでどんどん音符を入力していきましょー(↓)。
f:id:mariyudu:20150601203147p:plain

そんな感じで黙々と入力していったら、こんな感じでイントロ部分が出来上がりました(↓)。
f:id:mariyudu:20150601203505p:plain

…と、必要最小限ですがタブ譜の作成手順でした。説明した以外でも、繰り返し記号やタイ・スラー等はどうやって入力するの? 的なギモンがあると思いますが、その辺は通常の楽譜機能に属する事柄なので、純正のハンドブックから学んで頂ければと。自分でも MuseScore は初心者レベルなので、これからどんどん使い倒して、獲得したノウハウは共有して行こうと思ってます。そんな訳で、今日はここまで!

Redis で FIFO バッファを作って PHP から使う

昨今じゃ当たり前になった NoSQL ってやつですが、自分はどうも使う機会が無かったというか、フツーに RDB 使ったほうが目的に叶うケースが多かったので memcached でさえ殆ど手を触れずに今日まで来ました。それがやっと先ごろ、NoSQL なシチュエーションが発生!という訳で、人生初 NoSQL の作業メモです。

要件は、各所から発生するデータをそのまま RDB に書き込むと諸事情で色々と嬉しくないので、いったんバッファに溜めておいて専用のデータストア用プログラム経由で逐次 RDB に格納するというものです。古いものから順に読み出す必要があるので、所謂 FIFO (First In First Out) バッファですな。memcached は万一のデータ消失が怖いので、最近評判が良いらしい Redis を採用。

まずは環境づくりから。当方の AWS EC2 な LAMP サーバにて、Redis を PHP から使えるようにします。Redis 関係は EPEL リポジトリにしか無いようなので、それを指定して yumインスコします。

% sudo yum --enablerepo=epel -y install redis

Redis サーバを起動して、ブート時の設定も忘れずに。

% sudo service redis start
% sudo chkconfig redis on

で、動作確認…

$ redis-cli
redis 127.0.0.1:6379> info
redis_version:2.4.10
(省略)
redis 127.0.0.1:6379> exit

よし、OK。

PHP の Redis 用モジュールのほうも同様にインスコ

% sudo yum --enablerepo=epel -y install php-pecl-redis
% sudo service httpd reload

以上で環境が整ったので、プログラムを書きます。Redis は色々なデータ型が用意されていますが、FIFO バッファは Lists 型を使って実現できるとここにあったので、これに倣って LPUSH で書き込み、RPOP で読み出すことにします。RDB 用のデータを Redis に書き込む側はこんな感じ。

$data = array(':name' => $name, ':email' => $email, ':created' => date('Y-m-d H:i:s')); //テーブル列名 => 値、な1レコードぶんのデータ
$redis = new Redis();
$redis->connect('localhost');
$redis->lPush('mykey', json_encode($data)); //JSON に変換して Redis に保存

Redis → RDB の処理側はこんな感じ。

$redis = new Redis();
$redis->connect('localhost');
$pdo = new PDO('mysql:host=localhost;dbname=my_db', 'login_name', 'login_pw');
$stmt = $pdo->prepare('INSERT INTO my_table (name, email, created) VALUES (:name, :email, :created)');
while ($data = $redis->rPop('mykey')) { //有るだけ読み出しては RDB に追加
	$data = json_decode($data, true);
	$stmt->execute($data);
}

とまぁ、こんな具合です。実にシンプルな利用ケースなので一寸物足りない気もw 他のデータ型も使ってみたいなー。