Esempio n. 1
0
        public async Task <Order> PlaceOrderAsync(Order order)
        {
            _orderPlacedEventChannel.SendEvent(this, new OrderPlacedEventArgs(order));

            try
            {
                if (order.OrderType != OrderType.Market)
                {
                    await PlacePendingOrder(order);

                    return(order);
                }

                return(await PlaceOrderByMarketPrice(order));
            }
            catch (ValidateOrderException ex)
            {
                RejectOrder(order, ex.RejectReason, ex.Message, ex.Comment);
                return(order);
            }
            catch (Exception ex)
            {
                RejectOrder(order, OrderRejectReason.TechnicalError, ex.Message);
                _log.WriteError(nameof(TradingEngine), nameof(PlaceOrderByMarketPrice), ex);
                return(order);
            }
        }
Esempio n. 2
0
        public void Is_Fpl_Buy_Correct()
        {
            const string instrument = "BTCUSD";

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = instrument, Ask = 800, Bid = 790
            }));

            var order = new Order
            {
                Id                 = Guid.NewGuid().ToString(),
                AccountId          = Accounts[0].Id,
                ClientId           = Accounts[0].ClientId,
                AccountAssetId     = Accounts[0].BaseAssetId,
                TradingConditionId = Accounts[0].TradingConditionId,
                Instrument         = instrument,
                Volume             = 10,
                MatchedOrders      = new MatchedOrderCollection(new List <MatchedOrder> {
                    new MatchedOrder {
                        MatchedDate = DateTime.UtcNow, Volume = 10
                    }
                }),                                                                                                                                      //need for GetMatchedVolume()
                OpenPrice   = 790,
                LegalEntity = "LYKKEVU",
                Status      = OrderStatus.Active,
            };

            order.UpdateClosePrice(800);

            Assert.AreEqual(100, order.GetFpl());
        }
Esempio n. 3
0
        public async Task OvernightSwapCalculation_Success()
        {
            _bestPriceConsumer.SendEvent(this,
                                         new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = "BTCUSD", Bid = 9000M, Ask = 9010M
            }));

            await _accountAssetsRepository.AddOrReplaceAsync(new AccountAssetPair
            {
                TradingConditionId  = MarginTradingTestsUtils.TradingConditionId,
                BaseAssetId         = "USD",
                Instrument          = "BTCUSD",
                LeverageInit        = 100,
                LeverageMaintenance = 150,
                SwapLong            = 100,
                SwapShort           = 100,
                OvernightSwapLong   = 1,
                OvernightSwapShort  = 1
            });

            await _accountAssetsManager.UpdateAccountAssetsCache();

            var accountId = (await _fakeMarginTradingAccountsRepository.GetAllAsync("1"))
                            .First(x => x.ClientId == "1" && x.BaseAssetId == "USD").Id;

            _ordersCache.ActiveOrders.Add(new Order
            {
                Id                 = "1",
                AccountId          = accountId,
                Instrument         = "BTCUSD",
                ClientId           = "1",
                TradingConditionId = "1",
                AccountAssetId     = "USD",
                Volume             = 1,
                OpenDate           = new DateTime(2017, 01, 01, 20, 50, 0),
                CloseDate          = new DateTime(2017, 01, 02, 20, 50, 0),
                MatchedOrders      = new MatchedOrderCollection(new List <MatchedOrder> {
                    new MatchedOrder()
                    {
                        Volume = 1
                    }
                }),
                LegalEntity = "LYKKETEST",
            });

            var accountBalance = (await _fakeMarginTradingAccountsRepository.GetAsync(accountId)).Balance;

            _overnightSwapService.CalculateAndChargeSwaps();

            var calc = _overnightSwapCache.GetAll().First();

            Assert.AreEqual(24.68493151M, calc.Value);
            Assert.True(calc.IsSuccess);
            Assert.AreEqual(accountBalance - 24.68493151M, (await _fakeMarginTradingAccountsRepository.GetAsync(accountId)).Balance);
        }
