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
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 …
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.
More From ivanidris
ivanidris Recommends
- Seven Characteristics of Stepper Motors | Solder In The Veins (Solder In The Veins)


