当サイトは、アフィリエイト広告を利用しています

JForexプログラミング入門その5-サンプルプログラムを読み解く

JForexプログラミング入門

今回は、JForex Wikiで掲載されているサンプルプログラムの「Simple Strategy」を用いてソースコードを読み解いていきたいと思います。

Simple Strategyの概要

Simple Strategyがやってることは以下の通りです。

ストラテジー開始時に前日の日足を確認して、終値が始値より大きければロングポジション、始値以下ならショートポジションを持つ。

その際、ストップロスは10pips、テイクプロフィットは10pipsに設定。

テイクプロフィットに到達して決済となった場合は、同じ方向にストップロス10pips、テイクプロフィット5pipsに設定してポジションを持つ。

ストップロスに到達して決済となった場合は、方向を反転させ、ストップロス10pips、テイクプロフィット10pipsに設定してポジションを持つ。

後は決済される度に上記を判定してオーダーを繰り返す。

マニュアルで決済された時点でストラテジーは終了。

Simple Strategyのソースコード

Simple Strategyのソースコードは以下の通りです。

ソースファイル自体は、「Simple Strategy」ページの一番下の「Download 」の所にある「SimpleTpSlStrategy.java」というリンクからダウンロードできます。

ソースコード解説

ソースコードに何が記述されているのかを具体的に解説していきます。

使用するクラスのインポート

3から5行目で使用するクラスをインポートしています。

メンバ変数の定義

17から33行目でクラスのメンバ変数を定義しています。

27行目までは外部パラメータの宣言となり、@cofigurableをつけてメンバ変数を外部パラメータに指定しています。

「instrument」は取引する通貨ペア名、「amount」は取引数量、「slPips」は損失確定pips数、「tpPipsOnLoss」は前回のトレードが負けトレードだった時に次のトレードで使用する利益確定pips数、「tpPipsOnProfit」は、前回のトレードが勝ちトレードだった時に次のトレードで使用する利益確定pips数となり、ユーザーはこれらの値をプログラム開始時に表示されるパラメーター定義ダイアログ上で変更することができます。

29行目からは通常のメンバ変数となり、プログラム中で使用する各オブジェクトへの参照を格納する変数が定義されています。

onStart関数

onStart関数では、各メンバ変数の初期化及び、最初のトレードの方向を決定するための処理、及び最初の発注処理を行っています。

41行目は、JForexの銘柄リストに対象の通貨ペアが表示されているかチェックし、表示されていない場合は銘柄リストに追加するための処理です。

contextオブジェクトの「setSubscribedInstruments」関数に「Instrumentのコレクション」を渡すことで指定の通貨ペアを取引できる状態にしてくれます。

今回は単一の通貨ペアのみを指定するため、「java.util.Collections.singleton」を用いて、instrumentを要素が一つだけのコレクションに変換し引数に設定しています。

43行目は、前日の日足情報を取得するコードです。

historyオブジェクトの「getBar」関数を使用して、前日の日足情報をIBarオブジェクトで取得します。

getBarの仕様は以下の通り。

IBar getBar(Instrument instrument,Period period,OfferSide side,int shift) throws JFException

引数:
instrument:どの通貨ペアの足を取得するのかを指定
period :足のタイムフレーム
side – BidとAskのどちらかを指定
shift – 現在の足から何本前の情報を取得するかを指定、1なら1つ前の足、2なら2つ前の足となります

戻り値:IBarオブジェクト、取得できなかった場合はNULL

ここでは、1つ前の日足の情報を取得するために、「period」にPeriod.DAILY、「shift」に1を指定、「side」にはOfferSide.ASKを指定しAskの情報を取得しています。

getBarで取得したIBarオブジェクトの参照はprevDailyBarに格納しておきます。

45~47行目で最初のオーダーを買い注文をうのか、売り注文を行うのかを判定しています。

条件判定には三項演算子が使われており、先ほど取得した前日の足情報が格納されたprevDailyBarを使用してgetCloseで前日の終値を、getOpenで前日の始値を取得。終値の方が始値より大きければ「OrderCommand.BUY」を、終値が始値以下なら「OrderCommand.SELL」をorderCmdに設定しています。

49行目は、79行目から89行目で定義されているユーザー定義の「submitOrder」関数を呼び出して発注処理を行います。

ユーザー定義のsubmitOrderの引数は、「amount(取引数量)」,「orderCmd(取引種別)」,「tpPips(テイクプロフィットpips数)」の3つがあり、「amount」には外部パラメーター化したメンバ変数amountを、「orderCmd」は先ほど作成したorderCmdを、「tpPips」には1番最初のトレードなので、前回のトレードが負けトレードだった時に使用する外部パラメーター化したメンバ変数「tpPipsOnLoss」を指定しています。

この処理が終わると、一番最初のポジションを持つことになります。

ユーザー定義のsubmitOrder関数

79行目から89行目で定義した「submitOrder」関数は、ストップロスの価格とテイクプロフィットの価格を現在のレートから計算し発注処理を行います。

historyオブジェクトのgetLastTickを利用して最新のティック情報をITickオブジェクトとして取得。

submitOrder関数の引数で渡された「orderCmd」で買いか売りかを判断し、実際のストップロス価格とテイクプロフィット価格を計算し「slPrice」「tpPrice」にそれぞれ格納します。