Esempio 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);
            }
        }
Esempio n. 5
0
        private Task <Order> PlaceMarketOrderByMatchingEngineAsync(Order order, IMatchingEngineBase matchingEngine)
        {
            order.OpenOrderbookId    = matchingEngine.Id;
            order.MatchingEngineMode = matchingEngine.Mode;

            matchingEngine.MatchMarketOrderForOpen(order, matchedOrders =>
            {
                if (!matchedOrders.Any())
                {
                    order.CloseDate        = DateTime.UtcNow;
                    order.Status           = OrderStatus.Rejected;
                    order.RejectReason     = OrderRejectReason.NoLiquidity;
                    order.RejectReasonText = "No orders to match";
                    return(false);
                }

                if (matchedOrders.SummaryVolume < Math.Abs(order.Volume) && order.FillType == OrderFillType.FillOrKill)
                {
                    order.CloseDate        = DateTime.UtcNow;
                    order.Status           = OrderStatus.Rejected;
                    order.RejectReason     = OrderRejectReason.NoLiquidity;
                    order.RejectReasonText = "Not fully matched";
                    return(false);
                }

                try
                {
                    CheckIfWeCanOpenPosition(order, matchedOrders);
                }
                catch (ValidateOrderException e)
                {
                    order.CloseDate        = DateTime.UtcNow;
                    order.Status           = OrderStatus.Rejected;
                    order.RejectReason     = e.RejectReason;
                    order.RejectReasonText = e.Message;
                    return(false);
                }

                _equivalentPricesService.EnrichOpeningOrder(order);

                MakeOrderActive(order);

                return(true);
            });

            if (order.Status == OrderStatus.Rejected)
            {
                _orderRejectedEventChannel.SendEvent(this, new OrderRejectedEventArgs(order));
            }

            return(Task.FromResult(order));
        }
Esempio n. 6
0
        public void Is_Quote_Returned()
        {
            const string instrument = "EURUSD";

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = instrument, Ask = 1.05M, Bid = 1.04M
            }));

            var quote = _quoteCacheService.GetQuote(instrument);

            Assert.IsNotNull(quote);
            Assert.AreEqual(1.04, quote.Bid);
            Assert.AreEqual(1.05, quote.Ask);
        }
Esempio n. 7
0
        private void CancelRelatedOrdersForPosition(Position position, OrderCancellationReason reason)
        {
            var metadata = new OrderCancelledMetadata {
                Reason = reason.ToType <OrderCancellationReasonContract>()
            };

            foreach (var relatedOrderInfo in position.RelatedOrders)
            {
                if (_ordersCache.Active.TryPopById(relatedOrderInfo.Id, out var relatedOrder))
                {
                    relatedOrder.Cancel(_dateService.Now(), null);
                    _orderCancelledEventChannel.SendEvent(this, new OrderCancelledEventArgs(relatedOrder, metadata));
                }
            }
        }
Esempio n. 8
0
        public Task SetQuote(ExternalExchangeOrderbookMessage orderBookMessage)
        {
            var isDayOff       = _assetPairDayOffService.IsDayOff(orderBookMessage.AssetPairId);
            var isEodOrderbook = orderBookMessage.ExchangeName == ExternalOrderbookService.EodExternalExchange;

            // we should process normal orderbook only if asset is currently tradable
            if (isDayOff && !isEodOrderbook)
            {
                return(Task.CompletedTask);
            }

            // and process EOD orderbook only if asset is currently not tradable
            if (!isDayOff && isEodOrderbook)
            {
                _log.WriteWarning("EOD FX quotes processing", "",
                                  $"EOD FX quote for {orderBookMessage.AssetPairId} is skipped, because instrument is within trading hours");

                return(Task.CompletedTask);
            }

            var bidAskPair = CreatePair(orderBookMessage);

            if (bidAskPair == null)
            {
                return(Task.CompletedTask);
            }

            SetQuote(bidAskPair);

            _fxBestPriceChangeEventChannel.SendEvent(this, new FxBestPriceChangeEventArgs(bidAskPair));

            return(Task.CompletedTask);
        }
