Automatically Sorting a JavaFX TableView

With the SortedList implementation of ObservableList, automatically sorting a JavaFX TableView nearly works out of the box. In fact, it does work out of the box as long as you are adding or removing items from the list. In these circumstances, the list and the accompanying TableView will automatically resort the data. The case where the data isn’t automatically resorted is if the data in the existing rows change, but no rows are added or removed from the list.

For example, I have a TableView displaying various price information about a list of stocks including the last price, and the percent change from yesterday’s closing price. I would like to sort the list based on percent change, from lowest to highest as the prices change in real-time.  However since the app just loads the stocks into the list once and then never adds or removes items from the list, the TableView only auto sorted on the initial load, but did not automatically sort as the prices were updated.

Fortunately the fix proved to be fairly minor and easy to implement.

To start with, the application uses a Stock POJO which contains the following properties to represent the data. An ObservableList of these POJOs will be the basis of the data that the TableView will render.

public class Stock implements Level1QuoteListener {

protected StockTicker ticker;

protected SimpleStringProperty symbol = new SimpleStringProperty("");

protected SimpleDoubleProperty bid = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty ask = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty last = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty percentChange = new SimpleDoubleProperty(0);

protected SimpleIntegerProperty volume = new SimpleIntegerProperty(0);

protected SimpleDoubleProperty previousClose = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty open = new SimpleDoubleProperty(0);

 

The first step is to implement a new Callback, tying it to the property we wish to sort in the table. When this property is updated it will trigger the table to resort itself automatically.

      Callback<Stock,Observable[]> cb =(Stock stock) -> new Observable[]{
        stock.percentChangeProperty(),
    };

 

The next step is to create a new ObservableList using the Callback above.

      ObservableList<Stock> observableList = FXCollections.observableArrayList(cb);
      observableList.addAll(stocks);

Finally the last step is to create a new SortedList using the ObservableList previously created and also passing in an implementation of a Comparator which will be used to determine how to sort the data.

      SortedList<Stock> sortedList = new SortedList<>( observableList, 
      (Stock stock1, Stock stock2) -> {
        if( stock1.getPercentChange() < stock2.getPercentChange() ) {
            return -1;
        } else if( stock1.getPercentChange() > stock2.getPercentChange() ) {
            return 1;
        } else {
            return 0;
        }
    });


    tickerTableView.setItems(sortedList);
}

That’s it. The video below illustrates the auto-sorting in action as the price of the stocks are updated in real-time.


twitter: @RobTerpilowski

Advertisements

Formatting Rows in a JavaFX TableView Using CSS Pseudo Classes

One strategy for formatting cells in a JavaFX TableView is to utilize CSS Pseudo classes and a TableRowFactory to select the appropriate class to style the row. Below is a screenshot of an applcation that is configured to monitor real time stock quotes. Each row displays price information for a single stock. I would like the rows to be colored based on the price change of the particular stock, with a red row representing a stock that is trading lower since the previous day, and a green row to represent a stock whose current price is higher than the previous day.

enter image description here

First the domain object which represents the Stock is below. Notice that the class uses JavaFX properties to represent the various values that are displayed in each column.

