From 3953026ae4250e03ab347ad90589bb850d954f41 Mon Sep 17 00:00:00 2001 From: Oleg Rakhmatulin Date: Fri, 5 Apr 2024 11:01:18 +0200 Subject: [PATCH] Issue #731 - The `IAlpacaTradingClient` interface was extended with two new `ExerciseOptionsContractBy...Async` methods. (cherry picked from commit 2ec1decbfe91e23d30d3f7b28006c1c45c51eac2) --- .../AlpacaTradingClientTest.Positions.cs | 20 +++++++++ Alpaca.Markets/AlpacaTradingClient.Orders.cs | 12 ++++++ Alpaca.Markets/CompatibilitySuppressions.xml | 42 ++++++++++++++++++ .../Helpers/HttpClientExtensions.Post.cs | 16 +++++++ .../Interfaces/IAlpacaTradingClient.cs | 43 +++++++++++++++++++ .../Parameters/OptionChainRequest.cs | 2 +- Alpaca.Markets/PublicAPI.Unshipped.txt | 2 + 7 files changed, 136 insertions(+), 1 deletion(-) diff --git a/Alpaca.Markets.Tests/AlpacaTradingClientTest.Positions.cs b/Alpaca.Markets.Tests/AlpacaTradingClientTest.Positions.cs index b7988a68..01d00539 100644 --- a/Alpaca.Markets.Tests/AlpacaTradingClientTest.Positions.cs +++ b/Alpaca.Markets.Tests/AlpacaTradingClientTest.Positions.cs @@ -93,6 +93,26 @@ public async Task DeleteAllPositionsWithOrdersAsyncWorks() Assert.NotEmpty(statuses); } + [Fact] + public async Task ExerciseOptionsPositionByIdAsyncWorks() + { + using var mock = mockClientsFactory.GetAlpacaTradingClientMock(); + + mock.AddPost("/v2/positions/*/exercise", new JObject()); + + Assert.True(await mock.Client.ExerciseOptionsPositionByIdAsync(Guid.NewGuid())); + } + + [Fact] + public async Task ExerciseOptionsPositionBySymbolAsyncWorks() + { + using var mock = mockClientsFactory.GetAlpacaTradingClientMock(); + + mock.AddPost("/v2/positions/*/exercise", new JObject()); + + Assert.True(await mock.Client.ExerciseOptionsPositionBySymbolAsync(Stock)); + } + [SuppressMessage("ReSharper", "StringLiteralTypo")] private static JObject createPosition() => new( diff --git a/Alpaca.Markets/AlpacaTradingClient.Orders.cs b/Alpaca.Markets/AlpacaTradingClient.Orders.cs index 441f5404..a5e1dc5e 100644 --- a/Alpaca.Markets/AlpacaTradingClient.Orders.cs +++ b/Alpaca.Markets/AlpacaTradingClient.Orders.cs @@ -62,4 +62,16 @@ public Task> CancelAllOrdersAsync( CancellationToken cancellationToken = default) => _httpClient.DeleteAsync, List>( "v2/orders", _rateLimitHandler, cancellationToken); + + public Task ExerciseOptionsPositionByIdAsync( + Guid contractId, + CancellationToken cancellationToken = default) => + _httpClient.TryPostAsync( + $"v2/positions/{contractId:D}/exercise", _rateLimitHandler, cancellationToken); + + public Task ExerciseOptionsPositionBySymbolAsync( + String symbol, + CancellationToken cancellationToken = default) => + _httpClient.TryPostAsync( + $"v2/positions/{symbol.EnsureNotNull()}/exercise", _rateLimitHandler, cancellationToken); } diff --git a/Alpaca.Markets/CompatibilitySuppressions.xml b/Alpaca.Markets/CompatibilitySuppressions.xml index ce16c569..8c521d14 100644 --- a/Alpaca.Markets/CompatibilitySuppressions.xml +++ b/Alpaca.Markets/CompatibilitySuppressions.xml @@ -1485,6 +1485,20 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionByIdAsync(System.Guid,System.Threading.CancellationToken) + lib/net6.0/Alpaca.Markets.dll + lib/net6.0/Alpaca.Markets.dll + true + + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionBySymbolAsync(System.String,System.Threading.CancellationToken) + lib/net6.0/Alpaca.Markets.dll + lib/net6.0/Alpaca.Markets.dll + true + CP0006 M:Alpaca.Markets.IAlpacaTradingClient.GetOptionContractByIdAsync(System.Guid,System.Threading.CancellationToken) @@ -1534,6 +1548,20 @@ lib/net6.0/Alpaca.Markets.dll true + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionByIdAsync(System.Guid,System.Threading.CancellationToken) + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionBySymbolAsync(System.String,System.Threading.CancellationToken) + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + CP0006 M:Alpaca.Markets.IAlpacaTradingClient.GetOptionContractByIdAsync(System.Guid,System.Threading.CancellationToken) @@ -1583,6 +1611,20 @@ lib/netstandard2.0/Alpaca.Markets.dll true + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionByIdAsync(System.Guid,System.Threading.CancellationToken) + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + M:Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionBySymbolAsync(System.String,System.Threading.CancellationToken) + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0006 M:Alpaca.Markets.IAlpacaTradingClient.GetOptionContractByIdAsync(System.Guid,System.Threading.CancellationToken) diff --git a/Alpaca.Markets/Helpers/HttpClientExtensions.Post.cs b/Alpaca.Markets/Helpers/HttpClientExtensions.Post.cs index e14e6f53..482a615e 100644 --- a/Alpaca.Markets/Helpers/HttpClientExtensions.Post.cs +++ b/Alpaca.Markets/Helpers/HttpClientExtensions.Post.cs @@ -2,6 +2,22 @@ internal static partial class HttpClientExtensions { + public static Task TryPostAsync( + this HttpClient httpClient, + UriBuilder uriBuilder, + RateLimitHandler rateLimitHandler, + CancellationToken cancellationToken) => + callAndReturnSuccessCodeAsync( + httpClient, HttpMethod.Post, uriBuilder.Uri, rateLimitHandler, cancellationToken); + + public static Task TryPostAsync( + this HttpClient httpClient, + String endpointUri, + RateLimitHandler rateLimitHandler, + CancellationToken cancellationToken) => + callAndReturnSuccessCodeAsync( + httpClient, HttpMethod.Post, asUri(endpointUri), rateLimitHandler, cancellationToken); + public static Task PostAsync( this HttpClient httpClient, String endpointUri, diff --git a/Alpaca.Markets/Interfaces/IAlpacaTradingClient.cs b/Alpaca.Markets/Interfaces/IAlpacaTradingClient.cs index 06d0f64d..c31d507d 100644 --- a/Alpaca.Markets/Interfaces/IAlpacaTradingClient.cs +++ b/Alpaca.Markets/Interfaces/IAlpacaTradingClient.cs @@ -976,4 +976,47 @@ Task GetOptionContractByIdAsync( Task GetOptionContractBySymbolAsync( String symbol, CancellationToken cancellationToken = default); + + /// + /// Exercises a held option contract, converting it into the underlying asset based on the specified terms. + /// + /// Option contract unique identifier. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation or timeout. + /// + /// + /// The initial TPC socket connection failed due to an underlying low-level network connectivity issue. + /// + /// + /// .NET Core and .NET 5 and later only: The request failed due to timeout. + /// + /// Returns true if operation completed successfully. + [UsedImplicitly] + Task ExerciseOptionsPositionByIdAsync( + Guid contractId, + CancellationToken cancellationToken = default); + + /// + /// Exercises a held option contract, converting it into the underlying asset based on the specified terms. + /// + /// Option contract unique symbol name. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation or timeout. + /// + /// + /// The initial TPC socket connection failed due to an underlying low-level network connectivity issue. + /// + /// + /// .NET Core and .NET 5 and later only: The request failed due to timeout. + /// + /// + /// The argument is null. + /// + /// Returns true if operation completed successfully. + [UsedImplicitly] + Task ExerciseOptionsPositionBySymbolAsync( + String symbol, + CancellationToken cancellationToken = default); } diff --git a/Alpaca.Markets/Parameters/OptionChainRequest.cs b/Alpaca.Markets/Parameters/OptionChainRequest.cs index eda4ac52..eefbc308 100644 --- a/Alpaca.Markets/Parameters/OptionChainRequest.cs +++ b/Alpaca.Markets/Parameters/OptionChainRequest.cs @@ -6,7 +6,7 @@ public sealed class OptionChainRequest : Validation.IRequest { /// - /// Creates new instance of object. + /// Creates new instance of object. /// /// Option underlying symbol for data retrieval. /// diff --git a/Alpaca.Markets/PublicAPI.Unshipped.txt b/Alpaca.Markets/PublicAPI.Unshipped.txt index 314f8f91..487fdb67 100644 --- a/Alpaca.Markets/PublicAPI.Unshipped.txt +++ b/Alpaca.Markets/PublicAPI.Unshipped.txt @@ -1,4 +1,6 @@ #nullable enable +Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionByIdAsync(System.Guid contractId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Alpaca.Markets.IAlpacaTradingClient.ExerciseOptionsPositionBySymbolAsync(string! symbol, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! Alpaca.Markets.LatestOptionsDataRequest Alpaca.Markets.LatestOptionsDataRequest.LatestOptionsDataRequest(System.Collections.Generic.IEnumerable! symbols) -> void Alpaca.Markets.LatestOptionsDataRequest.OptionsFeed.get -> Alpaca.Markets.OptionsFeed?