diff --git a/CoinbasePro.Specs/JsonFixtures/Websocket/WebSocketTypeResponseFixture.cs b/CoinbasePro.Specs/JsonFixtures/Websocket/WebSocketTypeResponseFixture.cs index a77bfaa6..1207c137 100644 --- a/CoinbasePro.Specs/JsonFixtures/Websocket/WebSocketTypeResponseFixture.cs +++ b/CoinbasePro.Specs/JsonFixtures/Websocket/WebSocketTypeResponseFixture.cs @@ -148,6 +148,62 @@ public static string CreateDoneResponse() }"; } + public static string CreateStatusResponse() + { + return @" +{ + ""type"": ""status"", + ""products"": [ + { + ""id"": ""BTC-USD"", + ""base_currency"": ""BTC"", + ""quote_currency"": ""USD"", + ""base_min_size"": ""0.001"", + ""base_max_size"": ""70"", + ""base_increment"": ""0.00000001"", + ""quote_increment"": ""0.01"", + ""display_name"": ""BTC/USD"", + ""status"": ""online"", + ""status_message"": null, + ""min_market_funds"": ""10"", + ""max_market_funds"": ""1000000"", + ""post_only"": false, + ""limit_only"": false, + ""cancel_only"": false + } + ], + ""currencies"": [ + { + ""id"": ""USD"", + ""name"": ""United States Dollar"", + ""min_size"": ""0.01000000"", + ""status"": ""online"", + ""status_message"": null, + ""max_precision"": ""0.01"", + ""convertible_to"": [""USDC""], ""details"": { } + }, + { + ""id"": ""USDC"", + ""name"": ""USD Coin"", + ""min_size"": ""0.00000100"", + ""status"": ""online"", + ""status_message"": null, + ""max_precision"": ""0.000001"", + ""convertible_to"": [""USD""], ""details"": { } + }, + { + ""id"": ""BTC"", + ""name"": ""Bitcoin"", + ""min_size"":"" 0.00000001"", + ""status"": ""online"", + ""status_message"": null, + ""max_precision"": ""0.00000001"", + ""convertible_to"": [] + } + ] +}"; + } + public static string CreateMatchResponse() { return @" diff --git a/CoinbasePro.Specs/WebSocket/WebSocketSpecs.cs b/CoinbasePro.Specs/WebSocket/WebSocketSpecs.cs index e710fcb8..0fd1720e 100644 --- a/CoinbasePro.Specs/WebSocket/WebSocketSpecs.cs +++ b/CoinbasePro.Specs/WebSocket/WebSocketSpecs.cs @@ -147,7 +147,7 @@ class with_authentication_with_no_channels It should_have_called_send_with_authentication_properties = () => The(). - WasToldTo(p => p.Send(@"{""type"":""subscribe"",""product_ids"":[""BTC-USD""],""channels"":[{""name"":""full"",""product_ids"":[""BTC-USD""]},{""name"":""heartbeat"",""product_ids"":[""BTC-USD""]},{""name"":""level2"",""product_ids"":[""BTC-USD""]},{""name"":""matches"",""product_ids"":[""BTC-USD""]},{""name"":""ticker"",""product_ids"":[""BTC-USD""]},{""name"":""user"",""product_ids"":[""BTC-USD""]}],""key"":""key"",""passphrase"":""passphrase"",""timestamp"":""-62135596800""}")); + WasToldTo(p => p.Send(@"{""type"":""subscribe"",""product_ids"":[""BTC-USD""],""channels"":[{""name"":""full"",""product_ids"":[""BTC-USD""]},{""name"":""heartbeat"",""product_ids"":[""BTC-USD""]},{""name"":""level2"",""product_ids"":[""BTC-USD""]},{""name"":""matches"",""product_ids"":[""BTC-USD""]},{""name"":""ticker"",""product_ids"":[""BTC-USD""]},{""name"":""user"",""product_ids"":[""BTC-USD""]},{""name"":""status"",""product_ids"":[""BTC-USD""]}],""key"":""key"",""passphrase"":""passphrase"",""timestamp"":""-62135596800""}")); } class with_authentication_with_specified_channels @@ -178,7 +178,7 @@ class without_authentication It should_have_called_send_without_authentication_properties = () => The(). - WasToldTo(p => p.Send(@"{""type"":""subscribe"",""product_ids"":[""BTC-USD""],""channels"":[{""name"":""full"",""product_ids"":[""BTC-USD""]},{""name"":""heartbeat"",""product_ids"":[""BTC-USD""]},{""name"":""level2"",""product_ids"":[""BTC-USD""]},{""name"":""matches"",""product_ids"":[""BTC-USD""]},{""name"":""ticker"",""product_ids"":[""BTC-USD""]},{""name"":""user"",""product_ids"":[""BTC-USD""]}],""timestamp"":""-62135596800""}")); + WasToldTo(p => p.Send(@"{""type"":""subscribe"",""product_ids"":[""BTC-USD""],""channels"":[{""name"":""full"",""product_ids"":[""BTC-USD""]},{""name"":""heartbeat"",""product_ids"":[""BTC-USD""]},{""name"":""level2"",""product_ids"":[""BTC-USD""]},{""name"":""matches"",""product_ids"":[""BTC-USD""]},{""name"":""ticker"",""product_ids"":[""BTC-USD""]},{""name"":""user"",""product_ids"":[""BTC-USD""]},{""name"":""status"",""product_ids"":[""BTC-USD""]}],""timestamp"":""-62135596800""}")); } } @@ -327,6 +327,20 @@ class when_response_type_is_done WasToldTo(p => p.Invoke(Param.IsAny>>(), Param.IsAny(), Param.IsAny>())); } + class when_response_type_is_status + { + Because of = () => + { + Subject.Start(product_type_inputs, no_channel_type_inputs); + + websocket_feed.Raise(e => e.MessageReceived += null, new MessageReceivedEventArgs(WebSocketTypeResponseFixture.CreateStatusResponse())); + }; + + It should_have_invoked_status_response = () => + The(). + WasToldTo(p => p.Invoke(Param.IsAny>>(), Param.IsAny(), Param.IsAny>())); + } + class when_response_type_is_match { Because of = () => diff --git a/CoinbasePro/WebSocket/IWebSocket.cs b/CoinbasePro/WebSocket/IWebSocket.cs index 9baf77e2..4c914e80 100644 --- a/CoinbasePro/WebSocket/IWebSocket.cs +++ b/CoinbasePro/WebSocket/IWebSocket.cs @@ -22,6 +22,7 @@ public interface IWebSocket void WebSocket_Closed(object sender, EventArgs e); event EventHandler> OnTickerReceived; + event EventHandler> OnStatusReceived; event EventHandler> OnSubscriptionReceived; event EventHandler> OnSnapShotReceived; event EventHandler> OnLevel2UpdateReceived; diff --git a/CoinbasePro/WebSocket/Models/Response/Status.cs b/CoinbasePro/WebSocket/Models/Response/Status.cs new file mode 100644 index 00000000..f6cc2a13 --- /dev/null +++ b/CoinbasePro/WebSocket/Models/Response/Status.cs @@ -0,0 +1,84 @@ +namespace CoinbasePro.WebSocket.Models.Response +{ + public class Status : BaseMessage + { + public Product[] Products { get; set; } + + public Currency[] Currencies { get; set; } + } + + public class Currency + { + public string Id { get; set; } + + public string Name { get; set; } + + public decimal MinSize { get; set; } + + public string Status { get; set; } + + public string StatusMessage { get; set; } + + public decimal MaxPrecision { get; set; } + + public string[] ConvertibleTo { get; set; } + + public Details Details { get; set; } + } + + public class Details + { + public string Type { get; set; } + + public string Symbol { get; set; } + + public int NetworkConfirmations { get; set; } + + public int SortOrder { get; set; } + + public string CryptoAddressLink { get; set; } + + public string CryptoTransactionLink { get; set; } + + public string[] PushPaymentMethods { get; set; } + + public long? MaxWithdrawalAmount { get; set; } + + public string[] GroupTypes { get; set; } + + public string DisplayName { get; set; } + } + + public class Product + { + public string Id { get; set; } + + public string BaseCurrency { get; set; } + + public string QuoteCurrency { get; set; } + + public decimal BaseMinSize { get; set; } + + public decimal BaseMaxSize { get; set; } + + public decimal BaseIncrement { get; set; } + + public decimal QuoteIncrement { get; set; } + + public string DisplayName { get; set; } + + public string Status { get; set; } + + public string StatusMessage { get; set; } + + public decimal MinMarketFunds { get; set; } + + public decimal MaxMarketFunds { get; set; } + + public bool PostOnly { get; set; } + + public bool LimitOnly { get; set; } + + public bool CancelOnly { get; set; } + } +} diff --git a/CoinbasePro/WebSocket/Types/ChannelType.cs b/CoinbasePro/WebSocket/Types/ChannelType.cs index 2373c911..4ba95165 100644 --- a/CoinbasePro/WebSocket/Types/ChannelType.cs +++ b/CoinbasePro/WebSocket/Types/ChannelType.cs @@ -15,6 +15,8 @@ public enum ChannelType [EnumMember(Value = "ticker")] Ticker, [EnumMember(Value = "user")] - User + User, + [EnumMember(Value = "status")] + Status } } diff --git a/CoinbasePro/WebSocket/Types/ResponseType.cs b/CoinbasePro/WebSocket/Types/ResponseType.cs index 7417b547..e46f9c69 100644 --- a/CoinbasePro/WebSocket/Types/ResponseType.cs +++ b/CoinbasePro/WebSocket/Types/ResponseType.cs @@ -18,6 +18,7 @@ public enum ResponseType LastMatch, Change, Activate, - Error + Error, + Status } } diff --git a/CoinbasePro/WebSocket/WebSocket.cs b/CoinbasePro/WebSocket/WebSocket.cs index 24991173..8b6e3cba 100644 --- a/CoinbasePro/WebSocket/WebSocket.cs +++ b/CoinbasePro/WebSocket/WebSocket.cs @@ -239,6 +239,10 @@ public void WebSocket_MessageReceived(object sender, MessageReceivedEventArgs e) var activate = JsonConfig.DeserializeObject(json); webSocketFeed.Invoke(OnActivateReceived, sender, new WebfeedEventArgs(activate)); break; + case ResponseType.Status: + var status = JsonConfig.DeserializeObject(json); + webSocketFeed.Invoke(OnStatusReceived, sender, new WebfeedEventArgs(status)); + break; default: Log.Error("Unknown ResponseType {@ResponseJson}. Ignoring message received.", json); break; @@ -323,6 +327,7 @@ private string SubscribeMessage(bool withAuthentication, List channels, } public event EventHandler> OnTickerReceived; + public event EventHandler> OnStatusReceived; public event EventHandler> OnSubscriptionReceived; public event EventHandler> OnSnapShotReceived; public event EventHandler> OnLevel2UpdateReceived; diff --git a/README.md b/README.md index 0dcac299..5b37b7bb 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,7 @@ The following methods are EventHandlers: - OnHeartbeatReceived - EventHandler for data with response type `heartbeat` - OnReceivedReceived - EventHandler for data with response type `received` - OnOpenReceived - EventHandler for data with response type `open` +- OnStatusReceived - EventHandler for data with response type `status` - OnDoneReceived - EventHandler for data with response type `done` - OnMatchReceived - EventHandler for data with response type `match` - OnChangeReceived - EventHandler for data with response type `change`