public async Task InsertOrReplaceAsync(MarketMakerState state) { var entity = new MarketMakerStateEntity(GetPartitionKey(), GetRowKey()); Mapper.Map(state, entity); await _storage.InsertOrReplaceAsync(entity); }
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(); } }
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); } }
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(); } }
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); } }
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 }); }
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)); }
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); }
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); }
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); } } }
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 }); }
public async Task <MarketMakerStateModel> GetStateAsync() { MarketMakerState marketMakerState = await _marketMakerStateService.GetAsync(); return(Mapper.Map <MarketMakerStateModel>(marketMakerState)); }