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 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.
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.
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 bitcoin.org tutorial was pretty vague. It's amazing how much I can write when I'm avoiding refactoring code.
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"
FulfilledOrderList.append(TopBuyOrder[0])
FulfilledOrderList.append(TopSellOrder[0])
TransactionVolume = TopSellOrder[3]
elif TopBuyOrder[3] > TopSellOrder[3]:
BuyOrderCompletion = "Partial"
SellOrderCompletion = "Full"
FulfilledOrderList.append(TopSellOrder[0])
NewBuyOrderVolume = TopBuyOrder[3] - TopSellOrder[3]
TransactionVolume = TopSellOrder[3]
cursor.execute("""UPDATE BasicOrderBook SET Volume = %f WHERE OrderNumber = %d""" % (NewBuyOrderVolume, TopBuyOrderNumber))
db.commit()
print "Order " + str(TopBuyOrder[0]) + " Volume Updated To " + str(NewBuyOrderVolume)
elif TopBuyOrder[3] < TopSellOrder[3]:
BuyOrderCompletion = "Full"
SellOrderCompletion = "Partial"
FulfilledOrderList.append(TopBuyOrder[0])
NewSellOrderVolume = TopSellOrder[3] - TopBuyOrder[3]
TransactionVolume = TopBuyOrder[3]
cursor.execute("""UPDATE BasicOrderBook SET Volume = %f WHERE OrderNumber = %d""" % (NewSellOrderVolume, TopSellOrderNumber))
db.commit()
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.
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:
If I learned anything, it was this. Drawing sketches of how a page should work, wireframe models of how your functions will interact, and even your file structure. Planning things out makes the future a much friendlier place.
This was my first run-in with web development. Turns out, I love it! There's so many good resources out there on how to get started, and I'm a strong advocate for starting programming things that you can see your progress on. Sure, you can do a lot of really cool stuff in a terminal, but most novice programmers may get bored or feel demotivated if their entire programming experience is with a black box with white text. Anyway, this project opened my eyes to the things I could do with HTML/CSS/Javascript and made me excited to start something new.
It's worth noting that the database schema above is the 11th iteration. And each version was vastly different from the preceding. Using them correctly, especially from the start, will make your code much cleaner, your functions much faster, and your conscious much relaxed. This ties into point 1.
It took me over a month to figure out how to use Apache to set up a web server. I didn't even know what DNS was before this, and my only run-ins with IP addresses was juggling them around for hosting Minecraft servers on a Hamachi VPN. I still remember the feeling I got when I saw the homepage pop up after refreshing the page instead of an Apache error. I felt like I could do things again. I didn't learn until later, though, that that cycle of self-doubt and euphoria is part of life for every programmer.
Project Exchange was invaluable to me. I went from Codecademy Python student to full-stack developer in about a year, and along the way I made enough mistakes to know when I was doing something wrong before I started. I developed what I would call a "code intuition." And now, I still use what I learned in my current projects. All in all, it was a success.