Charting for Java: Building a Charting Applet for Technical Stock Analysis

By Dr P.G. Sarang

Traders, brokers, and investors are just a few of the people interested in technical analysis of stocks. In the market, several technical analysis programs run on stand-alone machines. The users of such software download the daily quotation files to update their databases on a day-to-day basis. This isn't just time-consuming, but also prone to errors; users risk corrupting the database while updating it.

Many Web sites maintain their own quotation databases. Users can access these databases for a small fee (sometimes even free of charge). Some sites provide definable charts on the data in which users can define the type of chart, such as a close-price chart, or an OHLC (Open, High, Low, Close) chart. Users specify the desired indicator and request a chart for a particular scrip. The server in turn dynamically generates the chart and returns it to the user as an image file. Unfortunately, no further technical analysis is possible on such charts — they are restricted to viewing.

Figure 1: The user interface of our applet.

In this article, we'll discuss the design and implementation of a Java applet that performs technical analysis of charts, commodities, currencies, etc. The database is maintained on the server. For every security, a separate data file is maintained. The server administrator updates these database files every day; thus users are relieved of maintaining the database at their end. (If you aren't familiar with technical analysis of stocks, see the sidebar "Technical Analysis of Stocks" on page X for a quick review.)

Our Applet

The user interface of the applet is shown in Figure 1, and the HTML code used for running the applet is shown in Figure 2. This applet uses several parameters:

CoCode specifies the stock symbol for which the chart is to be loaded.

CoName specifies the name of the stock.

Avg1Day and Avg2Day specify the values for the first and second moving averages.

Indicator specifies the type of indicator (e.g. ROC, RSI, etc.).

IndPeriod specifies the number of days for indicator calculations.

IndAvgPeriod specifies the number of days for calculating the average on the indicator data.

Period specifies the period for plotting; it can be daily, weekly, or monthly.

GraphType specifies the type of chart, which can be an OHLC, HLC, or close-price chart.

<HTML>
<HEAD>
<TITLE>Charts</TITLE>
</HEAD>
<BODY BGColor=FFFFFF>
<CENTER>
<APPLET CODE=Charts.class ID=Charts WIDTH=600 HEIGHT=300>
  <PARAM NAME=CoCode VALUE="aa"> <! ticker symbol >
  <PARAM NAME=CoName VALUE="American Airlines">
    <! stock name >
  <PARAM NAME=Avg1Day VALUE="12"> 
    <! The period 1st average >
  <PARAM NAME=Avg2Day VALUE="48">
    <! The period 2nd average >
  <PARAM NAME=Indicator VALUE="ROC">
    <! Can be either ROC or RSI >
  <PARAM NAME=IndPeriod VALUE="12">
    <! Period of the Indicator >
  <PARAM NAME=IndAvgPeriod VALUE="24"> 
  <PARAM NAME=Period VALUE="W"> <! Can be "D","W","M" >
  <PARAM NAME=GraphType VALUE="OHLC">
    <! Can be "Close","HLC","OHLC" >
</APPLET>
</CENTER>
</BODY>
</HTML> 

Figure 2: The code for running our applet.

This applet consists of several Java classes. The main class for the applet is named Charts. The user interface of the applet consists of two vertically-split portions. The left side displays the chart for the selected scrip, and the right side displays the chart details. The chartCanvas class is responsible for displaying the chart, and the DetailPanel class is used to display the chart status. The graphData class holds the data for the selected scrip, and the rawData class represents the structure of the underlying data file. In addition, the TemplateData class holds the information on the various parameters used for plotting. The Average class represents the moving averages plotted on the chart and holds the averages data. Similarly, the Indicator class represents the indicator that is plotted below the chart and holds the calculated data for the indicator. The diagram shown in Figure 3 illustrates the relationship between the different classes.

Figure 3: The relationship between the classes.

The rawData Class

Let's discuss the design of the applet by studying the various classes it uses. We'll start with the rawData class, which represents the daily scrip data. This class has data members in Figure 4.  Tradedate represents the date of trade, and Day represents the day count with respect to the start date of data. OpenPrice, HighPrice, LowPrice, and ClosePrice represent open, high, low, and close prices for the stock on a selected trade day. Finally, Volume represents the transaction volume on a selected trade day.

public Date  Tradedate;
public int   Day;
public float OpenPrice;
public float HighPrice;
public float LowPrice;
public float ClosePrice;
public long  Volume;

Figure 4: The data member of rawData.

The rawData class defines a read method, which is used for reading the data from the data file. The method receives DataInputStream as a parameter, reads a record from the underlying stream, and initializes the class fields (see Figure 5). Listing One on page X shows the complete code for rawData.

