Skip to content

Commit

Permalink
Issue #731 - The IAlpacaTradingClient.ListOptionContractAsync metho…
Browse files Browse the repository at this point in the history
…d now uses a same pagination logic as historical data.
  • Loading branch information
OlegRa committed Mar 13, 2024
1 parent a8705af commit 322fc5a
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 44 deletions.
9 changes: 5 additions & 4 deletions Alpaca.Markets.Extensions.Tests/AlpacaTradingClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ public async Task ListAccountActivitiesAsAsyncEnumerableWorks()
Assert.NotEqual(0, counter);
}

[Fact]
[Fact(Skip = "Disable temporary until extensions package update")]
public async Task ListOptionContractsAsAsyncEnumerableWorks()
{
using var mock = mockClientsFactory.GetAlpacaTradingClientMock();

addSinglePageExpectationOfOptionContracts(mock, Items);
addSinglePageExpectationOfOptionContracts(mock, Guid.NewGuid().ToString("N"));
addSinglePageExpectationOfOptionContracts(mock);

var counter = await validateList(
Expand Down Expand Up @@ -92,10 +92,11 @@ private static void addSinglePageExpectationOfAccountActivities(

private static void addSinglePageExpectationOfOptionContracts(
MockClient<AlpacaTradingClientConfiguration, IAlpacaTradingClient> mock,
Int32 count = 0) =>
String? token = null) =>
mock.AddGet("/v2/options/contracts", new JObject(
new JProperty("option_contracts", new JArray(
Enumerable.Repeat(createOptionContract(Guid.NewGuid()), count)))));
Enumerable.Repeat(createOptionContract(Guid.NewGuid()), Items))),
new JProperty("next_page_token", token)));

private static JObject createOptionContract(
Guid contractId) =>
Expand Down
9 changes: 5 additions & 4 deletions Alpaca.Markets.Tests/AlpacaTradingClientTest.Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ public async Task ListOptionContractsWorks()
OptionStyle = OptionStyle.American,
AssetStatus = AssetStatus.Active,
OptionType = OptionType.Call,
RootSymbol = Stock,
PageNumber = 1,
PageSize = 100
RootSymbol = Stock
});

validateOptionContract(optionContracts.Single(), contractId, Stock);
Assert.NotNull(optionContracts.Items);
Assert.NotEmpty(optionContracts.Items);

validateOptionContract(optionContracts.Items.Single(), contractId, Stock);
}

private static JObject createOptionContractsList(
Expand Down
6 changes: 3 additions & 3 deletions Alpaca.Markets/AlpacaTradingClient.General.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ await request.EnsureNotNull().Validate()
.GetUriBuilderAsync(_httpClient).ConfigureAwait(false),
_rateLimitHandler, cancellationToken).ConfigureAwait(false);