public class Stock implements Level1QuoteListener {

protected StockTicker ticker;
protected SimpleStringProperty symbol = new SimpleStringProperty();
protected SimpleDoubleProperty bid = new SimpleDoubleProperty();
protected SimpleDoubleProperty ask= new SimpleDoubleProperty();
protected SimpleDoubleProperty last = new SimpleDoubleProperty();
protected SimpleDoubleProperty percentChange = new SimpleDoubleProperty();
protected SimpleIntegerProperty volume = new SimpleIntegerProperty();
protected SimpleDoubleProperty previousClose = new SimpleDoubleProperty();
protected SimpleDoubleProperty open = new SimpleDoubleProperty();


public Stock( StockTicker ticker ) {
    this.ticker = ticker;
    setSymbol( ticker.getSymbol() );
}

public void setSymbol( String symbol ) {
    this.symbol.set(symbol);
}

public String getSymbol() {
    return symbol.get();
}

public StringProperty symbol() {
    return symbol;
}

public void setBid( double bid ) {
    this.bid.set(bid);
}

public double getBid() {
    return bid.get();
}

public SimpleDoubleProperty bid() {
    return bid;
}

public void setAsk( double ask ) {
    this.ask.set(ask);
}

public double getAsk() {
    return ask.get();
}

public DoubleProperty ask() {
    return ask;
}

public void setLast( double last ) {
    this.last.set(last);
    double change = ((last-closeProperty().get() ) / closeProperty().get() ) * 100.0;
    setPercentChange(change);

}

public double getLast() {
    return last.get();
}

public DoubleProperty last() {
    return last;
}

public void setPercentChange( double percentChange ) {
    this.percentChange.set(percentChange);
}

public double getPercentChange() {
    return percentChange.get();
}

public void setVolume( int volume ) {
    this.volume.set(volume);
}

public int getVolume() {
    return volume.get();
}

public void setPreviousClose( double close ) {
    this.previousClose.set(close);
    double change = ((last.get()-close ) / close ) * 100.0;
    setPercentChange(change);
}


public double getPreviousClose() {
    return previousClose.get();
}

public DoubleProperty previousClose() {
    return previousClose;
}

public void setOpen( double open ) {
    this.open.set(open);
}

public double getOpen() {
    return open.get();
}

public DoubleProperty openProperty() {
    return open;
}

public DoubleProperty closeProperty() {
    return previousClose;
}

public DoubleProperty percentChangeProperty() {
    return percentChange;
}

public StockTicker getTicker() {
    return ticker;
}



@Override
public void quoteRecieved(ILevel1Quote quote) {
    if( quote.getTicker().equals(ticker)) {
        BigDecimal quoteValue = quote.getValue();
        switch( quote.getType() ) {
            case ASK:
                setAsk(quoteValue.doubleValue());
                break;
            case BID:
                setBid(quoteValue.doubleValue());
                break;
            case LAST:
                setLast(quoteValue.doubleValue());
                break;
            case CLOSE:                  
                setPreviousClose(quoteValue.doubleValue());
                break;
            case OPEN:
                setOpen(quoteValue.doubleValue());
                break;
            case VOLUME:
                setVolume(quoteValue.intValue());
                break;
            default:
                break;

        }
    }
}

The first step in creating a custom format is to define the styles in the CSS stylesheet that is associated with the TableView. The CSS file below shows how the table row will be formatted. Comments below describe each item including the ‘up’ and ‘down’ Pseudo classes that are defined for the .table-row-cell class.

/* Default row background is black */
.table-row-cell {
    -fx-background-color: black;
}

/* Text in the rows will be white */
.table-row-cell .text {
       -fx-fill: white ;
}

/*
Pseudo class 'up' will change the row background
 color to green when activated 
 */
.table-row-cell:up 
{
    -fx-background-color: #007054; 
}

/*
Pseudo class 'down' will change the row background 
color to red when activated
*/
.table-row-cell:down {
    -fx-background-color: #A30029;
}

Ok, so far this seems easy enough. Now the tricky part is to activate the proper Pseudo class when the % change of the stock price is positive or negative. This can be done using a TableRowFactory in the controller class which is managing the TableView.

Below is an example controller which has a reference to a TableView object called tickerTableView. The setup() method contains logic for selecting the appropriate pseudo class based on the stock data.

public class FXMLController implements Initializable {


@FXML
private TableView tickerTableView;


