IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Java technology  >

第2回スーパー・カブロボ・コンテスト: 上級編(4)

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません


レベル: 上級

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

2007年 6月 01日

今回は一般的なテクニカル分析の範疇からはいったんはずれて、どちらかというとファンダメンタル的な情報を元に動作するようなカブロボの例を紹介します。具体的にはカブロボの SDK を利用して取得できる外国為替の情報を頼りに、輸出関連銘柄や輸入関連銘柄を売買する、というロジックを実装してみます。

まず最初に、前回の記事でカブロボ SDK 2.0 正式版のリリースについて紹介しましたが、一部の不具合を修正した最新版 SDK 2.0.1 がリリースされています。今回に限りませんが、Java によるカブロボのプログラミングにおいてはなるべく最新版の SDK を利用することを推奨しますので、是非最新版をダウンロードした上でロボットの開発をしてください。

外国為替と、日本企業への影響

カブロボ SDK では各銘柄の株価に関する情報だけではなく、他のマーケット関連情報についても一部取得することができるようになっています。その1つが外国為替情報です。株価同様毎日変化する米ドルやユーロといった外国通貨のクロスレート(簡単に言えば「1ドルや1ユーロが何円なのか」という情報)を取得することができます。

まず簡単に外国為替の「円高」/「円安」という言葉について説明します。ただ外国通貨には米ドルやユーロだけでなく、主要なものだけでも英ポンド/スイスフラン・・・と各種存在しています。そしてこれらそれぞれの通貨に対して日本円での値段がついており、しかも常にその相場は変動しています。ここでは説明を単純化する目的で、以降は全て基軸通貨である米ドルと日本円との比較で説明します:

「円高」とは文字通り「日本円の価値が高くなること」です。逆に「円安」とは「日本円の価値が安くなること」です。では仮に $1 = \100 であったとして、これが $1 = \110 になるのは円高でしょうか? それとも円安でしょうか?数字が大きくなったので高くなったように錯覚を起こしやすいですね。でもこれはあくまで「ドルの価値が」高くなったのです。「$1」を「リンゴ」と読み替えると、リンゴが値上がりした(価値が上がった)ことが分かると思います。つまりこれは「ドル高」であって、つまり「円安」なのです。 逆に $1 = \90 となった場合は「ドル安」で「円高」になります。 分かりにくいかもしれませんが「ドル高円安」とか「ドル安円高」といった具合に、2つをセットにして表現すると、少しは間違えにくくなると思います。

なお、ここでは米ドルの場合で説明しましたが、他の通貨でも考え方は一緒です。ただ一般的な「円高」とか「円安」といった表現は米ドルを比較対象に使われていることが多いようです。

日本の株式ニュースの中でも「円高の影響により・・・」とか「ドル高を背景とした・・・」といった表現をよく目にすると思います。例えばですが、海外に大きな市場を持っているような会社がある商品を $100 で売っている場合を考えてみましょう。$1 = \100 であれば、商品が1つ売れるたびに \10,000 の売り上げになります。これが 10% の円安によって $1 = \110 になった場合、(関税などの影響を無視して考えた場合ですが)商品1つあたりの売り上げは \11,000 になります。つまり全く同じ商品が $100 という同じ値段で売れたにも関わらず、10% もの売り上げ増になるわけです。単純に考えると「円安は日本の輸出企業に有利」といえます。逆に為替が 10% 円高になって $1 = \90 となると、今度は全く同じ商品1つの売り上げが 10% 減って \9,000 となってしまいます。「円高は日本の輸出企業に不利」なのです。

逆に輸入企業の場合はどうでしょうか? $100 で仕入れた商品を \11,000 で売っている企業の場合を考えます。仮に $1 = \100 であれば仕入れ値は \10,000 なので、商品1つの売り上げに対して \1,000 の利益になります。ここで 10% の円安で $1 = \110 となった場合、仕入れ値が \11,000 となってしまいます。これを \11,000 のままで売っていたのでは利益が出ないことになってしまいますので売れ行きへの影響を覚悟した上で値上げをするか、あるいはもっと安い商品に切り替えて仕入れる必要がでてきます。「円安は日本の輸入企業に不利」なのです。逆に $1 = \90 といった具合に円高に傾いた場合は、単純に仕入れ値が \9,000 と安くできますから、同じ値段で売っても利益の部分が大きくなるわけです。「円高は日本の輸入企業に有利」です。




上に戻る


外国為替の影響を考慮したカブロボの作成

上記で説明している円安/円高の、輸出企業/輸入企業への影響をまとめると以下のようになります:

  円安円高
輸出企業 有利 不利
輸入企業 不利 有利

