Skip to content

Commit

Permalink
[Feature] Add optional levels to product order book (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
dougdellolio authored Jan 15, 2018
1 parent 26af7a9 commit ab55f41
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,21 @@ public static string Create()

return json;
}

public static string CreateWithLevelThree()
{
var json = @"
{
'sequence': '3',
'bids': [
[200, 100, '3b0f1225-7f84-490b-a29f-0faef9de823a'],
],
'asks': [
[200, 100, 'da863862-25f4-4868-ac41-005d11ab0a5f'],
]
}";

return json;
}
}
}
78 changes: 71 additions & 7 deletions GDAXClient.Specs/Services/Products/ProductsServiceSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class when_getting_all_products
};
}

class when_getting_a_product_order_book
class when_getting_a_product_order_book_for_level_one
{
Establish context = () =>
{
Expand All @@ -86,12 +86,76 @@ class when_getting_a_product_order_book
It should_have_correct_product_order_book_response = () =>
{
product_order_books_response.Sequence.ShouldEqual(3M);
product_order_books_response.Bids.SelectMany(p => p).ShouldContain(200);
product_order_books_response.Bids.SelectMany(p => p).ShouldContain(100);
product_order_books_response.Bids.SelectMany(p => p).ShouldContain(3);
product_order_books_response.Asks.SelectMany(p => p).ShouldContain(200);
product_order_books_response.Asks.SelectMany(p => p).ShouldContain(100);
product_order_books_response.Asks.SelectMany(p => p).ShouldContain(3);
product_order_books_response.Bids.First().Price.ShouldEqual(200M);
product_order_books_response.Bids.First().Size.ShouldEqual(100M);
product_order_books_response.Bids.First().NumberOfOrders.ShouldEqual(3);
product_order_books_response.Bids.First().OrderId.ShouldBeNull();
product_order_books_response.Asks.First().Price.ShouldEqual(200M);
product_order_books_response.Asks.First().Size.ShouldEqual(100M);
product_order_books_response.Asks.First().NumberOfOrders.ShouldEqual(3);
product_order_books_response.Asks.First().OrderId.ShouldBeNull();
};
}

class when_getting_a_product_order_book_for_level_two
{
Establish context = () =>
{
The<IHttpRequestMessageService>().WhenToldTo(p => p.CreateHttpRequestMessage(Param.IsAny<HttpMethod>(), Param.IsAny<Authenticator>(), Param.IsAny<string>(), Param.IsAny<string>()))
.Return(new HttpRequestMessage());

The<IHttpClient>().WhenToldTo(p => p.SendASync(Param.IsAny<HttpRequestMessage>()))
.Return(Task.FromResult(new HttpResponseMessage()));

The<IHttpClient>().WhenToldTo(p => p.ReadAsStringAsync(Param.IsAny<HttpResponseMessage>()))
.Return(Task.FromResult(ProductsOrderBookResponseFixture.Create()));
};

Because of = () =>
product_order_books_response = Subject.GetProductOrderBookAsync(ProductType.BtcUsd, ProductLevel.Two).Result;

It should_have_correct_product_order_book_response = () =>
{
product_order_books_response.Sequence.ShouldEqual(3M);
product_order_books_response.Bids.First().Price.ShouldEqual(200M);
product_order_books_response.Bids.First().Size.ShouldEqual(100M);
product_order_books_response.Bids.First().NumberOfOrders.ShouldEqual(3);
product_order_books_response.Bids.First().OrderId.ShouldBeNull();
product_order_books_response.Asks.First().Price.ShouldEqual(200M);
product_order_books_response.Asks.First().Size.ShouldEqual(100M);
product_order_books_response.Asks.First().NumberOfOrders.ShouldEqual(3);
product_order_books_response.Asks.First().OrderId.ShouldBeNull();
};
}

class when_getting_a_product_order_book_with_level_3_specified
{
Establish context = () =>
{
The<IHttpRequestMessageService>().WhenToldTo(p => p.CreateHttpRequestMessage(Param.IsAny<HttpMethod>(), Param.IsAny<Authenticator>(), Param.IsAny<string>(), Param.IsAny<string>()))
.Return(new HttpRequestMessage());

The<IHttpClient>().WhenToldTo(p => p.SendASync(Param.IsAny<HttpRequestMessage>()))
.Return(Task.FromResult(new HttpResponseMessage()));

The<IHttpClient>().WhenToldTo(p => p.ReadAsStringAsync(Param.IsAny<HttpResponseMessage>()))
.Return(Task.FromResult(ProductsOrderBookResponseFixture.CreateWithLevelThree()));
};

Because of = () =>
product_order_books_response = Subject.GetProductOrderBookAsync(ProductType.BtcUsd, ProductLevel.Three).Result;

It should_have_correct_product_order_book_response = () =>
{
product_order_books_response.Sequence.ShouldEqual(3M);
product_order_books_response.Bids.First().Price.ShouldEqual(200M);
product_order_books_response.Bids.First().Size.ShouldEqual(100M);
product_order_books_response.Bids.First().NumberOfOrders.ShouldBeNull();
product_order_books_response.Bids.First().OrderId.ShouldEqual(new Guid("3b0f1225-7f84-490b-a29f-0faef9de823a"));
product_order_books_response.Asks.First().Price.ShouldEqual(200M);
product_order_books_response.Asks.First().Size.ShouldEqual(100M);
product_order_books_response.Asks.First().NumberOfOrders.ShouldBeNull();
product_order_books_response.Asks.First().OrderId.ShouldEqual(new Guid("da863862-25f4-4868-ac41-005d11ab0a5f"));
};
}

Expand Down
5 changes: 5 additions & 0 deletions GDAXClient/GDAXClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,15 @@
<Compile Include="Services\Fundings\FundingsService.cs" />
<Compile Include="Services\Fundings\FundingStatus.cs" />
<Compile Include="Services\Fundings\Models\Funding.cs" />
<Compile Include="Services\Products\Models\Ask.cs" />
<Compile Include="Services\Products\Models\Bid.cs" />
<Compile Include="Services\Products\Models\Product.cs" />
<Compile Include="Services\Products\Models\ProductLevel.cs" />
<Compile Include="Services\Products\Models\ProductStats.cs" />
<Compile Include="Services\Products\Models\ProductTicker.cs" />
<Compile Include="Services\Products\Models\Quote.cs" />
<Compile Include="Services\Products\Models\Responses\ProductsOrderBookResponse.cs" />
<Compile Include="Services\Products\Models\Responses\ProductsOrderBookJsonResponse.cs" />
<Compile Include="Services\Products\ProductsService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\AbstractService.cs" />
Expand Down
12 changes: 12 additions & 0 deletions GDAXClient/Services/Products/Models/Ask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace GDAXClient.Services.Products.Models
{
public class Ask : Quote
{
public Ask(
decimal price,
decimal size)
: base(price, size)
{
}
}
}
12 changes: 12 additions & 0 deletions GDAXClient/Services/Products/Models/Bid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace GDAXClient.Services.Products.Models
{
public class Bid : Quote
{
public Bid(
decimal price,
decimal size)
: base(price, size)
{
}
}
}
9 changes: 9 additions & 0 deletions GDAXClient/Services/Products/Models/ProductLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace GDAXClient.Services.Products.Models
{
public enum ProductLevel
{
One = 1,
Two = 2,
Three = 3
}
}
23 changes: 23 additions & 0 deletions GDAXClient/Services/Products/Models/Quote.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

namespace GDAXClient.Services.Products.Models
{
public class Quote
{
public Quote(
decimal price,
decimal size)
{
Price = price;
Size = size;
}

public decimal Price { get; }

public decimal Size { get; }

public decimal? NumberOfOrders { get; set; }

public Guid? OrderId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;

namespace GDAXClient.Services.Products.Models.Responses
{
public class ProductsOrderBookJsonResponse
{
public decimal Sequence { get; set; }

public IEnumerable<IEnumerable<string>> Bids { get; set; }

public IEnumerable<IEnumerable<string>> Asks { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ namespace GDAXClient.Services.Products.Models.Responses
{
public class ProductsOrderBookResponse
{
public decimal Sequence { get; set; }
public ProductsOrderBookResponse(
decimal sequence,
IEnumerable<Bid> bids,
IEnumerable<Ask> asks)
{
Sequence = sequence;
Bids = bids;
Asks = asks;
}

public IEnumerable<IEnumerable<decimal>> Bids { get; set; }
public decimal Sequence { get; }

public IEnumerable<IEnumerable<decimal>> Asks { get; set; }
public IEnumerable<Bid> Bids { get; }

public IEnumerable<Ask> Asks { get; }
}
}
39 changes: 35 additions & 4 deletions GDAXClient/Services/Products/ProductsService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using GDAXClient.Authentication;
Expand Down Expand Up @@ -43,11 +44,13 @@ public async Task<IEnumerable<Product>> GetAllProductsAsync()
return productsResponse;
}

public async Task<ProductsOrderBookResponse> GetProductOrderBookAsync(ProductType productPair)
public async Task<ProductsOrderBookResponse> GetProductOrderBookAsync(ProductType productPair, ProductLevel productLevel = ProductLevel.One)
{
var httpResponseMessage = await SendHttpRequestMessageAsync(HttpMethod.Get, authenticator, $"/products/{productPair.ToDasherizedUpper()}/book");
var httpResponseMessage = await SendHttpRequestMessageAsync(HttpMethod.Get, authenticator, $"/products/{productPair.ToDasherizedUpper()}/book/?level={(int)productLevel}");
var contentBody = await httpClient.ReadAsStringAsync(httpResponseMessage).ConfigureAwait(false);
var productOrderBookResponse = JsonConvert.DeserializeObject<ProductsOrderBookResponse>(contentBody);
var productsOrderBookJsonResponse = JsonConvert.DeserializeObject<ProductsOrderBookJsonResponse>(contentBody);

var productOrderBookResponse = ConvertProductOrderBookResponse(productsOrderBookJsonResponse, productLevel);

return productOrderBookResponse;
}
Expand All @@ -69,7 +72,7 @@ public async Task<ProductStats> GetProductStatsAsync(ProductType productPair)

return productStatsResponse;
}

public async Task<IEnumerable<object[]>> GetHistoricRatesAsync(ProductType productPair, DateTime start, DateTime end, int granularity)
{
var isoStart = start.ToString("s");
Expand All @@ -86,5 +89,33 @@ public async Task<IEnumerable<object[]>> GetHistoricRatesAsync(ProductType produ

return productHistoryResponse;
}

private ProductsOrderBookResponse ConvertProductOrderBookResponse(
ProductsOrderBookJsonResponse productsOrderBookJsonResponse,
ProductLevel productLevel)
{
var askList = productsOrderBookJsonResponse.Asks.Select(product => product.ToArray()).Select(askArray => new Ask(Convert.ToDecimal(askArray[0]), Convert.ToDecimal(askArray[1]))
{
OrderId = productLevel == ProductLevel.Three
? new Guid(askArray[2])
: (Guid?)null,
NumberOfOrders = productLevel == ProductLevel.Three
? (decimal?)null
: Convert.ToDecimal(askArray[2])
}).ToArray();

var bidList = productsOrderBookJsonResponse.Bids.Select(product => product.ToArray()).Select(bidArray => new Bid(Convert.ToDecimal(bidArray[0]), Convert.ToDecimal(bidArray[1]))
{
OrderId = productLevel == ProductLevel.Three
? new Guid(bidArray[2])
: (Guid?)null,
NumberOfOrders = productLevel == ProductLevel.Three
? (decimal?)null
: Convert.ToDecimal(bidArray[2])
});

var productOrderBookResponse = new ProductsOrderBookResponse(productsOrderBookJsonResponse.Sequence, bidList, askList);
return productOrderBookResponse;
}
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var allAccounts = await gdaxClient.AccountsService.GetAllAccountsAsync();

###### Products ######
- GetAllProductsAsync() - get a list of available currency pairs for trading
- GetProductOrderBookAsync(productType) - get a list of open orders for a product
- GetProductOrderBookAsync(productType, productLevel) - get a list of open orders for a product (specify level 1, 2, or 3)
- GetProductTickerAsync(productType) - get information about the last trade (tick), best bid/ask and 24h volume
- GetProductStatsAsync(productType) - get 24 hour stats for a product
- GetHistoricRatesAsync(productPair, start, end, granularity) - get historic rates for a product
Expand Down

0 comments on commit ab55f41

Please sign in to comment.