The intelligence of machines and the branch of computer science which aims to create it

Artificial Intelligence Journal

Subscribe to Artificial Intelligence Journal: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Artificial Intelligence Journal: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Artificial Intelligence Authors: Jason Steinbach, Yeshim Deniz, Liz McMillan, Pat Romanski, Zakia Bouachraoui

Related Topics: Artificial Intelligence Journal

Artificial Intelligence: Article

Timing the Market with Distributed Genetics - Part 2

Picking the best stocks for investing a fixed amount of money

Special Needs for Picking Stocks
Since the MSDN article produced a genetic solution for ants gathering food and we're looking for a solution that lets us pick a good set of stocks for a 24-hour investment, clearly some adaptations have to be made. There are three classes in particular that we need to create: StockPicker, Stock, and TerminationReport.

Listing 1 contains our StockPicker class. Our solution will use this class as the template for generating multiple random algorithms that will all attempt to pick the best selection of stocks for us. The empty "Execute" method at the start of the listing is the method whose body will be randomly generated for this purpose. The "Init" method is a special method that is exempt from potential use by our randomly generated code, as it is the code that is called first by the application to initialize every randomly generated algo. The methods in the "Terminals" region are fair game for use in the randomly generated algorithms - they are how the actual purchasing actions will be registered for later evaluation.

All of the properties in the "Functions" region will be used as the basis for making Buy, Sell, or Ignore decisions as the algorithm works its way down the list of stocks available for selection. A key bit of understanding about the nature of genetic algorithms should be apparent as you read through these properties - a genetic algorithm is only as good as the information you give it to make its decisions.

This should be true intuitively if you remember that a genetic algorithm is an artificial intelligence pattern and, as such, will try to model the way that humans like you or I solve problems. If we are asked to decide whether or not to sell our house, and are then given the temperature outside and Noel Fielding's home telephone number as the basis for making our decision, we are unlikely to make a very good decision. On the other hand, if we are given an index of recent house prices in our area and expectations of future economic patterns, we would probably do better.

The same concept applies here. "HasEPSAboveOneDollar" is a (relatively) good basis for making a stock trading decision. "StartsWithTheLetterA" is a fairly poor fact to consider in trying to make such a decision. One of the first things you should think about when building a genetic solution then is what kinds of data are going to be relevant to arriving at the right solution - whatever that might be.

That evaluation of a random algo's suitability is conducted by the ConcludingReport property - assisted by the ComputeReturns helper method. When the property value is requested, it iterates through lists of all the bought, sold, and ignored stocks. As described in the previous article, the returns on these actions are computed and returned as a single numeric value that will be used to judge the efficiency of the algorithm.

ConcludingReport returns a TerminationReport, which is shown in Listing 2. The TerminationReport serves as a container for the evaluation of a given random algorithm. It performs two vital functions in this capacity. First, by dividing the initial amount of cash by the final amount of cash, it allows all algorithms to be compared equally regardless of the absolute prices of the stocks chosen by any of them. Second, it implements the IComparable interface in such a way that this scaled ROI is used as the basis for comparing multiple TerminationReports against one another.

The stock class is shown in Listing 3. Its purpose is to wrap the market data retrieved for the individual stocks on the stock list and allow it to be easily consumed by the automatically generated C# code. Since the format of the market data we retrieve is XML, our Stock class parses this XML in its constructor and stores it in local variables that are then exposed as public properties. This class could be easily adjusted for any other source of market data that might be provided without requiring changes in any of the rest of the application.

The Grid
In the first part of this article, I indicated that I would be using the Executive Worker pattern for the grid enablement of my genetic algorithm. My thinking at that point was that I would have all of the random algorithms generated in the central application, then sent out to the Grid for execution, but returned to the main application for comparison, prior to breeding and a repeat of the entire pattern with a new generation. If you think about this for a moment though (as I did after the previous article), you realize that this has some significant disadvantages.

First, in this model, the load of creating each new generation is put entirely on the central application. This makes the central application a potential bottleneck in the system's ability to proceed quickly and smoothly from one generation to the next. In building a grid-enabled system, work should be off-loaded onto remote agents whenever possible.

Second, the amount of bandwidth used in this model could be considerable. Consider a generation of 100,000 random algorithms. If every random algorithm is 10k, this is a full gigabyte of data that needs to be round-tripped from the client to the Grid at the start of every generation. This exact same data needs to be round-tripped back again at the end of that generation. The particularly painful part about this round-tripping is that the actual implementation of every random algorithm would be sent back to the client application at the end of every generation, when all that the client application really needs is the metadata and a relative success rating.

For this reason, I decided to implement this system using the Executive Executable pattern instead. The Executive Executable system lets us have a user-defined process running on the remote agents that continue to reside in memory between every Task in a given Job. By modeling each generation in our genetic solution as a Job and every random algorithm in a given generation as a Task, we can leverage Digipede's rich Web-based monitoring and administration interface to track the progress of our genetic Grid as it runs.

The MasterApp class shown in Listing 4 represents the main centralized client executable for our grid solution. The Main method in this class begins by parsing the arguments passed into the application on the command line. As you can see, Digipede includes support in the DigipedeClient class for extracting parameters from the command line and using them, if it understands them. In our case, we are passing four parameters. The first two of these are Digipede-related "/host BS128686" - meaning that our client should connect to BS128686 as the main host system for our Grid application.

The specific body of our Main method comprises just a few calls. We begin by creating a first generation of our stock-picking algos. The first generation is different from all other generations, because it is the only generation that is produced entirely at random, rather than being "bred" from previous generations.

After this, we copy the seeds returned by the first generation. This operation represents one of the key hurdles I had to overcome in architecting this solution. If you skip to the TaskCompleted method at the end of Listing 4, you will see the event handler that is executed every time Digipede informs our application that a Task (which, recall, represents a single genetic algo instance in our solution) has finished being run.

More Stories By Derek Ferguson

Derek Ferguson, founding editor and editor-in-chief of .Net Developer's Journal, is a noted technology expert and former Microsoft MVP.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.