Package com.archean.jtradegui

Source Code of com.archean.jtradegui.TraderMainForm

/*
* jCryptoTrader trading client
* Copyright (C) 2014 1M4SKfh83ZxsCSDmfaXvfCfMonFxMa5vvh (BTC public key)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/

package com.archean.jtradegui;

import com.archean.coinmarketcap.CoinMarketCapParser;
import com.archean.jautotrading.MarketRule;
import com.archean.jautotrading.RuleAction;
import com.archean.jautotrading.RuleCondition;
import com.archean.jtradeapi.*;
import com.jgoodies.forms.factories.CC;
import com.jgoodies.forms.layout.FormLayout;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.data.xy.OHLCDataItem;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

public class TraderMainForm extends JPanel {
    public volatile Map<String, MarketRule.MarketRuleList> ruleListDb = new HashMap<>();
    private volatile MarketRule.MarketRuleList ruleList;
    private volatile String currentPair = "";
    private double feePercent = 0.2;

    static private class ApiLag {
        long priceUpdated;
        long depthUpdated;
        long ordersUpdated;
        long marketHistoryUpdated;
        long accountHistoryUpdated;
        long balancesUpdated;
    }

    private ApiLag lastUpdated = new ApiLag();

    public ApiWorker worker = new ApiWorker();
    public Map<String, BaseTradeApi.StandartObjects.CurrencyPair> pairList = new TreeMap<>();
    static ResourceBundle locale = ResourceBundle.getBundle("com.archean.jtradegui.locale", new UTF8Control());
    private volatile boolean initialized = false;
    private volatile boolean needStepUpdate = true;
    private volatile List<HistoryUtils.Candle> candles = null;
    private final Object candlesLock = new Object();
    private Date lastChartUpdate = new Date(0);
    private volatile Map<String, Thread> threadMap = new HashMap<>();

    private void stopThreads(String[] threadNames) {
        for (String t : threadNames) {
            Thread thread = threadMap.get(t);
            if (thread != null && thread.isAlive()) {
                thread.interrupt();
                threadMap.remove(t);
            }
        }
    }

    public void stopWorker() {
        initialized = false;
        worker.stopAllThreads();
        CoinMarketCapParser.getWorker().removeEventHandler(System.identityHashCode(this));
    }

    public void startWorker() {
        initialized = true;
        setUpdateOptions();
        CoinMarketCapParser.getWorker().addEventHandler(System.identityHashCode(this), new CoinMarketCapParser.CoinMarketCapEvent() {
            @Override
            public void onDataUpdate(List<CoinMarketCapParser.CoinCapitalization> data) {
                updateMarketCap(data);
            }

            @Override
            public void onError(Exception e) {
                processException(e);
            }
        });
    }

    public void killThreads() {
        stopWorker();
        for (Thread thread : threadMap.values()) {
            thread.interrupt();
        }
        threadMap.clear();
    }

    public void setSettings(double feePercent, int timeInterval) {
        this.feePercent = feePercent;
        worker.setTimeInterval(timeInterval);
        spinnerUpdateInterval.setValue(timeInterval);
        spinnerFeePercent.setValue(feePercent);
    }

    public void setRuleListDb(Map<String, MarketRule.MarketRuleList> ruleListDb) {
        this.ruleListDb = ruleListDb;
        this.ruleList = ruleListDb.get(currentPair);
        if (ruleList == null) {
            ruleList = new MarketRule.MarketRuleList();
            ruleListDb.put(currentPair, ruleList);
        }
        refreshRulesTable();
    }

    private void initPair(String pairName) {
        this.currentPair = pairName;
        Object pairId = pairList.get(pairName).pairId;
        worker.setPair(pairId);
        ruleList = ruleListDb.get(pairName);
        if (ruleList == null) {
            ruleList = new MarketRule.MarketRuleList();
            ruleListDb.put(pairName, ruleList);
        }
        ruleList.callback = new MarketRule.MarketRuleList.MarketRuleListCallback() {
            @Override
            public void onSuccess(MarketRule rule) {
                processNotification(String.format(locale.getString("RuleExecuted.notification.template"), formatMarketConditionString(rule.condition), formatMarketActionString(rule.action)));
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        refreshRulesTable();
                    }
                });
            }

            @Override
            public void onError(Exception e) {
                processException(new Exception("Rule execution error: " + e.getMessage()));
            }
        };
        clearMarketData();
    }

    public void setPair(final String pairName) {
        stopWorker();
        comboBoxPair.setSelectedItem(pairName);
        initPair(pairName);
        startWorker();
    }

    public Map<String, Object> getSettings() {
        Map<String, Object> settings = new HashMap<>();
        settings.put("timeInterval", spinnerUpdateInterval.getValue());
        settings.put("feePercent", feePercent);
        settings.put("currentPair", currentPair);
        settings.put("marketRuleListDb", ruleListDb);
        return settings;
    }

    protected void processError(final String excString) {
        TrayIconController.showMessage(locale.getString("notification.error.title"), excString, TrayIcon.MessageType.ERROR);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                StyledDocument document = textPaneLog.getStyledDocument();
                SimpleAttributeSet errorStyle = new SimpleAttributeSet();
                StyleConstants.setForeground(errorStyle, Color.RED);
                StyleConstants.setBold(errorStyle, true);
                try {
                    document.insertString(document.getLength(), excString + "\n", errorStyle);
                } catch (BadLocationException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }

    protected void processException(final Exception e) {
        e.printStackTrace();
        this.processError(e.getLocalizedMessage());
    }

    protected void processNotification(final String notification) {
        TrayIconController.showMessage(locale.getString("notification.info.title"), notification, TrayIcon.MessageType.INFO);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                StyledDocument document = textPaneLog.getStyledDocument();
                SimpleAttributeSet notificationStyle = new SimpleAttributeSet();
                StyleConstants.setForeground(notificationStyle, Color.BLUE);
                StyleConstants.setItalic(notificationStyle, true);
                try {
                    document.insertString(document.getLength(), notification + "\n", notificationStyle);
                } catch (BadLocationException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }

    protected String getCurrentPrimaryCurrency() {
        return pairList.get(comboBoxPair.getSelectedItem()).firstCurrency;
    }

    protected String getCurrentSecondaryCurrency() {
        return pairList.get(comboBoxPair.getSelectedItem()).secondCurrency;
    }

    protected double getCurrentPrimaryBalance() {
        return worker.accountInfo.balance.getBalance(getCurrentPrimaryCurrency());
    }

    protected double getCurrentSecondaryBalance() {
        return worker.accountInfo.balance.getBalance(getCurrentSecondaryCurrency());
    }

    protected void updateLabelTotal() {
        if (tabbedPaneTrade.getSelectedIndex() == 0) { // Buy
            double balance = getCurrentSecondaryBalance();
            double enteredTotal = Calculator.totalWithFee(BaseTradeApi.Constants.ORDER_BUY, (Double) spinnerBuyOrderPrice.getValue(), (Double) spinnerBuyOrderAmount.getValue(), feePercent);
            labelBuyOrderTotalValue.setText(Utils.Strings.formatNumber(enteredTotal) + " / " + Utils.Strings.formatNumber(balance) + " " + getCurrentSecondaryCurrency());
            if (enteredTotal > balance) {
                labelBuyOrderTotalValue.setForeground(Color.RED);
            } else {
                labelBuyOrderTotalValue.setForeground(Color.BLACK);
            }
        } else { // Sell
            double balance = getCurrentPrimaryBalance(),
                    amount = (Double) spinnerSellOrderAmount.getValue(),
                    enteredTotal = Calculator.totalWithFee(BaseTradeApi.Constants.ORDER_SELL, (Double) spinnerSellOrderPrice.getValue(), (Double) spinnerSellOrderAmount.getValue(), feePercent);

            labelSellOrderTotalValue.setText(Utils.Strings.formatNumber(amount) + " / " + Utils.Strings.formatNumber(balance) + " " + getCurrentPrimaryCurrency() + " (" + Utils.Strings.formatNumber(enteredTotal) + " " + getCurrentSecondaryCurrency() + ")");
            if (amount > balance) {
                labelSellOrderTotalValue.setForeground(Color.RED);
            } else {
                labelSellOrderTotalValue.setForeground(Color.BLACK);
            }
        }
    }

    private void sliderBuyOrderAmountStateChanged(ChangeEvent e) {
        double balance = getCurrentSecondaryBalance(), price = (Double) spinnerBuyOrderPrice.getValue(), percent = sliderBuyOrderAmount.getValue();
        if (price > 0 && percent > 0 && balance > 0) {
            double amount = Calculator.balancePercentAmount(balance, percent, BaseTradeApi.Constants.ORDER_BUY, price, feePercent);
            spinnerBuyOrderAmount.setValue(amount);
        }
    }

    private void sliderSellOrderAmountStateChanged(ChangeEvent e) {
        double balance = getCurrentPrimaryBalance(), percent = sliderSellOrderAmount.getValue();
        double amount = Calculator.balancePercentAmount(balance, percent, BaseTradeApi.Constants.ORDER_SELL, 0, 0);
        spinnerSellOrderAmount.setValue(amount);
    }

    protected void clearMarketData() {
        ((DefaultTableModel) tableAccountHistory.getModel()).setRowCount(0);
        ((DefaultTableModel) tableMarketHistory.getModel()).setRowCount(0);
        ((DefaultTableModel) tableBuyOrders.getModel()).setRowCount(0);
        ((DefaultTableModel) tableSellOrders.getModel()).setRowCount(0);
        ((DefaultTableModel) tableOpenOrders.getModel()).setRowCount(0);
        spinnerBuyOrderPrice.setValue(0.0);
        spinnerSellOrderPrice.setValue(0.0);
        textFieldAvgPrice.setText("");
        textFieldBuyPrice.setText("");
        textFieldSellPrice.setText("");
        textFieldHighPrice.setText("");
        textFieldLowPrice.setText("");
        textFieldLastPrice.setText("");
        textFieldVolume.setText("");
        needStepUpdate = true;
        synchronized (candlesLock) {
            candles = null;
            lastChartUpdate = new Date(0);
        }
        refreshRulesTable();
    }

    public void initMarket(AccountManager.Account account) {
        stopWorker();
        worker.initTradeApiInstance(account);
        try {
            pairList = worker.tradeApi.getCurrencyPairs().makeNameInfoMap();
            DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
            for (Map.Entry<String, BaseTradeApi.StandartObjects.CurrencyPair> entry : pairList.entrySet()) {
                model.addElement(entry.getKey());
            }
            comboBoxPair.setModel(model);
            comboBoxPair.setSelectedIndex(0);
            BaseTradeApi.StandartObjects.CurrencyPair firstPair = ((TreeMap<String, BaseTradeApi.StandartObjects.CurrencyPair>) pairList).firstEntry().getValue();
            initPair(firstPair.pairName);
            worker.setTimeInterval((Integer) spinnerUpdateInterval.getValue());
            feePercent = worker.tradeApi.getFeePercent(firstPair.pairId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // GUI MVC functions
    private void drawChart(OHLCDataItem[] dataset) {
        final ChartPanel chartPanel = CandleChart.initOHLCChart(CandleChart.Parameters.builder()
                .numberFormat(Utils.Strings.moneyFormat.toDecimalFormat())
                .dateFormat(new SimpleDateFormat())
                .labelX(locale.getString("Chart.legend.time.string"))
                .labelY(locale.getString("Chart.legend.price.string"))
                .title(currentPair).build(), dataset);
        // chartPanel.setPreferredSize(new Dimension(600, 300));
        chartPanel.addChartMouseListener(new ChartMouseListener() {
            @Override
            public void chartMouseClicked(ChartMouseEvent chartMouseEvent) {
                if(chartMouseEvent.getTrigger().getClickCount() >= 2) {
                    popupMenuTimeframe.show((Component) chartMouseEvent.getTrigger().getSource(), chartMouseEvent.getTrigger().getX(), chartMouseEvent.getTrigger().getY());
                }
            }

            @Override
            public void chartMouseMoved(ChartMouseEvent chartMouseEvent) {
                // nothing
            }
        });
        tabbedPaneInfo.setComponentAt(4, chartPanel);
    }

    private OHLCDataItem[] ohlcDataCache = null;
    private volatile long chartPeriod = HistoryUtils.PERIOD_30M;
    private void clearChartData() {
        synchronized (candlesLock) {
            candles = null;
            ohlcDataCache = null;
            lastChartUpdate = new Date(0);
        }
    }
    private void setChartPeriod(long newPeriod) {
        chartPeriod = newPeriod;
        clearChartData();
    }
    private void updateChart(List<HistoryUtils.Candle> candles) {
        if (candles == null || candles.isEmpty()) return;
        HistoryUtils.Candle lastCandle = candles.get(candles.size() - 1);
        if (lastCandle.update == null || !lastChartUpdate.before(lastCandle.update)) {
            return;
        } else {
            lastChartUpdate = lastCandle.update;
        }
        ohlcDataCache = CandleChart.updateOHLCDataArray(ohlcDataCache, candles);
        if (ohlcDataCache != null && ohlcDataCache.length > 0) {
            if (tabbedPaneInfo.getComponentAt(4) instanceof ChartPanel) {
                CandleChart.updateOHLCChart((ChartPanel) tabbedPaneInfo.getComponentAt(4), currentPair, ohlcDataCache);
            } else {
                drawChart(ohlcDataCache);
            }
        }
    }

    private void setPrice(final JTextField field, double newValue) {
        String oldValue = field.getText();
        if (oldValue.equals("")) {
            field.setText(Utils.Strings.formatNumber(newValue));
            field.setBackground(new Color(240, 240, 240)); // Default color
        } else {
            double oldPrice = Double.parseDouble(oldValue);
            if (oldPrice != newValue) {
                field.setText(Utils.Strings.formatNumber(newValue));
                field.setBackground(newValue > oldPrice ? Color.GREEN : Color.RED);
            }
        }
    }

    private void updatePrices(final BaseTradeApi.StandartObjects.Prices price) {
        lastUpdated.priceUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                setPrice(textFieldLastPrice, price.last);
                setPrice(textFieldLowPrice, price.low);
                setPrice(textFieldHighPrice, price.high);
                setPrice(textFieldAvgPrice, price.average);
                setPrice(textFieldBuyPrice, price.buy);
                setPrice(textFieldSellPrice, price.sell);
                setPrice(textFieldVolume, price.volume);

                if (needStepUpdate) {
                    if (spinnerBuyOrderPrice.getValue().equals(0.0)) {
                        spinnerBuyOrderPrice.setValue(price.buy);
                    }
                    if (spinnerSellOrderPrice.getValue().equals(0.0)) {
                        spinnerSellOrderPrice.setValue(price.sell);
                    }
                    double stepSize = price.buy / 100.0;
                    if (stepSize < Calculator.MINIMAL_AMOUNT) stepSize = Calculator.MINIMAL_AMOUNT;
                    ((SpinnerNumberModel) spinnerBuyOrderPrice.getModel()).setStepSize(stepSize);
                    ((SpinnerNumberModel) spinnerBuyOrderAmount.getModel()).setStepSize(getCurrentSecondaryBalance() * 0.01 / price.buy);

                    stepSize = price.sell / 100.0;
                    if (stepSize < Calculator.MINIMAL_AMOUNT) stepSize = Calculator.MINIMAL_AMOUNT;
                    ((SpinnerNumberModel) spinnerSellOrderPrice.getModel()).setStepSize(stepSize);
                    ((SpinnerNumberModel) spinnerSellOrderAmount.getModel()).setStepSize(getCurrentPrimaryBalance() * 0.01);
                    updateLabelTotal();
                    needStepUpdate = false;
                }
            }
        });
        ruleList.checkRules(worker);
    }

    private void updateDepth(final BaseTradeApi.StandartObjects.Depth depth) {
        lastUpdated.depthUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                DefaultTableModel model = (DefaultTableModel) tableBuyOrders.getModel();
                model.setRowCount(depth.buyOrders.size());
                int i = 0;
                for (BaseTradeApi.StandartObjects.Order order : depth.buyOrders) {
                    model.setValueAt(order.price, i, 0);
                    model.setValueAt(order.amount, i, 1);
                    i++;
                }
                model.fireTableDataChanged();

                model = (DefaultTableModel) tableSellOrders.getModel();
                model.setRowCount(depth.sellOrders.size());
                i = 0;
                for (BaseTradeApi.StandartObjects.Order order : depth.sellOrders) {
                    model.setValueAt(order.price, i, 0);
                    model.setValueAt(order.amount, i, 1);
                    i++;
                }
                model.fireTableDataChanged();
            }
        });
    }

    private void updateMarketHistory(final List<BaseTradeApi.StandartObjects.Order> history) {
        lastUpdated.marketHistoryUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                DefaultTableModel model = (DefaultTableModel) tableMarketHistory.getModel();
                model.setRowCount(history.size());
                for (BaseTradeApi.StandartObjects.Order order : history) {
                    model.setValueAt(order.time, i, 0);
                    model.setValueAt(locale.getString(order.type == BaseTradeApi.Constants.ORDER_SELL ? "sell.text" : "buy.text"), i, 1);
                    model.setValueAt(order.price, i, 2);
                    model.setValueAt(order.amount, i, 3);
                    model.setValueAt(Calculator.totalWithFee(order.type, order.price, order.amount, feePercent), i, 4);
                    i++;
                }
                model.fireTableDataChanged();
            }
        });

        synchronized (candlesLock) {
            // Update chart:
            if (candles == null) {
                candles = HistoryUtils.buildCandles(history, HistoryUtils.timeDelta(Calendar.DAY_OF_MONTH, -1), chartPeriod);
            } else {
                HistoryUtils.refreshCandles(candles, history, HistoryUtils.timeDelta(Calendar.DAY_OF_MONTH, -1), chartPeriod);
            }
            if (tabbedPaneInfo.getComponentAt(4).isVisible()) updateChart(candles);

            // Price change 1h %:
            HistoryUtils.Candle candle = HistoryUtils.getNearestCandle(candles, HistoryUtils.timeDelta(Calendar.HOUR_OF_DAY, -1));
            if(candle == null) {
                labelPriceChangePercent.setText("???");
                labelPriceChangePercent.setForeground(Color.BLUE);
            } else {
                labelPriceChangePercent.setToolTipText(String.format("%s -> %s", Utils.Strings.formatNumber(candle.open), Utils.Strings.formatNumber(worker.marketInfo.price.last)));
                double percent = Calculator.priceChangePercent(candle.open, worker.marketInfo.price.last);
                labelPriceChangePercent.setText(Utils.Strings.formatNumber(percent, Utils.Strings.percentDecimalFormat) + "%");
                if (percent > 0)
                    labelPriceChangePercent.setForeground(Color.GREEN);
                else
                    labelPriceChangePercent.setForeground(Color.RED);
            }
        }
    }

    private void updateAccountHistory(final List<BaseTradeApi.StandartObjects.Order> history) {
        lastUpdated.accountHistoryUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                DefaultTableModel model = (DefaultTableModel) tableAccountHistory.getModel();
                model.setRowCount(history.size());
                for (BaseTradeApi.StandartObjects.Order order : history) {
                    model.setValueAt(order.time, i, 0);
                    model.setValueAt(locale.getString(order.type == BaseTradeApi.Constants.ORDER_SELL ? "sell.text" : "buy.text"), i, 1);
                    model.setValueAt(order.price, i, 2);
                    model.setValueAt(order.amount, i, 3);
                    model.setValueAt(Calculator.totalWithFee(order.type, order.price, order.amount, feePercent), i, 4);
                    i++;
                }
                model.fireTableDataChanged();
            }
        });
    }

    private void updateOpenOrders(final List<BaseTradeApi.StandartObjects.Order> orders) {
        lastUpdated.ordersUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                synchronized (tableOpenOrders) {
                    DefaultTableModel model = (DefaultTableModel) tableOpenOrders.getModel();
                    model.setRowCount(orders.size());
                    for (BaseTradeApi.StandartObjects.Order order : orders) {
                        model.setValueAt(order.id, i, 0); // ID
                        model.setValueAt(locale.getString(order.type == BaseTradeApi.Constants.ORDER_SELL ? "sell.text" : "buy.text"), i, 1); // Type
                        model.setValueAt(order.price, i, 2); // Price
                        model.setValueAt(order.amount, i, 3); // Amount
                        model.setValueAt(Calculator.totalWithFee(order.type, order.price, order.amount, feePercent), i, 4); // Total
                        i++;
                    }
                    model.fireTableDataChanged();
                }
            }
        });
    }

    private void updateAccountBalances(final Map<String, Double> balances) {
        lastUpdated.balancesUpdated = System.currentTimeMillis();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                DefaultTableModel model = (DefaultTableModel) tableBalances.getModel();
                model.setRowCount(balances.size());
                for (Map.Entry<String, Double> balance : balances.entrySet()) {
                    model.setValueAt(balance.getKey(), i, 0); // Currency name
                    model.setValueAt(balance.getValue(), i, 1); // Amount
                    i++;
                }
                model.fireTableDataChanged();
                updateLabelTotal();
            }
        });
    }

    private void updateMarketCap(final List<CoinMarketCapParser.CoinCapitalization> capitalizationList) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                DefaultTableModel model = (DefaultTableModel) tableMarketCap.getModel();
                model.setRowCount(capitalizationList.size());
                for (CoinMarketCapParser.CoinCapitalization capitalization : capitalizationList) {
                    model.setValueAt(i + 1, i, 0);
                    model.setValueAt(String.format("%s (%s)", capitalization.coinName, capitalization.coinCode), i, 1); // Currency name
                    model.setValueAt(capitalization.usdCap, i, 2); // USD cap
                    model.setValueAt(capitalization.btcCap, i, 3); // BTC cap
                    model.setValueAt(capitalization.usdVolume, i, 4); // USD volume
                    model.setValueAt(capitalization.btcVolume, i, 5); // BTC volume
                    model.setValueAt(capitalization.change, i, 6); // Change (24h)
                    i++;
                }
                model.fireTableDataChanged();
            }
        });
    }

    private final ApiWorker.ApiDataUpdateEvent apiWorkerEventHandler = new ApiWorker.ApiDataUpdateEvent() {
        @Override
        public void onMarketPricesUpdate(BaseTradeApi.StandartObjects.Prices data) {
            updatePrices(data);
        }

        @Override
        public void onMarketDepthUpdate(BaseTradeApi.StandartObjects.Depth data) {
            updateDepth(data);
        }

        @Override
        public void onMarketHistoryUpdate(List<BaseTradeApi.StandartObjects.Order> data) {
            updateMarketHistory(data);
        }

        @Override
        public void onAccountBalancesUpdate(BaseTradeApi.StandartObjects.AccountInfo.AccountBalance data) {
            updateAccountBalances(data);
        }

        @Override
        public void onAccountOrdersUpdate(List<BaseTradeApi.StandartObjects.Order> data) {
            updateOpenOrders(data);
        }

        @Override
        public void onAccountHistoryUpdate(List<BaseTradeApi.StandartObjects.Order> data) {
            updateAccountHistory(data);
        }

        @Override
        public void onError(Exception e) {
            processException(e);
        }
    };

    public TraderMainForm(AccountManager.Account account) {
        initComponents();
        spinnerBuyOrderPrice.setEditor(new JSpinner.NumberEditor(spinnerBuyOrderPrice, "##############.########"));
        spinnerBuyOrderAmount.setEditor(new JSpinner.NumberEditor(spinnerBuyOrderAmount, "##############.########"));
        spinnerSellOrderPrice.setEditor(new JSpinner.NumberEditor(spinnerSellOrderPrice, "##############.########"));
        spinnerSellOrderAmount.setEditor(new JSpinner.NumberEditor(spinnerSellOrderAmount, "##############.########"));

        TableCellRenderer capCellRenderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value, boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                if (value instanceof Long || value instanceof Integer) {
                    value = Utils.Strings.formatNumber(value, Utils.Strings.moneyRepresentFormat);
                } else if (value instanceof Double) {
                    value = ((Double) value > 0 ? "+" : "") + Utils.Strings.formatNumber(value, Utils.Strings.percentDecimalFormat) + "%";
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        };
        TableColumnModel model = tableMarketCap.getColumnModel();
        {
            model.getColumn(2).setCellRenderer(capCellRenderer);
            model.getColumn(3).setCellRenderer(capCellRenderer);
            model.getColumn(4).setCellRenderer(capCellRenderer);
            model.getColumn(5).setCellRenderer(capCellRenderer);
            model.getColumn(6).setCellRenderer(capCellRenderer);
        }

        TableCellRenderer moneyAmountCellRenderer = new DefaultTableCellRenderer() {
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value, boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                if (value instanceof Double) {
                    value = Utils.Strings.formatNumber(value, Utils.Strings.moneyRepresentFormat);
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        };
        TableCellRenderer moneyPriceCellRenderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value, boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                if (value instanceof Double) {
                    value = Utils.Strings.formatNumber(value, Utils.Strings.moneyFormat);
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        };
        TableCellRenderer moneyTotalCellRenderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value, boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                if (value instanceof Double) {
                    value = Utils.Strings.formatNumber(value, (Double) value < 0.001 ? Utils.Strings.moneyRepresentFormat : Utils.Strings.moneyRoughRepresentFormat) + " " + getCurrentSecondaryCurrency();
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        };

        final SimpleDateFormat tableDateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
        TableCellRenderer dateCellRenderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value, boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                if (value instanceof Date) {
                    value = tableDateFormat.format(value);
                }
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        };

        model = tableOpenOrders.getColumnModel();
        {
            model.getColumn(2).setCellRenderer(moneyPriceCellRenderer);
            model.getColumn(3).setCellRenderer(moneyAmountCellRenderer);
            model.getColumn(4).setCellRenderer(moneyTotalCellRenderer);
        }
        model = tableAccountHistory.getColumnModel();
        {
            model.getColumn(0).setCellRenderer(dateCellRenderer);
            model.getColumn(2).setCellRenderer(moneyPriceCellRenderer);
            model.getColumn(3).setCellRenderer(moneyAmountCellRenderer);
            model.getColumn(4).setCellRenderer(moneyTotalCellRenderer);
        }
        model = tableMarketHistory.getColumnModel();
        {
            model.getColumn(0).setCellRenderer(dateCellRenderer);
            model.getColumn(2).setCellRenderer(moneyPriceCellRenderer);
            model.getColumn(3).setCellRenderer(moneyAmountCellRenderer);
            model.getColumn(4).setCellRenderer(moneyTotalCellRenderer);
        }

        model = tableBalances.getColumnModel();
        {
            model.getColumn(1).setCellRenderer(moneyAmountCellRenderer);
        }

        model = tableBuyOrders.getColumnModel();
        {
            model.getColumn(0).setCellRenderer(moneyPriceCellRenderer);
            model.getColumn(1).setCellRenderer(moneyAmountCellRenderer);
        }
        model = tableSellOrders.getColumnModel();
        {
            model.getColumn(0).setCellRenderer(moneyPriceCellRenderer);
            model.getColumn(1).setCellRenderer(moneyAmountCellRenderer);
        }

        worker.addEventHandler(System.identityHashCode(this), apiWorkerEventHandler);
        initMarket(account);

        Thread apiLagThread = new Thread(new Utils.Threads.CycledRunnable() {
            @Override
            protected int cycle() throws Exception {
                if (lastUpdated.priceUpdated != 0 && isVisible()) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            double apiLag = (System.currentTimeMillis() - lastUpdated.priceUpdated) / 1000.0;
                            labelApiLagValue.setText(Utils.Strings.formatNumber(apiLag) + " sec");
                        }
                    });
                }
                return 200;
            }
        });
        apiLagThread.start();
        threadMap.put("apiLag", apiLagThread);
    }

    protected void setUpdateOptions() {
        if (!initialized) return;
        if (toggleButtonUpdateAll.isSelected()) {
            worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.MARKET_DEPTH, ApiWorker.ApiDataType.MARKET_HISTORY, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.ACCOUNT_ORDERS, ApiWorker.ApiDataType.ACCOUNT_HISTORY}); // Update all
        } else switch (tabbedPaneInfo.getSelectedIndex()) {
            case 0: // Orders
                worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_ORDERS, ApiWorker.ApiDataType.MARKET_HISTORY});
                break;
            case 1: // Balances
                worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.MARKET_HISTORY});
                break;
            case 2: // Depth
                worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.MARKET_DEPTH, ApiWorker.ApiDataType.MARKET_HISTORY});
                break;
            case 3: // History
                if (panelHistory.getSelectedIndex() == 0)
                    worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.ACCOUNT_HISTORY, ApiWorker.ApiDataType.MARKET_HISTORY});
                else
                    worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.MARKET_HISTORY});
                break;
            default: // Other tabs
                worker.setActiveThreads(new ApiWorker.ApiDataType[]{ApiWorker.ApiDataType.MARKET_PRICES, ApiWorker.ApiDataType.ACCOUNT_BALANCES, ApiWorker.ApiDataType.MARKET_HISTORY});
        }
    }

    private void tabbedPaneInfoStateChanged(ChangeEvent e) {
        setUpdateOptions();
    }

    private void panelHistoryStateChanged(ChangeEvent e) {
        setUpdateOptions();
    }

    private void comboBoxPairActionPerformed(ActionEvent e) {
        setPair((String) comboBoxPair.getSelectedItem());
    }

    private void buttonApplySettingsActionPerformed(ActionEvent e) {
        setSettings((Double) spinnerFeePercent.getValue(), (Integer) spinnerUpdateInterval.getValue());
        buttonApplySettings.setEnabled(false);
    }

    private void settingsChanged(ChangeEvent e) {
        buttonApplySettings.setEnabled(true);
    }

    private void spinnerPriceOrAmountStateChanged(ChangeEvent e) {
        updateLabelTotal();
    }

    private static String formatOrderRepresentation(int orderType, double amount, double price, String primaryCurrency, String secondaryCurrency) {
        return String.format(locale.getString("order_representation.template"), locale.getString(orderType == BaseTradeApi.Constants.ORDER_SELL ? "sell.text" : "buy.text"), Utils.Strings.formatNumber(amount), primaryCurrency, Utils.Strings.formatNumber(price), secondaryCurrency);
    }

    private void buttonCommitBuyOrderActionPerformed(ActionEvent e) {
        final String orderRepresentation = formatOrderRepresentation(BaseTradeApi.Constants.ORDER_BUY, (Double) spinnerBuyOrderAmount.getValue(), (Double) spinnerBuyOrderPrice.getValue(), getCurrentPrimaryCurrency(), getCurrentSecondaryCurrency());

        if (JOptionPane.showConfirmDialog(this, String.format(locale.getString("order_confirmation.template"), orderRepresentation), locale.getString("order_confirmation.caption"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            Thread orderCreateThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    buttonCommitBuyOrder.setEnabled(false);
                    try {
                        Object orderId = worker.tradeApi.createOrder(pairList.get(comboBoxPair.getSelectedItem()).pairId, BaseTradeApi.Constants.ORDER_BUY, (Double) spinnerBuyOrderAmount.getValue(), (Double) spinnerBuyOrderPrice.getValue());
                        processNotification(String.format(locale.getString("order_created.template"), orderRepresentation, orderId.toString()));
                    } catch (Exception e1) {
                        processException(e1);
                    } finally {
                        buttonCommitBuyOrder.setEnabled(true);
                    }
                }
            });
            threadMap.put(String.format("createOrderBuy%d", System.identityHashCode(orderCreateThread)), orderCreateThread);
            orderCreateThread.start();
        }
    }

    private void buttonCommitSellOrderActionPerformed(ActionEvent e) {
        final String orderRepresentation = formatOrderRepresentation(BaseTradeApi.Constants.ORDER_SELL, (Double) spinnerSellOrderAmount.getValue(), (Double) spinnerSellOrderPrice.getValue(), getCurrentPrimaryCurrency(), getCurrentSecondaryCurrency());


        if (JOptionPane.showConfirmDialog(this, String.format(locale.getString("order_confirmation.template"), orderRepresentation), locale.getString("order_confirmation.caption"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            Thread orderCreateThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        buttonCommitSellOrder.setEnabled(false);
                        Object orderId = worker.tradeApi.createOrder(pairList.get(comboBoxPair.getSelectedItem()).pairId, BaseTradeApi.Constants.ORDER_SELL, (Double) spinnerSellOrderAmount.getValue(), (Double) spinnerSellOrderPrice.getValue());
                        processNotification(String.format(locale.getString("order_created.template"), orderRepresentation, orderId.toString()));
                    } catch (Exception e1) {
                        processException(e1);
                    } finally {
                        buttonCommitSellOrder.setEnabled(true);
                    }
                }
            });
            threadMap.put(String.format("createOrderSell%d", System.identityHashCode(orderCreateThread)), orderCreateThread);
            orderCreateThread.start();
        }
    }

    private void tableOpenOrdersPopupMenuHandler(MouseEvent e) {
        if (e.isPopupTrigger()) {
            synchronized (tableOpenOrders) {
                popupMenuOrders.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    }

    private void menuItemCancelOrderActionPerformed(ActionEvent e) {
        if (tableOpenOrders.getSelectedRow() == -1) return;
        final long orderId;
        synchronized (tableOpenOrders) {
            orderId = (Long) tableOpenOrders.getValueAt(tableOpenOrders.getSelectedRow(), 0);
        }
        final String threadId = String.format("cancelOrder%d", orderId);
        if(!threadMap.containsKey(threadId)) {
            Thread cancelOrderThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    if (JOptionPane.showConfirmDialog(TraderMainForm.this, String.format(locale.getString("order_cancel_confirmation.template"), orderId), locale.getString("order_cancel_confirmation.caption"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                        try {
                            worker.tradeApi.cancelOrder(orderId);
                            processNotification(String.format(locale.getString("order_cancelled.template"), orderId));
                        } catch (Exception e1) {
                            processException(e1);
                        }
                    }
                }
            });
            threadMap.put(threadId, cancelOrderThread);
            cancelOrderThread.start();
        }
    }

    private void buttonBuyOrderPriceSetCurrentActionPerformed(ActionEvent e) {
        spinnerBuyOrderPrice.setValue(worker.marketInfo.price.buy);
    }

    private void buttonSellOrderPriceSetCurrentActionPerformed(ActionEvent e) {
        spinnerSellOrderPrice.setValue(worker.marketInfo.price.sell);
    }

    private void toggleButtonUpdateAllStateChanged(ChangeEvent e) {
        setUpdateOptions();
    }

    private static String priceToString(BaseTradeApi.PriceType priceType) {
        switch (priceType) {
            case LAST:
                return locale.getString("TraderMainForm.labelLastPrice.text");
            case LOW:
                return locale.getString("TraderMainForm.labelLowPrice.text");
            case HIGH:
                return locale.getString("TraderMainForm.labelHighPrice.text");
            case ASK:
                return locale.getString("TraderMainForm.labelSellPrice.text");
            case BID:
                return locale.getString("TraderMainForm.labelBuyPrice.text");
            case AVG:
                return locale.getString("TraderMainForm.labelAvgPrice.text");
            default:
                throw new IllegalArgumentException();
        }
    }

    private static String arithmeticComparatorToString(Calculator.ArithmeticCompareCondition compareCondition) {
        switch (compareCondition) {
            case EQUAL:
                return "==";
            case GREATER:
                return ">";
            case LESS:
                return "<";
            case GREATER_OR_EQUAL:
                return ">=";
            case LESS_OR_EQUAL:
                return "<=";
            default:
                throw new IllegalArgumentException();
        }
    }

    private static String formatMarketConditionString(RuleCondition.BaseCondition condition) {
        String stringType = "", stringComparator = "", stringCondition = "", stringValue = condition.value.toString();
        if (condition instanceof RuleCondition.PriceCondition) {
            stringType = locale.getString("MarketRuleType.price.title");
            stringCondition = priceToString((BaseTradeApi.PriceType) condition.conditionType);
            stringValue = Utils.Strings.formatNumber(((BigDecimal) condition.value).doubleValue());
        }
        if (condition.compareType instanceof Calculator.ArithmeticCompareCondition) {
            stringComparator = arithmeticComparatorToString((Calculator.ArithmeticCompareCondition) condition.compareType);
        }
        return String.format("%s <%s> %s %s", stringType, stringCondition, stringComparator, stringValue);
    }

    private static String formatMarketActionString(RuleAction.BaseAction action) {
        if (action == null) {
            return "-";
        } else if (action instanceof RuleAction.TradeAction) {
            RuleAction.TradeAction tradeAction = (RuleAction.TradeAction) action;
            String stringAmount, stringPrice = tradeAction.priceCustom == null ? priceToString(tradeAction.priceType) : Utils.Strings.formatNumber(tradeAction.priceCustom.doubleValue());
            if (tradeAction.amountType == RuleAction.TradeAction.AMOUNT_TYPE_CONSTANT) {
                stringAmount = Utils.Strings.formatNumber(tradeAction.amount.doubleValue());
            } else {
                stringAmount = Utils.Strings.formatNumber(tradeAction.amount.doubleValue(), Utils.Strings.percentDecimalFormat) + "%";
            }
            return String.format(locale.getString("MarketRuleAction.trade.template"), locale.getString(tradeAction.tradeType == BaseTradeApi.Constants.ORDER_SELL ? "sell.text" : "buy.text"), stringAmount, stringPrice);
        }
        throw new NotImplementedException();
    }

    private void refreshRulesTable() {
        DefaultTableModel model = (DefaultTableModel) tableRules.getModel();
        int i = 0;
        model.setRowCount(ruleList.size());
        for (MarketRule rule : ruleList) {
            model.setValueAt(i, i, 0); // Index
            model.setValueAt(formatMarketConditionString(rule.condition), i, 1); // Condition
            model.setValueAt(formatMarketActionString(rule.action), i, 2); // Action
        }
        model.fireTableDataChanged();
        ruleListDb.put(currentPair, ruleList);
    }

    private void buttonAddRuleActionPerformed(ActionEvent e) {
        final RuleAction.TradeAction.Callback tradeCallback = new RuleAction.TradeAction.Callback() {
            @Override
            public void onSuccess(Object orderId, int tradeType, BigDecimal amount, BigDecimal price) {
                final String orderRepresentation = formatOrderRepresentation(tradeType, amount.doubleValue(), price.doubleValue(), getCurrentPrimaryCurrency(), getCurrentSecondaryCurrency());
                processNotification(String.format(locale.getString("order_created.template"), orderRepresentation, orderId.toString()));
            }

            @Override
            public void onError(Exception e) {
                processException(new Exception("RuleAction error: " + e.getMessage()));
            }
        };
        RuleSettingsDlg ruleSettingsDlg = new RuleSettingsDlg((JFrame) SwingUtilities.getWindowAncestor(this));
        ruleSettingsDlg.setVisible(true);
        if (ruleSettingsDlg.result != null) {
            MarketRule rule = ruleSettingsDlg.result;
            if (rule.action instanceof RuleAction.TradeAction) {
                rule.action.setCallback(tradeCallback);
            }
            ruleList.add(rule);
            refreshRulesTable();
        }
    }

    private void buttonDeleteRuleActionPerformed(ActionEvent e) {
        ruleList.remove(tableRules.getSelectedRow());
        refreshRulesTable();
    }

    private void radioButtonMenuItem1MActionPerformed(ActionEvent e) {
        setChartPeriod(HistoryUtils.PERIOD_1M);
    }

    private void radioButtonMenuItem15MActionPerformed(ActionEvent e) {
        setChartPeriod(HistoryUtils.PERIOD_15M);
    }

    private void radioButtonMenuItem30MActionPerformed(ActionEvent e) {
        setChartPeriod(HistoryUtils.PERIOD_30M);
    }

    private void radioButtonMenuItem1HActionPerformed(ActionEvent e) {
        setChartPeriod(HistoryUtils.PERIOD_1H);
    }


    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
        ResourceBundle bundle = ResourceBundle.getBundle("com.archean.jtradegui.locale", new UTF8Control());
        comboBoxPair = new JComboBox();
        separator3 = new JSeparator();
        panelPrice = new JPanel();
        labelBuyPrice = new JLabel();
        labelLastPrice = new JLabel();
        labelSellPrice = new JLabel();
        textFieldBuyPrice = new JTextField();
        textFieldLastPrice = new JTextField();
        textFieldSellPrice = new JTextField();
        labelLowPrice = new JLabel();
        labelPriceChange = new JLabel();
        labelHighPrice = new JLabel();
        textFieldLowPrice = new JTextField();
        labelPriceChangePercent = new JLabel();
        textFieldHighPrice = new JTextField();
        labelAvgPrice = new JLabel();
        labelApiLag = new JLabel();
        labelVolume = new JLabel();
        textFieldAvgPrice = new JTextField();
        labelApiLagValue = new JLabel();
        textFieldVolume = new JTextField();
        separator1 = new JSeparator();
        splitPane1 = new JSplitPane();
        tabbedPaneTrade = new JTabbedPane();
        panelBuy = new JPanel();
        labelBuyOrderPrice = new JLabel();
        spinnerBuyOrderPrice = new JSpinner();
        buttonBuyOrderPriceSetCurrent = new JButton();
        buttonCommitBuyOrder = new JButton();
        labelBuyOrderAmount = new JLabel();
        spinnerBuyOrderAmount = new JSpinner();
        sliderBuyOrderAmount = new JSlider();
        labelBuyOrderTotal = new JLabel();
        labelBuyOrderTotalValue = new JLabel();
        panelSell = new JPanel();
        labelSellOrderPrice = new JLabel();
        spinnerSellOrderPrice = new JSpinner();
        buttonSellOrderPriceSetCurrent = new JButton();
        buttonCommitSellOrder = new JButton();
        labelSellOrderAmount = new JLabel();
        spinnerSellOrderAmount = new JSpinner();
        sliderSellOrderAmount = new JSlider();
        labelSellOrderTotal = new JLabel();
        labelSellOrderTotalValue = new JLabel();
        panelRules = new JPanel();
        scrollPane2 = new JScrollPane();
        tableRules = new JTable();
        toolBar1 = new JToolBar();
        buttonAddRule = new JButton();
        buttonDeleteRule = new JButton();
        tabbedPaneInfo = new JTabbedPane();
        panelOrders = new JPanel();
        scrollPane4 = new JScrollPane();
        tableOpenOrders = new JTable();
        panelBalance = new JPanel();
        scrollPane3 = new JScrollPane();
        tableBalances = new JTable();
        panelDepth = new JPanel();
        labelBuyOrders = new JLabel();
        labelSellOrders = new JLabel();
        scrollPaneBuyOrders = new JScrollPane();
        tableBuyOrders = new JTable();
        scrollPaneSellOrders = new JScrollPane();
        tableSellOrders = new JTable();
        panelHistory = new JTabbedPane();
        panelMyTrades = new JPanel();
        scrollPane6 = new JScrollPane();
        tableAccountHistory = new JTable();
        panelMarketTrades = new JPanel();
        scrollPane7 = new JScrollPane();
        tableMarketHistory = new JTable();
        panelCharts = new JPanel();
        panelMarketCap = new JPanel();
        scrollPane1 = new JScrollPane();
        tableMarketCap = new JTable();
        panelSettings = new JPanel();
        labelFeePercent = new JLabel();
        spinnerFeePercent = new JSpinner();
        toggleButtonUpdateAll = new JToggleButton();
        labelUpdateInterval = new JLabel();
        spinnerUpdateInterval = new JSpinner();
        buttonApplySettings = new JButton();
        panelLog = new JPanel();
        scrollPane5 = new JScrollPane();
        textPaneLog = new JTextPane();
        popupMenuOrders = new JPopupMenu();
        menuItemCancelOrder = new JMenuItem();
        popupMenuTimeframe = new JPopupMenu();
        radioButtonMenuItem1M = new JRadioButtonMenuItem();
        radioButtonMenuItem15M = new JRadioButtonMenuItem();
        radioButtonMenuItem30M = new JRadioButtonMenuItem();
        radioButtonMenuItem1H = new JRadioButtonMenuItem();

        //======== this ========
        setLayout(new FormLayout(
            "[90dlu,pref]:grow, $lcgap, [92dlu,pref]:grow",
            "default, 10dlu, top:[95dlu,default], 10dlu, 77dlu, 0dlu, 10dlu, $lgap, fill:[55dlu,default]:grow"));

        //---- comboBoxPair ----
        comboBoxPair.setMaximumRowCount(20);
        comboBoxPair.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                comboBoxPairActionPerformed(e);
            }
        });
        add(comboBoxPair, CC.xywh(1, 1, 3, 1));
        add(separator3, CC.xywh(1, 2, 3, 1));

        //======== panelPrice ========
        {
            panelPrice.setLayout(new FormLayout(
                "default:grow, $lcgap, 70dlu, $lcgap, default:grow",
                "3*(default, $lgap), [18dlu,default], 2*($lgap, default)"));

            //---- labelBuyPrice ----
            labelBuyPrice.setText(bundle.getString("TraderMainForm.labelBuyPrice.text"));
            labelBuyPrice.setFont(labelBuyPrice.getFont().deriveFont(labelBuyPrice.getFont().getStyle() | Font.BOLD));
            labelBuyPrice.setLabelFor(textFieldBuyPrice);
            panelPrice.add(labelBuyPrice, CC.xy(1, 1, CC.CENTER, CC.DEFAULT));

            //---- labelLastPrice ----
            labelLastPrice.setText(bundle.getString("TraderMainForm.labelLastPrice.text"));
            labelLastPrice.setLabelFor(textFieldLastPrice);
            labelLastPrice.setFont(labelLastPrice.getFont().deriveFont(labelLastPrice.getFont().getStyle() | Font.BOLD));
            panelPrice.add(labelLastPrice, CC.xy(3, 1, CC.CENTER, CC.DEFAULT));

            //---- labelSellPrice ----
            labelSellPrice.setText(bundle.getString("TraderMainForm.labelSellPrice.text"));
            labelSellPrice.setLabelFor(textFieldSellPrice);
            labelSellPrice.setFont(labelSellPrice.getFont().deriveFont(Font.BOLD));
            panelPrice.add(labelSellPrice, CC.xy(5, 1, CC.CENTER, CC.DEFAULT));

            //---- textFieldBuyPrice ----
            textFieldBuyPrice.setEditable(false);
            panelPrice.add(textFieldBuyPrice, CC.xy(1, 3, CC.CENTER, CC.DEFAULT));

            //---- textFieldLastPrice ----
            textFieldLastPrice.setEditable(false);
            panelPrice.add(textFieldLastPrice, CC.xy(3, 3, CC.CENTER, CC.DEFAULT));

            //---- textFieldSellPrice ----
            textFieldSellPrice.setEditable(false);
            panelPrice.add(textFieldSellPrice, CC.xy(5, 3, CC.CENTER, CC.DEFAULT));

            //---- labelLowPrice ----
            labelLowPrice.setText(bundle.getString("TraderMainForm.labelLowPrice.text"));
            labelLowPrice.setFont(labelLowPrice.getFont().deriveFont(labelLowPrice.getFont().getStyle() | Font.BOLD));
            labelLowPrice.setLabelFor(textFieldLowPrice);
            panelPrice.add(labelLowPrice, CC.xy(1, 5, CC.CENTER, CC.DEFAULT));

            //---- labelPriceChange ----
            labelPriceChange.setText(bundle.getString("TraderMainForm.labelPriceChange.text"));
            labelPriceChange.setFont(labelPriceChange.getFont().deriveFont(Font.BOLD|Font.ITALIC));
            panelPrice.add(labelPriceChange, CC.xy(3, 5, CC.CENTER, CC.DEFAULT));

            //---- labelHighPrice ----
            labelHighPrice.setText(bundle.getString("TraderMainForm.labelHighPrice.text"));
            labelHighPrice.setFont(labelHighPrice.getFont().deriveFont(labelHighPrice.getFont().getStyle() | Font.BOLD));
            labelHighPrice.setLabelFor(textFieldHighPrice);
            panelPrice.add(labelHighPrice, CC.xy(5, 5, CC.CENTER, CC.DEFAULT));

            //---- textFieldLowPrice ----
            textFieldLowPrice.setEditable(false);
            panelPrice.add(textFieldLowPrice, CC.xy(1, 7, CC.CENTER, CC.DEFAULT));

            //---- labelPriceChangePercent ----
            labelPriceChangePercent.setText("0%");
            panelPrice.add(labelPriceChangePercent, CC.xy(3, 7, CC.CENTER, CC.DEFAULT));

            //---- textFieldHighPrice ----
            textFieldHighPrice.setEditable(false);
            panelPrice.add(textFieldHighPrice, CC.xy(5, 7, CC.CENTER, CC.DEFAULT));

            //---- labelAvgPrice ----
            labelAvgPrice.setText(bundle.getString("TraderMainForm.labelAvgPrice.text"));
            labelAvgPrice.setFont(labelAvgPrice.getFont().deriveFont(labelAvgPrice.getFont().getStyle() | Font.BOLD));
            labelAvgPrice.setLabelFor(textFieldAvgPrice);
            panelPrice.add(labelAvgPrice, CC.xy(1, 9, CC.CENTER, CC.DEFAULT));

            //---- labelApiLag ----
            labelApiLag.setText(bundle.getString("TraderMainForm.labelApiLag.text"));
            labelApiLag.setFont(labelApiLag.getFont().deriveFont(Font.ITALIC));
            panelPrice.add(labelApiLag, CC.xy(3, 9, CC.CENTER, CC.DEFAULT));

            //---- labelVolume ----
            labelVolume.setText(bundle.getString("TraderMainForm.labelVolume.text"));
            labelVolume.setFont(labelVolume.getFont().deriveFont(labelVolume.getFont().getStyle() | Font.BOLD));
            labelVolume.setLabelFor(textFieldVolume);
            panelPrice.add(labelVolume, CC.xy(5, 9, CC.CENTER, CC.DEFAULT));

            //---- textFieldAvgPrice ----
            textFieldAvgPrice.setEditable(false);
            panelPrice.add(textFieldAvgPrice, CC.xy(1, 11, CC.CENTER, CC.DEFAULT));

            //---- labelApiLagValue ----
            labelApiLagValue.setText("0.0 sec");
            panelPrice.add(labelApiLagValue, CC.xy(3, 11, CC.CENTER, CC.DEFAULT));

            //---- textFieldVolume ----
            textFieldVolume.setEditable(false);
            panelPrice.add(textFieldVolume, CC.xy(5, 11, CC.CENTER, CC.DEFAULT));
        }
        add(panelPrice, CC.xywh(1, 3, 3, 1));
        add(separator1, CC.xywh(1, 4, 3, 1));

        //======== splitPane1 ========
        {
            splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);

            //======== tabbedPaneTrade ========
            {

                //======== panelBuy ========
                {
                    panelBuy.setLayout(new FormLayout(
                        "5dlu, $lcgap, 30dlu, $lcgap, 108dlu, $lcgap, 45dlu:grow, $lcgap, [70dlu,default]:grow",
                        "5dlu, 2*($lgap, default), $lgap, 14dlu"));

                    //---- labelBuyOrderPrice ----
                    labelBuyOrderPrice.setText(bundle.getString("TraderMainForm.labelBuyOrderPrice.text"));
                    labelBuyOrderPrice.setLabelFor(spinnerBuyOrderPrice);
                    panelBuy.add(labelBuyOrderPrice, CC.xy(3, 3, CC.LEFT, CC.DEFAULT));

                    //---- spinnerBuyOrderPrice ----
                    spinnerBuyOrderPrice.setModel(new SpinnerNumberModel(0.0, 0.0, null, 1.0));
                    spinnerBuyOrderPrice.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            spinnerPriceOrAmountStateChanged(e);
                        }
                    });
                    panelBuy.add(spinnerBuyOrderPrice, CC.xy(5, 3));

                    //---- buttonBuyOrderPriceSetCurrent ----
                    buttonBuyOrderPriceSetCurrent.setText(bundle.getString("TraderMainForm.buttonBuyOrderPriceSetCurrent.text"));
                    buttonBuyOrderPriceSetCurrent.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            buttonBuyOrderPriceSetCurrentActionPerformed(e);
                        }
                    });
                    panelBuy.add(buttonBuyOrderPriceSetCurrent, CC.xy(7, 3, CC.FILL, CC.DEFAULT));

                    //---- buttonCommitBuyOrder ----
                    buttonCommitBuyOrder.setText(bundle.getString("buy.text"));
                    buttonCommitBuyOrder.setFont(buttonCommitBuyOrder.getFont().deriveFont(buttonCommitBuyOrder.getFont().getStyle() | Font.BOLD));
                    buttonCommitBuyOrder.setBackground(new Color(45, 195, 22));
                    buttonCommitBuyOrder.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            buttonCommitBuyOrderActionPerformed(e);
                        }
                    });
                    panelBuy.add(buttonCommitBuyOrder, CC.xy(9, 3, CC.FILL, CC.DEFAULT));

                    //---- labelBuyOrderAmount ----
                    labelBuyOrderAmount.setText(bundle.getString("TraderMainForm.labelBuyOrderAmount.text"));
                    labelBuyOrderAmount.setLabelFor(spinnerBuyOrderAmount);
                    panelBuy.add(labelBuyOrderAmount, CC.xy(3, 5, CC.LEFT, CC.DEFAULT));

                    //---- spinnerBuyOrderAmount ----
                    spinnerBuyOrderAmount.setModel(new SpinnerNumberModel(0.0, 0.0, null, 0.01));
                    spinnerBuyOrderAmount.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            spinnerPriceOrAmountStateChanged(e);
                        }
                    });
                    panelBuy.add(spinnerBuyOrderAmount, CC.xy(5, 5));

                    //---- sliderBuyOrderAmount ----
                    sliderBuyOrderAmount.setValue(0);
                    sliderBuyOrderAmount.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            sliderBuyOrderAmountStateChanged(e);
                        }
                    });
                    panelBuy.add(sliderBuyOrderAmount, CC.xywh(7, 5, 3, 1, CC.FILL, CC.DEFAULT));

                    //---- labelBuyOrderTotal ----
                    labelBuyOrderTotal.setText(bundle.getString("TraderMainForm.labelBuyOrderTotal.text"));
                    panelBuy.add(labelBuyOrderTotal, CC.xy(3, 7, CC.LEFT, CC.DEFAULT));

                    //---- labelBuyOrderTotalValue ----
                    labelBuyOrderTotalValue.setText("0 / 0");
                    panelBuy.add(labelBuyOrderTotalValue, CC.xywh(5, 7, 5, 1, CC.LEFT, CC.DEFAULT));
                }
                tabbedPaneTrade.addTab(bundle.getString("buy.text"), panelBuy);

                //======== panelSell ========
                {
                    panelSell.setLayout(new FormLayout(
                        "5dlu, $lcgap, 30dlu, $lcgap, 108dlu, $lcgap, 45dlu:grow, $lcgap, [70dlu,default]:grow",
                        "5dlu, 2*($lgap, default), $lgap, 14dlu"));

                    //---- labelSellOrderPrice ----
                    labelSellOrderPrice.setText(bundle.getString("TraderMainForm.labelSellOrderPrice.text"));
                    labelSellOrderPrice.setLabelFor(spinnerSellOrderPrice);
                    panelSell.add(labelSellOrderPrice, CC.xy(3, 3, CC.LEFT, CC.DEFAULT));

                    //---- spinnerSellOrderPrice ----
                    spinnerSellOrderPrice.setModel(new SpinnerNumberModel(0.0, 0.0, null, 1.0));
                    spinnerSellOrderPrice.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            spinnerPriceOrAmountStateChanged(e);
                        }
                    });
                    panelSell.add(spinnerSellOrderPrice, CC.xy(5, 3));

                    //---- buttonSellOrderPriceSetCurrent ----
                    buttonSellOrderPriceSetCurrent.setText(bundle.getString("TraderMainForm.buttonSellOrderPriceSetCurrent.text"));
                    buttonSellOrderPriceSetCurrent.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            buttonSellOrderPriceSetCurrentActionPerformed(e);
                        }
                    });
                    panelSell.add(buttonSellOrderPriceSetCurrent, CC.xy(7, 3, CC.FILL, CC.DEFAULT));

                    //---- buttonCommitSellOrder ----
                    buttonCommitSellOrder.setText(bundle.getString("sell.text"));
                    buttonCommitSellOrder.setBackground(new Color(255, 81, 81));
                    buttonCommitSellOrder.setFont(buttonCommitSellOrder.getFont().deriveFont(buttonCommitSellOrder.getFont().getStyle() | Font.BOLD));
                    buttonCommitSellOrder.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            buttonCommitSellOrderActionPerformed(e);
                        }
                    });
                    panelSell.add(buttonCommitSellOrder, CC.xy(9, 3, CC.FILL, CC.DEFAULT));

                    //---- labelSellOrderAmount ----
                    labelSellOrderAmount.setText(bundle.getString("TraderMainForm.labelSellOrderAmount.text"));
                    labelSellOrderAmount.setLabelFor(spinnerSellOrderAmount);
                    panelSell.add(labelSellOrderAmount, CC.xy(3, 5, CC.LEFT, CC.DEFAULT));

                    //---- spinnerSellOrderAmount ----
                    spinnerSellOrderAmount.setModel(new SpinnerNumberModel(0.0, 0.0, null, 0.01));
                    spinnerSellOrderAmount.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            spinnerPriceOrAmountStateChanged(e);
                        }
                    });
                    panelSell.add(spinnerSellOrderAmount, CC.xy(5, 5));

                    //---- sliderSellOrderAmount ----
                    sliderSellOrderAmount.setValue(0);
                    sliderSellOrderAmount.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            sliderSellOrderAmountStateChanged(e);
                        }
                    });
                    panelSell.add(sliderSellOrderAmount, CC.xywh(7, 5, 3, 1, CC.FILL, CC.DEFAULT));

                    //---- labelSellOrderTotal ----
                    labelSellOrderTotal.setText(bundle.getString("TraderMainForm.labelSellOrderTotal.text"));
                    panelSell.add(labelSellOrderTotal, CC.xy(3, 7, CC.LEFT, CC.DEFAULT));

                    //---- labelSellOrderTotalValue ----
                    labelSellOrderTotalValue.setText("0 / 0");
                    panelSell.add(labelSellOrderTotalValue, CC.xywh(5, 7, 5, 1, CC.LEFT, CC.DEFAULT));
                }
                tabbedPaneTrade.addTab(bundle.getString("sell.text"), panelSell);

                //======== panelRules ========
                {
                    panelRules.setLayout(new FormLayout(
                        "default:grow, $lcgap, right:16dlu",
                        "fill:default"));

                    //======== scrollPane2 ========
                    {

                        //---- tableRules ----
                        tableRules.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null, null},
                            },
                            new String[] {
                                "#", "Condition", "Action"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                Integer.class, Object.class, Object.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                false, false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        {
                            TableColumnModel cm = tableRules.getColumnModel();
                            cm.getColumn(0).setMaxWidth(50);
                            cm.getColumn(0).setPreferredWidth(20);
                        }
                        scrollPane2.setViewportView(tableRules);
                    }
                    panelRules.add(scrollPane2, CC.xy(1, 1));

                    //======== toolBar1 ========
                    {
                        toolBar1.setOrientation(SwingConstants.VERTICAL);
                        toolBar1.setFloatable(false);

                        //---- buttonAddRule ----
                        buttonAddRule.setIcon(new ImageIcon(getClass().getResource("/icons/plus.png")));
                        buttonAddRule.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                buttonAddRuleActionPerformed(e);
                            }
                        });
                        toolBar1.add(buttonAddRule);

                        //---- buttonDeleteRule ----
                        buttonDeleteRule.setIcon(new ImageIcon(getClass().getResource("/icons/delete.png")));
                        buttonDeleteRule.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                buttonDeleteRuleActionPerformed(e);
                            }
                        });
                        toolBar1.add(buttonDeleteRule);
                    }
                    panelRules.add(toolBar1, CC.xy(3, 1));
                }
                tabbedPaneTrade.addTab(bundle.getString("TraderMainForm.panelRules.tab.title"), panelRules);
            }
            splitPane1.setTopComponent(tabbedPaneTrade);

            //======== tabbedPaneInfo ========
            {
                tabbedPaneInfo.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        tabbedPaneInfoStateChanged(e);
                    }
                });

                //======== panelOrders ========
                {
                    panelOrders.setLayout(new FormLayout(
                        "default:grow",
                        "[55dlu,default]"));

                    //======== scrollPane4 ========
                    {

                        //---- tableOpenOrders ----
                        tableOpenOrders.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null, null, null, null},
                            },
                            new String[] {
                                "#", "Type", "Price", "Amount", "Total"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                Object.class, String.class, Double.class, Double.class, Double.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                true, false, false, false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        tableOpenOrders.addMouseListener(new MouseAdapter() {
                            @Override
                            public void mousePressed(MouseEvent e) {
                                tableOpenOrdersPopupMenuHandler(e);
                            }
                            @Override
                            public void mouseReleased(MouseEvent e) {
                                tableOpenOrdersPopupMenuHandler(e);
                            }
                        });
                        scrollPane4.setViewportView(tableOpenOrders);
                    }
                    panelOrders.add(scrollPane4, CC.xy(1, 1));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelOrders.tab.title"), panelOrders);

                //======== panelBalance ========
                {
                    panelBalance.setLayout(new FormLayout(
                        "112dlu:grow",
                        "[55dlu,default]"));

                    //======== scrollPane3 ========
                    {

                        //---- tableBalances ----
                        tableBalances.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null},
                            },
                            new String[] {
                                "Currency", "Balance"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                String.class, Double.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        tableBalances.setAutoCreateRowSorter(true);
                        tableBalances.setCellSelectionEnabled(true);
                        scrollPane3.setViewportView(tableBalances);
                    }
                    panelBalance.add(scrollPane3, CC.xy(1, 1));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelBalance.tab.title"), panelBalance);

                //======== panelDepth ========
                {
                    panelDepth.setLayout(new FormLayout(
                        "[90dlu,default], $lcgap, [90dlu,default]",
                        "default, $lgap, fill:[55dlu,default]:grow"));

                    //---- labelBuyOrders ----
                    labelBuyOrders.setText(bundle.getString("TraderMainForm.labelBuyOrders.text"));
                    labelBuyOrders.setHorizontalAlignment(SwingConstants.CENTER);
                    labelBuyOrders.setFont(labelBuyOrders.getFont().deriveFont(labelBuyOrders.getFont().getStyle() | Font.BOLD));
                    labelBuyOrders.setLabelFor(tableBuyOrders);
                    panelDepth.add(labelBuyOrders, CC.xy(1, 1));

                    //---- labelSellOrders ----
                    labelSellOrders.setText(bundle.getString("TraderMainForm.labelSellOrders.text"));
                    labelSellOrders.setLabelFor(tableSellOrders);
                    labelSellOrders.setHorizontalAlignment(SwingConstants.CENTER);
                    labelSellOrders.setFont(labelSellOrders.getFont().deriveFont(labelSellOrders.getFont().getStyle() | Font.BOLD));
                    panelDepth.add(labelSellOrders, CC.xy(3, 1));

                    //======== scrollPaneBuyOrders ========
                    {

                        //---- tableBuyOrders ----
                        tableBuyOrders.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null},
                            },
                            new String[] {
                                "Price", "Amount"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                Double.class, Double.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        tableBuyOrders.setAutoCreateRowSorter(true);
                        tableBuyOrders.setCellSelectionEnabled(true);
                        scrollPaneBuyOrders.setViewportView(tableBuyOrders);
                    }
                    panelDepth.add(scrollPaneBuyOrders, CC.xy(1, 3));

                    //======== scrollPaneSellOrders ========
                    {

                        //---- tableSellOrders ----
                        tableSellOrders.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null},
                            },
                            new String[] {
                                "Price", "Amount"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                Double.class, Double.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        tableSellOrders.setAutoCreateRowSorter(true);
                        scrollPaneSellOrders.setViewportView(tableSellOrders);
                    }
                    panelDepth.add(scrollPaneSellOrders, CC.xy(3, 3));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelDepth.tab.title"), panelDepth);

                //======== panelHistory ========
                {
                    panelHistory.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            panelHistoryStateChanged(e);
                        }
                    });

                    //======== panelMyTrades ========
                    {
                        panelMyTrades.setLayout(new FormLayout(
                            "default:grow",
                            "fill:[55dlu,default]:grow"));

                        //======== scrollPane6 ========
                        {

                            //---- tableAccountHistory ----
                            tableAccountHistory.setModel(new DefaultTableModel(
                                new Object[][] {
                                    {null, null, null, null, null},
                                },
                                new String[] {
                                    "Time", "Type", "Price", "Amount", "Total"
                                }
                            ) {
                                Class<?>[] columnTypes = new Class<?>[] {
                                    Date.class, String.class, Double.class, Double.class, Double.class
                                };
                                boolean[] columnEditable = new boolean[] {
                                    false, false, false, false, false
                                };
                                @Override
                                public Class<?> getColumnClass(int columnIndex) {
                                    return columnTypes[columnIndex];
                                }
                                @Override
                                public boolean isCellEditable(int rowIndex, int columnIndex) {
                                    return columnEditable[columnIndex];
                                }
                            });
                            tableAccountHistory.setAutoCreateRowSorter(true);
                            scrollPane6.setViewportView(tableAccountHistory);
                        }
                        panelMyTrades.add(scrollPane6, CC.xy(1, 1));
                    }
                    panelHistory.addTab(bundle.getString("TraderMainForm.panelMyTrades.tab.title"), panelMyTrades);

                    //======== panelMarketTrades ========
                    {
                        panelMarketTrades.setLayout(new FormLayout(
                            "default:grow",
                            "fill:[55dlu,default]:grow"));

                        //======== scrollPane7 ========
                        {

                            //---- tableMarketHistory ----
                            tableMarketHistory.setModel(new DefaultTableModel(
                                new Object[][] {
                                    {null, null, null, null, null},
                                },
                                new String[] {
                                    "Time", "Type", "Price", "Amount", "Total"
                                }
                            ) {
                                Class<?>[] columnTypes = new Class<?>[] {
                                    Date.class, String.class, Double.class, Double.class, Double.class
                                };
                                boolean[] columnEditable = new boolean[] {
                                    false, false, false, false, false
                                };
                                @Override
                                public Class<?> getColumnClass(int columnIndex) {
                                    return columnTypes[columnIndex];
                                }
                                @Override
                                public boolean isCellEditable(int rowIndex, int columnIndex) {
                                    return columnEditable[columnIndex];
                                }
                            });
                            tableMarketHistory.setAutoCreateRowSorter(true);
                            scrollPane7.setViewportView(tableMarketHistory);
                        }
                        panelMarketTrades.add(scrollPane7, CC.xy(1, 1));
                    }
                    panelHistory.addTab(bundle.getString("TraderMainForm.panelMarketTrades.tab.title"), panelMarketTrades);
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelHistory.tab.title"), panelHistory);

                //======== panelCharts ========
                {
                    panelCharts.setLayout(new FormLayout(
                        "default, $lcgap, default",
                        "2*(default, $lgap), default"));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelCharts.tab.title"), panelCharts);

                //======== panelMarketCap ========
                {
                    panelMarketCap.setLayout(new FormLayout(
                        "default:grow",
                        "fill:[55dlu,default]:grow"));

                    //======== scrollPane1 ========
                    {

                        //---- tableMarketCap ----
                        tableMarketCap.setModel(new DefaultTableModel(
                            new Object[][] {
                                {null, null, null, null, null, null, null},
                            },
                            new String[] {
                                "#", "Currency", "USD cap", "BTC cap", "USD volume", "BTC volume", "Change (24h)"
                            }
                        ) {
                            Class<?>[] columnTypes = new Class<?>[] {
                                Short.class, String.class, Long.class, Long.class, Long.class, Long.class, Double.class
                            };
                            boolean[] columnEditable = new boolean[] {
                                true, false, false, false, false, false, false
                            };
                            @Override
                            public Class<?> getColumnClass(int columnIndex) {
                                return columnTypes[columnIndex];
                            }
                            @Override
                            public boolean isCellEditable(int rowIndex, int columnIndex) {
                                return columnEditable[columnIndex];
                            }
                        });
                        {
                            TableColumnModel cm = tableMarketCap.getColumnModel();
                            cm.getColumn(0).setPreferredWidth(20);
                        }
                        tableMarketCap.setAutoCreateRowSorter(true);
                        scrollPane1.setViewportView(tableMarketCap);
                    }
                    panelMarketCap.add(scrollPane1, CC.xy(1, 1));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelMarketCap.tab.title"), panelMarketCap);

                //======== panelSettings ========
                {
                    panelSettings.setLayout(new FormLayout(
                        "5dlu, $lcgap, 67dlu, $lcgap, 57dlu, 2*($lcgap, default)",
                        "3*(default, $lgap), default"));

                    //---- labelFeePercent ----
                    labelFeePercent.setText(bundle.getString("TraderMainForm.labelFeePercent.text"));
                    labelFeePercent.setLabelFor(spinnerFeePercent);
                    panelSettings.add(labelFeePercent, CC.xy(3, 1));

                    //---- spinnerFeePercent ----
                    spinnerFeePercent.setModel(new SpinnerNumberModel(0.2, 0.0, 100.0, 0.1));
                    spinnerFeePercent.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            settingsChanged(e);
                        }
                    });
                    panelSettings.add(spinnerFeePercent, CC.xy(5, 1));

                    //---- toggleButtonUpdateAll ----
                    toggleButtonUpdateAll.setText(bundle.getString("TraderMainForm.toggleButtonUpdateAll.text"));
                    toggleButtonUpdateAll.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            toggleButtonUpdateAllStateChanged(e);
                        }
                    });
                    panelSettings.add(toggleButtonUpdateAll, CC.xy(9, 1));

                    //---- labelUpdateInterval ----
                    labelUpdateInterval.setText(bundle.getString("TraderMainForm.labelUpdateInterval.text"));
                    labelUpdateInterval.setLabelFor(spinnerUpdateInterval);
                    panelSettings.add(labelUpdateInterval, CC.xy(3, 3));

                    //---- spinnerUpdateInterval ----
                    spinnerUpdateInterval.setModel(new SpinnerNumberModel(500, 0, 30000, 50));
                    spinnerUpdateInterval.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            settingsChanged(e);
                        }
                    });
                    panelSettings.add(spinnerUpdateInterval, CC.xy(5, 3));

                    //---- buttonApplySettings ----
                    buttonApplySettings.setText(bundle.getString("TraderMainForm.buttonApplySettings.text"));
                    buttonApplySettings.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            buttonApplySettingsActionPerformed(e);
                        }
                    });
                    panelSettings.add(buttonApplySettings, CC.xywh(3, 5, 3, 1));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelSettings.tab.title"), panelSettings);

                //======== panelLog ========
                {
                    panelLog.setLayout(new FormLayout(
                        "default:grow",
                        "fill:[55dlu,default]:grow"));

                    //======== scrollPane5 ========
                    {
                        scrollPane5.setViewportView(textPaneLog);
                    }
                    panelLog.add(scrollPane5, CC.xy(1, 1));
                }
                tabbedPaneInfo.addTab(bundle.getString("TraderMainForm.panelLog.tab.title"), panelLog);
            }
            splitPane1.setBottomComponent(tabbedPaneInfo);
        }
        add(splitPane1, CC.xywh(1, 5, 3, 5, CC.FILL, CC.FILL));

        //======== popupMenuOrders ========
        {

            //---- menuItemCancelOrder ----
            menuItemCancelOrder.setText(bundle.getString("TraderMainForm.menuItemCancelOrder.text"));
            menuItemCancelOrder.setForeground(Color.red);
            menuItemCancelOrder.setIcon(new ImageIcon(getClass().getResource("/icons/delete.png")));
            menuItemCancelOrder.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    menuItemCancelOrderActionPerformed(e);
                }
            });
            popupMenuOrders.add(menuItemCancelOrder);
        }

        //======== popupMenuTimeframe ========
        {

            //---- radioButtonMenuItem1M ----
            radioButtonMenuItem1M.setText("1M");
            radioButtonMenuItem1M.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    radioButtonMenuItem1MActionPerformed(e);
                }
            });
            popupMenuTimeframe.add(radioButtonMenuItem1M);

            //---- radioButtonMenuItem15M ----
            radioButtonMenuItem15M.setText("15M");
            radioButtonMenuItem15M.setFont(radioButtonMenuItem15M.getFont().deriveFont(radioButtonMenuItem15M.getFont().getStyle() & ~Font.BOLD));
            radioButtonMenuItem15M.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    radioButtonMenuItem15MActionPerformed(e);
                }
            });
            popupMenuTimeframe.add(radioButtonMenuItem15M);

            //---- radioButtonMenuItem30M ----
            radioButtonMenuItem30M.setText("30M");
            radioButtonMenuItem30M.setSelected(true);
            radioButtonMenuItem30M.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    radioButtonMenuItem30MActionPerformed(e);
                }
            });
            popupMenuTimeframe.add(radioButtonMenuItem30M);

            //---- radioButtonMenuItem1H ----
            radioButtonMenuItem1H.setText("1H");
            radioButtonMenuItem1H.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    radioButtonMenuItem1HActionPerformed(e);
                }
            });
            popupMenuTimeframe.add(radioButtonMenuItem1H);
        }

        //---- buttonGroupTimeframe ----
        ButtonGroup buttonGroupTimeframe = new ButtonGroup();
        buttonGroupTimeframe.add(radioButtonMenuItem1M);
        buttonGroupTimeframe.add(radioButtonMenuItem15M);
        buttonGroupTimeframe.add(radioButtonMenuItem30M);
        buttonGroupTimeframe.add(radioButtonMenuItem1H);
        // JFormDesigner - End of component initialization  //GEN-END:initComponents
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
    private JComboBox comboBoxPair;
    private JSeparator separator3;
    private JPanel panelPrice;
    private JLabel labelBuyPrice;
    private JLabel labelLastPrice;
    private JLabel labelSellPrice;
    private JTextField textFieldBuyPrice;
    private JTextField textFieldLastPrice;
    private JTextField textFieldSellPrice;
    private JLabel labelLowPrice;
    private JLabel labelPriceChange;
    private JLabel labelHighPrice;
    private JTextField textFieldLowPrice;
    private JLabel labelPriceChangePercent;
    private JTextField textFieldHighPrice;
    private JLabel labelAvgPrice;
    private JLabel labelApiLag;
    private JLabel labelVolume;
    private JTextField textFieldAvgPrice;
    private JLabel labelApiLagValue;
    private JTextField textFieldVolume;
    private JSeparator separator1;
    private JSplitPane splitPane1;
    private JTabbedPane tabbedPaneTrade;
    private JPanel panelBuy;
    private JLabel labelBuyOrderPrice;
    private JSpinner spinnerBuyOrderPrice;
    private JButton buttonBuyOrderPriceSetCurrent;
    private JButton buttonCommitBuyOrder;
    private JLabel labelBuyOrderAmount;
    private JSpinner spinnerBuyOrderAmount;
    private JSlider sliderBuyOrderAmount;
    private JLabel labelBuyOrderTotal;
    private JLabel labelBuyOrderTotalValue;
    private JPanel panelSell;
    private JLabel labelSellOrderPrice;
    private JSpinner spinnerSellOrderPrice;
    private JButton buttonSellOrderPriceSetCurrent;
    private JButton buttonCommitSellOrder;
    private JLabel labelSellOrderAmount;
    private JSpinner spinnerSellOrderAmount;
    private JSlider sliderSellOrderAmount;
    private JLabel labelSellOrderTotal;
    private JLabel labelSellOrderTotalValue;
    private JPanel panelRules;
    private JScrollPane scrollPane2;
    private JTable tableRules;
    private JToolBar toolBar1;
    private JButton buttonAddRule;
    private JButton buttonDeleteRule;
    private JTabbedPane tabbedPaneInfo;
    private JPanel panelOrders;
    private JScrollPane scrollPane4;
    private JTable tableOpenOrders;
    private JPanel panelBalance;
    private JScrollPane scrollPane3;
    private JTable tableBalances;
    private JPanel panelDepth;
    private JLabel labelBuyOrders;
    private JLabel labelSellOrders;
    private JScrollPane scrollPaneBuyOrders;
    private JTable tableBuyOrders;
    private JScrollPane scrollPaneSellOrders;
    private JTable tableSellOrders;
    private JTabbedPane panelHistory;
    private JPanel panelMyTrades;
    private JScrollPane scrollPane6;
    private JTable tableAccountHistory;
    private JPanel panelMarketTrades;
    private JScrollPane scrollPane7;
    private JTable tableMarketHistory;
    private JPanel panelCharts;
    private JPanel panelMarketCap;
    private JScrollPane scrollPane1;
    private JTable tableMarketCap;
    private JPanel panelSettings;
    private JLabel labelFeePercent;
    private JSpinner spinnerFeePercent;
    private JToggleButton toggleButtonUpdateAll;
    private JLabel labelUpdateInterval;
    private JSpinner spinnerUpdateInterval;
    private JButton buttonApplySettings;
    private JPanel panelLog;
    private JScrollPane scrollPane5;
    private JTextPane textPaneLog;
    private JPopupMenu popupMenuOrders;
    private JMenuItem menuItemCancelOrder;
    private JPopupMenu popupMenuTimeframe;
    private JRadioButtonMenuItem radioButtonMenuItem1M;
    private JRadioButtonMenuItem radioButtonMenuItem15M;
    private JRadioButtonMenuItem radioButtonMenuItem30M;
    private JRadioButtonMenuItem radioButtonMenuItem1H;
    // JFormDesigner - End of variables declaration  //GEN-END:variables
}
TOP

Related Classes of com.archean.jtradegui.TraderMainForm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.