Skip to content

Commit 24313fc

Browse files
authored
Merge pull request #45 from ainestal/burst
Burst
2 parents 97ae693 + a002918 commit 24313fc

File tree

5 files changed

+186
-37
lines changed

5 files changed

+186
-37
lines changed

src/bitstamp/api.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use serde_json::value::Map;
1212

1313
use std::collections::HashMap;
1414
use std::io::Read;
15+
use std::thread;
16+
use std::time::Duration;
1517

1618
use coinnect::Credentials;
1719
use exchange::Exchange;
@@ -44,6 +46,7 @@ pub struct BitstampApi {
4446
api_secret: String,
4547
customer_id: String,
4648
http_client: Client,
49+
burst: bool,
4750
}
4851

4952

@@ -69,9 +72,30 @@ impl BitstampApi {
6972
api_secret: creds.get("api_secret").unwrap_or_default(),
7073
customer_id: creds.get("customer_id").unwrap_or_default(),
7174
http_client: Client::with_connector(connector),
75+
burst: false, // No burst by default
7276
})
7377
}
7478

79+
/// The number of calls in a given period is limited. In order to avoid a ban we limit
80+
/// by default the number of api requests.
81+
/// This function sets or removes the limitation.
82+
/// Burst false implies no block.
83+
/// Burst true implies there is a control over the number of calls allowed to the exchange
84+
pub fn set_burst(&mut self, burst: bool) {
85+
self.burst = burst
86+
}
87+
88+
fn block_or_continue(&self) {
89+
if ! self.burst {
90+
let threshold: u64 = 1000; // 600 requests per 10 mins = 1 request per second
91+
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - self.last_request as u64;
92+
if offset < threshold {
93+
let wait_ms = Duration::from_millis(threshold - offset);
94+
thread::sleep(wait_ms);
95+
}
96+
}
97+
}
98+
7599
fn public_query(&mut self, params: &HashMap<&str, &str>) -> Result<Map<String, Value>> {
76100

77101
let method: &str = params
@@ -80,7 +104,7 @@ impl BitstampApi {
80104
let pair: &str = params.get("pair").ok_or_else(|| "Missing \"pair\" field.")?;
81105
let url: String = utils::build_url(method, pair);
82106

83-
utils::block_or_continue(self.last_request);
107+
self.block_or_continue();
84108
let mut response = self.http_client.get(&url).send()?;
85109
self.last_request = helpers::get_unix_timestamp_ms();
86110
let mut buffer = String::new();
@@ -327,3 +351,45 @@ impl BitstampApi {
327351
self.private_query(&params)
328352
}
329353
}
354+
355+
356+
#[cfg(test)]
357+
mod bitstamp_api_tests {
358+
use super::*;
359+
360+
#[test]
361+
fn should_block_or_not_block_when_enabled_or_disabled() {
362+
let mut api = BitstampApi {
363+
last_request: helpers::get_unix_timestamp_ms(),
364+
api_key: "".to_string(),
365+
api_secret: "".to_string(),
366+
customer_id: "".to_string(),
367+
http_client: Client::new(),
368+
burst: false,
369+
};
370+
371+
let mut counter = 0;
372+
loop {
373+
api.set_burst(false);
374+
let start = helpers::get_unix_timestamp_ms();
375+
api.block_or_continue();
376+
api.last_request = helpers::get_unix_timestamp_ms();
377+
378+
let difference = api.last_request - start;
379+
assert!(difference >= 999);
380+
assert!(difference < 10000);
381+
382+
383+
api.set_burst(true);
384+
let start = helpers::get_unix_timestamp_ms();
385+
api.block_or_continue();
386+
api.last_request = helpers::get_unix_timestamp_ms();
387+
388+
let difference = api.last_request - start;
389+
assert!(difference < 10);
390+
391+
counter = counter + 1;
392+
if counter >= 3 { break; }
393+
}
394+
}
395+
}

src/bitstamp/utils.rs

-25
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ use serde_json;
77
use serde_json::Value;
88
use serde_json::value::Map;
99

10-
use std::thread;
11-
use std::time::Duration;
12-
1310
use error::*;
1411
use helpers;
1512
use types::Currency;
@@ -41,15 +38,6 @@ pub fn get_pair_enum(pair: &str) -> Option<&Pair> {
4138
PAIRS_STRING.get_by_second(&pair)
4239
}
4340

44-
pub fn block_or_continue(last_request: i64) {
45-
let threshold: u64 = 1000; // 600 requests per 10 mins = 1 request per second
46-
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - last_request as u64;
47-
if offset < threshold {
48-
let wait_ms = Duration::from_millis(threshold - offset);
49-
thread::sleep(wait_ms);
50-
}
51-
}
52-
5341
pub fn build_signature(nonce: &str,
5442
customer_id: &str,
5543
api_key: &str,
@@ -160,16 +148,3 @@ pub fn get_currency_string(currency: Currency) -> Option<String> {
160148
_ => None,
161149
}
162150
}
163-
164-
#[cfg(test)]
165-
mod utils_tests {
166-
use super::*;
167-
168-
#[test]
169-
fn should_block_when_enabled() {
170-
let start = helpers::get_unix_timestamp_ms();
171-
block_or_continue(start);
172-
let end = helpers::get_unix_timestamp_ms();
173-
assert!(end - start >= 1000)
174-
}
175-
}

src/kraken/api.rs

+59-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub struct KrakenApi {
4646
api_secret: String,
4747
otp: Option<String>, // two-factor password (if two-factor enabled, otherwise not required)
4848
http_client: Client,
49+
burst: bool,
4950
}
5051

5152

@@ -69,6 +70,7 @@ impl KrakenApi {
6970
api_secret: creds.get("api_secret").unwrap_or_default(),
7071
otp: None,
7172
http_client: Client::with_connector(connector),
73+
burst: false,
7274
})
7375
}
7476