Esempio n. 9
0
        private void CommitStopout(MarginTradingAccount account)
        {
            var activeOrders = _ordersCache.ActiveOrders.GetOrdersByAccountIds(account.Id);

            var ordersToClose        = new List <Order>();
            var newAccountUsedMargin = account.GetUsedMargin();

            foreach (var order in activeOrders.OrderBy(o => o.GetTotalFpl()))
            {
                if (newAccountUsedMargin <= 0 ||
                    account.GetTotalCapital() / newAccountUsedMargin > account.GetMarginCallLevel())
                {
                    break;
                }

                ordersToClose.Add(order);
                newAccountUsedMargin -= order.GetMarginMaintenance();
            }

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

            _stopoutEventChannel.SendEvent(this, new StopOutEventArgs(account, ordersToClose.ToArray()));

            foreach (var order in ordersToClose)
            {
                SetOrderToClosingState(order, OrderCloseReason.StopOut);
            }
        }
Esempio n. 10
0
        public void ChangeOrderLimits(string orderId, decimal?stopLoss, decimal?takeProfit, decimal?expectedOpenPrice)
        {
            using (_contextFactory.GetWriteSyncContext($"{nameof(TradingEngine)}.{nameof(ChangeOrderLimits)}"))
            {
                var order = _ordersCache.GetOrderById(orderId);

                if (order.Status != OrderStatus.WaitingForExecution && expectedOpenPrice > 0)
                {
                    return;
                }

                var quote        = _quoteCashService.GetQuote(order.Instrument);
                var tp           = takeProfit == 0 ? null : takeProfit;
                var sl           = stopLoss == 0 ? null : stopLoss;
                var expOpenPrice = expectedOpenPrice == 0 ? null : expectedOpenPrice;

                var accountAsset = _accountAssetsCacheService.GetAccountAsset(order.TradingConditionId,
                                                                              order.AccountAssetId, order.Instrument);

                _validateOrderService.ValidateOrderStops(order.GetOrderType(), quote,
                                                         accountAsset.DeltaBid, accountAsset.DeltaAsk, tp, sl, expOpenPrice, order.AssetAccuracy);

                order.TakeProfit        = tp.HasValue ? Math.Round(tp.Value, order.AssetAccuracy) : (decimal?)null;
                order.StopLoss          = sl.HasValue ? Math.Round(sl.Value, order.AssetAccuracy) : (decimal?)null;
                order.ExpectedOpenPrice = expOpenPrice.HasValue ? Math.Round(expOpenPrice.Value, order.AssetAccuracy) : (decimal?)null;
                _orderLimitsChangesEventChannel.SendEvent(this, new OrderLimitsChangedEventArgs(order));
            }
        }
Esempio n. 11
0
        public async Task Is_Swaps_Correct()
        {
            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = "EURUSD", Bid = 1.02M, Ask = 1.04M
            }));

            _accountAssetsRepository.AddOrReplaceAsync(new AccountAssetPair
            {
                TradingConditionId  = MarginTradingTestsUtils.TradingConditionId,
                BaseAssetId         = "USD",
                Instrument          = "EURUSD",
                LeverageInit        = 100,
                LeverageMaintenance = 150,
                SwapLong            = 100,
                SwapShort           = 100
            }).Wait();

            await _accountAssetsManager.UpdateAccountAssetsCache();

            var dayOrder = new Order
            {
                AccountAssetId = "USD",
                Instrument     = "EURUSD",
                Volume         = 20,
                OpenDate       = new DateTime(2017, 01, 01, 20, 50, 0),
                CloseDate      = new DateTime(2017, 01, 02, 20, 50, 0),
                MatchedOrders  = new MatchedOrderCollection(new List <MatchedOrder> {
                    new MatchedOrder()
                    {
                        Volume = 20
                    }
                }),
                SwapCommission = 100
            };

            var swapsForDay = _swapService.GetSwaps(dayOrder);

            var twoDayOrder = new Order
            {
                AccountAssetId = "USD",
                Instrument     = "EURUSD",
                Volume         = 20,
                OpenDate       = new DateTime(2017, 01, 01, 20, 50, 0),
                CloseDate      = new DateTime(2017, 01, 03, 20, 50, 0),
                MatchedOrders  = new MatchedOrderCollection(new List <MatchedOrder>()
                {
                    new MatchedOrder()
                    {
                        Volume = 20
                    }
                }),
                SwapCommission = 100
            };

            var swapsFor2Days = _swapService.GetSwaps(twoDayOrder);

            Assert.AreEqual(5.69863014m, swapsForDay);
            Assert.AreEqual(11.39726027m, swapsFor2Days);
        }
