My attempt at a market analytics application for EVE Online.

The Idea

Anyone who has played with the markets on EVE Online before will probably have something to say about the number of times they had to keep their orders on top of everyone else’s, or the sheer amount of time required to sift through all the items on the market one-by-one in search of a good trade.

Feeling rather burnt out, I arrived at the decision of creating a market application for myself. Sure, there are already existing ones out there (such as this one), but this project gave me an opportunity to learn GUI development, expanding on programming knowledge I gained from a basic course in high school.

Setup

I tried using wxPython to design the user interface at first, since that was the first thing that showed up when I looked up ‘Python GUI framework’. However, it was akin to using an excavator when you only needed a shovel – there was too much detail in its design which created unnecessary complexity, in turn hindering the developmental process.

The solution was switching to PyQt, a python binding for the Qt GUI framework. There are many tutorials available (such as this one) which helped me in understanding the basics of GUI design in Python, and converting the design on paper to a working interface.

The market ‘scanner’ was designed to do the following:

Grab data for the relevant market items Format and display the information, highlighting ideal trades

Pulling data from APIs

I chose to extract data from the CREST API for the application, as it was provided by CCP (the company that develops and maintains EVE Online). API pulls take quite some time, especially with the sheer number of items that the game has. I split up the items into chunks of 40, and created a QDialog window with a progress bar and a couple labels to visually display the process of data collection.

This was when I noticed the application would freeze when the collection routine was initiated, only responding after all the data was acquired, defeating the purpose of the dialog to begin with.

It turns out this is because Qt’s event loop wasn’t given a chance to run after the individual chunks of data had been retrieved. Stack Overflow suggested using the processEvents() function to fix this, but that didn’t work either as calling the functions QLabel.setText() or QProgressbar.setValue() already repaints the visual elements. All it does is queue the paint events which never gets processed since the subsequent API data pull is already in underway.

Fixing this problem required the use of QThread(), provided by PyQt as a platform-independent way of managing threads on an application. Creating a separate work thread to retrieve and process data from the API endpoint allows me to send a signal to the main thread to update the dialog every time a chunk of the collection was done.

Displaying the data

Once all the data is collected, all that’s left is to format the numbers nicely (eg. adding the thousands separator for large numbers) and display them on the table. QTableWidget provided by the framework conveniently allows sorting of items so I can determine which items to trade.

We can’t just call it a day though, due to how Python compares strings to carry out sorting. The string comparison uses character-by-character comparison, terminating once it arrives at a mismatch (eg. ’13’ > ‘120’ will return True as ‘3’ > ‘2’). The locale module I used to generate the comma separators on the output had inadvertently converted the floating point values into strings, resulting in all the table columns with numerical values to be sorted incorrectly.

The solution is to implement sort keys for the necessary columns, which will override the default sorting mechanism by telling python to use the raw values in comparing the table entries.