@@ -78,12 +80,23 @@ impl KrakenApi {
7880
self.otp = Some(otp);
7981
}
8082

83+
/// The number of calls in a given period is limited. In order to avoid a ban we limit
84+
/// by default the number of api requests.
85+
/// This function sets or removes the limitation.
86+
/// Burst false implies no block.
87+
/// Burst true implies there is a control over the number of calls allowed to the exchange
88+
pub fn set_burst(&mut self, burst: bool) {
89+
self.burst = burst
90+
}
91+
8192
pub fn block_or_continue(&self) {
82-
let threshold: u64 = 2000; // 1 request/2sec
83-
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - self.last_request as u64;
84-
if offset < threshold {
85-
let wait_ms = Duration::from_millis(threshold - offset);
86-
thread::sleep(wait_ms);
93+
if ! self.burst {
94+
let threshold: u64 = 2000; // 1 request/2sec
95+
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - self.last_request as u64;
96+
if offset < threshold {
97+
let wait_ms = Duration::from_millis(threshold - offset);
98+
thread::sleep(wait_ms);
99+
}
87100
}
88101
}
89102

@@ -1111,3 +1124,44 @@ impl KrakenApi {
11111124
self.private_query("WithdrawCancel", &mut params)
11121125
}
11131126
}
1127+
1128+
#[cfg(test)]
1129+
mod kraken_api_tests {
1130+
use super::*;
1131+
1132+
#[test]
1133+
fn should_block_or_not_block_when_enabled_or_disabled() {
1134+
let mut api = KrakenApi {
1135+
last_request: helpers::get_unix_timestamp_ms(),
1136+
api_key: "".to_string(),
1137+
api_secret: "".to_string(),
1138+
otp: None,
1139+
http_client: Client::new(),
1140+
burst: false,
1141+
};
1142+
1143+
let mut counter = 0;
1144+
loop {
1145+
api.set_burst(false);
1146+
let start = helpers::get_unix_timestamp_ms();
1147+
api.block_or_continue();
1148+
api.last_request = helpers::get_unix_timestamp_ms();
1149+
1150+
let difference = api.last_request - start;
1151+
assert!(difference >= 1999);
1152+
assert!(difference < 10000);
1153+
1154+
1155+
api.set_burst(true);
1156+
let start = helpers::get_unix_timestamp_ms();
1157+
api.block_or_continue();
1158+
api.last_request = helpers::get_unix_timestamp_ms();
1159+
1160+
let difference = api.last_request - start;
1161+
assert!(difference < 10);
1162+
1163+
counter = counter + 1;
1164+
if counter >= 3 { break; }
1165+
}
1166+
}
1167+
}

