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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//! Module encapsulating the error handling of internal errors and errors returned from Kraken
use std::error::Error;
use std::fmt;
use hyper::Error as HyperError;
use serde_json::Error as SerdeError;
/// Newtype wrapper around a vector of error values
#[derive(Debug)]
pub struct KrakenErrors<KError>(pub Vec<KError>);
impl Error for KrakenErrors<KError> {}
impl fmt::Display for KrakenErrors<KError> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[{}]",
self.0
.iter()
.fold(String::from(""), |acc, error| format!("{},{}", acc, error))
)
}
}
/// Possible errors that could occur internally or errors that were returned from Kraken
#[derive(Debug)]
pub enum KError {
/// Wrapper around [hyper::Error] when an internal http error has occurred
HttpError(HyperError),
/// Wrapper around [serde_json::Error] for when serde fails to parse the json into the output
/// structure
ParseError(SerdeError),
/// Failed to parse into KAsset/KAssetPair
AssetParseError,
/// Invalid currency pair
/// You can pull the complete list of our asset pairs from the AssetPairs public call
/// and look for the pair name as the entry of the Json headers or by the parameter
/// "altname": `https://api.kraken.com/0/public/AssetPairs`
UnknownAssetPair,
/// This error is returned when a method is called without the required parameters.
/// For example, calling the QueryOrders method without specifying a valid transaction
/// id (txid) parameter would cause the invalid arguments error to be returned.
/// Calling a method with unnecessary parameters would still not return the
/// invalid arguments error because the unnecessary parameters would simply be ignored.
InvalidArguments,
/// Permission denied errors are returned when the API client is attempting a task
/// for which the API key does not have permission. For example, if an API client
/// attempted to retrieve the account balance using an API key that was configured to
/// allow trading access but not account management access, then the permission denied
/// error would be returned. You can review your API keys and their settings
/// (such as their permissions) via the Settings -> API tab of account management.
PermissionDenied,
/// This error is returned when the API key used for the call is either expired or disabled,
/// please review the API key in your Settings -> API tab of account management or
/// generate a new one and update your application.
InvalidKey,
/// The Invalid Key error occurs if either your API key or API secret are written
/// incorrectly in your program or because the POST data used in the authentication
/// and the POST data sent to the API do not match
InvalidSignature,
/// This error is returned when an invalid nonce is sent.
/// Check your [nonce
/// window](https://support.kraken.com/hc/en-us/articles/360001148023-What-is-a-Nonce-Window-)
InvalidNonce,
/// This error occurs when the [API call
/// limits](https://support.kraken.com/hc/en-us/articles/206548367-What-is-the-API-call-rate-limit-)
/// are exceeded
APIRateLimit,
/// While adding/canceling orders does not count against our standard API counter limits,
/// these operations do have their own add/cancel order counter. This counter works in a
/// way where the longer orders are left on the book, the more orders clients are able
/// to add/cancel. After the error "EAPI:Rate limit exceeded", please wait ~15 min for
/// being able to send new requests.
OrderRateLimit,
/// Temporary lockout error messages can occur if you had too many failed API calls
/// or too many invalid nonce errors in a short period of time or invalid signatures.
/// Even though these calls return an error, that error still counts against your API
/// limits and may result in a temporary lockout.
///
/// Temporary lockouts typically last approximately 15 minutes. If you are triggering
/// several invalid nonce errors, please increase the nonce window as this can help
/// reduce the frequency that these errors will occur. Please try to reduce the frequency
/// of your private API calls also.
TemporaryLockout,
/// Opening new spot positions on margin has been temporarily suspended for trading
/// engine maintenance. The feature will be making a return soon and you can follow
/// along with [updates](status.kraken.com)
///
/// Another reasons may be that spot positions on margin are not currently available
/// for clients residing in certain countries. Please see this article for our
/// [geographical restrictions](https://support.kraken.com/hc/en-us/articles/360001368823)
OpenPosition,
/// No [hedging](https://support.kraken.com/hc/en-us/articles/205367328-Hedging).
/// Cannot open a long and short position for the same pair.
///
/// If wishing to open a long and short position for the same currency, please
/// choose different trading pairs with the same currency as the base or quote currency.
/// Ex: short XBT/USD, long XBT/EUR.
OpposingPosition,
/// This error occurs when you have exceeded the margin allowance limits for your
/// current verification level. Margin allowance limits for each currency varies
/// based on your current verification level. Please refer to this support article for
/// more information regarding [margin allowance limits](https://support.kraken.com/hc/en-us/articles/209238787-Margin-allowance-limits)
MarginAllowanceExceeded,
/// We have limited funds available for margin extensions. The "insufficient margin"
/// message indicates that we are out of funds in the applicable margin pool for the
/// time being. This can change at any time. You may be able to successfully place your
/// order just seconds or minutes later, but high volume orders and orders placed during
/// high volume times may take longer. Please accept our apologies for any inconvenience.
/// For more [information](https://support.kraken.com/hc/en-us/articles/217696017-Insufficient-Margin)
InsufficientMargin,
/// You do not have the funds available to place this order. Please review your open
/// positions and orders for items that may be holding up your funds
InsufficientFunds,
/// You have not met the minimum order volume for this asset.
///
/// You can find more information about [minimum order sizes](https://support.kraken.com/hc/en-us/articles/205893708-What-is-the-minimum-order-size-volume-)
OrderMinimum,
/// You have exceeded the maximum amount of open orders available to your account.
///
/// These limits are based on your verification level. Please close some of your open
/// orders or verify your account to a higher level.
///
/// You can learn more about the [maximum amount of open orders](https://support.kraken.com/hc/en-us/articles/209090607-What-is-the-maximum-number-of-open-orders-positions-)
OrderLimit,
/// You have exceeded the maximum amount of open positions available to your account.
///
/// These limits are based on your verification level. Please close or settle some or all
/// of your open positions or verify your account to a higher level if possible.
///
/// You can learn more about the [maximum amount of open positions](https://support.kraken.com/hc/en-us/articles/209090607-What-is-the-maximum-number-of-open-orders-positions-)
PositionLimit,
/// In case of this error you will need to submit your order with the following parameter:
/// ‘trading_agreement’:’agree’
///
/// This will resolve the error message you are receiving when placing an order:
/// [Trading Agreement](https://support.kraken.com/hc/en-us/articles/360000920026-Trading-Agreement-required-for-orders-sent-via-API)
TradingAgreement,
/// The service errors you are experiencing should only be temporary. You may wish to
/// resubmit your requests if they have failed. We will be monitoring the issues and
/// will update our [page](https://status.kraken.com/)
ServiceUnavailable,
/// The service errors you are experiencing should only be temporary. You may wish to
/// resubmit your requests if they have failed. We will be monitoring the issues and
/// will update our [page](https://status.kraken.com/)
ServiceBusy,
/// When we are facing API degradation issues, these can translate into problems for
/// both Kraken and cryptowat.ch in the form of service unavailable messages, 8XX errors
/// on [cryptowatch](https://cryptowat.ch/) and site outages.
InternalError,
/// This issue has to do with the security of your account which may have been compromised.
/// Please change your password and Two-Factor Authentication and contact our Support Center
Locked,
/// This error occurs when a flag or input parameter is disabled temporary or permanently.
/// The error should come from one of the inputs passed, please contact our support sending
/// a log with the complete informations used for the call that generated the error
FeatureDisabled,
/// Default KError if none of the others above
UnknownError,
}
impl fmt::Display for KError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
// Errors from internal dependencies
KError::HttpError(err) => write!(f, "HTTP Error: {}", err.to_string()),
KError::ParseError(err) => write!(f, "Parse Error: {}", err.to_string()),
// Errors from processing within this crate
KError::AssetParseError => write!(f, "Failed to parse string into KAsset"),
// Errors coming directly from Kraken's servers
KError::UnknownAssetPair => write!(f, "Unknown AssetPair"),
KError::InvalidArguments => write!(f, "Invalid Arguments"),
KError::PermissionDenied => write!(f, "Permission Denied"),
KError::InvalidKey => write!(f, "Invalid Key"),
KError::InvalidSignature => write!(f, "Invalid Signature"),
KError::InvalidNonce => write!(f, "Invalid Nonce"),
KError::APIRateLimit => write!(f, "API Rate Limit"),
KError::OrderRateLimit => write!(f, "Order Rate Limit"),
KError::TemporaryLockout => write!(f, "Temporary Lockout"),
KError::OpenPosition => write!(f, "Cannot Open Position"),
KError::OpposingPosition => write!(f, "Cannot Open Opposing Position"),
KError::MarginAllowanceExceeded => write!(f, "Margin Allowance Exceeded"),
KError::InsufficientMargin => write!(f, "Insufficient Margin"),
KError::InsufficientFunds => write!(f, "Insufficient User Funds"),
KError::OrderMinimum => write!(f, "Order Minimum Not Met (volume too low)"),
KError::OrderLimit => write!(f, "Orders Limit Reached"),
KError::PositionLimit => write!(f, "Positions Limit Reached"),
KError::TradingAgreement => write!(f, "Trading Agreement Required"),
KError::ServiceUnavailable => write!(f, "Service Unavailable"),
KError::ServiceBusy => write!(f, "Service Busy"),
KError::InternalError => write!(f, "Internal Error"),
KError::Locked => write!(f, "Account Locked"),
KError::FeatureDisabled => write!(f, "A Feature Was Disabled"),
KError::UnknownError => write!(f, "An Unknown Error Occurred"),
}
}
}
impl From<HyperError> for KrakenErrors<KError> {
fn from(err: HyperError) -> Self {
KrakenErrors(vec![KError::HttpError(err)])
}
}
impl From<SerdeError> for KrakenErrors<KError> {
fn from(err: SerdeError) -> Self {
KrakenErrors(vec![KError::ParseError(err)])
}
}
pub(crate) fn generate_errors(errors: Vec<String>) -> KrakenErrors<KError> {
let mut errs: Vec<KError> = Vec::with_capacity(errors.len());
for error in errors {
let index = error.find(':').unwrap();
// Assume kraken will not return an error like "EError:" with no error description
let (category, message) = error.split_at(index + 1);
let err = match message {
"Unknown asset pair" => KError::UnknownAssetPair,
"Invalid arguments" => KError::InvalidArguments,
"Permission denied" => KError::PermissionDenied,
"Invalid key" => KError::InvalidKey,
"Invalid signature" => KError::InvalidSignature,
"Invalid nonce" => KError::InvalidNonce,
"Rate limit exceeded" => match category {
"EAPI:" => KError::APIRateLimit,
"EOrder:" => KError::OrderRateLimit,
_ => KError::UnknownError,
},
"Temporary lockout" => KError::TemporaryLockout,
"Cannot open position" => KError::OpenPosition,
"Cannot open opposing position" => KError::OpposingPosition,
"Margin allowance exceeded" => KError::MarginAllowanceExceeded,
"Insufficient margin" => KError::InsufficientMargin,
"Insufficient insufficient user funds" => KError::InsufficientFunds,
"Order minimum not volume too low" => KError::OrderMinimum,
"Orders limit exceeded" => KError::OrderLimit,
"Positions limit exceeded" => KError::PositionLimit,
"Trading agreement required" => KError::TradingAgreement,
"Unavailable" => KError::ServiceUnavailable,
"Busy" => KError::ServiceBusy,
"Internal error" => KError::InternalError,
"Locked" => KError::Locked,
"Feature disabled" => KError::FeatureDisabled,
_ => KError::UnknownError,
};
errs.push(err);
}
KrakenErrors(errs)
}