概要
下面的策略獲取了指定Instrument過往的bars,用來確定訂單的方向。如果收盤價大于開盤價,創建多單。否則創建空單。每個盈利的交易-----------
定義可配置參數
為了給我們的策略定義可配置的策略,我們需要使用@Configurable注解。
下面的代碼片段定義了4個可配置參數:Instrument, Amount, Take profit, Stop loss
并設置了默認值。
字段engine
和history
用來從各自的歷史數據中拉取bars。
public class SimpleTpSlStrategy implements IStrategy {
// Configurable parameters
@Configurable("Instrument")
public Instrument instrument = Instrument.EURUSD;
@Configurable("Amount")
public double amount = 0.001;
@Configurable("Stop loss")
public int slPips = 10;
@Configurable("Take profit on loss")
public int tpPipsOnLoss = 10;
@Configurable("Take profit on profit")
public int tpPipsOnProfit = 5;
private IEngine engine;
private IHistory history;
private IConsole console;
private IContext context;
private IOrder order;
onStart方法
onStart
方法在策略開始的時候被調用。
我們使用它來創建初始訂單。下面的代碼片段從歷史數據中拉取了之前的日bar,標示了初始訂單的方向并提交了訂單。
方法submitOrder(double amount, OrderCommand orderCmd, double takeProfitPips)
計算了合適的止損和止盈價格并創建一個新的訂單:
public void onStart(IContext context) throws JFException {
this.engine = context.getEngine();
this.history = context.getHistory();
this.console = context.getConsole();
this.context = context;
// subscribe the instrument that we are going to work with
context.setSubscribedInstruments(java.util.Collections.singleton(instrument));
// Fetching previous daily bar from history
IBar prevDailyBar = history.getBar(instrument, Period.DAILY, OfferSide.ASK, 1);
// Identifying the side of the initial order
OrderCommand orderCmd = prevDailyBar.getClose() > prevDailyBar.getOpen()
? OrderCommand.BUY
: OrderCommand.SELL;
// submitting the order with the specified amount, command and take profit
submitOrder(amount, orderCmd, tpPipsOnLoss);
}
private void submitOrder(double amount, OrderCommand orderCmd, double tpPips) throws JFException {
double slPrice, tpPrice;
ITick lastTick = history.getLastTick(instrument);
// Calculating stop loss and take profit prices
if (orderCmd == OrderCommand.BUY) {
slPrice = lastTick.getAsk() - slPips * instrument.getPipValue();
tpPrice = lastTick.getAsk() + tpPips * instrument.getPipValue();
} else {
slPrice = lastTick.getBid() + slPips * instrument.getPipValue();
tpPrice = lastTick.getBid() - tpPips * instrument.getPipValue();
}
// Submitting the order for the specified instrument at the current market price
order = engine.submitOrder(orderCmd.toString() + System.currentTimeMillis(), instrument, orderCmd, amount, 0, 20, slPrice, tpPrice);
}
onMessage方法
onMessage
方法在每次收到新消息的時候被調用,在我們的例子里,就是每次訂單關閉的時候。我們用它來創建新的訂單。
public void onMessage(IMessage message) throws JFException {
if (message.getType() != Type.ORDER_CLOSE_OK
|| !message.getOrder().equals(order) //only respond to our own order close
) {
return;
}
console.getInfo().format("%s closed with P/L %.1f pips", order.getLabel(), order.getProfitLossInPips()).println();
if (message.getReasons().contains(IMessage.Reason.ORDER_CLOSED_BY_TP)) {
// on close by TP we keep the order direction
submitOrder(amount, order.getOrderCommand(), tpPipsOnProfit);
} else if (message.getReasons().contains(IMessage.Reason.ORDER_CLOSED_BY_SL)) {
// on close by SL we change the order direction and use other TP distance
OrderCommand orderCmd = order.isLong() ? OrderCommand.SELL : OrderCommand.BUY;
submitOrder(amount, orderCmd, tpPipsOnLoss);
} else {
//on manual close or close by another strategy we stop our strategy
console.getOut().println("Order closed either from outside the strategy. Stopping the strategy.");
context.stop();
}
}
public void onStop() throws JFException {
if(order.getState() == IOrder.State.FILLED || order.getState() == IOrder.State.OPENED){
order.close();
}
}