Hello everyone, i want to update the client.py code for this task.
TASK -
You’ve been asked to assist with some development to add a chart to a trader’s dashboard allowing them to better identify under/over-valued stocks.
The trader would like to be able to monitor two historically correlated stocks and be able to visualize when the correlation between the two weakens (i.e. one stock moves proportionally more than the historical correlation would imply). This could indicate a potential trade strategy to simultaneously buy the relatively underperforming stock and sell the relatively outperforming stock. Assuming the two prices subsequently converge, the trade should be profitable.
I'm to update this client.py code
import urllib2
import time
import json
import random
# Server API URLs
QUERY = "http://localhost:8080/query?id={}"
# 500 server request
N = 500
def getDataPoint(quote):
""" Produce all of the needed values to generate a datapoint """
""" ------------- Update this function ------------- """
stock = quote['stock']
bid_price = float(quote['top_bid']['price'])
ask_price = float(quote['top_ask']['price'])
price = bid_price
return stock, bid_price, ask_price, price
def getRatio(price_a, price_b):
""" Get ratio of price_a and price_b """
""" ------------- Update this function ------------- """
""" Also create some unit tests for this function in client_test.py """
return 1
# Main
if __name__ == "__main__":
# Query the price once every N seconds.
for _ in xrange(N):
quotes = json.loads(urllib2.urlopen(QUERY.format(random.random())).read())
""" ----------- Update to get the ratio --------------- """
for quote in quotes:
stock, bid_price, ask_price, price = getDataPoint(quote)
print "Quoted %s at (bid:%s, ask:%s, price:%s)" % (stock, bid_price, ask_price, price)
print "Ratio %s" % getRatio(price, price)
This code is in python and am a java developer but i want to solve this challenge. I am getting data feed for this project unto my machine(PC).
This is the server.py file for this project
from itertools import izip
from random import normalvariate, random
from datetime import timedelta, datetime
import csv
import dateutil.parser
import os.path
import operator
import json
import re
import threading
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from SocketServer import ThreadingMixIn
################################################################################
#
# Config
# Sim params
REALTIME = True
SIM_LENGTH = timedelta(days = 365 * 5)
MARKET_OPEN = datetime.today().replace(hour = 0, minute = 30, second = 0)
# Market parms
# min / max / std
SPD = (2.0, 6.0, 0.1)
PX = (60.0, 150.0, 1)
FREQ = (12, 36, 50)
# Trades
OVERLAP = 4
################################################################################
#
# Test Data
def bwalk(min, max, std):
""" Generates a bounded random walk. """
rng = max - min
while True:
max += normalvariate(0, std)
yield abs((max % (rng * 2)) - rng) + min
def market(t0 = MARKET_OPEN):
""" Generates a random series of market conditions,
(time, price, spread).
"""
for hours, px, spd in izip(bwalk(*FREQ), bwalk(*PX), bwalk(*SPD)):
yield t0, px, spd
t0 += timedelta(hours = abs(hours))
def orders(hist):
""" Generates a random set of limit orders (time, side, price, size) from
a series of market conditions.
"""
for t, px, spd in hist:
stock = 'ABC' if random() > 0.5 else 'DEF'
side, d = ('sell', 2) if random() > 0.5 else ('buy', -2)
order = round(normalvariate(px + (spd / d), spd / OVERLAP), 2)
size = int(abs(normalvariate(0, 100)))
yield t, stock, side, order, size
################################################################################
#
# Order Book
def add_book(book, order, size, _age = 10):
""" Add a new order and size to a book, and age the rest of the book. """
yield order, size, _age
for o, s, age in book:
if age > 0:
yield o, s, age - 1
def clear_order(order, size, book, op = operator.ge, _notional = 0):
""" Try to clear a sized order against a book, returning a tuple of
(notional, new_book) if successful, and None if not. _notional is a
recursive accumulator and should not be provided by the caller.
"""
(top_order, top_size, age), tail = book[0], book[1:]
if op(order, top_order):
_notional += min(size, top_size) * top_order
sdiff = top_size - size
if sdiff > 0:
return _notional, list(add_book(tail, top_order, sdiff, age))
elif len(tail) > 0:
return clear_order(order, -sdiff, tail, op, _notional)
def clear_book(buy = None, sell = None):
""" Clears all crossed orders from a buy and sell book, returning the new
books uncrossed.
"""
while buy and sell:
order, size, _ = buy[0]
new_book = clear_order(order, size, sell)
if new_book:
sell = new_book[1]
buy = buy[1:]
else:
break
return buy, sell
def order_book(orders, book, stock_name):
""" Generates a series of order books from a series of orders. Order books
are mutable lists, and mutating them during generation will affect the
next turn!
"""
for t, stock, side, order, size in orders:
if stock_name == stock:
new = add_book(book.get(side, []), order, size)
book[side] = sorted(new, reverse = side == 'buy', key = lambda x: x[0])
bids, asks = clear_book(**book)
yield t, bids, asks
################################################################################
#
# Test Data Persistence
def generate_csv():
""" Generate a CSV of order history. """
with open('test.csv', 'wb') as f:
writer = csv.writer(f)
for t, stock, side, order, size in orders(market()):
if t > MARKET_OPEN + SIM_LENGTH:
break
writer.writerow([t, stock, side, order, size])
def read_csv():
""" Read a CSV or order history into a list. """
with open('test.csv', 'rb') as f:
for time, stock, side, order, size in csv.reader(f):
yield dateutil.parser.parse(time), stock, side, float(order), int(size)
################################################################################
#
# Server
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
""" Boilerplate class for a multithreaded HTTP Server, with working
shutdown.
"""
allow_reuse_address = True
def shutdown(self):
""" Override MRO to shutdown properly. """
self.socket.close()
HTTPServer.shutdown(self)
def route(path):
""" Decorator for a simple bottle-like web framework. Routes path to the
decorated method, with the rest of the path as an argument.
"""
def _route(f):
setattr(f, '__route__', path)
return f
return _route
def read_params(path):
""" Read query parameters into a dictionary if they are parseable,
otherwise returns None.
"""
query = path.split('?')
if len(query) > 1:
query = query[1].split('&')
return dict(map(lambda x: x.split('='), query))
def get(req_handler, routes):
""" Map a request to the appropriate route of a routes instance. """
for name, handler in routes.__class__.__dict__.iteritems():
if hasattr(handler, "__route__"):
if None != re.search(handler.__route__, req_handler.path):
req_handler.send_response(200)
req_handler.send_header('Content-Type', 'application/json')
req_handler.send_header('Access-Control-Allow-Origin', '*')
req_handler.end_headers()
params = read_params(req_handler.path)
data = json.dumps(handler(routes, params)) + '\n'
req_handler.wfile.write(data)
return
def run(routes, host = '0.0.0.0', port = 8080):
""" Runs a class as a server whose methods have been decorated with
@route.
"""
class RequestHandler(BaseHTTPRequestHandler):
def log_message(self, *args, **kwargs):
pass
def do_GET(self):
get(self, routes)
server = ThreadedHTTPServer((host, port), RequestHandler)
thread = threading.Thread(target = server.serve_forever)
thread.daemon = True
thread.start()
print 'HTTP server started on port 8080'
while True:
from time import sleep
sleep(1)
server.shutdown()
server.start()
server.waitForThread()
################################################################################
#
# App
ops = {
'buy': operator.le,
'sell': operator.ge,
}
class App(object):
""" The trading game server application. """
def __init__(self):
self._book_1 = dict()
self._book_2 = dict()
self._data_1 = order_book(read_csv(), self._book_1, 'ABC')
self._data_2 = order_book(read_csv(), self._book_2, 'DEF')
self._rt_start = datetime.now()
self._sim_start, _, _ = self._data_1.next()
self.read_10_first_lines()
@property
def _current_book_1(self):
for t, bids, asks in self._data_1:
if REALTIME:
while t > self._sim_start + (datetime.now() - self._rt_start):
yield t, bids, asks
else:
yield t, bids, asks
@property
def _current_book_2(self):
for t, bids, asks in self._data_2:
if REALTIME:
while t > self._sim_start + (datetime.now() - self._rt_start):
yield t, bids, asks
else:
yield t, bids, asks
def read_10_first_lines(self):
for _ in xrange(10):
self._data_1.next()
self._data_2.next()
@route('/query')
def handle_query(self, x):
""" Takes no arguments, and yields the current top of the book; the
best bid and ask and their sizes.
"""
t1, bids1, asks1 = self._current_book_1.next()
t2, bids2, asks2 = self._current_book_2.next()
t = t1 if t1 > t2 else t2
#print 'Query received @ t%s' % t
return [{
'id': x and x.get('id', None),
'stock': 'ABC',
'timestamp': str(t),
'top_bid': bids1 and {
'price': bids1[0][0],
'size': bids1[0][1]
},
'top_ask': asks1 and {
'price': asks1[0][0],
'size': asks1[0][1]
}
},
{
'id': x and x.get('id', None),
'stock': 'DEF',
'timestamp': str(t),
'top_bid': bids2 and {
'price': bids2[0][0],
'size': bids2[0][1]
},
'top_ask': asks2 and {
'price': asks2[0][0],
'size': asks2[0][1]
}
}]
################################################################################
#
# Main
if __name__ == '__main__':
if not os.path.isfile('test.csv'):
print "No data found, generating..."
generate_csv()
run(App())
Any help on how to update the client.py code would be greatly appreciated, thanks.
What I have tried:
import urllib2
import time
import jason
import random
QUERY = "http://localhost:8080/query?id={}"
N = 500
def getDataPoint(quote):
stock = quote[stock]
bid_price = float(quote['top_bid']['price'])
ask_price = float(quote['top_ask']['price'])
price = bid_price
return stock, bid_price, ask_price, stock