public int read (DataInputStream finStream) {
  long lTemp;
  try {
    lTemp      = finStream.readLong();
    date       = new Date(lTemp);
    OpenPrice  = finStream.readFloat();
    HighPrice  = finStream.readFloat();
    LowPrice   = finStream.readFloat();
    ClosePrice = finStream.readFloat();
    Volume     = finStream.readLong();
  }
  catch (EOFException e) { ... }
}

Figure 5: Defining the read method.

The graphData Class

The next class, graphData, declares three array variables for storing objects of the rawData class (see Figure 6). The objRawData array stores the rawData objects containing the daily quotation values for the selected stock. The objRawMonthData array stores rawData objects containing the monthly prices and objRawWeekData array stores weekly prices. The monthly and weekly open, high, low, and close prices are computed from the daily quotations and stored in these arrays. The ptrRawData variable is used as a pointer to the active list. At any given time, only one of the data lists is active, and the chart corresponding to that period is plotted. The daily, weekly, and monthly prices are stored in separate data arrays, so that when the user switches between different chart periods, the new chart can be generated quickly.

rawData[] objRawData;      // The list of data.
rawData[] objRawMonthData; // The month list of data.
rawData[] objRawWeekData;  // The week list of data.
rawData[] ptrRawData;      // Will point to active list.

Figure 6: graphData declares three array type variables.

The graphData class contains a data member called NumberOfDays, which stores the number of trade points for a selected scrip. This variable is initialized after reading the entire data file. Similarly, the NumberOfWeeks variable stores the number of trade points for the weekly data. This is initialized after computing the weekly data. Likewise, the NumberOfMonths variable holds the number of trade points for monthly data and is initialized in the calculation of monthly data.

graphData also declares a data member called m_Template of type TemplateData:

// Points to the various properties of the graph.
TemplateData m_Template;

In addition, this class stores information about the various parameters used by the active chart.

The graphData constructor first creates the TemplateData object. The TemplateData constructor initializes its data members using the parameters passed in HTML. (This class is discussed later.) The graphData constructor then reads the data file by calling its readRawData method. The readRawData method opens the data file from the document URL. The name of the data file is the stock symbol having extension .dat:

fS = new URL(app.getDocumentBase(),
             (strCoName + ".dat")).openStream();

The program then creates the DataInputStream object on the open stream and allocates an array of 5,000 rawData points. We're assuming the data file won't contain more than 5,000 trades, which is a reasonable assumption in practical situations (about 10 years of daily quotations). If you're concerned with the extra memory allocation, store the number of trades the file contains as a header in the data file.

The program then sets up a loop to read all the data points into the objRawData array (see Figure 7). For each data point, a new rawData object is created and added to the array. When the loop terminates, the variable i holds the number of data points. The variable is then copied into the NumberOfPoints variable for later use. The function closes the data stream, sets the start and end dates in the template, and returns. The start date is the first trade date, and end date is the last trade date.

// Read and initialize each day.
do {
  int retValue = tempRawData.read(dataStream);
  if (retValue == -1)
    break;
  if (bFirst) {  // Set startDate to date of first day.
    startDate = tempRawData.date;
    bFirst = false;
  }
  objRawData[i]            = new rawData();
  objRawData[i].Day        = Day++;
  objRawData[i].Tradedate  = tempRawData.Tradedate;
  objRawData[i].OpenPrice  = tempRawData.OpenPrice;
  objRawData[i].HighPrice  = tempRawData.HighPrice;
  objRawData[i].LowPrice   = tempRawData.LowPrice;
  objRawData[i].ClosePrice = tempRawData.ClosePrice;
  objRawData[i].Volume     = tempRawData.Volume;

  i++;
} 
while (true);
  NumberOfPoints = i;

Figure 7: A loop to read all the data points into the objRawData array.

The graphData constructor now reads the Period parameter from the HTML code and calls the setPeriod method to set the desired period for the chart. The setPeriod method sets the ptrRawData variable to point to the appropriate data array and sets the NumberOfPoints variable to the appropriate number of days. The constructor then calls the Recompute method. This method in turn calls CalWeeklyData and CalMonthData methods to compute the weekly and monthly data prices from the daily trade prices.

The open price on the opening day of the week is considered the open price for the week, and the close price on the last trading day of the week is treated as the close price for the week. The high and low prices for the week are determined from the highest and the lowest trade price during the week. Similarly, the monthly data is calculated using the open price as the open price on the first trade day of the month and the close price as the close price on the last trade day of the month. The high and low prices for the month represents the highest and lowest prices during the entire month.