この考え方をそっくりそのままカブロボの投資判断材料として取り入れてみちゃいましょう、というのが今回紹介するロボットのテーマになります。カブロボ SDK には MarketExchange というクラス(正確にはインターフェース)が用意されており、米ドルだけでなくユーロ/英ポンド/豪ドル/スイスフラン/カナダドル の6通貨について日本円と比較した日足の4本値や更新日といった情報が取得できるようになっています。平たく言えば、個別銘柄の株価と同様に情報を取得できるようになっています。

また、カブロボ SDK では株式銘柄の業種を Category というクラス(インターフェース)で管理しており、特にこのクラスの getStockList メソッドを利用すると、その特定業種に分類される銘柄のリストを簡単に取得できます。

ちなみに、カブロボ SDK 2.0.0 と、標準パックの 50 銘柄で用意されている全業種および各業種に分類される銘柄は以下の通りです。以下で作成するロボットをみなさん自身で改良される際の参考にしてください。

業種業種コードこの業種に分類される銘柄
建設業2050積水ハウス
食料品3050キリンビール、JT
繊維製品3100東レ
化学3200信越化学工業、富士写真フィルム
医薬品3250武田薬品工業、第一三共
石油・石炭製品3300新日本石油
ゴム製品3350ブリヂストン
ガラス・土石製品3400旭硝子
鉄鋼3450新日本製鐵、JFEホールディングス
非鉄金属3500住友電気工業
機械3600コマツ、セガサミーホールディングス、三菱重工業
電気機器3650日立製作所、松下電器産業、キヤノン
輸送用機器3700トヨタ自動車、ホンダ
精密機器3750HOYA
その他製品3800大日本印刷
電気・ガス業4050東京電力、関西電力、東京瓦斯
陸運業5050東日本旅客鉄道、東海旅客鉄道
海運業5100商船三井
情報・通信業5250NTT、KDDI、NTTドコモ
卸売業6050三井物産、三菱商事、ソフトバンク
小売業6100イオン、ヤマダ電機
銀行業7050三菱UFJフィナンシャル・グループ、三井住友フィナンシャルグループ、みずほフィナンシャルブループ
証券・商品先物取引7100大和證券グループ本社、野村ホールディングス
保険業7150三井住友海上火災保険、ミレアホールディングス
その他金融業7200クレディ セゾン、オリックス
不動産業8050三井不動産、三菱地所
サービス業9050セコム



上に戻る


外国為替情報を元に売買判断を行うカブロボ

上記で説明したクラスを利用して、実際にカブロボを作ってみます。まずは輸出企業に該当しそうな業種をいくつかと、輸入企業に該当しそうな業種を2つずつ、私自身の判断で選んでみました(カッコ内は業種コード):

輸出企業の業種 ・・・輸送用機器(3700)、電気機器(3650)
輸入企業の業種 ・・・電気・ガス(4050)、石油・石灰製品(3300)

これは私が直感的に思った輸出企業と輸入企業の業種です。「輸出といえば車と電化製品だよなあ・・・輸入に真っ先に影響するのは電気・ガスや石油などのエネルギー資源」という程度の、本当に単純な発想で他意なく2つずつ選びました(※ そもそもこの選択が正しいという自信はあまりありません)。皆さんがこのロボットを改良される場合は、皆さんの判断で輸出/輸入の業種を(2つずつである必要はありませんので)選んで、色々試してみてください。

また基本ロジックとしては米ドルの為替情報(終値)を直近の3営業日に渡って取得して、

  • 終値ベースで2日続けてドル高(=円安)、
  • かつ、その2日間で 1.5 円以上、ドルが上昇

の両方の条件を満たした場合を「ドル高(=円安)」と判断し、輸出企業を買って輸入企業を売る、という判断を行うことにします。

逆に

  • 終値ベースで2日続けてドル安(=円高)、
  • かつ、その2日間で 1.5 円以上、ドルが下落

の両方の条件を満たした場合を「ドル安(=円高)」と判断し、逆に輸出企業を売って輸入企業を買う、という判断を行うことにします。

実際に作成するロボットの内容は以下のようになります。今回も order メソッドの内容は DwRobot04 と同じものを利用することにしますので省略します。


DwRobotAdv04.java の内容
                
import java.util.ArrayList;
import java.util.Calendar;

import jp.tradesc.superkaburobo.sdk.driver.RobotDriver;
import jp.tradesc.superkaburobo.sdk.robot.AbstractRobot;
import jp.tradesc.superkaburobo.sdk.trade.TradeAgent;
import jp.tradesc.superkaburobo.sdk.trade.data.Category;
import jp.tradesc.superkaburobo.sdk.trade.data.EnumMarketExchangeType;
import jp.tradesc.superkaburobo.sdk.trade.data.MarketExchange;
import jp.tradesc.superkaburobo.sdk.trade.data.Portfolio;
import jp.tradesc.superkaburobo.sdk.trade.data.Stock;


