#!/usr/bin/python2.4 """Techlab Compilation 1.00 Copyright (C) 2007 John Sherwood""" import MySQLdb#for SQL work import Color#to display things in pretty colors import getpass#for passwords import readline#makes prompts nicer import regression#my regression package import XML.parser#my XML parser import os#for OS calls import sys#for sys calls (exit, mainly) import conf#config settings import config#cursor connection settings from err import * print Color.cyan + "John Sherwood's techlab compilation" + Color.end sql = config.cursor() mask_errors = conf.errors debug_status = conf.debug echo = conf.echo def set_output(errors = None, debug = None, display = None): """Set status for error display, debug display, and general output""" global mask_errors, debug_status, echo if errors != None:mask_errors = errors if debug != None:debug_status = debug if display != None:echo = display def debug(message): """Display a debug message. If global variable 'debug_status' is set to false, message will not be displayed""" global debug_status if not debug_status: return print Color.yellow + str(message) + Color.end def error(message): """Display an error message. If global variable 'mask_errors' is set to True, message will not be displayed""" global mask_errors if not mask_errors:print Color.red+str(message)+Color.end def display(message): """Display a output message. If global variable 'echo' is set to False, message will not be displayed""" global echo if not echo:return print message def clear(): """Clear the terminal screen""" os.system('clear') def exit(code=0): """Exit the program with the specified exit code""" sys.exit(code) def find_current_news(symbol,name): """Find the current news for a stock (uses XML.parser)""" symbol = ''.join([x.capitalize() for x in symbol]) name = name.capitalize() news = [] def check(symbol, name, nav): """check for news links""" for child in nav._tree["children"]: if symbol in XML.parser.navigator(child).parseTree() or name in XML.parser.navigator(child).parseTree(): check(symbol,name,XML.parser.navigator(child)) else: pass if len(nav._tree["children"]) is 0: if 'href' in nav._tree["attributes"].keys(): news.append([" ".join(nav._tree["inside"]),nav._tree["attributes"]['href']]) nav = XML.parser.navigator(XML.parser.parseurl("http://finance.google.com/finance?q="+symbol)).getChild([5],nav=True) check(symbol,name,nav) return news def sql_status(disable=False,enable=False): """Determine if an SQL connection has been established""" global sql if disable: debug("Disabling SQL connection") if sql is False: error("No SQL connection exists.") else: sql = False display("SQL connection terminated.") return if enable: if sql_status(): error('SQL already enabled.') return else: try: host = raw_input('SQL Host: ') uname = raw_input('Username: ') database = raw_input('Database: ') password = getpass.getpass('Password: ') sql = MySQLdb.connect(host,uname,password,database).cursor(MySQLdb.cursors.DictCursor) except: error('Could not establish connection') debug('Failed to connect to %s@%s'%uname,host) if sql:return True else:return False def query(q): """execute a MySQL query""" global sql if not sql:return None try: sql.execute(q) return sql.fetchall() except Error,e: error(e) return None def latestprice(symbol): """Find the latest price of a stock by its symbol (requires SQL connection)""" global sql if not sql: raise SqlStatusException,'SQL connection not established' try: sql.execute("SELECT price FROM stockData WHERE symbol='%s' ORDER BY `time` DESC LIMIT 1"%symbol) res = sql.fetchall() if not len(res): error('Symbol not found in database.') else: return round(res[0]['price'],2) except MySQLdb.OperationalError: debug('Function `latestprice` failed; called with symbol `%s`'%symbol) error('Invalid symbol') return False def extended_news(symbol,name): """Get the extended news on a stock (uses XML.parser)""" r = [] news = find_current_news(symbol,name) for item in news: try: data = XML.parser.navigator(XML.parser.parseurl(item[1])).findContent(mlen=200) r.append([item[0],(''.join(data)).strip()]) except: debug('Error parsing news from `%s`'%item[1]) return r def news_score(news): """generate a score for a news item""" terms = {\ 'deal':.2,\ 'lawsuit':-.15,\ 'infringement':-.3,\ 'new':.2,\ 'error':-.2,\ 'loss':-.3,\ 'killed':-.7,\ 'hiring':.4,\ 'layoff':-.3,\ 'earnings':.2,\ 'increase':.1,\ 'increased profit':.5,\ 'fired':-.1,\ 'scandal':-.4,\ 'merger':.4,\ 'delay':-.2,\ 'sue':-.2,\ 'infringe':-.25,\ 'patent':.1,\ 'corrupt':-.5,\ 'favorable':.1,\ 'enhancement':.2,\ 'win':.1\ } return sum([terms[x] for x in terms.keys() if x in news]) def score_all_news(SCORE_MIN=-1.0,SCORE_MAX=1.0): """score and normalize all news""" news = query("SELECT * FROM mining_2") if not news: error('No SQL connection.') return None for i in range(len(news)): news[i]['score'] = news_score(news[i]['news']) s_max = max([i['score'] for i in news]) s_min = min([i['score'] for i in news]) if s_min == 0:s_min = SCORE_MIN if s_max == 0:s_max = SCORE_MAX debug("Max:%d\nMin:%d"%(s_max,s_min)) for item in news: if item['score'] > 0: item['normalized_score'] = item['score']/s_max*SCORE_MAX else: item['normalized_score'] = item['score']/s_min*SCORE_MIN debug("%f -> %f"%(item['score'],item['normalized_score'])) q = "UPDATE mining_2 SET score=%f, normalized_score=%f WHERE newsID=%d"%(item['score'],item['normalized_score'],item['newsID']) # debug(q) query(q) display("News successfully scored.") return True def calc_pricechange(stock,start,end): """Predict a price change for the specified stock between times 'start' and 'end' Times must be supplied in YYYY-MM-DD format, with HH:MM:SS optional""" news = query("SELECT * FROM mining_2 WHERE symbol=\"%s\" AND time >= \"%s\" AND time <= \"%s\""%(stock,start,end)) print news def linegraph(data,write_to,xdim=400,ydim=100): """Generate a PNG line graph of data""" f = file('graphsettings.in','w') f.write("%d\n%d\n"%(xdim,ydim)) for i in range(len(data[0])): f.write(' '.join([str(data[j][i]) for j in range(len(data))])+'\n') f.close() os.system('php generate.php > %r'%write_to) def regress(stock,target,start,end): return regression.regress(target,query("SELECT * FROM mining_2 WHERE symbol=%r AND time < %r AND time > %r"%(target,end,start))) if __name__ == "__main__":print Color.green+"Succesfully compiled."+Color.end