前回まででカンタンですが結構使い勝手の良い指値・逆指値注文まで出来ました。
今回は個人的によく使うブレイクアウト注文用の画面を作りたいと思います。
要は逆指値注文なんですが、個人的に前の足の高値を◯◯pipsブレイクしたらエントリーみたいなコトをよくやっていて、それを勝手にブレイクアウト注文と呼んでいますw
GUIのパーツはEclipseとWindowBuilderでちゃちゃっと作ってこんな感じにしました。
どの足を基準にするか
ただの逆指値注文とブレイクアウト注文の違いですが、ただの逆指値注文は今のレートから◯◯pips離れたところに注文を置くのに対し、ブレイクアウト注文の場合は基準にする足があって、その足の高値(安値)から◯◯pips離れたところに注文を置くという点です。
なので、どの足を基準にするか選択するためのコンボボックスが必要になります。
コンボボックスで基準となる足を選んだ後は
private void refresh() { Instrument instrument = (Instrument)cmbInstrument.getSelectedItem(); Period period = (Period)cmbPeriod.getSelectedItem(); final String scaleFormat = "%." + String.valueOf(instrument.getPipScale() + 1) + "f"; final double entryMarginePrice = (Double)spnEntryMarginePips.getValue() * instrument.getPipValue(); try { IHistory history = context.getHistory(); final IBar bid = history.getBar(instrument, period, OfferSide.BID, 1); final IBar ask = history.getBar(instrument, period, OfferSide.ASK, 1); SwingUtilities.invokeLater(new Runnable () { public void run() { btnSellStop.setText(String.format(scaleFormat, bid.getLow() - entryMarginePrice)); btnBuyStop.setText(String.format(scaleFormat, ask.getHigh() + entryMarginePrice)); } }); } catch (JFException e) { console.getErr().println(e.toString()); } }
こんな感じで基準となる時間足の確定足を引っ張ってきて高値・安値を取得します。
あとは前回の指値・逆指値注文とほとんど同じです。
全コード
package jforex; import java.awt.Color; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Vector; import java.util.concurrent.Callable; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JSpinner.NumberEditor; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.dukascopy.api.IAccount; import com.dukascopy.api.IBar; import com.dukascopy.api.IConsole; import com.dukascopy.api.IContext; import com.dukascopy.api.IEngine; import com.dukascopy.api.IEngine.OrderCommand; import com.dukascopy.api.IHistory; import com.dukascopy.api.IMessage; import com.dukascopy.api.IOrder; import com.dukascopy.api.IStrategy; import com.dukascopy.api.ITick; import com.dukascopy.api.Instrument; import com.dukascopy.api.JFException; import com.dukascopy.api.OfferSide; import com.dukascopy.api.Period; public class ConditionalOrder03 extends JFrame implements IStrategy { private IEngine engine; private IConsole console; private IContext context; private JButton btnBuyStop; private JLabel lblAmount; private JLabel lblAskT; private JLabel lblBidT; private JLabel lblStopLossPips; private JLabel lblTakeProfitPips; private JPanel pnlAmount; private JPanel pnlOrder; private JPanel pnlTpSlPips; private JSpinner spnAmount; private JSpinner spnStopLossPips; private JSpinner spnTakeProfitPips; private JComboBox cmbInstrument; private JButton btnCancelAll; private JLabel lblSlippagePips; private JSpinner spnSlippagePips; private JButton btnSellStop; private JSpinner spnEntryMarginePips; private JLabel lblBid; private JLabel lblAsk; private JLabel lblGoodTillSec; private JSpinner spnGoodTillSec; private JComboBox cmbPeriod; public ConditionalOrder03() { addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { try { onStop(); } catch (JFException e1) { e1.printStackTrace(); } } }); setResizable(false); setTitle("BreakOut Order"); setBounds(100, 100, 340, 400); setLocationRelativeTo(null); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[] {200}; gridBagLayout.rowHeights = new int[] {30, 150, 120}; getContentPane().setLayout(gridBagLayout); pnlAmount = new JPanel(); GridBagConstraints gbc_pnlAmount = new GridBagConstraints(); gbc_pnlAmount.insets = new Insets(0, 0, 5, 0); gbc_pnlAmount.fill = GridBagConstraints.BOTH; gbc_pnlAmount.gridx = 0; gbc_pnlAmount.gridy = 0; getContentPane().add(pnlAmount, gbc_pnlAmount); GridBagLayout gbl_pnlAmount = new GridBagLayout(); gbl_pnlAmount.rowHeights = new int[] {30}; gbl_pnlAmount.columnWidths = new int[] {80, 60, 60}; pnlAmount.setLayout(gbl_pnlAmount); cmbInstrument = new JComboBox(getInstruments().toArray()); cmbInstrument.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { refresh(); } }); GridBagConstraints gbc_cmbInstrument = new GridBagConstraints(); gbc_cmbInstrument.fill = GridBagConstraints.BOTH; gbc_cmbInstrument.gridx = 0; gbc_cmbInstrument.gridy = 0; pnlAmount.add(cmbInstrument, gbc_cmbInstrument); lblAmount = new JLabel("Amount:"); lblAmount.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblAmount = new GridBagConstraints(); gbc_lblAmount.anchor = GridBagConstraints.EAST; gbc_lblAmount.gridx = 1; gbc_lblAmount.gridy = 0; gbc_lblAmount.fill = GridBagConstraints.BOTH; pnlAmount.add(lblAmount, gbc_lblAmount); SpinnerNumberModel snm; NumberEditor ne; snm = new SpinnerNumberModel(new Double(1), new Double(1), new Double(2500), new Double(0.1)); spnAmount = new JSpinner(snm); ne = new NumberEditor(spnAmount, "0.0"); spnAmount.setEditor(ne); GridBagConstraints gbc_spnAmount = new GridBagConstraints(); gbc_spnAmount.fill = GridBagConstraints.BOTH; gbc_spnAmount.gridx = 2; gbc_spnAmount.gridy = 0; pnlAmount.add(spnAmount, gbc_spnAmount); pnlOrder = new JPanel(); GridBagConstraints gbc_pnlOrder = new GridBagConstraints(); gbc_pnlOrder.insets = new Insets(0, 0, 5, 0); gbc_pnlOrder.fill = GridBagConstraints.BOTH; gbc_pnlOrder.gridx = 0; gbc_pnlOrder.gridy = 1; getContentPane().add(pnlOrder, gbc_pnlOrder); GridBagLayout gbl_pnlOrder = new GridBagLayout(); gbl_pnlOrder.columnWidths = new int[] {80, 50, 80}; gbl_pnlOrder.rowHeights = new int[] {30, 30, 30, 30, 30, 30}; pnlOrder.setLayout(gbl_pnlOrder); cmbPeriod = new JComboBox(getPeriods().toArray()); cmbPeriod.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { refresh(); } }); GridBagConstraints gbc_cmbPeriod = new GridBagConstraints(); gbc_cmbPeriod.fill = GridBagConstraints.BOTH; gbc_cmbPeriod.gridx = 0; gbc_cmbPeriod.gridy = 0; pnlOrder.add(cmbPeriod, gbc_cmbPeriod); lblBidT = new JLabel("Bid(SELL)"); lblBidT.setForeground(Color.RED); lblBidT.setHorizontalAlignment(SwingConstants.CENTER); GridBagConstraints gbc_lblBidT = new GridBagConstraints(); gbc_lblBidT.fill = GridBagConstraints.BOTH; gbc_lblBidT.gridx = 0; gbc_lblBidT.gridy = 1; pnlOrder.add(lblBidT, gbc_lblBidT); lblAskT = new JLabel("Ask(BUY)"); lblAskT.setForeground(Color.BLUE); lblAskT.setHorizontalAlignment(SwingConstants.CENTER); GridBagConstraints gbc_lblAskT = new GridBagConstraints(); gbc_lblAskT.fill = GridBagConstraints.BOTH; gbc_lblAskT.gridx = 2; gbc_lblAskT.gridy = 1; pnlOrder.add(lblAskT, gbc_lblAskT); btnBuyStop = new JButton(); btnBuyStop.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { JButton source = (JButton)e.getSource(); double price = Double.parseDouble(source.getText()); context.executeTask(new SubmitOrder(OrderCommand.BUYSTOP, price)); } }); snm = new SpinnerNumberModel(new Double(1.0), new Double(0.0), null, new Double(0.1)); spnEntryMarginePips = new JSpinner(snm); spnEntryMarginePips.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { refresh(); } }); ne = new NumberEditor(spnEntryMarginePips, "0.0"); spnEntryMarginePips.setEditor(ne); GridBagConstraints gbc_spnEntryMargine = new GridBagConstraints(); gbc_spnEntryMargine.fill = GridBagConstraints.BOTH; gbc_spnEntryMargine.gridheight = 3; gbc_spnEntryMargine.gridx = 1; gbc_spnEntryMargine.gridy = 2; pnlOrder.add(spnEntryMarginePips, gbc_spnEntryMargine); GridBagConstraints gbc_btnBuyStop = new GridBagConstraints(); gbc_btnBuyStop.fill = GridBagConstraints.BOTH; gbc_btnBuyStop.gridx = 2; gbc_btnBuyStop.gridy = 2; pnlOrder.add(btnBuyStop, gbc_btnBuyStop); btnCancelAll = new JButton(); btnCancelAll.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { context.executeTask(new CancelOpenedOrders()); } }); lblBid = new JLabel(); lblBid.setHorizontalAlignment(SwingConstants.CENTER); GridBagConstraints gbc_lblBid = new GridBagConstraints(); gbc_lblBid.fill = GridBagConstraints.BOTH; gbc_lblBid.gridx = 0; gbc_lblBid.gridy = 3; pnlOrder.add(lblBid, gbc_lblBid); lblAsk = new JLabel(); lblAsk.setHorizontalAlignment(SwingConstants.CENTER); GridBagConstraints gbc_lblAsk = new GridBagConstraints(); gbc_lblAsk.fill = GridBagConstraints.BOTH; gbc_lblAsk.gridx = 2; gbc_lblAsk.gridy = 3; pnlOrder.add(lblAsk, gbc_lblAsk); btnSellStop = new JButton(); btnSellStop.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { JButton source = (JButton)e.getSource(); double price = Double.parseDouble(source.getText()); context.executeTask(new SubmitOrder(OrderCommand.SELLSTOP, price)); } }); GridBagConstraints gbc_btnSellStop = new GridBagConstraints(); gbc_btnSellStop.fill = GridBagConstraints.BOTH; gbc_btnSellStop.gridx = 0; gbc_btnSellStop.gridy = 4; pnlOrder.add(btnSellStop, gbc_btnSellStop); btnCancelAll.setText("Cancel All"); GridBagConstraints gbc_btnCancelAll = new GridBagConstraints(); gbc_btnCancelAll.gridwidth = 3; gbc_btnCancelAll.fill = GridBagConstraints.BOTH; gbc_btnCancelAll.gridx = 0; gbc_btnCancelAll.gridy = 5; pnlOrder.add(btnCancelAll, gbc_btnCancelAll); pnlTpSlPips = new JPanel(); TitledBorder titleBorder = new TitledBorder(UIManager.getBorder("TitledBorder.border")); titleBorder.setTitle("Entry Option"); titleBorder.setTitleJustification(TitledBorder.LEADING); titleBorder.setTitlePosition(TitledBorder.TOP); pnlTpSlPips.setBorder(titleBorder); GridBagConstraints gbc_pnlTpSlPips = new GridBagConstraints(); gbc_pnlTpSlPips.insets = new Insets(0, 0, 5, 0); gbc_pnlTpSlPips.fill = GridBagConstraints.BOTH; gbc_pnlTpSlPips.gridx = 0; gbc_pnlTpSlPips.gridy = 2; getContentPane().add(pnlTpSlPips, gbc_pnlTpSlPips); GridBagLayout gbl_pnlTpSlPips = new GridBagLayout(); gbl_pnlTpSlPips.columnWidths = new int[] {100, 100}; gbl_pnlTpSlPips.rowHeights = new int[] {30, 30, 30, 30}; pnlTpSlPips.setLayout(gbl_pnlTpSlPips); lblSlippagePips = new JLabel("Slippage(Pips):"); lblSlippagePips.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblSlippagePips = new GridBagConstraints(); gbc_lblSlippagePips.fill = GridBagConstraints.BOTH; gbc_lblSlippagePips.gridx = 0; gbc_lblSlippagePips.gridy = 0; pnlTpSlPips.add(lblSlippagePips, gbc_lblSlippagePips); snm = new SpinnerNumberModel(new Double(0), new Double(0), null, new Double(0.1)); spnSlippagePips = new JSpinner(snm); ne = new NumberEditor(spnSlippagePips, "0.0"); spnSlippagePips.setEditor(ne); GridBagConstraints gbc_spnSlippagePips = new GridBagConstraints(); gbc_spnSlippagePips.fill = GridBagConstraints.BOTH; gbc_spnSlippagePips.gridx = 1; gbc_spnSlippagePips.gridy = 0; pnlTpSlPips.add(spnSlippagePips, gbc_spnSlippagePips); lblStopLossPips = new JLabel("StopLoss(Pips):"); lblStopLossPips.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblStopLossPips = new GridBagConstraints(); gbc_lblStopLossPips.fill = GridBagConstraints.BOTH; gbc_lblStopLossPips.gridx = 0; gbc_lblStopLossPips.gridy = 1; pnlTpSlPips.add(lblStopLossPips, gbc_lblStopLossPips); snm = new SpinnerNumberModel(new Double(0), new Double(0), null, new Double(0.1)); spnTakeProfitPips = new JSpinner(snm); ne = new NumberEditor(spnTakeProfitPips, "0.0"); spnTakeProfitPips.setEditor(ne); GridBagConstraints gbc_spnTakeProfitPips = new GridBagConstraints(); gbc_spnTakeProfitPips.fill = GridBagConstraints.BOTH; gbc_spnTakeProfitPips.gridx = 1; gbc_spnTakeProfitPips.gridy = 1; pnlTpSlPips.add(spnTakeProfitPips, gbc_spnTakeProfitPips); lblTakeProfitPips = new JLabel("TakeProfit(Pips):"); lblTakeProfitPips.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblTakeProfitPips = new GridBagConstraints(); gbc_lblTakeProfitPips.fill = GridBagConstraints.BOTH; gbc_lblTakeProfitPips.gridx = 0; gbc_lblTakeProfitPips.gridy = 2; pnlTpSlPips.add(lblTakeProfitPips, gbc_lblTakeProfitPips); snm = new SpinnerNumberModel(new Double(0), new Double(0), null, new Double(0.1)); spnStopLossPips = new JSpinner(snm); ne = new NumberEditor(spnStopLossPips, "0.0"); spnStopLossPips.setEditor(ne); GridBagConstraints gbc_spnStopLossPips = new GridBagConstraints(); gbc_spnStopLossPips.fill = GridBagConstraints.BOTH; gbc_spnStopLossPips.gridx = 1; gbc_spnStopLossPips.gridy = 2; pnlTpSlPips.add(spnStopLossPips, gbc_spnStopLossPips); lblGoodTillSec = new JLabel("GoodTillTime(sec):"); lblGoodTillSec.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblGoodTillTime = new GridBagConstraints(); gbc_lblGoodTillTime.fill = GridBagConstraints.BOTH; gbc_lblGoodTillTime.gridx = 0; gbc_lblGoodTillTime.gridy = 3; pnlTpSlPips.add(lblGoodTillSec, gbc_lblGoodTillTime); snm = new SpinnerNumberModel(new Long(0), new Long(0), null, new Long(1)); spnGoodTillSec = new JSpinner(snm); GridBagConstraints gbc_spinner = new GridBagConstraints(); gbc_spinner.fill = GridBagConstraints.BOTH; gbc_spinner.gridx = 1; gbc_spinner.gridy = 3; pnlTpSlPips.add(spnGoodTillSec, gbc_spinner); } public void onStart(IContext context) throws JFException { this.engine = context.getEngine(); this.console = context.getConsole(); this.context = context; EventQueue.invokeLater(new Runnable() { public void run() { try { setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); console.getOut().println("Strategy Started."); refresh(); } public void onAccount(IAccount account) throws JFException { } public void onMessage(IMessage message) throws JFException { if (message.getOrder() == null) return; if (!cmbInstrument.getSelectedItem().equals(message.getOrder().getInstrument())) return; console.getOut().println(message.toString()); } public void onStop() throws JFException { console.getOut().println("Strategy Stopped."); } public void onTick(Instrument instrument, final ITick tick) throws JFException { if (!cmbInstrument.getSelectedItem().equals(instrument)) return; final String scaleFormat = "%." + String.valueOf(instrument.getPipScale() + 1) + "f"; SwingUtilities.invokeLater(new Runnable () { public void run() { lblBid.setText(String.format(scaleFormat, tick.getBid())); lblAsk.setText(String.format(scaleFormat, tick.getAsk())); double sellPrice = Double.parseDouble(btnSellStop.getText()); if (sellPrice > tick.getBid()) btnSellStop.setForeground(Color.RED); else btnSellStop.setForeground(Color.BLACK); double buyPrice = Double.parseDouble(btnBuyStop.getText()); if (buyPrice < tick.getAsk()) btnBuyStop.setForeground(Color.RED); else btnBuyStop.setForeground(Color.BLACK); } }); } public void onBar(Instrument instrument, Period period, final IBar askBar, final IBar bidBar) throws JFException { if (!cmbInstrument.getSelectedItem().equals(instrument)) return; if (!cmbPeriod.getSelectedItem().equals(period)) return; final String scaleFormat = "%." + String.valueOf(instrument.getPipScale() + 1) + "f"; final double entryMarginePrice = (Double)spnEntryMarginePips.getValue() * instrument.getPipValue(); SwingUtilities.invokeLater(new Runnable () { public void run() { btnSellStop.setText(String.format(scaleFormat, bidBar.getLow() - entryMarginePrice)); btnBuyStop.setText(String.format(scaleFormat, askBar.getHigh() + entryMarginePrice)); } }); } private void refresh() { Instrument instrument = (Instrument)cmbInstrument.getSelectedItem(); Period period = (Period)cmbPeriod.getSelectedItem(); final String scaleFormat = "%." + String.valueOf(instrument.getPipScale() + 1) + "f"; final double entryMarginePrice = (Double)spnEntryMarginePips.getValue() * instrument.getPipValue(); try { IHistory history = context.getHistory(); final IBar bid = history.getBar(instrument, period, OfferSide.BID, 1); final IBar ask = history.getBar(instrument, period, OfferSide.ASK, 1); SwingUtilities.invokeLater(new Runnable () { public void run() { btnSellStop.setText(String.format(scaleFormat, bid.getLow() - entryMarginePrice)); btnBuyStop.setText(String.format(scaleFormat, ask.getHigh() + entryMarginePrice)); } }); } catch (JFException e) { console.getErr().println(e.toString()); } } //通貨ペア private final Vector<Instrument> getInstruments() { Vector<Instrument> instruments = new Vector<Instrument>(); instruments.add(Instrument.USDJPY); instruments.add(Instrument.EURUSD); instruments.add(Instrument.EURJPY); instruments.add(Instrument.GBPUSD); instruments.add(Instrument.GBPJPY); instruments.add(Instrument.AUDUSD); instruments.add(Instrument.AUDJPY); return instruments; } //時間足 private final Vector<Period> getPeriods() { Vector<Period> periods = new Vector<Period>(); periods.add(Period.ONE_MIN); periods.add(Period.FIVE_MINS); periods.add(Period.FIFTEEN_MINS); periods.add(Period.THIRTY_MINS); periods.add(Period.ONE_HOUR); return periods; } //新規注文 private class SubmitOrder implements Callable<IOrder> { private OrderCommand orderCommand; private double price; public SubmitOrder(OrderCommand orderCommand, double price) { this.orderCommand = orderCommand; this.price = price; } public IOrder call() throws Exception { Instrument instrument = (Instrument)cmbInstrument.getSelectedItem(); double amount = (Double)spnAmount.getValue() * 0.01D; double slippagePips = (Double)spnSlippagePips.getValue(); double stopLossPips = (Double)spnStopLossPips.getValue(); double takeProfitPips = (Double)spnTakeProfitPips.getValue(); long goodTillSec = (Long)spnGoodTillSec.getValue(); Calendar c = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); String label = orderCommand.toString() + sdf.format(c.getTime()); double stopLossPrice = 0.0D; double takeProfitPrice = 0.0D; if (orderCommand.isLong()) { if (stopLossPips > 0.0D) stopLossPrice = roundToPippette(price - stopLossPips * instrument.getPipValue(), instrument); if (takeProfitPips > 0.0D) takeProfitPrice = roundToPippette(price + takeProfitPips * instrument.getPipValue(), instrument); } else { if (stopLossPips > 0.0D) stopLossPrice = roundToPippette(price + stopLossPips * instrument.getPipValue(), instrument); if (takeProfitPips > 0.0D) takeProfitPrice = price - roundToPippette(takeProfitPips * instrument.getPipValue(), instrument); } long goodTillTime = 0L; if (goodTillSec > 0L) goodTillTime = System.currentTimeMillis() + goodTillSec * 1000; IOrder order = engine.submitOrder(label, instrument, orderCommand, amount, price, slippagePips, stopLossPrice, takeProfitPrice, goodTillTime); return order; } private double roundToPippette(double amount, Instrument instrument) { return round(amount, instrument.getPipScale() + 1); } private double round(double amount, int decimalPlaces) { return (new BigDecimal(amount)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).doubleValue(); } } //注文キャンセル public class CancelOpenedOrders implements Callable<CancelOpenedOrders> { public CancelOpenedOrders call() throws JFException { Instrument instrument = (Instrument)cmbInstrument.getSelectedItem(); for (IOrder o: engine.getOrders(instrument)) { if (o.getState() == IOrder.State.OPENED) { o.setRequestedAmount(0); } } return this; } } }
いたるところでrefresh()しててもっと綺麗に出来そうですがまぁそこはそれということでw
注意点
この方法でエントリーするレートを決めた場合、今より不利なレートで注文を出す可能性が出てきます。
具体的には
- 基準となる足の高値よりも高い位置にレートがある場合のロング
- 基準となる足の安値よりも低い位置にレートがある場合のショート
がそうなるわけですが、この場合、注文を出すと成行として処理されるので注意が必要です。
不利なレートでも注文したい場合もあるので今回は不利なレートの場合は赤字にしています。
コメント