ストップロス価格とテイクプロフィット価格の計算ですが、まず、instrument.getPipValue()を使って、指定の通貨ペアの1pipsに相当するレートを取得しそれを指定のpipsを乗算することで指定pipsあたりの変動価格を計算。

買い注文の場合は、lastTickのgetAsk関数で現在レートのASK値を、売り注文の場合は、lastTickのgetBid関数でBid値を取得し、そのレートに対して変動価格を増減することで実際のストップロスとテイクプロフィットの価格を割り出しています。

88行目はIEngineオブジェクト「engine」のsubmitOrder関数を使用して、実際に発注を行っています。

IEngineオブジェクトのsubmitOrder関数の仕様は以下の通りです。

IOrder submitOrder(String label,
Instrument instrument,
IEngine.OrderCommand orderCommand,
double amount,
double price,
double slippage,
double stopLossPrice,
double takeProfitPrice)
throws JFException

引数:
label:ユーザー定義の注文識別子(最大256文字からなるユニークな文字列)
instrument:通貨ペアを指定
orderCommand:オーダーの種類を指定
smount:発注数量(単位は100万通貨、1000通貨を指定する場合0.001となる)
price:発注価格(0指定は最新のプライス)
slippage:スリッページ
stopLossPrice:ストップロス価格
takeProfitPrice:テイクプロフィット価格

戻り値:IOrder.State.CREATEDで作成されたIOrderオブジェクト

IEngineオブジェクトのsubmitOrderの引数「label」には「orderCmd.toString() + System.currentTimeMillis()」でユニーク識別子を作成して設定、「instrument」にはクラスのメンバ変数のinstrument、「orderCommand」と「amount」は渡されてきた引数をそのまま指定、「price」には最新価格で発注するので0を、「slippage」は20、「stopLossPrice」と「takeProfitPrice」には直前で作成したslPriceとtpPriceを指定しています。

決済した時にオーダーに関する情報を取得できるようにするため、submitOrderの戻り値をメンバ変数のorderに格納しておきます。

ユーザー定義のsubmitOrderは戻り値がvoidなのでそのまま処理を終了して呼び出し元に戻ります。

onMessage関数

onMessage関数では直前のトレードの勝ち負けを読み取り、次のオーダーを発注します。

56~60行目でメッセージのタイプを判定し、自身が発注したオーダーと関係がないメッセージおよび、オーダーのクローズが成功したというメッセージ以外をフィルタリングしています。

このストラテジーで発注したポジションのクローズが成功したというメッセージを受け取った場合のみ次の処理に進みます。

61行目はコンソールにメッセージを表示しています。

新規注文の際に取得したIOrderオブジェクト「order」を使用して、getLabel関数で発注の際に設定したユニークなラベルを、getProfitLossInPips関数で利益もしくは損失になったpips数を表示しています。

consoleのgetInfo関数を使用してメッセージを出力すると、コンソール上のメッセージの背景を緑色にすることができます。

jforexprog5-1

62~73行目は、クローズした理由によって処理を分岐させています。

messageの「getReasons」関数で返されるコレクションに対して「contains」関数を用い、クローズ理由が「IMessage.Reason.ORDER_CLOSED_BY_TP」なのか「IMessage.Reason.ORDER_CLOSED_BY_SL」なのかを判定します。

「IMessage.Reason.ORDER_CLOSED_BY_TP」は、テイクプロフィット価格に到達してポジションをクローズ、「IMessage.Reason.ORDER_CLOSED_BY_SL」はストップロス価格に到達してポジションをクローズの意味となります。

テイクプロフィット価格でのクローズの場合は、ユーザー定義の「submitOrder」関数の引数「orderCmd」には前回と同じ方向で発注するためorder.getOrderCommand()を指定、「tpPips」には勝ちトレードだった時に使用する外部パラメーター化したメンバ変数「tpPipsOnProfit」を指定しています。

ストップロス価格でのクローズの場合は、注文方向を反転させないといけません。

そのため、orderのisLong()を使用して前回の注文の方向を確認し、ロングだった場合、orderCmdに「OrderCommand.SELL」を、ショートだった場合は「OrderCommand.BUY」をセットしてユーザー定義の「submitOrder」関数の引数「orderCmd」に渡します。

また、「tpPips」には負けトレードだった時に使用する外部パラメーター化したメンバ変数「tpPipsOnLoss」を指定しています。

マニュアル操作でポジションをクローズした場合等、テイクプロフィットとストップロス以外の理由でポジションクローズが起こった場合は、最後の条件分岐が実行されます。

この場合はコンソールにメッセージを表示。

そして、IContextオブジェクトのcontextに対してstop関数を呼び、ストラテジーを終了させます。

onStop関数

onStop関数では、ストラテジー終了時にポジションが残っていれば、ポジションをクローズするという処理が書かれています。

ポジションやオーダーが残っているかどうかをorderのgetState関数で判定し、状態がFILLD(ポジション保有中)、もしくはOPEND(注文中)ならば、orderのclose関数を読んでポジションをクローズ、もしくはオーダーを削除します。

まとめ

今回は、実際に売買を行うストラテジーのソースを元に、ソースコードにどういう処理が記述されているかを解説しました。

あまり深く解説できていないかもしれませんが、今回のソースを一通り理解できれば単純な売買プログラムは書けるようになると思います。

ぜひ自分で売買プログラムの作成に挑戦してみてください。

コメント