Ejemplo n.º 1
0
        private void NotifyQuoteIsOk(InstrumentBidAskPair quote)
        {
            var message = $"Quotes for {quote.Instrument} started at {quote.Date}";

            WriteMessage(quote, message, EventTypeEnum.QuoteStarted);
            _outdatedQuotes.Remove(quote.Instrument);
        }
Ejemplo n.º 2
0
        private IEnumerable <Order> GetPendingOrdersToBeExecuted(InstrumentBidAskPair quote)
        {
            var pendingOrders = _ordersCache.Active.GetOrdersByInstrument(quote.Instrument);

            foreach (var order in pendingOrders)
            {
                var price = quote.GetPriceForOrderDirection(order.Direction);

                if (order.IsSuitablePriceForPendingOrder(price) &&
                    _validateOrderService.CheckIfPendingOrderExecutionPossible(order.AssetPairId, order.OrderType,
                                                                               ShouldOpenNewPosition(order)))
                {
                    if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume))
                    {
                        _ordersCache.Active.Remove(order);
                        yield return(order);
                    }
                    else //let's validate one more time, considering orderbook depth
                    {
                        var me = _meRouter.GetMatchingEngineForExecution(order);
                        var executionPriceInfo = me.GetBestPriceForOpen(order.AssetPairId, order.Volume);

                        if (executionPriceInfo.price.HasValue && order.IsSuitablePriceForPendingOrder(executionPriceInfo.price.Value))
                        {
                            _ordersCache.Active.Remove(order);
                            yield return(order);
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public void Is_RelatedOrder_Validated_Correctly_Against_Base_MarketOrder_On_Create(
            OrderDirectionContract baseDirection, decimal?slPrice, decimal?tpPrice, OrderRejectReason?rejectReason)
        {
            const string instrument = "EURUSD";
            var          quote      = new InstrumentBidAskPair {
                Instrument = instrument, Bid = 1.55M, Ask = 1.57M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));

            var orderRequest = new OrderPlaceRequest
            {
                AccountId     = Accounts[0].Id,
                CorrelationId = Guid.NewGuid().ToString(),
                Direction     = baseDirection,
                InstrumentId  = instrument,
                Type          = OrderTypeContract.Market,
                StopLoss      = slPrice,
                TakeProfit    = tpPrice,
                Volume        = 1
            };

            if (!rejectReason.HasValue)
            {
                Assert.DoesNotThrowAsync(async() =>
                                         await _validateOrderService.ValidateRequestAndCreateOrders(orderRequest));
            }
            else
            {
                var ex1 = Assert.ThrowsAsync <ValidateOrderException>(() =>
                                                                      _validateOrderService.ValidateRequestAndCreateOrders(orderRequest));

                Assert.That(ex1.RejectReason == rejectReason);
            }
        }
Ejemplo n.º 4
0
        public void Is_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 order = new Order
            {
                CreateDate = DateTime.UtcNow,
                Id         = Guid.NewGuid().ToString("N"),
                AccountId  = Accounts[0].Id,
                ClientId   = Accounts[0].ClientId,
                Instrument = instrument,
                Volume     = volume,
                FillType   = OrderFillType.FillOrKill
            };

            if (isValid)
            {
                Assert.DoesNotThrow(() => _validateOrderService.Validate(order));
            }
            else
            {
                var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.Validate(order));

                Assert.That(ex.RejectReason == OrderRejectReason.InvalidVolume);
            }
        }
Ejemplo n.º 5
0
        public void Is_MarketOrder_Sell_StopLoss_Invalid()
        {
            const string instrument = "BTCCHF";
            var          quote      = new InstrumentBidAskPair {
                Instrument = instrument, Bid = 963.633M, Ask = 964.228M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));

            var order = new Order
            {
                CreateDate         = DateTime.UtcNow,
                Id                 = Guid.NewGuid().ToString("N"),
                AccountId          = Accounts[0].Id,
                ClientId           = Accounts[0].ClientId,
                TradingConditionId = MarginTradingTestsUtils.TradingConditionId,
                AccountAssetId     = Accounts[0].BaseAssetId,
                Instrument         = instrument,
                Volume             = -10,
                StopLoss           = 964.2553256564M,
                FillType           = OrderFillType.FillOrKill
            };

            var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.Validate(order));

            Assert.That(ex.RejectReason == OrderRejectReason.InvalidStoploss);
            StringAssert.Contains($"{quote.Bid}/{quote.Ask}", ex.Comment);
            StringAssert.Contains("more", ex.Message);
        }
