Current section
Files
Jump to
Current section
Files
lib/ccxt/ws/patterns/custom.ex
defmodule CCXT.WS.Patterns.Custom do
@moduledoc """
Custom pattern for exchanges with unique WebSocket formats.
These exchanges have unique subscription formats that don't fit into
standard patterns. Each requires exchange-specific handling.
## Custom Types
- `type_as_channel` (Bithumb) - Type field IS the channel name
- `url_path` (Bitopro) - Channel embedded in URL path
- `url_query` (IndependentReserve) - Channel in URL query param
- `auth_only` (Luno) - Sends credentials only, no subscribe message
- `numeric_message_type` (NDAX) - Numeric message type codes
- `sendTopicAction` (Deepcoin) - Nested sendTopicAction structure
- `array_format` (Upbit) - Array of subscription objects
For these exchanges, the generator may need custom handling or
the exchange module may override the generated functions.
"""
@behaviour CCXT.WS.Pattern
alias CCXT.WS.Pattern
@impl true
def subscribe(channels, config) when is_list(channels) do
# Custom patterns require exchange-specific handling
# Return a generic structure that can be extended
custom_type = config[:custom_type]
case custom_type do
"array_format" ->
# Upbit style: array of subscription objects
Enum.map(channels, fn channel ->
%{"type" => "ticker", "codes" => [channel]}
end)
"sendTopicAction" ->
# Deepcoin style: nested structure
%{
"sendTopicAction" => %{
"action" => "subscribe",
"topics" => channels
}
}
_ ->
# Default fallback
%{
"subscribe" => true,
"channels" => channels
}
end
end
@impl true
def unsubscribe(channels, config) when is_list(channels) do
custom_type = config[:custom_type]
case custom_type do
"array_format" ->
Enum.map(channels, fn channel ->
%{"type" => "ticker", "codes" => [channel], "isOnlyRealtime" => true}
end)
"sendTopicAction" ->
%{
"sendTopicAction" => %{
"action" => "unsubscribe",
"topics" => channels
}
}
_ ->
%{
"unsubscribe" => true,
"channels" => channels
}
end
end
@impl true
def format_channel(template, params, config) do
channel_name = template[:channel_name] || ""
separator = template[:separator] || config[:separator] || "."
market_id_format = template[:market_id_format] || config[:market_id_format] || :native
case params[:symbol] do
nil -> channel_name
symbol -> channel_name <> separator <> Pattern.format_market_id(symbol, market_id_format, config[:symbol_context])
end
end
end