Click here to Skip to main content
15,891,607 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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
Posted
Updated 20-Nov-19 15:52pm
v3
Comments
Richard MacCutchan 21-Nov-19 5:06am    
You need to ask a proper question, we do not know what help you are asking for.
UT7 21-Nov-19 5:20am    
Kindly help me update the client.py code above to achieve the above task, thanks.
phil.o 22-Nov-19 16:17pm    
We are not a translation service. Please read the FAQ.
Besides, as you wrote in your submission, this is your challenge, not ours.
So now, you have two choices:

- either you start providing some actual thinking/work (study what the original is doing, and how it does it; identify the parts which need being adapted; make necessary changes and test; repeat until fulfilled). If you do that, at any point we will be glad to help on any concrete issue;
- or you keep acting like you would like us to do it all for you; and you won't go anywhere I'm afraid.
UT7 22-Nov-19 21:10pm    
@phil.o thanks for your comment. When i asked this question i was thinking that there might be person(s) here who might be familiar with "interfacing with stock prices" and i was hoping the person(s) might say.... looking at this code structure for this task you need to 1. Override method XYZ 2. Make the ratio work with math.random 3. Call the method ABC from the main etc. Sorry if i have offended anyone with this question, as i stated before, i don't do python, i do java. I have received answers to my questions before on this platform and am sure i would get more answers in future, thanks, no hard feelings.
phil.o 23-Nov-19 5:00am    
No hard feelings, indeed :)

1 solution

Hi, I see it's JP Morgan chase's challenge. For this JP Morgan chase already has provided in their series on how to tackle this
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900