A real-time VWAP calculation engine using Coinbase's Websocket data feed.
-
This engine subscribes to the Coinbase Websocket
matches
channel and retrieves data for the following trading pairs:- BTC-USD
- ETH-USD
- ETH-BTC
-
It then calculates the VWAP per trading pair using a sliding window of 200 (maximum) data points.
-
The VWAP formula used is based on the following resources:
-
The sliding window is implemented as a slice of data points. When a new data point is pushed into the window, we check if the window size has been exceeded, and pop the oldest data point from the queue.
-
Rather than recalculate the
Product * Quantity
andQuantity
summations each time a new data point is added, thePQ
andQ
of the oldest data point is first deducted from a running total in O(N) constant time and O(1) space.
For the purposes of this exercise, this engine takes the KISS+YAGNI approach. Therefore, the following assumptions have been made:
-
No client authentication. The engine uses the publicly available websocket feed, and takes rate limiting into consideration. Client authentication can be trivially added if required.
-
The engine only handles the
matches
channel. This could be further extended to handle the other channel types in the Coinbase websocket client. -
Only the Coinbase websocket feed is supported. The packages may need to be structured differently to handle other exchanges, and client types.
-
Under normal circumstances, the data feed service would be separate from the vwap calculation engine. I have opted to combine it in a single service due to time constraints.
To run the engine...
make run
This builds the docker image and runs the docker container.
make run-cli
This runs the command go run ./cmd/server/main.go
To run the tests:
make test
Unit tests only. No integration test.
Things to do if I had more time:
- Improve test coverage
- Split the websocket data feed and VWAP calculation engine into two separate service implementions. We use the Dogma framework to build event-sourcing services like this.
- Handle websocket timeouts and disconnects.
- The sandbox environment operates differently to the live environment.
Firstly, it only accepts
BTC-USD
. All otherproduct_id
results in aFailed to subscribe
error. - Secondly, it sends a single
last_match
response and nothing else for an extended period. It intermittently sendsmatch
responses in short bursts, again at extended intervals. It could be a quirk with the sandbox environment, as it seems to work fine on the live feed.