From 93c070d7a2591f2d8d8ad9d1c69f04fc1ae463af Mon Sep 17 00:00:00 2001 From: Alex Kwiatkowski Date: Fri, 25 May 2018 16:33:31 -0700 Subject: [PATCH 1/2] Add fill or kill limit orders --- .../order_limit_buy_fill_or_kill_success.json | 41 +++++++++++++++++++ ...order_limit_sell_fill_or_kill_success.json | 41 +++++++++++++++++++ lib/binance.ex | 30 ++++++++++---- test/binance_test.exs | 38 +++++++++++++++++ 4 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 fixture/vcr_cassettes/order_limit_buy_fill_or_kill_success.json create mode 100644 fixture/vcr_cassettes/order_limit_sell_fill_or_kill_success.json diff --git a/fixture/vcr_cassettes/order_limit_buy_fill_or_kill_success.json b/fixture/vcr_cassettes/order_limit_buy_fill_or_kill_success.json new file mode 100644 index 0000000..95a7d67 --- /dev/null +++ b/fixture/vcr_cassettes/order_limit_buy_fill_or_kill_success.json @@ -0,0 +1,41 @@ +[ + { + "request": { + "body": "price=0.01&quantity=0.1&recvWindow=1000&side=BUY&symbol=LTCBTC&timeInForce=FOK×tamp=1527290557371&type=LIMIT&signature=***", + "headers": { + "X-MBX-APIKEY": "***" + }, + "method": "post", + "options": [], + "request_body": "", + "url": "https://api.binance.com/api/v3/order" + }, + "response": { + "binary": false, + "body": "{\"symbol\":\"LTCBTC\",\"orderId\":47527179,\"clientOrderId\":\"dY67P33S4IxPnJGx5EtuSf\",\"transactTime\":1527290557607,\"price\":\"0.01000000\",\"origQty\":\"0.10000000\",\"executedQty\":\"0.00000000\",\"status\":\"EXPIRED\",\"timeInForce\":\"FOK\",\"type\":\"LIMIT\",\"side\":\"BUY\"}", + "headers": { + "Content-Type": "application/json", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Date": "Fri, 25 May 2018 23:22:37 GMT", + "Server": "nginx", + "Vary": "Accept-Encoding", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains", + "X-Frame-Options": "SAMEORIGIN", + "X-Xss-Protection": "1; mode=block", + "X-Content-Type-Options": "nosniff", + "Content-Security-Policy": "default-src 'self'", + "X-Content-Security-Policy": "default-src 'self'", + "X-WebKit-CSP": "default-src 'self'", + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + "X-Cache": "Miss from cloudfront", + "Via": "1.1 aa42484f82c16d99015c599631def20c.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "EUJfEb7dmPCXVDExHIg_zyXCioBbrAvTnUO7W7oM0iXLb5u9RLfC4Q==" + }, + "status_code": 200, + "type": "ok" + } + } +] \ No newline at end of file diff --git a/fixture/vcr_cassettes/order_limit_sell_fill_or_kill_success.json b/fixture/vcr_cassettes/order_limit_sell_fill_or_kill_success.json new file mode 100644 index 0000000..9200288 --- /dev/null +++ b/fixture/vcr_cassettes/order_limit_sell_fill_or_kill_success.json @@ -0,0 +1,41 @@ +[ + { + "request": { + "body": "price=50000&quantity=0.001&recvWindow=1000&side=SELL&symbol=BTCUSDT&timeInForce=FOK×tamp=1527290985049&type=LIMIT&signature=***", + "headers": { + "X-MBX-APIKEY": "***" + }, + "method": "post", + "options": [], + "request_body": "", + "url": "https://api.binance.com/api/v3/order" + }, + "response": { + "binary": false, + "body": "{\"symbol\":\"BTCUSDT\",\"orderId\":108277184,\"clientOrderId\":\"lKYECwEPSTPzurwx6emuN2\",\"transactTime\":1527290985305,\"price\":\"50000.00000000\",\"origQty\":\"0.00100000\",\"executedQty\":\"0.00000000\",\"status\":\"EXPIRED\",\"timeInForce\":\"FOK\",\"type\":\"LIMIT\",\"side\":\"SELL\"}", + "headers": { + "Content-Type": "application/json", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Date": "Fri, 25 May 2018 23:29:45 GMT", + "Server": "nginx", + "Vary": "Accept-Encoding", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains", + "X-Frame-Options": "SAMEORIGIN", + "X-Xss-Protection": "1; mode=block", + "X-Content-Type-Options": "nosniff", + "Content-Security-Policy": "default-src 'self'", + "X-Content-Security-Policy": "default-src 'self'", + "X-WebKit-CSP": "default-src 'self'", + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + "X-Cache": "Miss from cloudfront", + "Via": "1.1 68807936c056006818525c5da31d108e.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "w3qEO4sfOGkq_SUsElVerpJPvffAYa-rxZGUfgpZhsoAXlQBqzJwTg==" + }, + "status_code": 200, + "type": "ok" + } + } +] \ No newline at end of file diff --git a/lib/binance.ex b/lib/binance.ex index eeea6d3..0a02726 100644 --- a/lib/binance.ex +++ b/lib/binance.ex @@ -311,22 +311,29 @@ defmodule Binance do Returns `{:ok, %{}}` or `{:error, reason}` """ - def order_limit_buy(%Binance.TradePair{from: from, to: to} = symbol, quantity, price) + def order_limit_buy(symbol, quantity, price, time_in_force \\ "GTC") + + def order_limit_buy( + %Binance.TradePair{from: from, to: to} = symbol, + quantity, + price, + time_in_force + ) when is_number(quantity) when is_number(price) when is_binary(from) when is_binary(to) do case find_symbol(symbol) do - {:ok, binance_symbol} -> order_limit_buy(binance_symbol, quantity, price) + {:ok, binance_symbol} -> order_limit_buy(binance_symbol, quantity, price, time_in_force) e -> e end end - def order_limit_buy(symbol, quantity, price) + def order_limit_buy(symbol, quantity, price, time_in_force) when is_binary(symbol) when is_number(quantity) when is_number(price) do - create_order(symbol, "BUY", "LIMIT", quantity, price, "GTC") + create_order(symbol, "BUY", "LIMIT", quantity, price, time_in_force) |> parse_order_response end @@ -337,22 +344,29 @@ defmodule Binance do Returns `{:ok, %{}}` or `{:error, reason}` """ - def order_limit_sell(%Binance.TradePair{from: from, to: to} = symbol, quantity, price) + def order_limit_sell(symbol, quantity, price, time_in_force \\ "GTC") + + def order_limit_sell( + %Binance.TradePair{from: from, to: to} = symbol, + quantity, + price, + time_in_force + ) when is_number(quantity) when is_number(price) when is_binary(from) when is_binary(to) do case find_symbol(symbol) do - {:ok, binance_symbol} -> order_limit_sell(binance_symbol, quantity, price) + {:ok, binance_symbol} -> order_limit_sell(binance_symbol, quantity, price, time_in_force) e -> e end end - def order_limit_sell(symbol, quantity, price) + def order_limit_sell(symbol, quantity, price, time_in_force) when is_binary(symbol) when is_number(quantity) when is_number(price) do - create_order(symbol, "SELL", "LIMIT", quantity, price, "GTC") + create_order(symbol, "SELL", "LIMIT", quantity, price, time_in_force) |> parse_order_response end diff --git a/test/binance_test.exs b/test/binance_test.exs index 8a4da8d..785c382 100644 --- a/test/binance_test.exs +++ b/test/binance_test.exs @@ -107,6 +107,25 @@ defmodule BinanceTest do assert response.type == "LIMIT" end end + + test "can create an order with a fill or kill duration" do + use_cassette "order_limit_buy_fill_or_kill_success" do + assert {:ok, %Binance.OrderResponse{} = response} = + Binance.order_limit_buy("LTCBTC", 0.1, 0.01, "FOK") + + assert response.client_order_id == "dY67P33S4IxPnJGx5EtuSf" + assert response.executed_qty == "0.00000000" + assert response.order_id == 47_527_179 + assert response.orig_qty == "0.10000000" + assert response.price == "0.01000000" + assert response.side == "BUY" + assert response.status == "EXPIRED" + assert response.symbol == "LTCBTC" + assert response.time_in_force == "FOK" + assert response.transact_time == 1_527_290_557_607 + assert response.type == "LIMIT" + end + end end describe ".order_limit_sell" do @@ -128,5 +147,24 @@ defmodule BinanceTest do assert response.type == "LIMIT" end end + + test "can create an order with a fill or kill duration" do + use_cassette "order_limit_sell_fill_or_kill_success" do + assert {:ok, %Binance.OrderResponse{} = response} = + Binance.order_limit_sell("BTCUSDT", 0.001, 50_000, "FOK") + + assert response.client_order_id == "lKYECwEPSTPzurwx6emuN2" + assert response.executed_qty == "0.00000000" + assert response.order_id == 108_277_184 + assert response.orig_qty == "0.00100000" + assert response.price == "50000.00000000" + assert response.side == "SELL" + assert response.status == "EXPIRED" + assert response.symbol == "BTCUSDT" + assert response.time_in_force == "FOK" + assert response.transact_time == 1_527_290_985_305 + assert response.type == "LIMIT" + end + end end end From d2d73320161e8ea99b1d83fdbdc60b7b6a966c29 Mon Sep 17 00:00:00 2001 From: Alex Kwiatkowski Date: Fri, 25 May 2018 16:39:28 -0700 Subject: [PATCH 2/2] Add immediate or cancel limit orders --- ...limit_buy_immediate_or_cancel_success.json | 41 +++++++++++++++++++ ...imit_sell_immediate_or_cancel_success.json | 41 +++++++++++++++++++ test/binance_test.exs | 38 +++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 fixture/vcr_cassettes/order_limit_buy_immediate_or_cancel_success.json create mode 100644 fixture/vcr_cassettes/order_limit_sell_immediate_or_cancel_success.json diff --git a/fixture/vcr_cassettes/order_limit_buy_immediate_or_cancel_success.json b/fixture/vcr_cassettes/order_limit_buy_immediate_or_cancel_success.json new file mode 100644 index 0000000..244cdb3 --- /dev/null +++ b/fixture/vcr_cassettes/order_limit_buy_immediate_or_cancel_success.json @@ -0,0 +1,41 @@ +[ + { + "request": { + "body": "price=0.01&quantity=0.1&recvWindow=1000&side=BUY&symbol=LTCBTC&timeInForce=IOC×tamp=1527291300666&type=LIMIT&signature=***", + "headers": { + "X-MBX-APIKEY": "***" + }, + "method": "post", + "options": [], + "request_body": "", + "url": "https://api.binance.com/api/v3/order" + }, + "response": { + "binary": false, + "body": "{\"symbol\":\"LTCBTC\",\"orderId\":47528830,\"clientOrderId\":\"zyMyhtRENlvFHrl4CitDe0\",\"transactTime\":1527291300912,\"price\":\"0.01000000\",\"origQty\":\"0.10000000\",\"executedQty\":\"0.00000000\",\"status\":\"EXPIRED\",\"timeInForce\":\"IOC\",\"type\":\"LIMIT\",\"side\":\"BUY\"}", + "headers": { + "Content-Type": "application/json", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Date": "Fri, 25 May 2018 23:35:00 GMT", + "Server": "nginx", + "Vary": "Accept-Encoding", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains", + "X-Frame-Options": "SAMEORIGIN", + "X-Xss-Protection": "1; mode=block", + "X-Content-Type-Options": "nosniff", + "Content-Security-Policy": "default-src 'self'", + "X-Content-Security-Policy": "default-src 'self'", + "X-WebKit-CSP": "default-src 'self'", + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + "X-Cache": "Miss from cloudfront", + "Via": "1.1 fb1574d5a6ba2d77d2a656aba08aa3c3.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "7FpRejCpXjYssWLkFBBSqvrIlcQQUmXaFGh4q1eFUpiWvRc91Ipo2g==" + }, + "status_code": 200, + "type": "ok" + } + } +] \ No newline at end of file diff --git a/fixture/vcr_cassettes/order_limit_sell_immediate_or_cancel_success.json b/fixture/vcr_cassettes/order_limit_sell_immediate_or_cancel_success.json new file mode 100644 index 0000000..0b140b2 --- /dev/null +++ b/fixture/vcr_cassettes/order_limit_sell_immediate_or_cancel_success.json @@ -0,0 +1,41 @@ +[ + { + "request": { + "body": "price=50000&quantity=0.001&recvWindow=1000&side=SELL&symbol=BTCUSDT&timeInForce=IOC×tamp=1527291410866&type=LIMIT&signature=***", + "headers": { + "X-MBX-APIKEY": "***" + }, + "method": "post", + "options": [], + "request_body": "", + "url": "https://api.binance.com/api/v3/order" + }, + "response": { + "binary": false, + "body": "{\"symbol\":\"BTCUSDT\",\"orderId\":108279070,\"clientOrderId\":\"roSkLhwX9KCgYqr4yFPx1V\",\"transactTime\":1527291411088,\"price\":\"50000.00000000\",\"origQty\":\"0.00100000\",\"executedQty\":\"0.00000000\",\"status\":\"EXPIRED\",\"timeInForce\":\"IOC\",\"type\":\"LIMIT\",\"side\":\"SELL\"}", + "headers": { + "Content-Type": "application/json", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Date": "Fri, 25 May 2018 23:36:51 GMT", + "Server": "nginx", + "Vary": "Accept-Encoding", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains", + "X-Frame-Options": "SAMEORIGIN", + "X-Xss-Protection": "1; mode=block", + "X-Content-Type-Options": "nosniff", + "Content-Security-Policy": "default-src 'self'", + "X-Content-Security-Policy": "default-src 'self'", + "X-WebKit-CSP": "default-src 'self'", + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + "X-Cache": "Miss from cloudfront", + "Via": "1.1 51f2e50a0d2a5ee1d9c830bf417b2713.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "BX8-X-VXYRrjfwPJ8H-Gx4sgVhcoBDZ7WlOiWn-u0SWuW2h0e5Rhpw==" + }, + "status_code": 200, + "type": "ok" + } + } +] \ No newline at end of file diff --git a/test/binance_test.exs b/test/binance_test.exs index 785c382..b95c5a0 100644 --- a/test/binance_test.exs +++ b/test/binance_test.exs @@ -126,6 +126,25 @@ defmodule BinanceTest do assert response.type == "LIMIT" end end + + test "can create an order with am immediate or cancel duration" do + use_cassette "order_limit_buy_immediate_or_cancel_success" do + assert {:ok, %Binance.OrderResponse{} = response} = + Binance.order_limit_buy("LTCBTC", 0.1, 0.01, "IOC") + + assert response.client_order_id == "zyMyhtRENlvFHrl4CitDe0" + assert response.executed_qty == "0.00000000" + assert response.order_id == 47_528_830 + assert response.orig_qty == "0.10000000" + assert response.price == "0.01000000" + assert response.side == "BUY" + assert response.status == "EXPIRED" + assert response.symbol == "LTCBTC" + assert response.time_in_force == "IOC" + assert response.transact_time == 1_527_291_300_912 + assert response.type == "LIMIT" + end + end end describe ".order_limit_sell" do @@ -166,5 +185,24 @@ defmodule BinanceTest do assert response.type == "LIMIT" end end + + test "can create an order with am immediate or cancel duration" do + use_cassette "order_limit_sell_immediate_or_cancel_success" do + assert {:ok, %Binance.OrderResponse{} = response} = + Binance.order_limit_sell("BTCUSDT", 0.001, 50_000, "IOC") + + assert response.client_order_id == "roSkLhwX9KCgYqr4yFPx1V" + assert response.executed_qty == "0.00000000" + assert response.order_id == 108_279_070 + assert response.orig_qty == "0.00100000" + assert response.price == "50000.00000000" + assert response.side == "SELL" + assert response.status == "EXPIRED" + assert response.symbol == "BTCUSDT" + assert response.time_in_force == "IOC" + assert response.transact_time == 1_527_291_411_088 + assert response.type == "LIMIT" + end + end end end