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); }