The weekly prices are stored in the objRawWeekData array and the monthly prices are stored in the objRawMonthData array. The Recompute method then calls the Compute method of the TemplateData class to calculate moving averages and indicator values for the desired period. The setPeriod method is called to set the ptrRawData pointer to point to the appropriate array. I haven't explained the calculation of the weekly and monthly prices, but the source code for these methods should be self-explanatory. (The source for the entire program is available for download; see the end of the article for details.)

The TemplateData Class

This class contains various data members, which are used during plotting of the chart (see Figure 8). The strStartDate and strEndDate variables define the starting and ending date for the data plot. Initially, these contain the starting and ending dates for the full data range that is read from the data file. Users can change these variables at run time.

String strStartDate, strEndDate;
// 'C' - Close, 'O' - OHLC, 'H' - HLC.
Chartchar ChartType; 
// Set to true if Vertical grid is to be shown.
boolean bVertGrid;
// Set to true if Horizontal grid is to be shown.
boolean bHorzGrid;  
// Color of various objects of the graph.
Color clrVGrid;   // Vertical Grid.
Color clrHGrid;   // Horizontal Grid.
Color clrGraph;   // Graph Color.
Color clrBack;    // Graph Background.
Color clrDetail;  // Detail Panel
// The Open, Close and Bar of OHLC Graph.
Color clrOHLCOpen,clrOHLCClose,clrOHLCBar;
// The Close and Bar for HLC Graph.
Color clrHLCClose,clrHLCBar;

Figure 8: The various data members of the TemplateData class.

When you change the start and end dates for the plot, you will effectively zoom into the chart. The values of bVertGrid and bHorzGrid determine if a vertical or horizontal grid is to be plotted. After these declarations, several color variables are declared to customize the appearance of the chart at run time.

The class then defines two array type data members for holding the list of averages and indicators:

Average[] Averages;      // List of Averages defined.
Indicator[] Indicators;  // List of Indicators defined.

The Average class holds information about the desired moving average, and the Indicator class stores information regarding the type of indicator to be plotted. Both these classes are discussed later.

The TemplateData constructor reads the applet parameters and sets its data members. For this simple applet, the template parameters are set through the HTML code. In a larger version of this applet, all the template parameters would be set through the user interface dialog box. The idea behind defining the template is that analysts can define several templates, depending on the type of analysis desired for each scrip. When an analyst switches from a daily to a weekly chart (or to a monthly chart), he or she will probably want to apply a different set of parameters — especially averages, indicators, and type of chart. In a larger version of this applet, the independent templates for each period are defined. Users set the templates for different periods once, and whenever they switch from one chart period to another, the new template is automatically applied. For an analyst, this is a useful and powerful feature.

After initializing the various data members, the TemplateData constructor reads the Avg1Day and Avg2Day HTML parameters for establishing the moving averages. If the parameter isn't null, the AddAverage method is called to add the information about this average in the Averages array (see Figure 9). As you can see from the AddAverage method, the number of averages doesn't need to be restricted to two.

String AvgDay = Chart.getParameter("Avg1Day");
// Check if Average is defined.
if (AvgDay != null) {
  AddAverage(Integer.parseInt(AvgDay));
  Averages[0].setColor(Color.red);
}

Figure 9: The AddAverage method adds the average information in the Averages array.

Similarly, if the user has specified an indicator choice in the HTML parameter, the AddIndicator method is called to add the Indicator object to the Indicators array:

if (Ind != null)
  AddIndicator(IndNum,Integer.parseInt(Period), 
               0, Integer.parseInt(IndAvg));

In this simple example, only one indicator is supported; however, a larger version of the applet would allow you to add as many indicators as you wish. Our program defines calculations for only ROC and RSI types of indicators; calculations for other indicators aren't supported here.

The TemplateData class declares the fPer variable, which defines the percentage of the screen allocated to the chart. This demonstration applet allows only one indicator to be displayed, in which case the fPer variable is set to 75. Thus, the chart will use 75 percent of the screen, and the other 25 percent will display the indicator. In a larger version, this parameter would be user definable, giving the user a configuration option for the layout of charts.

The TemplateData class defines an import method called Compute. This method iterates through both the Averages and Indicators array, and computes the values of averages and indicators for each selected object (see Figure 10). Listing Two (beginning on page X) shows the complete code for TemplateData.

public void Compute(rawData[] ptrRawData, int nPts) {
  int i;
  // First compute values for all averages.
  for (i = 0;Averages != null && i < Averages.length;i++)
    Averages[i].ComputeAverage(ptrRawData,nPts);
  // Now compute values for all Indicators.
  for (i = 0;Indicators != null && i<Indicators.length;i++)
    Indicators[i].Compute(ptrRawData,nPts);
}

