Grails Finance 0.2

This entry is part of 15 in the series Grails Finance

Last week I made a scaffolded Grails finance application. This week I will fill the database with historical price data from Google Finance.

Model Changes

I needed to change the model a bit. I changed the name of the DateTime field and added some instance variables with corresponding constraints. Here is the modified FieldValue domain class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package finance
 
import org.joda.time.*
import org.joda.time.contrib.hibernate.*
 
class FieldValue {
    String val
    DateTime added
    Instrument instrument
    Field field
 
    static constraints = {
      val(blank:false)
      added(blank:false)
      instrument(blank:false)
      field(blank:false)
    }
 
    static belongsTo = [Instrument, Field]
 
    String toString() {
      "${val} ${added}"
    }
}

The view

I created a Groovy Server Page (GSP) that displays in a table all the Google Finance instruments in the database and buttons for data retrieval. Prototype is used to perform AJAX calls to the controller. I hope you recognize the famous Spinner UI design pattern.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<html>
   <head>
      <title>Retrieve EOD data from Google Finance</title>
      <g:javascript library="prototype"/>
   </head>
   <body>
      <table>
         <g:each var="instrument" in="${instruments}">
         <tr>
            <td>${instrument.symbol}</td>
            <td>${instrument.name}</td>
            <td><g:form action='retrieve'>
            <g:hiddenField name='symbol' value='${instrument.symbol}'/>
            <g:submitToRemote value="Get data"
            url="[controller: 'fieldValue', action: 'retrieve']"
            onLoading="showSpinner(true)" 
            onComplete="showSpinner(false)"/>
            <img id="spinner" style="display: none" src="<g:createLinkTo dir='/images' file='spinner.gif'/>"/>
            </g:form></td>
         </tr>
         </g:each>
      </table>
      <g:javascript>
            function showSpinner(visible) {
                $('spinner').style.display = visible ? "inline" : "none"
            }   
        </g:javascript>
 
   </body>
</html>

The page looks like this in Safari

Instruments

The controller

The controller does all the hard work of querying for instruments and retrieving data in CSV format. The data consists of a Date, Open, HighLow, Close and Volume column. I installed the REST plugin for the HTTP communication part

1
grails install-plugin rest

The plugin injects amongst others the withAsyncHttp method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package finance
 
import static groovyx.net.http.ContentType.HTML
import org.joda.time.*
import org.joda.time.format.*
import org.joda.time.contrib.hibernate.*
 
class FieldValueController {
    def scaffold = true
 
    def eodgoogle = {
      def instruments = Instrument.findAll().findAll { 
         instrument -> instrument.source.name == 'Google Finance'
      }
      [instruments : instruments]
    }
 
   def retrieve = {
      withAsyncHttp(poolSize : 4, uri : "http://finance.google.com", contentType : HTML) { 
         def result = get(path:'/finance/historical', query: [q:params.symbol, output:'csv']) { 
            resp, html ->  println ' got async response!' 
            return html
         } 
 
         assert result instanceof java.util.concurrent.Future
 
         while (! result.done) { 
            Thread.sleep(2000) 
         }
 
         def html = result.get().toString()
 
         for(line in html.split('\n')) {
            if(!line.contains('Date')) {
               def fields = line.split(',')
               def dateTime = DateTimeFormat.forPattern("dd-MMM-yy").parseDateTime(fields[0])
               def instrument = Instrument.findBySymbol(params.symbol)
               saveValueByFieldName('Open', dateTime, instrument, fields[1])
               saveValueByFieldName('High', dateTime, instrument, fields[2])
               saveValueByFieldName('Low', dateTime, instrument, fields[3])
               saveValueByFieldName('Close', dateTime, instrument, fields[4])
               saveValueByFieldName('Volume', dateTime, instrument, fields[5])
            }
         }
      }
   }
 
   def saveValueByFieldName(fieldName, dateTime, instrument, val) {
         def mnemonic = Field.findByName(fieldName)
         def fVal = new FieldValue(added: dateTime, val: val, instrument: instrument, field:mnemonic).save();
   }
}

A screenshot of the historical values list is shown here below. Mmm, gold …

Values

Notice that no effort is required to get pagination.

Conclusion

Grails is really perfect for secret home projects, especially for weekend ones. Next on the Grails finance roadmap is charting, some mathematical analysis, a REST webservice, lots of polishing and even more features, which will remain secret for now.

Series Navigation
By the author of NumPy Beginner's Guide, NumPy Cookbook and Instant Pygame. If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
Share
This entry was posted in programming and tagged , , . Bookmark the permalink.