Esempio n. 12
0
        private void ProduceBestPrice(string instrument)
        {
            var bestPrice = _orderBooks.GetBestPrice(instrument);

            if (bestPrice != null)
            {
                _bestPriceChangeEventChannel.SendEvent(this, new BestPriceChangeEventArgs(bestPrice));
            }
        }
Esempio n. 13
0
 private void NotifyAccountLevelChanged(MarginTradingAccount account, AccountLevel newAccountLevel)
 {
     switch (newAccountLevel)
     {
     case AccountLevel.MarginCall:
         _marginCallEventChannel.SendEvent(this, new MarginCallEventArgs(account));
         break;
     }
 }
Esempio n. 14
0
        public async Task Is_Swaps_Correct()
        {
            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = "EURUSD", Bid = 1.02M, Ask = 1.04M
            }));

            var instrumentContract = new TradingInstrumentContract
            {
                TradingConditionId  = MarginTradingTestsUtils.TradingConditionId,
                Instrument          = "EURUSD",
                LeverageInit        = 100,
                LeverageMaintenance = 150,
                SwapLong            = 100,
                SwapShort           = 100
            };

            Mock.Get(_tradingInstruments).Setup(s => s.List(It.IsAny <string>()))
            .ReturnsAsync(new List <TradingInstrumentContract> {
                instrumentContract
            });

            await _accountAssetsManager.UpdateTradingInstrumentsCacheAsync();



            var dayPosition = new Position(Guid.NewGuid().ToString("N"), 0, "EURUSD", 20, Accounts[0].Id,
                                           MarginTradingTestsUtils.TradingConditionId, Accounts[0].BaseAssetId, null, MatchingEngineConstants.DefaultMm,
                                           new DateTime(2017, 01, 01, 20, 50, 0), "OpenTrade", OrderType.Market, 20, 1, 1, "USD", 1,
                                           new List <RelatedOrderInfo>(), "LYKKETEST", OriginatorType.Investor, "", "EURUSD", FxToAssetPairDirection.Straight, "");

            dayPosition.SetCommissionRates(100, 0, 0, 1);

            dayPosition.StartClosing(new DateTime(2017, 01, 02, 20, 50, 0), PositionCloseReason.Close,
                                     OriginatorType.Investor, "");
            dayPosition.Close(new DateTime(2017, 01, 02, 20, 50, 0), MatchingEngineConstants.DefaultMm, 2, 1, 1, OriginatorType.Investor,
                              PositionCloseReason.Close, "", "CloseTrade");

            var swapsForDay = _swapService.GetSwaps(dayPosition);

            var twoDayPosition = new Position(Guid.NewGuid().ToString("N"), 0, "EURUSD", 20, Accounts[0].Id,
                                              MarginTradingTestsUtils.TradingConditionId, Accounts[0].BaseAssetId, null, MatchingEngineConstants.DefaultMm,
                                              new DateTime(2017, 01, 01, 20, 50, 0), "OpenTrade", OrderType.Market, 20, 1, 1, "USD", 1,
                                              new List <RelatedOrderInfo>(), "LYKKETEST", OriginatorType.Investor, "", "EURUSD", FxToAssetPairDirection.Straight, "");

            twoDayPosition.SetCommissionRates(100, 0, 0, 1);

            twoDayPosition.StartClosing(new DateTime(2017, 01, 03, 20, 50, 0), PositionCloseReason.Close,
                                        OriginatorType.Investor, "");
            twoDayPosition.Close(new DateTime(2017, 01, 03, 20, 50, 0), MatchingEngineConstants.DefaultMm, 2, 1, 1, OriginatorType.Investor,
                                 PositionCloseReason.Close, "", "CloseTrade");

            var swapsFor2Days = _swapService.GetSwaps(twoDayPosition);

            Assert.AreEqual(5.69863014m, swapsForDay);
            Assert.AreEqual(11.39726027m, swapsFor2Days);
        }