Figure 10: The Compute method computes the values of averages and indicators for each selected object.

The Average Class

The Average class declares four data members:

int     nAvgDays;  // Days of average.
Color   clrAvg;    // Color for moving avgerage.
float   avgData[]; // Array to hold the average data.
boolean bVisible;  // Set to true if Average is visible.

The nAvgDays data member stores the number of days used in the calculation of Average. The clrAvg variable defines the color for the average line. The avgData array stores the average values for the entire data, and the bVisible member determines whether to show or hide the average line.

The ComputeAverage method of this class accepts the ptrRawData variable, which points to the appropriate data list (daily, weekly, or monthly), and the number of points in the list as parameters. The method calculates a simple average on the data and stores it in the avgData array:

void ComputeAverage(rawData[] ptrRawData,
                    int nNoOfPoints) {
  ...
}

Most technical analysis programs provide the computation of both simple and exponential types of averages. Here, I have only included calculation for the simple averages to keep the article concise. Listing Three (beginning on page X) shows the complete code for the Average class.

The Indicator Class

The data members of the Indicator class are listed in Figure 11. The m_nName variable defines the type of indicator. In this example, only two indicator types are defined — ROC and RSI. The m_nDay1 and m_nDay2 data members represent the number of days — day 1 and day 2 are used for the calculation of the indicator values. Note that all the indicators may not require both day 1 and day 2.

int m_nName;                  // Type of indicator.
int m_nDay1, m_nDay2, m_nAvg; // Day1, Day2, and Average.
Color m_clrInd, m_clrAvg;     // Indicator, average color.
float[] indData;              // Contain indicator data.
// This array holds the average indicator data.
float[] avgData; 
// Percentage of space to be occupied by this indicator.
float m_fPer;
// Set to true for the indicator to be visible.
boolean bVisible;
// Values of names of the indicator.
final static int ROC = 0;
final static int RSI = 1;
static String[] IndName = {"ROC","RSI",""};
float fMaxValy, fMnValy, fYScale;

Figure 11: The data members of the Indicator class.

The m_nAvg variable defines the number of days used while calculating the average values on the indicator data. The m_clrInd and m_clrAvg variables define the color for the indicator and its average line, respectively. indData holds the average values for the entire data, and avgData holds the values for the averages on the calculated average data. The m_fPer variable defines the percentage of the chart space to be used by this indicator. Because this demonstration applet contains only one indicator, this parameter isn't of much relevance here.

The bVisible member determines whether to show or hide the current indicator, and the IndName array holds the names of indicators currently programmed in the software. Finally, the fMaxValy and fMnValy variables define the maximum and minimum values on the indicator data, and fYScale variable defines the scaling factor for the y axis.

The Compute method of the Indicator class calls the appropriate method for the calculation of the indictor values. In this example, the ComputeROC method computes ROC indicator values and the ComputeRSI method computes RSI values. (Note: The ROC and RSI calculations are defined in many books on technical analysis of stocks.) The ComputeAverage method computes the simple moving average on the indicator data. (The complete code for the Indicator class is also available for download.)

User-Interface Classes

Now that we've looked at the basic foundation classes, we'll turn to the user-interface classes. As mentioned earlier, the user interface consists of two portions — one displays the chart and the other displays the chart status. First we'll look at the DetailPanel class, which is responsible for rendering the chart status information. This class is derived from the Panel class. The same status panel is used for displaying the trade data under the cursor when the user clicks the mouse on any point on the chart. The class defines a variable called pChart, which stores the reference to the Charts object:

Charts pChart;
boolean bShowData;  // Show data values at index.
int index;

This reference is obtained in the constructor of the class. The Boolean variable bShowData determines if the panel will display the chart status or the data values. Thus, in the paint method, the bShowData flag is used to determine if the trade prices are to be displayed. If the flag is set, the DrawData method is called to display the trade values:

if (bShowData) {  // Check if data is to be shown.
  DrawData(g);    // Show the data.
  bShowData = false;  
  return;
}

If bDrawData is false, the various data members of the TemplateData class are displayed using the drawString method. The current active template is obtained using the following statement:

TemplateData data = pChart.graph.getTemplate();

If bDrawData is true, the DrawData method is called. This method obtains the data under the cursor using the following two statements:

rawData ptrRawData[] = pChart.graph.getData();
rawData raw = ptrRawData[index];

The getData method returns the current active list; index provides the position in the data list of the selected trade day. The DrawData method also displays the appropriate average and indicator values at the specified index.

