Project Exchange

Training wheels attached
Github: ProjectExchange

This is a bit of an embarassing project for me to put up, but it was my first one so it deserves to be on here. The intent was to make a Bitcoin exchange. It turned out kinda ugly, but it was actually a functional and featureful exchange. Since I knew it wouldn't ever be pushed to production (edit 2018: this was a regrettable decision), I sacrificed security and good design for user convenience and utility. It was named "BitSomething" because I got lazy.

The homepage - including color-coded news article titles!

The idea behind the project was to make a Bitcoin exchange that could support any feature that current exchanges (at the time, this was mostly Mt. Gox, Bitstamp, and BTC-e) had, as well as adding others. The exchange allowed for 4 different types of orders:

Instant Orders were simple: you entered a number of Bitcoins to buy or sell, and it was done at whatever the market price at that instant was. In traditional terms: a market order. Liquid and limit orders are similar, in that you enter a quantity of Bitcoins and a price per coin, but limit orders would only transact at that price while liquid orders would transact at any point where you could get that price or a "worse" price. For example, if the buy price was at $200 and the sell price was at $300, a limit order to buy at $150 wouldn't go through until the buy price had decreased to $150, but a liquid order would be processed immediately at $200. "Limit orders" are similar to post-only limit orders and "liquid orders" are similar to non-post-only limit orders.

Here, a wealthy intern buys 2 Bitcoins instead of fixing the broken footer.

The last type of order, conditional orders, were a bit different. On top of specifying a quantity and price per coin, the user would also submit a "condition" to wait for before activating the order. This condition could be a price level or a metric of the current market (volatility measures, hourly volume, etc.). Once the condition was met once, the order would be added to the order book as a limit order and be available for transaction. The idea was to provide users with the means for basic event-triggered ordering. You could think of them as stop orders, but with more triggers than just rates. Anything beyond this simple level of 1-event, 1-order system would be done programmatically. A public API would have been on my to-do list if I knew what an API was.

The main trading panel, currently set to the conditional order screen.

I also wrote out a pretty extensive "About" page for some reason. I think I committed so much time to it so that I would have a definitive reference for myself on the different kinds of orders (I kept forgetting the difference between liquid and limit orders). It also had a basic Bitcoin tutorial, since at the time even the tutorial was pretty vague. It's amazing how much I can write when I'm avoiding refactoring code.

The about page gives a brief overview of the different order types.

Programmatically, it was a fairly simple system: a website made in Python via Django with a MySQL server backend. Django is now my favorite web framework (this website is made with it), but I can't say I've ever been a fan of the relational database space. I started by writing the exchange engine, which handled all of the incoming orders. Then I made some wireframes (using MS Paint of course) to sketch out the homepage, exchange terminal, and then all of the other pages.

I had my own workflow for the development process: Copy, Redo, And Paste. I'm pretty sure every CSS file was copied from the first one I made and just configured for each page. Once that was done, I set up all of the Javascript. I didn't even look at my code while writing this, but I'm sure it's industry standard in some universe.

The backend was a bit more forgivable. The exchange engine was actually done in a fairly efficient manner. It was mostly conditionals and arithmetic, so maybe that isn't too surprising. The script was fired when the user submitted an order, and it essentially grabbed the top 10 existing orders in the database, compared the prices and conditions, and did all of the math necessary to set the current exchange state to equilibrium (where buy orders have higher prices than sell orders). Here's a snippet from the transaction mechanism:

			#Performs volume calculations and updates volumes
			if TopBuyOrder[3] == TopSellOrder[3]:
				BuyOrderCompletion = "Full"
				SellOrderCompletion = "Full"
				TransactionVolume = TopSellOrder[3]
			elif TopBuyOrder[3] > TopSellOrder[3]:
				BuyOrderCompletion = "Partial"
				SellOrderCompletion = "Full"
				NewBuyOrderVolume = TopBuyOrder[3] - TopSellOrder[3]
				TransactionVolume = TopSellOrder[3]
				cursor.execute("""UPDATE BasicOrderBook SET Volume = %f WHERE OrderNumber = %d""" % (NewBuyOrderVolume, TopBuyOrderNumber))
				print "Order " + str(TopBuyOrder[0]) + " Volume Updated To " + str(NewBuyOrderVolume)
			elif TopBuyOrder[3] < TopSellOrder[3]:
				BuyOrderCompletion = "Full"
				SellOrderCompletion = "Partial"
				NewSellOrderVolume = TopSellOrder[3] - TopBuyOrder[3]
				TransactionVolume = TopBuyOrder[3]
				cursor.execute("""UPDATE BasicOrderBook SET Volume = %f WHERE OrderNumber = %d""" % (NewSellOrderVolume, TopSellOrderNumber))
				print "Order " + str(TopSellOrder[0]) + " Volume Updated To " + str(NewSellOrderVolume)

This block is but a small piece of the main transaction function, which spans about 500 lines. It compares the the current top (most competitive) buy order's volume in the order book against the top sell order's volume. Then, it calculates whether each order was fully or partially filled (note: all orders were able to be partially fulfilled) and the new volume of each, then updates the order book again.

The SQL queries for the database were pretty bad. I'm not quite sure how I got through a single SQL tutorial without learning what a JOIN was (or even that it exists). Instead, whenever I needed an order, I would query for it within the aptly named IDBook table, then use the ID returned to query for it in the BasicOrderBook table. The database was also on the -3rd Normal Form, making the queries even slower. It was definitely a learning experience. Here's a corner of the database schema, as rendered in MySQL Workbench:

It's actually interesting to note that the transaction engine was about twice as fast as the leading exchange online at the time, discounting network lag of course, though that's probably because they had some extra work going on for cases I hadn't even considered. Still, it was a great source of motivation.

At least it was somewhat organized. Also note how I stored money as an 8-byte float.
Learning Points

First, let's say this was a huge project for someone completely new to web development and programming in general. Luckily, it had some simple calculations in the backend which could be easily implemented using loops and conditionals. All in all, I had a lot of fun. These are some of the main things I learned: