Example #1
0
        internal void ParseFromMarketOrderPriceZero(OrderSide side)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Market,
                orderStatus: New,
                createdTimestamp: 0,
                setPrice: 0.4M,
                side: side,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 40M)
            {
                AverageFilledPrice = 0M,
                FilledQuantity     = 10M,
            };

            var exec = TradeExecution.FromOrder(order);

            Assert.Equal(exec.From.Locked, decimal.Zero);

            if (side == OrderSide.Sell)
            {
                Assert.Equal(10M, exec.From.Free);
                Assert.Equal(decimal.Zero, exec.To.Free);
            }
            else
            {
                Assert.Equal(decimal.Zero, exec.From.Free);
                Assert.Equal(10M, exec.To.Free);
            }

            Assert.Equal(exec.To.Locked, decimal.Zero);
        }
Example #2
0
        /// <summary>
        /// Queue a trade based on a proposal, the callback must return the trade execution
        /// which will be used to update the allocation.
        /// </summary>
        /// <param name="p">TradeProposal to be verified.</param>
        /// <param name="tradeCallback">Trade callback to be executed if verification was successful.</param>
        /// <returns>Boolean indicating successful execution of the callback.</returns>
        public virtual ResponseObject <OrderUpdate> QueueTrade(TradeProposal p, Func <OrderUpdate> tradeCallback)
        {
            Guard.Argument(_allocation).NotNull("Initialise allocations first");
            Guard.Argument(p).NotNull();

            var alloc = GetAvailableFunds(p.From.Symbol);

            if (alloc.Free < p.From.Free || alloc.Locked < p.From.Locked)
            {
                _logger.LogCritical($"Got trade proposal for ({p.From}, but allocation " +
                                    $"showed only ({alloc}) was available\n" +
                                    "Trade will not be executed.");
                return(ResponseObject.OrderRefused);
            }

            // Let the provider execute the trade and save the execution report
            var order = tradeCallback();

            // TradingProvider can give a null execution report when it decides not to trade.
            // if this happens the portfolio will be checked against the remote using an 'empty' or 'monoid' trade execution.
            if (order is null)
            {
                _logger.LogWarning("TradingProvider implementation returned a null OrderUpdate");
                return(ResponseObject.OrderPlacementFailed("Implementation returned a null OrderUpdate"));
            }

            TradeExecution exec = TradeExecution.FromOrder(order);

            // Update the local information
            UpdateAllocation(exec);

            return(new ResponseObject <OrderUpdate>(order));
        }
Example #3
0
        internal void ParseFromMarketSellOrderNewHappyFlow()
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Market,
                orderStatus: New,
                createdTimestamp: 0,
                setPrice: 0.4M,
                side: OrderSide.Sell,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 40M)
            {
                FilledQuantity     = 40M,
                AverageFilledPrice = 0.401M,
            };

            var exec = TradeExecution.FromOrder(order);

            Assert.Equal(order.Pair.Left, exec.From.Symbol);
            Assert.Equal(order.Pair.Right, exec.To.Symbol);
            Assert.Equal(40M, exec.From.Free);
            Assert.Equal(0, exec.From.Locked);
            Assert.Equal(40M * 0.401M, exec.To.Free);
            Assert.Equal(0, exec.To.Locked);
        }
Example #4
0
        internal void ParseFromNonMarketBuyOrderForeignCommission(OrderUpdate.OrderTypes type)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: type,
                orderStatus: Filled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: OrderSide.Buy,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M)
            {
                FilledQuantity     = 100M,
                AverageFilledPrice = 0.15M,
                LastFillIncrement  = 100M,
                LastFillPrice      = 0.15M,
                Commission         = 96.42M,
                CommissionAsset    = new Currency("BNB"),
            };

            var exec = TradeExecution.FromOrder(order);

            Assert.Equal(0M, exec.From.Free);
            Assert.Equal(100M * 0.2M, exec.From.Locked);
            Assert.Equal(100M, exec.To.Free);
            Assert.Equal(0M, exec.To.Locked);
        }
Example #5
0
        internal void ParseFromNonMarketSellOrderCancelledHappyFlow(OrderUpdate.OrderTypes orderType)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: orderType,
                orderStatus: Cancelled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: OrderSide.Sell,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M);
            var exec = TradeExecution.FromOrder(order);

            Assert.NotNull(exec);

            var symbol = new Currency("EOS");

            Assert.Equal(symbol, exec.From.Symbol);
            Assert.Equal(symbol, exec.To.Symbol);
            Assert.Equal(0M, exec.From.Free);
            Assert.Equal(100M, exec.From.Locked);
            Assert.Equal(100M, exec.To.Free);
            Assert.Equal(0M, exec.To.Locked);
        }
Example #6
0
        internal void ParseFromMarketCancelledOrderInvalid(OrderSide side)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Market,
                orderStatus: Cancelled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: side,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M);

            Assert.Throws <ArgumentException>(() => TradeExecution.FromOrder(order));
        }
Example #7
0
        internal void ParseFromMarketFilled(OrderSide side)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Market,
                orderStatus: Filled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: side,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M);
            var exec = TradeExecution.FromOrder(order);

            // Assert that the order is calculated as a complete market order
            Assert.NotEqual(exec.From.Symbol, exec.To.Symbol);
            Assert.Equal(0M, exec.From.Locked);
            Assert.Equal(0M, exec.To.Locked);
        }
Example #8
0
        private void UpdateAllocation(OrderUpdate order)
        {
            Guard.Argument(order).NotNull(nameof(order));

            // Skip Market orders, there are filled at execution time.
            if (order.OrderType == OrderUpdate.OrderTypes.Market)
            {
                return;
            }

            // Skip new orders, their allocation is already processed
            if (order.Status == OrderUpdate.OrderStatus.New)
            {
                return;
            }

            var exec = TradeExecution.FromOrder(order);

            _allocationManager.UpdateAllocation(exec);
        }
Example #9
0
        internal void ParseFromMarketOrderCommission(OrderSide side)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Market,
                orderStatus: Filled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: side,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M)
            {
                FilledQuantity     = 100M,
                AverageFilledPrice = 0.15M,
                LastFillIncrement  = 100M,
                LastFillPrice      = 0.15M,
                Commission         = 2.3M,
                CommissionAsset    = new Currency("EOS"),
            };

            var exec = TradeExecution.FromOrder(order);

            if (side == OrderSide.Buy)
            {
                Assert.Equal(100M * 0.15M, exec.From.Free);
                Assert.Equal(100M - 2.3M, exec.To.Free);
            }
            else
            {
                Assert.Equal(100M, exec.From.Free);
                Assert.Equal((100M * 0.15M) - (2.3M * 0.15M), exec.To.Free);
            }

            Assert.Equal(0, exec.To.Locked);
            Assert.Equal(0, exec.From.Locked);
        }
Example #10
0
        internal void ParseFromLimitFilledDifferentPrice(OrderSide side)
        {
            var order = new OrderUpdate(
                orderId: 0,
                tradeId: 0,
                orderType: Limit,
                orderStatus: Filled,
                createdTimestamp: 0,
                setPrice: 0.2M,
                side: side,
                pair: TradingPair.Parse("EOSETH"),
                setQuantity: 100M)
            {
                FilledQuantity     = 100M,
                AverageFilledPrice = 0.15M,
                LastFillIncrement  = 100M,
                LastFillPrice      = 0.15M,
            };

            var exec = TradeExecution.FromOrder(order);

            Assert.Equal(0M, exec.From.Free);
            if (side == OrderSide.Buy)
            {
                // Allocation was locked using the set price, and should be freed as such
                Assert.Equal(100M * 0.2M, exec.From.Locked);
                Assert.Equal(100M, exec.To.Free);
            }
            else
            {
                Assert.Equal(100M, exec.From.Locked);
                Assert.Equal(100M * 0.15M, exec.To.Free);
            }

            Assert.Equal(0, exec.To.Locked);
        }