public LatestPriceResultMessage GetResult(AssetPair pair) { return(Results().FirstOrDefault(x => x.Pair.Equals(pair))); }
public async Task <IActionResult> Update([FromBody] AssetPair assetPair) { await _assetPairService.UpdateAsync(assetPair); return(NoContent()); }
public IReadOnlyList <ICandle> FillGapUpTo(AssetPair assetPair, IFeedHistory feedHistory) { return(feedHistory.Candles .Select(item => item.ToCandle(feedHistory.AssetPair, feedHistory.PriceType, feedHistory.DateTime)) .ToList()); }
public object Parse(TypeNode typeNode, ArchiveBinaryReader reader) { object result = null; switch (typeNode.TypeFlag) { case "bool": result = reader.ReadBoolean(); break; case "SInt8": result = reader.ReadSByte(); break; case "char": case "UInt8": result = reader.ReadByte(); break; case "short": case "SInt16": result = reader.ReadInt16(); break; case "unsigned short": case "UInt16": result = reader.ReadUInt16(); break; case "int": case "SInt32": result = reader.ReadInt32(); break; case "unsigned int": case "UInt32": case "Type*": result = reader.ReadUInt32(); break; case "long long": case "SInt64": result = reader.ReadInt64(); break; case "unsigned long long": case "UInt64": result = reader.ReadUInt64(); break; case "float": result = reader.ReadSingle(); break; case "double": result = reader.ReadDouble(); break; case "Quaternionf": { result = reader.ReadQuaternion(); break; } case "float4": case "Vector4f": { result = reader.ReadVector4(); break; } case "float3": case "Vector3f": { result = reader.ReadVector3(); break; } case "float2": case "Vector2f": { result = reader.ReadVector2(); break; } case "ColorRGBA": { if (typeNode.Version == 2) { result = reader.ReadColor32(); } else { result = reader.ReadColor(); } break; } case "Matrix4x4f": { result = reader.ReadMatrix4x4(); break; } case "Hash128": { result = reader.ReadHash128(); break; } case "string": { result = reader.ReadString(); break; } case "vector": case "staticvector": case "set": { var valueTypeNode = typeNode.Children[0]; result = this.Parse(valueTypeNode, reader); break; } case "map": { var pairTypeNode = typeNode.Children[0].Children[1]; var keyTypeNode = pairTypeNode.Children[0]; var valueTypeNode = pairTypeNode.Children[1]; var size = reader.ReadInt32(); Map map = new Map(typeNode); for (int i = 0; i < size; i++) { var key = this.Parse(keyTypeNode, reader); var value = this.Parse(valueTypeNode, reader); map.Add(key, value); } result = map; break; } case "Array": { var valueTypeNode = typeNode.Children[1]; var size = reader.ReadInt32(); result = this.ParseArray(valueTypeNode, size, reader); break; } case "PPtr": { var fileID = reader.ReadInt32(); var pathID = reader.ReadInt64(); result = new PPtr(fileID, pathID, typeNode.TypeName); break; } case "TypelessData": { var size = reader.ReadInt32(); result = new TypelessData(reader.ReadBytes(size)); break; } case "StreamedResource": { var source = reader.ReadString(); var offset = reader.ReadUInt64(); var size = reader.ReadUInt64(); var streamedResource = new StreamedResource(source, offset, size); result = streamedResource; break; } case "AssetBundle": { AssetBundle bundle = new AssetBundle(((TypeTree)typeNode).Archive); bundle.FullName = reader.ReadString(); var size = reader.ReadInt32(); List <PPtr> preloadTable = new List <PPtr>(size); for (int i = 0; i < size; i++) { PPtr pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); preloadTable.Add(pptr); } bundle.Preloads.AddRange(preloadTable); size = reader.ReadInt32(); List <AssetPair> container = new List <AssetPair>(size); for (int i = 0; i < size; i++) { var first = reader.ReadString(); var preloadIndex = reader.ReadInt32(); var preloadSize = reader.ReadInt32(); var pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); var pair = new AssetPair(first, new Objects.AssetInfo(preloadIndex, preloadSize, pptr)); container.Add(pair); } bundle.Container.AddRange(container); bundle.MainAsset = new Objects.AssetInfo(reader.ReadInt32(), reader.ReadInt32(), new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>")); bundle.RuntimeCompatibility = reader.ReadUInt32(); bundle.Name = reader.ReadString(); size = reader.ReadInt32(); List <string> dependencies = new List <string>(size); for (int i = 0; i < size; i++) { dependencies.Add(reader.ReadString()); } bundle.Dependencies.AddRange(dependencies); bundle.IsStreamed = reader.ReadBoolean(); result = bundle; break; } case "PreloadData": { PreloadData preloadData = new PreloadData(((TypeTree)typeNode).Archive); preloadData.Name = reader.ReadString(); var size = reader.ReadInt32(); List <PPtr> preloadTable = new List <PPtr>(size); for (int i = 0; i < size; i++) { PPtr pptr = new PPtr(reader.ReadInt32(), reader.ReadInt64(), "PPtr<Object>"); preloadTable.Add(pptr); } preloadData.Preloads.AddRange(preloadTable); size = reader.ReadInt32(); List <string> dependencies = new List <string>(size); for (int i = 0; i < size; i++) { dependencies.Add(reader.ReadString()); } preloadData.Dependencies.AddRange(dependencies); result = preloadData; break; } case "AssetBundleManifest": { Objects.AssetBundleManifest obj = new Objects.AssetBundleManifest((TypeTree)typeNode); foreach (TypeNode childNode in typeNode.Children) { var key = childNode.FieldName; var childValue = this.Parse(childNode, reader); obj[key] = childValue; } result = obj; break; } default: { DynamicObject obj = typeNode is TypeTree ? new UnityDynamicObject((TypeTree)typeNode) : new DynamicObject(typeNode); foreach (TypeNode childNode in typeNode.Children) { var key = childNode.FieldName; var childValue = this.Parse(childNode, reader); obj[key] = childValue; } result = obj; break; } } if (typeNode.IsAlign) { reader.Align(4); } return(result); }
private async Task <OrderBook> CalculateDirectOrderBookAsync(Instrument instrument, DateTime iterationDateTime) { Quote[] quotes = _b2C2OrderBookService.GetQuotes(instrument.AssetPairId); if (quotes == null || quotes.Length != 2) { _log.WarningWithDetails("No quotes for instrument", instrument.AssetPairId); return(null); } Balance baseAssetBalance = null; Balance quoteAssetBalance = null; TimeSpan timeSinceLastTrade = TimeSpan.Zero; if (instrument.AllowSmartMarkup) { AssetPairLink assetPairLink = await _assetPairLinkService.GetByInternalAssetPairIdAsync(instrument.AssetPairId); if (assetPairLink != null && !assetPairLink.IsEmpty()) { baseAssetBalance = await _balanceService.GetByAssetIdAsync(ExchangeNames.B2C2, assetPairLink.ExternalBaseAssetId); quoteAssetBalance = await _balanceService.GetByAssetIdAsync(ExchangeNames.B2C2, assetPairLink.ExternalQuoteAssetId); timeSinceLastTrade = DateTime.UtcNow - _tradeService.GetLastInternalTradeTime(instrument.AssetPairId); } else { _log.WarningWithDetails("The asset pair link does not configured", new { instrument.AssetPairId }); } } AssetPair assetPair = await _assetsServiceWithCache.TryGetAssetPairAsync(instrument.AssetPairId); Asset baseAsset = await _assetsServiceWithCache.TryGetAssetAsync(assetPair.BaseAssetId); MarketMakerSettings marketMakerSettings = await _marketMakerSettingsService.GetAsync(); decimal globalMarkup = marketMakerSettings.LimitOrderPriceMarkup; decimal noQuotesMarkup = await _noFreshQuotesStopLossService.GetNoFreshQuotesMarkup(assetPair.Id); decimal pnLStopLossMarkup = await _pnLStopLossEngineService.GetTotalMarkupByAssetPairIdAsync(assetPair.Id); decimal fiatEquityStopLossMarkup = await _fiatEquityStopLossService.GetFiatEquityMarkup(assetPair.Id); _log.InfoWithDetails("Arguments for Calculator.CalculateLimitOrders(...).", new { instrument.AssetPairId, quotes, levels = instrument.Levels.ToArray(), baseAmountBalance = baseAssetBalance?.Amount ?? 0, quoteAmountBalance = quoteAssetBalance?.Amount ?? 0, timeSinceLastTradeTotalSeconds = (int)timeSinceLastTrade.TotalSeconds, instrumentHalfLifePeriod = instrument.HalfLifePeriod, instrumentAllowSmartMarkup = instrument.AllowSmartMarkup, marketMakerSettingsLimitOrderPriceMarkup = globalMarkup, pnLStopLossMarkup, fiatEquityStopLossMarkup, noQuotesMarkup, assetPairAccuracy = assetPair.Accuracy, baseAssetAccuracy = baseAsset.Accuracy, instrument }); OrderBookUpdateReport orderBookUpdateReport = null; if (_isOrderBooksUpdateReportEnabled) { orderBookUpdateReport = new OrderBookUpdateReport(iterationDateTime); orderBookUpdateReport.AssetPair = instrument.AssetPairId; orderBookUpdateReport.FirstQuoteAsk = quotes[0].Ask; orderBookUpdateReport.FirstQuoteBid = quotes[0].Bid; orderBookUpdateReport.SecondQuoteAsk = quotes[1].Ask; orderBookUpdateReport.SecondQuoteBid = quotes[1].Bid; orderBookUpdateReport.QuoteDateTime = quotes[0].Time; orderBookUpdateReport.GlobalMarkup = globalMarkup; orderBookUpdateReport.NoFreshQuoteMarkup = noQuotesMarkup; orderBookUpdateReport.PnLStopLossMarkup = pnLStopLossMarkup; orderBookUpdateReport.FiatEquityMarkup = fiatEquityStopLossMarkup; } IReadOnlyCollection <LimitOrder> limitOrders = Calculator.CalculateLimitOrders( quotes[0], quotes[1], instrument.Levels.ToArray(), baseAssetBalance?.Amount ?? 0, quoteAssetBalance?.Amount ?? 0, (int)timeSinceLastTrade.TotalSeconds, instrument.HalfLifePeriod, instrument.AllowSmartMarkup, globalMarkup, pnLStopLossMarkup, fiatEquityStopLossMarkup, noQuotesMarkup, assetPair.Accuracy, baseAsset.Accuracy, orderBookUpdateReport); await ValidateQuoteTimeoutAsync(limitOrders, quotes[0]); await ValidateQuoteTimeoutAsync(limitOrders, quotes[1]); ValidateMinVolume(limitOrders, (decimal)assetPair.MinVolume); await ValidatePriceAsync(limitOrders); await ValidateBalanceAsync(limitOrders, assetPair); WriteInfoLog(instrument.AssetPairId, quotes, timeSinceLastTrade, limitOrders, "Direct limit orders calculated"); if (orderBookUpdateReport != null) { await _orderBooksUpdatesReportPublisher.PublishAsync(orderBookUpdateReport); } return(new OrderBook { AssetPairId = instrument.AssetPairId, Time = DateTime.UtcNow, LimitOrders = limitOrders, IsDirect = true }); }
//public static async Task<AssetPair> GetAsync(this IAssetPairsRepository assetPairsRepository, string assetId1, string assetId2) //{ // var assetPairs = await assetPairsRepository.GetAllAsync(); // return assetPairs.FirstOrDefault(itm => // (itm.BaseAssetId == assetId1 && itm.QuotingAssetId == assetId2) || // (itm.BaseAssetId == assetId2 && itm.QuotingAssetId == assetId1)); //} public static bool IsInverted(this AssetPair assetPair, string targetAsset) { return(assetPair.QuotingAssetId == targetAsset); }
public static string RateToString(this double src, AssetPair assetPair) { var mask = "0." + new string('#', assetPair.Accuracy); return(src.ToString(mask)); }
public Request(AssetPair pair, Network network = null) { NetworkSuggested = network; Pair = pair; }
public async Task <decimal> GetRateAsync( string baseAssetId, string quotingAssetId, decimal markupPercent, int markupPips, IMarkup merchantMarkup) { decimal askPrice, bidPrice; AssetPair priceAssetPair = null, assetPair = null; if (!string.IsNullOrEmpty(merchantMarkup.PriceAssetPairId)) { _log.Info($"Price asset pair will be used: {merchantMarkup.PriceAssetPairId}"); priceAssetPair = await _assetsLocalCache.GetAssetPairByIdAsync(merchantMarkup.PriceAssetPairId); IAssetPairRate assetPairRate = await _assetRatesService.GetCurrentRateAsync(priceAssetPair.BaseAssetId, priceAssetPair.QuotingAssetId); _log.Info($"Price method: {merchantMarkup.PriceMethod.ToString()}"); switch (merchantMarkup.PriceMethod) { case PriceMethod.None: case PriceMethod.Direct: askPrice = assetPairRate.AskPrice; bidPrice = assetPairRate.BidPrice; break; case PriceMethod.Reverse: askPrice = Math.Abs(assetPairRate.AskPrice) > 0 ? 1 / assetPairRate.AskPrice : throw new MarketPriceZeroException("ask"); bidPrice = Math.Abs(assetPairRate.BidPrice) > 0 ? 1 / assetPairRate.BidPrice : throw new MarketPriceZeroException("bid"); break; default: throw new UnexpectedAssetPairPriceMethodException(merchantMarkup.PriceMethod); } } else { assetPair = await _assetsLocalCache.GetAssetPairAsync(baseAssetId, quotingAssetId); try { IAssetPairRate assetPairRate = await _assetRatesService.GetCurrentRateAsync(baseAssetId, quotingAssetId); askPrice = assetPairRate.AskPrice; bidPrice = assetPairRate.BidPrice; } catch (Exception) { askPrice = bidPrice = 1; } } _log.Info($"Market rate that will be used for calculation, askPrice = {askPrice}, bidPrice = {bidPrice}"); Asset baseAsset = await _assetsLocalCache.GetAssetByIdAsync(baseAssetId); int pairAccuracy = priceAssetPair?.Accuracy ?? assetPair?.Accuracy ?? baseAsset.Accuracy; return(CalculatePrice(askPrice, bidPrice, pairAccuracy, baseAsset.Accuracy, markupPercent, markupPips, PriceCalculationMethod.ByBid, merchantMarkup)); }
public static double CalcEffectivePrice(List <TradeQueueItem.TradeInfo> trades, AssetPair assetPair, bool isBuy) { return(CalcEffectivePrice(trades.Select(x => new CommonTrade { Asset = x.MarketAsset, OppositeAsset = x.LimitAsset, Volume = x.MarketVolume, OppositeVolume = x.LimitVolume, Price = x.Price.GetValueOrDefault() }).ToList(), assetPair, isBuy)); }
private void GetTradeOrderStatus(IOrderLimitProvider provider, string remoteOrderId, AssetPair market = null) { var context = new RemoteIdContext(UserContext.Current, remoteOrderId); if (market != null) { context.Market = market; } var r = AsyncContext.Run(() => provider.GetOrderStatusAsync(context)); Assert.IsTrue(remoteOrderId.Equals(r.RemoteOrderId, StringComparison.Ordinal), "Remote trade order ids don't match"); Trace.WriteLine($"Remote trade order id: {r.RemoteOrderId}"); if (market != null) { if (r.AmountInitial.HasValue) { Assert.IsTrue(r.AmountInitial.Value.Asset.Equals(market.Asset2)); } if (r.AmountFilled.HasValue) { Assert.IsTrue(r.AmountFilled.Value.Asset.Equals(market.Asset2)); } if (r.AmountRemaining.HasValue) { Assert.IsTrue(r.AmountRemaining.Value.Asset.Equals(market.Asset2)); } } if (r.IsOpen) { Trace.WriteLine("Order is open"); } if (r.IsCancelRequested) { Trace.WriteLine("Order is requested to be canceled"); } if (r.IsCanceled) { Trace.WriteLine("Order is canceled"); } if (r.IsClosed) { Trace.WriteLine("Order is closed"); } if (r.IsFound) { Trace.WriteLine("Order is found"); } if (r.Rate.HasValue) { Trace.WriteLine($"The rate of order is {r.Rate.Value}"); } if (r.AmountInitial.HasValue) { Trace.WriteLine($"Initial amount is {r.AmountInitial.Value.Display}"); } if (r.AmountFilled.HasValue) { Trace.WriteLine($"Filled amount is {r.AmountFilled.Value.Display}"); } if (r.AmountRemaining.HasValue) { Trace.WriteLine($"Remaining amount is {r.AmountRemaining.Value.Display}"); } }
public static double CalcEffectivePrice(List <LimitQueueItem.LimitTradeInfo> trades, AssetPair assetPair, bool isBuy) { return(CalcEffectivePrice(trades.Select(x => new CommonTrade { Asset = x.Asset, OppositeAsset = x.OppositeAsset, Volume = x.Volume, OppositeVolume = x.OppositeVolume, Price = x.Price }).ToList(), assetPair, isBuy)); }
public static IReadOnlyList <ClientTrade> ToDomain(this LimitQueueItem.LimitOrderWithTrades item, AssetPair assetPair) { var trade = item.Trades[0]; var limitVolume = item.Trades.Sum(x => x.Volume); var oppositeLimitVolume = item.Trades.Sum(x => x.OppositeVolume); var price = CalcEffectivePrice(item.Trades, assetPair, item.Order.Volume > 0); var clientId = trade.ClientId ?? item.Order.ClientId; var depositAssetRecord = CreateCommonPartForTradeRecord(trade, item.Order, item.Order.Id, price); var withdrawAssetRecord = CreateCommonPartForTradeRecord(trade, item.Order, item.Order.Id, price); depositAssetRecord.ClientId = withdrawAssetRecord.ClientId = clientId; depositAssetRecord.Amount = oppositeLimitVolume; depositAssetRecord.AssetId = trade.OppositeAsset; withdrawAssetRecord.Amount = limitVolume; if (Math.Sign(limitVolume) == Math.Sign(oppositeLimitVolume)) { withdrawAssetRecord.Amount *= -1; } withdrawAssetRecord.AssetId = trade.Asset; foreach (var t in item.Trades) { var transfer = t.Fees?.FirstOrDefault()?.Transfer; if (transfer != null) { if (depositAssetRecord.AssetId == transfer.Asset) { depositAssetRecord.FeeSize += (double)transfer.Volume; depositAssetRecord.FeeType = Service.OperationsRepository.AutorestClient.Models.FeeType.Absolute; } else { withdrawAssetRecord.FeeSize += (double)transfer.Volume; withdrawAssetRecord.FeeType = Service.OperationsRepository.AutorestClient.Models.FeeType.Absolute; } } } depositAssetRecord.Id = Core.Domain.CashOperations.Utils.GenerateRecordId(depositAssetRecord.DateTime); withdrawAssetRecord.Id = Core.Domain.CashOperations.Utils.GenerateRecordId(withdrawAssetRecord.DateTime); return(new[] { depositAssetRecord, withdrawAssetRecord }); }
private async Task <OrderBook> CalculateDirectOrderBookAsync(Instrument instrument) { Quote[] quotes = _b2C2OrderBookService.GetQuotes(instrument.AssetPairId); if (quotes == null || quotes.Length != 2) { _log.WarningWithDetails("No quotes for instrument", instrument.AssetPairId); return(null); } Balance baseAssetBalance = null; Balance quoteAssetBalance = null; TimeSpan timeSinceLastTrade = TimeSpan.Zero; if (instrument.AllowSmartMarkup) { AssetPairLink assetPairLink = await _assetPairLinkService.GetByInternalAssetPairIdAsync(instrument.AssetPairId); if (assetPairLink != null && !assetPairLink.IsEmpty()) { baseAssetBalance = await _balanceService.GetByAssetIdAsync(ExchangeNames.B2C2, assetPairLink.ExternalBaseAssetId); quoteAssetBalance = await _balanceService.GetByAssetIdAsync(ExchangeNames.B2C2, assetPairLink.ExternalQuoteAssetId); timeSinceLastTrade = DateTime.UtcNow - _tradeService.GetLastInternalTradeTime(instrument.AssetPairId); } else { _log.WarningWithDetails("The asset pair link does not configured", new { instrument.AssetPairId }); } } AssetPair assetPair = await _assetsServiceWithCache.TryGetAssetPairAsync(instrument.AssetPairId); Asset baseAsset = await _assetsServiceWithCache.TryGetAssetAsync(assetPair.BaseAssetId); MarketMakerSettings marketMakerSettings = await _marketMakerSettingsService.GetAsync(); decimal pnLStopLossMarkup = await _pnLStopLossEngineService.GetTotalMarkupByAssetPairIdAsync(assetPair.Id); decimal fiatEquityStopLossMarkup = await _fiatEquityStopLossService.GetFiatEquityMarkup(assetPair.Id); decimal stopLossMarkup = await _noFreshQuotesStopLossService.GetNoFreshQuotesMarkup(assetPair.Id); IReadOnlyCollection <LimitOrder> limitOrders = Calculator.CalculateLimitOrders( quotes[0], quotes[1], instrument.Levels.ToArray(), baseAssetBalance?.Amount ?? 0, quoteAssetBalance?.Amount ?? 0, (int)timeSinceLastTrade.TotalSeconds, instrument.HalfLifePeriod, instrument.AllowSmartMarkup, marketMakerSettings.LimitOrderPriceMarkup, pnLStopLossMarkup, fiatEquityStopLossMarkup, stopLossMarkup, assetPair.Accuracy, baseAsset.Accuracy); await ValidateQuoteTimeoutAsync(limitOrders, quotes[0]); await ValidateQuoteTimeoutAsync(limitOrders, quotes[1]); ValidateMinVolume(limitOrders, (decimal)assetPair.MinVolume); await ValidatePriceAsync(limitOrders); await ValidateBalanceAsync(limitOrders, assetPair); WriteInfoLog(instrument.AssetPairId, quotes, timeSinceLastTrade, limitOrders, "Direct limit orders calculated"); return(new OrderBook { AssetPairId = instrument.AssetPairId, Time = DateTime.UtcNow, LimitOrders = limitOrders, IsDirect = true }); }
private async Task <MultiOrderItemModel> ToMultiOrderItemModel(string clientId, AssetPair assetPair, BulkOrderItemModel item) { var requestId = GetNextRequestId(); var fees = _calculateOrderFees ? await _feeCalculator.GetLimitOrderFees(clientId, assetPair, item.OrderAction) : Array.Empty <LimitOrderFeeModel>(); var model = new MultiOrderItemModel { Id = requestId.ToString(), Price = (double)item.Price, Volume = (double)item.Volume, OrderAction = item.OrderAction.ToMeOrderAction(), Fee = fees.FirstOrDefault() }; if (!string.IsNullOrWhiteSpace(item.OldId)) { model.OldId = item.OldId; } return(model); }
private async Task ProcessLimitOrdersAsync(LimitOrdersMessage message) { if (message.Orders == null || !message.Orders.Any()) { return; } HashSet <string> limitOrderIds = message.Orders .Select(o => o.Order.Id) .ToHashSet(); foreach (var orderMessage in message.Orders) { if (orderMessage.Trades == null || !orderMessage.Trades.Any()) { continue; } string assetPairId = orderMessage.Order.AssetPairId; AssetPair assetPair = _assetPairsRepository.TryGet(assetPairId); if (assetPair == null) { _log.Error($"Asset pair {assetPairId} not found"); continue; } List <LimitOrdersMessage.Trade> allTrades = message.Orders.SelectMany(x => x.Trades).ToList(); string marketDataKey = RedisService.GetMarketDataKey(assetPairId); string baseVolumeKey = RedisService.GetMarketDataBaseVolumeKey(assetPairId); string quoteVolumeKey = RedisService.GetMarketDataQuoteVolumeKey(assetPairId); string priceKey = RedisService.GetMarketDataPriceKey(assetPairId); foreach (var tradeMessage in orderMessage.Trades.OrderBy(t => t.Timestamp).ThenBy(t => t.Index)) { long maxIndex = allTrades .Where(x => x.OppositeOrderId == tradeMessage.OppositeOrderId) .Max(t => t.Index); var price = (decimal)tradeMessage.Price; string priceString = price.ToString(CultureInfo.InvariantCulture); var nowDate = tradeMessage.Timestamp; var nowTradeDate = nowDate.AddMilliseconds(tradeMessage.Index); await Task.WhenAll( _database.HashSetAsync(marketDataKey, nameof(MarketSlice.LastPrice), priceString), _database.SortedSetAddAsync(priceKey, RedisExtensions.SerializeWithTimestamp(priceString, nowTradeDate), nowTradeDate.ToUnixTime()) ); var isOppositeOrderIsLimit = limitOrderIds.Contains(tradeMessage.OppositeOrderId); // If opposite order is market order, then unconditionally takes the given limit order. // But if both of orders are limit orders, we should take only one of them. if (isOppositeOrderIsLimit) { var isBuyOrder = orderMessage.Order.Volume > 0; // Takes trade only for the sell limit orders if (isBuyOrder) { continue; } } decimal baseVolume; decimal quotingVolume; if (tradeMessage.Asset == assetPair.BaseAssetId) { baseVolume = (decimal)tradeMessage.Volume; quotingVolume = (decimal)tradeMessage.OppositeVolume; } else { baseVolume = (decimal)tradeMessage.OppositeVolume; quotingVolume = (decimal)tradeMessage.Volume; } if (tradeMessage.Price > 0 && baseVolume > 0 && quotingVolume > 0) { double now = nowDate.ToUnixTime(); double from = (nowDate - _marketDataInterval).ToUnixTime(); decimal baseVolumeSum = baseVolume; decimal quoteVolumeSum = quotingVolume; decimal priceChange = 0; decimal highValue = (decimal)tradeMessage.Price; decimal lowValue = (decimal)tradeMessage.Price; var tasks = new List <Task>(); var baseVolumesDataTask = _database.SortedSetRangeByScoreAsync(baseVolumeKey, from, now); var quoteVolumesDataTask = _database.SortedSetRangeByScoreAsync(quoteVolumeKey, from, now); var priceDataTask = _database.SortedSetRangeByScoreAsync(priceKey, from, now); await Task.WhenAll(baseVolumesDataTask, quoteVolumesDataTask, priceDataTask); baseVolumeSum += baseVolumesDataTask.Result .Where(x => x.HasValue) .Sum(x => RedisExtensions.DeserializeTimestamped <decimal>(x)); quoteVolumeSum += quoteVolumesDataTask.Result .Where(x => x.HasValue) .Sum(x => RedisExtensions.DeserializeTimestamped <decimal>(x)); var currentHigh = priceDataTask.Result.Any(x => x.HasValue) ? priceDataTask.Result .Where(x => x.HasValue) .Max(x => RedisExtensions.DeserializeTimestamped <decimal>(x)) : (decimal?)null; if (currentHigh.HasValue && currentHigh.Value > highValue) { highValue = currentHigh.Value; } var currentLow = priceDataTask.Result.Any(x => x.HasValue) ? priceDataTask.Result .Where(x => x.HasValue) .Min(x => RedisExtensions.DeserializeTimestamped <decimal>(x)) : (decimal?)null; if (currentLow.HasValue && currentLow.Value < lowValue) { lowValue = currentLow.Value; } var pricesData = priceDataTask.Result; if (pricesData.Any() && pricesData[0].HasValue) { decimal openPrice = RedisExtensions.DeserializeTimestamped <decimal>(pricesData[0]); if (openPrice > 0) { priceChange = ((decimal)tradeMessage.Price - openPrice) / openPrice; } } tasks.Add(_database.SortedSetAddAsync(baseVolumeKey, RedisExtensions.SerializeWithTimestamp(baseVolume, nowTradeDate), now)); tasks.Add(_database.SortedSetAddAsync(quoteVolumeKey, RedisExtensions.SerializeWithTimestamp(quotingVolume, nowTradeDate), now)); await Task.WhenAll(tasks); //send event only for the last trade in the order if (tradeMessage.Index == maxIndex) { var evt = new MarketDataChangedEvent { AssetPairId = assetPairId, VolumeBase = baseVolumeSum, VolumeQuote = quoteVolumeSum, PriceChange = priceChange, LastPrice = (decimal)tradeMessage.Price, High = highValue, Low = lowValue }; _cqrsEngine.PublishEvent(evt, MarketDataBoundedContext.Name); try { await _tickerWriter.InsertOrReplaceAsync(new Ticker(assetPairId) { VolumeBase = baseVolumeSum, VolumeQuote = quoteVolumeSum, PriceChange = priceChange, LastPrice = (decimal)tradeMessage.Price, High = highValue, Low = lowValue, UpdatedDt = nowTradeDate }); } catch (Exception ex) { _log.Error(ex, "Error sending ticker to MyNySqlServer", context: evt.ToJson()); } } } } } }
public async Task <ResponseModel <MarketOrderResponseModel> > PlaceMarketOrderAsync(string clientId, AssetPair assetPair, OrderAction orderAction, decimal volume, bool straight, double?reservedLimitVolume = null) { var fees = _calculateOrderFees ? await _feeCalculator.GetMarketOrderFees(clientId, assetPair, orderAction) : Array.Empty <MarketOrderFeeModel>(); var order = new MarketOrderModel { Id = GetNextRequestId().ToString(), AssetPairId = assetPair.Id, ClientId = clientId, ReservedLimitVolume = reservedLimitVolume, Straight = straight, Volume = (double)Math.Abs(volume), OrderAction = orderAction.ToMeOrderAction(), Fees = fees }; var response = await _matchingEngineClient.HandleMarketOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new MarketOrderResponseModel { Price = response.Price }; return(ConvertToApiModel(response.Status, result)); }
public ExchangeRateSubscribe(ObjectId id, AssetPair pair, SubscriptionType type) : base(id, type) { Pair = pair; }
public static int Multiplier(this AssetPair assetPair) { return((int)Math.Pow(10, assetPair.Accuracy)); }
public ExchangeRateSubscribe(ObjectId id, AssetPair pair, Network network, SubscriptionType type) : this(id, pair, type) { Network = network; }
private IReadOnlyList <OrderBook> GetOrderBooks(AssetPair assetPair1, AssetPair assetPair2, AssetPair assetPair3) { var orderBook1 = new OrderBook("FE", assetPair1, new List <VolumePrice>(), new List <VolumePrice>(), DateTime.UtcNow); var orderBook2 = new OrderBook("FE", assetPair2, new List <VolumePrice>(), new List <VolumePrice>(), DateTime.UtcNow); var orderBook3 = new OrderBook("FE", assetPair3, new List <VolumePrice>(), new List <VolumePrice>(), DateTime.UtcNow); return(new List <OrderBook> { orderBook1, orderBook2, orderBook3 }); }
public LatestPriceRequestSubscription(ObjectId subscriberId, AssetPair pair, Network network = null, SubscriptionType type = SubscriptionType.Subscribe) : base(subscriberId, type) { Pair = pair; Network = network; }
public async Task <decimal> GetMultiplierAsync(AssetPair pair) { var rates = await GetRatesAsync().ConfigureAwait(false); return(rates.Get(pair, 0)); }
protected override async Task <AssetPrice> Handle(IProjection <AssetPairsInfo> projection, AssetPriceQuery query) { var price = 1.0; var fordom = AssetPair.Fordom(query.ForAsset, query.DomAsset); var info = projection.State; info.Tree.Log = _log; var timestamp = query.Timestamp; if (query.Timeline != "") { timestamp = _branchManager.GetTime(query.Timeline); } else if (timestamp == default) { timestamp = _branchManager.GetTime(_branchManager.ActiveBranch); } if (info.Pairs.ToList().Contains(fordom)) { var result = await _handler.Handle(new SingleAssetPriceQuery(fordom) { Timeline = query.Timeline, Timestamp = query.Timestamp, }); if (result == null || result.Timestamp.Minus(timestamp).Days > 0 || timestamp.Minus(result.Timestamp).Days > 0) { throw new InvalidOperationException($"Stale pricing date for {fordom}"); } price = result.Price; } else { // try to triangulate the price var path = info.Tree.GetPath(query.ForAsset, query.DomAsset); if (path == null) { throw new InvalidOperationException($"No path found from {query.ForAsset?.Ticker} to {query.DomAsset?.Ticker}"); } foreach (var(forAsset, domAsset) in path) { var pathForDom = forAsset + domAsset; var isInverse = info.Pairs.Contains(domAsset + forAsset); if (isInverse) { pathForDom = domAsset + forAsset; } var pathResult = await _handler.Handle(new SingleAssetPriceQuery(pathForDom) { Timeline = query.Timeline, Timestamp = query.Timestamp, }); if (pathResult == null || pathResult.Timestamp.Minus(timestamp).Days > 0 || timestamp.Minus(pathResult.Timestamp).Days > 0) { throw new InvalidOperationException($"Stale pricing date for {pathForDom}"); } if (isInverse) { pathResult.Price = 1.0 / pathResult.Price; } price *= pathResult.Price; } } return(new AssetPrice(price, timestamp)); }
private async Task ValidateBalanceAsync(IReadOnlyCollection <LimitOrder> limitOrders, AssetPair assetPair) { Asset baseAsset = await _assetsServiceWithCache.TryGetAssetAsync(assetPair.BaseAssetId); Asset quoteAsset = await _assetsServiceWithCache.TryGetAssetAsync(assetPair.QuotingAssetId); List <LimitOrder> sellLimitOrders = limitOrders .Where(o => o.Error == LimitOrderError.None) .Where(o => o.Type == LimitOrderType.Sell) .OrderBy(o => o.Price) .ToList(); List <LimitOrder> buyLimitOrders = limitOrders .Where(o => o.Error == LimitOrderError.None) .Where(o => o.Type == LimitOrderType.Buy) .OrderByDescending(o => o.Price) .ToList(); if (sellLimitOrders.Any()) { decimal balance = (await _balanceService.GetByAssetIdAsync(ExchangeNames.Lykke, baseAsset.Id)).Amount; foreach (LimitOrder limitOrder in sellLimitOrders) { decimal amount = limitOrder.Volume.TruncateDecimalPlaces(baseAsset.Accuracy, true); if (balance - amount < 0) { decimal volume = balance.TruncateDecimalPlaces(baseAsset.Accuracy); if (volume < (decimal)assetPair.MinVolume) { limitOrder.Error = LimitOrderError.NotEnoughFunds; } else { limitOrder.UpdateVolume(volume); } } balance -= amount; } } if (buyLimitOrders.Any()) { decimal balance = (await _balanceService.GetByAssetIdAsync(ExchangeNames.Lykke, quoteAsset.Id)).Amount; foreach (LimitOrder limitOrder in buyLimitOrders) { decimal amount = (limitOrder.Price * limitOrder.Volume) .TruncateDecimalPlaces(quoteAsset.Accuracy, true); if (balance - amount < 0) { decimal volume = (balance / limitOrder.Price).TruncateDecimalPlaces(baseAsset.Accuracy); if (volume < (decimal)assetPair.MinVolume) { limitOrder.Error = LimitOrderError.NotEnoughFunds; } else { limitOrder.UpdateVolume(volume); } } balance -= amount; } } }
public async Task <ResponseModel <LimitOrderResponseModel> > PlaceLimitOrderAsync(string clientId, AssetPair assetPair, OrderAction orderAction, decimal volume, decimal price, bool cancelPreviousOrders = false) { var requestId = GetNextRequestId(); var fees = _calculateOrderFees ? await _feeCalculator.GetLimitOrderFees(clientId, assetPair, orderAction) : Array.Empty <LimitOrderFeeModel>(); var order = new LimitOrderModel { Id = requestId.ToString(), AssetPairId = assetPair.Id, ClientId = clientId, Price = (double)price, CancelPreviousOrders = cancelPreviousOrders, Volume = (double)Math.Abs(volume), OrderAction = orderAction.ToMeOrderAction(), Fees = fees }; var response = await _matchingEngineClient.PlaceLimitOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new LimitOrderResponseModel { Id = requestId }; return(ConvertToApiModel(response.Status, result)); }
private BitcoinIndonesiaSchema.TickerEntryResponse CreateTickerObject(Dictionary <string, decimal> response, AssetPair pair) { response.TryGetValue("high", out decimal high); response.TryGetValue("low", out decimal low); response.TryGetValue("vol_" + pair.Asset1.ShortCode.ToLower(), out decimal volBase); response.TryGetValue("vol_" + pair.Asset2.ShortCode.ToLower(), out decimal volQuote); response.TryGetValue("last", out decimal last); response.TryGetValue("buy", out decimal buy); response.TryGetValue("sell", out decimal sell); response.TryGetValue("server_time", out decimal server_time); return(new BitcoinIndonesiaSchema.TickerEntryResponse() { high = high, low = low, vol_base = volBase, vol_quote = volQuote, last = last, buy = buy, sell = sell, server_time = (long)server_time }); }
public async Task <ResponseModel <BulkOrderResponseModel> > PlaceBulkLimitOrderAsync(string clientId, AssetPair assetPair, IEnumerable <BulkOrderItemModel> items, bool cancelPrevious, CancelMode?cancelMode) { var requestId = GetNextRequestId(); var orders = new ConcurrentBag <MultiOrderItemModel>(); await items.ParallelForEachAsync(async item => { var subOrder = await ToMultiOrderItemModel(clientId, assetPair, item); orders.Add(subOrder); }); var order = new MultiLimitOrderModel { Id = requestId.ToString(), ClientId = clientId, AssetPairId = assetPair.Id, CancelPreviousOrders = cancelPrevious, Orders = orders.ToArray() }; if (cancelMode.HasValue) { order.CancelMode = cancelMode.Value.ToMeCancelModel(); } var response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new BulkOrderResponseModel { AssetPairId = assetPair.Id, Error = response.Status != MeStatusCodes.Ok ? ErrorCodeType.Rejected : default(ErrorCodeType?), Statuses = response.Statuses?.Select(ToBulkOrderItemStatusModel).ToArray() }; return(ConvertToApiModel(response.Status, result)); }
public IReadOnlyList <ICandle> FillGapUpTo(AssetPair assetPair, CandlePriceType priceType, DateTime dateTime, ICandle endCandle) { return(Array.Empty <ICandle>()); }
private void CheckResponseErrors <T>(BittrexSchema.BaseResponse <T> response, AssetPair pair = null) { if (response.success == false) { if (response.message.Equals("INVALID_MARKET") && pair != null) { throw new NoAssetPairException(pair, this); } throw new ApiResponseException($"API error: {response.message}", this); } }