diff --git a/Alpaca.Markets.Tests/OrderTypeTest.cs b/Alpaca.Markets.Tests/OrderTypeTest.cs index 2930b1b9..42d66356 100644 --- a/Alpaca.Markets.Tests/OrderTypeTest.cs +++ b/Alpaca.Markets.Tests/OrderTypeTest.cs @@ -125,6 +125,41 @@ public void BracketOrderCreationWorks() .StopLoss(stopLossStopPrice, stopLossLimitPrice)); } + [Fact] + public void MultiLegOrderCreationWorks() + { + const Decimal limitPrice = 100M; + const Decimal ratioQuantity = 0.25M; + + var legs = getOrderLegs() + .Select(tuple => new OrderLeg(Stock, ratioQuantity, tuple.Item1, tuple.Item2)) + .ToList(); + + var marketOrder1 = MultiLegOrder.Market(Quantity, legs[0], legs[1]); + var marketOrder2 = MultiLegOrder.Market(Quantity, legs[0], legs[1], legs[2]); + var marketOrder3 = MultiLegOrder.Market(Quantity, legs[0], legs[1], legs[2], legs[3]); + + var limitOrder1 = MultiLegOrder.Limit(Quantity, limitPrice, legs[0], legs[1]); + var limitOrder2 = MultiLegOrder.Limit(Quantity, limitPrice, legs[0], legs[1], legs[2]); + var limitOrder3 = MultiLegOrder.Limit(Quantity, limitPrice, legs[0], legs[1], legs[2], legs[3]); + + assertOrdersAreEqual(marketOrder1, marketOrder1); + assertOrdersAreEqual(marketOrder2, marketOrder2); + assertOrdersAreEqual(marketOrder3, marketOrder3); + + assertOrdersAreEqual(limitOrder1, limitOrder1); + assertOrdersAreEqual(limitOrder2, limitOrder2); + assertOrdersAreEqual(limitOrder3, limitOrder3); + } + + private static IEnumerable<(PositionIntent, OrderSide)> getOrderLegs() + { + 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 +262,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/Messages/JsonNewOrder.cs b/Alpaca.Markets/Messages/JsonNewOrder.cs index 1d2256ed..078b2060 100644 --- a/Alpaca.Markets/Messages/JsonNewOrder.cs +++ b/Alpaca.Markets/Messages/JsonNewOrder.cs @@ -2,7 +2,7 @@ internal sealed class JsonNewOrder { - [JsonProperty(PropertyName = "symbol", Required = Required.Always)] + [JsonProperty(PropertyName = "symbol", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] public String? Symbol { get; set; } [JsonProperty(PropertyName = "qty", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] @@ -14,8 +14,8 @@ internal sealed class JsonNewOrder [JsonProperty(PropertyName = "side", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] public OrderSide? OrderSide { get; set; } - [JsonProperty(PropertyName = "type", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] - public OrderType? OrderType { get; set; } + [JsonProperty(PropertyName = "type", Required = Required.Always)] + public OrderType OrderType { get; set; } [JsonProperty(PropertyName = "time_in_force", Required = Required.Always)] public TimeInForce TimeInForce { get; set; } diff --git a/Alpaca.Markets/Parameters/NewOrderRequest.cs b/Alpaca.Markets/Parameters/NewOrderRequest.cs index 2d1e4542..6f8a38b8 100644 --- a/Alpaca.Markets/Parameters/NewOrderRequest.cs +++ b/Alpaca.Markets/Parameters/NewOrderRequest.cs @@ -156,6 +156,7 @@ public NewOrderRequest( /// /// The option multi-leg order leg information. /// Original order request object with new leg. + [UsedImplicitly] public NewOrderRequest With( OptionLegRequest leg) {