test_that("spot place order validates market quantity selectors", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", config = cfg ), "Provide at least one of: quantity, quote_order_qty" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, quote_order_qty = 100, config = cfg ), "Only one of quantity, quote_order_qty may be supplied" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, time_in_force = "GTC", config = cfg ), "time_in_force" ) }) test_that("spot place order validates conditional limit and stop order fields", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, price = 100, config = cfg ), "time_in_force" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "SELL", type = "STOP_LOSS", quantity = 1, config = cfg ), "Provide at least one of: stop_price, trailing_delta" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "SELL", type = "LIMIT_MAKER", quantity = 1, price = 100, stop_price = 90, config = cfg ), "stop_price" ) }) test_that("spot place order validates iceberg and pegged order constraints", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, price = 100, time_in_force = "IOC", iceberg_qty = 0.1, config = cfg ), "iceberg_qty" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, peg_price_type = "PRIMARY_PEG", config = cfg ), "peg_price_type" ) expect_error( spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, time_in_force = "GTC", peg_price_type = "PRIMARY_PEG", peg_offset_value = 2, config = cfg ), "peg_offset_type" ) }) test_that("spot place order forwards signed params for valid requests", { local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_place_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, price = 100, time_in_force = "GTC", iceberg_qty = 0.2, new_order_resp_type = "FULL", config = config_spot(api_key = "k", secret_key = "s") ) expect_identical(out$path, "/api/v3/order") expect_identical(out$method, "POST") expect_identical(out$params$symbol, "BTCUSDT") expect_identical(out$params$timeInForce, "GTC") expect_identical(out$params$icebergQty, 0.2) expect_identical(out$params$newOrderRespType, "FULL") }) test_that("spot test order includes computeCommissionRates", { local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_test_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, compute_commission_rates = TRUE, config = config_spot(api_key = "k", secret_key = "s") ) expect_identical(out$path, "/api/v3/order/test") expect_identical(out$params$computeCommissionRates, "true") }) test_that("spot cancel order validates selectors and restrictions", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_cancel_order(symbol = "BTCUSDT", config = cfg), "Provide at least one of: order_id, orig_client_order_id" ) expect_error( spot_cancel_order( symbol = "BTCUSDT", order_id = 1, cancel_restrictions = "INVALID", config = cfg ), "cancel_restrictions" ) }) test_that("spot cancel order and cancel all orders call signed endpoints", { local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) cancel_out <- spot_cancel_order( symbol = "BTCUSDT", order_id = 10, new_client_order_id = "cancel-1", cancel_restrictions = "ONLY_NEW", config = config_spot(api_key = "k", secret_key = "s") ) cancel_all_out <- spot_cancel_all_orders( symbol = "BTCUSDT", config = config_spot(api_key = "k", secret_key = "s") ) expect_identical(cancel_out$path, "/api/v3/order") expect_identical(cancel_out$method, "DELETE") expect_identical(cancel_out$params$orderId, 10) expect_identical(cancel_out$params$cancelRestrictions, "ONLY_NEW") expect_identical(cancel_all_out$path, "/api/v3/openOrders") expect_identical(cancel_all_out$method, "DELETE") expect_identical(cancel_all_out$params$symbol, "BTCUSDT") }) test_that("spot cancel-replace validates cancel selectors and forwards params", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_cancel_replace_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", cancel_replace_mode = "STOP_ON_FAILURE", quantity = 1, config = cfg ), "Provide at least one of: cancel_order_id, cancel_orig_client_order_id" ) local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_cancel_replace_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", cancel_replace_mode = "ALLOW_FAILURE", cancel_order_id = 123, quantity = 1, price = 100, time_in_force = "GTC", order_rate_limit_exceeded_mode = "CANCEL_ONLY", config = cfg ) expect_identical(out$path, "/api/v3/order/cancelReplace") expect_identical(out$method, "POST") expect_identical(out$params$cancelOrderId, 123) expect_identical(out$params$cancelReplaceMode, "ALLOW_FAILURE") expect_identical(out$params$orderRateLimitExceededMode, "CANCEL_ONLY") }) test_that("spot amend keep priority validates selectors and uses PUT", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_amend_order_keep_priority( symbol = "BTCUSDT", new_qty = 1, config = cfg ), "Provide at least one of: order_id, orig_client_order_id" ) local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_amend_order_keep_priority( symbol = "BTCUSDT", order_id = 10, new_client_order_id = "amended-1", new_qty = 0.5, config = cfg ) expect_identical(out$path, "/api/v3/order/amend/keepPriority") expect_identical(out$method, "PUT") expect_identical(out$params$newQty, 0.5) }) test_that("spot order list oco validates conditional fields", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_order_list_oco( symbol = "BTCUSDT", side = "SELL", quantity = 1, above_type = "STOP_LOSS_LIMIT", below_type = "STOP_LOSS", below_stop_price = 90, config = cfg ), "above_price" ) local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_place_order_list_oco( symbol = "BTCUSDT", side = "SELL", quantity = 1, above_type = "TAKE_PROFIT_LIMIT", above_price = 110, above_stop_price = 108, above_time_in_force = "GTC", below_type = "STOP_LOSS_LIMIT", below_price = 90, below_stop_price = 92, below_time_in_force = "GTC", config = cfg ) expect_identical(out$path, "/api/v3/orderList/oco") expect_identical(out$params$aboveType, "TAKE_PROFIT_LIMIT") expect_identical(out$params$belowType, "STOP_LOSS_LIMIT") }) test_that("spot order list oto validates working and pending requirements", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_order_list_oto( symbol = "BTCUSDT", working_type = "LIMIT", working_side = "BUY", working_price = 100, working_quantity = 1, pending_type = "LIMIT", pending_side = "SELL", pending_quantity = 1, config = cfg ), "working_time_in_force" ) local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) out <- spot_place_order_list_oto( symbol = "BTCUSDT", working_type = "LIMIT", working_side = "BUY", working_price = 100, working_quantity = 1, working_time_in_force = "GTC", pending_type = "STOP_LOSS_LIMIT", pending_side = "SELL", pending_price = 90, pending_stop_price = 92, pending_quantity = 1, pending_time_in_force = "GTC", config = cfg ) expect_identical(out$path, "/api/v3/orderList/oto") expect_identical(out$params$workingType, "LIMIT") expect_identical(out$params$pendingType, "STOP_LOSS_LIMIT") }) test_that("spot order list otoco and cancel order list call signed endpoints", { cfg <- config_spot(api_key = "k", secret_key = "s") local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) otoco_out <- spot_place_order_list_otoco( symbol = "BTCUSDT", working_type = "LIMIT", working_side = "BUY", working_price = 100, working_quantity = 1, working_time_in_force = "GTC", pending_side = "SELL", pending_quantity = 1, pending_above_type = "TAKE_PROFIT_LIMIT", pending_above_price = 110, pending_above_stop_price = 108, pending_above_time_in_force = "GTC", pending_below_type = "STOP_LOSS_LIMIT", pending_below_price = 90, pending_below_stop_price = 92, pending_below_time_in_force = "GTC", config = cfg ) cancel_out <- spot_cancel_order_list( symbol = "BTCUSDT", order_list_id = 99, config = cfg ) expect_identical(otoco_out$path, "/api/v3/orderList/otoco") expect_identical(otoco_out$params$pendingAboveType, "TAKE_PROFIT_LIMIT") expect_identical(cancel_out$path, "/api/v3/orderList") expect_identical(cancel_out$method, "DELETE") expect_identical(cancel_out$params$orderListId, 99) }) test_that("spot opo and opoco order lists call signed endpoints", { cfg <- config_spot(api_key = "k", secret_key = "s") local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) opo_out <- spot_place_order_list_opo( symbol = "BTCUSDT", working_type = "LIMIT", working_side = "BUY", working_price = 100, working_quantity = 1, working_time_in_force = "GTC", pending_type = "MARKET", pending_side = "SELL", config = cfg ) opoco_out <- spot_place_order_list_opoco( symbol = "BTCUSDT", working_type = "LIMIT", working_side = "BUY", working_price = 100, working_quantity = 1, working_time_in_force = "GTC", pending_side = "SELL", pending_above_type = "TAKE_PROFIT_LIMIT", pending_above_price = 110, pending_above_stop_price = 108, pending_above_time_in_force = "GTC", pending_below_type = "STOP_LOSS_LIMIT", pending_below_price = 90, pending_below_stop_price = 92, pending_below_time_in_force = "GTC", config = cfg ) expect_identical(opo_out$path, "/api/v3/orderList/opo") expect_identical(opo_out$params$pendingType, "MARKET") expect_identical(opoco_out$path, "/api/v3/orderList/opoco") expect_identical(opoco_out$params$pendingAboveType, "TAKE_PROFIT_LIMIT") }) test_that("spot sor order validates type-specific fields and forwards params", { cfg <- config_spot(api_key = "k", secret_key = "s") expect_error( spot_place_sor_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, config = cfg ), "price" ) expect_error( spot_place_sor_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, price = 100, config = cfg ), "price" ) local_mocked_bindings( .request_signed = function(config, path, params = NULL, method = c("GET", "POST", "PUT", "DELETE")) { list(path = path, params = params, method = method) }, .package = "binxr" ) place_out <- spot_place_sor_order( symbol = "BTCUSDT", side = "BUY", type = "LIMIT", quantity = 1, price = 100, time_in_force = "GTC", iceberg_qty = 0.1, config = cfg ) test_out <- spot_test_sor_order( symbol = "BTCUSDT", side = "BUY", type = "MARKET", quantity = 1, compute_commission_rates = TRUE, config = cfg ) expect_identical(place_out$path, "/api/v3/sor/order") expect_identical(place_out$params$icebergQty, 0.1) expect_identical(test_out$path, "/api/v3/sor/order/test") expect_identical(test_out$params$computeCommissionRates, "true") })