public void ShouldExecuteInstructionWhenThereIsEnoughLiquidityOnOneMarket()
        {
            // Given market A: 150 @ $100, market B: 55 @ $101 
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested price
            var marketA = new Market
            {
                                  SellQuantity = 150,
                                  SellPrice = 100M
                              };
            
            var marketB = new Market
            {
                                  SellQuantity = 55,
                                  SellPrice = 101M
                              };

            var marketsInvolved = new[] { marketA, marketB };

            ICanRouteOrders canRouteOrders = null;//new OrderRoutingService(marketsInvolved);
            ICanReceiveMarketData canReceiveMarketData = new MarketDataProvider(marketsInvolved);
            IProvideMarkets provideMarkets = new MarketProvider(marketsInvolved);
            var sor = new SmartOrderRoutingEngine(provideMarkets, canRouteOrders, canReceiveMarketData);

            var investorInstructionDto = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), Way.Buy, quantity: 125, price: 100M);

            OrderExecutedEventArgs orderExecutedEventArgs = null;
            sor.Subscribe(investorInstructionDto.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, null);
                //investorInstruction.Executed += (sender, args) => { orderExecutedEventArgs = args; };
            
            // orderRequest.Route(); ?
            sor.Route(investorInstructionDto);

            // TODO :introduce autoreset event instead
            Check.That(orderExecutedEventArgs).HasFieldsWithSameValues(new { Way = Way.Buy, Quantity = 125, Price = 100M });
        }
        public void Route(InvestorInstructionDto investorInstructionDto)
        {
            // 1. Digest Investment instructions
            // 2. Prepare order book (solver)
            // 3. Send and monitor
            // 4. Feedback investor

            var investorInstruction = this.CreateInvestorInstruction(investorInstructionDto.UniqueIdentifier, null, investorInstructionDto.Way, investorInstructionDto.Quantity, investorInstructionDto.Price, investorInstructionDto.AllowPartialExecution, investorInstructionDto.GoodTill);

            var executionState = new InstructionExecutionContext(investorInstruction);

            this.RouteImpl(investorInstruction, executionState);
        }
        public void Run()
        {
            // initialize the context
            var sor = BuildSor();
            var identifier = sor.RequestUniqueIdentifier();

            // instantiate the service
            var adapter = new SmartOrderRoutingRawInprocAdapter(sor);

            // initialize our engine
            adapter.InstructionUpdated += ServiceOnInstructionUpdated;
            this.instructionIdentifier = adapter.RequestUniqueIdentifier();

            // build demo order
            this.investorInstructionDto = new InvestorInstructionDto(identifier, Way.Buy, 10, 100M, true, null);

            var stopWatch = new Stopwatch();

            // sends the instruction
            stopWatch.Start();
            // Subscribes to the instruction's events
            OrderExecutedEventArgs orderExecutedEventArgs = null;
            string failureReason = null;
            sor.Subscribe(investorInstructionDto.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, (args) => { failureReason = args; });
            sor.Route(investorInstructionDto);

            // wait for the exit condition
            lock (this.synchro)
            {
                if (this.done == false)
                {
                    Monitor.Wait(this.synchro, 500);
                }
            }

            stopWatch.Stop();
            
            if (this.done)
            {
                this.AverageLatency = stopWatch.ElapsedMilliseconds;
            }

        }
        public void ShouldFaileWhenOrderExceedsAllMarketCapacityAndPartialExecutionNotAllowed()
        {
            // Given market A: 150 @ $100, market B: 55 @ $101 
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested price
            var marketA = new Market
            {
                                  SellQuantity = 15,
                                  SellPrice = 100M
                              };
            
            var marketB = new Market
            {
                                  SellQuantity = 55,
                                  SellPrice = 101M
                              };

            var sor = CreateSmartOrderRoutingEngine(new[] { marketA, marketB });

            var investorInstruction = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), Way.Buy, quantity: 125, price: 100M, allowPartialExecution: false);

            // Subscribes to the instruction's events
            OrderExecutedEventArgs orderExecutedEventArgs = null;
            string failureReason = null;

            sor.Subscribe(investorInstruction.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, (args) => { failureReason = args; });

            // orderRequest.Route(); ?
            sor.Route(investorInstruction);

            // Couldn't execute because order with excessive quantity
            Check.That(failureReason).IsNotNull().And.IsEqualIgnoringCase("Excessive quantity!");
            Check.That(orderExecutedEventArgs).IsNull();
        }
        public void ShouldExecuteOrdersOnWeightedAverageOfAvailableQuantities()
        {
            // 25 premier ; 75 % sur le second marché
            // Given market A: 100 @ $100, market B: 50 @ $100 
            // When Investor wants to buy 75 stocks @ $100 Then SOR can execute at the requested price
            // And execution is: 50 stocks on MarketA and 25 stocks on MarketB
            var marketA = new Market()
            {
                SellQuantity = 100,
                SellPrice = 100M
            };

            var marketB = new Market()
            {
                SellQuantity = 50,
                SellPrice = 100M
            };

            var sor = CreateSmartOrderRoutingEngine(new[] { marketA, marketB });

            var investorInstruction = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), Way.Buy, quantity: 75, price: 100M);

            OrderExecutedEventArgs orderExecutedEventArgs = null;

            sor.Subscribe(investorInstruction.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, null);

            sor.Route(investorInstruction);

            Check.That(orderExecutedEventArgs).HasFieldsWithSameValues(new { Way = Way.Buy, Quantity = 75, Price = 100M });
            Check.That(marketA.SellQuantity).IsEqualTo(50);
            Check.That(marketB.SellQuantity).IsEqualTo(25);
        }
        public void ShouldExecuteInstructionWhenThereIsEnoughLiquidityOnTheMarkets()
        {
            // Given market A: 100 @ $100, market B: 55 @ $100 
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested price
            var marketA = new Market()
                              {
                                  SellQuantity = 100,
                                  SellPrice = 100M
                              };
            
            var marketB = new Market()
                              {
                                  SellQuantity = 55,
                                  SellPrice = 100M
                              };

            var sor = CreateSmartOrderRoutingEngine(new[] { marketA, marketB });

            var investorInstruction = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), /*new InstrumentIdentifier("EURUSD"),*/ Way.Buy, quantity: 125, price: 100M);

            OrderExecutedEventArgs orderExecutedEventArgs = null;

            sor.Subscribe(investorInstruction.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, null);

            // orderRequest.Route(); ?
            sor.Route(investorInstruction);

            Check.That(orderExecutedEventArgs).HasFieldsWithSameValues(new { Way = Way.Buy, Quantity = 125, Price = 100M });
        }
        public void ShouldSucceededWhenLiquidityISAvailableEvenIfOneMarketRejects()
        {
            // Given market A: 150 @ $100, market B: 55 @ $101 
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested price
            var marketA = new Market()
            {
                SellQuantity = 50,
                SellPrice = 100M
            };

            var rejectMarket = new Market()
            {
                SellQuantity = 50,
                SellPrice = 100M,
                OrderPredicate = (o) => false
            };

            var sor = CreateSmartOrderRoutingEngine(new[] { marketA, rejectMarket });

            var investorInstruction = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), Way.Buy, quantity: 50, price: 100M, goodTill: DateTime.Now.AddMinutes(5));

            // Subscribes to the instruction's events
            OrderExecutedEventArgs orderExecutedEventArgs = null;
            string failureReason = null;
            
            sor.Subscribe(investorInstruction.UniqueIdentifier, (args) => { orderExecutedEventArgs = args; }, (args) => { failureReason = args; });

            // orderRequest.Route(); ?
            sor.Route(investorInstruction);

            Check.That(orderExecutedEventArgs).IsNotNull();
            Check.That(failureReason).IsNull();
        }
        public void ShouldStopSendingOrdersToAMarketAfter3Rejects()
        {
            var rejectingMarket = new Market
                             {
                                 SellQuantity = 100,
                                 SellPrice = 100M,
                                 OrderPredicate = order => false
                             };

            var sor = CreateSmartOrderRoutingEngine(new[] { rejectingMarket });
            var investorInstruction = new InvestorInstructionDto(new InvestorInstructionIdentifierDto(), Way.Buy, quantity: 50, price: 100M, goodTill: DateTime.Now.AddMinutes(5));
            sor.Route(investorInstruction);

            Check.That(rejectingMarket.TimesSent).IsEqualTo(3);
        }