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

FX

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

なので、簡易版ですが国内業者チックな見やすい約定履歴画面を自作したいと思います。

例によってGUIのパーツはEclipseとWindowBuilderでちゃちゃっと作ってます。

決済し終わったトレード

JForexでは未決済(保有中、待機中)のトレードと決済し終わったトレードは別々に管理されています。

未決済のトレードについてはIEngine.getOrders()メソッドなどで、決済し終わったトレードについてはIHistory.getHistory()メソッドで取得出来ます。

今回は取得期間を指定するようにして

private void fetchOrderHistory(Date startDt, Date stopDt) {
    orders.clear();

    IHistory history;
    Instrument instrument = (Instrument)cmbInstruments.getSelectedItem();
    try {
        history = context.getHistory();
        for (IOrder o: history.getOrdersHistory(instrument, startDt.getTime(), stopDt.getTime()))
            orders.add(o);
    } catch (JFException e) {
        e.printStackTrace();
    }
    //新規約定日時でソート
    class FillTimeComparator implements Comparator {
        @Override
        public int compare(IOrder o1, IOrder o2) {
            return o1.getFillTime() < o2.getFillTime() ? -1: 1;
        }
    }
    Collections.sort(orders, new FillTimeComparator());
}

こんな感じにしてます。

実際に取得してみると順序がバラバラなので一応ソートもしておきました。

全コード

package jforex;

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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
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.Period;

public class ClosedOrder01 extends JFrame implements IStrategy {
    private IContext context;
    private IConsole console;

    private ArrayList orders = new ArrayList();
    private JComboBox cmbInstruments;
    private JFormattedTextField txtStartDt;
    private JFormattedTextField txtStopDt;
    private JButton btnOpen;
    private JTable tblHistory;
    private DefaultTableModel tableModel;
    private JTextField txtAmountTotal;
    private JTextField txtTpTotal;
    private JTextField txtPipsTotal;