Esempio n. 15
0
        private void CancelWaitingForExecutionOrder(Order order, OrderCloseReason reason)
        {
            order.Status      = OrderStatus.Closed;
            order.CloseDate   = DateTime.UtcNow;
            order.CloseReason = reason;

            _ordersCache.WaitingForExecutionOrders.Remove(order);

            _orderCancelledEventChannel.SendEvent(this, new OrderCancelledEventArgs(order));
        }
Esempio n. 16
0
        private void MakeOrderActive(Order order)
        {
            order.OpenDate = DateTime.UtcNow;
            order.Status   = OrderStatus.Active;

            var account = _accountsCacheService.Get(order.ClientId, order.AccountId);

            _swapCommissionService.SetCommissionRates(account.TradingConditionId, account.BaseAssetId, order);
            _ordersCache.ActiveOrders.Add(order);
            _orderActivatedEventChannel.SendEvent(this, new OrderActivatedEventArgs(order));
        }
Esempio n. 17
0
        private void PlacePendingOrder(Order order)
        {
            var me = _meRouter.GetMatchingEngineForOpen(order);

            order.MatchingEngineMode = me.Mode;

            using (_contextFactory.GetWriteSyncContext($"{nameof(TradingEngine)}.{nameof(PlacePendingOrder)}"))
                _ordersCache.WaitingForExecutionOrders.Add(order);

            _orderPlacedEventChannel.SendEvent(this, new OrderPlacedEventArgs(order));
        }
        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,
                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, 0);
                });
            }
            else
            {
                var ex = Assert.ThrowsAsync <ValidateOrderException>(
                    async() =>
                {
                    var order = (await _validateOrderService.ValidateRequestAndCreateOrders(request)).order;
                    _validateOrderService.MakePreTradeValidation(order, true, _me, 0);
                });

                Assert.That(ex.RejectReason ==
                            (volume == 0 ? OrderRejectReason.InvalidVolume : OrderRejectReason.MaxOrderSizeLimit));
            }
        }
Esempio n. 19
0
        private void CancelRelatedOrders(List <RelatedOrderInfo> relatedOrderInfos, OrderCancellationReason reason)
        {
            var metadata = new OrderCancelledMetadata
            {
                Reason = reason.ToType <OrderCancellationReasonContract>()
            };

            foreach (var relatedOrderInfo in relatedOrderInfos)
            {
                if (_ordersCache.Inactive.TryPopById(relatedOrderInfo.Id, out var inactiveRelatedOrder))
                {
                    inactiveRelatedOrder.Cancel(_dateService.Now(), null);
                    _orderCancelledEventChannel.SendEvent(this, new OrderCancelledEventArgs(inactiveRelatedOrder, metadata));
                }
                else if (_ordersCache.Active.TryPopById(relatedOrderInfo.Id, out var activeRelatedOrder))
                {
                    activeRelatedOrder.Cancel(_dateService.Now(), null);
                    _orderCancelledEventChannel.SendEvent(this, new OrderCancelledEventArgs(activeRelatedOrder, metadata));
                }
            }
        }
