本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

カブロボ テクニカル分析と、そのアルゴリズムの紹介: その3 月齢

木村 桂 (kimuc@jp.ibm.com), ソフトウェア事業, IBM 
木村 桂: 日本IBM ソフトウェア事業

概要: 本連載も3回目になりました。今回も含めて、今までに紹介してきた RCI や標準偏差のアルゴリズムでは注文の翌日に決済をしています。つまり1営業日しか保有していません。このように、ごく短期間に大きく値が動くことを期待したアルゴリズムなのですが、本来 RCI や標準偏差は「そろそろ上がってもいい頃かな?」という判断をする考え方なので、もっと中長期的な視野で売買する時に使う手法といえます。

日付:  2006年 2月 24日
レベル:  上級
アクティビティー: 1433 ビュー
お気軽にご意見・ご感想をお寄せください: 


生物学的投資(?)

連載の三回目である今回は少し趣を変えてみます。具体的にはより短期売買向きな考え方に基づく方法を紹介してみます。また、今までは RCI や標準偏差といった、数学的な統計を元に売買判断をするテクニカル分析を紹介してきましたが、今回は数学からも少し離れ、どちらかというと生物学的(?)な分析をしてみます。


人はみな狼男? という仮説

今回は月齢を売買判断に取り入れてみます。月齢というと堅苦しく聞こえるかもしれませんが、要するに満月だの、新月だの、三日月だのというアレです。結論を先に言うと、今回は「新月および満月の日には投資をしてみる」というアルゴリズムを実装してみます。

多くの人は「なんで投資と月齢が関係あるの?」と不思議に思っているかもしれません。 ごもっともです。今まで紹介してきたケースと異なり、この方法には数学的な根拠はありません。ただその一方で「全く関係ない」とは言い切れない、とも思っています。満月の日は殺人事件や交通事故は他の日と比べて無視できないほど高くなる、という統計があります(参考文献(1))。また負傷した人の血液も他の人比べて止まりにくくなっているようです。生体的にも潮の満ち干きが存在し、多かれ少なかれ人は満月の日には狼男のように興奮しやすくなっているのかもしれません。ということは、株式相場においても満月の前後に人は興奮しやすくなり、狼狽的な判断をしやすくなってしまうのではないでしょうか?

こんな「いやいや、まさか何言ってるの?」的な推測を大胆にも仮説化して、「だったらその流れに載って売買してみよう」というのが今回の内容になります。


月齢を使った売買アルゴリズム

ところで、月齢について簡単に紹介しておきます。月齢は0(ゼロ)から約29.53の間で少しずつ大きくなり、29.53 になるともう一度ゼロに戻ります。

新月を月齢ゼロとし、三日月→半月と少しずつ大きくなりながら月齢も加算されてゆき、満月になると月齢は約 14.765 になります。ここからは月が少しずつ小さくなりながら月齢は増えてゆき、次の新月の時に月齢は約 29.53 になります。ここで再度月齢をゼロにリセットして、また月とともに少しずつ増えていきます。これが月齢です。月齢については計算アルゴリズムが確立しているため、それを用います。

本来、満月の日(あるいは満月に近い日)にだけ、直前に最も大きく動いた銘柄を(その興奮が冷めないうちに)売買する、というアルゴリズムにしたかったのですが、カブロボは1ヶ月に2度以上の売買を行うことが運用ルールになっています。満月は月に1回程度しかないため、このアルゴリズムではルール上不充分です。したがって満月と新月、両方のタイミングを売買ポイントとします。

以上の点を考慮して、今回は以下のようなアルゴリズムを株ロボット上に実装することにします:

  1. まず前営業日に注文がなされていた場合は、無条件にその決済注文を行う(つまり注文の翌日に決済する)。
  2. 各銘柄ごとに株価のサンプルとして最近2日間の終値を取得し、その銘柄の直近の上昇率(下落率)を求める。
  3. 全銘柄でこれらの計算を行った値を比較し、直前に最も上昇(下落)した銘柄を1つ決定する。
  4. 当日の月齢を求めて、満月か新月が迫っていることが分かった場合は、3 で決定した銘柄を1売買単位だけ注文する。直前に上昇していた場合は買い、下落していた場合は売り注文とする。

1. の部分は過去2回の紹介記事のものと全く同じです。 また、本来は先に月齢を求めておいて、売買該当日だった場合だけ各銘柄の上昇・下落率を計算するアルゴリズムの方が効率はいいのですが、月齢を気にしなかった場合はどの銘柄の上昇・下落率が大きかったのかを確認したい場合を考慮して、今回のアルゴリズムとしました。


Java のプログラムで実装

ここまでに決めたアルゴリズムを実際の Java プログラムで記述してみたのが、以下のソースコードになります。ここでは run メソッドの中身と、月齢を求めるためのプライベート関数の内容、そしてスタティック変数一覧を紹介しています:

static double lastma = -1.0;        // 前営業日の月齢を一時記憶するための変数
static int idx_sb = 0;              // 前日に行った売買の種類

public void run( InvestmentAgent arg0 ) {
	// TODO Auto-generated method stub
	Calendar cdt = Time.getTime();	    // 日付を取得
	double j_today = getJulian( cdt );  // 当日のユリウス通日
	double j_tomorrow = j_today + 1.0;  // 翌日のユリウス通日
    
	double ma_today = getMoonAge( j_today );       // 当日の月齢
	double ma_tomorrow = getMoonAge( j_tomorrow ); // 翌日の月齢

	Stock[] stocks = arg0.getStocks(); 			// 銘柄リストの取得
	int i, idx;
	double idx_pr, pricerate;
		
	//. ポートフォリオを取得
	InformationManager infoManager = arg0.getInformationManager();
	Portfolio portfolio = arg0.getPortfolio();
	Map holdingMap = portfolio.getHoldings();

	// 前営業日に注文した株があれば決済する
	if( holdingMap.size() > 0 ){
		//. 前営業日に注文した銘柄の情報を取得
		Iterator itr = holdingMap.values().iterator();
		Holding holding = ( Holding )itr.next();			
		int tradetype;

		// 決済なので、注文した内容が買いであれば売り、売りであれば買いの注文を行う
		if( holding.getNumber() > 0 ){
			tradetype = StockOrder.SELL;
		}else{
			tradetype = StockOrder.BUY;
		}
		
		// 決済注文
		SimpleStockOrder stockOrder = new SimpleStockOrder();
		stockOrder.setStock( holding.getStock() );		// 注文の銘柄を設定
		stockOrder.setLimitType( StockOrder.MARKET );	// 成り行き注文
		stockOrder.setTradeType( tradetype );		// 買い/売り注文を設定
		stockOrder.setQuantity( 1 );			// 注文を1単位株に設定
		arg0.order( stockOrder );			// 注文の発行
	}
	
	// 直近の2日で最も株価が変化した銘柄を探す
	for( i = 0, idx = -1, idx_sb = 0, idx_pr = 0.0; i < stocks.length; i++ ){
		// 直近の日付から2日分の銘柄指標データを取得
		List list = infoManager.getIndexInformation( stocks[i], cdt, -2 );
		IndexInformation index1 = ( IndexInformation )list.get(0); // 一つ前のデータ
		IndexInformation index2 = ( IndexInformation )list.get(1); // 直近データ
			if( index2.getClosingPrice() > index1.getClosingPrice() ){
			// 値上がり → 買いの候補
        
			// 値上がり率
			pricerate = ( ( double )index2.getClosingPrice() - index1.getClosingPrice() )
				/ index2.getClosingPrice();
			
			// 株価変動率の最も大きなものかどうかを調べる
			if( idx_pr < pricerate ){
				idx = i;
				idx_pr = pricerate;
				idx_sb = StockOrder.BUY;
			}
		}else{
			// 値下がり → 売りの候補
        
			// 値下がり率
			pricerate = ( ( double )index1.getClosingPrice() - index2.getClosingPrice() )
				/ index2.getClosingPrice();
				// 株価変動率の最も大きなものかどうかを調べる
			if( idx_pr < pricerate ){
				idx = i;
				idx_pr = pricerate;
				idx_sb = StockOrder.SELL;
			}
		}
	}
    
	// 売買を行うのは新月か満月の夜のみに限定する
	if( ( lastma > 27.0 && ma_today <= 3.0 ) || ( lastma < 14.765 && 14.765 <= ma_today ) ){
		//         新月                  or                  満月
			SimpleStockOrder stockOrder = new SimpleStockOrder();
		stockOrder.setStock( stocks[idx] );		// 注文銘柄を設定
		stockOrder.setTradeType( idx_sb );		// 買い/売り注文を設定
		stockOrder.setQuantity( 1 );			// 1単位
		arg0.order( stockOrder );			// 注文の発行
	}
    
	lastma = ma_today;
}
	
// 月齢計算
//	新月の月齢: 0.0
//	満月の月齢: 14.0 - 15.6
public double getMoonAge( double julian ){
	double newmoon = getNewMoon( julian );
		return ( julian - newmoon );
}

// 直前の新月日の計算
public double getNewMoon( double j ){
	double k = Math.floor( ( j - 2451550.09765 ) / 29.530589 );
	double t = k / 1236.85;
	double nm = 2451550.09765
			+ 29.530589 * k
			+ 0.0001337 * t * t
			- 0.40720 * Math.sin( ( 201.5643 + 385.8169 * k ) * 0.017453292519943 )
			+ 0.17241   * Math.sin( ( 2.5534 +  29.1054 * k ) * 0.017453292519943 );
		return ( nm );  // 月齢は j - nm
}