src/poloniex/api.rs

+59-5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub struct PoloniexApi {
4747
api_key: String,
4848
api_secret: String,
4949
http_client: Client,
50+
burst: bool,
5051
}
5152

5253

@@ -69,15 +70,27 @@ impl PoloniexApi {
6970
api_key: creds.get("api_key").unwrap_or_default(),
7071
api_secret: creds.get("api_secret").unwrap_or_default(),
7172
http_client: Client::with_connector(connector),
73+
burst: false,
7274
})
7375
}
7476

77+
/// The number of calls in a given period is limited. In order to avoid a ban we limit
78+
/// by default the number of api requests.
79+
/// This function sets or removes the limitation.
80+
/// Burst false implies no block.
81+
/// Burst true implies there is a control over the number of calls allowed to the exchange
82+
pub fn set_burst(&mut self, burst: bool) {
83+
self.burst = burst
84+
}
85+
7586
fn block_or_continue(&self) {
76-
let threshold: u64 = 167; // 6 requests/sec = 1/6*1000
77-
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - self.last_request as u64;
78-
if offset < threshold {
79-
let wait_ms = Duration::from_millis(threshold - offset);
80-
thread::sleep(wait_ms);
87+
if ! self.burst {
88+
let threshold: u64 = 167; // 6 requests/sec = 1/6*1000
89+
let offset: u64 = helpers::get_unix_timestamp_ms() as u64 - self.last_request as u64;
90+
if offset < threshold {
91+
let wait_ms = Duration::from_millis(threshold - offset);
92+
thread::sleep(wait_ms);
93+
}
8194
}
8295
}
8396

@@ -787,3 +800,44 @@ impl PoloniexApi {
787800
self.private_query("toggleAutoRenew", &params)
788801
}
789802
}
803+
804+
805+
#[cfg(test)]
806+
mod poloniex_api_tests {
807+
use super::*;
808+
809+
#[test]
810+
fn should_block_or_not_block_when_enabled_or_disabled() {
811+
let mut api = PoloniexApi {
812+
last_request: helpers::get_unix_timestamp_ms(),
813+
api_key: "".to_string(),
814+
api_secret: "".to_string(),
815+
http_client: Client::new(),
816+
burst: false,
817+
};
818+
819+
let mut counter = 0;
820+
loop {
821+
api.set_burst(false);
822+
let start = helpers::get_unix_timestamp_ms();
823+
api.block_or_continue();
824+
api.last_request = helpers::get_unix_timestamp_ms();
825+
826+
let difference = api.last_request - start;
827+
assert!(difference >= 166);
828+
assert!(difference < 1000);
829+
830+
831+
api.set_burst(true);
832+
let start = helpers::get_unix_timestamp_ms();
833+
api.block_or_continue();
834+
api.last_request = helpers::get_unix_timestamp_ms();
835+
836+
let difference = api.last_request - start;
837+
assert!(difference < 10);
838+
839+
counter = counter + 1;
840+
if counter >= 3 { break; }
841+
}
842+
}
843+
}

tests/coinnect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ mod coinnect_tests {
2424
"BitstampApi { last_request: 0, api_key: \"bs_api_key\", api_secret: \
2525
\"bs_api_secret\", customer_id: \"bs_cust_id\", http_client: Client { \
2626
redirect_policy: FollowAll, read_timeout: None, write_timeout: None, proxy: \
27-
None } }");
27+
None }, burst: false }");
2828
}
2929
#[test]
3030
fn can_create_new_api_connection_to_kraken() {

0 commit comments

Comments
 (0)