Ejemplo n.º 6
0
        public void Is_Order_ExpectedOpenPrice_Validated_Correctly(OrderDirectionContract direction, OrderTypeContract orderType,
                                                                   decimal?price, bool isValid)
        {
            const string instrument = "EURUSD";
            var          quote      = new InstrumentBidAskPair {
                Instrument = instrument, Bid = 1.55M, Ask = 1.57M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));

            var request = new OrderPlaceRequest
            {
                AccountId     = Accounts[0].Id,
                CorrelationId = Guid.NewGuid().ToString(),
                Direction     = direction,
                InstrumentId  = instrument,
                Type          = orderType,
                Price         = price,
                Volume        = 1
            };

            if (isValid)
            {
                Assert.DoesNotThrowAsync(async() =>
                                         await _validateOrderService.ValidateRequestAndCreateOrders(request));
            }
            else
            {
                var ex = Assert.ThrowsAsync <ValidateOrderException>(() =>
                                                                     _validateOrderService.ValidateRequestAndCreateOrders(request));

                Assert.That(ex.RejectReason == OrderRejectReason.InvalidExpectedOpenPrice);
                StringAssert.Contains($"{quote.Bid}/{quote.Ask}", ex.Comment);
            }
        }
Ejemplo n.º 7
0
        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 = new Order
            {
                CreateDate         = DateTime.UtcNow,
                Id                 = Guid.NewGuid().ToString("N"),
                AccountId          = Accounts[0].Id,
                ClientId           = Accounts[0].ClientId,
                TradingConditionId = MarginTradingTestsUtils.TradingConditionId,
                AccountAssetId     = Accounts[0].BaseAssetId,
                Instrument         = instrument,
                Volume             = 150000,
                FillType           = OrderFillType.FillOrKill,
            };

            var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.Validate(order));

            Assert.That(ex.RejectReason == OrderRejectReason.NotEnoughBalance);
        }
Ejemplo n.º 8
0
        private void UpdateBestPrice()
        {
            var newBestPrice = new InstrumentBidAskPair
            {
                Instrument = Instrument,
                Date       = DateTime.UtcNow
            };

            if (Sell.Any())
            {
                var fl = Sell.First();
                newBestPrice.Ask = fl.Key;
                newBestPrice.AskFirstLevelVolume = fl.Value.Sum(o => Math.Abs(o.Volume));
            }
            else
            {
                newBestPrice.Ask = BestPrice?.Ask ?? 0;
            }

            if (Buy.Any())
            {
                var fl = Buy.First();
                newBestPrice.Bid = fl.Key;
                newBestPrice.BidFirstLevelVolume = fl.Value.Sum(o => Math.Abs(o.Volume));
            }
            else
            {
                newBestPrice.Bid = BestPrice?.Bid ?? 0;
            }

            if (newBestPrice.Ask > 0 && newBestPrice.Bid > 0)
            {
                BestPrice = newBestPrice;
            }
        }
Ejemplo n.º 9
0
        public void Is_Sell_Order_ExpectedOpenPrice_Invalid()
        {
            const string instrument = "EURUSD";
            var          quote      = new InstrumentBidAskPair {
                Instrument = instrument, Bid = 1.55M, Ask = 1.57M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));

            var order = new Order
            {
                CreateDate         = DateTime.UtcNow,
                Id                 = Guid.NewGuid().ToString("N"),
                AccountId          = Accounts[0].Id,
                ClientId           = Accounts[0].ClientId,
                TradingConditionId = MarginTradingTestsUtils.TradingConditionId,
                AccountAssetId     = Accounts[0].BaseAssetId,
                Instrument         = instrument,
                Volume             = -10,
                ExpectedOpenPrice  = 1.54532567434M,
                FillType           = OrderFillType.FillOrKill
            };

            var ex = Assert.Throws <ValidateOrderException>(() => _validateOrderService.Validate(order));

            Assert.That(ex.RejectReason == OrderRejectReason.InvalidExpectedOpenPrice);
            StringAssert.Contains($"{quote.Bid}/{quote.Ask}", ex.Comment);
        }