// ユリウス通日の計算
public double getJulian( Calendar d ){
	double j = d.getTime().getTime() / 86400000.0 + 2440587.5;

	return j;
}

今回はあまり技術的な内容ではないため、プログラムの詳細説明は省略します。簡単に説明すると満月・新月の判断は当日と翌日の月齢を求めて、これら2つの月齢が満月あるいは新月の条件となる月齢をまたいでいるかどうかを調べています。


シミュレーション結果

このプログラムを実行すると以下のような結果になります。シミュレート期間は 2005 年の4月です:

■1日目2005/04/01 金 終了時の所持金額
                  総資産 = 手持ち資金+所有株式時価総額 = 5,000,000円
                 手持ち資金(運転可能金額 + ロック金額) = 5,000,000円
                                           運転可能金額 = 5,000,000円
                                                     ロック資金 = 0円
                                              単純計算年率利益率 0.0%

○ロボットの銘柄評価
購入: 2914 JT 1単位 成行

【注文処理結果】
                        銘柄名|銘柄コード|      枚数|  購入価格|    前日比
------------------------------+----------+----------+----------+----------
                          JT|      2914|         1| 1,240,000|   -20,000



【ポートフォリオ】
                        銘柄名|銘柄コード|      枚数|  購入価格|    前日比
------------------------------+----------+----------+----------+----------
                          JT|      2914|         1| 1,240,000|   -20,000


実行時間: 2.328 秒.

■2日目2005/04/02 土 終了時の所持金額
No Data
実行時間: 0.0 秒.

■3日目2005/04/03 日 終了時の所持金額
No Data
実行時間: 0.0 秒.

■4日目2005/04/04 月 終了時の所持金額
                  総資産 = 手持ち資金+所有株式時価総額 = 5,020,000円
                 手持ち資金(運転可能金額 + ロック金額) = 3,760,000円
                                           運転可能金額 = 3,760,000円
                                                     ロック資金 = 0円
                                            単純計算年率利益率 145.0%

○ロボットの銘柄評価
売却: 2914 JT 1単位 成行

【注文処理結果】
                        銘柄名|銘柄コード|      枚数|  購入価格|    前日比
------------------------------+----------+----------+----------+----------
                          JT|      2914|        -1| 1,260,000|    10,000


実行時間: 1.61 秒.


  :
  :
 (略)
  :
  :


■28日目2005/04/28 木 終了時の所持金額
                  総資産 = 手持ち資金+所有株式時価総額 = 5,022,000円
                 手持ち資金(運転可能金額 + ロック金額) = 5,022,000円
                                           運転可能金額 = 5,022,000円
                                                     ロック資金 = 0円
                                              単純計算年率利益率 8.0%

○ロボットの銘柄評価
実行時間: 1.75 秒.

■29日目2005/04/29 金 終了時の所持金額
No Data
実行時間: 0.0 秒.

■30日目2005/04/30 土 終了時の所持金額
No Data
実行時間: 0.0 秒.

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
【最終結果】
あなたのロボットによる、該当期間の運用成績は、こちらです。
総資産 = 手持ち資金+所有株式時価総額 = 5,022,000円
                                              単純計算年率利益率 7.0%

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


実際のところ、この期間中には3度の売買しか行っていないのですが、最終的には 22,000 円の利益がでました。他の期間でもシミュレートしてみましたが、このアルゴリズムは結構安定して利益を出してくれています。「当たるも八卦、当たらぬも八卦」程度のつもりで作ってみた今回のロボットでしたが、意外な結果になりました。月の魔力は侮れません。


What's Next?

カブロボの投資アルゴリズム、特にテクニカル分析(さすがに今回のはテクニカルと呼ぶのに抵抗もありますが・・・)についての解説も3回を迎えることができました。三日坊主ならぬ、三週坊主はなんとかクリアできそうです。

さて次の紹介内容は・・・ と考えたのですが、筆者が一方的に内容を決めて紹介するよりも、読者の皆様から「こういう手法を実装してみてほしい」という要望をいただきたいと思いました。あまりに複雑な内容になりすぎて私自身の能力を超えてしまうかもしれませんが、いただいた要望も考慮に取り入れた上で内容を検討させていただくことにします。要望がありましたら、ぜひフィードバックとして送ってください。

要望をお待ちしつつも、とりあえず次回分としては MACD を、少し通常とは改良を加えた形で紹介してみる予定です。要望分につきましては次々回以降で実現できれば、と考えております。


参考文献

著者について

木村 桂: 日本IBM ソフトウェア事業

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=251098
ArticleTitle=カブロボ テクニカル分析と、そのアルゴリズムの紹介: その3 月齢
publish-date=02242006
author1-email=kimuc@jp.ibm.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。