Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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)));
 }
Ejemplo n.º 4
0
 public Task UpdateAsync(AssetPairSettings assetPairSettings)
 {
     return(_storage.MergeAsync(GetPartitionKey(assetPairSettings.Exchange),
                                GetRowKey(assetPairSettings.AssetPair), entity =>
     {
         Mapper.Map(assetPairSettings, entity);
         return entity;
     }));
 }
Ejemplo n.º 5
0
        public async Task InsertAsync(AssetPairSettings assetPairSettings)
        {
            var entity = new AssetPairSettingsEntity(GetPartitionKey(assetPairSettings.Exchange),
                                                     GetRowKey(assetPairSettings.AssetPair));

            Mapper.Map(assetPairSettings, entity);

            await _storage.InsertAsync(entity);
        }
Ejemplo n.º 6
0
        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");
            }
        }
Ejemplo n.º 7
0
        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 });
        }
Ejemplo n.º 8
0
        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 });
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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
            });
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 13
0
 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);
            }
        }
Ejemplo n.º 15
0
 public AssetPairValidator(string assetPairId, AssetPairSettings pairSettings, SettingsRoot root)
 {
     _assetPairId  = assetPairId;
     _pairSettings = pairSettings;
     _root         = root;
 }
Ejemplo n.º 16
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);
        }