Now let's look at the chartCanvas class. This class is extended from the Panel class and implements the MouseListener interface to enable the processing of mouse events whenever the user clicks on the chart. In this example, the mouse events are used to obtain the trade prices at the mouse-clicked position, which are then displayed on the details panel. The paint method of chartCanvas class uses double buffering to avoid the screen flicker (see Figure 12).

if (modified()) {
  img = createImage(size().width,size().height);
  Graphics gimg = img.getGraphics();
  getImage(gimg);
  bModify = false; // Set modified flag to false.
}
// Now draw the image on the screen.
g.drawImage(img,0,0,this);

Figure 12: Using double buffering to avoid the screen flicker.

The getImage method forms the off-screen image of the chart. This method first obtains the current template and the active data list using the following statements:

TemplateData m_data  = graph.getTemplate();
rawData[] ptrRawData = graph.getData();

It then sets several parameters for chart plotting and calls the CalMinMax method of the graphData class to calculate the minimum and maximum values of the graph data:

graph.CalMinMax();

The PlotXScale and PlotYScale methods of the Charts class are then called to plot x and y scales:

pChart.PlotXScale(g);
pChart.PlotYScale(g);

After the x and y scales are plotted, the chart is plotted. If the user has requested the close-price chart, the DrawCloseGraph method is called. If the user has requested an HLC or OHLC chart, the DrawHilowGraph method is called. Both these methods iterate through all the data points in the data array and use the drawLine method to draw the desired chart. After plotting the main chart, the program plots the average lines using the following code:

int nAvg = m_data.getAverageCount();
for (int i = 0;i < nAvg;i++) {
  if (m_data.Averages[i].isVisible())
    pChart.PlotMovAvg(g,m_data.Averages[i]);
}

For each average defined in the Averages array, the PlotMovAvg method of the Charts class is called to plot the moving average line. The PlotMovAvg method, like the DrawCloseGraph method, iterates through all data points and uses the drawLine method to draw the moving average line.

Likewise, the program then iterates through the Indicators array to display each indicator, its average line, and y scale for the indicator. Note that the demonstration applet restricts the user to the selection of one indicator. However, in a more generic case, you will need to traverse through all the elements of the Indicators array and plot each indicator (see Figure 13). Note: The PlotIndicator and PlotIndYScale methods are similar to the DrawCloseGraph and PlotYScale methods, and should be self-explanatory.

// Now plot the indicators.
int nInd = m_data.getIndicatorCount();
for (int i = 0;i < nInd;i++) {
  if (m_data.Indicators[i].isVisible()) {
    pChart.PlotIndicator(g,m_data.Indicators[i],i);
    pChart.PlotIndYScale(g,m_data.Indicators[i],i);
  }
}

Figure 13: Plotting the indicators.

The chartCanvas class implements the mouse-click methods to determine the stock quotes at any desired location on the chart. In the mousePressed event handler, the program obtains the x position of the mouse click, and then calls the ShowData method of Charts class to display the prices under the cursor on the details panel. The ShowData method uses the getIndexAt method to obtain the index in the data array corresponding to the x coordinate of the mouse-pointer position. The getIndexAt method then iterates through the data array to find the closest match for the x value. And the DrawCursor method draws a vertical line at the clicked position:

public void mousePressed(MouseEvent e) {
  ...
  int x = e.getX();  // Get the current x point.
  pChart.ShowData(x);
  DrawCursor(x);
}

In the mouseReleased method, both panels are repainted to show the original status information on the details panel, and to remove the vertical cursor from the chart panel:

public void mouseReleased(MouseEvent e) {
  pChart.details.repaint();
  pChart.grapharea.repaint();
}

Finally, we're ready to look at the Charts class, the main class of our application. This class is derived from the Applet class. In the init method, the stock code is read from the HTML parameter, and the graphData object is constructed. The construction of the graphData object causes the reading of the data file and construction of appropriate average and indicator data as seen earlier. The init method then calls CreateControls, which constructs the two panel objects and adds them to the applet using the GridBagLayout layout manager (see Figure 14).

private void CreateControls() {
  GridBagLayout gridbag = new GridBagLayout();
  setLayout(gridbag);
  // Create the new panels of the applet.
  grapharea = new chartCanvas(this);
  details = new DetailPanel(this);
  // Set the constraints on the panels so that they 
  // are relatively sized.
  setConstraints(gridbag,grapharea, 1, 1, 6,
                 GridBagConstraints.REMAINDER);
  setConstraints(gridbag,details, 0, 1, 2,
                 GridBagConstraints.REMAINDER);
  // Add the panels to the applet frame.
  add(grapharea);
  add(details);
}

