コード例 #1
0
        public async Task InsertOrReplaceAsync(MarketMakerState state)
        {
            var entity = new MarketMakerStateEntity(GetPartitionKey(), GetRowKey());

            Mapper.Map(state, entity);

            await _storage.InsertOrReplaceAsync(entity);
        }
コード例 #2
0
        public async Task HandleIndexAsync(Index index)
        {
            MarketMakerState marketMakerState = await _marketMakerStateService.GetAsync();

            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(index.Name);

            if (marketMakerState.Status != MarketMakerStatus.Active)
            {
                if (indexSettings != null)
                {
                    foreach (AssetWeight assetWeight in index.Weights)
                    {
                        await _assetHedgeSettingsService.EnsureAsync(assetWeight.AssetId);
                    }
                }

                return;
            }

            foreach (var assetWeight in index.Weights)
            {
                Quote quote = new Quote($"{assetWeight.AssetId}USD", index.Timestamp, assetWeight.Price,
                                        assetWeight.Price, ExchangeNames.Virtual);

                await _quoteService.UpdateAsync(quote);
            }

            if (indexSettings == null)
            {
                return;
            }

            await _semaphore.WaitAsync();

            try
            {
                await _indexPriceService.UpdateAsync(index);

                await _hedgeService.UpdateLimitOrdersAsync();

                await _marketMakerService.UpdateLimitOrdersAsync(index.Name);
            }
            catch (InvalidOperationException exception)
            {
                _log.WarningWithDetails("An error occurred while processing index", exception, index);
            }
            catch (Exception exception)
            {
                _log.ErrorWithDetails(exception, "An error occurred while processing index", index);
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }
コード例 #3
0
        private async Task ClosePositionsAsync(IEnumerable <Position> positions, PositionType positionType)
        {
            foreach (IGrouping <string, Position> group in positions.GroupBy(o => o.AssetPairId))
            {
                var startedAt = DateTime.UtcNow;

                MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync();

                if (marketMakerState.Status != MarketMakerStatus.Active)
                {
                    continue;
                }

                Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(group.Key);

                decimal originalVolume = group.Sum(o => o.Volume);

                decimal volume = Math.Round(originalVolume, instrument.VolumeAccuracy);

                if (volume < instrument.MinVolume)
                {
                    _log.InfoWithDetails("The volume of open positions is less than min volume", new
                    {
                        instrument.AssetPairId,
                        positionType,
                        volume,
                        instrument.MinVolume
                    });
                    continue;
                }

                ExternalTrade externalTrade = await ExecuteLimitOrderAsync(group.Key, volume, positionType);

                if (externalTrade != null)
                {
                    await _positionService.CloseAsync(group.ToArray(), externalTrade);

                    await _remainingVolumeService.RegisterVolumeAsync(group.Key,
                                                                      (originalVolume - externalTrade.Volume) *GetSign(positionType));
                }

                var finishedAt = DateTime.UtcNow;

                _log.Info("HedgeService.ClosePositionsAsync() completed.", new
                {
                    AssetPairId = instrument.AssetPairId,
                    TradeIds    = positions.Select(x => x.TradeId).ToList(),
                    StartedAt   = startedAt,
                    FinishedAt  = finishedAt,
                    Latency     = (finishedAt - startedAt).TotalMilliseconds
                });

                PrometheusMetrics.HedgeAssetPairLatency.Inc((finishedAt - startedAt).TotalMilliseconds);
            }
        }
コード例 #4
0
        public async Task HandleIndexAsync(Index index, Index shortIndex)
        {
            MarketMakerState marketMakerState = await _marketMakerStateService.GetAsync();

            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(index.Name);

            IndexSettings shortIndexSettings = null;

            if (shortIndex != null)
            {
                shortIndexSettings = await _indexSettingsService.GetByIndexAsync(shortIndex.Name);
            }

            if (marketMakerState.Status != MarketMakerStatus.Active)
            {
                // TODO: Shouldn't they be updated if Market Maker status is Active?
                await UpdateAssets(indexSettings, index);

                return;
            }

            await UpdateVirtualExchangePrices(index);

            if (indexSettings == null)
            {
                return;
            }

            await _semaphore.WaitAsync();

            try
            {
                await RecalculateIndicesPrices(index, shortIndex, shortIndexSettings);

                await _hedgeService.UpdateLimitOrdersAsync();

                await UpdateMarketMakerOrders(index, shortIndex, shortIndexSettings);
            }
            catch (InvalidOperationException exception)
            {
                _log.WarningWithDetails("An error occurred while processing index", exception, index);
            }
            catch (Exception exception)
            {
                _log.ErrorWithDetails(exception, "An error occurred while processing index", index);
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }
コード例 #5
0
        private async Task ValidateMarketMakerStateAsync(IEnumerable <OrderBook> orderBooks)
        {
            MarketMakerState state = await _marketMakerStateService.GetStateAsync();

            if (state.Status == MarketMakerStatus.Error)
            {
                SetError(orderBooks.SelectMany(o => o.LimitOrders), LimitOrderError.MarketMakerError);
            }

            else if (state.Status == MarketMakerStatus.Disabled)
            {
                SetError(orderBooks.SelectMany(o => o.LimitOrders), LimitOrderError.Idle);
            }
        }
コード例 #6
0
        public async Task UpdateAsync(MarketMakerStatus marketMakerStatus, string comment, string userId)
        {
            MarketMakerState marketMakerState = await GetAsync();

            marketMakerState.Status    = marketMakerStatus;
            marketMakerState.Timestamp = DateTime.UtcNow;

            await _marketMakerStateRepository.InsertOrReplaceAsync(marketMakerState);

            _cache.Set(marketMakerState);

            _log.InfoWithDetails("Market maker status updated", new
            {
                marketMakerState,
                comment,
                userId
            });
        }
コード例 #7
0
        public async Task SetStateAsync([FromBody] MarketMakerStateUpdateModel model)
        {
            var status = Mapper.Map <Domain.MarketMaker.MarketMakerStatus>(model.Status);

            MarketMakerState currentState = await _marketMakerStateService.GetStateAsync();

            if (status == currentState.Status)
            {
                return;
            }

            if (currentState.Status == Domain.MarketMaker.MarketMakerStatus.Error &&
                string.IsNullOrEmpty(model.Comment))
            {
                throw new ValidationApiException("Comment required.");
            }

            await _marketMakerStateService.SetStateAsync(status, model.Comment, model.UserId);
        }
        private async Task SetStateAsync(MarketMakerStatus status, MarketMakerError marketMakerError,
                                         string errorMessages, string comment, string userId)
        {
            var marketMakerState = new MarketMakerState
            {
                Time         = DateTime.UtcNow,
                Status       = status,
                Error        = marketMakerError,
                ErrorMessage = errorMessages
            };

            MarketMakerState currentMarketMakerState = await GetStateAsync();

            await _marketMakerStateRepository.InsertOrReplaceAsync(marketMakerState);

            _cache.Set(marketMakerState);

            _log.InfoWithDetails("Market maker state is changed.",
                                 new StateOperationContext(currentMarketMakerState.Status, marketMakerState.Status, comment, userId,
                                                           marketMakerState.Error, marketMakerState.ErrorMessage));
        }
コード例 #9
0
        private async Task ClosePositionsAsync(IEnumerable <Position> positions, PositionType positionType)
        {
            foreach (IGrouping <string, Position> group in positions.GroupBy(o => o.AssetPairId))
            {
                MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync();

                if (marketMakerState.Status != MarketMakerStatus.Active)
                {
                    continue;
                }

                Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(group.Key);

                decimal originalVolume = group.Sum(o => o.Volume);

                decimal volume = Math.Round(originalVolume, instrument.VolumeAccuracy);

                if (volume < instrument.MinVolume)
                {
                    _log.InfoWithDetails("The volume of open positions is less than min volume", new
                    {
                        instrument.AssetPairId,
                        positionType,
                        volume,
                        instrument.MinVolume
                    });
                    continue;
                }

                ExternalTrade externalTrade = await ExecuteLimitOrderAsync(group.Key, volume, positionType);

                if (externalTrade != null)
                {
                    await _positionService.CloseAsync(group.ToArray(), externalTrade);

                    await _remainingVolumeService.RegisterVolumeAsync(group.Key,
                                                                      (originalVolume - volume) *GetSign(positionType));
                }
            }
        }
        public async Task <MarketMakerState> GetStateAsync()
        {
            MarketMakerState state = _cache.Get(CacheKey);

            if (state == null)
            {
                state = await _marketMakerStateRepository.GetAsync();

                if (state == null)
                {
                    state = new MarketMakerState
                    {
                        Status = MarketMakerStatus.Disabled,
                        Time   = DateTime.UtcNow
                    };
                }

                _cache.Initialize(new[] { state });
            }

            return(state);
        }
コード例 #11
0
        public async Task <MarketMakerState> GetAsync()
        {
            MarketMakerState marketMakerState = _cache.Get(CacheKey);

            if (marketMakerState == null)
            {
                marketMakerState = await _marketMakerStateRepository.GetAsync();

                if (marketMakerState == null)
                {
                    marketMakerState = new MarketMakerState
                    {
                        Status    = MarketMakerStatus.Stopped,
                        Timestamp = DateTime.UtcNow
                    };
                }

                _cache.Initialize(new[] { marketMakerState });
            }

            return(marketMakerState);
        }
コード例 #12
0
        private async Task CloseRemainingVolumeAsync()
        {
            IReadOnlyCollection <RemainingVolume> remainingVolumes = await _remainingVolumeService.GetAllAsync();

            foreach (RemainingVolume remainingVolume in remainingVolumes)
            {
                MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync();

                if (marketMakerState.Status != MarketMakerStatus.Active)
                {
                    continue;
                }

                Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(remainingVolume.AssetPairId);

                if (Math.Abs(remainingVolume.Volume) < instrument.MinVolume)
                {
                    continue;
                }

                decimal volume = Math.Round(Math.Abs(remainingVolume.Volume), instrument.VolumeAccuracy);

                PositionType positionType = remainingVolume.Volume > 0
                    ? PositionType.Long
                    : PositionType.Short;

                ExternalTrade externalTrade =
                    await ExecuteLimitOrderAsync(instrument.AssetPairId, volume, positionType);

                if (externalTrade != null)
                {
                    await _positionService.CloseRemainingVolumeAsync(instrument.AssetPairId, externalTrade);

                    await _remainingVolumeService.RegisterVolumeAsync(instrument.AssetPairId,
                                                                      volume *GetSign(positionType) * -1);
                }
            }
        }
コード例 #13
0
        private async Task CloseRemainingVolumeAsync()
        {
            var startedAt = DateTime.UtcNow;

            // close remaining volumes once per 1 min
            lock (_remainingSync)
            {
                if ((startedAt - _lastCloseRemaining).TotalSeconds > 60)
                {
                    _lastCloseRemaining = startedAt;
                }
                else
                {
                    return;
                }
            }

            IReadOnlyCollection <RemainingVolume> remainingVolumes = await _remainingVolumeService.GetAllAsync();

            foreach (RemainingVolume remainingVolume in remainingVolumes)
            {
                MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync();

                if (marketMakerState.Status != MarketMakerStatus.Active)
                {
                    continue;
                }

                Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(remainingVolume.AssetPairId);

                if (Math.Abs(remainingVolume.Volume) < instrument.MinVolume)
                {
                    continue;
                }

                decimal volume = Math.Round(Math.Abs(remainingVolume.Volume), instrument.VolumeAccuracy);

                PositionType positionType = remainingVolume.Volume > 0
                    ? PositionType.Long
                    : PositionType.Short;

                ExternalTrade externalTrade =
                    await ExecuteLimitOrderAsync(instrument.AssetPairId, volume, positionType);

                if (externalTrade != null)
                {
                    await _positionService.CloseRemainingVolumeAsync(instrument.AssetPairId, externalTrade);

                    await _remainingVolumeService.RegisterVolumeAsync(instrument.AssetPairId,
                                                                      externalTrade.Volume *GetSign(positionType) * -1);
                }
            }

            var finishedAt = DateTime.UtcNow;

            _log.Info("HedgeService.CloseRemainingVolumeAsync() completed.", new
            {
                StartedAt  = startedAt,
                FinishedAt = finishedAt,
                Latency    = (finishedAt - startedAt).TotalMilliseconds
            });
        }
コード例 #14
0
        public async Task <MarketMakerStateModel> GetStateAsync()
        {
            MarketMakerState marketMakerState = await _marketMakerStateService.GetAsync();

            return(Mapper.Map <MarketMakerStateModel>(marketMakerState));
        }