 public void setup() {
 //The pseudo classes 'up' and 'down' that were defined in the css file.
    PseudoClass up = PseudoClass.getPseudoClass("up");
    PseudoClass down = PseudoClass.getPseudoClass("down");



//Set a rowFactory for the table view.
tickerTableView.setRowFactory(tableView -> {
        TableRow<Stock> row = new TableRow<>();
        ChangeListener<Number> changeListener = (obs, oldPrice, newPrice) -> {
            row.pseudoClassStateChanged(up, newPrice.doubleValue() > 0);
            row.pseudoClassStateChanged(down, newPrice.doubleValue() <= 0);
        };

        row.itemProperty().addListener((obs, previousStock, currentStock) -> {
            if (previousStock != null) {
                previousStock.percentChangeProperty().removeListener(changeListener);
            }
            if (currentStock != null) {
                currentStock.percentChangeProperty().addListener(changeListener);
                row.pseudoClassStateChanged(up, currentStock.getPercentChange() > 0);
                row.pseudoClassStateChanged(down, currentStock.getPercentChange() <= 0);
            } else {
                row.pseudoClassStateChanged(up, false);
                row.pseudoClassStateChanged(down, false);
            }
        });
        return row;
    });
}

The first step is to create 2 new PseudoClass object which will map to the Pseudo classes that were defined in the css file.

PseudoClass up = PseudoClass.getPseudoClass("up");
PseudoClass down = PseudoClass.getPseudoClass("down");

Next a RowFactory needs to be defined which knows how to select the proper PseudoClass. The setRowFactory() method on the TableView class takes a Callback object which in turn takes a TableView as an argument and returns a TableRow.

The first thing to do in the row factory is to create a new change listener. This listener will monitor the stock for a particular row. The oldPrice and newPrice are passed into the change listener. The pseudo class of the row can then be activated or deactivated by invoking the pseudoClassStateChanged() method on the TableRow and passing the appropriate PseudoClass and boolean value to indicate whether or not the class should be active.

tickerTableView.setRowFactory(tableView -> {
   TableRow<Stock> row = new TableRow<>();
   ChangeListener<Number> changeListener = (obs, oldPrice, newPrice) -> {
     row.pseudoClassStateChanged(up, newPrice.doubleValue() > 0);
     row.pseudoClassStateChanged(down, newPrice.doubleValue() <= 0);
   };

The final piece is to tie the change listener to the item in the TableRow. This is done by adding a listener on the ItemProperty of the row. Once a Stock item is added to the TableRow, the ChangeListener defined above can be bound to the Stock’s percentChangeProperty. The initial state of the classes are also set when the new item is added. If a Stock item is being removed from the TableRow, the previousStock variable will be populate with the Stock object that is being removed. At this point the change listener can be removed from the row for the old Stock before the new one is added.

row.itemProperty().addListener((obs, previousStock, currentStock) -> {
            if (previousStock != null) {
                previousStock.percentChangeProperty().removeListener(changeListener);
            }
            if (currentStock != null) {
                currentStock.percentChangeProperty().addListener(changeListener);
                //Set the initial state of the pseudo classes
                row.pseudoClassStateChanged(up, currentStock.getPercentChange() > 0);
                row.pseudoClassStateChanged(down, currentStock.getPercentChange() <= 0);
            } else {
                row.pseudoClassStateChanged(up, false);
                row.pseudoClassStateChanged(down, false);
            }
        });
        return row;
    });

The final result is displayed in the table below Rows will change between red and green automatically in real time as the price of the stock fluctuates throughout the trading day.

enter image description here

twitter: @RobTerpilowski

Designing an Automated Trading Application on the Netbeans Rich Client Platform (Part 1)

Over the past 10 years new opportunities have opened in the stock, futures and currency markets to allow retail traders the ability to produce their own automated trading strategies which was once only the realm of hedge funds and investment banks.  Interactive Brokers was one of the first brokerage firms to offer a Java API to its retail customers. Originally envisioned as way for developers to augment Interactive Brokers Trader Workstation (TWS) desktop application with features such as charting or record keeping, the API has gained popularity as a way to automate trading strategies.

In my first iteration of developing a trading strategy and software to automate the trades I built a Java desktop application using Swing components which would monitor stocks throughout the day and place trades when certain parameters were met, and then exit the trades at the close of the trading day. The software worked well, and it was adequate for the strategy it was designed to trade, however it was not extensible and attempting to implement new trading strategies to automate as well as connect to different brokerage accounts proved difficult and cumbersome.  Also, there are restrictions on how many stocks could be monitored via the broker’s data feed so the software had to be able to accommodate real-time market data feeds from other sources in addition to the broker’s data feed. 

I was introduced to the Netbeans Rich Client Platform (RCP) a couple of years ago and have recently decided to begin porting my application to the platform due to a large number of advantages that it provides.  The Netbeans RCP is built on a modular design principle allowing the developer to define abstract APIs for features and then provide modules which may have different implementations of the API, allowing the application to select at runtime which implementation to use.  Not only does it provide for a cleaner design by separating concerns, but by using the Netbeans Lookup API it also decouples the application and its various components from each other.  There are numerous other features that can be leveraged including a built-in windowing system, text editor, file explorer, toolbar, table and tree table components as well the Action API (just to name a few).

The trading application will make use of the RCP module system to define abstract APIs with the following functionality:

Broker API

