private async Task ReserveClientFundsAsync(Settlement settlement)
        {
            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(settlement.IndexName);

            // TODO: Use internal asset
            AssetSettings assetSettings = (await _instrumentService.GetAssetsAsync())
                                          .Single(o => o.Exchange == ExchangeNames.Lykke && o.AssetId == indexSettings.AssetId);

            try
            {
                await _settlementTransferService.ReserveClientFundsAsync(settlement.WalletId, assetSettings.Asset,
                                                                         settlement.Amount, settlement.ClientId, settlement.Id);

                settlement.Status = SettlementStatus.Reserved;

                _log.InfoWithDetails("Funds reserved from client wallet",
                                     new { SettlementId = settlement.Id, indexSettings.AssetId, settlement.Amount, settlement.WalletId });
            }
            catch (NotEnoughFundsException)
            {
                settlement.Error = SettlementError.NotEnoughFunds;

                _log.WarningWithDetails("Not enough funds to reserve from client wallet",
                                        new { SettlementId = settlement.Id, indexSettings.AssetId, settlement.Amount, settlement.WalletId });
            }
            catch (Exception exception)
            {
                settlement.Error = SettlementError.Unknown;

                _log.ErrorWithDetails(exception, "An error occurred while reserving funds from client wallet",
                                      new { SettlementId = settlement.Id, indexSettings.AssetId, settlement.Amount, settlement.WalletId });
            }

            await _settlementRepository.UpdateAsync(settlement);
        }
        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();
            }
        }
예제 #3
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();
            }
        }
예제 #4
0
        public async Task <IndexSettingsModel> GetByIndexAsync(string indexName)
        {
            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(indexName);

            if (indexSettings == null)
            {
                throw new ValidationApiException(HttpStatusCode.NotFound, "The index settings does not exist");
            }

            return(Mapper.Map <IndexSettingsModel>(indexSettings));
        }
예제 #5
0
        public async Task UpdateAsync(Index index)
        {
            if (!index.ValidateValue())
            {
                throw new InvalidOperationException("Invalid index value");
            }

            if (!index.ValidateWeights())
            {
                throw new InvalidOperationException("Invalid index weights");
            }

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

            if (indexSettings == null)
            {
                throw new InvalidOperationException("Index settings not found");
            }

            IndexPrice indexPrice = await GetByIndexAsync(index.Name);

            if (indexPrice == null)
            {
                indexPrice = IndexPrice.Init(index.Name, index.Value, index.Timestamp, index.Weights);

                await _indexPriceRepository.InsertAsync(indexPrice);

                _log.InfoWithDetails("The index price initialized", indexPrice);
            }
            else
            {
                IndexSettlementPrice indexSettlementPrice = IndexSettlementPriceCalculator.Calculate(
                    index.Value, indexPrice.Value, indexSettings.Alpha, indexPrice.K, indexPrice.Price,
                    index.Timestamp, indexPrice.Timestamp, indexSettings.TrackingFee, indexSettings.PerformanceFee,
                    indexSettings.IsShort);

                indexPrice.Update(index.Value, index.Timestamp, indexSettlementPrice.Price, indexSettlementPrice.K,
                                  indexSettlementPrice.R, indexSettlementPrice.Delta, index.Weights);

                await _indexPriceRepository.UpdateAsync(indexPrice);

                _log.InfoWithDetails("The index price calculated", new
                {
                    indexPrice,
                    indexSettings
                });
            }

            _cache.Set(indexPrice);
        }