Ejemplo n.º 10
0
        private void ProcessPositions(InstrumentBidAskPair quote)
        {
            var stopoutAccounts = UpdateClosePriceAndDetectStopout(quote);

            foreach (var account in stopoutAccounts)
            {
                CommitStopOut(account, quote);
            }
        }
Ejemplo n.º 11
0
 public OrderBook(string instrument)
 {
     Instrument = instrument;
     Buy        = new SortedDictionary <decimal, List <LimitOrder> >(new ReverseComparer <decimal>(Comparer <decimal> .Default));
     Sell       = new SortedDictionary <decimal, List <LimitOrder> >();
     BestPrice  = new InstrumentBidAskPair {
         Instrument = instrument, Date = DateTime.UtcNow
     };
 }
Ejemplo n.º 12
0
 public static BidAskClientContract ToClientContract(this InstrumentBidAskPair src)
 {
     return(new BidAskClientContract
     {
         Id = src.Instrument,
         Date = src.Date,
         Bid = src.Bid,
         Ask = src.Ask
     });
 }
Ejemplo n.º 13
0
//        private void ProcessPendingOrdersMarginRecalc(string instrument)
//        {
//            var pendingOrders = _ordersCache.GetPendingForMarginRecalc(instrument);
//
//            foreach (var pendingOrder in pendingOrders)
//            {
//                pendingOrder.UpdatePendingOrderMargin();
//            }
//        }

        #endregion


        #region Positions

        private void UpdatePositionsFxRates(InstrumentBidAskPair quote)
        {
            foreach (var position in _ordersCache.GetPositionsByFxAssetPairId(quote.Instrument))
            {
                var fxPrice = _cfdCalculatorService.GetPrice(quote, position.FxToAssetPairDirection,
                                                             position.Volume * (position.ClosePrice - position.OpenPrice) > 0);

                position.UpdateCloseFxPrice(fxPrice);
            }
        }
Ejemplo n.º 14
0
        private void WriteMessage(InstrumentBidAskPair quote, string message, EventTypeEnum eventType)
        {
            _log.WriteInfoAsync(nameof(QuotesMonitor), quote.ToJson(), message);
            var slackChannelType = _alertSeverityLevelService.GetSlackChannelType(eventType);

            if (!string.IsNullOrWhiteSpace(slackChannelType))
            {
                _slackNotificationsSender.SendRawAsync(slackChannelType, nameof(QuotesMonitor), message);
            }
        }
Ejemplo n.º 15
0
 public static InstrumentBidAskPairContract ToBackendContract(this InstrumentBidAskPair src)
 {
     return(new InstrumentBidAskPairContract
     {
         Id = src.Instrument,
         Date = src.Date,
         Bid = src.Bid,
         Ask = src.Ask
     });
 }
Ejemplo n.º 16
0
 public static BestPriceContract ConvertToContract(this InstrumentBidAskPair arg)
 {
     return(new BestPriceContract
     {
         Ask = arg.Ask,
         Bid = arg.Bid,
         Id = arg.Instrument,
         Timestamp = arg.Date,
     });
 }
Ejemplo n.º 17
0
 public static BidAskPairRabbitMqContract ToRabbitMqContract(this InstrumentBidAskPair pair)
 {
     return(new BidAskPairRabbitMqContract
     {
         Instrument = pair.Instrument,
         Ask = pair.Ask,
         Bid = pair.Bid,
         Date = pair.Date
     });
 }