Esempio n. 20
0
 private void ActivateRelatedOrders(Position position)
 {
     foreach (var relatedOrderInfo in position.RelatedOrders)
     {
         if (_ordersCache.Inactive.TryPopById(relatedOrderInfo.Id, out var relatedOrder))
         {
             relatedOrder.Activate(_dateService.Now(), true, position.ClosePrice);
             _ordersCache.Active.Add(relatedOrder);
             _orderActivatedEventChannel.SendEvent(this, new OrderActivatedEventArgs(relatedOrder));
         }
     }
 }
Esempio n. 21
0
        private Task <Order> CloseActiveOrderByMatchingEngineAsync(Order order, IMatchingEngineBase matchingEngine, OrderCloseReason reason, string comment)
        {
            order.CloseOrderbookId = matchingEngine.Id;
            order.StartClosingDate = DateTime.UtcNow;
            order.CloseReason      = reason;
            order.Comment          = comment;

            matchingEngine.MatchMarketOrderForClose(order, matchedOrders =>
            {
                if (!matchedOrders.Any())
                {
                    order.CloseRejectReasonText = "No orders to match";
                    return(false);
                }

                order.MatchedCloseOrders.AddRange(matchedOrders);

                _equivalentPricesService.EnrichClosingOrder(order);

                if (!order.GetIsCloseFullfilled())
                {
                    order.Status = OrderStatus.Closing;
                    _ordersCache.ActiveOrders.Remove(order);
                    _ordersCache.ClosingOrders.Add(order);
                    _orderClosingEventChannel.SendEvent(this, new OrderClosingEventArgs(order));
                }
                else
                {
                    order.Status    = OrderStatus.Closed;
                    order.CloseDate = DateTime.UtcNow;
                    _ordersCache.ActiveOrders.Remove(order);
                    _orderClosedEventChannel.SendEvent(this, new OrderClosedEventArgs(order));
                }

                return(true);
            });

            return(Task.FromResult(order));
        }
Esempio n. 22
0
        public async Task <string> UpdateBalanceAsync(IMarginTradingAccount account, decimal amount, AccountHistoryType historyType,
                                                      string comment, string eventSourceId = null, bool changeTransferLimit = false, string auditLog = null)
        {
            if (historyType == AccountHistoryType.Deposit && changeTransferLimit)
            {
                CheckDepositLimits(account, amount);
            }

            if (changeTransferLimit)
            {
                CheckTransferLimits(account, amount);
            }

            var semaphore = GetSemaphore(account);

            await semaphore.WaitAsync();

            try
            {
                var updatedAccount =
                    await _repository.UpdateBalanceAsync(account.ClientId, account.Id, amount, changeTransferLimit);

                _acountBalanceChangedEventChannel.SendEvent(this, new AccountBalanceChangedEventArgs(updatedAccount));
                //todo: move to separate event consumers
                _accountsCacheService.UpdateBalance(updatedAccount);
                _clientNotifyService.NotifyAccountUpdated(updatedAccount);

                var transactionId = Guid.NewGuid().ToString("N");

                await _rabbitMqNotifyService.AccountHistory(
                    transactionId,
                    account.Id,
                    account.ClientId,
                    amount,
                    updatedAccount.Balance,
                    updatedAccount.WithdrawTransferLimit,
                    historyType,
                    _equivalentPricesService.GetUsdEquivalent(amount, account.BaseAssetId, account.LegalEntity),
                    comment,
                    eventSourceId,
                    account.LegalEntity,
                    auditLog);

                return(transactionId);
            }
            finally
            {
                semaphore.Release();
            }
        }
Esempio n. 23
0
        private void HandleOvernightMarginWarnings()
        {
            foreach (var account in _accountsCacheService.GetAll())
            {
                var accountOvernightUsedMargin = _accountUpdateService.CalculateOvernightUsedMargin(account);
                var accountLevel = account.GetAccountLevel(accountOvernightUsedMargin);

                if (accountLevel == AccountLevel.StopOut)
                {
                    _marginCallEventChannel.SendEvent(this,
                                                      new MarginCallEventArgs(account, AccountLevel.OvernightMarginCall));
                }
            }
        }
