Packages

Elixir client library for cryptocurrency exchanges — generated from CCXT specs via compile-time macros.

Current section

Files

Jump to
ccxt_client lib ccxt registry.ex
Raw

lib/ccxt/registry.ex

defmodule CCXT.Registry do
@moduledoc """
Compile-time exchange lookup registry.
Maps exchange ID atoms and strings to their generated module names.
Built from the spec manifest at compile time — recompiles automatically
when the manifest changes.
## Usage
CCXT.Registry.lookup(:bybit)
#=> {:ok, CCXT.Bybit}
CCXT.Registry.lookup!("binance")
#=> CCXT.Binance
CCXT.Registry.exchanges()
#=> ["aftermath", "alpaca", "apex", ...]
CCXT.Registry.loaded?(:bybit)
#=> true # if CCXT.Bybit module is compiled
"""
@manifest_path CCXT.Spec.manifest_path()
@external_resource @manifest_path
@exchange_ids CCXT.Spec.load_manifest!()["exchanges"]
# Pre-compute the ID-to-module mapping at compile time
@exchange_modules (for id <- @exchange_ids, into: %{} do
{id, Module.concat(CCXT, Macro.camelize(id))}
end)
@doc """
Looks up the module for an exchange ID.
Accepts both string and atom IDs.
## Examples
CCXT.Registry.lookup("bybit")
#=> {:ok, CCXT.Bybit}
CCXT.Registry.lookup(:unknown)
#=> {:error, {:unknown_exchange, "unknown"}}
"""
@spec lookup(String.t() | atom()) :: {:ok, module()} | {:error, {:unknown_exchange, String.t()}}
def lookup(id) when is_atom(id), do: lookup(Atom.to_string(id))
for {id, module} <- @exchange_modules do
def lookup(unquote(id)), do: {:ok, unquote(module)}
end
def lookup(id) when is_binary(id), do: {:error, {:unknown_exchange, id}}
@doc """
Looks up the module for an exchange ID, raising on unknown.
## Examples
CCXT.Registry.lookup!(:bybit)
#=> CCXT.Bybit
"""
@spec lookup!(String.t() | atom()) :: module()
def lookup!(id) do
case lookup(id) do
{:ok, module} -> module
{:error, _} -> raise ArgumentError, "unknown exchange: #{inspect(id)}"
end
end
@doc """
Returns the module for an exchange ID, or nil if unknown.
## Examples
CCXT.Registry.module_for("bybit")
#=> CCXT.Bybit
CCXT.Registry.module_for("nope")
#=> nil
"""
@spec module_for(String.t() | atom()) :: module() | nil
def module_for(id) do
case lookup(id) do
{:ok, module} -> module
{:error, _} -> nil
end
end
@doc """
Returns all registered exchange IDs as strings.
## Examples
CCXT.Registry.exchanges()
#=> ["aftermath", "alpaca", "apex", ...]
"""
@spec exchanges() :: [String.t()]
def exchanges, do: Enum.sort(@exchange_ids)
@doc """
Checks if an exchange ID is registered.
## Examples
CCXT.Registry.registered?(:bybit)
#=> true
"""
@spec registered?(String.t() | atom()) :: boolean()
def registered?(id) when is_atom(id), do: registered?(Atom.to_string(id))
def registered?(id) when is_binary(id), do: Map.has_key?(@exchange_modules, id)
@doc """
Checks if the exchange module is compiled and loaded.
Returns true only if the exchange is registered AND its module is
available in the BEAM. Useful for distinguishing "known exchange"
from "exchange module exists."
## Examples
CCXT.Registry.loaded?(:bybit)
#=> true # if CCXT.Bybit is compiled
"""
@spec loaded?(String.t() | atom()) :: boolean()
def loaded?(id) do
case lookup(id) do
{:ok, module} -> Code.ensure_loaded?(module)
{:error, _} -> false
end
end
end