レベル: 上級 木村 桂 (kimuc@jp.ibm.com), ソフトウェア事業, IBM
2007年 6月 15日 約1ヶ月半に渡って紹介してきましたスーパー・カブロボ・コンテスト 上級編の紹介ですが、定期連載としてはいよいよ今回が最終回になります。今まではどちらかというと上昇する株や下落する株の選び方をテクニカル指標をベースにしたり、ファンダメンタル情報に基づきながら選別する方法を中心に紹介してきました。今回は少し視点を変えて、選別された株の注文方法を工夫するような投資ロボットを作ってみます。
条件付き発注
カブロボを Java プログラミングで作成するためのツールであるスーパー・カブロボ SDK は、第1回大会から用いられておりました。当時の SDK はバージョン1でしたが、バージョン2になっても基本的には互換性が保たれており、第1回大会で作成したロボットは第2回大会においてもそのまま利用できるようになっています。
とはいえ、カブロボ SDK は全く進化していないわけではありません。機能の高速化や計算精度の向上といった基本機能の向上に加え、第一回大会ではできなかった売買機能も追加されています。その1つが「条件付き発注」の機能です。カブロボは前場および後場の開始前に売買命令を執行するため、第1回大会の SDK バージョン1では寄り付き時の値段を意識した注文はできませんでした。 バージョン2から追加されたこの機能は一度成立した指値注文や逆指値注文に対して、(売買が成立する前に)更に条件を追加することでより細かな注文指定を可能にするものです。特に寄り付き時の値段を意識した注文ができるため、カブロボの投資戦略の幅を広げることが可能になります。
なお、この条件付き発注機能について、詳しくはカブロボの Java Doc 内、OrderManager クラスの setLastOrderSpecialControl メソッドを参考にしてください:
このエントリをクリックして、もう少し詳しい内容を参照すると以下の様に記述されています。
現在のカブロボ SDK 2.0 で用意されている条件付き発注には、大きく以下の2種類があります:
- トリガー機能
- 注文価格修正指示機能
トリガー機能は「始値が○○以上××以下だった場合に注文する」という指示による注文です。カブロボのルールでは order メソッドが実行されるのは前後場の前なので、なんらかの異常事態によって始値が直前の終値と比べて大きく変化していたとしても注文時には気付くことができませんでした。その点、このトリガー機能を使うことで始値が特定範囲に含まれている場合に限って注文できるようになります。
一方、注文価格修正指示機能は指値・指成・逆指値の各注文の価格を、始値からの差分で指定する昨日です。この機能を使うことで、始値が直前の終値と大きく離れているような事態でも、始値を基調とした値段で注文できるようになります。
これらの条件付き発注を行うことで、始値をベースとした値段の指定ができるようになるため、よりリアルタイム性の強い注文が可能になります。
条件付き発注ロボットを作るための準備
この条件付き発注機能ですが、利用する前に設定ファイル上でこの機能を有効にするよう指定する必要があります。robot-config.xml を開いて、<special-order>タグの値を true に変更します。
この変更によって、この後のプログラミング内で利用する条件付き発注が正しく執行されるようになります。なお、この機能を有効にするための設定とは異なりますが、今回紹介するロボットでは空売りを行いますので、このタイミングで robot-config.xml の <short-trade> タグの値も true に変更しておいてください。
条件付き発注ロボットを作る
ここまでの準備ができたら、改めてロボットを作成します。今回作成するロボットは DwRobotAdv06 とし、その内容は以下の通りです。今回は空売りを行うこともあり、ロボットのベースは中級編(6)で紹介した DwRobot05 にしました。中級編(6)を参照いただき、ロボット: DwRobot05.java の内容をコピー&ペーストしてから変更すると編集作業は最小限で済むと思います。また上級編のこれまでのロボットは screening メソッド内の処理が肝になるものばかりでしたが、今回は order メソッドが重要です。
DwRobotAdv06.java の内容
import java.util.ArrayList;
import jp.tradesc.superkaburobo.sdk.driver.RobotDriver;
import jp.tradesc.superkaburobo.sdk.robot.AbstractRobot;
import jp.tradesc.superkaburobo.sdk.trade.EnumAnalysisSpan;
import jp.tradesc.superkaburobo.sdk.trade.OrderManager;
import jp.tradesc.superkaburobo.sdk.trade.TradeAgent;
import jp.tradesc.superkaburobo.sdk.trade.analysis.technicalindex.GoldenCross;
import jp.tradesc.superkaburobo.sdk.trade.data.EnumControlAddType;
import jp.tradesc.superkaburobo.sdk.trade.data.EnumControlTrigger;
import jp.tradesc.superkaburobo.sdk.trade.data.EnumTradeTerms;
import jp.tradesc.superkaburobo.sdk.trade.data.EnumTradeTiming;
import jp.tradesc.superkaburobo.sdk.trade.data.Portfolio;
import jp.tradesc.superkaburobo.sdk.trade.data.Stock;
public class DwRobotAdv06 extends AbstractRobot {
@Override
public void order(TradeAgent arg0) {
// TODO Auto-generated method stub
//. 手持ちのポジションを清算するため、ポートフォリオを取得する
ArrayList<Portfolio> portfolioList = arg0.getPortfolioManager().getPortfolio();
//. 売り候補リストと現在のポートフォリオとを比較する
for( Portfolio portfolio : portfolioList ){
//. 購入時の約定値段
Integer execPrice = portfolio.getExecPrice();
//. 購入時の枚数
Integer execQty = portfolio.getExecQty();
//. この銘柄の現在の価格
Stock stock = portfolio.getStock();
Integer closingPrice
= arg0.getInformationManager().getStockSession( stock ).getClosingPrice();
//. ポジションの種類(買い/空売り)ごとにポジション管理の方法を変える
if( execQty > 0 ){
//. 買いポジションの場合
if( closingPrice >= execPrice * 1.15 ){
//. 既に購入価格よりも 15% 上昇していたら、利益確定で決済
portfolio.orderReverseNowMarketAll();
}else if( closingPrice <= execPrice * 0.9 ){
//. 既に購入価格よりも 10% 下落していたら、損切で決済
portfolio.orderReverseNowMarketAll();
}
}else{
//. 空売りポジションの場合
if( closingPrice <= execPrice * 0.9 ){
//. 既に購入価格よりも 10% 下落していたら、利益確定で決済
portfolio.orderReverseNowMarketAll();
}else if( closingPrice <= execPrice * 1.07 ){
//. 既に購入価格よりも 7% 上昇していたら、損切で決済
portfolio.orderReverseNowMarketAll();
}
}
}
//. 後で何度も使うので、OrderManager オブジェクトを取得しておく (1)
OrderManager orderManager = arg0.getOrderManager();
//. スクリーニング時に設定した売買リストのメモを取り出す
DwMemo memo = ( DwMemo )arg0.getMemoManager().getObjectMemo();
if( memo != null ){
ArrayList<Stock> buyList = memo.getBuyList();
ArrayList<Stock> sellList = memo.getSellList();
//. 買い候補リストの銘柄には単元株数分だけ買い注文を発行する
for( Stock stock : buyList ){
//. 取り出した銘柄の単元数を取得する
Integer unit = stock.getUnit();
//. この銘柄の現在の価格 (2)
Integer closingPrice
= arg0.getInformationManager().getStockSession( stock ).getClosingPrice();
//. この銘柄の呼び値 (3)
Integer spread
= arg0.getInformationManager().checkSpread( closingPrice );
//. この直近終値の指値で、単元数だけ新規買い注文 (4)
boolean b = orderManager.orderActual( stock, closingPrice, unit,
EnumTradeTerms.LIMIT_ORDER, EnumTradeTiming.NOW );
if( b ){
//. 成功していた場合は、更に注文価格を修正する (5)
b = orderManager.setLastOrderSpecialControl( null, 0, 0,
EnumControlAddType.OPENING_PRICE, -1 * spread );
}
}
//. 売り候補リストの銘柄には単元株数分だけ空売り注文を発行する
for( Stock stock : sellList ){
//. 取り出した銘柄の単元数を取得する
Integer unit = stock.getUnit();
//. この銘柄の現在の価格
Integer closingPrice
= arg0.getInformationManager().getStockSession( stock ).getClosingPrice();
//. この銘柄の呼び値
Integer spread
= arg0.getInformationManager().checkSpread( closingPrice );
//. 最低取引株数(=単元数)分だけ空売り注文
boolean b = orderManager
.orderCreditNowLimit( stock, closingPrice + spread, -1 * unit );
if( b ){
//. 成功していた場合は、更に上限と下限のトリガー条件を付与する (6)
orderManager.setLastOrderSpecialControl( EnumControlTrigger.OPENING_PRICE,
( int )( closingPrice * 0.95 ), ( int )( closingPrice * 1.05 ), null, 0 );
}
}
}
//. 全ての注文が終わったらメモを初期化する
arg0.getMemoManager().setObjectMemo( null );
}
@Override
public void screening(TradeAgent arg0) {
// TODO Auto-generated method stub
//. 省略(DwRobot05 の screening メソッドと同じ)
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//. 便利に実行するためのおまじない
String[] arg = { "-n", "DwRobotAdv06" };
RobotDriver.main( arg );
}
}
|
ロボットの大まかな説明は中級編(6)で済ませていますので、今回はそこからの変更点を中心に解説します。まず screening メソッドについては一切変更しません。元の DwRobot05 同様、ゴールデンクロスとデッドクロスで買い/売りの候補を作ります。
また注文を行う order メソッド内についても、既にポジションとして持っているポートフォリオの管理方法は DwRobot05 のものと同じものを使いますので、こちらも変更はありません。次にスクリーニングした結果をうけて新規に購入したり、空売りを行うのですが、この後 OrderManager クラスのオブジェクトを何度も使うことになりますので、あらかじめオブジェクトを取得して変数に代入しておきます(1)。今後はこの変数を使って各種売買命令を実行します。
まずは買い候補のリストを取り出します。DwRobot05 では各銘柄の単元数を取得し、その数だけ成行注文していましたが、今回は各銘柄の直近終値を指定して指値注文を行います。そのため現在の価格(直近の終値)と(2)、加えて呼び値を取得しておきます(3)。そして直近の終値を指定して指値注文を発行します(4)。一応、ここまでで注文そのものはできていることになりますが、今回はこの注文を更に条件付きに変更して、新規での買い注文の指値価格を「始値 - 呼び値」に設定しています(5)。つまり注文時点ではわからない始値(寄り付き値)を指定し、「そこから呼び値だけ安く注文する」という条件を後から付けています。
売り候補のリストについても同様です。一度単元株数だけ空売り注文を逆指値注文で発注した後、今度は「始値の 95% から 105% の間だった場合に限って注文する」という条件を後から設定しています(6)。
これが今回作成したロボットで実現している注文方法になります。このようにカブロボ SDK 2.0 からは一度発行した注文に後からより詳細な条件を付けることができるようになりました。
スーパー・カブロボ・コンテストに参加しましょう!
既に第2回スーパー・カブロボ・コンテストの本番運用も開始されました。皆さんが作ったロボットも参加・検討していますでしょうか?
2ヶ月近くに渡って続けてきた本連載記事は今回がとりあえず最終回となります。一応、基本的なロボットの作り方から、テクニカル・ファンダメンタル情報を元に売買するロボットを紹介できたと思っていますが、連載で紹介できなかった内容に関する要望などありましたら、ご意見としてお聞かせください。不定期な形でご紹介できれば、と考えています。
最後に、スーパー・カブロボ・コンテストは参加してみることで自分自身の投資手法を見直すきっかけになると思いますし、Java 言語を使えばソフトウェアプログラミングの取得にも役立ちます。是非コンテストへ参加してみてください。そのために本連載記事が役立てば幸いです。
著者について  | |  | 木村 桂: 日本IBM ソフトウェア事業 |
記事の評価
|