Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ The following cryptocurrency exchanges are supported:
| KuCoin | x | x | T R B | |
| LBank | x | x | R | |
| Livecoin | x | x | | |
| MEXC | x | x | | |
| MEXC | x | x | B | |
| NDAX | x | x | T R | |
| OKCoin | x | x | R B | |
| OKEx | x | x | T R B O | |
Expand Down
109 changes: 108 additions & 1 deletion src/ExchangeSharp/API/Exchanges/MEXC/ExchangeMEXCAPI.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ExchangeSharp.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ExchangeSharp.API.Exchanges.MEXC.Models;

namespace ExchangeSharp
{
Expand All @@ -21,6 +23,7 @@ private ExchangeMEXCAPI()
MarketSymbolSeparator = string.Empty;
MarketSymbolIsUppercase = true;
RateLimit = new RateGate(20, TimeSpan.FromSeconds(2));
WebSocketOrderBookType = WebSocketOrderBookType.FullBookFirstThenDeltas;
}

public override Task<string> ExchangeMarketSymbolToGlobalMarketSymbolAsync(string marketSymbol)
Expand Down Expand Up @@ -369,6 +372,110 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy
await MakeJsonRequestAsync<JToken>("/order", BaseUrl, payload, "DELETE");
}

protected override async Task<IWebSocket> OnGetDeltaOrderBookWebSocketAsync(
Action<ExchangeOrderBook> callback,
int maxCount = 20,
params string[] marketSymbols
)
{
if (marketSymbols == null || marketSymbols.Length == 0)
{
marketSymbols = (await GetMarketSymbolsAsync()).ToArray();
}

var initialSequenceIds = new Dictionary<string, long>();

return await ConnectPublicWebSocketAsync(
string.Empty,
(_socket, msg) =>
{
var json = msg.ToStringFromUTF8();

MarketDepthDiffUpdate update = null;
try
{
update = JsonConvert.DeserializeObject<MarketDepthDiffUpdate>(json, SerializerSettings);
}
catch
{
}

if (update == null || string.IsNullOrWhiteSpace(update.Channel) || update.Details == null)
{
return Task.CompletedTask;
}

if (update.Details.Version < initialSequenceIds[update.Symbol])
{
// A deprecated update should be ignored
return Task.CompletedTask;
}

var eventTimeDateTime = update.EventTime.UnixTimeStampToDateTimeMilliseconds();

var orderBook = new ExchangeOrderBook
{
IsFromSnapshot = false,
ExchangeName = Name,
SequenceId = update.Details.Version,
MarketSymbol = update.Symbol,
LastUpdatedUtc = eventTimeDateTime,
};

if (update.Details.Asks != null)
{
foreach (var ask in update.Details.Asks)
{
orderBook.Asks[ask.Price] = new ExchangeOrderPrice
{
Price = ask.Price,
Amount = ask.Volume,
};
}
}

if (update.Details.Bids != null)
{
foreach (var bid in update.Details.Bids)
{
orderBook.Bids[bid.Price] = new ExchangeOrderPrice
{
Price = bid.Price,
Amount = bid.Volume,
};
}
}

callback(orderBook);

return Task.CompletedTask;
},
async (_socket) =>
{
foreach (var marketSymbol in marketSymbols) // "Every websocket connection maximum support 30 subscriptions at one time." - API docs
{
var initialBook = await OnGetOrderBookAsync(marketSymbol, maxCount);
initialBook.IsFromSnapshot = true;

callback(initialBook);

initialSequenceIds[marketSymbol] = initialBook.SequenceId;

var subscriptionParams = new List<string>
{
$"spot@public.increase.depth.v3.api@{marketSymbol}"
};

await _socket.SendMessageAsync(new WebSocketSubscription
{
Method = "SUBSCRIPTION",
Params = subscriptionParams,
});
}
}
);
}

private async Task<JToken> GetBalance()
{
var token = await MakeJsonRequestAsync<JToken>("/account", payload: await GetNoncePayloadAsync());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace ExchangeSharp.API.Exchanges.MEXC.Models
{
internal class MarketDepthDiffUpdateDetailItem
{
[JsonProperty("p")]
public decimal Price { get; set; }

[JsonProperty("v")]
public decimal Volume { get; set; }
}

internal class MarketDepthDiffUpdateDetails
{
public List<MarketDepthDiffUpdateDetailItem> Asks { get; set; }

public List<MarketDepthDiffUpdateDetailItem> Bids { get; set; }

[JsonProperty("e")]
public string EventType { get; set; }

[JsonProperty("r")]
public long Version { get; set; }
}

internal class MarketDepthDiffUpdate
{
[JsonProperty("c")]
public string Channel { get; set; }

[JsonProperty("d")]
public MarketDepthDiffUpdateDetails Details { get; set; }

[JsonProperty("s")]
public string Symbol { get; set; }

/// <summary>
/// Milliseconds since Unix epoch
/// </summary>
[JsonProperty("t")]
public long EventTime { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace ExchangeSharp.API.Exchanges.MEXC.Models
{
internal class WebSocketSubscription
{
public string Method { get; set; }

public List<string> Params { get; set; }
}
}