As a physical Crypto Ticker producer, we know that stable and real-time data is very important for us and our customers, so our products L1 crypto ticker and Nixie bitcoin clock are powered by several professional platforms’ data sources. To ensure that we get the data in real time, we prefer using the WebSocket streams from Binance and Coinbase first.
In this article, we are going to show you how we built the Elixir application to get real-time updates from the Binance and Coinbase WebSocket streams.
Binance Websocket streams
Let’s get started with the Binance WebSocket streams. Actually, the awesome online book ‘Hands-on Elixir & OTP: Cryptocurrency trading bot’ written by Kamil Skowron has the details of how to stream live cryptocurrency prices from the Binance WSS. The code in the book is based on Elixir umbrella app, but for us, we are using Phoenix to build our app, so here we would adapt the code base to Phoenix.
1. Create a Phoenix project
mix phx.new x_sure_wss
2. Append WebSocket client module: WebSocket
and the concurrent cache module: con_cache
to the deps
function inside the mix.exs
file. And don’t forget to run mix deps.get
to fetch these dependencies.
3. :con_cache an ETS based key/value storage for caching the data from WebSocket, we need to start it in lib/x_sure_wss/application.ex:
4. Connect Binance’s WebSocket Stream using the WebSockex module
As we want to receive multiple cryptocurrency trades and ticker streams and look at the Binance WebSocket documents, combined streams are accessed at /stream?streams=<streamName1>/<streamName2>/<streamName3>
meet our requirements perfectly.
The trade streams for multiple cryptocurrencies is: wss://stream.binance.com:9443/stream?streams=btcusdt@trade/ethusdt@trade/bnbusdt@trade/solusdt@trade/adausdt@trade/xrpusdt@trade/dotusdt@trade/dogeusdt@trade/avaxusdt@trade
So define the XSureWss.Binance.BinanceWss (lib/x_sure_wss/binance/binance_wss.ex) module to use WebSockex to connect to Binance Websocket
defmodule XSureWss.Binance.BinanceWss do
use WebSockex
require Logger
@stream_endpoint "wss://stream.binance.com:9443/stream?streams="
def start_link(streams) do
case WebSockex.start_link(
"#{@stream_endpoint}#{streams}",
__MODULE__,
nil
) do
{:ok, pid} ->
Logger.info("Binance websocket started for #{streams}")
{:ok, pid}
{:error, reason} ->
Logger.error("error: #{inspect(reason)}")
{:error, %{msg: "#{inspect(reason)}"}}
end
end
def terminate(reason, state) do
Logger.warning("\nSocket Terminating:\n#{inspect reason}\n\n#{inspect state}\n")
exit(:normal)
end
def handle_frame({_type, msg}, state) do
case Jason.decode(msg) do
{:ok, event} -> process_event(event)
{:error, _} -> Logger.error("Unable to parse msg: #{msg}")
end
{:ok, state}
end
defp process_event(%{"data" => event, "stream"=> stream}) do
Logger.debug(
"Stream event received " <>
"#{stream} #{inspect(event)}"
)
case event do
%{"e" => "trade"} ->
ConCache.put(:xsure_cache, stream, event["p"])
%{"e" => "24hrTicker"} ->
ConCache.put(:xsure_cache, stream, event["0"])
Logger.debug("ticker event")
_->
Logger.debug("other steam event")
end
end
end
5. Start Binance WebSocket when Phoenix application starts
Define XSureWss.Binance.Streamer (lib/x_sure_wss/binance/binance_streamer.ex) the Phoenix Supervisor child_spec. Here we separate trade streams and ticker streams into 2 processes.
defmodule XSureWss.Binance.Streamer do
alias XSureWss.Binance.BinanceWss
alias XSureWss.TickerUtils
def child_spec(_args) do
# Specs for the Binance websocket.
streams = [Enum.join(TickerUtils.binance_trade_streams, "/"), Enum.join(TickerUtils.binance_ticker_streams, "/")]
children =
for {stream, i} <- Enum.with_index(streams) do
Supervisor.child_spec({BinanceWss, stream},
id: {BinanceWss, "stream_#{i}"}
)
end
# Spec for the supervisor that will supervise the Binance websocket.
%{
id: BinanceStreamerSupervisor,
type: :supervisor,
start: {Supervisor, :start_link, [children, [strategy: :one_for_one]]}
}
end
end
Append XSureWss.Binance.Streamer to application start
Run mix phx.server
. If everything is OK, you will see the following streams logs
Source code
You can find the complete finished code in this GitHub repository. Please don’t forget to change the dev DB config to yours, otherwise, you will get the below Postgrex errors.
What’s Next
In the next article, we will show you how to integrate Coinbase WebSocket as well.