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(); } }
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(); } }
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)); }
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); }
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); }
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); }