public class DwRobotAdv04 extends AbstractRobot {
//. 輸出産業株のカテゴリー(輸送用機器、電気機器) (1)
                private final int[] ExportingCategories = { 3700, 3650 };
                //. 輸入産業株のカテゴリー(電気・ガス、石油・石灰製品) (2)
  private final int[] ImportingCategories = { 4050, 3300 };

  @Override
  public void order(TradeAgent arg0) {
    // TODO Auto-generated method stub
    
    //. 省略(DwRobot04 の order メソッドと同じ)
  }

  @Override
  public void screening(TradeAgent arg0) {
    // TODO Auto-generated method stub
    //. 当日の日付と2営業日前の日付を取得 (3)
                Calendar c0 = arg0.getTimeManager().getCurrentDate();     //. 当日
                Calendar c2 = arg0.getTimeManager().getBusinessDay( -3 ); //. 2営業日前の日付
                //. 外国為替相場を取得 (4)
                ArrayList<MarketExchange> mxUSDList
                = arg0.getInformationManager()
	         .getMarketExchangeByInterval( c2, c0, EnumMarketExchangeType.USD );

    //. 売買の候補リストを用意
    ArrayList<Stock> buyList = new ArrayList<Stock>();  //. 買い候補
    ArrayList<Stock> sellList = new ArrayList<Stock>(); //. 売り候補
    
    //. 米ドルの直近3日間の終値を取得 (5)
                double usdjpy[] = new double[3];
                int i = 0;
                for( MarketExchange mxUSD : mxUSDList ){
                  usdjpy[i++] = mxUSD.getClosingPrice();
                }
    
    if( usdjpy[0] > usdjpy[1]  usdjpy[1] > usdjpy[2]  usdjpy[0] > usdjpy[2] + 1.5  ){
      //. 2日続けてドル高 & 2日で 1.5 円以上上昇 になった場合は、輸出産業株を買う (6)
                for( i = 0; i < ExportingCategories.length; i ++ ){
                //. カテゴリーコードを指定して特定業種のカテゴリーオブジェクトを取得する (7)
                Category category = arg0.getInformationManager().getCategory( ExportingCategories[i] );
                //. その業種カテゴリーに属する銘柄のリストを取得する (8)
                ArrayList<Stock> stockList = arg0.getInformationManager().getStockList( category );
        for( Stock stock : stockList ){
          buyList.add( stock );
        }
      }
      
      //. 併せて、輸入産業株を売る (9)
                for( i = 0; i < ImportingCategories.length; i ++ ){
                Category category = arg0.getInformationManager().getCategory( ImportingCategories[i] );
                ArrayList<Stock> stockList = arg0.getInformationManager().getStockList( category );
        for( Stock stock : stockList ){
          sellList.add( stock );
        }
      }
   }else if( usdjpy[0] < usdjpy[1]  usdjpy[1] < usdjpy[2]  usdjpy[0] + 1.5 <  usdjpy[2] ){
      //. 2日続けて円高 & 2日で 1.5 円以上上昇 になった場合は、輸入産業株を買う (10)
                for( i = 0; i < ImportingCategories.length; i ++ ){
                //. カテゴリーコードを指定して特定業種のカテゴリーオブジェクトを取得する (11)
                Category category = arg0.getInformationManager().getCategory( ImportingCategories[i] );
                //. その業種カテゴリーに属する銘柄のリストを取得する (12)
                ArrayList<Stock> stockList = arg0.getInformationManager().getStockList( category );
        for( Stock stock : stockList ){
          buyList.add( stock );
        }
      }
                //. 併せて、輸出産業株を売る (13)
                for( i = 0; i < ExportingCategories.length; i ++ ){
                Category category = arg0.getInformationManager().getCategory( ExportingCategories[i] );
                ArrayList<Stock> stockList = arg0.getInformationManager().getStockList( category );
        for( Stock stock : stockList ){
          sellList.add( stock );
        }
      }
    }


    //. 買い/売りの候補リストを記憶するメモクラスを用意する
    DwMemo memo = new DwMemo();
    
    //. メモに売買それぞれの候補リストを設定する
    memo.setBuyList( buyList );
    memo.setSellList( sellList );
    
    //. メモを格納する
    arg0.getMemoManager().setObjectMemo( memo );
  }

  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    //. 便利に実行するためのおまじない
    String[] arg = { "-n", "DwRobotAdv04" };
    RobotDriver.main( arg );
  }

}

まずは輸出業種と輸入業種を定義します。今回は私の思い付きで輸出業種=輸送用機器、および電気機器(1)、輸入業種=電気・ガス、および石油・石灰製品(2)であると決めました。みなさんがこのカブロボをご自身の考えに基づいて業種を改良する場合は、この部分を変更してください。

