まめりうむ

WindowsからMacへ乗り換るためのネタをまとめたり好きなことをまとめたり。

*

JForexで注文画面を自作する(スプレッド表示と新規注文時のオプション)

      2017/06/06

スポンサーリンク

前回までで成行注文と全決済が出来るようになったので、今回はもう少し使い勝手を良くしたいと思います。

例によって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 &gt; 0.0D)
                stopLossPrice = roundToPippette(price - stopLossPips * instrument.getPipValue(), instrument);
            if (takeProfitPips &gt; 0.0D)
                takeProfitPrice = roundToPippette(price + takeProfitPips * instrument.getPipValue(), instrument);
        } else {
            if (stopLossPips &gt; 0.0D)
                stopLossPrice = roundToPippette(price + stopLossPips * instrument.getPipValue(), instrument);
            if (takeProfitPips &gt; 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;
        }
    }
}

 - FX, プログラミング

スポンサーリンク

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

  関連記事

JForexで約定履歴画面を自作する

MT4もそうなんですけど、JForexも多くの国内業者に比べて約定履歴が見にくい …

JForexで注文画面を自作する(成行注文と全決済)

まずは成行注文と全決済が出来るようにしたいと思います。 GUIのパーツはEcli …

Pythonでニコ生アラートを作る(放送通知サーバへの接続情報を使ってsocket接続)

前回の続きです。 今回は、前回得られた放送通知サーバへの接続情報を使ってsock …

Pythonのwith文

このところ興味の矛先がPythonからRaspberry Piに移りつつあります …

JForexで注文画面を自作する(ブレイクアウト注文)

前回まででカンタンですが結構使い勝手の良い指値・逆指値注文まで出来ました。 今回 …

リーダブルコードを読みました

ひょんなことからクオカード1,000円分が手に入ったので、前から読んでみたかった …

Pythonスタートブックを読みました

Sublime Text3きっかけで、前からちょっと触ってみたいなと思ってたスク …

[Python]try~finally文中でreturn文を使ったときの動作

Pythonドキュメントの日本語訳を読んでて気付いたんですが return によ …

Sublime Text3でPython開発環境を整えるためにインストールしたパッケージと設定

Sublime Text3でPythonのお勉強をするのに役立ちそうなパッケージ …

Pythonでニコ生アラートを作る(放送通知サーバをクラス化する)

前回までのスクリプトでニコ生の放送通知を受け取ることが出来たので、今回はもう少し …