Ejemplo n.º 18
0
        private List <MarginTradingAccount> UpdateClosePriceAndDetectStopout(InstrumentBidAskPair quote)
        {
            var positionsByAccounts = _ordersCache.Positions.GetPositionsByInstrument(quote.Instrument)
                                      .GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.ToArray());

            var accountsWithStopout = new List <MarginTradingAccount>();

            foreach (var accountPositions in positionsByAccounts)
            {
                var account         = _accountsCacheService.Get(accountPositions.Key);
                var oldAccountLevel = account.GetAccountLevel();

                foreach (var position in accountPositions.Value)
                {
                    var closeOrderDirection = position.Volume.GetClosePositionOrderDirection();
                    var closePrice          = quote.GetPriceForOrderDirection(closeOrderDirection);

                    if (quote.GetVolumeForOrderDirection(closeOrderDirection) < Math.Abs(position.Volume))
                    {
                        var defaultMatchingEngine = _meRouter.GetMatchingEngineForClose(position.OpenMatchingEngineId);

                        var orderbookPrice = defaultMatchingEngine.GetPriceForClose(position.AssetPairId, position.Volume,
                                                                                    position.ExternalProviderId);

                        if (orderbookPrice.HasValue)
                        {
                            closePrice = orderbookPrice.Value;
                        }
                    }

                    if (closePrice != 0)
                    {
                        position.UpdateClosePriceWithoutAccountUpdate(closePrice);

                        UpdateTrailingStops(position);
                    }
                }

                account.CacheNeedsToBeUpdated();

                var newAccountLevel = account.GetAccountLevel();

                if (newAccountLevel == AccountLevel.StopOut)
                {
                    accountsWithStopout.Add(account);
                }

                if (oldAccountLevel != newAccountLevel)
                {
                    _marginCallEventChannel.SendEvent(this, new MarginCallEventArgs(account, newAccountLevel));
                }
            }

            return(accountsWithStopout);
        }
Ejemplo n.º 19
0
 public static BidAskPairRabbitMqContract ToRabbitMqContract(this InstrumentBidAskPair pair, bool isEod)
 {
     return(new BidAskPairRabbitMqContract
     {
         Instrument = pair.Instrument,
         Ask = pair.Ask,
         Bid = pair.Bid,
         Date = pair.Date,
         IsEod = isEod ? true : (bool?)null,
     });
 }
Ejemplo n.º 20
0
 public decimal GetPrice(InstrumentBidAskPair quote, FxToAssetPairDirection direction,
                         bool metricIsPositive = true)
 {
     return(metricIsPositive
         ? direction == FxToAssetPairDirection.Straight
             ? quote.Ask
             : 1 / quote.Bid
         : direction == FxToAssetPairDirection.Straight
             ? quote.Bid
             : 1 / quote.Ask);
 }
Ejemplo n.º 21
0
        private void NotifyQuoteIsOutdated(InstrumentBidAskPair quote)
        {
            var message = $"Quotes for {quote.Instrument} stopped at {quote.Date}!";

            WriteMessage(quote, message, EventTypeEnum.QuoteStopped);
            var info = new OutdatedQuoteInfo
            {
                LastQuoteRecieved    = quote.Date,
                LastNotificationSend = _dateService.Now()
            };

            _outdatedQuotes[quote.Instrument] = info;
        }
Ejemplo n.º 22
0
        private void UpdateBestPrice()
        {
            var newBestPrice = new InstrumentBidAskPair
            {
                Instrument = Instrument,
                Ask        = Sell.Any() ? Sell.First().Key : BestPrice?.Ask ?? 0,
                Bid        = Buy.Any() ? Buy.First().Key : BestPrice?.Bid ?? 0,
                Date       = DateTime.UtcNow
            };

            if (newBestPrice.Ask > 0 && newBestPrice.Bid > 0)
            {
                BestPrice = newBestPrice;
            }
        }
Ejemplo n.º 23
0
        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);
        }
Ejemplo n.º 24
0
        private void SetupAssetPair(string id, bool isDiscontinued = false, bool isFrozen = false,
                                    bool isSuspended = false)
        {
            var pair = _assetPairsCache.GetAssetPairById(id);

            _assetPairsCache.AddOrUpdate(
                new AssetPair(pair.Id, pair.Name, pair.BaseAssetId, pair.QuoteAssetId,
                              pair.Accuracy, pair.LegalEntity, pair.BaseAssetId, pair.MatchingEngineMode,
                              pair.StpMultiplierMarkupAsk, pair.StpMultiplierMarkupBid,
                              isSuspended, isFrozen, isDiscontinued));

            var quote = new InstrumentBidAskPair {
                Instrument = id, Bid = 1.55M, Ask = 1.57M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));
        }
Ejemplo n.º 25
0
        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));
        }