次に screening メソッドを説明します。今回は2日連続で円安あるいは円高になっているかどうかを調べますので、全部で3日分の為替情報が必要になります。したがって為替情報を取得する期間は当日から、その2営業日前までになりますので、それぞれの日付を求めておきます(3)。この辺りの詳しい説明は上級編(2)の回を参考にされてください。

次にこの期間内の米ドルの情報をリスト形式で取得します(4)。ここが今回作成するロボットの肝になる部分です。今回は特定の期間を指定して複数日のデータが必要になることから、InformationManager クラスの getMarketExchangeByInterval というメソッドを使います。そしてパラメータに期間の開始日と終了日、そして米ドルを示す EnumMarketExchangeType.USD を指定しています。米ドル以外の外国為替情報を取得する場合はこの最後のパラメータを変更することになります。 そして取得したリストから直近3日間における米ドル相場の終値の値だけを取り出します(5)。この辺りは個別銘柄のデータを取り出す場合と同様なので、やはり上級編(2)の回が参考になると思います。

そして取り出した3日間の終値の値を比較して、

  • 当日の値 > 前日の値
  • 前日の値 > 前々日の値
  • 当日の値 > 前々日の値 + 1.5

の全ての条件を満たしていた場合は充分にドル高になったと判断します(6)。その場合、まずは輸出産業に指定した業種の株を全て買うために、各業種を1つずつ取り出して(7)、更にはその業種に含まれる個別銘柄のリストを取り出して(8)、それぞれの銘柄を1つずつ買い候補のリストに追加します。続けて今度は輸入産業に指定した業種の株を1つずつ取り出して、売り候補のリストに追加します(9)。

また、取り出した3日間の終値の値を比較して、

  • 当日の値 < 前日の値
  • 前日の値 < 前々日の値
  • 当日の値 + 1.5 < 前々日の値

の全ての条件を満たしていた場合は充分に円高になったと判断します(10)。その場合、まずは輸入産業に指定した業種の株を全て買うために、各業種を1つずつ取り出して(11)、更にはその業種に含まれる個別銘柄のリストを取り出して(12)、それぞれの銘柄を1つずつ買い候補のリストに追加します。続けて今度は輸出産業に指定した業種の株を1つずつ取り出して、売り候補のリストに追加します(13)。

リストが完成した後は DwRobot04 と同様、このリストをオブジェクトメモに保存して翌日の売買に備えて記録します。

こうして作成したカブロボを実行すると、最終結果は以下のようになりました:


カブロボ DwRobotAdv04 が停止した後の Console の内容
                
■■最終成績表■■■■■■■■■■■■■■■■■■■■
--●取引データ●--------------------------------------
初期資産額(円)      : 50,000,000
最終資産額(円)      : 50,469,236
取引開始日        :2006-01-04
取引終了日        :2006-12-29
経過日数(日)       :359
運用日数(日)       :248
総トレード数       :94
勝ちトレード数      :57
負けトレード数      :37
勝率(%)         :60.64
年間平均トレード数    :94
全トレード平均期間(日)  :24
勝ちトレード平均期間(日) :23
負けトレード平均期間(日) :24
最長フラット期間(日)   :2
トータル約定金額(円)   :122,322,500
--●損益データ●--------------------------------------
トータル純損益(%)    :0.94
勝ちトレード純利益(%)  :3.8
負けトレード純損失(%)  :-2.63
買いトレード純損益(%)  :1.17
売りトレード純損益(%)  :0
平均損益(%)       :1.26
平均利益(%)       :5.03
平均損失(%)       :-4.55
年率換算利回り(%)    :0.93
最大勝ちトレード(%)   :15.13
最大負けトレード(%)   :-13.88
--●指標データ●--------------------------------------
平均ドローダウン(%)   :0.54
最大ドローダウン(%)   :2
損益レシオ(倍)      :0.94
プロフィットファクター(倍):1.45
リスクレシオ(倍)     :0.46
年率シャープレシオ(倍)  :0.56
年率ボラティリティ(%)  :1.67
■■■■■■■■■■■■■■■■■■■■■■■■■■■

微妙なところですが、一応プラスにはなりました。勝率は 60% を超えているのでまあまあですね。これ以外の輸出入関連業種をいろいろ追加したり取り除いたりすることで調整もできると思います。また、米ドル以外の外国為替についても扱うことができますので、例えば豪ドルの上下に合わせて鉄鋼業を売買する、といったロボットにも応用できると思います。




上に戻る


次回予告

今回はいつもとは少し趣向を変えて、テクニカルというよりは比較的ファンダメンタル的な考えに基づくカブロボを紹介してみました。次回もファンダメンタルの情報を使って、いわゆる「バリュー株」を見つけ出して売買するようなカブロボ作りに挑戦してみる予定です。



著者について

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




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


54321
大変素晴らしい不充分・不完全である
 


上に戻る


    日本IBMについて プライバシー お問い合わせ