Tea & Tech (🍵)

How I learned Rust by trading Cryptocurrencies

August 08, 2020

Since around 2015, I’ve been dollar-cost averaging cryptocurrencies over at Coinbase. “Stacking Sats,” it’s called these days.

Coinbase makes it very straightforward: link your bank account, pick your currency and frequency of purchase, et voila: your USD becomes cryptocurrency. For a fee, of course.

Anybody who has been around Cryptocurrency for more than a couple minutes knows that prices tend to fluctuate wildly. On the whole, however, prices have been trending up. As of the time of this writing, Bitcoin is:

  • Last 6 months, +194.86%
  • Last 2 years, +266.49%
  • Last 3 years, +290.18%
  • Last 5 years, +5,300.92%
Price information derived from barchart

With a significant general upward trend like this, monthly cost averaging means you’re leaving a lot of BTC on the table compared with weekly or daily cost average investing. I decided that daily dollar cost averaging was in my best interest, so I set up a recurring purchase for $10 per day, and ate the $1 service charge. What’s $30/mo when you’ve got compounding double-digit gains on $270/mo?

It’s a lot of extra money on the table! Thinking about this in terms of USD is the wrong approach; the amount of USD I’m spending is fixed. The correct way to think about this is: how much more BTC would I have if I were not paying Coinbase a 10% fee?

To be clear, Coinbase’s fee is a much smaller percentage if you’re investing a larger sum of money. Investing a larger sum would mean more time between purchases, which (for reasons described above) I want to avoid.

One solution is to use Coinbase Pro instead of Coinbase. The trading fees on Coinbase Pro are significantly less — at the volume I’m trading, they’re 0.5% instead of 10%: a whole 9.5% less.

Switching to Coinbase Pro, in other words, earns me 10.5% more BTC per transaction when compared with Coinbase’s “Recurring Buys” offering. The problem? Coinbase Pro does not offer recurring buys! They do, however, offer an API that we can use to initiate recurring buys on our own.

Enter Rust

Call me paranoid, but I am not about to put API keys that can access my personal Coinbase account on servers that I don’t physically control. This means running servers at home, which means electricity costs and heat.

The electricity and heat problems associated with running servers at home can be mitigated by using hardware like a Raspberry Pi — a credit-card sized computer that draws around 5W of power, and doesn’t put out enough heat to even require fans. The downsides include limited processing power, and downright atrocious disk IO (if using the built-in SD card reader).

The Pi’s performance limitations mean that I want software running on it to be small and fast. Furthermore, because I’m dealing with money and network-based APIs, it’s also important that the software I’m using is correct.

The Rust Programming Language checks all of these boxes — with performance on par with C and C++, and a compiler that requires you to account for failure cases and not just happy paths, it becomes difficult to write incorrect code. Furthermore, Rust makes it easy to compile to multiple targets, which means getting it onto an ARM processor (the Pi) is not a significant undertaking.

In fact, thanks to Github’s new pricing strategy around Github Actions (free!), we can just let Github compile all the binaries for us! 😁

The Strategy

Instead of relying on Coinbase to purchase BTC for us, we’ll write a Rust program to do it instead. Nothing fancy needed here — no price watching or machine learning to optimize purchase times, just a Rust binary that starts instantly, makes a transaction, logs the output, and exits. Stick it on the crontab and call it good!

The program I ended up with, hodl, has been running faithfully for the past two months! It’s my first Rust program, so please be kind and help me learn 😊.

Since I began “stacking sats” this way, I’ve only run into one issue: after losing power in a storm, we came back online with a new IP address, and the new address was not yet associated with my API key, so hodl failed to make a couple purchases (this is a security feature that you can elect to disable). I noticed something was afoot after I stopped receiving my nightly confirmation emails, so I logged onto the Pi, checked the logs, saw the issue, added the new IP address, and we were back in business.

Setting it up

Everyone is going to have different API keys, and I’m not about to check mine into the repository :) In order to use hodl, you need to set some environment variables.

My recommendation would be to create a script, hodl, that sets these and invokes the hodl binary you download:

#!/bin/bash

export COINBASE_API_KEY=[your key]
export COINBASE_API_SECRET=[your secret]
export COINBASE_API_PASSPHRASE=[your passphrase]
export BANK_ID=[id of your associated bank account]

./hodl-ARMv7 $@

Then, you can set your crontab to run periodic deposit and buy commands. For example,

# m h  dom mon dow   command
0   0   */3  *   *   /home/pi/hodl deposit 45 2>&1 | tee -a /home/pi/logs/hodl.log
7   0   *    *   *   /home/pi/hodl buy BTC 10 2>&1 | tee -a /home/pi/logs/hodl.log
8   0   *    *   *   /home/pi/hodl buy ETH 5 2>&1 | tee -a /home/pi/logs/hodl.log

Et voila, cryptocurrency dollar cost averaging at a fraction of the retail cost!

The crontab above will:

  1. Deposit $45 USD into Coinbase every 3 days (every 72 hours)
  2. Buy $10 USD worth of BTC every day at 7 minutes past midnight
  3. Buy $5 USD worth of ETH every day at 8 minutes past midnight
  4. Send both standard error and standard output to a log file

The times I picked were arbitrary; some time spent with historical data and in a Jupyter notebook revealed that there wasn’t a reliable correlation with time of day and low (relative to a sliding window) prices, so pick a time that’s convenient for you!

Thoughts on Rust

Overall, I’ve walked away with a positive impression of Rust. I especially like the match structure, though it took me a while to get comfortable with the difference between Option and Result types. Figuring out how to cryptographically sign API request headers to accommodate the Coinbase Pro API was a fun challenge that forced me to get into the docs of other Crates, and (coming from the dynamically typed world of JavaScript and Clojure) suffer a bit of pain for the type system, though I am grateful that it keeps me honest. I also like the stance Rust takes towards data organization with Structs, which I feel are a much better alternative to the OO purgatory I found myself in back when worked in Java. When it comes to data, though, I still feel like Clojure has it figured out the best.

For this job, Rust was excellent, and I believe in picking the right tool for the job. Not that other tools wouldn’t have done the job just as nicely, but I was looking for an excuse to learn something, and this solved a real problem that is making me more money as a result. Just in time, too: since I started using hodl instead of Coinbase, the price of BTC has gone up over 30%!

Conclusion

If you’re in the market for some Cryptocurrencies, why not check out hodl, or use it as a starting point for trading against some other API if Coinbase Pro is not your preferred exchange? If you’re a Rust pro, I’d love your feedback on how to improve the program. And I’d like everyone to start buying Bitcoin — if you haven’t already, now is the time to hop on the bandwagon!


Andrew J. Pierce collects Jian Shui teapots and lives in Virginia with his wife, son, and Ziggy the cat. You can follow him on Twitter.

BTC: 121NtsFHrjjfxTLBhH1hQWrP432XhNG7kB
© 2020 Andrew J. Pierce