Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions atra-gateway/lib/atra_gateway/matching_engine.ex
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ defmodule AtraGateway.MatchingEngine do

request = %Orderbook.OrderRequest{
id: params.id,
price: to_string(params.price),
quantity: to_string(params.quantity),
price: to_proto_decimal(params.price),
quantity: to_proto_decimal(params.quantity),
side: proto_side(params.side),
order_type: proto_order_type(params.type),
instrument_id: params.instrument_id,
Expand Down Expand Up @@ -116,4 +116,9 @@ defmodule AtraGateway.MatchingEngine do

defp proto_order_type(:limit), do: :LIMIT
defp proto_order_type(:market), do: :MARKET

defp to_proto_decimal(value) do
scaled = round(value * 100_000_000)
%Orderbook.DecimalValue{units: scaled, scale: 8}
end
end
35 changes: 24 additions & 11 deletions atra-gateway/lib/atra_gateway/orders.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ defmodule AtraGateway.Orders do
def from_proto(response) do
%{
id: response.id,
price: String.to_float(response.price),
quantity: String.to_float(response.quantity),
remaining_quantity: String.to_float(response.remaining_quantity),
price: decimal_from_proto(response.price),
quantity: decimal_from_proto(response.quantity),
remaining_quantity: decimal_from_proto(response.remaining_quantity),
side: atom_from_proto_side(response.side),
type: atom_from_proto_order_type(response.order_type),
status: atom_from_proto_status(response.status),
Expand All @@ -40,16 +40,29 @@ defmodule AtraGateway.Orders do
}
end

defp atom_from_proto_side(0), do: :bid
defp atom_from_proto_side(1), do: :ask
defp atom_from_proto_side(:BID), do: :bid
defp atom_from_proto_side(:ASK), do: :ask
defp atom_from_proto_side(1), do: :bid
defp atom_from_proto_side(2), do: :ask

defp atom_from_proto_order_type(0), do: :limit
defp atom_from_proto_order_type(1), do: :market
defp atom_from_proto_order_type(:LIMIT), do: :limit
defp atom_from_proto_order_type(:MARKET), do: :market
defp atom_from_proto_order_type(1), do: :limit
defp atom_from_proto_order_type(2), do: :market

defp atom_from_proto_status(0), do: :pending
defp atom_from_proto_status(1), do: :partially_filled
defp atom_from_proto_status(2), do: :filled
defp atom_from_proto_status(3), do: :cancelled
defp atom_from_proto_status(:PENDING), do: :pending
defp atom_from_proto_status(:PARTIALLY_FILLED), do: :partially_filled
defp atom_from_proto_status(:FILLED), do: :filled
defp atom_from_proto_status(:CANCELLED), do: :cancelled
defp atom_from_proto_status(1), do: :pending
defp atom_from_proto_status(2), do: :partially_filled
defp atom_from_proto_status(3), do: :filled
defp atom_from_proto_status(4), do: :cancelled

defp decimal_from_proto(nil), do: 0.0
defp decimal_from_proto(%{units: units, scale: scale}) do
units / :math.pow(10, scale)
end

defp proto_timestamp_to_datetime(%{seconds: seconds, nanos: nanos}) do
DateTime.from_unix!(seconds, :second)
Expand Down
47 changes: 35 additions & 12 deletions atra-gateway/lib/atra_gateway/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ defmodule AtraGateway.Server do
use GRPC.Server, service: Orderbook.OrderBookService.Service
require Logger

defp parse_numeric(str) do
case Float.parse(str) do
{float, _} -> float
:error -> raise ArgumentError, "Invalid numeric format: #{inspect(str)}"
end
defp parse_numeric(%{units: units, scale: scale}) do
units / :math.pow(10, scale)
end

def place_order(request, _stream) do
Expand All @@ -28,7 +25,7 @@ defmodule AtraGateway.Server do
end

def cancel_order(request, _stream) do
Logger.info("atra.gateway.request.cancel_order id:#{inspect(request.order_id)}")
Logger.info("atra.gateway.request.cancel_order id:#{inspect(request.order_id)} instrument:#{inspect(request.instrument_id)}")
:poolboy.transaction(:grpc_pool, fn pid ->
channel = AtraGateway.GrpcConnection.get_channel(pid)
case Orderbook.OrderBookService.Stub.cancel_order(channel, request) do
Expand All @@ -40,8 +37,21 @@ defmodule AtraGateway.Server do
end)
end

def cancel_orders(request, _stream) do
Logger.info("atra.gateway.request.cancel_orders batch:#{length(request.requests)}")
:poolboy.transaction(:grpc_pool, fn pid ->
channel = AtraGateway.GrpcConnection.get_channel(pid)
case Orderbook.OrderBookService.Stub.cancel_orders(channel, request) do
{:ok, response} -> response
{:error, reason} ->
Logger.error("atra.gateway.error.request request:cancel_orders note:'#{inspect(reason)}'")
raise GRPC.RPCError, status: :internal, message: "Internal error"
end
end)
end

def get_order_book(request, _stream) do
Logger.info("atra.gateway.request.get_order_book depth:#{inspect(request.depth)}")
Logger.info("atra.gateway.request.get_order_book depth:#{inspect(request.depth)} instrument:#{inspect(request.instrument_id)}")
:poolboy.transaction(:grpc_pool, fn pid ->
channel = AtraGateway.GrpcConnection.get_channel(pid)
case Orderbook.OrderBookService.Stub.get_order_book(channel, request) do
Expand All @@ -54,7 +64,7 @@ defmodule AtraGateway.Server do
end

def get_order_status(request, _stream) do
Logger.info("atra.gateway.request.order_status id:#{inspect(request.order_id)}")
Logger.info("atra.gateway.request.order_status id:#{inspect(request.order_id)} instrument:#{inspect(request.instrument_id)}")
:poolboy.transaction(:grpc_pool, fn pid ->
channel = AtraGateway.GrpcConnection.get_channel(pid)
case Orderbook.OrderBookService.Stub.get_order_status(channel, request) do
Expand All @@ -67,7 +77,7 @@ defmodule AtraGateway.Server do
end

def get_trade_history(request, _stream) do
Logger.info("atra.gateway.request.get_trade_history limit:#{inspect(request.limit)}")
Logger.info("atra.gateway.request.get_trade_history limit:#{inspect(request.limit)} instrument:#{inspect(request.instrument_id)}")
:poolboy.transaction(:grpc_pool, fn pid ->
channel = AtraGateway.GrpcConnection.get_channel(pid)
case Orderbook.OrderBookService.Stub.get_trade_history(channel, request) do
Expand All @@ -79,6 +89,14 @@ defmodule AtraGateway.Server do
end)
end

def stream_order_book(_request, _stream) do
raise GRPC.RPCError, status: :unimplemented, message: "stream_order_book is not yet proxied by gateway"
end

def stream_trade_history(_request, _stream) do
raise GRPC.RPCError, status: :unimplemented, message: "stream_trade_history is not yet proxied by gateway"
end

def place_orders(request, _stream) do
Logger.info("atra.gateway.request.place_order batch:#{length(request.orders)}")
orders =
Expand Down Expand Up @@ -116,9 +134,9 @@ defmodule AtraGateway.Server do
defp to_proto_response(response) do
%Orderbook.OrderResponse{
id: response.id,
price: to_string(response.price),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gateway batch response uses outdated proto field

High Severity

The place_orders handler constructs Orderbook.OrderBatchResponse with an orders field containing OrderResponse items. The updated proto definition now uses a results field with OrderBatchItemResult items. This creates an incompatible wire format and will break once the Elixir proto module is regenerated.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 699f812. Configure here.

quantity: to_string(response.quantity),
remaining_quantity: to_string(response.remaining_quantity),
price: to_proto_decimal(response.price),
quantity: to_proto_decimal(response.quantity),
remaining_quantity: to_proto_decimal(response.remaining_quantity),
side: proto_side(response.side),
order_type: proto_order_type(response.type),
status: proto_status(response.status),
Expand All @@ -139,5 +157,10 @@ defmodule AtraGateway.Server do
defp proto_status(:partially_filled), do: :PARTIALLY_FILLED
defp proto_status(:filled), do: :FILLED
defp proto_status(:cancelled), do: :CANCELLED

defp to_proto_decimal(value) do
scaled = round(value * 100_000_000)
%Orderbook.DecimalValue{units: scaled, scale: 8}
end
end

Loading
Loading