Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
fawce committed Jan 12, 2012
1 parent 10a9971 commit b157230
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 4 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.bundle
db/*.sqlite3
log/*.log
*.log
tmp/**/*
tmp/*
doc/api
doc/app
*.swp
*~
.DS_Store
*.pyc
.tddium
.tddium-deploy-key
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ A backtesting session is comprised of:

## Pre-requisites
You need to have the tornado and pymongo eggs installed:
easy_install tornado pymongo

easy_install tornado pymongo pyzmq

You need to have mongodb installed and running. Find your system at http://www.mongodb.org/downloads and set it up.

You need to have zeromq installed - http://www.zeromq.org/intro:get-the-software. If you are on mac, get homebrew https://github.com/mxcl/homebrew then:

brew install zeromq

### Database and Collections expected in MongoDB ###
QBT requires a running mongodb instance with a few collections:

Expand Down
35 changes: 35 additions & 0 deletions backtest/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Small classes to assist with db access, timezone calculations, and so on.
"""

class DocWrap():
"""
Provides attribute access style on top of dictionary results from pymongo.
Allows you to access result['field'] as result.field.
Aliases result['_id'] to result.id.
"""
def __init__(self, store=None):
if(store == None):
self.store = {}
else:
self.store = store.copy()
if(self.store.has_key('_id')):
self.store['id'] = self.store['_id']
del(self.store['_id'])

def __setitem__(self,key,value):
if(key == '_id'):
self.store['id'] = value
else:
self.store[key] = value

def __getitem__(self, key):
if self.store.has_key(key):
return self.store[key]

def __getattr__(self,attrname):
if self.store.has_key(attrname):
return self.store[attrname]
else:
raise AttributeError("No attribute named {name}".format(name=attrname))
36 changes: 36 additions & 0 deletions qbt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
qbt runs backtests using multiple processes and zeromq messaging.
Backtest is the primary process. It maintains both server and client sockets:
zmq sockets for internal processing:
====================================
- data sink, ZMQ.PULL. Port = port_start + 1
- backtest will connect to socket, and then spawn one process per datasource, passing the data sink url as a startup arg. Each
datasource process will bind to the socket, and start processing
- backtest is responsible for merging the data events from all sources into a serialized stream and relaying it to the
aggregators, merging agg results, and transmitting consolidated stream to event feed.
- agg source, ZMQ.PUSH. Port = port_start + 2
- agg sink, ZMQ.PULL. Port = port_start + 3
- control source, ZMQ.PUB. Port = port_start + 4
- all child processes must subscribe to this socket. Control commands:
- START -- begin processing
- KILL -- exit immediately
zmq sockets for backtest clients:
=================================
- orders sink, ZMQ.RESP. Port = port_start + 5
- backtest will connect (can you bind?) to this socket and await orders from the client. Order data will be processed against the streaming datafeed.
- event feed, ZMQ.RESP. Port = port_start + 6
- backtest will bind to this socket and respond to requests from client for more data. Response data will be the queue of events that
transpired since the last request.
"""
import multiprocessing
import zmq

class Backtest(object):

def __init__(self, port_start=10000):

40B8729046
18 changes: 15 additions & 3 deletions qbt_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import os
import logging
import datetime
import multiprocessing

logging.getLogger().setLevel(logging.DEBUG)
logger = logging.getLogger()

define("port", default=8888, help="run the qbt on the given port", type=int)
Expand Down Expand Up @@ -47,6 +47,7 @@ def __init__(self):
handlers = [
(r"/", MainHandler),
(r"/login", LoginHandler),
(r"/backtest", BacktestHandler)
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
Expand Down Expand Up @@ -81,8 +82,8 @@ def get_current_user(self):
class MainHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
self.write("Hello, world")

self.write("Hello, world. Try launching a <a href='/backtest'>backtest</a>.")
class LoginHandler(BaseHandler):
def get(self):
self.write('<html><body><form action="/login" method="post">'
Expand Down Expand Up @@ -113,6 +114,17 @@ def authenticate(self, username, password):
logger.debug("setting user_id cookie to {id}".format(id=user_record['_id']))
self.set_secure_cookie(u"user_id", unicode(user_record['_id']))

class BacktestHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
self.write('<html><body><form action="/backtest" method="post">'
'<input type="submit" value="Launch">'
'</form></body></html>')
@tornado.web.authenticated
def post(self):



def main():
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(Application())
Expand Down
Empty file added qbt_test_client.py
Empty file.

0 comments on commit b157230

Please sign in to comment.