Esempio n. 24
0
        public void SetOrderbook(ExternalOrderBook orderbook)
        {
            var isEodOrderbook = orderbook.ExchangeName == ExternalOrderbookService.EodExternalExchange;

            var instrumentTradingStatus = _assetPairDayOffService.IsAssetTradingDisabled(orderbook.AssetPairId);

            if (!isEodOrderbook &&
                !instrumentTradingStatus.TradingEnabled &&
                instrumentTradingStatus.Reason == InstrumentTradingDisabledReason.InstrumentTradingDisabled)
            {
                return;
            }

            if (_orderbookValidation.ValidateInstrumentStatusForEodQuotes && isEodOrderbook ||
                _orderbookValidation.ValidateInstrumentStatusForTradingQuotes && !isEodOrderbook)
            {
                // we should process normal orderbook only if instrument is currently tradable
                if (_orderbookValidation.ValidateInstrumentStatusForTradingQuotes && instrumentTradingStatus && !isEodOrderbook)
                {
                    return;
                }

                // and process EOD orderbook only if instrument is currently not tradable
                if (_orderbookValidation.ValidateInstrumentStatusForEodQuotes && !instrumentTradingStatus && isEodOrderbook)
                {
                    //log current schedule for the instrument
                    var schedule = _scheduleSettingsCache.GetMarketTradingScheduleByAssetPair(orderbook.AssetPairId);

                    _log.WriteWarning("EOD quotes processing", $"Current schedule for the instrument's market: {schedule.ToJson()}",
                                      $"EOD quote for {orderbook.AssetPairId} is skipped, because instrument is within trading hours");

                    return;
                }
            }

            if (!CheckZeroQuote(orderbook, isEodOrderbook))
            {
                return;
            }

            orderbook.ApplyExchangeIdFromSettings(_defaultExternalExchangeId);

            var bba = orderbook.GetBestPrice();

            _orderbooks.AddOrUpdate(orderbook.AssetPairId, a => orderbook, (s, book) => orderbook);

            _bestPriceChangeEventChannel.SendEvent(this, new BestPriceChangeEventArgs(bba, isEodOrderbook));
        }
Esempio n. 25
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));
        }
Esempio n. 26
0
        private void CommitStopout(MarginTradingAccount account)
        {
            var pendingOrders = _ordersCache.WaitingForExecutionOrders.GetOrdersByAccountIds(account.Id);

            var cancelledPendingOrders = new List <Order>();

            foreach (var pendingOrder in pendingOrders)
            {
                cancelledPendingOrders.Add(pendingOrder);
                CancelPendingOrder(pendingOrder.Id, OrderCloseReason.CanceledBySystem, "Stop out");
            }

            var activeOrders = _ordersCache.ActiveOrders.GetOrdersByAccountIds(account.Id);

            var ordersToClose        = new List <Order>();
            var newAccountUsedMargin = account.GetUsedMargin();

            foreach (var order in activeOrders.OrderBy(o => o.GetTotalFpl()))
            {
                if (newAccountUsedMargin <= 0 ||
                    account.GetTotalCapital() / newAccountUsedMargin > account.GetMarginCallLevel())
                {
                    break;
                }

                ordersToClose.Add(order);
                newAccountUsedMargin -= order.GetMarginMaintenance();
            }

            if (!ordersToClose.Any() && !cancelledPendingOrders.Any())
            {
                return;
            }

            _stopoutEventChannel.SendEvent(this,
                                           new StopOutEventArgs(account, ordersToClose.Concat(cancelledPendingOrders).ToArray()));

            foreach (var order in ordersToClose)
            {
                SetOrderToClosingState(order, OrderCloseReason.StopOut);
            }
        }
