defmodule Tai.VenueAdapters.OkEx.Positions do
def positions(venue_id, credential_id, credentials) do
venue_credentials = to_venue_credentials(credentials)
with {:ok, swap_venue_positions} <- ExOkex.Swap.Private.list_positions(venue_credentials),
{:ok, futures_venue_positions} <-
ExOkex.Futures.Private.list_positions(venue_credentials) do
swap_positions = swap_venue_positions |> Enum.map(&build_swap(&1, venue_id, credential_id))
futures_positions =
futures_venue_positions |> Enum.flat_map(&build_futures(&1, venue_id, credential_id))
positions = swap_positions ++ futures_positions
{:ok, positions}
else
{:error, reason} ->
{:error, reason}
end
end
defp to_venue_credentials(credentials), do: struct(ExOkex.Config, credentials)
def build_swap(venue_position, venue_id, credential_id) do
%Tai.Trading.Position{
venue_id: venue_id,
credential_id: credential_id,
product_symbol: venue_position |> product_symbol(),
side: venue_position |> swap_side(),
qty: venue_position.position |> Decimal.new(),
entry_price: venue_position.avg_cost |> Decimal.new(),
margin_mode: venue_position |> margin_mode(),
leverage: venue_position |> leverage()
}
end
defp build_futures(venue_position, venue_id, credential_id) do
[
build_long_future(venue_position, venue_id, credential_id),
build_short_future(venue_position, venue_id, credential_id)
]
end
def build_long_future(venue_position, venue_id, credential_id) do
%Tai.Trading.Position{
venue_id: venue_id,
credential_id: credential_id,
product_symbol: venue_position |> product_symbol(),
side: :long,
qty: venue_position |> futures_qty(:long),
entry_price: venue_position |> futures_entry_price(:long),
margin_mode: venue_position |> margin_mode(),
leverage: venue_position |> leverage()
}
end
def build_short_future(venue_position, venue_id, credential_id) do
%Tai.Trading.Position{
venue_id: venue_id,
credential_id: credential_id,
product_symbol: venue_position |> product_symbol(),
side: :short,
qty: venue_position |> futures_qty(:short),
entry_price: venue_position |> futures_entry_price(:short),
margin_mode: venue_position |> margin_mode(),
leverage: venue_position |> leverage()
}
end
# TODO: This should come from products
defp product_symbol(venue_position) do
venue_position.instrument_id
|> String.downcase()
|> String.to_atom()
end
defp swap_side(%_struct{side: "long"}), do: :long
defp swap_side(%_struct{side: "short"}), do: :short
defp futures_qty(%_struct{long_qty: q}, :long), do: Decimal.new(q)
defp futures_qty(%_struct{short_qty: q}, :short), do: Decimal.new(q)
defp futures_entry_price(%_struct{long_avg_cost: p}, :long), do: Decimal.new(p)
defp futures_entry_price(%_struct{short_avg_cost: p}, :short), do: Decimal.new(p)
@crossed [ExOkex.Futures.CrossedPosition, ExOkex.Swap.CrossedPosition]
@fixed [ExOkex.Futures.FixedPosition, ExOkex.Swap.FixedPosition]
defp margin_mode(%type{}) when type in @crossed, do: :crossed
defp margin_mode(%type{}) when type in @fixed, do: :fixed
defp leverage(venue_position), do: venue_position.leverage |> Decimal.new()
end