このチュートリアルではストップロス(クローズ逆指値)とリミット(クローズ指値)のオーダーを行います。
以前作成したストラテジーJavaファイル(ChartUsage.java)を変更します。
まず初めに、新しいインポートを追加し、余分なインポートを削除します。
前回、IChartObjectオブジェクトに"signal-up"と"signal-down"を割り当てていましたが、
今回はより具体的なIChartDependentChartObjectオブジェクトを使用します。
このオブジェクトを使用する事で、チャートにオブジェクトを追加する時にバーに固執せずに表示する事が出来ます
(IChartObjectオブジェクトでは不可能)。
import com.dukascopy.api.drawings.IChartDependentChartObject;
import com.dukascopy.api.drawings.ITriangleChartObject;
import com.dukascopy.api.drawings.ITextChartObject;
新しいインスタンス変数を定義します。
private int uniqueOrderCounter = 1;
private SMATrend previousSMADirection = SMATrend.NOT_SET;
private SMATrend currentSMADirection = SMATrend.NOT_SET;
private Map<IOrder, Boolean> createdOrderMap = new HashMap<IOrder, Boolean>();
private int shorLineCounter;
private int textCounterOldSL;
private int textCounterNewSL;
ストップロスとリミットのオーダーをするので、ストラテジー起動時に必要な値を設定出来るようにパラメータを追加する必要があります。
breakEventPips変数はストップロスレベル変更に使用します。
pipsでこのレベルに到達した時、ストップロスオーダーのレベルはエントリー価格に設定されます
(同値撤退限定のトレーリングストップみたいなもの)。
@Configurable("ストップロス(pips)")
public int stopLossPips = 10;
@Configurable("リミット(pips)")
public int takeProfitPips = 10;
@Configurable("ブレークイーブン(pips)")
public double breakEventPips = 5;
SMAトレンド状態の全てのパターンの定数を持つ列挙を定義します。
private enum SMATrend {
UP, DOWN, NOT_SET;
}
ブレークイーブン(同値撤退トレーリングストップ)
全ての通貨ペアのtick更新時に呼び出されるonTickについて考慮する必要があります。
特定の通貨ペアだけフィルタリングするようにしなければなりません。
後でonBarメソッドにて、全ての新しいオーダーを
Mapオブジェクト
に追加します。
ブレークイーブンレベル到達によって既にストップロスレベルが移動しているか、Mapでオーダーを確認します。
まだ移動していない場合、含み益がbreakEventPipsパラメータよりも大きいか確認します。
含み益がブレークイーブンレベルに到達しているなら、ストップロスレベルをエントリー価格のレベルに変更する事が出来ます。
ストップロスの値がエントリー価格に設定されたら、チャート上に視覚的な三角形の変更プロセス(後述するaddBreakToChartメソッドを呼びます)を表示します。
最後に、ストップロスオーダーを変更し、マップのエントリーを更新します。
onTickメソッドの実装は以下の通りになります。
public void onTick(Instrument instrument, ITick tick) throws JFException {
if ( instrument != myInstrument) {
return;
}
for ( Map.Entry<IOrder, Boolean> entry : createdOrderMap.entrySet() ) {
IOrder currentOrder = entry.getKey();
boolean currentValue = entry.getValue();
if ( currentValue == false && currentOrder.getProfitLossInPips() >= breakEventPips ) {
printMe( currentOrder.getProfitLossInPips() + "pipsリミットのポジションのストップロスはエントリーレートに移動しました。");
addBreakToChart( currentOrder, tick, currentOrder.getStopLossPrice(), currentOrder.getOpenPrice() );
currentOrder.setStopLossPrice( currentOrder.getOpenPrice() );
entry.setValue( true );
}
}
}
SMAによるトレード
前回作成したonBarメソッドを変更します。
新しいオーダーをする際にSMATrend列挙を用いてチェックするようにします。
更にストップロスとリミットの設定も行います。
前回との違いは、既にポジションを持っていたとしてもそのポジションをクローズしない所です。
ストップロスやリミットに到達した時は、ポジションは自動的にクローズされます。
それと、全ての新しいオーダーは、後でonTickメソッドでチェックするのでMapに記録します。
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
if (!instrument.equals(myInstrument) || !period.equals(myPeriod)) {
return;
}
int candlesBefore = 2, candlesAfter = 0;
long completedBarTimeL = myOfferSide == OfferSide.ASK ? askBar.getTime() : bidBar.getTime();
double sma[] = indicators.sma(instrument, period, myOfferSide, IIndicators.AppliedPrice.CLOSE,
smaTimePeriod, Filter.NO_FILTER, candlesBefore, completedBarTimeL, candlesAfter);
IEngine.OrderCommand myCommand = null;
printMe( String.format("SMAの値: 2つ前 = %.5f; 1つ前 = %.5f", sma[SECOND_TO_LAST], sma[PREV]));
if( sma[PREV] > sma[SECOND_TO_LAST]){
printMe("SMA上昇");
myCommand = IEngine.OrderCommand.BUY;
currentSMADirection = SMATrend.UP;
} else if ( sma[PREV] < sma[SECOND_TO_LAST]){
printMe("SMA下降");
myCommand = IEngine.OrderCommand.SELL;
currentSMADirection = SMATrend.DOWN;
} else {
return;
}
double lastTickBid = history.getLastTick(myInstrument).getBid();
double lastTickAsk = history.getLastTick(myInstrument).getAsk();
double stopLossValueForLong = myInstrument.getPipValue() * stopLossPips;
double stopLossValueForShort = myInstrument.getPipValue() * takeProfitPips;
double stopLossPrice = myCommand.isLong() ? (lastTickBid - stopLossValueForLong ) : (lastTickAsk + stopLossValueForLong);
double takeProfitPrice = myCommand.isLong() ? (lastTickBid + stopLossValueForShort) : (lastTickAsk - stopLossValueForShort);
if ( currentSMADirection != previousSMADirection ) {
previousSMADirection = currentSMADirection;
IOrder newOrder = engine.submitOrder("MyStrategyOrder" + uniqueOrderCounter++, instrument, myCommand,
0.001, 0, 1, stopLossPrice, takeProfitPrice);
createdOrderMap.put(newOrder, false);
if( openedChart == null ){
return;
}
long time = bidBar.getTime() + myPeriod.getInterval();
double space = myInstrument.getPipValue() * 2;
IChartDependentChartObject signal = myCommand.isLong()
? factory.createSignalUp( "signalUpKey" + signals++, time, bidBar.getLow() - space)
: factory.createSignalDown("signalDownKey" + signals++, time, bidBar.getHigh() + space);
signal.setStickToCandleTimeEnabled(false);
signal.setText("MyStrategyOrder" + (uniqueOrderCounter - 1));
openedChart.addToMainChart(signal);
}
}
チャートにインジケータ追加
addToChartメソッドを変更し、チャートのチェックは新しい(checkChart)メソッドで行います。
private boolean addToChart(IChart chart){
if ( !checkChart(chart) ) {
return false;
}
chart.addIndicator(indicators.getIndicator("SMA"), new Object[] {smaTimePeriod},
new Color[]{Color.BLUE}, new DrawingStyle[]{DrawingStyle.LINE}, new int[]{3});
if(addOHLC){
IOhlcChartObject ohlc = null;
for (IChartObject obj : chart.getAll()) {
if (obj instanceof IOhlcChartObject) {
ohlc = (IOhlcChartObject) obj;
}
}
if (ohlc == null) {
ohlc = chart.getChartObjectFactory().createOhlcInformer();
ohlc.setPreferredSize(new Dimension(100, 200));
chart.addToMainChart(ohlc);
}
ohlc.setShowIndicatorInfo(true);
}
return true;
}
チャートをチェックするメソッド:
private boolean checkChart(IChart chart) {
if (chart == null ) {
printMeError( myInstrument + " のチャートが開かれていません");
return false;
}
if (chart.getSelectedOfferSide() != this.myOfferSide) {
printMeError( "チャートのオーダータイプ(アスク/ビッド)と一致していません:" + this.myOfferSide);
return false;
}
if (chart.getSelectedPeriod() != this.myPeriod) {
printMeError(this.myPeriod + "の時間軸チャートが開かれていません。");
return false;
}
if (chart.getFilter() != this.filter) {
printMeError("chart filter is not " + this.filter);
return false;
}
return true;
}
チャート上にブレークイーブントライアングルをプロット
チャート上のストップロス変更を視覚的に表示するaddBreakToChartメソッドを実装します。
このメソッドはストップロスオーダーが変更されたら、チャート上に三角形のオブジェクトを追加します。
緑の三角形はロングポジションのストップロス変更で、赤い三角形はショートポジションのストップロス変更を表しています。
この三角形は新しいオーダーを行った時に開始し、ストップロス変更時が終点です。
古いストップロスと新しいストップロスの値をテキストで三角形の所に表示します。
private void addBreakToChart(IOrder changedOrder, ITick tick, double oldSL, double newSL) throws JFException {
if ( openedChart == null ) {
return;
}
ITriangleChartObject orderSLTriangle = factory.createTriangle("Triangle " + shorLineCounter++,
changedOrder.getFillTime(), changedOrder.getOpenPrice(), tick.getTime(), oldSL, tick.getTime(), newSL);
Color lineColor = oldSL > newSL ? Color.RED : Color.GREEN;
orderSLTriangle.setColor(lineColor);
orderSLTriangle.setLineStyle(LineStyle.SOLID);
orderSLTriangle.setLineWidth(1);
orderSLTriangle.setStickToCandleTimeEnabled(false);
openedChart.addToMainChart(orderSLTriangle);
String breakTextOldSL = String.format(" Old SL: %.5f", oldSL);
String breakTextNewSL = String.format(" New SL: %.5f", newSL);
double textVerticalPosition = oldSL > newSL ? newSL - myInstrument.getPipValue() : newSL + myInstrument.getPipValue();
ITextChartObject textOldSL = factory.createText("textKey1" + textCounterOldSL++, tick.getTime(), oldSL);
ITextChartObject textNewSL = factory.createText("textKey2" + textCounterNewSL++, tick.getTime(), newSL);
textOldSL.setText(breakTextOldSL);
textNewSL.setText(breakTextNewSL);
textOldSL.setStickToCandleTimeEnabled(false);
textNewSL.setStickToCandleTimeEnabled(false);
openedChart.addToMainChart(textOldSL);
openedChart.addToMainChart(textNewSL);
}
サンプルソースコード:
StopLossStrategy.java
ストップロスの詳細については、ストップロス価格の設定の項目参照。
ストラテジーのテスト
次のパラメータ設定でテストを行います。
緑矢印はロングオーダー時に、赤矢印はショートオーダー時に作成されます。
三角形の右側には、ストップロス変更時に古いストップレベルと新しいストップレベルが表示されます。
三角形の左端はオーダー時のレベルになります。ストップレベル変更時に目で追い易くなります。