  • Place and cancel orders for stocks, options, futures, or currencies
  • Provide event notification when orders are filled
  • Monitor cash balances in the account

Market Data API

  • Subscribe to real-time quote data for any ticker symbol
  • Subscribe to Level 2 data (market depth/order-book) for any ticker symbol

Historical Data API

  • Request historical price data for any ticker symbol

Trading Strategy API

  • Define a set of rules for entering and exiting trades
  • Ability to use any broker, market data, and historical data API implementations in order to make trading decisions.

The primary implementation for the Broker, Market Data and Historical data API modules will be utilizing Interactive Broker’s Java API,  but other implementations can also be created  as Netbeans modules and then imported into the trading application so that trading strategies can make use of market data from different sources if needed.

New trading strategies can be built as Netbeans modules  implementing the Trading Strategy API, where each strategy can make use of one of the implementations of the various data and broker APIs.  Utilizing the Netbeans Lookup API, strategies can query the platform to get a list of all implementations of the broker and market data APIs providing for loose coupling between the APIs and allowing the user to select which implementation to use at runtime.
Below is a diagram illustrating the organization of the various API components of the application:

In future posts I will go into more detail on how to create an API plug-in for the Netbeans RCP as well as show how to create a concrete implementation of the API.  In the illustration above the abstract broker, market data, and trading strategy APIs are installed into the RCP as plug-ins.  The broker API has a single implementation for Interactive Brokers at this point in time.  The market data API has plug-ins which provide implementations for real-time market data from Yahoo Finance as well as Interactive Brokers real-time market data.  Finally, the trading strategy API has 2 implementations in this example.  The first strategy named “Limit Buyer” will watch the prices of approx 800 stocks and place limit order to buy when certain conditions are met.  The second strategy in the example above, named AUD/NZD Currency Strategy will monitor the exchange rates of the Australian and New Zealand dollars and place orders to buy or sell when certain conditions are met.  

At this point in time the application is functional and is utilizing Interactive Brokers as the main brokerage as well as market data provider.  The AUD/NZD trading strategy is actively being traded through the application, albeit with a rudimentary user interface which is publishing messages to a text area within the strategy’s main tab.  The screenshot below illustrates Interactive Brokers “Trader Workstation” application, the large black application (which is a Java Swing app), as well as the Netbeans RCP automated trading application which is the small white application, with the large text area.  In the screenshot below the application is currently monitoring prices and placing trades for the Australian Dollar, New Zealand dollar, Hong Kong dollar and Japanese yen currencies.

screenshot

 

This post is just a high level overview on the design of an RCP application to trade in the financial markets.  Future parts to this series will include more information on how to implement abstract APIs and make them available for other portions of the application to use via the Netbeans Lookup API as well as working with some of the Netbeans UI components included with the platform such as tabs, trees and tables, showing how easy it is to render the same data via these different views using the Netbeans Nodes API.  In addition to this I would like to incorporate some JavaFX components into the application such as the charting components that can be found in the core JavaFX library which will provide a graphical representation of some of the data the strategies are monitoring which will be a bit more user friendly than the current large text area.  The integration of JavaFX components within the application will be documented in a future post as well.

You can follow my trading related blog if you would like to see the actual trading results of the application as its being refined at:
http://LimitUpTrading.wordpress.com

twitter: @RobTerp
twitter: @LimitUpTrading