Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lt 4571 add quote cache inspector #429

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace MarginTrading.Backend.Core.Extensions
{
public static class InstrumentBidAskPairExtensions
{
/// <summary>
/// Calculates a hash for the bid/ask pair, which is used only to determine
/// if the quote has already been warned about being stale. Probably, the
/// implementation entirely correct only for the stale usage scenario.
/// </summary>
/// <param name="bidAskPair"></param>
/// <returns></returns>
public static int GetStaleHash(this InstrumentBidAskPair bidAskPair)
{
unchecked
{
int hash = 23;
hash = hash * 31 + (bidAskPair?.Instrument.GetHashCode() ?? 0);
hash = hash * 31 + (bidAskPair?.Date.GetHashCode() ?? 0);
return hash;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,8 @@ public class MarginTradingSettings

[Optional]
public bool LogBlockedMarginCalculation { get; set; }

[Optional]
public MonitoringSettings Monitoring { get; set; }
}
}
13 changes: 13 additions & 0 deletions src/MarginTrading.Backend.Core/Settings/MonitoringSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2019 Lykke Corp.
// See the LICENSE file in the project root for more information.

using Lykke.SettingsReader.Attributes;

namespace MarginTrading.Backend.Core.Settings
{
public class MonitoringSettings
{
[Optional]
public QuotesMonitoringSettings Quotes { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2019 Lykke Corp.
// See the LICENSE file in the project root for more information.

using System;

namespace MarginTrading.Backend.Core.Settings
{
public class QuotesMonitoringSettings
{
public bool IsEnabled { get; set; }
public TimeSpan ConsiderQuoteStalePeriod { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
<PackageReference Include="System.Reactive.Linq" Version="4.4.1" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>MarginTradingTests</_Parameter1>
</AssemblyAttribute>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
<InternalsVisibleTo Include="MarginTradingTests" />
</ItemGroup>
</Project>
14 changes: 13 additions & 1 deletion src/MarginTrading.Backend.Services/Modules/ServicesModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,26 @@ namespace MarginTrading.Backend.Services.Modules
{
public class ServicesModule : Module
{
private readonly MarginTradingSettings _settings;

public ServicesModule(MarginTradingSettings settings)
{
_settings = settings;
}

protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<QuoteCacheService>()
.AsSelf()
.As<IQuoteCacheService>()
.As<IEventConsumer<BestPriceChangeEventArgs>>()
.SingleInstance();


if (_settings.Monitoring?.Quotes?.IsEnabled ?? false)
{
builder.RegisterDecorator<QuoteCacheInspector, IQuoteCacheService>();
}

builder.RegisterType<FxRateCacheService>()
.AsSelf()
.As<IFxRateCacheService>()
Expand Down
118 changes: 118 additions & 0 deletions src/MarginTrading.Backend.Services/Quotes/QuoteCacheInspector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2019 Lykke Corp.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using MarginTrading.Backend.Core;
using MarginTrading.Backend.Core.Extensions;
using MarginTrading.Backend.Core.Quotes;
using MarginTrading.Backend.Core.Settings;
using MarginTrading.Common.Services;
using Microsoft.Extensions.Logging;

namespace MarginTrading.Backend.Services.Quotes
{
/// <summary>
/// Inspects the quotes returned from the cache.
/// Logs a warning if the quote is not up to date (Is older than 5 seconds).
/// </summary>
internal sealed class QuoteCacheInspector : IQuoteCacheService
{
private readonly IQuoteCacheService _decoratee;
private readonly IDateService _dateService;
private readonly ILogger<QuoteCacheInspector> _logger;
private readonly TimeSpan _quoteStalePeriod;
private readonly ConcurrentDictionary<int, byte> _warnedQuotes = new ConcurrentDictionary<int, byte>();

public QuoteCacheInspector(IQuoteCacheService decoratee,
IDateService dateService,
ILogger<QuoteCacheInspector> logger,
MarginTradingSettings settings)
{
_decoratee = decoratee;
_dateService = dateService;
_logger = logger;
_quoteStalePeriod = settings.Monitoring?.Quotes?.ConsiderQuoteStalePeriod ?? TimeSpan.FromSeconds(5);

_logger.LogInformation("Quote Cache Inspector is activated with stale period {stalePeriod}",
_quoteStalePeriod);
}

public InstrumentBidAskPair GetQuote(string instrument)
{
var quote = _decoratee.GetQuote(instrument);

try
{
if (CanWarn(quote))
WarnOnStaleQuote(quote);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to inspect quote for {instrument}", instrument);
}

return quote;
}

public Dictionary<string, InstrumentBidAskPair> GetAllQuotes()
{
return _decoratee.GetAllQuotes();
}

public bool TryGetQuoteById(string instrument, out InstrumentBidAskPair result)
{
var success = _decoratee.TryGetQuoteById(instrument, out var quote);

try
{
if (CanWarn(quote))
WarnOnStaleQuote(quote);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to inspect quote for {instrument}", instrument);
}

result = quote;
return success;
}

public RemoveQuoteError RemoveQuote(string assetPairId)
{
return _decoratee.RemoveQuote(assetPairId);
}

public void WarnOnStaleQuote(InstrumentBidAskPair quote)
{
if (quote == null)
return;

_logger.LogWarning("Quote for {instrument} is stale. Quote date: {quoteDate}, now: {now}",
quote.Instrument, quote.Date, _dateService.Now());

_warnedQuotes.TryAdd(quote.GetStaleHash(), 0);
}

public bool CanWarn(InstrumentBidAskPair quote)
{
if (quote == null)
return false;

var current = _dateService.Now();
if (IsQuoteStale(quote.Date, current, _quoteStalePeriod))
{
var hash = quote.GetStaleHash();
return !_warnedQuotes.ContainsKey(hash);
}

return false;
}

public static bool IsQuoteStale(DateTime quoteDateTime, DateTime now, TimeSpan stalePeriod)
{
return now.Subtract(quoteDateTime) > stalePeriod;
}
}
}
7 changes: 0 additions & 7 deletions src/MarginTrading.Backend.Services/Services/OrderValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,6 @@ private void ValidateBaseOrderPrice(Order order, decimal? orderPrice)
throw new OrderRejectionException(OrderRejectReason.NoLiquidity, "Quote not found");
}

//TODO: implement in MTC-155
// if (_assetDayOffService.ArePendingOrdersDisabled(order.AssetPairId))
// {
// throw new ValidateOrderException(OrderRejectReason.NoLiquidity,
// "Trades for instrument are not available");
// }

if (order.OrderType == OrderType.Limit)
{
if (order.Direction == OrderDirection.Buy && quote.Ask <= orderPrice)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Common.Log;
Expand Down Expand Up @@ -455,16 +454,6 @@ await InternalRetryPriceRequest(e.CreationTime, sender, executionInfo,
}
}

private decimal GetActualNetPositionCloseVolume(ICollection<string> positionIds, string accountId)
{
var netPositionVolume = _ordersCache.GetPositions()
.Where(x => positionIds.Contains(x.Id)
&& (string.IsNullOrEmpty(accountId) || x.AccountId == accountId))
.Sum(x => x.Volume);

return -netPositionVolume;
}

private void RequestPrice(ICommandSender sender, IOperationExecutionInfo<SpecialLiquidationOperationData>
executionInfo)
{
Expand Down
2 changes: 1 addition & 1 deletion src/MarginTrading.Backend/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ private static void RegisterModules(
builder.RegisterModule(new EventModule());
builder.RegisterModule(new CacheModule());
builder.RegisterModule(new ManagersModule());
builder.RegisterModule(new ServicesModule());
builder.RegisterModule(new ServicesModule(settings.CurrentValue));
builder.RegisterModule(new BackendServicesModule(
mtSettings.CurrentValue,
settings.CurrentValue,
Expand Down
6 changes: 5 additions & 1 deletion tests/MarginTradingTests/BaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
using MarginTrading.Backend.Services.AssetPairs;
using MarginTrading.Backend.Services.Quotes;
using MarginTradingTests.Modules;
using Microsoft.Extensions.Logging;
using Moq;

namespace MarginTradingTests
Expand Down Expand Up @@ -83,6 +84,9 @@ private void RegisterDependenciesCore(bool mockEvents = false)
OvernightMargin = overnightMarginSettings
};

// register mocks of loggers
builder.RegisterInstance(Mock.Of<ILogger<QuoteCacheInspector>>());

builder.RegisterInstance(marginSettings).SingleInstance();
builder.RegisterInstance(PositionHistoryEvents).As<List<PositionHistoryEvent>>().SingleInstance();
builder.RegisterInstance(overnightMarginSettings).SingleInstance();
Expand Down Expand Up @@ -123,7 +127,7 @@ private void RegisterDependenciesCore(bool mockEvents = false)
}

builder.RegisterModule(new CacheModule());
builder.RegisterModule(new ServicesModule());
builder.RegisterModule(new ServicesModule(marginSettings));
builder.RegisterModule(new ManagersModule());

builder.RegisterType<EventChannel<AccountBalanceChangedEventArgs>>()
Expand Down
Loading