Skip to content

Commit c4e39ae

Browse files
committed
Optimize order book hot paths
Add BenchmarkDotNet coverage for order book processing and read access, reduce allocations in source conversion and order book update paths, and document the measured performance improvements.
1 parent d601653 commit c4e39ae

37 files changed

Lines changed: 1999 additions & 507 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dlldata.c
4444
# DNX
4545
project.lock.json
4646
artifacts/
47+
BenchmarkDotNet.Artifacts/
4748

4849
*_i.c
4950
*_p.c

Crypto.Websocket.Extensions.sln

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,92 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crypto.Websocket.Extensions
2929
EndProject
3030
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crypto.Websocket.Extensions.Core", "src\Crypto.Websocket.Extensions.Core\Crypto.Websocket.Extensions.Core.csproj", "{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}"
3131
EndProject
32+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{66320409-64EC-F7C5-3DEF-65E7510DAAD1}"
33+
EndProject
34+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crypto.Websocket.Extensions.Benchmarks", "benchmarks\Crypto.Websocket.Extensions.Benchmarks\Crypto.Websocket.Extensions.Benchmarks.csproj", "{DBC8FB10-E26E-4852-B43D-446E35B38C5A}"
35+
EndProject
3236
Global
3337
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3438
Debug|Any CPU = Debug|Any CPU
39+
Debug|x64 = Debug|x64
40+
Debug|x86 = Debug|x86
3541
Release|Any CPU = Release|Any CPU
42+
Release|x64 = Release|x64
43+
Release|x86 = Release|x86
3644
EndGlobalSection
3745
GlobalSection(ProjectConfigurationPlatforms) = postSolution
3846
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3947
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
48+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|x64.ActiveCfg = Debug|Any CPU
49+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|x64.Build.0 = Debug|Any CPU
50+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|x86.ActiveCfg = Debug|Any CPU
51+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Debug|x86.Build.0 = Debug|Any CPU
4052
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
4153
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|Any CPU.Build.0 = Release|Any CPU
54+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|x64.ActiveCfg = Release|Any CPU
55+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|x64.Build.0 = Release|Any CPU
56+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|x86.ActiveCfg = Release|Any CPU
57+
{17A9A7BA-8387-4689-A581-A9C2CAC5B3E2}.Release|x86.Build.0 = Release|Any CPU
4258
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4359
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|Any CPU.Build.0 = Debug|Any CPU
60+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|x64.ActiveCfg = Debug|Any CPU
61+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|x64.Build.0 = Debug|Any CPU
62+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|x86.ActiveCfg = Debug|Any CPU
63+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Debug|x86.Build.0 = Debug|Any CPU
4464
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|Any CPU.ActiveCfg = Release|Any CPU
4565
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|Any CPU.Build.0 = Release|Any CPU
66+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|x64.ActiveCfg = Release|Any CPU
67+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|x64.Build.0 = Release|Any CPU
68+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|x86.ActiveCfg = Release|Any CPU
69+
{17E08CC0-D8ED-4DDD-88E1-9DADB5C8AA06}.Release|x86.Build.0 = Release|Any CPU
4670
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4771
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
72+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|x64.ActiveCfg = Debug|Any CPU
73+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|x64.Build.0 = Debug|Any CPU
74+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|x86.ActiveCfg = Debug|Any CPU
75+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Debug|x86.Build.0 = Debug|Any CPU
4876
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
4977
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|Any CPU.Build.0 = Release|Any CPU
78+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|x64.ActiveCfg = Release|Any CPU
79+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|x64.Build.0 = Release|Any CPU
80+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|x86.ActiveCfg = Release|Any CPU
81+
{081FD24C-6264-41D5-8444-C47C7331CCDE}.Release|x86.Build.0 = Release|Any CPU
5082
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
5183
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|Any CPU.Build.0 = Debug|Any CPU
84+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|x64.ActiveCfg = Debug|Any CPU
85+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|x64.Build.0 = Debug|Any CPU
86+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|x86.ActiveCfg = Debug|Any CPU
87+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Debug|x86.Build.0 = Debug|Any CPU
5288
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|Any CPU.ActiveCfg = Release|Any CPU
5389
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|Any CPU.Build.0 = Release|Any CPU
90+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|x64.ActiveCfg = Release|Any CPU
91+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|x64.Build.0 = Release|Any CPU
92+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|x86.ActiveCfg = Release|Any CPU
93+
{2AFCA5EA-E46D-40FF-A79A-310B60E23632}.Release|x86.Build.0 = Release|Any CPU
5494
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
5595
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
96+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|x64.ActiveCfg = Debug|Any CPU
97+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|x64.Build.0 = Debug|Any CPU
98+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|x86.ActiveCfg = Debug|Any CPU
99+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Debug|x86.Build.0 = Debug|Any CPU
56100
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
57101
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|Any CPU.Build.0 = Release|Any CPU
102+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|x64.ActiveCfg = Release|Any CPU
103+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|x64.Build.0 = Release|Any CPU
104+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|x86.ActiveCfg = Release|Any CPU
105+
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0}.Release|x86.Build.0 = Release|Any CPU
106+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
107+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
108+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|x64.ActiveCfg = Debug|Any CPU
109+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|x64.Build.0 = Debug|Any CPU
110+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|x86.ActiveCfg = Debug|Any CPU
111+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Debug|x86.Build.0 = Debug|Any CPU
112+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
113+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|Any CPU.Build.0 = Release|Any CPU
114+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|x64.ActiveCfg = Release|Any CPU
115+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|x64.Build.0 = Release|Any CPU
116+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|x86.ActiveCfg = Release|Any CPU
117+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A}.Release|x86.Build.0 = Release|Any CPU
58118
EndGlobalSection
59119
GlobalSection(SolutionProperties) = preSolution
60120
HideSolutionNode = FALSE
@@ -65,6 +125,7 @@ Global
65125
{081FD24C-6264-41D5-8444-C47C7331CCDE} = {42E4078C-4FBE-4B03-B889-1573332945A9}
66126
{2AFCA5EA-E46D-40FF-A79A-310B60E23632} = {42E4078C-4FBE-4B03-B889-1573332945A9}
67127
{BDE39220-9DBC-4799-A5DC-89D631A8F4A0} = {360B18BD-653A-4824-9261-C88167EEBAD2}
128+
{DBC8FB10-E26E-4852-B43D-446E35B38C5A} = {66320409-64EC-F7C5-3DEF-65E7510DAAD1}
68129
EndGlobalSection
69130
GlobalSection(ExtensibilityGlobals) = postSolution
70131
SolutionGuid = {EE3E0B94-CF20-4C22-B50B-E720E8DFD675}

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@ It helps to unify data models and usage of more clients together.
2323
* targets `netstandard2.1`, `net6.0`, `net7.0`, `net8.0`, `net9.0`, `net10.0`
2424
* built on [Websocket.Client 5.4.0](https://www.nuget.org/packages/Websocket.Client/5.4.0) through the updated exchange clients
2525
* third-party exchange adapters for Bybit, Luno, and VALR remain enabled; NuGet resolves the shared websocket transport to the newer package version
26+
* benchmarked order book hot paths with [BenchmarkDotNet](benchmarks/README.md)
2627
* reactive extensions ([Rx.NET](https://github.com/Reactive-Extensions/Rx.NET))
2728
* integrated logging abstraction ([LibLog](https://github.com/damianh/LibLog))
2829

30+
### Performance
31+
32+
The order book implementation is tuned for allocation-sensitive websocket streams. Common L2 diff processing avoids temporary notification objects when nobody is subscribed, keeps internal source-to-orderbook handoff on the single-update path, and uses list-based dispatch for bulk level updates to avoid interface enumerator allocations.
33+
34+
The current benchmark suite focuses on `CryptoOrderBook`, `CryptoOrderBookL2`, and related source adapters. In the latest pass, representative BenchmarkDotNet runs showed `CryptoOrderBook.BidLevels` improving from 17,822 ns / 77 KB to 5,409 ns / 4.8 KB, and `CryptoOrderBookL2` diff processing improving from 935 ns / 545 B to 665 ns / 160 B. See the [benchmarks README](benchmarks/README.md) for commands and detailed results.
35+
2936
### Supported exchanges
3037

3138
| Logo | Name | Websocket client |
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Crypto.Websocket.Extensions.Core.OrderBooks.Models;
2+
using Crypto.Websocket.Extensions.Core.OrderBooks.Sources;
3+
using Microsoft.Extensions.Logging.Abstractions;
4+
5+
namespace Crypto.Websocket.Extensions.Benchmarks;
6+
7+
internal sealed class BenchmarkOrderBookSource : OrderBookSourceBase
8+
{
9+
public BenchmarkOrderBookSource() : base(NullLogger.Instance)
10+
{
11+
BufferEnabled = false;
12+
LoadSnapshotEnabled = false;
13+
}
14+
15+
public override string ExchangeName => "benchmark";
16+
17+
public void StreamSnapshotRaw(OrderBookLevelBulk snapshot)
18+
{
19+
StreamSnapshot(snapshot);
20+
}
21+
22+
public void StreamBulk(OrderBookLevelBulk bulk)
23+
{
24+
BufferData(bulk);
25+
}
26+
27+
protected override Task<OrderBookLevelBulk?> LoadSnapshotInternal(string? pair, int count = 1000)
28+
{
29+
return Task.FromResult<OrderBookLevelBulk?>(null);
30+
}
31+
32+
protected override OrderBookLevelBulk[] ConvertData(object data)
33+
{
34+
return data is OrderBookLevelBulk bulk
35+
? new[] { bulk }
36+
: Array.Empty<OrderBookLevelBulk>();
37+
}
38+
39+
protected override bool TryConvertData(object data, out OrderBookLevelBulk? bulk)
40+
{
41+
bulk = data as OrderBookLevelBulk;
42+
return bulk != null;
43+
}
44+
45+
protected override OrderBookLevelBulk[] ConvertData(object[] data)
46+
{
47+
if (data.Length == 0)
48+
return Array.Empty<OrderBookLevelBulk>();
49+
50+
if (data.Length == 1 && data[0] is OrderBookLevelBulk single)
51+
return new[] { single };
52+
53+
var result = new OrderBookLevelBulk[data.Length];
54+
var count = 0;
55+
foreach (var item in data)
56+
{
57+
if (item is OrderBookLevelBulk bulk)
58+
result[count++] = bulk;
59+
}
60+
61+
if (count == result.Length)
62+
return result;
63+
64+
Array.Resize(ref result, count);
65+
return result;
66+
}
67+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<IsPackable>false</IsPackable>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\Crypto.Websocket.Extensions.Core\Crypto.Websocket.Extensions.Core.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Crypto.Websocket.Extensions.Core.Models;
2+
using Crypto.Websocket.Extensions.Core.OrderBooks;
3+
using Crypto.Websocket.Extensions.Core.OrderBooks.Models;
4+
using Crypto.Websocket.Extensions.Core.Utils;
5+
6+
namespace Crypto.Websocket.Extensions.Benchmarks;
7+
8+
internal static class OrderBookBenchmarkData
9+
{
10+
public const string Pair = "BTC/USD";
11+
public const int LevelsPerSide = 500;
12+
public const int DiffCount = 1000;
13+
14+
public static readonly string PairClean = CryptoPairsHelper.Clean(Pair);
15+
public static readonly OrderBookLevelBulk Snapshot = CreateSnapshot(PairClean, LevelsPerSide);
16+
public static readonly OrderBookLevelBulk[] Diffs = CreateDiffs(PairClean, DiffCount, LevelsPerSide, LevelsPerSide);
17+
18+
private static OrderBookLevelBulk CreateSnapshot(string pair, int count)
19+
{
20+
var levels = new OrderBookLevel[count * 2];
21+
var index = 0;
22+
23+
for (var i = 0; i < count; i++)
24+
levels[index++] = CreateLevel(pair, i, count * 2 + i, CryptoOrderSide.Bid);
25+
26+
for (var i = count * 2; i > count; i--)
27+
levels[index++] = CreateLevel(pair, i, count * 4 + i, CryptoOrderSide.Ask);
28+
29+
return new OrderBookLevelBulk(OrderBookAction.Insert, levels, CryptoOrderBookType.L2);
30+
}
31+
32+
private static OrderBookLevelBulk[] CreateDiffs(string pair, int iterations, int maxBidPrice, int maxAskCount)
33+
{
34+
var bulks = new OrderBookLevelBulk[iterations];
35+
for (var i = 0; i < iterations; i++)
36+
{
37+
var levels = new[]
38+
{
39+
i % 10 == 0
40+
? CreateLevel(pair, (i % maxBidPrice) + 0.4, i + 50, CryptoOrderSide.Bid)
41+
: CreateLevel(pair, i % maxBidPrice, i + 50, CryptoOrderSide.Bid),
42+
i % 10 == 0
43+
? CreateLevel(pair, (Math.Max(i - 55, 1) % maxBidPrice) + 0.4, i + 600, CryptoOrderSide.Bid)
44+
: CreateLevel(pair, Math.Max(i - 55, 1) % maxBidPrice, i + 600, CryptoOrderSide.Bid),
45+
i % 10 == 0
46+
? CreateLevel(pair, maxBidPrice + (i % maxAskCount) + 0.4, i + 400, CryptoOrderSide.Ask)
47+
: CreateLevel(pair, maxBidPrice + (i % maxAskCount), i + 400, CryptoOrderSide.Ask),
48+
i % 10 == 0
49+
? CreateLevel(pair, maxBidPrice + (Math.Min(i + 55, maxAskCount) % maxAskCount) + 0.4, i + 3000, CryptoOrderSide.Ask)
50+
: CreateLevel(pair, maxBidPrice + (Math.Min(i + 55, maxAskCount) % maxAskCount), i + 3000, CryptoOrderSide.Ask)
51+
};
52+
53+
var action = i % 10 == 0 ? OrderBookAction.Insert : OrderBookAction.Update;
54+
bulks[i] = new OrderBookLevelBulk(action, levels, CryptoOrderBookType.L2);
55+
}
56+
57+
return bulks;
58+
}
59+
60+
private static OrderBookLevel CreateLevel(string pair, double? price, double? amount, CryptoOrderSide side)
61+
{
62+
return new OrderBookLevel(
63+
$"{price}-{(side == CryptoOrderSide.Bid ? "bid" : "ask")}",
64+
side,
65+
price,
66+
amount,
67+
3,
68+
pair);
69+
}
70+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using BenchmarkDotNet.Attributes;
2+
using Crypto.Websocket.Extensions.Core.OrderBooks;
3+
4+
namespace Crypto.Websocket.Extensions.Benchmarks;
5+
6+
[MemoryDiagnoser]
7+
[ShortRunJob]
8+
[RankColumn]
9+
public class OrderBookProcessingBenchmarks
10+
{
11+
[Benchmark(Baseline = true, Description = "OrderBookL2 process diffs", OperationsPerInvoke = OrderBookBenchmarkData.DiffCount)]
12+
public double OrderBookL2_ProcessDiffs()
13+
{
14+
return ProcessDiffs(createL2: true, subscribeToUpdates: false);
15+
}
16+
17+
[Benchmark(Description = "OrderBookL2 process diffs with observer", OperationsPerInvoke = OrderBookBenchmarkData.DiffCount)]
18+
public double OrderBookL2_ProcessDiffs_WithObserver()
19+
{
20+
return ProcessDiffs(createL2: true, subscribeToUpdates: true);
21+
}
22+
23+
[Benchmark(Description = "OrderBook process L2 diffs", OperationsPerInvoke = OrderBookBenchmarkData.DiffCount)]
24+
public double OrderBook_ProcessDiffs()
25+
{
26+
return ProcessDiffs(createL2: false, subscribeToUpdates: false);
27+
}
28+
29+
[Benchmark(Description = "OrderBook process L2 diffs with observer", OperationsPerInvoke = OrderBookBenchmarkData.DiffCount)]
30+
public double OrderBook_ProcessDiffs_WithObserver()
31+
{
32+
return ProcessDiffs(createL2: false, subscribeToUpdates: true);
33+
}
34+
35+
private static double ProcessDiffs(bool createL2, bool subscribeToUpdates)
36+
{
37+
using var source = new BenchmarkOrderBookSource();
38+
using var orderBook = CreateOrderBook(createL2, source);
39+
40+
var notifications = 0;
41+
using var subscription = subscribeToUpdates
42+
? orderBook.OrderBookUpdatedStream.Subscribe(_ => notifications++)
43+
: null;
44+
45+
source.StreamSnapshotRaw(OrderBookBenchmarkData.Snapshot);
46+
47+
foreach (var bulk in OrderBookBenchmarkData.Diffs)
48+
source.StreamBulk(bulk);
49+
50+
return orderBook.BidPrice + orderBook.AskPrice + orderBook.BidAmount + orderBook.AskAmount + notifications;
51+
}
52+
53+
private static ICryptoOrderBook CreateOrderBook(bool createL2, BenchmarkOrderBookSource source)
54+
{
55+
ICryptoOrderBook orderBook = createL2
56+
? new CryptoOrderBookL2(OrderBookBenchmarkData.Pair, source)
57+
: new CryptoOrderBook(OrderBookBenchmarkData.Pair, source, CryptoOrderBookType.L2);
58+
59+
orderBook.SnapshotReloadEnabled = false;
60+
orderBook.ValidityCheckEnabled = false;
61+
orderBook.NotifyForLevelAndAbove = 0;
62+
return orderBook;
63+
}
64+
}

0 commit comments

Comments
 (0)