private async Task <bool> ProcessAsync(AssetPairSettings assetPair, DateTime date) { _log.Info($"Start processing {assetPair} {date.ToString("yyyy-MM-dd")}."); try { var candles = (await _candlesRepository.GetAsync(assetPair.AssetPairId, date)) .OrderBy(c => c.CandleTimestamp).ToArray(); if (!candles.Any()) { _log.Info($"There are no candles to process {assetPair} on {date.ToString("yyyy-MM-dd")}."); return(false); } if (candles.Length < ChangesGap + MinDeviationCount) { _log.Info($"Not enought candles to process {assetPair} on {date.ToString("yyyy-MM-dd")}."); return(false); } Volatility volatility = Calculate(assetPair, candles); await _volatilityRepository.InsertAsync(volatility); await _candlesRepository.DeleteAsync(candles); _log.Info($"Processed {assetPair} {date.ToString("yyyy-MM-dd")} based on {candles.Length} candles."); } catch (Exception ex) { _log.Error(ex, $"Fail processing {assetPair} {date.ToString("yyyy-MM-dd")}."); } return(true); }
private async Task ValidateAsync(IndexSettings indexSettings) { // TODO: Use internal asset id AssetSettings assetSettings = (await _instrumentService.GetAssetsAsync()) .Single(o => o.Exchange == ExchangeNames.Lykke && o.AssetId == indexSettings.AssetId); if (assetSettings == null) { throw new InvalidOperationException("Asset settings not found"); } AssetPairSettings assetPairSettings = await _instrumentService.GetAssetPairAsync(indexSettings.AssetPairId, ExchangeNames.Lykke); if (assetPairSettings == null) { throw new InvalidOperationException("Asset pair settings not found"); } if (indexSettings.SellVolume / indexSettings.SellLimitOrdersCount < assetPairSettings.MinVolume) { throw new InvalidOperationException("Sell limit order volume is less than min volume"); } if (indexSettings.BuyVolume / indexSettings.BuyLimitOrdersCount < assetPairSettings.MinVolume) { throw new InvalidOperationException("Buy limit order volume is less than min volume"); } }
public void Add(string assetPairId, [NotNull] AssetPairSettings settings) { if (settings == null) { throw new ArgumentNullException(nameof(settings)); } Change(old => new SettingsRoot(old.AssetPairs.Add(assetPairId, settings))); }
public Task UpdateAsync(AssetPairSettings assetPairSettings) { return(_storage.MergeAsync(GetPartitionKey(assetPairSettings.Exchange), GetRowKey(assetPairSettings.AssetPair), entity => { Mapper.Map(assetPairSettings, entity); return entity; })); }
public async Task InsertAsync(AssetPairSettings assetPairSettings) { var entity = new AssetPairSettingsEntity(GetPartitionKey(assetPairSettings.Exchange), GetRowKey(assetPairSettings.AssetPair)); Mapper.Map(assetPairSettings, entity); await _storage.InsertAsync(entity); }
private async Task ValidateAssetPairSettingsAsync(AssetPairSettings assetPairSettings) { AssetSettings baseAssetSettings = await GetAssetAsync(assetPairSettings.BaseAsset, assetPairSettings.Exchange); if (baseAssetSettings == null) { throw new InvalidOperationException("Base asset not found"); } AssetSettings quoteAssetSettings = await GetAssetAsync(assetPairSettings.QuoteAsset, assetPairSettings.Exchange); if (quoteAssetSettings == null) { throw new InvalidOperationException("Quote asset not found"); } }
public async Task UpdateAssetPairAsync(AssetPairSettings assetPairSettings, string userId) { AssetPairSettings existingAssetPairSettings = await GetAssetPairAsync(assetPairSettings.AssetPair, assetPairSettings.Exchange); if (existingAssetPairSettings == null) { throw new EntityNotFoundException(); } await ValidateAssetPairSettingsAsync(assetPairSettings); await _assetPairSettingsRepository.UpdateAsync(assetPairSettings); _assetPairsCache.Set(assetPairSettings); _log.InfoWithDetails("Asset pair settings updated", new { assetPairSettings, userId }); }
public async Task AddAssetPairAsync(AssetPairSettings assetPairSettings, string userId) { AssetPairSettings existingAssetPairSettings = await GetAssetPairAsync(assetPairSettings.AssetPair, assetPairSettings.Exchange); if (existingAssetPairSettings != null) { throw new EntityAlreadyExistsException(); } await ValidateAssetPairSettingsAsync(assetPairSettings); await _assetPairSettingsRepository.InsertAsync(assetPairSettings); _assetPairsCache.Set(assetPairSettings); InitializeAssetPairs(); _log.InfoWithDetails("Asset pair settings added", new { assetPairSettings, userId }); }
private IReadOnlyCollection <LimitOrder> CreateLimitOrders(IndexSettings indexSettings, AssetPairSettings assetPairSettings, decimal sellPrice, decimal buyPrice) { var limitOrders = new List <LimitOrder>(); string walletId = _settingsService.GetWalletId(); decimal sellVolume = Math.Round(indexSettings.SellVolume / indexSettings.SellLimitOrdersCount, assetPairSettings.VolumeAccuracy); if (sellVolume >= assetPairSettings.MinVolume) { for (int i = 0; i < indexSettings.SellLimitOrdersCount; i++) { limitOrders.Add(LimitOrder.CreateSell(walletId, sellPrice, sellVolume)); } } else { limitOrders.Add(LimitOrder.CreateSell(walletId, sellPrice, Math.Round(indexSettings.SellVolume, assetPairSettings.VolumeAccuracy))); } decimal buyVolume = Math.Round(indexSettings.BuyVolume / indexSettings.BuyLimitOrdersCount, assetPairSettings.VolumeAccuracy); if (buyVolume >= assetPairSettings.MinVolume) { for (int i = 0; i < indexSettings.BuyLimitOrdersCount; i++) { limitOrders.Add(LimitOrder.CreateBuy(walletId, buyPrice, buyVolume)); } } else { limitOrders.Add(LimitOrder.CreateBuy(walletId, buyPrice, Math.Round(indexSettings.BuyVolume, assetPairSettings.VolumeAccuracy))); } return(limitOrders); }
private Volatility Calculate(AssetPairSettings assetPairSettings, ICandle[] candles) { var closePriceChanges = new List <double>(); var highPriceChanges = new List <double>(); for (int i = ChangesGap; i < candles.Length; i++) { var baseIndex = i - ChangesGap; var baseCandle = candles[baseIndex]; var candle = candles[i]; decimal closePriceChange = candle.Close / baseCandle.Close - 1; decimal highPriceChange = candle.High / baseCandle.High - 1; closePriceChanges.Add((double)closePriceChange); highPriceChanges.Add((double)highPriceChange); } var closePriceStdev = (decimal)closePriceChanges.StandardDeviation(); var highPriceStdev = (decimal)highPriceChanges.StandardDeviation(); AssetPair assetPair = _cachedAssetsService.GetAssetPair(assetPairSettings.AssetPairId); decimal closePriceVolatilityShieldPercentage = Math.Round(assetPairSettings.MultiplierFactor * closePriceStdev * 100, assetPair.Accuracy, MidpointRounding.AwayFromZero); decimal highPriceVolatilityShieldPercentage = Math.Round(assetPairSettings.MultiplierFactor * highPriceStdev * 100, assetPair.Accuracy, MidpointRounding.AwayFromZero); var temp = candles.First(); return(new Volatility() { AssetPairId = assetPairSettings.AssetPairId, Date = temp.CandleTimestamp.Date, MultiplierFactor = assetPairSettings.MultiplierFactor, ClosePriceStdev = closePriceStdev, ClosePriceVolatilityShield = closePriceVolatilityShieldPercentage, HighPriceStdev = highPriceStdev, HighPriceVolatilityShield = highPriceVolatilityShieldPercentage }); }
public async Task DeleteAssetPairAsync(string assetPair, string exchange, string userId) { AssetPairSettings existingAssetPairSettings = await GetAssetPairAsync(assetPair, exchange); if (existingAssetPairSettings == null) { throw new EntityNotFoundException(); } IReadOnlyCollection <AssetHedgeSettings> assetHedgeSettings = await _assetHedgeSettingsService.GetAllAsync(); if (assetHedgeSettings.Any(o => o.Exchange == exchange && o.AssetPairId == assetPair)) { throw new InvalidOperationException("Asset pair is used by asset hedge settings."); } await _assetPairSettingsRepository.DeleteAsync(assetPair, exchange); _assetPairsCache.Remove(GetKey(assetPair, exchange)); InitializeAssetPairs(); _log.InfoWithDetails("Asset settings deleted", new { existingAssetPairSettings, userId }); }
public async Task ExecuteLimitOrderAsync(HedgeLimitOrder hedgeLimitOrder) { await _hedgeLimitOrderService.AddAsync(hedgeLimitOrder); AssetPairSettings assetPairSettings = await _instrumentService.GetAssetPairAsync(hedgeLimitOrder.AssetPairId, Name); if (assetPairSettings == null) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Instrument not configured"; _log.WarningWithDetails("No settings for instrument", hedgeLimitOrder); return; } decimal price = hedgeLimitOrder.Price .TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, hedgeLimitOrder.Type == LimitOrderType.Sell); decimal volume = Math.Round(hedgeLimitOrder.Volume, assetPairSettings.VolumeAccuracy); if (volume < assetPairSettings.MinVolume) { hedgeLimitOrder.Error = LimitOrderError.TooSmallVolume; return; } var limitOrder = new LimitOrder { Id = hedgeLimitOrder.Id, Price = price, Volume = volume, Type = hedgeLimitOrder.Type }; try { await _lykkeExchangeService.ApplyAsync(hedgeLimitOrder.AssetPairId, limitOrder); if (limitOrder.Error == LimitOrderError.None) { _hedgeLimitOrders[hedgeLimitOrder.AssetId] = hedgeLimitOrder; } hedgeLimitOrder.Error = limitOrder.Error; hedgeLimitOrder.ErrorMessage = limitOrder.ErrorMessage; } catch (ExchangeException exception) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = exception.Message; } catch (Exception exception) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Cannot create limit orders an unexpected error occurred"; _log.WarningWithDetails("An error occurred during creating limit orders", exception, hedgeLimitOrder); } }
private static string GetKey(AssetPairSettings assetPairSettings) => GetKey(assetPairSettings.AssetPair, assetPairSettings.Exchange);
public async Task ExecuteLimitOrderAsync(HedgeLimitOrder hedgeLimitOrder) { await _hedgeLimitOrderService.AddAsync(hedgeLimitOrder); ExternalOrder externalOrder = await _externalOrderRepository.GetAsync(hedgeLimitOrder.Exchange, hedgeLimitOrder.AssetId); if (externalOrder != null) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Already exists"; return; } AssetPairSettings assetPairSettings = await _instrumentService.GetAssetPairAsync(hedgeLimitOrder.AssetPairId, hedgeLimitOrder.Exchange); if (assetPairSettings == null) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Instrument not configured"; _log.WarningWithDetails("No settings for instrument", hedgeLimitOrder); return; } decimal price = hedgeLimitOrder.Price .TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, hedgeLimitOrder.Type == LimitOrderType.Sell); decimal volume = Math.Round(hedgeLimitOrder.Volume, assetPairSettings.VolumeAccuracy); if (volume < assetPairSettings.MinVolume) { hedgeLimitOrder.Error = LimitOrderError.TooSmallVolume; return; } ISpotController spotController = _exchangeAdapterClientFactory.GetSpotController(Name); try { var assetPair = assetPairSettings.AssetPairId; // TODO: Remove this workaround if (Name == "NettingEngineDefault") { assetPair = GetAssetPair(assetPair); } OrderIdResponse response = await spotController.CreateLimitOrderAsync(new LimitOrderRequest { Instrument = assetPair, TradeType = hedgeLimitOrder.Type == LimitOrderType.Sell ? TradeType.Sell : TradeType.Buy, Price = price, Volume = volume }); externalOrder = new ExternalOrder(response.OrderId, hedgeLimitOrder.Exchange, hedgeLimitOrder.AssetId, hedgeLimitOrder.Id); await _externalOrderRepository.InsertAsync(externalOrder); _log.InfoWithDetails("External order created", externalOrder); } catch (Exception exception) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = exception.Message; _log.WarningWithDetails("An error occurred while creating external order", exception, hedgeLimitOrder); } }
public AssetPairValidator(string assetPairId, AssetPairSettings pairSettings, SettingsRoot root) { _assetPairId = assetPairId; _pairSettings = pairSettings; _root = root; }
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); }