Skip to content

Commit e37432f

Browse files
authored
Merge pull request #4 from scripbox/task/add-orders-api
Add orders API
2 parents 5be66a6 + 52248b3 commit e37432f

File tree

4 files changed

+254
-1
lines changed

4 files changed

+254
-1
lines changed

lib/kite_connect_ex.ex

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule KiteConnectEx do
2-
alias KiteConnectEx.{User, Response, Portfolio, Instrument}
2+
alias KiteConnectEx.{User, Response, Portfolio, Instrument, Orders}
33

44
@api_url "https://api.kite.trade"
55

@@ -104,4 +104,14 @@ defmodule KiteConnectEx do
104104
"""
105105
@spec funds_and_margins(String.t(), String.t()) :: {:ok, List.t()} | Response.error()
106106
defdelegate funds_and_margins(access_token, segment_type), to: User
107+
108+
@doc """
109+
Get user's all orders `all_orders`
110+
111+
## Example
112+
113+
{:ok, orders} = KiteConnectEx.all_orders("access-token")
114+
"""
115+
@spec orders(String.t()) :: {:ok, List.t()} | Response.error()
116+
defdelegate orders(access_token), to: Orders, as: :all_orders
107117
end

lib/kite_connect_ex/orders.ex

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
defmodule KiteConnectEx.Orders do
2+
@moduledoc """
3+
Module to represent a user's orders
4+
"""
5+
6+
alias KiteConnectEx.Request
7+
alias KiteConnectEx.Orders.{Order}
8+
9+
@orders_path "/orders"
10+
11+
@doc """
12+
Get all user's `orders`
13+
14+
## Example
15+
16+
{:ok, orders} = KiteConnectEx.Orders.all_orders("access-token")
17+
"""
18+
@spec all_orders(String.t()) :: {:ok, List.t()} | Response.error()
19+
def all_orders(access_token) when is_binary(access_token) do
20+
Request.get(@orders_path, nil, auth_header(access_token), KiteConnectEx.request_options())
21+
|> case do
22+
{:ok, orders_data} ->
23+
{:ok, orders_data}
24+
25+
{:error, error} ->
26+
{:error, error}
27+
end
28+
end
29+
30+
defp auth_header(access_token) do
31+
[{"Authorization", "token " <> KiteConnectEx.api_key() <> ":" <> access_token}]
32+
end
33+
34+
end
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
defmodule KiteConnectEx.Orders.Order do
2+
@moduledoc """
3+
Module to represent a order resource.
4+
5+
- [Docs](https://kite.trade/docs/connect/v3/orders/#retrieving-orders)
6+
"""
7+
8+
@keys [
9+
order_id: nil,
10+
parent_order_id: nil,
11+
exchange_order_id: nil,
12+
placed_by: nil,
13+
variety: nil,
14+
status: nil,
15+
tradingsymbol: nil,
16+
exchange: nil,
17+
instrument_token: nil,
18+
transaction_type: nil,
19+
order_type: nil,
20+
product: nil,
21+
validity: nil,
22+
price: nil,
23+
quantity: nil,
24+
trigger_price: nil,
25+
average_price: nil,
26+
pending_quantity: nil,
27+
filled_quantity: nil,
28+
disclosed_quantity: nil,
29+
market_protection: nil,
30+
order_timestamp: nil,
31+
exchange_timestamp: nil,
32+
status_message: nil,
33+
tag: nil,
34+
meta: %{}
35+
]
36+
37+
@type t :: %__MODULE__{
38+
order_id: String.t(),
39+
parent_order_id: String.t(),
40+
exchange_order_id: String.t(),
41+
placed_by: String.t(),
42+
variety: String.t(),
43+
status: String.t(),
44+
tradingsymbol: String.t(),
45+
exchange: String.t(),
46+
instrument_token: Integer.t(),
47+
transaction_type: String.t(),
48+
order_type: String.t(),
49+
product: String.t(),
50+
validity: String.t(),
51+
price: Float.t(),
52+
quantity: Float.t(),
53+
trigger_price: Float.t(),
54+
average_price: Float.t(),
55+
pending_quantity: Float.t(),
56+
filled_quantity: Float.t(),
57+
disclosed_quantity: Float.t(),
58+
market_protection: Float.t(),
59+
order_timestamp: DateTime.t(),
60+
exchange_timestamp: DateTime.t(),
61+
status_message: String.t(),
62+
tag: String.t(),
63+
meta: %{}
64+
}
65+
66+
@derive {Jason.Encoder, only: Keyword.keys(@keys)}
67+
defstruct @keys
68+
69+
def new(attributes) when is_map(attributes) do
70+
struct(__MODULE__, %{
71+
order_id: attributes["order_id"],
72+
parent_order_id: attributes["parent_order_id"],
73+
exchange_order_id: attributes["exchange_order_id"],
74+
placed_by: attributes["placed_by"],
75+
variety: attributes["variety"],
76+
status: attributes["status"],
77+
tradingsymbol: attributes["tradingsymbol"],
78+
exchange: attributes["exchange"],
79+
instrument_token: attributes["instrument_token"],
80+
transaction_type: attributes["transaction_type"],
81+
order_type: attributes["order_type"],
82+
product: attributes["product"],
83+
validity: attributes["validity"],
84+
price: attributes["price"],
85+
quantity: attributes["quantity"],
86+
trigger_price: attributes["trigger_price"],
87+
average_price: attributes["average_price"],
88+
pending_quantity: attributes["pending_quantity"],
89+
filled_quantity: attributes["filled_quantity"],
90+
disclosed_quantity: attributes["disclosed_quantity"],
91+
market_protection: attributes["market_protection"],
92+
order_timestamp: attributes["order_timestamp"],
93+
exchange_timestamp: attributes["exchange_timestamp"],
94+
status_message: attributes["status_message"],
95+
tag: attributes["tag"],
96+
meta: attributes["meta"]
97+
})
98+
end
99+
100+
def new(_) do
101+
struct(__MODULE__, %{})
102+
end
103+
end

test/kite_connect_ex_test.exs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
defmodule KiteConnectExTest do
22
use ExUnit.Case
3+
alias KiteConnectEx.SampleResponse.Orders.{Order}
34

45
setup do
56
bypass = Bypass.open()
@@ -258,6 +259,111 @@ defmodule KiteConnectExTest do
258259
end
259260
end
260261

262+
describe "orders/1" do
263+
test "returns orders with valid response", %{bypass: bypass} do
264+
Bypass.expect_once(bypass, "GET", "/orders", fn conn ->
265+
Plug.Conn.resp(conn, 201, all_orders())
266+
end)
267+
268+
assert KiteConnectEx.orders("access-token") ==
269+
{:ok,
270+
[
271+
%{
272+
"average_price" => 0,
273+
"cancelled_quantity" => 0,
274+
"disclosed_quantity" => 0,
275+
"exchange" => "NSE",
276+
"exchange_order_id" => "1300000009032605",
277+
"exchange_timestamp" => "2021-04-01 13:31:36",
278+
"exchange_update_timestamp" => "2021-04-01 13:31:36",
279+
"filled_quantity" => 0,
280+
"guid" => "3106Xndfsskwjufvb",
281+
"instrument_token" => 1522689,
282+
"market_protection" => 0,
283+
"meta" => %{},
284+
"order_id" => "210401003340053",
285+
"order_timestamp" => "2021-04-01 13:31:35",
286+
"order_type" => "LIMIT",
287+
"parent_order_id" => nil,
288+
"pending_quantity" => 1,
289+
"placed_by" => "XG0030",
290+
"price" => 8.55,
291+
"product" => "MIS",
292+
"quantity" => 1,
293+
"status" => "OPEN",
294+
"status_message" => nil,
295+
"status_message_raw" => nil,
296+
"tag" => nil,
297+
"tradingsymbol" => "SOUTHBANK",
298+
"transaction_type" => "BUY",
299+
"trigger_price" => 0,
300+
"validity" => "DAY",
301+
"variety" => "regular"
302+
}
303+
]}
304+
end
305+
306+
test "returns error if API request fails", %{bypass: bypass} do
307+
Bypass.expect_once(bypass, "GET", "/orders", fn conn ->
308+
Plug.Conn.resp(
309+
conn,
310+
403,
311+
~s<{"status": "error", "error_type": "TokenException", "message": "Invalid access_token"}>
312+
)
313+
end)
314+
315+
assert KiteConnectEx.orders("access-token") ==
316+
{:error,
317+
%KiteConnectEx.Error{
318+
code: 403,
319+
error_type: "TokenException",
320+
message: "Invalid access_token"
321+
}}
322+
end
323+
324+
def all_orders() do
325+
"""
326+
{
327+
"data": [
328+
{
329+
"average_price": 0,
330+
"cancelled_quantity": 0,
331+
"disclosed_quantity": 0,
332+
"exchange": "NSE",
333+
"exchange_order_id": "1300000009032605",
334+
"exchange_timestamp": "2021-04-01 13:31:36",
335+
"exchange_update_timestamp": "2021-04-01 13:31:36",
336+
"filled_quantity": 0,
337+
"guid": "3106Xndfsskwjufvb",
338+
"instrument_token": 1522689,
339+
"market_protection": 0,
340+
"meta": {},
341+
"order_id": "210401003340053",
342+
"order_timestamp": "2021-04-01 13:31:35",
343+
"order_type": "LIMIT",
344+
"parent_order_id": null,
345+
"pending_quantity": 1,
346+
"placed_by": "XG0030",
347+
"price": 8.55,
348+
"product": "MIS",
349+
"quantity": 1,
350+
"status": "OPEN",
351+
"status_message": null,
352+
"status_message_raw": null,
353+
"tag": null,
354+
"tradingsymbol": "SOUTHBANK",
355+
"transaction_type": "BUY",
356+
"trigger_price": 0,
357+
"validity": "DAY",
358+
"variety": "regular"
359+
}
360+
],
361+
"status": "success"
362+
}
363+
"""
364+
end
365+
end
366+
261367
describe "holdings/1" do
262368
test "returns portfolio holdings with valid access_token", %{bypass: bypass} do
263369
Bypass.expect_once(bypass, "GET", "/portfolio/holdings", fn conn ->

0 commit comments

Comments
 (0)