Ejemplo n.º 26
0
        public void SetOrderbook(ExternalOrderBook orderbook)
        {
            if (!ValidateOrderbook(orderbook))
            {
                return;
            }

            var bba = new InstrumentBidAskPair
            {
                Bid        = 0,
                Ask        = decimal.MaxValue,
                Date       = _dateService.Now(),
                Instrument = orderbook.AssetPairId
            };

            Dictionary <string, ExternalOrderBook> UpdateOrderbooksDictionary(string assetPairId,
                                                                              Dictionary <string, ExternalOrderBook> dict)
            {
                dict[orderbook.ExchangeName] = orderbook;
                foreach (var pair in dict.Values.RequiredNotNullOrEmptyCollection(nameof(dict)))
                {
                    // guaranteed to be sorted best first
                    var bestBid = pair.Bids.First().Price;
                    var bestAsk = pair.Asks.First().Price;
                    if (bestBid > bba.Bid)
                    {
                        bba.Bid = bestBid;
                    }

                    if (bestAsk < bba.Ask)
                    {
                        bba.Ask = bestAsk;
                    }
                }

                return(dict);
            }

            _orderbooks.AddOrUpdate(orderbook.AssetPairId,
                                    k => UpdateOrderbooksDictionary(k, new Dictionary <string, ExternalOrderBook>()),
                                    UpdateOrderbooksDictionary);

            _bestPriceChangeEventChannel.SendEvent(this, new BestPriceChangeEventArgs(bba));
        }
Ejemplo n.º 27
0
        public bool TryGetQuoteById(string instrument, out InstrumentBidAskPair result)
        {
            _lockSlim.EnterReadLock();
            try
            {
                if (!_cache.TryGetValue(instrument, out var quote))
                {
                    result = null;
                    return(false);
                }

                result = quote;
                return(true);
            }
            finally
            {
                _lockSlim.ExitReadLock();
            }
        }
Ejemplo n.º 28
0
        public void Is_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 request = new OrderPlaceRequest
            {
                AccountId     = Accounts[0].Id,
                CorrelationId = Guid.NewGuid().ToString(),
                Direction     = OrderDirectionContract.Buy,
                InstrumentId  = instrument,
                Type          = OrderTypeContract.Market,
                Volume        = volume
            };

            if (isValid)
            {
                Assert.DoesNotThrow(
                    () =>
                {
                    var order = _validateOrderService.ValidateRequestAndCreateOrders(request).Result.order;
                    _validateOrderService.MakePreTradeValidation(order, true, _me);
                });
            }
            else
            {
                var ex = Assert.ThrowsAsync <ValidateOrderException>(
                    async() =>
                {
                    var order = (await _validateOrderService.ValidateRequestAndCreateOrders(request)).order;
                    _validateOrderService.MakePreTradeValidation(order, true, _me);
                });

                Assert.That(ex.RejectReason ==
                            (volume == 0 ? OrderRejectReason.InvalidVolume : OrderRejectReason.MaxOrderSizeLimit));
            }
        }
Ejemplo n.º 29
0
        private void ProcessOrdersWaitingForExecution(InstrumentBidAskPair quote)
        {
            //TODO: MTC-155
            //ProcessPendingOrdersMarginRecalc(instrument);

            var orders = GetPendingOrdersToBeExecuted(quote).GetSortedForExecution();

            if (!orders.Any())
            {
                return;
            }

            foreach (var order in orders)
            {
                _threadSwitcher.SwitchThread(async() =>
                {
                    await PlaceOrderByMarketPrice(order);
                });
            }
        }
Ejemplo n.º 30
0
        public void Is_ValidityDate_Valid_ForNotMarket()
        {
            var quote = new InstrumentBidAskPair {
                Instrument = "BTCUSD", Bid = 1.55M, Ask = 1.57M
            };

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(quote));

            var request = new OrderPlaceRequest
            {
                AccountId    = Accounts[0].Id,
                Direction    = OrderDirectionContract.Buy,
                InstrumentId = "BTCUSD",
                Type         = OrderTypeContract.Limit,
                Price        = 1,
                Validity     = DateTime.UtcNow.Date,
                Volume       = 10
            };

            Assert.DoesNotThrowAsync(async() =>
                                     await _validateOrderService.ValidateRequestAndCreateOrders(request));
        }