diff --git a/Alpaca.Markets.Extensions/Alpaca.Markets.Extensions.csproj b/Alpaca.Markets.Extensions/Alpaca.Markets.Extensions.csproj index a5215c7d1..18764cd02 100644 --- a/Alpaca.Markets.Extensions/Alpaca.Markets.Extensions.csproj +++ b/Alpaca.Markets.Extensions/Alpaca.Markets.Extensions.csproj @@ -12,9 +12,9 @@ - 8.0.0.0 - 8.0.0.0 - 8.0.0-alpha1 + 8.0.0.1 + 8.0.0.1 + 8.0.0-beta1 diff --git a/Alpaca.Markets.Tests/OrderTypeTest.cs b/Alpaca.Markets.Tests/OrderTypeTest.cs index 2930b1b9e..2e60dca98 100644 --- a/Alpaca.Markets.Tests/OrderTypeTest.cs +++ b/Alpaca.Markets.Tests/OrderTypeTest.cs @@ -125,6 +125,48 @@ public void BracketOrderCreationWorks() .StopLoss(stopLossStopPrice, stopLossLimitPrice)); } + [Fact] + public void MultiLegOrderCreationWorks() + { + const Decimal limitPrice = 100M; + const Decimal ratioQuantity = 0.25M; + + var lfi = getOrderLegCreationInfo() + .Select(info => info.Intent.Leg(Stock, ratioQuantity, info.Side)) + .ToList(); + var lfs = getOrderLegCreationInfo() + .Select(info => info.Side.Leg(Stock, ratioQuantity, info.Intent)) + .ToList(); + + assertOrdersAreEqual( + MultiLegOrder.Market(Quantity, lfi[0], lfi[1]), + MultiLegOrder.Market(Quantity, lfs[0], lfs[1])); + assertOrdersAreEqual( + MultiLegOrder.Market(Quantity, lfi[0], lfi[1], lfi[2]), + MultiLegOrder.Market(Quantity, lfs[0], lfs[1], lfs[2])); + assertOrdersAreEqual( + MultiLegOrder.Market(Quantity, lfi[0], lfi[1], lfi[2], lfi[3]), + MultiLegOrder.Market(Quantity, lfs[0], lfs[1], lfs[2], lfs[3])); + + assertOrdersAreEqual( + MultiLegOrder.Limit(Quantity, limitPrice, lfi[0], lfi[1]), + MultiLegOrder.Limit(Quantity, limitPrice, lfs[0], lfs[1])); + assertOrdersAreEqual( + MultiLegOrder.Limit(Quantity, limitPrice, lfi[0], lfi[1], lfi[2]), + MultiLegOrder.Limit(Quantity, limitPrice, lfs[0], lfs[1], lfs[2])); + assertOrdersAreEqual( + MultiLegOrder.Limit(Quantity, limitPrice, lfi[0], lfi[1], lfi[2], lfi[3]), + MultiLegOrder.Limit(Quantity, limitPrice, lfs[0], lfs[1], lfs[2], lfs[3])); + } + + private static IEnumerable<(PositionIntent Intent, OrderSide Side)> getOrderLegCreationInfo() + { + yield return (PositionIntent.BuyToClose, OrderSide.Buy); + yield return (PositionIntent.SellToClose, OrderSide.Sell); + yield return (PositionIntent.BuyToOpen, OrderSide.Buy); + yield return (PositionIntent.SellToOpen, OrderSide.Sell); + } + private static void assertOrdersAreEqual( OrderBase lhs, OrderBase rhs) @@ -227,6 +269,14 @@ private static void assertOrderBasePropertiesAreEqual( Assert.Equal(lhs.Type, rhs.Type); } + private static void assertOrdersAreEqual( + MultiLegOrder lhs, + MultiLegOrder rhs) + { + assertOrderBasePropertiesAreEqual(lhs, rhs); + assertJsonSerializedOrdersAreEqual(lhs, rhs); + } + private static void assertJsonSerializedOrdersAreEqual( OrderBase lhs, OrderBase rhs) => diff --git a/Alpaca.Markets/Alpaca.Markets.csproj b/Alpaca.Markets/Alpaca.Markets.csproj index 00318cb94..a3caf6ad6 100644 --- a/Alpaca.Markets/Alpaca.Markets.csproj +++ b/Alpaca.Markets/Alpaca.Markets.csproj @@ -12,14 +12,15 @@ - 8.0.0.0 - 8.0.0.0 - 8.0.0-alpha1 + 8.0.0.1 + 8.0.0.1 + 8.0.0-beta1 - Obsolete members cleanup - remove fully obsolete and convert warnings into errors. +- Initial support for the options multi-legs orders were added in experimental mode. C# SDK for Alpaca Trade API https://docs.alpaca.markets/ https://github.com/alpacahq/alpaca-trade-api-csharp diff --git a/Alpaca.Markets/CompatibilitySuppressions.xml b/Alpaca.Markets/CompatibilitySuppressions.xml index f140f4eb7..abb81a07f 100644 --- a/Alpaca.Markets/CompatibilitySuppressions.xml +++ b/Alpaca.Markets/CompatibilitySuppressions.xml @@ -554,6 +554,27 @@ lib/net462/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetClass + lib/net462/Alpaca.Markets.dll + lib/net462/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetId + lib/net462/Alpaca.Markets.dll + lib/net462/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_OrderSide + lib/net462/Alpaca.Markets.dll + lib/net462/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.LatestDataListRequest.#ctor(System.Collections.Generic.IEnumerable{System.String},Alpaca.Markets.CryptoExchange) @@ -568,6 +589,13 @@ lib/net462/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.NewOrderRequest.get_Side + lib/net462/Alpaca.Markets.dll + lib/net462/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.PortfolioHistoryRequest.get_TimeInterval @@ -848,6 +876,27 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetClass + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetId + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_OrderSide + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.LatestDataListRequest.#ctor(System.Collections.Generic.IEnumerable{System.String},Alpaca.Markets.CryptoExchange) @@ -862,6 +911,13 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.NewOrderRequest.get_Side + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.PortfolioHistoryRequest.get_TimeInterval @@ -1142,6 +1198,27 @@ lib/netstandard2.0/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetClass + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetId + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_OrderSide + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.LatestDataListRequest.#ctor(System.Collections.Generic.IEnumerable{System.String},Alpaca.Markets.CryptoExchange) @@ -1156,6 +1233,13 @@ lib/netstandard2.0/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.NewOrderRequest.get_Side + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.PortfolioHistoryRequest.get_TimeInterval @@ -1436,6 +1520,27 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetClass + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_AssetId + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0002 + M:Alpaca.Markets.IOrder.get_OrderSide + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.LatestDataListRequest.#ctor(System.Collections.Generic.IEnumerable{System.String},Alpaca.Markets.CryptoExchange) @@ -1450,6 +1555,13 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0002 + M:Alpaca.Markets.NewOrderRequest.get_Side + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0002 M:Alpaca.Markets.PortfolioHistoryRequest.get_TimeInterval @@ -1457,6 +1569,69 @@ lib/netstandard2.1/Alpaca.Markets.dll true + + CP0006 + P:Alpaca.Markets.IOrder.AssetClass + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.AssetId + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.OrderSide + lib/net6.0/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.AssetClass + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.AssetId + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.OrderSide + lib/netstandard2.0/Alpaca.Markets.dll + lib/netstandard2.0/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.AssetClass + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.AssetId + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + + + CP0006 + P:Alpaca.Markets.IOrder.OrderSide + lib/netstandard2.1/Alpaca.Markets.dll + lib/netstandard2.1/Alpaca.Markets.dll + true + CP0008 T:Alpaca.Markets.AccountActivityType diff --git a/Alpaca.Markets/Enums/OrderClass.cs b/Alpaca.Markets/Enums/OrderClass.cs index a4ead0ec7..76eee591a 100644 --- a/Alpaca.Markets/Enums/OrderClass.cs +++ b/Alpaca.Markets/Enums/OrderClass.cs @@ -4,6 +4,7 @@ namespace Alpaca.Markets; /// Order class for advanced orders in the Alpaca REST API. /// [JsonConverter(typeof(StringEnumConverter))] +[SuppressMessage("ReSharper", "StringLiteralTypo")] public enum OrderClass { /// @@ -29,5 +30,11 @@ public enum OrderClass /// One Triggers Other order /// [EnumMember(Value = "oto")] - OneTriggersOther + OneTriggersOther, + + /// + /// Multi-leg options order + /// + [EnumMember(Value = "mleg")] + MultiLegOptions } diff --git a/Alpaca.Markets/Helpers/JsonNewOrderExtensions.cs b/Alpaca.Markets/Helpers/JsonNewOrderExtensions.cs index fe40a4f14..4ed3d8f1c 100644 --- a/Alpaca.Markets/Helpers/JsonNewOrderExtensions.cs +++ b/Alpaca.Markets/Helpers/JsonNewOrderExtensions.cs @@ -9,6 +9,20 @@ public static JsonNewOrder WithoutLimitPrice( return order; } + public static JsonNewOrder WithoutOrderSide( + this JsonNewOrder order) + { + order.OrderSide = null; + return order; + } + + public static JsonNewOrder WithoutSymbol( + this JsonNewOrder order) + { + order.Symbol = null; + return order; + } + public static JsonNewOrder WithStopPrice( this JsonNewOrder order, Decimal stopPrice) @@ -70,4 +84,12 @@ public static JsonNewOrder WithStopLoss( }; return order; } + + public static JsonNewOrder WithOrderLegs( + this JsonNewOrder order, + IEnumerable legs) + { + (order.Legs ??= []).AddRange(legs); + return order; + } } diff --git a/Alpaca.Markets/Helpers/Validation.cs b/Alpaca.Markets/Helpers/Validation.cs index a49f49576..7eb90176d 100644 --- a/Alpaca.Markets/Helpers/Validation.cs +++ b/Alpaca.Markets/Helpers/Validation.cs @@ -53,6 +53,10 @@ public static TRequest Validate( return request; } + public static IEnumerable GetExceptions( + this IEnumerable items) => + items.OfType().SelectMany(request => request.GetExceptions()); + public static RequestValidationException? TryValidateSymbolName( this String symbolName, [CallerArgumentExpression(nameof(symbolName))] String propertyName = "") => diff --git a/Alpaca.Markets/Interfaces/IOrder.cs b/Alpaca.Markets/Interfaces/IOrder.cs index 0c418f297..e6573de77 100644 --- a/Alpaca.Markets/Interfaces/IOrder.cs +++ b/Alpaca.Markets/Interfaces/IOrder.cs @@ -70,19 +70,19 @@ public interface IOrder /// Gets unique asset identifier. /// [UsedImplicitly] - Guid AssetId { get; } + Guid? AssetId { get; } /// /// Gets asset symbol. /// [UsedImplicitly] - String Symbol { get; } + String? Symbol { get; } /// /// Gets asset class. /// [UsedImplicitly] - AssetClass AssetClass { get; } + AssetClass? AssetClass { get; } /// /// Gets original notional order quantity (with the fractional part). @@ -128,7 +128,7 @@ public interface IOrder /// Gets order side (buy or sell). /// [UsedImplicitly] - OrderSide OrderSide { get; } + OrderSide? OrderSide { get; } /// /// Gets order duration. diff --git a/Alpaca.Markets/Messages/JsonNewOrder.cs b/Alpaca.Markets/Messages/JsonNewOrder.cs index 86d259f35..078b2060e 100644 --- a/Alpaca.Markets/Messages/JsonNewOrder.cs +++ b/Alpaca.Markets/Messages/JsonNewOrder.cs @@ -2,8 +2,8 @@ internal sealed class JsonNewOrder { - [JsonProperty(PropertyName = "symbol", Required = Required.Always)] - public String Symbol { get; set; } = String.Empty; + [JsonProperty(PropertyName = "symbol", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public String? Symbol { get; set; } [JsonProperty(PropertyName = "qty", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] public Decimal? Quantity { get; set; } @@ -11,8 +11,8 @@ internal sealed class JsonNewOrder [JsonProperty(PropertyName = "notional", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] public Decimal? Notional { get; set; } - [JsonProperty(PropertyName = "side", Required = Required.Always)] - public OrderSide OrderSide { get; set; } + [JsonProperty(PropertyName = "side", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public OrderSide? OrderSide { get; set; } [JsonProperty(PropertyName = "type", Required = Required.Always)] public OrderType OrderType { get; set; } @@ -49,4 +49,7 @@ internal sealed class JsonNewOrder [JsonProperty(PropertyName = "position_intent", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] public PositionIntent? PositionIntent { get; set; } + + [JsonProperty(PropertyName = "legs", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public List? Legs { get; set; } } diff --git a/Alpaca.Markets/Messages/JsonOrder.cs b/Alpaca.Markets/Messages/JsonOrder.cs index 1a7f27d3d..ed8841dcc 100644 --- a/Alpaca.Markets/Messages/JsonOrder.cs +++ b/Alpaca.Markets/Messages/JsonOrder.cs @@ -44,14 +44,14 @@ internal sealed class JsonOrder : IOrder [JsonConverter(typeof(AssumeUtcIsoDateTimeConverter))] public DateTime? ReplacedAtUtc { get; [ExcludeFromCodeCoverage] set; } - [JsonProperty(PropertyName = "asset_id", Required = Required.Always)] - public Guid AssetId { get; set; } + [JsonProperty(PropertyName = "asset_id", Required = Required.Default)] + public Guid? AssetId { get; set; } - [JsonProperty(PropertyName = "symbol", Required = Required.Always)] - public String Symbol { get; set; } = String.Empty; + [JsonProperty(PropertyName = "symbol", Required = Required.Default)] + public String? Symbol { get; set; } - [JsonProperty(PropertyName = "asset_class", Required = Required.Always)] - public AssetClass AssetClass { get; set; } + [JsonProperty(PropertyName = "asset_class", Required = Required.Default)] + public AssetClass? AssetClass { get; set; } [JsonProperty(PropertyName = "notional", Required = Required.Default)] public Decimal? Notional { get; [ExcludeFromCodeCoverage] set; } @@ -74,8 +74,8 @@ internal sealed class JsonOrder : IOrder [JsonProperty(PropertyName = "order_class", Required = Required.Always)] public OrderClass OrderClass { get; } - [JsonProperty(PropertyName = "side", Required = Required.Always)] - public OrderSide OrderSide { get; set; } + [JsonProperty(PropertyName = "side", Required = Required.Default)] + public OrderSide? OrderSide { get; set; } [JsonProperty(PropertyName = "time_in_force", Required = Required.Always)] public TimeInForce TimeInForce { get; set; } diff --git a/Alpaca.Markets/Messages/JsonOrderLeg.cs b/Alpaca.Markets/Messages/JsonOrderLeg.cs new file mode 100644 index 000000000..0ed9e72a0 --- /dev/null +++ b/Alpaca.Markets/Messages/JsonOrderLeg.cs @@ -0,0 +1,16 @@ +namespace Alpaca.Markets; + +internal sealed class JsonOrderLeg +{ + [JsonProperty(PropertyName = "symbol", Required = Required.Always)] + public String Symbol { get; set; } = String.Empty; + + [JsonProperty(PropertyName = "ratio_qty", Required = Required.Always)] + public Decimal RatioQuantity { get; set; } + + [JsonProperty(PropertyName = "side", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public OrderSide? OrderSide { get; set; } + + [JsonProperty(PropertyName = "position_intent", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public PositionIntent? PositionIntent { get; set; } +} diff --git a/Alpaca.Markets/Orders/LimitOrder.cs b/Alpaca.Markets/Orders/LimitOrder.cs index 1d5120ffc..6454bf49f 100644 --- a/Alpaca.Markets/Orders/LimitOrder.cs +++ b/Alpaca.Markets/Orders/LimitOrder.cs @@ -59,7 +59,7 @@ public static LimitOrder Sell( /// Creates a new instance of the order from the current order. /// /// Stop loss order stop price. - /// New advanced order representing pair of original order and stop loss order. + /// New advanced order representing a pair of original order and stop loss order. [UsedImplicitly] public OneCancelsOtherOrder OneCancelsOther( Decimal stopLossStopPrice) => @@ -70,7 +70,7 @@ public OneCancelsOtherOrder OneCancelsOther( /// /// Stop loss order stop price. /// Stop loss order limit price. - /// New advanced order representing pair of original order and stop loss order. + /// New advanced order representing a pair of original order and stop loss order. [UsedImplicitly] public OneCancelsOtherOrder OneCancelsOther( Decimal stopLossStopPrice, diff --git a/Alpaca.Markets/Orders/MultiLegOrder.cs b/Alpaca.Markets/Orders/MultiLegOrder.cs new file mode 100644 index 000000000..68a866613 --- /dev/null +++ b/Alpaca.Markets/Orders/MultiLegOrder.cs @@ -0,0 +1,131 @@ +namespace Alpaca.Markets; + +/// +/// TBD +/// +public sealed class MultiLegOrder : AdvancedOrderBase +{ + private readonly List _legs; + + private MultiLegOrder( + SimpleOrderBase baseOrder, + params IReadOnlyList legs) + : base(baseOrder, OrderClass.MultiLegOptions) + { + Duration = TimeInForce.Day; + _legs = [.. legs]; + } + + /// + /// Creates a new instance of the market order with two legs. + /// + /// Order quantity. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Market( + OrderQuantity quantity, + OrderLeg orderLeg1, + OrderLeg orderLeg2) => + createMarket(quantity, orderLeg1, orderLeg2); + + /// + /// Creates a new instance of the market order with three legs. + /// + /// Order quantity. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// Third leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Market( + OrderQuantity quantity, + OrderLeg orderLeg1, + OrderLeg orderLeg2, + OrderLeg orderLeg3) => + createMarket(quantity, orderLeg1, orderLeg2, orderLeg3); + + /// + /// Creates a new instance of the market order with four legs. + /// + /// Order quantity. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// Third leg of the multi-leg order. + /// Fourth leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Market( + OrderQuantity quantity, + OrderLeg orderLeg1, + OrderLeg orderLeg2, + OrderLeg orderLeg3, + OrderLeg orderLeg4) => + createMarket(quantity, orderLeg1, orderLeg2, orderLeg3, orderLeg4); + + /// + /// Creates a new instance of the limit order with two legs. + /// + /// Order quantity. + /// Order limit price. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Limit( + OrderQuantity quantity, + Decimal limitPrice, + OrderLeg orderLeg1, + OrderLeg orderLeg2) => + createLimit(quantity, limitPrice, orderLeg1, orderLeg2); + + /// + /// Creates a new instance of the limit order with three legs. + /// + /// Order quantity. + /// Order limit price. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// Third leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Limit( + OrderQuantity quantity, + Decimal limitPrice, + OrderLeg orderLeg1, + OrderLeg orderLeg2, + OrderLeg orderLeg3) => + createLimit(quantity, limitPrice, orderLeg1, orderLeg2, orderLeg3); + + /// + /// Creates a new instance of the limit order with four legs. + /// + /// Order quantity. + /// Order limit price. + /// First leg of the multi-leg order. + /// Second leg of the multi-leg order. + /// Third leg of the multi-leg order. + /// Fourth leg of the multi-leg order. + /// A new advanced options order with several legs. + public static MultiLegOrder Limit( + OrderQuantity quantity, + Decimal limitPrice, + OrderLeg orderLeg1, + OrderLeg orderLeg2, + OrderLeg orderLeg3, + OrderLeg orderLeg4) => + createLimit(quantity, limitPrice, orderLeg1, orderLeg2, orderLeg3, orderLeg4); + + private static MultiLegOrder createLimit( + OrderQuantity quantity, + Decimal limitPrice, + params IReadOnlyList legs) => + new(new LimitOrder(String.Empty, quantity, OrderSide.Buy, limitPrice), legs); + + private static MultiLegOrder createMarket( + OrderQuantity quantity, + params IReadOnlyList legs) => + new(new MarketOrder(String.Empty, quantity, OrderSide.Buy), legs); + + internal override JsonNewOrder GetJsonRequest() => + base.GetJsonRequest() + .WithOrderLegs(_legs.Select(leg => leg.GetJsonRequest())) + .WithoutOrderSide() + .WithoutSymbol(); +} \ No newline at end of file diff --git a/Alpaca.Markets/Orders/OrderLeg.cs b/Alpaca.Markets/Orders/OrderLeg.cs new file mode 100644 index 000000000..9f937aff1 --- /dev/null +++ b/Alpaca.Markets/Orders/OrderLeg.cs @@ -0,0 +1,105 @@ +namespace Alpaca.Markets; + +/// +/// Represents the single leg of the option multi-leg order. +/// +public sealed record OrderLeg +{ + /// + /// Creates a new instance of the object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order side (buy or sell). + /// + /// The argument is null. + /// + public OrderLeg( + String symbol, + Decimal ratioQuantity, + OrderSide side) + : this(symbol, ratioQuantity, side, null) + { + } + + /// + /// Creates a new instance of the object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order position intent. + /// + /// The argument is null. + /// + public OrderLeg( + String symbol, + Decimal ratioQuantity, + PositionIntent positionIntent) + : this(symbol, ratioQuantity, null, positionIntent) + { + } + + /// + /// Creates a new instance of the object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order side (buy or sell). + /// Order position intent. + /// + /// The argument is null. + /// + public OrderLeg( + String symbol, + Decimal ratioQuantity, + PositionIntent positionIntent, + OrderSide side) + : this(symbol, ratioQuantity, side, positionIntent) + { + } + + private OrderLeg( + String symbol, + Decimal ratioQuantity, + OrderSide? side, + PositionIntent? positionIntent) + { + Symbol = symbol.EnsureNotNull(); + RatioQuantity = ratioQuantity; + PositionIntent = positionIntent; + Side = side; + } + + /// + /// Gets the new order asset symbol. + /// + [UsedImplicitly] + public String Symbol { get; } + + /// + /// Gets the proportional quantity of this leg in relation to the overall multi-leg order quantity. + /// + [UsedImplicitly] + public Decimal RatioQuantity { get; } + + /// + /// Gets the new order side (buy or sell). + /// + [UsedImplicitly] + public OrderSide? Side { get; } + + /// + /// Gets the optional position intent for order placement. + /// + [UsedImplicitly] + public PositionIntent? PositionIntent { get; } + + internal JsonOrderLeg GetJsonRequest() => + new () + { + Symbol = Symbol, + OrderSide = Side, + RatioQuantity = RatioQuantity, + PositionIntent = PositionIntent + }; +} diff --git a/Alpaca.Markets/Orders/OrderSideExtensions.cs b/Alpaca.Markets/Orders/OrderSideExtensions.cs index 8d6d218ab..0782d55ab 100644 --- a/Alpaca.Markets/Orders/OrderSideExtensions.cs +++ b/Alpaca.Markets/Orders/OrderSideExtensions.cs @@ -99,4 +99,73 @@ public static TrailingStopOrder TrailingStop( OrderQuantity quantity, TrailOffset trailOffset) => new(symbol, quantity, orderSide, trailOffset); -} + + /// + /// Creates new leg for the options multi-leg order. + /// + /// Order side (buy or sell). + /// Order asset symbol. + /// Order quantity. + /// + /// The argument is null. + /// + /// The new object instance. + [UsedImplicitly] + public static OrderLeg Leg( + this OrderSide orderSide, + String symbol, + Decimal ratioQuantity) => + new (symbol, ratioQuantity, orderSide); + + /// + /// Creates new leg for the options multi-leg order. + /// + /// Order side (buy or sell). + /// Order asset symbol. + /// Order quantity. + /// Order position intent. + /// + /// The argument is null. + /// + /// The new object instance. + public static OrderLeg Leg( + this OrderSide orderSide, + String symbol, + Decimal ratioQuantity, + PositionIntent positionIntent) => + new (symbol, ratioQuantity, positionIntent, orderSide); + + /// + /// Creates new leg for the options multi-leg order. + /// + /// Order position intent. + /// Order asset symbol. + /// Order quantity. + /// + /// The argument is null. + /// + /// The new object instance. + [UsedImplicitly] + public static OrderLeg Leg( + this PositionIntent positionIntent, + String symbol, + Decimal ratioQuantity) => + new (symbol, ratioQuantity, positionIntent); + + /// + /// Creates new leg for the options multi-leg order. + /// + /// Order position intent. + /// Order asset symbol. + /// Order quantity. + /// Order side (buy or sell). + /// + /// The argument is null. + /// + /// The new object instance. + public static OrderLeg Leg( + this PositionIntent positionIntent, + String symbol, + Decimal ratioQuantity, + OrderSide orderSide) => + new (symbol, ratioQuantity, positionIntent, orderSide);} diff --git a/Alpaca.Markets/Parameters/NewOrderRequest.cs b/Alpaca.Markets/Parameters/NewOrderRequest.cs index 0c6eb2372..6f8a38b80 100644 --- a/Alpaca.Markets/Parameters/NewOrderRequest.cs +++ b/Alpaca.Markets/Parameters/NewOrderRequest.cs @@ -6,6 +6,8 @@ [UsedImplicitly] public sealed class NewOrderRequest : Validation.IRequest { + private readonly List _legs = []; + /// /// Creates new instance of object. /// @@ -26,16 +28,32 @@ public NewOrderRequest( { Symbol = symbol.EnsureNotNull(); Quantity = quantity; + Duration = duration; Side = side; Type = type; + } + + /// + /// Creates new instance of object. + /// + /// Order quantity. + /// Order duration. + /// Order type. + public NewOrderRequest( + OrderQuantity quantity, + OrderType type, + TimeInForce duration) + { + Quantity = quantity; Duration = duration; + Type = type; } /// /// Gets the new order asset symbol. /// [UsedImplicitly] - public String Symbol { get; } + public String? Symbol { get; } /// /// Gets the new order quantity. @@ -47,7 +65,7 @@ public NewOrderRequest( /// Gets the new order side (buy or sell). /// [UsedImplicitly] - public OrderSide Side { get; } + public OrderSide? Side { get; } /// /// Gets the new order type. @@ -127,12 +145,37 @@ public NewOrderRequest( [UsedImplicitly] public PositionIntent? PositionIntent { get; set; } + /// + /// Gets the list of order legs for option multi-legs order. + /// + [UsedImplicitly] + public IReadOnlyList Legs => _legs; + + /// + /// Adds the option multi-leg into the collection. + /// + /// The option multi-leg order leg information. + /// Original order request object with new leg. + [UsedImplicitly] + public NewOrderRequest With( + OptionLegRequest leg) + { + _legs.Add(leg); + return this; + } + IEnumerable Validation.IRequest.GetExceptions() { ClientOrderId = ClientOrderId?.TrimClientOrderId(); - yield return Symbol.TryValidateSymbolName(); + yield return Symbol?.TryValidateSymbolName(); yield return Quantity.TryValidateQuantity(); + + foreach (var exception in Legs.GetExceptions()) + { + yield return exception; + } } + internal JsonNewOrder GetJsonRequest() => new() { @@ -163,6 +206,9 @@ StopLossLimitPrice is not null StopPrice = StopLossStopPrice, LimitPrice = StopLossLimitPrice } + : null, + Legs = Legs.Count != 0 + ? Legs.Select(leg => leg.GetJsonRequest()).ToList() : null }; } diff --git a/Alpaca.Markets/Parameters/OptionLegRequest.cs b/Alpaca.Markets/Parameters/OptionLegRequest.cs new file mode 100644 index 000000000..b0b6738c1 --- /dev/null +++ b/Alpaca.Markets/Parameters/OptionLegRequest.cs @@ -0,0 +1,106 @@ +namespace Alpaca.Markets; + +/// +/// Encapsulates request parameters for call. +/// +[UsedImplicitly] +public sealed class OptionLegRequest : Validation.IRequest +{ + /// + /// Creates new instance of object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order side (buy or sell). + /// Order position intent. + /// + /// The argument is null. + /// + public OptionLegRequest( + String symbol, + Decimal ratioQuantity, + OrderSide side, + PositionIntent positionIntent) + { + Symbol = symbol.EnsureNotNull(); + PositionIntent = positionIntent; + RatioQuantity = ratioQuantity; + Side = side; + } + + /// + /// Creates new instance of object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order side (buy or sell). + /// + /// The argument is null. + /// + public OptionLegRequest( + String symbol, + Decimal ratioQuantity, + OrderSide side) + { + Symbol = symbol.EnsureNotNull(); + RatioQuantity = ratioQuantity; + Side = side; + } + + /// + /// Creates new instance of object. + /// + /// Order asset symbol. + /// Order quantity. + /// Order position intent. + /// + /// The argument is null. + /// + public OptionLegRequest( + String symbol, + Decimal ratioQuantity, + PositionIntent positionIntent) + { + Symbol = symbol.EnsureNotNull(); + PositionIntent = positionIntent; + RatioQuantity = ratioQuantity; + } + + /// + /// Gets the new order asset symbol. + /// + [UsedImplicitly] + public String Symbol { get; } + + /// + /// Gets the proportional quantity of this leg in relation to the overall multi-leg order quantity. + /// + [UsedImplicitly] + public Decimal RatioQuantity { get; } + + /// + /// Gets the new order side (buy or sell). + /// + [UsedImplicitly] + public OrderSide? Side { get; } + + /// + /// Gets the optional position intent for order placement. + /// + [UsedImplicitly] + public PositionIntent? PositionIntent { get; } + + IEnumerable Validation.IRequest.GetExceptions() + { + yield return Symbol.TryValidateSymbolName(); + } + + internal JsonOrderLeg GetJsonRequest() => + new() + { + Symbol = Symbol, + OrderSide = Side, + RatioQuantity = RatioQuantity, + PositionIntent = PositionIntent + }; +} diff --git a/Alpaca.Markets/PublicAPI.Shipped.txt b/Alpaca.Markets/PublicAPI.Shipped.txt index 96ad7adbd..8f5e3babc 100644 --- a/Alpaca.Markets/PublicAPI.Shipped.txt +++ b/Alpaca.Markets/PublicAPI.Shipped.txt @@ -753,8 +753,8 @@ Alpaca.Markets.IOptionSnapshot.Quote.get -> Alpaca.Markets.IQuote? Alpaca.Markets.IOptionSnapshot.Symbol.get -> string! Alpaca.Markets.IOptionSnapshot.Trade.get -> Alpaca.Markets.ITrade? Alpaca.Markets.IOrder -Alpaca.Markets.IOrder.AssetClass.get -> Alpaca.Markets.AssetClass -Alpaca.Markets.IOrder.AssetId.get -> System.Guid +Alpaca.Markets.IOrder.AssetClass.get -> Alpaca.Markets.AssetClass? +Alpaca.Markets.IOrder.AssetId.get -> System.Guid? Alpaca.Markets.IOrder.AverageFillPrice.get -> decimal? Alpaca.Markets.IOrder.CancelledAtUtc.get -> System.DateTime? Alpaca.Markets.IOrder.ClientOrderId.get -> string? @@ -770,7 +770,7 @@ Alpaca.Markets.IOrder.Legs.get -> System.Collections.Generic.IReadOnlyList decimal? Alpaca.Markets.IOrder.OrderClass.get -> Alpaca.Markets.OrderClass Alpaca.Markets.IOrder.OrderId.get -> System.Guid -Alpaca.Markets.IOrder.OrderSide.get -> Alpaca.Markets.OrderSide +Alpaca.Markets.IOrder.OrderSide.get -> Alpaca.Markets.OrderSide? Alpaca.Markets.IOrder.OrderStatus.get -> Alpaca.Markets.OrderStatus Alpaca.Markets.IOrder.OrderType.get -> Alpaca.Markets.OrderType Alpaca.Markets.IOrder.ReplacedAtUtc.get -> System.DateTime? @@ -780,7 +780,7 @@ Alpaca.Markets.IOrder.Quantity.get -> decimal? Alpaca.Markets.IOrder.Notional.get -> decimal? Alpaca.Markets.IOrder.StopPrice.get -> decimal? Alpaca.Markets.IOrder.SubmittedAtUtc.get -> System.DateTime? -Alpaca.Markets.IOrder.Symbol.get -> string! +Alpaca.Markets.IOrder.Symbol.get -> string? Alpaca.Markets.IOrder.TimeInForce.get -> Alpaca.Markets.TimeInForce Alpaca.Markets.IOrder.TrailOffsetInDollars.get -> decimal? Alpaca.Markets.IOrder.TrailOffsetInPercent.get -> decimal? @@ -1058,6 +1058,7 @@ Alpaca.Markets.MarketDataFeed.Iex = 0 -> Alpaca.Markets.MarketDataFeed Alpaca.Markets.MarketDataFeed.Otc = 2 -> Alpaca.Markets.MarketDataFeed Alpaca.Markets.MarketDataFeed.Sip = 1 -> Alpaca.Markets.MarketDataFeed Alpaca.Markets.MarketOrder +Alpaca.Markets.MultiLegOrder Alpaca.Markets.Multiplier Alpaca.Markets.Multiplier.Double = 2 -> Alpaca.Markets.Multiplier Alpaca.Markets.Multiplier.None = 0 -> Alpaca.Markets.Multiplier @@ -1069,22 +1070,24 @@ Alpaca.Markets.NewOrderRequest.ClientOrderId.set -> void Alpaca.Markets.NewOrderRequest.Duration.get -> Alpaca.Markets.TimeInForce Alpaca.Markets.NewOrderRequest.ExtendedHours.get -> bool? Alpaca.Markets.NewOrderRequest.ExtendedHours.set -> void +Alpaca.Markets.NewOrderRequest.Legs.get -> System.Collections.Generic.IReadOnlyList! Alpaca.Markets.NewOrderRequest.LimitPrice.get -> decimal? Alpaca.Markets.NewOrderRequest.LimitPrice.set -> void Alpaca.Markets.NewOrderRequest.NewOrderRequest(string! symbol, Alpaca.Markets.OrderQuantity quantity, Alpaca.Markets.OrderSide side, Alpaca.Markets.OrderType type, Alpaca.Markets.TimeInForce duration) -> void +Alpaca.Markets.NewOrderRequest.NewOrderRequest(Alpaca.Markets.OrderQuantity quantity, Alpaca.Markets.OrderType type, Alpaca.Markets.TimeInForce duration) -> void Alpaca.Markets.NewOrderRequest.OrderClass.get -> Alpaca.Markets.OrderClass? Alpaca.Markets.NewOrderRequest.OrderClass.set -> void Alpaca.Markets.NewOrderRequest.PositionIntent.get -> Alpaca.Markets.PositionIntent? Alpaca.Markets.NewOrderRequest.PositionIntent.set -> void Alpaca.Markets.NewOrderRequest.Quantity.get -> Alpaca.Markets.OrderQuantity -Alpaca.Markets.NewOrderRequest.Side.get -> Alpaca.Markets.OrderSide +Alpaca.Markets.NewOrderRequest.Side.get -> Alpaca.Markets.OrderSide? Alpaca.Markets.NewOrderRequest.StopLossLimitPrice.get -> decimal? Alpaca.Markets.NewOrderRequest.StopLossLimitPrice.set -> void Alpaca.Markets.NewOrderRequest.StopLossStopPrice.get -> decimal? Alpaca.Markets.NewOrderRequest.StopLossStopPrice.set -> void Alpaca.Markets.NewOrderRequest.StopPrice.get -> decimal? Alpaca.Markets.NewOrderRequest.StopPrice.set -> void -Alpaca.Markets.NewOrderRequest.Symbol.get -> string! +Alpaca.Markets.NewOrderRequest.Symbol.get -> string? Alpaca.Markets.NewOrderRequest.TakeProfitLimitPrice.get -> decimal? Alpaca.Markets.NewOrderRequest.TakeProfitLimitPrice.set -> void Alpaca.Markets.NewOrderRequest.TrailOffsetInDollars.get -> decimal? @@ -1092,6 +1095,7 @@ Alpaca.Markets.NewOrderRequest.TrailOffsetInDollars.set -> void Alpaca.Markets.NewOrderRequest.TrailOffsetInPercent.get -> decimal? Alpaca.Markets.NewOrderRequest.TrailOffsetInPercent.set -> void Alpaca.Markets.NewOrderRequest.Type.get -> Alpaca.Markets.OrderType +Alpaca.Markets.NewOrderRequest.With(Alpaca.Markets.OptionLegRequest! leg) -> Alpaca.Markets.NewOrderRequest! Alpaca.Markets.NewsArticlesRequest Alpaca.Markets.NewsArticlesRequest.ExcludeItemsWithoutContent.get -> bool? Alpaca.Markets.NewsArticlesRequest.ExcludeItemsWithoutContent.set -> void @@ -1166,6 +1170,14 @@ Alpaca.Markets.OptionContractsRequest.StrikePriceGreaterThanOrEqualTo.set -> voi Alpaca.Markets.OptionContractsRequest.StrikePriceLessThanOrEqualTo.get -> decimal? Alpaca.Markets.OptionContractsRequest.StrikePriceLessThanOrEqualTo.set -> void Alpaca.Markets.OptionContractsRequest.UnderlyingSymbols.get -> System.Collections.Generic.IReadOnlyCollection! +Alpaca.Markets.OptionLegRequest +Alpaca.Markets.OptionLegRequest.OptionLegRequest(string! symbol, decimal ratioQuantity, Alpaca.Markets.OrderSide side) -> void +Alpaca.Markets.OptionLegRequest.OptionLegRequest(string! symbol, decimal ratioQuantity, Alpaca.Markets.OrderSide side, Alpaca.Markets.PositionIntent positionIntent) -> void +Alpaca.Markets.OptionLegRequest.OptionLegRequest(string! symbol, decimal ratioQuantity, Alpaca.Markets.PositionIntent positionIntent) -> void +Alpaca.Markets.OptionLegRequest.PositionIntent.get -> Alpaca.Markets.PositionIntent? +Alpaca.Markets.OptionLegRequest.RatioQuantity.get -> decimal +Alpaca.Markets.OptionLegRequest.Side.get -> Alpaca.Markets.OrderSide? +Alpaca.Markets.OptionLegRequest.Symbol.get -> string! Alpaca.Markets.OptionsFeed Alpaca.Markets.OptionsFeed.Indicative = 1 -> Alpaca.Markets.OptionsFeed Alpaca.Markets.OptionsFeed.Opra = 0 -> Alpaca.Markets.OptionsFeed @@ -1203,10 +1215,19 @@ Alpaca.Markets.OrderBase.Type.get -> Alpaca.Markets.OrderType Alpaca.Markets.OrderBaseExtensions Alpaca.Markets.OrderClass Alpaca.Markets.OrderClass.Bracket = 1 -> Alpaca.Markets.OrderClass +Alpaca.Markets.OrderClass.MultiLegOptions = 4 -> Alpaca.Markets.OrderClass Alpaca.Markets.OrderClass.OneCancelsOther = 2 -> Alpaca.Markets.OrderClass Alpaca.Markets.OrderClass.OneTriggersOther = 3 -> Alpaca.Markets.OrderClass Alpaca.Markets.OrderClass.Simple = 0 -> Alpaca.Markets.OrderClass Alpaca.Markets.OrderExtensions +Alpaca.Markets.OrderLeg +Alpaca.Markets.OrderLeg.OrderLeg(string! symbol, decimal ratioQuantity, Alpaca.Markets.OrderSide side) -> void +Alpaca.Markets.OrderLeg.OrderLeg(string! symbol, decimal ratioQuantity, Alpaca.Markets.PositionIntent positionIntent) -> void +Alpaca.Markets.OrderLeg.OrderLeg(string! symbol, decimal ratioQuantity, Alpaca.Markets.PositionIntent positionIntent, Alpaca.Markets.OrderSide side) -> void +Alpaca.Markets.OrderLeg.PositionIntent.get -> Alpaca.Markets.PositionIntent? +Alpaca.Markets.OrderLeg.RatioQuantity.get -> decimal +Alpaca.Markets.OrderLeg.Side.get -> Alpaca.Markets.OrderSide? +Alpaca.Markets.OrderLeg.Symbol.get -> string! Alpaca.Markets.OrderSide Alpaca.Markets.OrderSide.Buy = 0 -> Alpaca.Markets.OrderSide Alpaca.Markets.OrderSide.Sell = 1 -> Alpaca.Markets.OrderSide @@ -1469,12 +1490,22 @@ static Alpaca.Markets.LimitOrder.Buy(string! symbol, Alpaca.Markets.OrderQuantit static Alpaca.Markets.LimitOrder.Sell(string! symbol, Alpaca.Markets.OrderQuantity quantity, decimal limitPrice) -> Alpaca.Markets.LimitOrder! static Alpaca.Markets.MarketOrder.Buy(string! symbol, Alpaca.Markets.OrderQuantity quantity) -> Alpaca.Markets.MarketOrder! static Alpaca.Markets.MarketOrder.Sell(string! symbol, Alpaca.Markets.OrderQuantity quantity) -> Alpaca.Markets.MarketOrder! +static Alpaca.Markets.MultiLegOrder.Limit(Alpaca.Markets.OrderQuantity quantity, decimal limitPrice, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2) -> Alpaca.Markets.MultiLegOrder! +static Alpaca.Markets.MultiLegOrder.Limit(Alpaca.Markets.OrderQuantity quantity, decimal limitPrice, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2, Alpaca.Markets.OrderLeg! orderLeg3) -> Alpaca.Markets.MultiLegOrder! +static Alpaca.Markets.MultiLegOrder.Limit(Alpaca.Markets.OrderQuantity quantity, decimal limitPrice, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2, Alpaca.Markets.OrderLeg! orderLeg3, Alpaca.Markets.OrderLeg! orderLeg4) -> Alpaca.Markets.MultiLegOrder! +static Alpaca.Markets.MultiLegOrder.Market(Alpaca.Markets.OrderQuantity quantity, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2) -> Alpaca.Markets.MultiLegOrder! +static Alpaca.Markets.MultiLegOrder.Market(Alpaca.Markets.OrderQuantity quantity, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2, Alpaca.Markets.OrderLeg! orderLeg3) -> Alpaca.Markets.MultiLegOrder! +static Alpaca.Markets.MultiLegOrder.Market(Alpaca.Markets.OrderQuantity quantity, Alpaca.Markets.OrderLeg! orderLeg1, Alpaca.Markets.OrderLeg! orderLeg2, Alpaca.Markets.OrderLeg! orderLeg3, Alpaca.Markets.OrderLeg! orderLeg4) -> Alpaca.Markets.MultiLegOrder! static Alpaca.Markets.OpenClose.implicit operator Alpaca.Markets.Interval(Alpaca.Markets.OpenClose openClose) -> Alpaca.Markets.Interval static Alpaca.Markets.OrderBaseExtensions.WithClientOrderId(this TOrder! order, string! clientOrderId) -> TOrder! static Alpaca.Markets.OrderBaseExtensions.WithDuration(this TOrder! order, Alpaca.Markets.TimeInForce duration) -> TOrder! static Alpaca.Markets.OrderBaseExtensions.WithExtendedHours(this TOrder! order, bool extendedHours) -> TOrder! static Alpaca.Markets.OrderBaseExtensions.WithPositionIntent(this TOrder! order, Alpaca.Markets.PositionIntent positionIntent) -> TOrder! static Alpaca.Markets.OrderExtensions.GetOrderQuantity(this Alpaca.Markets.IOrder! order) -> Alpaca.Markets.OrderQuantity +static Alpaca.Markets.OrderSideExtensions.Leg(this Alpaca.Markets.OrderSide orderSide, string! symbol, decimal ratioQuantity) -> Alpaca.Markets.OrderLeg! +static Alpaca.Markets.OrderSideExtensions.Leg(this Alpaca.Markets.OrderSide orderSide, string! symbol, decimal ratioQuantity, Alpaca.Markets.PositionIntent positionIntent) -> Alpaca.Markets.OrderLeg! +static Alpaca.Markets.OrderSideExtensions.Leg(this Alpaca.Markets.PositionIntent positionIntent, string! symbol, decimal ratioQuantity) -> Alpaca.Markets.OrderLeg! +static Alpaca.Markets.OrderSideExtensions.Leg(this Alpaca.Markets.PositionIntent positionIntent, string! symbol, decimal ratioQuantity, Alpaca.Markets.OrderSide orderSide) -> Alpaca.Markets.OrderLeg! static Alpaca.Markets.OrderSideExtensions.Limit(this Alpaca.Markets.OrderSide orderSide, string! symbol, Alpaca.Markets.OrderQuantity quantity, decimal limitPrice) -> Alpaca.Markets.LimitOrder! static Alpaca.Markets.OrderSideExtensions.Market(this Alpaca.Markets.OrderSide orderSide, string! symbol, Alpaca.Markets.OrderQuantity quantity) -> Alpaca.Markets.MarketOrder! static Alpaca.Markets.OrderSideExtensions.Stop(this Alpaca.Markets.OrderSide orderSide, string! symbol, Alpaca.Markets.OrderQuantity quantity, decimal stopPrice) -> Alpaca.Markets.StopOrder!