前回までで成行注文と全決済が出来るようになったので、今回はもう少し使い勝手を良くしたいと思います。
例によってGUIのパーツはEclipseとWindowBuilderでちゃちゃっと作ってこんな感じに。
スプレッド表示
public void onTick(final Instrument instrument, final ITick tick) throws JFException {
if (!cmbInstrument.getSelectedItem().equals(instrument)) return;</p>
final String scaleFormat = "%." + String.valueOf(instrument.getPipScale() + 1) + "f";
SwingUtilities.invokeLater(new Runnable () {
public void run() {
btnBid.setText(String.format(scaleFormat, tick.getBid()));
btnAsk.setText(String.format(scaleFormat, tick.getAsk()));
double spread = (tick.getAsk() - tick.getBid()) / instrument.getPipValue();
lblSpread.setText(String.format("%.1f", spread));
}
});
}
前回つけるのを忘れてましたw
やることはボタンへのレート表示と大差ないので説明は省略します。
エントリーオプション
新規注文はIEngine.submitOrderメソッドで行うわけですが、スリッページを設定しない場合、デフォルトで5pipsのスリッページが設定されてしまいます。
なので、任意に設定できるようにします。
また、新規注文時に指値と逆指値も設定できた方が便利ですので、コチラも同時に実装します。
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();
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);
}
IOrder order = engine.submitOrder(label, instrument, orderCommand, amount, price, slippagePips, stopLossPrice, takeProfitPrice);
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();
}
}
スリッページが0の場合はデフォルトの5pipsではなくスリッページなしでの注文となりますので弾かれやすくなります。
指値・逆指値が0の場合は設定しないのと同じことになります。
あと、指値・逆指値を設定する際、pipsからレートに換算し直すところで誤差が生じる可能性があり、一応丸めるようにしています。
全コード
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.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.ArrayList;
import java.util.Calendar;
import java.util.List;
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 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.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.Period;
public class SimpleOrder02 extends JFrame implements IStrategy {
private IEngine engine;
private IConsole console;
private IContext context;
private JButton btnAsk;
private JButton btnBid;
private JLabel lblAmount;
private JLabel lblAsk;
private JLabel lblBid;
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 btnCloseAll;
private JLabel lblSlippagePips;
private JSpinner spnSlippagePips;
private JLabel lblSpread;
public SimpleOrder02() {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
try {
onStop();
} catch (JFException e1) {
e1.printStackTrace();
}
}
});
setResizable(false);
setTitle("SimpleOrder");
setBounds(100, 100, 280, 320);
setLocationRelativeTo(null);
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[] {200};
gridBagLayout.rowHeights = new int[] {40, 60, 60};
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};
gbl_pnlAmount.columnWeights = new double[]{0.0, 1.0, 0.0};
pnlAmount.setLayout(gbl_pnlAmount);
cmbInstrument = new JComboBox(getInstruments().toArray());
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, 40, 80};
gbl_pnlOrder.rowHeights = new int[] {30, 30, 30};
pnlOrder.setLayout(gbl_pnlOrder);
lblBid = new JLabel("Bid(SELL)");
lblBid.setForeground(Color.RED);
lblBid.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc_lblBid = new GridBagConstraints();
gbc_lblBid.fill = GridBagConstraints.BOTH;
gbc_lblBid.gridx = 0;
gbc_lblBid.gridy = 0;
pnlOrder.add(lblBid, gbc_lblBid);
lblAsk = new JLabel("Ask(BUY)");
lblAsk.setForeground(Color.BLUE);
lblAsk.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc_lblAsk = new GridBagConstraints();
gbc_lblAsk.fill = GridBagConstraints.BOTH;
gbc_lblAsk.gridx = 2;
gbc_lblAsk.gridy = 0;
pnlOrder.add(lblAsk, gbc_lblAsk);
btnBid = new JButton();
btnBid.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.SELL, price));
}
});
GridBagConstraints gbc_btnBid = new GridBagConstraints();
gbc_btnBid.fill = GridBagConstraints.BOTH;
gbc_btnBid.gridx = 0;
gbc_btnBid.gridy = 1;
pnlOrder.add(btnBid, gbc_btnBid);
btnAsk = new JButton();
btnAsk.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.BUY, price));
}
});
lblSpread = new JLabel();
lblSpread.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc_lblSpread = new GridBagConstraints();
gbc_lblSpread.fill = GridBagConstraints.BOTH;
gbc_lblSpread.gridx = 1;
gbc_lblSpread.gridy = 1;
pnlOrder.add(lblSpread, gbc_lblSpread);
GridBagConstraints gbc_btnAsk = new GridBagConstraints();
gbc_btnAsk.fill = GridBagConstraints.BOTH;
gbc_btnAsk.gridx = 2;
gbc_btnAsk.gridy = 1;
pnlOrder.add(btnAsk, gbc_btnAsk);
btnCloseAll = new JButton();
btnCloseAll.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
context.executeTask(new CloseOrders());
}
});
btnCloseAll.setText("Close All");
GridBagConstraints gbc_btnCloseAll = new GridBagConstraints();
gbc_btnCloseAll.gridwidth = 3;
gbc_btnCloseAll.fill = GridBagConstraints.BOTH;
gbc_btnCloseAll.gridx = 0;
gbc_btnCloseAll.gridy = 2;
pnlOrder.add(btnCloseAll, gbc_btnCloseAll);
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};
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);
}
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.");
}
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(final 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() {
btnBid.setText(String.format(scaleFormat, tick.getBid()));
btnAsk.setText(String.format(scaleFormat, tick.getAsk()));
double spread = (tick.getAsk() - tick.getBid()) / instrument.getPipValue();
lblSpread.setText(String.format("%.1f", spread));
}
});
}
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
}
//通貨ペア
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 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();
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);
}
IOrder order = engine.submitOrder(label, instrument, orderCommand, amount, price, slippagePips, stopLossPrice, takeProfitPrice);
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();
}
}
//全決済注文
private class CloseOrders implements Callable<CloseOrders> {
public CloseOrders call() throws JFException {
Instrument instrument = (Instrument)cmbInstrument.getSelectedItem();
List<IOrder> orders = new ArrayList<IOrder>();
for (IOrder o: engine.getOrders()) {
if (o.getState().equals(IOrder.State.FILLED) && o.getInstrument().equals(instrument)) {
orders.add(o);
}
}
engine.closeOrders(orders);
return this;
}
}
}




コメント