|
7 | 7 | using FluentAssertions;
|
8 | 8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
|
9 | 9 | using Newtonsoft.Json;
|
| 10 | +using NSubstitute.ExceptionExtensions; |
| 11 | +using static System.Net.WebRequestMethods; |
10 | 12 |
|
11 | 13 | namespace ExchangeSharpTests
|
12 | 14 | {
|
13 | 15 | [TestClass]
|
14 | 16 | public sealed class ExchangeCoinbaseAPITests
|
15 | 17 | {
|
16 |
| - private async Task<ExchangeCoinbaseAPI> MakeMockRequestMaker(string response = null) |
17 |
| - { |
18 |
| - var requestMaker = new MockAPIRequestMaker(); |
19 |
| - if (response != null) |
20 |
| - { |
21 |
| - requestMaker.GlobalResponse = response; |
22 |
| - } |
| 18 | + private async Task<ExchangeCoinbaseAPI> CreateSandboxApiAsync(string response = null) |
| 19 | + { // per Coinbase: All responses are static and pre-defined. https://docs.cdp.coinbase.com/advanced-trade/docs/rest-api-sandbox. Thus, no need to use MockAPIRequestMaker and just connect to real sandbox every time |
| 20 | + //var requestMaker = new MockAPIRequestMaker(); |
| 21 | + //if (response != null) |
| 22 | + //{ |
| 23 | + // requestMaker.GlobalResponse = response; |
| 24 | + //} |
23 | 25 | var api = (
|
24 | 26 | await ExchangeAPI.GetExchangeAPIAsync(ExchangeName.Coinbase) as ExchangeCoinbaseAPI
|
25 | 27 | )!;
|
26 |
| - api.RequestMaker = requestMaker; |
| 28 | + //api.RequestMaker = requestMaker; |
| 29 | + api.BaseUrl = "https://api-sandbox.coinbase.com/api/v3/brokerage"; |
27 | 30 | return api;
|
28 | 31 | }
|
| 32 | + |
| 33 | + [TestMethod] |
| 34 | + public async Task PlaceOrderAsync_Success() |
| 35 | + { |
| 36 | + var api = await CreateSandboxApiAsync(); |
| 37 | + { // per Coinbase: Users can make API requests to Advanced sandbox API without authentication. https://docs.cdp.coinbase.com/advanced-trade/docs/rest-api-sandbox. Thus, no need to set api.PublicApiKey and api.PrivateApiKey |
| 38 | + var orderRequest = new ExchangeOrderRequest |
| 39 | + { |
| 40 | + MarketSymbol = "BTC-USD", |
| 41 | + Amount = 0.0001m, |
| 42 | + Price = 10000m, |
| 43 | + IsBuy = true, |
| 44 | + OrderType = OrderType.Limit |
| 45 | + }; |
| 46 | + |
| 47 | + var orderResult = await api.PlaceOrderAsync(orderRequest); |
| 48 | + orderResult.Should().NotBeNull("an order result should be returned"); |
| 49 | + orderResult.ClientOrderId.Should().Be("sandbox_success_order", "this is what the sandbox returns"); |
| 50 | + orderResult.OrderId.Should().Be("f898eaf4-6ffc-47be-a159-7ff292e5cdcf", "this is what the sandbox returns"); |
| 51 | + orderResult.MarketSymbol.Should().Be(orderRequest.MarketSymbol, "the market symbol should be the same as requested"); |
| 52 | + orderResult.IsBuy.Should().Be(false, "the sandbox always returns a SELL, even if a buy is submitted"); |
| 53 | + orderResult.Result.Should().Be(ExchangeAPIOrderResult.PendingOpen, "the order should be placed successfully in sandbox"); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + [TestMethod] |
| 58 | + public async Task PlaceOrderAsync_Failure() |
| 59 | + { |
| 60 | + var api = await CreateSandboxApiAsync(); |
| 61 | + { // per Coinbase: Users can make API requests to Advanced sandbox API without authentication. https://docs.cdp.coinbase.com/advanced-trade/docs/rest-api-sandbox. Thus, no need to set api.PublicApiKey and api.PrivateApiKey |
| 62 | + var orderRequest = new ExchangeOrderRequest |
| 63 | + { |
| 64 | + MarketSymbol = "BTC-USD", |
| 65 | + Amount = 0.0001m, |
| 66 | + Price = 10000m, |
| 67 | + IsBuy = true, |
| 68 | + OrderType = OrderType.Limit |
| 69 | + }; |
| 70 | + APIRequestMaker.AdditionalHeader = ("X-Sandbox", "PostOrder_insufficient_fund"); |
| 71 | + var orderResult = await api.PlaceOrderAsync(orderRequest); |
| 72 | + orderResult.Should().NotBeNull("an order result should be returned"); |
| 73 | + orderResult.ClientOrderId.Should().Be("9dde8003-fc68-4ec1-96ab-5a759e5f4f5c", "this is what the sandbox returns"); |
| 74 | + orderResult.OrderId.Should().BeNull("this is what the sandbox returns"); |
| 75 | + orderResult.MarketSymbol.Should().Be(orderRequest.MarketSymbol, "because the market symbol should be the same as requested"); |
| 76 | + orderResult.IsBuy.Should().Be(orderRequest.IsBuy, "this is what was requested"); |
| 77 | + orderResult.Result.Should().Be(ExchangeAPIOrderResult.Rejected, "testing for failure"); |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + [TestMethod] |
| 82 | + public async Task CancelOrderAsync_Success() |
| 83 | + { |
| 84 | + var api = await CreateSandboxApiAsync(); |
| 85 | + await api.CancelOrderAsync("1"); |
| 86 | + } |
| 87 | + |
| 88 | + [TestMethod] |
| 89 | + public async Task CancelOrderAsync_Failure() |
| 90 | + { |
| 91 | + var api = await CreateSandboxApiAsync(); |
| 92 | + APIRequestMaker.AdditionalHeader = ("X-Sandbox", "CancelOrders_failure"); |
| 93 | + Func<Task> act = () => api.CancelOrderAsync("1"); |
| 94 | + await act.Should().ThrowAsync<APIException>(); |
| 95 | + } |
29 | 96 | }
|
30 | 97 | }
|
0 commit comments