Figure 14: Constructing the two panel objects and adding them to the applet.

The Charts class provides several other utility methods for plotting the x, y scales, various types of charts, average lines, indicators lines, etc. The program code for most of these methods should be self-explanatory.

Conclusion

This article shows the technique of building a Java-based stock-charting applet for technical analysis of stocks. The applet allows the user to input a limited number of parameters. In real life, a technical analyst requires several other parameters, several types of indicators, and several drawing tools for the analysis of stocks. Visit http://www.abcom.com for a more advanced version than the one described here.

The files referenced in this article are available for download from the Informant Web site at http://www.informant.com/ji/jinewupl.htm. File name: JI9805PS.ZIP.

Dr P.G. Sarang is President and CEO of ABCOM Information Systems Pvt. Ltd. — a consulting firm that specializes in Internet programming using Java, JavaScript, ISAPI, and Windows-based application development using Visual Basic, Visual C++, Microsoft Access, and SQL Server.

Technical Analysis of Stocks

The stock exchange publishes the daily quotations for each traded stock as daily open, high, low, and close prices, as well as volume. The open price designates the price at which the stock opens, the high price indicates the highest trade price during the day, the low price indicates the lowest price during the day, and the close price indicates the last price for the day. The volume indicates the number of stocks transacted during the day; this is usually cumulative for the entire day.

Technical analysts plot a close-price chart for a stock by plotting the close-price values on the y axis, and days on the x axis. From the chart, an analyst can make decisions about the stock trends. Some analysts may prefer plotting an OHLC (Open-High-Low-Close) chart. In this case, for each trade day:

a vertical bar is plotted between the high and low prices;

a small horizontal line for the open price is plotted on the left side of the bar; and

a small horizontal line for the close price is plotted on the right side of the bar.

When analysts look between the adjacent lines, they can quickly determine if today's open is higher than yesterday's high, etc. From this, conclusions about general stock trends can be determined.

To avoid the effect of fluctuations, an average of the stock prices is calculated and superimposed on the stock chart. Generally, an analyst will plot two average lines — one for a short duration and another for a long duration. If a short-term average line cuts the long-term average line from below, the trend is bullish (rising); otherwise it's bearish (falling). An analyst generally uses indicators to make further conclusions on stock trends. There are several indicators defined in many books on technical analysis. These are generally the empirical formulas derived by several well-known analysts for determining stock trends. Two such indicators, ROC and RSI, are discussed in this software.

The above analysis can be done on daily stock prices to determine the short-term trends, or can be done on weekly or monthly prices to determine the long-term stock trends.

Dr. P.G. Sarang

Begin Listing One — rawData.java

import java.util.Date;
import java.io.*;

public class rawData {
  public Date  TradeDate;  // Date of Transaction.
  public int   Day;
  public float OpenPrice;  
  public float HighPrice;
  public float LowPrice;
  public float ClosePrice;
  public long  Volume;

  // Set the default values to all variables.
  public rawData() {
    TradeDate  = new Date("01/01/80");
    OpenPrice  = 0;
    HighPrice  = 0;
    LowPrice   = 0;
    ClosePrice = 0;
    Volume     = 0L;
  }
  
  // Reads the data from the Input stream and 
  // initializes the object.
  public int read(DataInputStream finStream) {
    long lTemp;
    try {
      lTemp      = finStream.readLong();
      TradeDate  = new Date(lTemp);
      OpenPrice  = finStream.readFloat();
      HighPrice  = finStream.readFloat();
      LowPrice   = finStream.readFloat();
      ClosePrice = finStream.readFloat();
      Volume     = finStream.readLong();
    }
    catch (EOFException e) {
      return -1;
    }
    catch (Exception e) {
      System.out.println("Error: " + e.toString());
      return 1;
    }
    return 0;
  }
}

End Listing One

Begin Listing Two — TemplateData.java

import java.util.*;
import java.awt.*;

class TemplateData {
  String strStartDate, strEndDate;
  // 'C' - Close, 'O' - OHLC, 'H' - HLC
  char  ChartType;   
  // Set to true if vertical grid is to be shown.
  boolean bVertGrid; 
  // Set to true if horizontal grid is to be shown.
  boolean bHorzGrid; 
  
  // Color of various objects of the graph.
  Color clrVGrid;  // Vertical Grid
  Color clrHGrid;  // Horizontal Grid
  Color clrGraph;  // Graph Color
  Color clrBack;   // Graph Background
  Color clrDetail; // Detail Panel
  // The Open, Close and Bar of OHLC Graph
  Color clrOHLCOpen, clrOHLCClose, clrOHLCBar;
  // The Close and Bar for HLC Graph
  Color clrHLCClose, clrHLCBar;