예제 #6
0
        public async Task <SimulationReport> GetReportAsync(string indexName)
        {
            SimulationParameters simulationParameters =
                await _simulationParametersRepository.GetByIndexNameAsync(indexName);

            if (simulationParameters == null)
            {
                simulationParameters = SimulationParameters.Create(indexName);
            }

            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(indexName);

            if (indexSettings == null)
            {
                return(null);
            }

            IndexPrice indexPrice = await _indexPriceService.GetByIndexAsync(indexSettings.Name);

            var simulationReport = new SimulationReport
            {
                IndexName      = indexName,
                AssetId        = indexSettings.AssetId,
                AssetPairId    = indexSettings.AssetPairId,
                Value          = indexPrice?.Value,
                Price          = indexPrice?.Price,
                Timestamp      = indexPrice?.Timestamp,
                K              = indexPrice?.K,
                OpenTokens     = simulationParameters.OpenTokens,
                AmountInUsd    = simulationParameters.OpenTokens * indexPrice?.Price ?? 0,
                Investments    = simulationParameters.Investments,
                Alpha          = indexSettings.Alpha,
                TrackingFee    = indexSettings.TrackingFee,
                PerformanceFee = indexSettings.PerformanceFee,
                SellMarkup     = indexSettings.SellMarkup,
                SellVolume     = indexSettings.SellVolume,
                BuyVolume      = indexSettings.BuyVolume,
                PnL            = simulationParameters.OpenTokens * indexPrice?.Price - simulationParameters.Investments ?? 0
            };

            var assets = new List <AssetDistribution>();

            if (indexPrice != null)
            {
                foreach (AssetWeight assetWeight in indexPrice.Weights)
                {
                    decimal amountInUsd = simulationReport.AmountInUsd * assetWeight.Weight;

                    decimal amount = amountInUsd / assetWeight.Price;

                    assets.Add(new AssetDistribution
                    {
                        Asset       = assetWeight.AssetId,
                        Weight      = assetWeight.Weight,
                        IsHedged    = simulationParameters.Assets.Contains(assetWeight.AssetId),
                        Amount      = amount,
                        AmountInUsd = amountInUsd,
                        Price       = assetWeight.Price
                    });
                }
            }

            simulationReport.Assets = assets;

            return(simulationReport);
        }
예제 #7
0
        public async Task UpdateLimitOrdersAsync(string indexName)
        {
            IndexPrice indexPrice = await _indexPriceService.GetByIndexAsync(indexName);

            if (indexPrice == null)
            {
                throw new InvalidOperationException("Index price not found");
            }

            IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(indexName);

            if (indexSettings == null)
            {
                throw new InvalidOperationException("Index settings not found");
            }

            AssetPairSettings assetPairSettings =
                await _instrumentService.GetAssetPairAsync(indexSettings.AssetPairId, Exchange);

            if (assetPairSettings == null)
            {
                throw new InvalidOperationException("Asset pair settings not found");
            }

            AssetSettings baseAssetSettings =
                await _instrumentService.GetAssetAsync(assetPairSettings.BaseAsset, ExchangeNames.Lykke);

            if (baseAssetSettings == null)
            {
                throw new InvalidOperationException("Base asset settings not found");
            }

            AssetSettings quoteAssetSettings =
                await _instrumentService.GetAssetAsync(assetPairSettings.QuoteAsset, ExchangeNames.Lykke);

            if (quoteAssetSettings == null)
            {
                throw new InvalidOperationException("Quote asset settings not found");
            }

            decimal sellPrice = (indexPrice.Price + indexSettings.SellMarkup)
                                .TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, true);

            decimal buyPrice = indexPrice.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy);

            IReadOnlyCollection <LimitOrder> limitOrders =
                CreateLimitOrders(indexSettings, assetPairSettings, sellPrice, buyPrice);

            ValidateBalance(limitOrders, baseAssetSettings, quoteAssetSettings);

            ValidateMinVolume(limitOrders, assetPairSettings.MinVolume);

            LimitOrder[] allowedLimitOrders = limitOrders
                                              .Where(o => o.Error == LimitOrderError.None)
                                              .ToArray();

            _log.InfoWithDetails("Limit orders created", limitOrders);

            _limitOrderService.Update(indexSettings.AssetPairId, limitOrders);

            await _lykkeExchangeService.ApplyAsync(indexSettings.AssetPairId, allowedLimitOrders);

            _traceWriter.LimitOrders(indexSettings.AssetPairId, limitOrders);
        }