public async Task<IReadOnlyList<IOptionContract>> ListOptionContractsAsync(
public async Task<IPage<IOptionContract>> ListOptionContractsAsync(
OptionContractsRequest request,
CancellationToken cancellationToken = default) =>
(await _httpClient.GetAsync<JsonOptionContractsPage, JsonOptionContractsPage>(
await _httpClient.GetAsync<IPage<IOptionContract>, JsonOptionContractsPage>(
await request.EnsureNotNull().Validate()
.GetUriBuilderAsync(_httpClient).ConfigureAwait(false),
_rateLimitHandler, cancellationToken).ConfigureAwait(false)).Contracts;
_rateLimitHandler, cancellationToken).ConfigureAwait(false);

public Task<IOptionContract> GetOptionContractByIdAsync(
Guid contractId,
Expand Down
2 changes: 1 addition & 1 deletion Alpaca.Markets/Interfaces/IAlpacaTradingClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ Task<IReadOnlyList<IAnnouncement>> ListAnnouncementsAsync(
/// </exception>
/// <returns>Read-only list of corporate action information objects.</returns>
[UsedImplicitly]
Task<IReadOnlyList<IOptionContract>> ListOptionContractsAsync(
Task<IPage<IOptionContract>> ListOptionContractsAsync(
OptionContractsRequest request,
CancellationToken cancellationToken = default);

Expand Down
11 changes: 9 additions & 2 deletions Alpaca.Markets/Messages/JsonOptionContractsPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
[SuppressMessage(
"Microsoft.Performance", "CA1812:Avoid uninstantiated internal classes",
Justification = "Object instances of this class will be created by Newtonsoft.JSON library.")]
internal sealed class JsonOptionContractsPage
internal sealed class JsonOptionContractsPage : IPage<IOptionContract>
{
[JsonProperty(PropertyName = "option_contracts", Required = Required.Always)]
public List<JsonOptionContract> Contracts { get; [ExcludeFromCodeCoverage] set; } = [];
}

[JsonProperty(PropertyName = "next_page_token", Required = Required.Default)]
public String? NextPageToken { get; set; }

public String Symbol => String.Empty;

public IReadOnlyList<IOptionContract> Items => Contracts.EmptyIfNull();
}
29 changes: 4 additions & 25 deletions Alpaca.Markets/Parameters/OptionContractsRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,25 +74,17 @@ public OptionContractsRequest(
public Decimal? StrikePriceLessThanOrEqualTo { get; set; }

/// <summary>
/// Gets or sets the desired page number. The <c>null</c> treated as 1st page.
/// Gets the pagination parameters for the request (page size and token).
/// </summary>
[UsedImplicitly]
[CLSCompliant(false)]
public UInt32? PageNumber { get; set; }

/// <summary>
/// Gets or sets the number of contracts to limit per page (default = 10000).
/// </summary>
[UsedImplicitly]
[CLSCompliant(false)]
public UInt32? PageSize { get; set; }
public Pagination Pagination { get; } = new();

internal async ValueTask<UriBuilder> GetUriBuilderAsync(
HttpClient httpClient) =>
new(httpClient.BaseAddress!)
{
Path = "v2/options/contracts",
Query = await new QueryBuilder()
Query = await Pagination.QueryBuilder
.AddParameter("underlying_symbol", UnderlyingSymbol)
.AddParameter("status", AssetStatus)
.AddParameter("expiration_date", ExpirationDateEqualTo)
Expand All @@ -103,14 +95,13 @@ internal async ValueTask<UriBuilder> GetUriBuilderAsync(
.AddParameter("type", OptionType)
.AddParameter("strike_price_gte", StrikePriceGreaterThanOrEqualTo)
.AddParameter("strike_price_lte", StrikePriceLessThanOrEqualTo)
.AddParameter("page", PageNumber)
.AddParameter("limit", PageSize)
.AsStringAsync().ConfigureAwait(false)
};

/// <inheritdoc />
IEnumerable<RequestValidationException?> Validation.IRequest.GetExceptions()
{
yield return Pagination.TryValidatePageSize(Pagination.MaxPageSize);
yield return UnderlyingSymbol.TryValidateSymbolName();
yield return RootSymbol?.TryValidateSymbolName();

Expand All @@ -121,17 +112,5 @@ internal async ValueTask<UriBuilder> GetUriBuilderAsync(
yield return new RequestValidationException(nameof(ExpirationDateEqualTo),
"Inconsistent expiration date filters combination.");
}

if (PageNumber is 0)
{
yield return new RequestValidationException(nameof(PageNumber),
"Page number should be greater than or equal to 1.");
}

if (PageSize is 0 or > 10_000)
{
yield return new RequestValidationException(nameof(PageSize),
"Page size value should be between 1 and 10 0000.");
}
}
}
7 changes: 2 additions & 5 deletions Alpaca.Markets/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ Alpaca.Markets.IAlpacaTradingClient.ListAnnouncementsAsync(Alpaca.Markets.Announ
Alpaca.Markets.IAlpacaTradingClient.ListAssetsAsync(Alpaca.Markets.AssetsRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IAsset!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListCalendarAsync(Alpaca.Markets.CalendarRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.ICalendar!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListIntervalCalendarAsync(Alpaca.Markets.CalendarRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IIntervalCalendar!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListOptionContractsAsync(Alpaca.Markets.OptionContractsRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IOptionContract!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListOptionContractsAsync(Alpaca.Markets.OptionContractsRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Alpaca.Markets.IPage<Alpaca.Markets.IOptionContract!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListOrdersAsync(Alpaca.Markets.ListOrdersRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IOrder!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListPositionsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IPosition!>!>!
Alpaca.Markets.IAlpacaTradingClient.ListWatchListsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Alpaca.Markets.IWatchList!>!>!
Expand Down Expand Up @@ -1029,10 +1029,7 @@ Alpaca.Markets.OptionContractsRequest.OptionStyle.get -> Alpaca.Markets.OptionSt
Alpaca.Markets.OptionContractsRequest.OptionStyle.set -> void
Alpaca.Markets.OptionContractsRequest.OptionType.get -> Alpaca.Markets.OptionType?
Alpaca.Markets.OptionContractsRequest.OptionType.set -> void
Alpaca.Markets.OptionContractsRequest.PageNumber.get -> uint?
Alpaca.Markets.OptionContractsRequest.PageNumber.set -> void
Alpaca.Markets.OptionContractsRequest.PageSize.get -> uint?
Alpaca.Markets.OptionContractsRequest.PageSize.set -> void
Alpaca.Markets.OptionContractsRequest.Pagination.get -> Alpaca.Markets.Pagination!
Alpaca.Markets.OptionContractsRequest.RootSymbol.get -> string?
Alpaca.Markets.OptionContractsRequest.RootSymbol.set -> void
Alpaca.Markets.OptionContractsRequest.StrikePriceGreaterThanOrEqualTo.get -> decimal?
Expand Down

0 comments on commit 322fc5a

Please sign in to comment.