lib/tai/venue_adapters/ftx/create_order.ex

defmodule Tai.VenueAdapters.Ftx.CreateOrder do
  @moduledoc """
  Create orders for the FTX adapter
  """

  alias Tai.Orders.Responses

  def create_order(%Tai.Orders.Order{type: :limit} = order, credentials) do
    venue_side = order.side |> to_venue_side()
    venue_ioc = order.time_in_force |> to_venue_ioc()
    venue_price = order.price |> Decimal.to_float()
    venue_size = order.qty |> Decimal.to_float()
    credentials = struct!(ExFtx.Credentials, credentials)

    venue_payload = %ExFtx.OrderPayload{
      client_id: order.client_id,
      market: order.venue_product_symbol,
      side: venue_side,
      price: venue_price,
      size: venue_size,
      type: "limit",
      reduce_only: false,
      ioc: venue_ioc,
      post_only: order.post_only
    }

    credentials
    |> ExFtx.Orders.Create.post(venue_payload)
    |> parse_response(order)
  end

  defp to_venue_side(side), do: side |> Atom.to_string()

  defp to_venue_ioc(time_in_force), do: time_in_force == :ioc

  @date_format "{ISO:Extended}"
  defp parse_response({:ok, %ExFtx.Order{status: "new"} = venue_order}, %Tai.Orders.Order{}) do
    received_at = Tai.Time.monotonic_time()
    venue_order_id = venue_order.id |> Integer.to_string()
    venue_timestamp = venue_order.created_at |> Timex.parse!(@date_format)

    response = %Responses.CreateAccepted{
      id: venue_order_id,
      venue_timestamp: venue_timestamp,
      received_at: received_at
    }

    {:ok, response}
  end

  defp parse_response({:error, "Size too small for provide"}, _) do
    {:error, :size_too_small}
  end

  defp parse_response({:error, reason}, _) do
    {:error, {:unhandled, reason}}
  end
end