    public ClosedOrder01() {
        frameInitialize();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                try {
                    onStop();
                } catch (JFException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }

    private void frameInitialize() {
        setTitle("約定履歴");
        setBounds(100, 100, 850, 510);
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[] {900};
        gridBagLayout.rowHeights = new int[] {30, 400, 30};
        gridBagLayout.columnWeights = new double[]{1.0};
        gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
        getContentPane().setLayout(gridBagLayout);

        JPanel pnlButton = new JPanel();
        GridBagConstraints gbc_pnlButton = new GridBagConstraints();
        gbc_pnlButton.fill = GridBagConstraints.BOTH;
        gbc_pnlButton.anchor = GridBagConstraints.NORTH;
        gbc_pnlButton.insets = new Insets(5, 0, 5, 0);
        gbc_pnlButton.gridx = 0;
        gbc_pnlButton.gridy = 0;
        getContentPane().add(pnlButton, gbc_pnlButton);
        GridBagLayout gbl_pnlButton = new GridBagLayout();
        gbl_pnlButton.columnWidths = new int[] {100, 50, 100, 50, 100, 100, 100};
        gbl_pnlButton.rowHeights = new int[] {30};
        pnlButton.setLayout(gbl_pnlButton);

        btnOpen = new JButton("表示");
        btnOpen.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

                Date startDt = null;
                Date stopDt = null;
                try {
                    startDt = sdf.parse(txtStartDt.getText());
                    stopDt = sdf.parse(txtStopDt.getText());
                } catch (ParseException e1) {
                    e1.printStackTrace();
                }
                if (startDt != null && stopDt != null) {
                    fetchOrderHistory(startDt, stopDt);
                    setOrderHistory();
                }
            }
        });

        cmbInstruments = new JComboBox(getInstruments().toArray());
        GridBagConstraints gbc_cmbboxInstruments = new GridBagConstraints();
        gbc_cmbboxInstruments.fill = GridBagConstraints.BOTH;
        gbc_cmbboxInstruments.gridx = 0;
        gbc_cmbboxInstruments.gridy = 0;
        pnlButton.add(cmbInstruments, gbc_cmbboxInstruments);

        JLabel lblStartDt = new JLabel("開始:");
        lblStartDt.setHorizontalAlignment(SwingConstants.RIGHT);
        GridBagConstraints gbc_lblStartDt = new GridBagConstraints();
        gbc_lblStartDt.fill = GridBagConstraints.BOTH;
        gbc_lblStartDt.gridx = 1;
        gbc_lblStartDt.gridy = 0;
        pnlButton.add(lblStartDt, gbc_lblStartDt);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Calendar calendar = Calendar.getInstance();

        calendar.add(Calendar.DAY_OF_MONTH, 0);

        txtStartDt = new JFormattedTextField(sdf);
        txtStartDt.setHorizontalAlignment(SwingConstants.CENTER);
        txtStartDt.setText(sdf.format(calendar.getTime()));
        GridBagConstraints gbc_txtStartDt = new GridBagConstraints();
        gbc_txtStartDt.fill = GridBagConstraints.BOTH;
        gbc_txtStartDt.gridx = 2;
        gbc_txtStartDt.gridy = 0;
        pnlButton.add(txtStartDt, gbc_txtStartDt);

        JLabel lblStopDt = new JLabel("終了:");
        lblStopDt.setHorizontalAlignment(SwingConstants.RIGHT);
        GridBagConstraints gbc_lblStopDt = new GridBagConstraints();
        gbc_lblStopDt.fill = GridBagConstraints.BOTH;
        gbc_lblStopDt.gridx = 3;
        gbc_lblStopDt.gridy = 0;
        pnlButton.add(lblStopDt, gbc_lblStopDt);

        calendar.add(Calendar.DAY_OF_MONTH, 1);

        txtStopDt = new JFormattedTextField(sdf);
        txtStopDt.setHorizontalAlignment(SwingConstants.CENTER);
        txtStopDt.setText(sdf.format(calendar.getTime()));
        GridBagConstraints gbc_txtStopDt = new GridBagConstraints();
        gbc_txtStopDt.fill = GridBagConstraints.BOTH;
        gbc_txtStopDt.gridx = 4;
        gbc_txtStopDt.gridy = 0;
        pnlButton.add(txtStopDt, gbc_txtStopDt);
        GridBagConstraints gbc_btnOpen = new GridBagConstraints();
        gbc_btnOpen.insets = new Insets(0, 5, 0, 5);
        gbc_btnOpen.fill = GridBagConstraints.BOTH;
        gbc_btnOpen.gridx = 5;
        gbc_btnOpen.gridy = 0;
        pnlButton.add(btnOpen, gbc_btnOpen);

        JScrollPane scrollPane = new JScrollPane();
        GridBagConstraints gbc_scrollPane = new GridBagConstraints();
        gbc_scrollPane.weighty = 1.0;
        gbc_scrollPane.weightx = 1.0;
        gbc_scrollPane.fill = GridBagConstraints.BOTH;
        gbc_scrollPane.gridx = 0;
        gbc_scrollPane.gridy = 1;
        getContentPane().add(scrollPane, gbc_scrollPane);


        Object[] colName = {"新規約定日時","決済約定日時","通貨ペア","新規売買","Lot数","新規約定値","決済約定値","損益pips","損益","ID"};
        tableModel = new DefaultTableModel(colName, 0);

        tblHistory = new JTable(tableModel);
        tblHistory.setRowSorter(new TableRowSorter(tableModel));
        tblHistory.setEnabled(false);
        tblHistory.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        scrollPane.setViewportView(tblHistory);

        JPanel pnlSummary = new JPanel();
        GridBagConstraints gbc_pnlSummary = new GridBagConstraints();
        gbc_pnlSummary.insets = new Insets(5, 0, 5, 0);
        gbc_pnlSummary.anchor = GridBagConstraints.SOUTH;
        gbc_pnlSummary.gridx = 0;
        gbc_pnlSummary.gridy = 2;
        getContentPane().add(pnlSummary, gbc_pnlSummary);
        GridBagLayout gbl_pnlSummary = new GridBagLayout();
        gbl_pnlSummary.columnWidths = new int[] {100, 100, 100, 100, 100, 100};
        gbl_pnlSummary.rowHeights = new int[] {30};
        pnlSummary.setLayout(gbl_pnlSummary);

        JLabel lblAmountTotal = new JLabel("Lot数合計:");
        lblAmountTotal.setHorizontalAlignment(SwingConstants.RIGHT);
        GridBagConstraints gbc_lblAmountTotal = new GridBagConstraints();
        gbc_lblAmountTotal.fill = GridBagConstraints.BOTH;
        gbc_lblAmountTotal.gridx = 0;
        gbc_lblAmountTotal.gridy = 0;
        pnlSummary.add(lblAmountTotal, gbc_lblAmountTotal);

        txtAmountTotal = new JTextField();
        txtAmountTotal.setHorizontalAlignment(SwingConstants.CENTER);
        GridBagConstraints gbc_txtAmountTotal = new GridBagConstraints();
        gbc_txtAmountTotal.fill = GridBagConstraints.BOTH;
        gbc_txtAmountTotal.gridx = 1;
        gbc_txtAmountTotal.gridy = 0;
        pnlSummary.add(txtAmountTotal, gbc_txtAmountTotal);
        txtAmountTotal.setColumns(10);

        JLabel lblTpTotal = new JLabel("損益合計:");
        lblTpTotal.setHorizontalAlignment(SwingConstants.RIGHT);
        GridBagConstraints gbc_lblTpTotal = new GridBagConstraints();
        gbc_lblTpTotal.fill = GridBagConstraints.BOTH;
        gbc_lblTpTotal.gridx = 2;
        gbc_lblTpTotal.gridy = 0;
        pnlSummary.add(lblTpTotal, gbc_lblTpTotal);

        txtTpTotal = new JTextField();
        txtTpTotal.setHorizontalAlignment(SwingConstants.CENTER);
        txtTpTotal.setColumns(10);
        GridBagConstraints gbc_txtTpTotal = new GridBagConstraints();
        gbc_txtTpTotal.fill = GridBagConstraints.BOTH;
        gbc_txtTpTotal.gridx = 3;
        gbc_txtTpTotal.gridy = 0;
        pnlSummary.add(txtTpTotal, gbc_txtTpTotal);

        JLabel lblPipsTotal = new JLabel("pips合計:");
        lblPipsTotal.setHorizontalAlignment(SwingConstants.RIGHT);
        GridBagConstraints gbc_lblPipsTotal = new GridBagConstraints();
        gbc_lblPipsTotal.fill = GridBagConstraints.BOTH;
        gbc_lblPipsTotal.gridx = 4;
        gbc_lblPipsTotal.gridy = 0;
        pnlSummary.add(lblPipsTotal, gbc_lblPipsTotal);

        txtPipsTotal = new JTextField();
        txtPipsTotal.setHorizontalAlignment(SwingConstants.CENTER);
        txtPipsTotal.setColumns(10);
        GridBagConstraints gbc_txtPipsTotal = new GridBagConstraints();
        gbc_txtPipsTotal.fill = GridBagConstraints.BOTH;
        gbc_txtPipsTotal.gridx = 5;
        gbc_txtPipsTotal.gridy = 0;
        pnlSummary.add(txtPipsTotal, gbc_txtPipsTotal);
}

    private void fetchOrderHistory(Date startDt, Date stopDt) {
        orders.clear();

        IHistory history;
        Instrument instrument = (Instrument)cmbInstruments.getSelectedItem();
        try {
            history = context.getHistory();
            for (IOrder o: history.getOrdersHistory(instrument, startDt.getTime(), stopDt.getTime()))
                orders.add(o);
        } catch (JFException e) {
            e.printStackTrace();
        }
        //新規約定日時でソート
        class FillTimeComparator implements Comparator {
            @Override
            public int compare(IOrder o1, IOrder o2) {
                return o1.getFillTime() < o2.getFillTime() ? -1: 1;
            }
        }
        Collections.sort(orders, new FillTimeComparator());
    }

    private void setOrderHistory() {

        DefaultTableModel model = (DefaultTableModel)tblHistory.getModel();
        model.setRowCount(0);

        double amountTotal = 0.0D;
        double tpTotal = 0.0D;
        double pipsTotal = 0.0D;

        for (IOrder o: orders) {

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            long fillTime = o.getFillTime();
            long closeTime = o.getCloseTime();
            Instrument instrument = o.getInstrument();
            String scaleFormat ="%." + String.valueOf(instrument.getPipScale() + 1) + "f";
            String entryOrderSide;
            entryOrderSide = o.isLong() ? "買" : "売";
            double amount = o.getAmount() * 100.0D;
            double openPrice = o.getOpenPrice();
            double closePrice = o.getClosePrice();
            double profitPips = o.getProfitLossInPips();
            double profitAmount = o.getProfitLossInAccountCurrency();


            tableModel.addRow(new Object[] {
                    sdf.format(fillTime),
                    sdf.format(closeTime),
                    instrument.toString(),
                    entryOrderSide,
                    String.format("%,.0f", amount),
                    String.format(scaleFormat, openPrice),
                    String.format(scaleFormat, closePrice),
                    String.format("%,.1f", profitPips),
                    String.format("%,.0f", profitAmount),
                    o.getId()});

            amountTotal += o.getAmount();
            tpTotal += o.getProfitLossInAccountCurrency();
            pipsTotal += o.getProfitLossInPips();
        }
        txtAmountTotal.setText(String.format("%,.2f", amountTotal));
        txtTpTotal.setText(String.format("%,.0f", tpTotal));
        txtPipsTotal.setText(String.format("%,.1f", pipsTotal));
    }

    @Override
    public void onStart(IContext context) throws JFException {
        this.context = context;
        console = context.getConsole();

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        console.getOut().println("Strategy Started.");
    }

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {
    }
    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    }
    @Override
    public void onMessage(IMessage message) throws JFException {
    }
    @Override
    public void onAccount(IAccount account) throws JFException {
    }
    @Override
    public void onStop() throws JFException {
        console.getOut().println("Strategy Stopped.");
    }
    //通貨ペア
    private final Vector getInstruments() {
        Vector instruments = new Vector();
        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;
    }
}

今までの注文画面と違いコールバック関数もほとんど使ってないので内容的には大したことないですねw

もっと綺麗なコーディングをしたいんですがスキルないのが悲しいです(;_;

コメント

タイトルとURLをコピーしました