public void Check_Account_Calculations_Correct() { var position1 = TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 1000, 1.02M); _ordersCache.Positions.Add(position1); position1.UpdateClosePrice(1.04M); position1.GetFpl(); var account = _accountsCacheService.Get(position1.AccountId); Assert.IsNotNull(account); Assert.AreEqual(1000, account.Balance); Assert.AreEqual(20, Math.Round(account.GetPnl(), 5)); Assert.AreEqual(1020, account.GetTotalCapital()); Assert.AreEqual(6.8M, account.GetUsedMargin()); Assert.AreEqual(1009.8M, account.GetMarginAvailable()); Assert.AreEqual(150M, account.GetMarginUsageLevel()); var position2 = TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, -30000, 1.02M); _ordersCache.Positions.Add(position2); position2.UpdateClosePrice(1.04M); position2.GetFpl(); Assert.IsNotNull(account); Assert.AreEqual(1000, account.Balance); Assert.AreEqual(-580, Math.Round(account.GetPnl(), 5)); Assert.AreEqual(420, Math.Round(account.GetTotalCapital(), 5)); Assert.AreEqual(214.8m, account.GetUsedMargin()); Assert.AreEqual(97.8m, Math.Round(account.GetMarginAvailable(), 5)); Assert.AreEqual(1.95531m, Math.Round(account.GetMarginUsageLevel(), 5)); }
public void Check_Position_PnL() { _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.25M, Bid = 1.15M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "CHFJPY", Ask = 6.036M, Bid = 1.9M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 9000M, Bid = 9000M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURJPY", Ask = 0.83M, Bid = 0.83M }); var position1 = TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[1], MarginTradingTestsUtils.TradingConditionId, 15000, 1.3M, 0.0001111111111111M); position1.UpdateClosePrice(1.15M); var position2 = TestObjectsFactory.CreateOpenedPosition("CHFJPY", Accounts[1], MarginTradingTestsUtils.TradingConditionId, -23, 1.96M, 1.204819277108M); position2.UpdateClosePrice(6.036M); Assert.AreEqual(-0.25M, position1.GetFpl()); Assert.AreEqual(-112.94939759M, position2.GetFpl()); }
public void Check_Order_InitialMargin() { _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.3M, Bid = 1.2M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "CHFJPY", Ask = 2.5M, Bid = 2.3M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.25M, Bid = 1.25M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURJPY", Ask = 2.3M, Bid = 2.3M }); var order1 = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[1], MarginTradingTestsUtils.TradingConditionId, 1000); var order2 = TestObjectsFactory.CreateNewOrder(OrderType.Market, "CHFJPY", Accounts[1], MarginTradingTestsUtils.TradingConditionId, -100); Assert.AreEqual(10.4M, _fplService.GetInitMarginForOrder(order1)); Assert.AreEqual(10M, _fplService.GetInitMarginForOrder(order2)); }
public void Is_Fpl_Buy_Cross_Correct() { const string instrument = "BTCCHF"; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "USDCHF", Ask = 1.072030M, Bid = 1.071940M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "BTCUSD", Ask = 1001M, Bid = 1000M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "BTCCHF", Ask = 901M, Bid = 900M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "USDCHF", Ask = 1.072030M, Bid = 1.071940M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "BTCUSD", Ask = 1001M, Bid = 1000M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "BTCCHF", Ask = 901M, Bid = 900M }); var position = TestObjectsFactory.CreateOpenedPosition(instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 1000, 935.461M, 0.932888034778M); position.UpdateClosePrice(935.61M); Assert.AreEqual(139m, Math.Round(position.GetFpl(), 3)); }
public void Check_Calculations_As_In_Excel_Document() { Accounts[0].Balance = 50000; _accountsCacheService.UpdateAccountBalance(Accounts[0].Id, Accounts[0].Balance, DateTime.UtcNow); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.061M, Bid = 1.06M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "BTCEUR", Ask = 1092M, Bid = 1091M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = "BTCUSD", Ask = 1001M, Bid = 1000M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.061M, Bid = 1.06M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "BTCEUR", Ask = 1092M, Bid = 1091M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "BTCUSD", Ask = 1001M, Bid = 1000M }); var positions = new List <Position> { TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 100000, 1.05M), TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, -200000, 1.04M), TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 50000, 1.061M), TestObjectsFactory.CreateOpenedPosition("BTCEUR", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 100, 1120, 1.06m) }; foreach (var position in positions) { _ordersCache.Positions.Add(position); } positions[0].UpdateClosePrice(1.06M); positions[1].UpdateClosePrice(1.061M); positions[2].UpdateClosePrice(1.06M); positions[3].UpdateClosePrice(1091M); var account = Accounts[0]; Assert.AreEqual(50000, account.Balance); Assert.AreEqual(43676.000, Math.Round(account.GetTotalCapital(), 5)); Assert.AreEqual(33484.3M, Math.Round(account.GetFreeMargin(), 1)); Assert.AreEqual(28388.5M, Math.Round(account.GetMarginAvailable(), 1)); Assert.AreEqual(-6324.000, Math.Round(account.GetPnl(), 5)); Assert.AreEqual(10191.7M, Math.Round(account.GetUsedMargin(), 1)); Assert.AreEqual(15287.5M, Math.Round(account.GetMarginInit(), 1)); }
public async Task Is_Order_NoLiquidity_ByInstrument_Not_Matched() { var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, "BTCUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 10); var matchedOrders = await _matchingEngine.MatchOrderAsync(order, false); Assert.AreEqual(0, matchedOrders.Count); }
public void Is_No_Quote() { var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 10); var ex = Assert.Throws <QuoteNotFoundException>(() => _validateOrderService.MakePreTradeValidation(order, true, _me)); Assert.That(ex.InstrumentId == "EURUSD"); }
public void Is_Frozen_Instrument_Valid_For_PositionClose_Pre_Traid() { const string instrument = "EURUSD"; SetupAssetPair(instrument, isFrozen: true); var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 10); Assert.DoesNotThrow(() => _validateOrderService.MakePreTradeValidation(order, false, _me)); }
public void Check_Account_StopOut_Level() { var position1 = TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 130000, 1.02M); _ordersCache.Positions.Add(position1); position1.UpdateClosePrice(1.02M); position1.GetFpl(); var account = _accountsCacheService.Get(position1.AccountId); Assert.IsNotNull(account); Assert.IsTrue(account.GetMarginUsageLevel() <= 1.25M); }
public void Is_Frozen_Instrument_Invalid_For_NewPosition_Pre_Traid() { const string instrument = "EURUSD"; SetupAssetPair(instrument, isFrozen: true); var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 10); var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.MakePreTradeValidation(order, true, _me)); Assert.That(ex.RejectReason == OrderRejectReason.InvalidInstrument); }
public void Is_Fpl_Sell_Correct() { const string instrument = "BTCUSD"; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair { Instrument = instrument, Ask = 800, Bid = 790 })); var position = TestObjectsFactory.CreateOpenedPosition(instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, -10, 790); position.UpdateClosePrice(800); Assert.AreEqual(-100, position.GetFpl()); }
public void Is_TradingDisabled_Instrument_Invalid_Pre_Trade() { const string instrument = "EURUSD"; SetupAssetPair(instrument, tradingDisabled: true); var order = TestObjectsFactory.CreateNewOrder(OrderType.Limit, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 10); var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.MakePreTradeValidation(order, true, _me, 0)); Assert.That(ex.RejectReason == OrderRejectReason.InvalidInstrument); Assert.That(ex.Message.Contains(CommonErrorCodes.InstrumentTradingDisabled)); }
public async Task Is_Buy_Fully_Matched() { var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 8); var matchedOrders = await _matchingEngine.MatchOrderAsync(order, false); var orderBooks = _matchingEngine.GetOrderBook("EURUSD"); Assert.AreEqual(2, matchedOrders.Count); Assert.True(matchedOrders.Any(item => item.OrderId == "3")); Assert.True(matchedOrders.Any(item => item.OrderId == "4")); Assert.AreEqual(order.Volume, matchedOrders.SummaryVolume); Assert.AreEqual(6, orderBooks.Sell[1.15M].First(item => item.Id == "4").GetRemainingVolume()); }
public async Task Is_Sell_Partial_Matched() { var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, -13); var matchedOrders = await _matchingEngine.MatchOrderAsync(order, false); var orderBooks = _matchingEngine.GetOrderBook("EURUSD"); Assert.AreEqual(2, matchedOrders.Count); Assert.True(matchedOrders.Any(item => item.OrderId == "1")); Assert.True(matchedOrders.Any(item => item.OrderId == "2")); Assert.AreEqual(2, Math.Abs(order.Volume) - matchedOrders.SummaryVolume); Assert.IsFalse(orderBooks.Buy.ContainsKey(1.05M)); Assert.IsFalse(orderBooks.Buy.ContainsKey(1.04M)); }
public void Is_Not_Enough_Balance() { const string instrument = "EURUSD"; var quote = new InstrumentBidAskPair { Instrument = instrument, Bid = 1.55M, Ask = 1.57M }; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote)); var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 150000); var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.MakePreTradeValidation(order, true, _me)); Assert.That(ex.RejectReason == OrderRejectReason.NotEnoughBalance); }
public void ControllerActionCreatePostWithValidModelStateShouldReditect() { var validRecipeCreateViewModel = TestObjectsFactory.GetValidRecipeCreateViewModel(); this.MockIdentity(); var validationController = new ModelStateTestController(); validationController.TestTryValidateModel(validRecipeCreateViewModel); this.controller.WithCallTo(a => a.Create(validRecipeCreateViewModel)) .ShouldRedirectTo <RecipesController>(c => c.All(1)); var modelState = validationController.ModelState; Assert.IsTrue(modelState.IsValid); }
public void Is_Enough_Balance_When_Additional_Margin_Exists() { const string instrument = "EURUSD"; var quote = new InstrumentBidAskPair { Instrument = instrument, Bid = 1.55M, Ask = 1.57M }; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote)); var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 150000); //account margin = 1000, margin requirement for order = 2355 => additional margin should be > 1355 Assert.DoesNotThrow(() => _validateOrderService.MakePreTradeValidation(order, true, _me, 1356)); }
public void ControllerActionCreatePostWithInvalidModelStateShouldReturnViewWithErrors() { var invalidRecipeCreateViewModel = TestObjectsFactory.GetInvalidRecipeCreateViewModel(); this.MockIdentity(); var validationController = new ModelStateTestController(); validationController.TestTryValidateModel(invalidRecipeCreateViewModel); var errorMessages = this.GetErrorMessages(validationController.ModelState); Assert.AreEqual("The Title must be at least 3 characters long.", errorMessages[0]); Assert.AreEqual("The field Preparation must be a string or array type with a minimum length of '100'.", errorMessages[1]); Assert.AreEqual("The Tags field is required.", errorMessages[2]); Assert.AreEqual("The recipe must contain at least 3 ingredients!", errorMessages[3]); Assert.AreEqual("The recipe must contain at least one image!", errorMessages[4]); }
public void Check_IsEnoughBalance() { //account have 1000 var me = new FakeMatchingEngine(10); var order1 = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 96000); Assert.DoesNotThrow(() => _accountUpdateService.CheckIsEnoughBalance(order1, me, 0)); var order2 = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 97000); Assert.Throws <ValidateOrderException>(() => _accountUpdateService.CheckIsEnoughBalance(order2, me, 0)); var meWithSpread = new FakeMatchingEngine(10, closePrice: 1); var order3 = TestObjectsFactory.CreateNewOrder(OrderType.Market, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 96000); Assert.Throws <ValidateOrderException>( () => _accountUpdateService.CheckIsEnoughBalance(order3, meWithSpread, 0)); var meForLimitOk = new FakeMatchingEngine(999); var limitOrderOk = TestObjectsFactory.CreateNewOrder(OrderType.Limit, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 960, price: 1000); Assert.DoesNotThrow(() => _accountUpdateService.CheckIsEnoughBalance(limitOrderOk, meForLimitOk, 0)); var limitOrderErr = TestObjectsFactory.CreateNewOrder(OrderType.Limit, "EURUSD", Accounts[0], MarginTradingTestsUtils.TradingConditionId, 960, price: 1000); var meWithHighPrice = new FakeMatchingEngine(1000, 10); var ex = Assert.Throws <ValidateOrderException>(() => _accountUpdateService.CheckIsEnoughBalance(limitOrderErr, meWithHighPrice, 0)); Console.WriteLine(ex.Comment); }
public async Task Check_Position_PnL_Multi_Thread() { _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "BTCUSD", Ask = 2M, Bid = 1M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1, Bid = 1 }); var position1 = TestObjectsFactory.CreateOpenedPosition("BTCUSD", Accounts[1], MarginTradingTestsUtils.TradingConditionId, 1, 2M, 1M); var updateFxTask = new Action(() => { position1.UpdateCloseFxPrice(2); }); var getPnLTask = new Action(() => { position1.GetFpl(); }); var wrong = 0; const int attempts = 100000; for (int i = 0; i < attempts; i++) { position1.UpdateClosePrice(1M); await Task.WhenAll(Task.Factory.StartNew(getPnLTask), Task.Factory.StartNew(updateFxTask)); var pnl = position1.GetFpl(); if (pnl != -2) { wrong++; } position1.UpdateClosePrice(2M); position1.UpdateCloseFxPrice(1); Assert.AreEqual(0, position1.GetFpl()); } Assert.AreEqual(0, wrong, $"Number of wrong P&L calculations from {attempts} attempts"); }
public void Check_Position_Margin() { _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 1.3M, Bid = 1.2M })); _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs( new InstrumentBidAskPair { Instrument = "CHFJPY", Ask = 2.5M, Bid = 2.3M })); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURUSD", Ask = 9000M, Bid = 9000M }); _fxRateCacheService.SetQuote(new InstrumentBidAskPair { Instrument = "EURJPY", Ask = 2.3M, Bid = 2.3M }); var position1 = TestObjectsFactory.CreateOpenedPosition("EURUSD", Accounts[1], MarginTradingTestsUtils.TradingConditionId, 15000, 1.3M, 1 / 9000M); position1.UpdateClosePrice(1.2M); position1.UpdateCloseFxPrice(1 / 9000M); var position2 = TestObjectsFactory.CreateOpenedPosition("CHFJPY", Accounts[1], MarginTradingTestsUtils.TradingConditionId, -100, 2.3M, 1 / 2.3M); position2.UpdateClosePrice(2.5M); position2.UpdateCloseFxPrice(1 / 2.3M); Assert.AreEqual(0.02M, position1.GetMarginInit()); Assert.AreEqual(0.01M, position1.GetMarginMaintenance()); Assert.AreEqual(10.87, position2.GetMarginInit()); Assert.AreEqual(7.25M, position2.GetMarginMaintenance()); }
public void Is_Summary_Volume_Ivalid(decimal volume, bool isValid) { const string instrument = "BTCUSD"; var quote = new InstrumentBidAskPair { Instrument = instrument, Bid = 1.55M, Ask = 1.57M }; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote)); var existingLong = TestObjectsFactory.CreateOpenedPosition(instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, 110, 1.57M); var existingShort = TestObjectsFactory.CreateOpenedPosition(instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, -12, 1.55M); var existingOtherAcc = TestObjectsFactory.CreateOpenedPosition(instrument, Accounts[1], MarginTradingTestsUtils.TradingConditionId, 49, 1.57M); _ordersCache.Positions.Add(existingLong); _ordersCache.Positions.Add(existingShort); _ordersCache.Positions.Add(existingOtherAcc); var order = TestObjectsFactory.CreateNewOrder(OrderType.Market, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, volume); if (isValid) { Assert.DoesNotThrow(() => _validateOrderService.MakePreTradeValidation(order, true, _me)); } else { var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.MakePreTradeValidation(order, true, _me)); Assert.That(ex.RejectReason == OrderRejectReason.MaxPositionLimit); } }
private Order CreatePendingOrder(OrderType orderType, OrderDirection direction, decimal?price, DateTime created) { return(TestObjectsFactory.CreateNewOrder(orderType, "AssetPair", new MarginTradingAccount(), "TradingCondition", direction == OrderDirection.Buy ? 1 : -1, price: price, created: created)); }
public void Is_BaseOrder_Validated_Correctly_Against_Related_On_Change( OrderDirection baseDirection, decimal newPrice, bool isValid) { const string instrument = "EURUSD"; var quote = new InstrumentBidAskPair { Instrument = instrument, Bid = 1.55M, Ask = 1.57M }; _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote)); Order CreateOrder(OrderType type) { var order = TestObjectsFactory.CreateNewOrder(type, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, volume: baseDirection == OrderDirection.Buy ? 1 : -1, price: baseDirection == OrderDirection.Buy ? 2 : 1); _ordersCache.Active.Add(order); var sl = TestObjectsFactory.CreateNewOrder(OrderType.StopLoss, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, volume: baseDirection == OrderDirection.Buy ? -1 : 1, price: baseDirection == OrderDirection.Buy ? 0.5M : 3, parentOrderId: order.Id); var tp = TestObjectsFactory.CreateNewOrder(OrderType.TakeProfit, instrument, Accounts[0], MarginTradingTestsUtils.TradingConditionId, volume: baseDirection == OrderDirection.Buy ? -1 : 1, price: baseDirection == OrderDirection.Buy ? 3 : 0.5M, parentOrderId: order.Id); order.AddRelatedOrder(sl); order.AddRelatedOrder(tp); _ordersCache.Inactive.Add(sl); _ordersCache.Inactive.Add(tp); return(order); } var limitOrder = CreateOrder(OrderType.Limit); var stopOrder = CreateOrder(OrderType.Stop); if (isValid) { Assert.DoesNotThrow(() => _validateOrderService.ValidateOrderPriceChange(limitOrder, newPrice)); Assert.DoesNotThrow(() => _validateOrderService.ValidateOrderPriceChange(stopOrder, newPrice)); } else { var ex1 = Assert.Throws <ValidateOrderException>(() => _validateOrderService.ValidateOrderPriceChange(limitOrder, newPrice)); Assert.That(ex1.RejectReason == OrderRejectReason.InvalidExpectedOpenPrice); StringAssert.Contains("against related", ex1.Message); var ex2 = Assert.Throws <ValidateOrderException>(() => _validateOrderService.ValidateOrderPriceChange(stopOrder, newPrice)); Assert.That(ex2.RejectReason == OrderRejectReason.InvalidExpectedOpenPrice); StringAssert.Contains("against related", ex1.Message); } }