Esempio n. 27
0
        private void ChangeRelatedOrderVolume(List <RelatedOrderInfo> relatedOrderInfos, decimal newVolume)
        {
            foreach (var relatedOrderInfo in relatedOrderInfos)
            {
                if (_ordersCache.TryGetOrderById(relatedOrderInfo.Id, out var relatedOrder) &&
                    relatedOrder.Volume != newVolume)
                {
                    var oldVolume = relatedOrder.Volume;

                    relatedOrder.ChangeVolume(newVolume, _dateService.Now(), OriginatorType.System);
                    var metadata = new OrderChangedMetadata
                    {
                        UpdatedProperty = OrderChangedProperty.Volume,
                        OldValue        = oldVolume.ToString("F2")
                    };

                    _orderChangedEventChannel.SendEvent(this, new OrderChangedEventArgs(relatedOrder, metadata));
                }
            }
        }
Esempio n. 28
0
        private void RemoveRelatedOrderFromParent(Order order)
        {
            if (!string.IsNullOrEmpty(order.ParentOrderId) &&
                _ordersCache.TryGetOrderById(order.ParentOrderId, out var parentOrder))
            {
                var metadata = new OrderChangedMetadata
                {
                    UpdatedProperty = OrderChangedProperty.RelatedOrderRemoved,
                    OldValue        = order.Id
                };

                parentOrder.RemoveRelatedOrder(order.Id);
                _orderChangedEventChannel.SendEvent(this, new OrderChangedEventArgs(parentOrder, metadata));
            }

            if (!string.IsNullOrEmpty(order.ParentPositionId) &&
                _ordersCache.Positions.TryGetPositionById(order.ParentPositionId, out var parentPosition))
            {
                parentPosition.RemoveRelatedOrder(order.Id);
            }
        }
        public void SetOrderbook(ExternalOrderBook orderbook)
        {
            if (!CheckZeroQuote(orderbook))
            {
                return;
            }

            var isDayOff       = _assetPairDayOffService.IsDayOff(orderbook.AssetPairId);
            var isEodOrderbook = orderbook.ExchangeName == ExternalOrderbookService.EodExternalExchange;

            // we should process normal orderbook only if instrument is currently tradable
            if (isDayOff && !isEodOrderbook)
            {
                return;
            }

            // and process EOD orderbook only if instrument is currently not tradable
            if (!isDayOff && isEodOrderbook)
            {
                //log current schedule for the instrument
                var schedule = _scheduleSettingsCache.GetCompiledScheduleSettings(
                    orderbook.AssetPairId,
                    _dateService.Now(),
                    TimeSpan.Zero);

                _log.WriteWarning("EOD quotes processing", $"Current schedule: {schedule.ToJson()}",
                                  $"EOD quote for {orderbook.AssetPairId} is skipped, because instrument is within trading hours");

                return;
            }

            orderbook.ApplyExchangeIdFromSettings(_defaultExternalExchangeId);

            var bba = orderbook.GetBestPrice();

            _orderbooks.AddOrUpdate(orderbook.AssetPairId, a => orderbook, (s, book) => orderbook);

            _bestPriceChangeEventChannel.SendEvent(this, new BestPriceChangeEventArgs(bba));
        }
Esempio n. 30
0
        private void CommitStopOut(MarginTradingAccount account, InstrumentBidAskPair quote)
        {
            if (account.IsInLiquidation())
            {
                return;
            }

            var liquidationType = account.GetUsedMargin() == account.GetCurrentlyUsedMargin()
                ? LiquidationType.Normal
                : LiquidationType.Mco;

            _cqrsSender.SendCommandToSelf(new StartLiquidationInternalCommand
            {
                OperationId     = _identityGenerator.GenerateGuid(),//TODO: use quote correlationId
                AccountId       = account.Id,
                CreationTime    = _dateService.Now(),
                QuoteInfo       = quote?.ToJson(),
                LiquidationType = liquidationType,
                OriginatorType  = OriginatorType.System,
            });

            _stopOutEventChannel.SendEvent(this, new StopOutEventArgs(account));
        }