3 # Copyright (C) 2008 by Daniel Martin Yerga
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # StocksPy: Application to get stocks data from Yahoo Finance.
29 #osso_c = osso.Context("net.yerga.stockthis", "0.2", False)
31 from marketdata import markets, idmarket, localmarkets, localids
33 #detect if is ran locally or not
35 runningpath = sys.path[0]
37 if '/usr/share' in runningpath:
38 running_locally = False
40 running_locally = True
45 imgdir = '/usr/share/stockthis/pixmaps/'
47 loading_img = imgdir + 'loading.gif'
49 fhsize = gtk.HILDON_SIZE_FINGER_HEIGHT
50 horbtn = hildon.BUTTON_ARRANGEMENT_HORIZONTAL
51 ui_normal = gtk.HILDON_UI_MODE_NORMAL
52 winprogind = hildon.hildon_gtk_window_set_progress_indicator
54 gtk.gdk.threads_init()
59 self.program = hildon.Program()
60 self.program.__init__()
61 gtk.set_application_name("StockThis")
62 self.window = hildon.StackableWindow()
63 self.window.set_default_size(800, 480)
64 self.program.add_window(self.window)
65 self.window.connect("destroy", gtk.main_quit)
67 menu = hildon.AppMenu()
68 self.window.set_app_menu(menu)
69 button = gtk.Button("About")
70 button.connect("clicked", self.on_about)
75 toolbar = self.main_toolbar(False)
77 parea = hildon.PannableArea()
78 tv = hildon.GtkTreeView(ui_normal)
79 inmodel = self.__create_model(markets, idmarket)
80 tv.connect("row-activated", self.show_instrument_view, inmodel)
85 vbox.pack_start(parea, True, True, 0)
86 vbox.pack_start(gtk.HSeparator(), False, False, 5)
87 vbox.pack_start(toolbar, False, False, 0)
90 self.window.show_all()
92 def show_instrument_view(self, widget, path, column, inmodel):
93 market = inmodel[path][0]
95 names = localmarkets[idmarket.index(market)]
96 ids = localids[idmarket.index(market)]
98 window = hildon.StackableWindow()
101 toolbar = self.main_toolbar(False)
103 parea = hildon.PannableArea()
104 tv = hildon.GtkTreeView(ui_normal)
105 model = self.__create_model(names, ids)
106 tv.connect("row-activated", self.show_quotes_view, model)
111 vbox.pack_start(parea, True, True, 0)
112 vbox.pack_start(gtk.HSeparator(), False, False, 5)
113 vbox.pack_start(toolbar, False, False, 0)
119 def show_quotes_view(self, widget, path, column, model):
120 quote = model[path][0], model[path][1]
122 self.stocks_id = quote[0]
123 self.stocks_name = quote[1]
126 self.quotes_win = hildon.StackableWindow()
129 toolbar = self.main_toolbar(True)
132 self.titlelbl = gtk.Label('')
133 self.titlelbl.set_markup('<b><big>' + quote[1].replace('&', '') +
135 color = gtk.gdk.color_parse("#03A5FF")
136 self.titlelbl.modify_fg(gtk.STATE_NORMAL, color)
138 parea = hildon.PannableArea()
143 label = gtk.Label('')
144 label.set_markup('<b><big>Price:</big></b>')
145 self.lprice = gtk.Label('')
146 hbox.pack_start(label, False, False, 50)
147 hbox.pack_start(self.lprice, False, False, 185)
148 vbox1.pack_start(hbox, True, True, 0)
151 label = gtk.Label('')
152 label.set_markup('<b><big>Change:</big></b>')
153 self.lchange = gtk.Label('')
154 self.lpercent = gtk.Label('')
155 hbox.pack_start(label, False, False, 50)
156 hbox.pack_start(self.lchange, False, False, 145)
157 hbox.pack_start(self.lpercent, False, False, 0)
158 vbox1.pack_start(hbox, True, True, 0)
161 label = gtk.Label('')
162 label.set_markup('<b><big>Volume:</big></b>')
163 self.lvolume = gtk.Label('')
164 hbox.pack_start(label, False, False, 50)
165 hbox.pack_start(self.lvolume, False, False, 145)
166 vbox1.pack_start(hbox, True, True, 0)
169 label = gtk.Label('')
170 label.set_markup('<b><big>52 week high:</big></b>')
171 self.l52whigh = gtk.Label('')
172 hbox.pack_start(label, False, False, 50)
173 hbox.pack_start(self.l52whigh, False, False, 55)
174 vbox1.pack_start(hbox, True, True, 0)
177 label = gtk.Label('')
178 label.set_markup('<b><big>52 week low:</big></b>')
179 self.l52wlow = gtk.Label('')
180 hbox.pack_start(label, False, False, 50)
181 hbox.pack_start(self.l52wlow, False, False, 70)
182 vbox1.pack_start(hbox, True, True, 0)
186 button = hildon.PickerButton(fhsize, horbtn)
187 #FIXME: touchentry selector
188 data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
190 selector = self.create_selector(data)
191 button.set_selector(selector)
192 button.set_title("Shares")
193 #FIXME: check portfolio and see if there's quotes
194 button.set_value(data[0])
195 hbox.pack_start(button, True, True, 0)
197 button = hildon.Button(fhsize, horbtn)
198 button.set_title("Add to Portfolio")
199 #button.connect("clicked", self.publish_opt_screen)
200 hbox.pack_start(button, True, True, 0)
201 vbox1.pack_start(hbox, False, False, 0)
203 parea.add_with_viewport(vbox1)
205 vbox.pack_start(self.titlelbl, False, False, 0)
206 vbox.pack_start(gtk.HSeparator(), False, False, 0)
207 vbox.pack_start(parea, True, True, 0)
208 vbox.pack_start(gtk.HSeparator(), False, False, 5)
209 vbox.pack_start(toolbar, False, False, 0)
211 self.quotes_win.add(vbox)
212 self.quotes_win.show_all()
213 self.show_data(quote[0], self.quotes_win)
215 def create_selector(self, data):
216 selector = hildon.hildon_touch_selector_new_text()
217 for i in range(len(data)):
218 selector.append_text(data[i])
222 def show_data(self, quote, win):
225 thread.start_new_thread(self.get_data, (quote, win))
227 def get_data(self, quote, win):
228 from ystockquote import ystockquote as yt
230 data = yt.get_all(quote)
232 print 'Failed to get internet data'
233 data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
234 '52_week_high': 'N/A', '52_week_low': 'N/A'}
235 self.titlelbl.set_markup('<b><big>Failed to get data</big></b>')
239 100.0 * float(data['change'])/(float(data['price']) - \
240 float(data['change']))
244 self.lprice.set_label(data['price'])
245 self.lchange.set_label(data['change'])
246 self.lpercent.set_label('%6.2f %%' % ch_percent)
248 if '-' in data['change']:
249 color = gtk.gdk.color_parse("#FF0000")
251 color = gtk.gdk.color_parse("#16EB78")
253 self.lpercent.modify_fg(gtk.STATE_NORMAL, color)
254 self.lchange.modify_fg(gtk.STATE_NORMAL, color)
256 self.lvolume.set_label(data['volume'])
257 self.l52whigh.set_label(data['52_week_high'])
258 self.l52wlow.set_label(data['52_week_low'])
262 def refresh_stock_data(self, widget):
263 self.show_data(self.stocks_id, self.quotes_win)
266 def show_graph_view(self, widget):
267 win = hildon.StackableWindow()
270 toolbar = self.main_toolbar(False)
272 self.graphs_title = gtk.Label(self.stocks_name)
273 color = gtk.gdk.color_parse("#03A5FF")
274 self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
276 parea = hildon.PannableArea()
279 hbox.set_homogeneous(True)
281 button = hildon.Button(fhsize, horbtn)
282 button.set_label('1d')
283 button.connect("clicked", self.show_graph, '1d', win)
284 hbox.pack_start(button)
286 button = hildon.Button(fhsize, horbtn)
287 button.set_label('5d')
288 button.connect("clicked", self.show_graph, '5d', win)
289 hbox.pack_start(button)
291 button = hildon.Button(fhsize, horbtn)
292 button.set_label('3m')
293 button.connect("clicked", self.show_graph, '3m', win)
294 hbox.pack_start(button)
296 button = hildon.Button(fhsize, horbtn)
297 button.set_label('6m')
298 button.connect("clicked", self.show_graph, '6m', win)
299 hbox.pack_start(button)
301 button = hildon.Button(fhsize, horbtn)
302 button.set_label('1y')
303 button.connect("clicked", self.show_graph, '1y', win)
304 hbox.pack_start(button)
306 button = hildon.Button(fhsize, horbtn)
307 button.set_label('2y')
308 button.connect("clicked", self.show_graph, '2y', win)
309 hbox.pack_start(button)
311 button = hildon.Button(fhsize, horbtn)
312 button.set_label('5y')
313 button.connect("clicked", self.show_graph, '5y', win)
314 hbox.pack_start(button)
316 button = hildon.Button(fhsize, horbtn)
317 button.set_label('Max')
318 button.connect("clicked", self.show_graph, 'max', win)
319 hbox.pack_start(button)
322 vbox1.pack_start(hbox, False, False, 0)
324 self.graph = gtk.Image()
325 vbox1.pack_start(self.graph, True, True, 0)
327 parea.add_with_viewport(vbox1)
329 vbox.pack_start(self.graphs_title, False, False, 0)
330 vbox.pack_start(gtk.HSeparator(), False, False, 0)
331 vbox.pack_start(parea, True, True, 0)
332 vbox.pack_start(gtk.HSeparator(), False, False, 5)
333 vbox.pack_start(toolbar, False, False, 0)
338 self.show_graph(None, '1d', win)
340 def show_graph(self, widget, option, win):
343 thread.start_new_thread(self.get_graph_data, (option, win))
345 def get_graph_data(self, option, win):
346 kind = self.stocks_id
348 url = 'http://uk.ichart.yahoo.com/b?s=%s' % kind
350 url = 'http://uk.ichart.yahoo.com/w?s=%s' % kind
352 url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % kind.lower()
354 url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % kind.lower()
356 url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % kind.lower()
358 url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % kind.lower()
360 url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % kind.lower()
361 elif option == 'max':
362 url = 'http://chart.finance.yahoo.com/c/my/s/%s' % kind.lower()
365 myimg = urllib2.urlopen(url)
366 imgdata = myimg.read()
368 pbl = gtk.gdk.PixbufLoader()
371 pbuf = pbl.get_pixbuf()
373 self.graph.set_from_pixbuf(pbuf)
377 self.graphs_title.set_label('Failed to get data')
382 def _tv_columns(self, treeview):
383 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
384 column.set_visible(False)
385 treeview.append_column(column)
387 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
388 treeview.append_column(column)
390 def __create_model(self, names, ids):
391 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
392 for item in range(len(names)):
393 iter = lstore.append()
394 lstore.set(iter, 0, ids[item], 1, names[item])
397 def main_toolbar(self, quotesview):
399 toolbar.set_homogeneous(True)
401 portfolio_btn = hildon.Button(fhsize, horbtn)
402 portfolio_btn.set_title("Portfolio")
403 portfolio_btn.connect("clicked", self.show_portfolio_view)
405 graph_btn = hildon.Button(fhsize, horbtn)
406 graph_btn.set_title("Graph")
407 graph_btn.connect("clicked", self.show_graph_view)
409 refresh_btn = hildon.Button(fhsize, horbtn)
410 refresh_btn.set_title("Refresh")
411 refresh_btn.connect("clicked", self.refresh_stock_data)
413 toolbar.pack_start(portfolio_btn)
415 toolbar.pack_start(graph_btn)
416 toolbar.pack_start(refresh_btn)
422 def show_portfolio_view(self, widget):
423 #FIXME: get data from sqlite settings
424 data = [["SAN.MC", "BANCO SANTANDER R", "200", "-"],
425 ["BBVA.MC", "BBVA R", "300", "-"]]
426 win = hildon.StackableWindow()
430 parea = hildon.PannableArea()
431 tv = hildon.GtkTreeView(ui_normal)
432 tv.set_headers_visible(True)
433 inmodel = self._create_portfolio_model(data)
434 #tv.connect("row-activated", self.show_instrument_view, inmodel)
435 tv.set_model(inmodel)
436 self._tv_portfolio_columns(tv)
439 button = hildon.Button(fhsize, horbtn)
440 button.set_title("Refresh All")
441 button.connect("clicked", self.refresh_portfolio, tv, win, data)
443 vbox.pack_start(parea, True, True, 0)
444 vbox.pack_start(button, False, False, 0)
448 def refresh_portfolio(self, widget, tv, win, data):
451 thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
454 def _do_refresh_portfolio(self, data, tv, win):
456 item[3] = self.get_price(item[0])
458 model = self._create_portfolio_model(data)
462 def get_price(self, symbol):
463 from ystockquote import ystockquote as yt
464 price = yt.get_price(symbol)
468 def _create_portfolio_model(self, data):
469 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
470 gobject.TYPE_STRING, gobject.TYPE_STRING)
472 iter = lstore.append()
473 lstore.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3])
476 def _tv_portfolio_columns(self, treeview):
477 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
478 column.set_visible(False)
479 treeview.append_column(column)
481 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
482 column.set_property("expand", True)
483 treeview.append_column(column)
485 column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
486 treeview.append_column(column)
488 column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
489 treeview.append_column(column)
491 def on_about(self, widget):
492 dialog = gtk.AboutDialog()
493 dialog.set_name("StockThis")
494 dialog.set_version("0.2")
495 dialog.set_copyright("Copyright © 2009")
496 dialog.set_website("http://stockthis.garage.maemo.org")
497 dialog.set_authors(["Daniel Martin Yerga <dyerga@gmail.com>"])
498 logo = gtk.gdk.pixbuf_new_from_file(imgdir + "stockthis.png")
499 dialog.set_logo(logo)
500 dialog.set_license("This program is released under the GNU\nGeneral Public License. Please visit \nhttp://www.gnu.org/copyleft/gpl.html\nfor details.")
501 dialog.set_artists(["Logo by Daniel Martin Yerga"])
505 if __name__ == "__main__":
506 stockspy = StocksPy()
507 gtk.gdk.threads_enter()
509 gtk.gdk.threads_leave()