  Average[] Averages;     // List of Averages defined.
  Indicator[] Indicators; // List of Indicators defined.
  float fPer;

  final static char CLOSE = 'C';  
  final static char OHLC  = 'O';
  final static char HLC   = 'H';

  // This class reads the HTML file PARAM tags for default
  // values of the charts and if not found initializes the
  // graph with default values.
  public TemplateData(Charts Chart) {
    // Set the default parameters. 
    strStartDate = "1/1/90";    
    strEndDate = "1/1/90";

    // Read the Graph Type from the HTML file.
    String TypeChart = Chart.getParameter("GraphType");
    if (TypeChart == null)
      ChartType = OHLC;  // If not defined, Default is OHLC.
    else if (TypeChart.equals("Close"))
      ChartType = CLOSE;
    else if (TypeChart.equals("HLC"))
      ChartType = HLC;
    else if (TypeChart.equals("OHLC"))
      ChartType = OHLC;

    // Both Vertical and Horizontal Grids are on.
    bVertGrid = bHorzGrid = true;
  
    // Set default colors.
    clrVGrid     = Color.darkGray;
    clrHGrid     = Color.darkGray;
    clrBack      = Color.black;
    clrGraph     = Color.white;
    clrDetail    = Color.gray;
    clrOHLCOpen  = Color.red;
    clrOHLCClose = Color.blue;
    clrOHLCBar   = Color.yellow;
    clrHLCClose  = Color.blue;
    clrHLCBar    = Color.yellow;

    // Read the averages from the HTML file.
    String AvgDay = Chart.getParameter("Avg1Day");
    // Check if Average is defined.
    if (AvgDay != null && Integer.parseInt(AvgDay) != 0) {
      AddAverage(Integer.parseInt(AvgDay));
      Averages[getAverageCount()-1].setColor(Color.red);
    }
    AvgDay = Chart.getParameter("Avg2Day");
    // Check if Average is defined.
    if (AvgDay != null && Integer.parseInt(AvgDay) != 0) {
      AddAverage(Integer.parseInt(AvgDay));
      Averages[getAverageCount()-1].setColor(Color.green);
    }

    // Create an indicator from the Details of HTML file.
    // If indicator not defined make a default Indicator.
    String Ind = Chart.getParameter("Indicator");
    String Period = Chart.getParameter("IndPeriod");
    String IndAvg = Chart.getParameter("IndAvgPeriod");
    int IndNum = Indicator.ROC;
    if (Period == null || Integer.parseInt(Period) == 0)
      Period = "12";
    if (IndAvg == null || Integer.parseInt(IndAvg) == 0)
      IndAvg = "12";

    if (Ind != null) {
      if (Ind.equals("RSI"))
        IndNum = Indicator.RSI;
      AddIndicator(IndNum, Integer.parseInt(Period), 0,
                   Integer.parseInt(IndAvg));
      
      // Set the properties of Indicator.
      Indicators[0].setColor(Color.yellow);
      Indicators[0].setVisible(true);
      Indicators[0].setPercent(25);

      fPer = 75.0f;
    }
    else
      fPer = 100.0f;
  }

  // This method returns the type of chart.
  public char getChartType() {
    return ChartType;
  }

  // Compute values for Averages and Indicators.
  public void Compute(rawData[] ptrRawData, int nPts) {
    int i;
    // First compute values for all averages.
    for (i = 0;Averages != null && i < Averages.length;i++)
      Averages[i].ComputeAverage(ptrRawData,nPts);
    // Now compute values for all Indicators.
    for (i=0;Indicators != null && i<Indicators.length;i++)
      Indicators[i].Compute(ptrRawData,nPts);
  }

  // strDate is in format d/m/yy. The function parses the
  // different fields and constructs a date object.
  private Date ConvertStringToDate (String strDate) {
    String temp;

    // Parse day.
    int index = strDate.indexOf('/');    
    int newindex;
    temp = strDate.substring(0, index);
    int day = (Integer.valueOf(temp)).intValue();

    // Parse month.
    newindex = strDate.indexOf('/', index+1);
    temp = strDate.substring(index+1, newindex);
    int month = (Integer.valueOf(temp)).intValue();
    index = newindex;

    // Parse year.
    temp = strDate.substring(index+1, strDate.length());
    int year = (Integer.valueOf(temp)).intValue();

    return (new Date (year, month-1, day));
  }

