-
Notifications
You must be signed in to change notification settings - Fork 82
/
SymbolStatisticsCache.cs
149 lines (113 loc) · 4.5 KB
/
SymbolStatisticsCache.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Binance.Api;
using Binance.Cache.Events;
using Binance.Market;
using Binance.WebSocket;
using Binance.WebSocket.Events;
using Microsoft.Extensions.Logging;
namespace Binance.Cache
{
public sealed class SymbolStatisticsCache : WebSocketClientCache<ISymbolStatisticsWebSocketClient, SymbolStatisticsEventArgs, SymbolStatisticsCacheEventArgs>, ISymbolStatisticsCache
{
#region Public Properties
public IEnumerable<SymbolStatistics> Statistics
{
get { lock (_sync) { return _symbols.Select(s => _statistics[s]).ToArray(); } }
}
#endregion Public Properties
#region Private Fields
private readonly IList<string> _symbols = new List<string>();
private readonly IDictionary<string, SymbolStatistics> _statistics
= new Dictionary<string, SymbolStatistics>();
private readonly object _sync = new object();
#endregion Private Fields
#region Constructors
public SymbolStatisticsCache(IBinanceApi api, ISymbolStatisticsWebSocketClient client, ILogger<SymbolStatisticsCache> logger = null)
: base(api, client, logger)
{ }
#endregion Constructors
#region Public Methods
public SymbolStatistics GetStatistics(string symbol)
{
Throw.IfNullOrWhiteSpace(symbol, nameof(symbol));
symbol = symbol.FormatSymbol();
lock (_sync)
{
return _statistics.ContainsKey(symbol) ? _statistics[symbol] : null;
}
}
public IEnumerable<SymbolStatistics> GetStatistics(params string[] symbols)
{
Throw.IfNull(symbols, nameof(symbols));
lock (_sync)
{
foreach (var symbol in symbols)
yield return GetStatistics(symbol);
}
}
public void Subscribe(Action<SymbolStatisticsCacheEventArgs> callback)
{
base.LinkTo(Client, callback);
Client.Subscribe(ClientCallback);
}
public void Subscribe(Action<SymbolStatisticsCacheEventArgs> callback, params string[] symbols)
{
Throw.IfNull(symbols, nameof(symbols));
base.LinkTo(Client, callback);
foreach (var symbol in symbols)
{
Throw.IfNullOrWhiteSpace(symbol, nameof(symbol));
if (_symbols.Contains(symbol))
continue;
_symbols.Add(symbol);
Client.Subscribe(symbol, ClientCallback);
}
}
public override void LinkTo(ISymbolStatisticsWebSocketClient client, Action<SymbolStatisticsCacheEventArgs> callback = null)
{
// Confirm client is subscribed to only one stream.
if (client.WebSocket.IsCombined)
throw new InvalidOperationException($"{nameof(SymbolStatisticsCache)} can only link to {nameof(ISymbolStatisticsWebSocketClient)} events from a single stream (not combined streams).");
base.LinkTo(client, callback);
Client.StatisticsUpdate += OnClientEvent;
}
public override void UnLink()
{
Client.StatisticsUpdate -= OnClientEvent;
base.UnLink();
}
#endregion Public Methods
#region Protected Methods
protected override async Task<SymbolStatisticsCacheEventArgs> OnAction(SymbolStatisticsEventArgs @event)
{
if (_statistics.Count == 0)
{
Logger?.LogInformation($"{nameof(SymbolStatisticsCache)}: Initializing symbol statistics...");
if (!_symbols.Any())
{
var statistics = await Api.Get24HourStatisticsAsync(@event.Token)
.ConfigureAwait(false);
lock (_sync)
{
foreach (var stats in statistics)
{
_statistics[stats.Symbol] = stats;
}
}
}
}
lock (_sync)
{
foreach (var stats in @event.Statistics)
{
_statistics[stats.Symbol] = stats;
}
return new SymbolStatisticsCacheEventArgs(_symbols.Select(s => _statistics[s]).ToArray());
}
}
#endregion Protected Methods
}
}