Skip to content

Commit 70a9a84

Browse files
author
codez0mb1e
committed
Merge branch 'develop'
2 parents f10ad97 + b931bb5 commit 70a9a84

File tree

16 files changed

+102
-85
lines changed

16 files changed

+102
-85
lines changed

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# How to contribute?
2+
3+
*Welcome on board!*
4+
5+
If U have useful stuff related to this project's Objectives, feel free to create a branch(es) from `main`. Then just add content and [Pull request](https://github.com/codez0mb1e/BinanceBot/pulls) changes.
6+
7+
Thanks in advance :tada:!

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Dmitry Petukhov.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Market Bot for Binance Exchange
22

3+
[![Status](https://img.shields.io/badge/status-in_active_development-green.svg)](https://github.com/codez0mb1e/BinanceBot/projects/1)
4+
[![Contributors Welcome](https://img.shields.io/badge/contributing-welcome-blue.svg)](CONTRIBUTING.md)
5+
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6+
7+
38
Naive _Market Maker Bot_ for Binance.
49

510
Solution contains two console projects:
@@ -18,37 +23,14 @@ Turn off `TEST_ORDER_CREATION_MODE` compilation symbol in [MarketMakerBot.cs](sr
1823
to _create real order_ in order book.
1924

2025

21-
## Roadmap
22-
23-
#### Throlling
24-
25-
Binance has numerous limits to requests, orders count, min/max volume of order, etc. The networks restrictions should be taken into BinanceBot working as part of `BinanceClientConfiguration`,
26-
and the orders restrictions - as part of `MarkerStrategyConfiguration`.
27-
28-
#### Security
29-
30-
Binance API keys should be stored in secured storage (such as `Azure Key Vault` service) instead of plain text such it is now.
31-
32-
#### Configurations
33-
34-
Any configuration (of connectors or bot) should be placed in separate configuration storage (such as `JSON files` in local file system).
35-
This will allow you to reconfigure the bot without the need for recompilation.
36-
37-
#### Other
38-
39-
BinanceBot doesn’t processed network connection errors.
40-
It would be to implement `Retry Policies` for the broken connections and handling other network errors.
41-
42-
The solution doesn’t contain any `Unit Tests`/`Integration Tests`, which is a bad practice.
43-
4426
## Requirements
4527

46-
- .NET Core 5.0.
28+
- .NET 6.0
4729

4830

4931
## References
5032

5133
1. [Binance official API docs](https://github.com/binance-exchange/binance-official-api-docs).
52-
2. [Official C# Wrapper for the Binance exchange API](https://github.com/glitch100/BinanceDotNet).
34+
1. [Official C# Wrapper for the Binance exchange API](https://github.com/glitch100/BinanceDotNet).
5335

5436
[binance_bot_running]: https://static.0xcode.in/images/binance_bot_running.png "binance bot"

src/BinanceBot.Market/Abstracts/BaseMarketBot.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Threading.Tasks;
4-
using Binance.Net.Objects.Spot.SpotData;
4+
using Binance.Net.Objects.Models.Spot;
55
using NLog;
66

77
namespace BinanceBot.Market

src/BinanceBot.Market/Abstracts/IMarketBot.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Collections.Generic;
22
using System.Threading.Tasks;
3-
using Binance.Net.Objects.Spot.SpotData;
3+
using Binance.Net.Objects.Models.Spot;
44

55

66
namespace BinanceBot.Market
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.1</TargetFramework>
55
<LangVersion>9.0</LangVersion>
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Binance.Net" Version="7.2.7" />
10-
<PackageReference Include="NLog" Version="4.7.13" />
9+
<PackageReference Include="Binance.Net" Version="8.0.13" />
10+
<PackageReference Include="NLog" Version="4.7.15" />
1111
</ItemGroup>
1212

1313
</Project>

src/BinanceBot.Market/Core/MarketDepth.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using Binance.Net.Enums;
5-
using Binance.Net.Objects;
5+
using Binance.Net.Objects.Models;
66
using BinanceBot.Market.Utility;
77

88
namespace BinanceBot.Market.Core
@@ -100,7 +100,7 @@ public void UpdateDepth(IEnumerable<BinanceOrderBookEntry> asks, IEnumerable<Bin
100100
if (asks == null && bids == null) return;
101101

102102

103-
void UpdateOrderBook(IEnumerable<BinanceOrderBookEntry> updates, IDictionary<decimal, decimal> orders)
103+
static void UpdateOrderBook(IEnumerable<BinanceOrderBookEntry> updates, IDictionary<decimal, decimal> orders)
104104
{
105105
if (orders == null) throw new ArgumentNullException(nameof(orders));
106106
if (updates == null) return;

src/BinanceBot.Market/CreateOrderRequest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class CreateOrderRequest
1111

1212
public OrderSide Side { get; set; }
1313

14-
public OrderType Type { get; set; }
14+
public SpotOrderType OrderType { get; set; }
1515

1616
public TimeInForce? TimeInForce { get; set; }
1717

@@ -24,6 +24,7 @@ public class CreateOrderRequest
2424
public decimal? StopPrice { get; set; }
2525

2626
public decimal? IcebergQuantity { get; set; }
27+
2728
public int? RecvWindow { get; set; }
2829
}
2930
}

src/BinanceBot.Market/MarketDepthManager.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using System;
22
using System.Threading.Tasks;
3-
using Binance.Net.Interfaces;
4-
using Binance.Net.Objects.Spot.MarketData;
5-
using BinanceBot.Market.Core;
3+
using Binance.Net.Interfaces.Clients;
4+
using Binance.Net.Objects.Models.Spot;
65
using CryptoExchange.Net.Objects;
76

87

@@ -57,7 +56,7 @@ public async Task BuildAsync(MarketDepth marketDepth, short limit = 10)
5756
if (limit <= 0)
5857
throw new ArgumentOutOfRangeException(nameof(limit));
5958

60-
WebCallResult<BinanceOrderBook> response = await _restClient.Spot.Market.GetOrderBookAsync(marketDepth.Symbol, limit);
59+
WebCallResult<BinanceOrderBook> response = await _restClient.SpotApi.ExchangeData.GetOrderBookAsync(marketDepth.Symbol, limit);
6160
BinanceOrderBook orderBook = response.Data;
6261

6362
marketDepth.UpdateDepth(orderBook.Asks, orderBook.Bids, orderBook.LastUpdateId);
@@ -74,7 +73,7 @@ public void StreamUpdates(MarketDepth marketDepth, TimeSpan? updateInterval = de
7473
if (marketDepth == null)
7574
throw new ArgumentNullException(nameof(marketDepth));
7675

77-
_webSocketClient.Spot.SubscribeToOrderBookUpdatesAsync(
76+
_webSocketClient.SpotStreams.SubscribeToOrderBookUpdatesAsync(
7877
marketDepth.Symbol,
7978
(int)updateInterval?.TotalMilliseconds,
8079
marketData => marketDepth.UpdateDepth(marketData.Data.Asks, marketData.Data.Bids, marketData.Data.LastUpdateId));

src/BinanceBot.Market/MarketMakerBot.cs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
using System.Collections.Generic;
55
using System.Threading.Tasks;
66
using Binance.Net.Enums;
7-
using Binance.Net.Interfaces;
8-
using Binance.Net.Objects.Spot.SpotData;
9-
using BinanceBot.Market.Core;
10-
using BinanceBot.Market.Strategies;
7+
using Binance.Net.Interfaces.Clients;
8+
using Binance.Net.Objects.Models.Spot;
119
using CryptoExchange.Net.Objects;
1210
using NLog;
1311

@@ -50,11 +48,18 @@ public MarketMakerBot(
5048

5149
public override async Task ValidateServerTimeAsync()
5250
{
53-
var exchangeServerTimeResult = await _binanceRestClient.Spot.System.GetServerTimeAsync().ConfigureAwait(false);
54-
TimeSpan delay = exchangeServerTimeResult.Data.Subtract(DateTime.UtcNow);
55-
56-
if (delay > MarketStrategy.Config.ReceiveWindow)
57-
Logger.Warn($"Exchange server time doesn't match with local time. Current delay {delay.TotalSeconds} ms");
51+
CallResult<long> testConnectResponse = await _binanceRestClient.SpotApi.ExchangeData.PingAsync().ConfigureAwait(false);
52+
53+
if (testConnectResponse.Error != null)
54+
Logger.Error(testConnectResponse.Error.Message);
55+
else
56+
{
57+
string msg = $"Connection was established successfully. Approximate ping time: {testConnectResponse.Data} ms";
58+
if (testConnectResponse.Data > 1000)
59+
Logger.Warn(msg);
60+
else
61+
Logger.Info(msg);
62+
}
5863
}
5964

6065

@@ -63,7 +68,7 @@ public override async Task<IEnumerable<BinanceOrder>> GetOpenedOrdersAsync(strin
6368
if (string.IsNullOrEmpty(symbol))
6469
throw new ArgumentException("Invalid symbol value", nameof(symbol));
6570

66-
var response = await _binanceRestClient.Spot.Order.GetOpenOrdersAsync(symbol).ConfigureAwait(false);
71+
var response = await _binanceRestClient.SpotApi.Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false);
6772
return response.Data;
6873
}
6974

@@ -74,7 +79,7 @@ public override async Task CancelOrdersAsync(IEnumerable<BinanceOrder> orders)
7479
throw new ArgumentNullException(nameof(orders));
7580

7681
foreach (var order in orders)
77-
await _binanceRestClient.Spot.Order.CancelOrderAsync(orderId: order.OrderId, origClientOrderId: order.ClientOrderId, symbol: order.Symbol).ConfigureAwait(false);
82+
await _binanceRestClient.SpotApi.Trading.CancelOrderAsync(orderId: order.Id, origClientOrderId: order.ClientOrderId, symbol: order.Symbol).ConfigureAwait(false);
7883
}
7984

8085

@@ -83,25 +88,23 @@ public override async Task<BinancePlacedOrder> CreateOrderAsync(CreateOrderReque
8388
if (order == null) throw new ArgumentNullException(nameof(order));
8489

8590
#if TEST_ORDER_CREATION_MODE
86-
WebCallResult<BinancePlacedOrder> response = await _binanceRestClient.Spot.Order.PlaceTestOrderAsync(
87-
symbol: order.Symbol,
88-
side: order.Side,
89-
type: order.Type,
90-
price: order.Price,
91-
quantity: order.Quantity,
92-
timeInForce: order.TimeInForce,
93-
newClientOrderId: order.NewClientOrderId,
94-
receiveWindow:order.RecvWindow)
91+
WebCallResult<BinancePlacedOrder> response = await _binanceRestClient.SpotApi.Trading.PlaceTestOrderAsync(
92+
order.Symbol, order.Side, order.OrderType, order.Quantity,
93+
newClientOrderId:order.NewClientOrderId,
94+
receiveWindow:order.RecvWindow)
9595
.ConfigureAwait(false);
9696
#else
97-
WebCallResult<BinancePlacedOrder> response = await _binanceRestClient.Spot.Order.PlaceOrderAsync(
98-
symbol: order.Symbol,
99-
side: order.Side,
100-
type: order.Type,
97+
WebCallResult<BinancePlacedOrder> response = await _binanceRestClient.SpotApi.Trading.PlaceOrderAsync(
98+
// general
99+
order.Symbol,
100+
order.Side,
101+
order.OrderType,
102+
// price-quantity
101103
price: order.Price,
102104
quantity: order.Quantity,
103-
timeInForce: order.TimeInForce,
105+
// metadata
104106
newClientOrderId: order.NewClientOrderId,
107+
timeInForce: order.TimeInForce,
105108
receiveWindow: order.RecvWindow)
106109
.ConfigureAwait(false);
107110
#endif
@@ -151,12 +154,16 @@ private async Task OnMarketBestPairChanged(object sender, MarketBestPairChangedE
151154
{
152155
var newOrderRequest = new CreateOrderRequest
153156
{
157+
// general
154158
Symbol = Symbol,
155-
Quantity = Decimal.Round(q.Volume, decimals: MarketStrategy.Config.QuoteAssetPrecision),
156-
Price = Decimal.Round(q.Price, decimals: MarketStrategy.Config.PricePrecision),
157159
Side = q.Direction,
158-
Type = OrderType.Limit,
159-
TimeInForce = TimeInForce.GoodTillCancel,
160+
OrderType = SpotOrderType.Limit,
161+
// price-quantity
162+
Price = Decimal.Round(q.Price, decimals: MarketStrategy.Config.PricePrecision),
163+
Quantity = Decimal.Round(q.Volume, decimals: MarketStrategy.Config.QuoteAssetPrecision),,
164+
// metadata
165+
NewClientOrderId = "test",
166+
TimeInForce = TimeInForce.GoodTillCanceled,
160167
RecvWindow = (int)MarketStrategy.Config.ReceiveWindow.TotalMilliseconds
161168
};
162169

0 commit comments

Comments
 (0)