public void Should_decrease_available_quantity_for_the_market_when_an_order_is_sent()
        {
            var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M);

            var order = marketGateway.CreateMarketOrder(ApiMarketWay.Buy, quantity: 10);

            marketGateway.Send(order);

            Check.That(marketGateway.SellQuantity).IsEqualTo(40);
        }
        public void Should_Notify_LimitOrder_execution()
        {
            var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M);

            var executed = false;
            var order    = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 100M, quantity: 10, allowPartial: false);

            marketGateway.OrderExecuted += (s, a) => executed = true;
            marketGateway.Send(order);

            Check.That(executed).IsTrue();
            Check.That(marketGateway.SellQuantity).IsEqualTo(40);
        }
Beispiel #3
0
        public void Should_stop_sending_Orders_to_a_Market_after_3_rejects()
        {
            var rejectingMarket = new ApiMarketGateway("LSE (London)", sellQuantity: 100, sellPrice: 100M, orderPredicate: order => false);

            var investorInstructionAdapter = CompositionRootHelper.ComposeTheHexagon(rejectingMarket);

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

            investorInstructionAdapter.Route(investorInstructionDto, (args) => { }, (args) => { });

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

            Check.That(rejectingMarket.SellQuantity).IsEqualTo(100);
        }
        public void Should_Solve_with_2_markets_when_asked_quantity_is_1()
        {
            var marketA              = new ApiMarketGateway("NYSE (New York)", sellQuantity: 50, sellPrice: 100M);
            var rejectingMarket      = new ApiMarketGateway("CME (Chicago)", sellQuantity: 50, sellPrice: 100M, orderPredicate: _ => false);
            var marketsInvolved      = new[] { marketA, rejectingMarket };
            var marketGatewayAdapter = new MarketsAdapter(marketsInvolved);

            var investorInstruction         = new InvestorInstruction(new InvestorInstructionIdentifierDto().Value, Way.Buy, quantity: 1, price: 100M, goodTill: DateTime.Now.AddMinutes(5));
            var instructionExecutionContext = new InstructionExecutionContext(investorInstruction, args => { }, failure => { });

            var marketSweepSolver = new MarketSweepSolver(new MarketSnapshotProvider(marketGatewayAdapter.GetAvailableMarketNames(), marketGatewayAdapter));
            var orderBasket       = marketSweepSolver.Solve(instructionExecutionContext, marketGatewayAdapter);

            Check.That(orderBasket.OrdersDescriptions.Extracting("Quantity")).ContainsExactly(1);
        }
        public void Should_failed_to_execute_order_when_quantity_is_excessive()
        {
            var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M);

            var order = marketGateway.CreateMarketOrder(ApiMarketWay.Buy, quantity: 100);

            bool   failed        = false;
            string failureReason = null;

            marketGateway.OrderFailed += (s, failedEventArgs) =>
            {
                failed        = true;
                failureReason = failedEventArgs.FailureCause;
            };

            marketGateway.Send(order);

            Check.That(failed).IsTrue();
            Check.That(failureReason).IsEqualTo("Excessive quantity!");
        }
        public void Should_support_partial_execution_for_LimitOrder()
        {
            var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M);

            var executed = false;
            var order    = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 100M, quantity: 110, allowPartial: true);

            var execQuantity = 0;

            marketGateway.OrderExecuted += (s, a) =>
            {
                executed     = true;
                execQuantity = a.Quantity;
            };
            marketGateway.Send(order);

            Check.That(execQuantity).IsEqualTo(50);
            Check.That(executed).IsTrue();
            Check.That(marketGateway.SellQuantity).IsEqualTo(0);
        }
Beispiel #7
0
        public void Should_execute_Instruction_when_there_is_enough_liquidity_on_the_Markets()
        {
            // Given market A: 100 @ $100, market B: 55 @ $100
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested MarketPrice
            var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 100, sellPrice: 100M);
            var marketB = new ApiMarketGateway("CME (Chicago)", sellQuantity: 55, sellPrice: 100M);

            var investorInstructionAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, marketB);

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

            InstructionExecutedDto instructionExecuted = null;

            investorInstructionAdapter.Route(investorInstructionDto, (args) => { instructionExecuted = args; }, null);

            Check.That(instructionExecuted).HasFieldsWithSameValues(new { Way = Way.Buy, Quantity = 125, Price = 100M });

            Check.That(marketA.SellQuantity).IsEqualTo(19);
            Check.That(marketB.SellQuantity).IsEqualTo(11);
        }
