defmodule IbkrApi.ClientPortal.Order do @moduledoc """ `IbkrApi.ClientPortal.Order` module for managing order placement and monitoring. """ defmodule LiveOrder do defstruct [:execution_id, :symbol, :side, :order_description, :trade_time, :trade_time_r, :size, :price, :order_ref, :submitter, :exchange, :commission, :net_amount, :account, :acountCode, :company_name, :contract_description_1, :sec_type, :conid, :conidex, :position, :clearing_id, :clearing_name, :liquidation_trade] end defmodule OrderResponse do defstruct [:filters, :orders, :snapshot] end defmodule OrderStatusResponse do defstruct [:sub_type, :request_id, :order_id, :conidex, :symbol, :side, :contract_description_1, :listing_exchange, :option_acct, :company_name, :size, :total_size, :currency, :account, :order_type, :limit_price, :stop_price, :cum_fill, :order_status, :order_status_description, :tif, :fg_color, :bg_color, :order_not_editable, :editable_fields, :cannot_cancel_order, :outside_rth, :deactivate_order, :use_price_mgmt_algo, :sec_type, :available_chart_periods, :order_description, :order_description_with_contract, :alert_active, :child_order_type, :size_and_fills, :exit_strategy_display_price, :exit_strategy_chart_description, :exit_strategy_tool_availability, :allowed_duplicate_opposite, :order_time, :oca_group_id] end defmodule ModifyOrderRequest do @moduledoc """ Struct representing a request to modify an existing order. """ @typedoc """ Type representing a modify order request struct. """ @type t :: %__MODULE__{ acct_id: String.t() | nil, conid: integer() | nil, order_type: String.t() | nil, outside_rth: boolean() | nil, price: float() | nil, aux_price: float() | nil, side: String.t() | nil, listing_exchange: String.t() | nil, ticker: String.t() | nil, tif: String.t() | nil, quantity: integer() | nil, deactivated: boolean() | nil } defstruct [ acct_id: nil, conid: nil, order_type: nil, outside_rth: nil, price: nil, aux_price: nil, side: nil, listing_exchange: nil, ticker: nil, tif: nil, quantity: nil, deactivated: nil ] end defmodule ModifyOrderResponse do defstruct [ order_id: nil, local_order_id: nil, order_status: nil ] end defmodule CancelOrderResponse do defstruct [ order_id: nil, msg: nil, conid: nil, account: nil ] end defmodule OrderPreviewRequest do @moduledoc """ Struct representing a request to preview an order before placement. """ @typedoc """ Type representing an order preview request struct. """ @type t :: %__MODULE__{ acct_id: String.t() | nil, conid: integer() | nil, conidex: String.t() | nil, sec_type: String.t() | nil, c_oid: String.t() | nil, parent_id: String.t() | nil, order_type: String.t() | nil, listing_exchange: String.t() | nil, is_single_group: boolean() | nil, outside_rth: boolean() | nil, price: float() | nil, aux_price: float() | nil, side: String.t() | nil, ticker: String.t() | nil, tif: String.t() | nil, trailing_amt: float() | nil, trailing_type: String.t() | nil, referrer: String.t() | nil, quantity: integer() | nil, cash_qty: float() | nil, fx_qty: float() | nil, use_adaptive: boolean() | nil, is_ccy_conv: boolean() | nil, allocation_method: String.t() | nil, strategy: String.t() | nil, strategy_parameters: map() } defstruct [ acct_id: nil, conid: nil, conidex: nil, sec_type: nil, c_oid: nil, parent_id: nil, order_type: nil, listing_exchange: nil, is_single_group: nil, outside_rth: nil, price: nil, aux_price: nil, side: nil, ticker: nil, tif: nil, trailing_amt: nil, trailing_type: nil, referrer: nil, quantity: nil, cash_qty: nil, fx_qty: nil, use_adaptive: nil, is_ccy_conv: nil, allocation_method: nil, strategy: nil, strategy_parameters: %{} ] end defmodule OrderPreviewResponse do defstruct [ amount: %{}, equity: %{}, initial: %{}, maintenance: %{}, warn: nil, error: nil ] end defmodule OrderRequest do @moduledoc """ Struct representing a request to place a new order. """ @typedoc """ Type representing an order request struct. """ @type t :: %__MODULE__{ acct_id: String.t() | nil, conid: integer() | nil, conidex: String.t() | nil, sec_type: String.t() | nil, c_oid: String.t() | nil, parent_id: String.t() | nil, order_type: String.t() | nil, listing_exchange: String.t() | nil, is_single_group: boolean() | nil, outside_rth: boolean() | nil, price: float() | nil, aux_price: float() | nil, side: String.t() | nil, ticker: String.t() | nil, tif: String.t() | nil, trailing_amt: float() | nil, trailing_type: String.t() | nil, referrer: String.t() | nil, quantity: integer() | nil, cash_qty: float() | nil, fx_qty: float() | nil, use_adaptive: boolean() | nil, is_ccy_conv: boolean() | nil, allocation_method: String.t() | nil, strategy: String.t() | nil, strategy_parameters: map() } defstruct [ acct_id: nil, conid: nil, conidex: nil, sec_type: nil, c_oid: nil, parent_id: nil, order_type: nil, listing_exchange: nil, is_single_group: nil, outside_rth: nil, price: nil, aux_price: nil, side: nil, ticker: nil, tif: nil, trailing_amt: nil, trailing_type: nil, referrer: nil, quantity: nil, cash_qty: nil, fx_qty: nil, use_adaptive: nil, is_ccy_conv: nil, allocation_method: nil, strategy: nil, strategy_parameters: %{} ] end defmodule OrderReplyResponse do defstruct order_id: nil, order_status: nil, local_order_id: nil end defmodule OrderPlacementResponse do defstruct id: nil, message: [] end alias IbkrApi.HTTP @base_url IbkrApi.Config.base_url() @spec get_live_orders() :: ErrorMessage.t_res() def get_live_orders do with {:ok, response} <- HTTP.get(Path.join(@base_url, "iserver/account/orders")) do {:ok, struct(OrderResponse, response)} end end @spec get_order_status(String.t()) :: ErrorMessage.t_res() def get_order_status(order_id) do with {:ok, response} <- HTTP.get(Path.join(@base_url, "iserver/account/order/status/#{order_id}")) do {:ok, struct(OrderStatusResponse, response)} end end @spec modify_order(String.t(), String.t(), ModifyOrderRequest.t()) :: ErrorMessage.t_res() def modify_order(account_id, order_id, %ModifyOrderRequest{} = modify_order_request) do with {:ok, response} <- HTTP.post(Path.join(@base_url, "/iserver/account/#{account_id}/order/#{order_id}"), modify_order_request) do {:ok, struct(ModifyOrderResponse, response)} end end @spec cancel_order(String.t(), String.t()) :: ErrorMessage.t_res() def cancel_order(account_id, order_id) do with {:ok, response} <- HTTP.delete(Path.join(@base_url, "/iserver/account/#{account_id}/order/#{order_id}")) do {:ok, struct(CancelOrderResponse, response)} end end @spec preview_order(String.t(), list(OrderPreviewRequest.t())) :: ErrorMessage.t_res() def preview_order(account_id, orders) do body = %{"orders" => orders} with {:ok, response} <- HTTP.post(Path.join(@base_url, "/iserver/account/#{account_id}/orders/whatif"), body) do {:ok, struct(OrderPreviewResponse, response)} end end @spec place_orders(String.t(), list(OrderRequest.t())) :: ErrorMessage.t_res() def place_orders(account_id, orders) do body = %{"orders" => orders} with {:ok, response} <- HTTP.post(Path.join(@base_url, "/iserver/account/#{account_id}/orders"), body) do {:ok, Enum.map(response, &struct(OrderPlacementResponse, &1))} end end @spec place_orders_for_fa(String.t(), list(OrderRequest.t())) :: ErrorMessage.t_res() def place_orders_for_fa(fa_group, orders) do body = %{"orders" => orders} with {:ok, response} <- HTTP.post(Path.join(@base_url, "/iserver/account/orders/#{fa_group}"), body) do {:ok, Enum.map(response, &struct(OrderPlacementResponse, &1))} end end @spec reply_to_order_query(String.t(), boolean) :: ErrorMessage.t_res() def reply_to_order_query(reply_id, confirmed) do body = %{"confirmed" => confirmed} with {:ok, response} <- HTTP.post(Path.join(@base_url, "/iserver/reply/#{reply_id}"), body) do {:ok, struct(OrderReplyResponse, response)} end end end