Elixir Macros… Can This Be Done?

Newbie question…

…Before I dive into learning Elixir macros, please let me know, am I using the right tool for the job… or am I wasting my time even trying?

The problem:

I need API wrappers & adaptors to connect to 20+ crypto currency exchanges, and translate their inputs/outputs to a universal API format.

Each API will share similar functions such as “place order”, “cancel order”, “get balances”, “get order book” etc.

They differ in plenty of other areas too.

Ideal solution would be basic configuration settings that configured the aspects that might vary between wrappers & then automatically generate everything accordingly.

Can it be done? Or should I put my time into simply making a skeleton then custom coding each wrapper + adaptor individually?

Edit:
For reference here’s a few APIs I’ll be working with.

Bitfinex (REST & Websocket)

Poloniex
https://poloniex.com/support/api/

Bitshares
http://docs.bitshares.eu/api/index.html
http://docs.bitshares.eu/integration/traders/index.html

EtherDelta


(Still can’t find the documentation for that API yet.)

Bittrex

BTC38
http://www.btc38.com/trade/en_api_manage.html
http://www.btc38.com/help/document/2581.html

BTC-E
https://btc-e.com/api/documentation

Without knowing anything of the APIs this is hard to answer. Could you post some links to the API docs?

You probably want to go more of a GenServer route, write two wrappers for different API’s and see where you can normalize the code across the 2 different API’s. Slowly build those into a GenCrypto module that exposes callbacks for the unique aspects of each API. The goal would be to minimize setup of boilerplate for each API.

1 Like

I added a few of the APIs above.

Consider behaviors. Write a generic exchange module with a few callbacks:

defmodule Exchange do
  @callback place_order(Order.t) :: :ok | {:error, reason}
  @callback cancel_order(Order.t) :: :ok | {:error, reason}
  @callback balances() :: [integer]
  @callback order_book() :: OrderBook.t

  @exchanges [xexchange: XExchange, yxchange: YExchange]

  def place_order(exchange, order), do: module(exchange).place_order(order)
  def cancel_order(exchange, order), do: module(exchange).cancel_order(order)
  def balances(exchange), do: module(exchange).balances()
  def order_book(exchange), do: module(exchange).order_book()

  for {atom, module} <- @exchanges do
    def module(unquote(atom)), do: Exchange.unquote(module)
  end
end

(You can delegate more work to the Exchange module if there’s some generic processing that needs to take place.)

Then implement a callback module for each exchange:

defmodule Exchange.XExchange do
  @behaviour Exchange

  def place_order(order), do: ...
  def cancel_order(order), do: ...
  def balances(), do: ...
  def order_book(), do: ...
end

Then call the generic Exchange module with the short atom name of the exchange.

Exchange.balances(:yexchange)


https://hexdocs.pm/elixir/behaviours.html

2 Likes

This was what I was getting at with the GenCrypto idea.