  // This method sets the start date of the graph.
  public void setStartDate(Date date) {
    strStartDate = Integer.toString(date.getDate());
    strStartDate += "/";
    strStartDate += Integer.toString(date.getMonth()+1);
    strStartDate += "/";
    strStartDate += Integer.toString(date.getYear());
  }

  // This method returns the start date of the graph.
  public Date getStartDate() {
    return ConvertStringToDate(strStartDate);
  }

  // This method sets the end date of the graph.
  public void setEndDate(Date date) {
    strEndDate = Integer.toString(date.getDate());
    strEndDate += "/";
    strEndDate += Integer.toString(date.getMonth()+1);
    strEndDate += "/";
    strEndDate += Integer.toString(date.getYear());
  }

  // This method returns the end date of the graph.
  public Date getEndDate() {
    return ConvertStringToDate(strEndDate);
  }

  // This method returns the color of the graph.
  public Color getGraphColor() {
    return clrGraph;
  }

  // This method returns the background color of the graph.
  public Color getBackColor() {
    return clrBack;
  }

  // This method is used to add an average to the chart.
  public void AddAverage(int nDays) {
    // Temporary array to hold current list of averages.
    Average[] avg; 

    if (Averages == null) { // No averages defined til now.
      avg = new Average[1];
      avg[0] = new Average(nDays); // Now add the average.
    }
    else {
      avg = new Average[Averages.length + 1];  
      for (int i = 0;i < Averages.length;i++)
        avg[i] = Averages[i];
      avg[Averages.length] = new Average(nDays);
    }

    Averages = avg;
    // The old avg array will automatically be cleared 
    // by garbage collector.
  }

  // This method returns the number of averages 
  // defined til now.
  public int getAverageCount() {
    return (Averages == null ? 0 : Averages.length);
  }

  // This method is used to add an indicator to the chart.
  public void AddIndicator(int nType, int nDays1,
                           int nDays2, int nAvg) {
    Indicator[] ind;  // Temporary array to hold averages.

    if (Indicators == null) {
      ind = new Indicator[1];
      ind[0] = new Indicator(nType,nDays1,nDays2,nAvg);
    }
    else {
      ind = new Indicator[Indicators.length + 1];
      for (int i = 0;i < Indicators.length;i++)
        ind[i] = Indicators[i];
      ind[Indicators.length] =
        new Indicator(nType, nDays1, nDays2, nAvg);
    }

    Indicators = ind;
    // The old array will be garbage collected.
  }

  // This method returns the number of indicators 
  // defined til now.
  public int getIndicatorCount() {
    return (Indicators == null ? 0 : Indicators.length);
  }
}

End Listing Two

Begin Listing Three — Average.java

import java.awt.Color;
public class Average {
  int     nAvgDays;   // Days of average.
  Color   clrAvg;     // Color for moving avgerage.
  float   avgData[];  // Array to hold the average data.
  boolean bVisible;   // Set to true if Average is visible.

  // Set the values of the Average Variables to 
  // those passed to constructor.
  public Average(int Days) {
    nAvgDays = Days;
    bVisible = true;
    clrAvg   = Color.red;
  }

  // This method sets the Color of Average line. 
  public void setColor(Color clr) {
    clrAvg = clr;
  }

  // This method returns the Color of Average line.
  public Color getColor() {
    return clrAvg;
  }

  // This method computes the Average data for all days.
  void ComputeAverage(
    rawData[] ptrRawData, int NumberOfPoints) {
    float fTotal = 0;
    int i = 0;

    // If average days is more than the number of
    // points, then return.
    if (nAvgDays >= NumberOfPoints)
      return;

    // Calculate Average for 1st Required number of days.
    fTotal = 0;
    for (;i < nAvgDays; i++) 
      fTotal += ptrRawData[i].ClosePrice;
    avgData = new float[NumberOfPoints];

    avgData[i] = fTotal/nAvgDays;
    
    while (i < NumberOfPoints) {
      // Subtract 1st Data.
      fTotal -= ptrRawData[i-nAvgDays].ClosePrice;
      // Add the New Data.
      fTotal += ptrRawData[i].ClosePrice;  
      avgData[i] = fTotal/nAvgDays;
      i++;
    }
  }

  // This method sets the visible property of Average
  // to the value passed by user.
  public void setVisible(boolean visible) {
    bVisible = visible;
  }

  // This method returns the visible property 
  // of the Average line.
  public boolean isVisible() {
    return bVisible;
  }

  // Returns the Strings Describing the Average.
  public String ConverttoString() {
    String temp = "";
    temp += nAvgDays;
    temp += " Simple";
    return temp;
  }
}

End Listing Three