Beispiel #8
0
        static void Main(string[] args)
        {
            var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 150, sellPrice: 100M);
            var marketB = new ApiMarketGateway("CME (Chicago)", sellQuantity: 55, sellPrice: 101M);

            var investorAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, marketB);

            System.Console.WriteLine("SOR connected to markets: {0} and {1}", marketA.MarketName, marketB.MarketName);

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

            System.Console.WriteLine();
            System.Console.WriteLine("Type 'Enter' to submit the following investor instruction: [{0}]\n\n", investorInstructionDto);
            System.Console.ReadLine();

            investorAdapter.Route(investorInstructionDto, arg => { System.Console.WriteLine("Instruction executed: [{0}]", arg); }, eventArgs => {});

            System.Console.WriteLine();
            System.Console.WriteLine("Type 'Enter' to exit");
            System.Console.ReadLine();
        }
        public void Should_not_execute_LimitOrder_when_price_is_too_high()
        {
            var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M);

            var    executed      = false;
            bool   failed        = false;
            string failureReason = null;
            var    order         = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 101M, quantity: 10, allowPartial: false);

            marketGateway.OrderExecuted += (s, a) => executed = true;
            marketGateway.OrderFailed   += (s, failedEventArgs) =>
            {
                failed        = true;
                failureReason = failedEventArgs.FailureCause;
            };
            marketGateway.Send(order);

            Check.That(executed).IsFalse();
            Check.That(failed).IsTrue();
            Check.That(failureReason).IsEqualTo("Invalid price");
            Check.That(marketGateway.SellQuantity).IsEqualTo(50);
        }
Beispiel #10
0
        public void Should_execute_Orders_on_weighted_average_of_available_quantities()
        {
            // 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 MarketPrice
            // And execution is: 50 stocks on MarketA and 25 stocks on MarketB
            var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 100, sellPrice: 100M);
            var marketB = new ApiMarketGateway("CME (Chicago)", sellQuantity: 50, sellPrice: 100M);

            var investorInstructionAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, marketB);

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

            InstructionExecutedDto instructionExecuted = null;

            investorInstructionAdapter.Route(investorInstructionDto, (args) => { instructionExecuted = args; }, null);

            Check.That(instructionExecuted).HasFieldsWithSameValues(new { Way = Way.Buy, Quantity = 75, Price = 100M });

            Check.That(marketA.SellQuantity).IsEqualTo(50);
            Check.That(marketB.SellQuantity).IsEqualTo(25);
        }
Beispiel #11
0
        public void Should_succeeded_when_liquidity_is_available_even_if_one_Market_rejects()
        {
            // Given market A: 150 @ $100, market B: 55 @ $101
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested MarketPrice
            var marketA         = new ApiMarketGateway("NYSE (New York)", sellQuantity: 50, sellPrice: 100M);
            var rejectingMarket = new ApiMarketGateway("LSE (London)", sellQuantity: 50, sellPrice: 100M, orderPredicate: _ => false);

            var investorInstructionAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, rejectingMarket);

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

            // Subscribes to the instruction's events
            InstructionExecutedDto instructionExecuted = null;
            InstructionFailedDto   instructionFailed   = null;

            investorInstructionAdapter.Route(investorInstructionDto, (args) => { instructionExecuted = args; }, (args) => { instructionFailed = args; });

            Check.That(instructionExecuted).IsNotNull();
            Check.That(instructionFailed).IsNull();

            Check.That(marketA.SellQuantity).IsEqualTo(0);
            Check.That(rejectingMarket.SellQuantity).IsEqualTo(50);
        }
Beispiel #12
0
        public void Should_failed_when_Order_exceeds_all_Market_capacity_and_partial_execution_not_allowed()
        {
            // Given market A: 150 @ $100, market B: 55 @ $101
            // When Investor wants to buy 125 stocks @ $100 Then SOR can execute at the requested MarketPrice
            var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 15, sellPrice: 100M);
            var marketB = new ApiMarketGateway("CME (Chicago)", sellQuantity: 55, sellPrice: 101M);

            var investorInstructionAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, marketB);

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

            // Subscribes to the instruction's events
            InstructionExecutedDto instructionExecuted = null;
            InstructionFailedDto   instructionFailed   = null;

            investorInstructionAdapter.Route(investorInstructionDto, (args) => { instructionExecuted = args; }, (args) => { instructionFailed = args; });

            // Couldn't execute because order with excessive QuantityOnTheMarket
            Check.That(instructionFailed.Reason).IsNotNull().And.IsEqualIgnoringCase("Excessive quantity!");
            Check.That(instructionExecuted).IsNull();

            Check.That(marketA.SellQuantity).IsEqualTo(15);
            Check.That(marketB.SellQuantity).IsEqualTo(55);
        }
 public LimitOrderAdapter(ApiMarketGateway marketGateway, ApiLimitOrder apiLimitOrder)
     : base(marketGateway, apiLimitOrder)
 {
     this.apiLimitOrder = apiLimitOrder;
 }
Beispiel #14
0
 protected OrderAdapter(ApiMarketGateway marketGateway, ApiOrder apiOrder)
 {
     this.apiOrder      = apiOrder;
     this.MarketGateway = marketGateway;
 }