lib/tai/venue_adapters/bitmex/positions.ex

defmodule Tai.VenueAdapters.Bitmex.Positions do
  def positions(venue_id, credential_id, credentials) do
    venue_credentials = to_venue_credentials(credentials)

    with {:ok, venue_positions, _rate_limit} <-
           ExBitmex.Rest.Position.Index.get(venue_credentials) do
      positions =
        venue_positions
        |> Enum.map(&build(&1, venue_id, credential_id))
        |> Enum.filter(& &1)

      {:ok, positions}
    else
      {:error, reason, _} ->
        {:error, reason}
    end
  end

  defdelegate to_venue_credentials(credentials),
    to: Tai.VenueAdapters.Bitmex.Credentials,
    as: :from

  defp build(%ExBitmex.Position{current_qty: 0}, _, _), do: nil

  defp build(venue_position, venue_id, credential_id) do
    # TODO: This should come from products
    product_symbol =
      venue_position.symbol
      |> String.downcase()
      |> String.to_atom()

    %Tai.Trading.Position{
      venue_id: venue_id,
      credential_id: credential_id,
      product_symbol: product_symbol,
      side: venue_position |> side(),
      qty: venue_position |> qty(),
      entry_price: venue_position |> entry_price(),
      leverage: venue_position |> leverage(),
      margin_mode: venue_position |> margin_mode()
    }
  end

  defp side(%ExBitmex.Position{current_qty: qty}) when qty > 0, do: :long
  defp side(%ExBitmex.Position{current_qty: qty}) when qty < 0, do: :short

  defp qty(%ExBitmex.Position{current_qty: qty}) when qty > 0, do: Decimal.new(qty)
  defp qty(%ExBitmex.Position{current_qty: qty}) when qty < 0, do: Decimal.new(-qty)

  defp entry_price(%ExBitmex.Position{avg_entry_price: p}), do: Tai.Utils.Decimal.cast!(p)

  defp leverage(%ExBitmex.Position{leverage: l}), do: Tai.Utils.Decimal.cast!(l)

  defp margin_mode(%ExBitmex.Position{cross_margin: true}), do: :crossed
  defp margin_mode(%ExBitmex.Position{cross_margin: false}), do: :fixed
end