bitstampede 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +10 -0
- data/lib/bitstampede/client.rb +3 -1
- data/lib/bitstampede/entities/base.rb +16 -4
- data/lib/bitstampede/net.rb +1 -1
- data/lib/bitstampede/version.rb +1 -1
- data/spec/integration/client_spec.rb +25 -13
- data/spec/unit/bitstampede/client_spec.rb +28 -15
- data/spec/unit/bitstampede/entities/balance_spec.rb +9 -9
- data/spec/unit/bitstampede/entities/order_spec.rb +38 -20
- data/spec/unit/bitstampede/mapper_spec.rb +6 -6
- data/spec/unit/bitstampede/net_spec.rb +5 -5
- metadata +4 -4
data/README.md
CHANGED
@@ -37,6 +37,9 @@ client = Bitstampede::Client.new
|
|
37
37
|
client.key = 'YOUR_USER_ID'
|
38
38
|
client.secret = 'YOUR_PASSWORD'
|
39
39
|
|
40
|
+
# Alternatively, you can configure the client on initialization with:
|
41
|
+
client = Bitstampede::Client.new('YOUR_USER_ID', 'YOUR_PASSWORD')
|
42
|
+
|
40
43
|
# Fetch your balance
|
41
44
|
client.balance
|
42
45
|
# => #<Bitstampede::Entities::Balance:0x0000000259f338 @usd_balance=#<BigDecimal:259e898,'0.0',9(9)>, @btc_balance=#<BigDecimal:2726698,'0.0',9(9)>, @usd_reserved=#<BigDecimal:2726328,'0.0',9(9)>, @btc_reserved=#<BigDecimal:2725fb8,'0.0',9(9)>, @usd_available=#<BigDecimal:2725c48,'0.0',9(9)>, @btc_available=#<BigDecimal:27258b0,'0.0',9(9)>, @fee=#<BigDecimal:2725540,'0.0',9(9)>>
|
@@ -75,3 +78,10 @@ ruby example/balance.rb
|
|
75
78
|
## License
|
76
79
|
|
77
80
|
This software is licensed under [the MIT License.](./LICENSE.md)
|
81
|
+
|
82
|
+
## Contributors
|
83
|
+
|
84
|
+
These people have contributed to the gem. Many thanks!:
|
85
|
+
|
86
|
+
- Josh Adams
|
87
|
+
- [Robert Jackson](https://github.com/rjackson)
|
data/lib/bitstampede/client.rb
CHANGED
@@ -9,10 +9,9 @@ module Bitstampede
|
|
9
9
|
self.mappings.keys
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
|
14
|
-
|
15
|
-
end
|
12
|
+
def initialize(hash)
|
13
|
+
check_for_errors(hash)
|
14
|
+
map_instance_variables(hash)
|
16
15
|
end
|
17
16
|
|
18
17
|
def inspect
|
@@ -35,6 +34,19 @@ module Bitstampede
|
|
35
34
|
def self.map_decimal
|
36
35
|
->(val) { BigDecimal(val) }
|
37
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def map_instance_variables(hash)
|
40
|
+
self.class.keys.each do |key|
|
41
|
+
instance_variable_set("@#{key}", self.class.mappings[key].call(hash[key.to_s].to_s))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_for_errors(hash)
|
46
|
+
if hash.keys.include?("error")
|
47
|
+
raise Bitstampede::StandardError.new(hash["error"]["__all__"].join(". "))
|
48
|
+
end
|
49
|
+
end
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
data/lib/bitstampede/net.rb
CHANGED
@@ -44,7 +44,7 @@ module Bitstampede
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def raw_post(endpoint, options)
|
47
|
-
HTTParty.post(url_for(endpoint), body: options.merge(auth_options)).to_s
|
47
|
+
HTTParty.post(url_for(endpoint), body: options.merge(auth_options)).to_s.tap {|r| STDOUT.puts r}
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/bitstampede/version.rb
CHANGED
@@ -46,21 +46,33 @@ describe "Integrating a client" do
|
|
46
46
|
expect(orders[0].type).to eq(:buy)
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
context "handling #buy!" do
|
50
|
+
it "succeeds properly" do
|
51
|
+
example_buy_response = <<-JSON
|
52
|
+
{
|
53
|
+
"id": "1",
|
54
|
+
"datetime": "1234567",
|
55
|
+
"type": 0,
|
56
|
+
"price": "12.34",
|
57
|
+
"amount": "100"
|
58
|
+
}
|
59
|
+
JSON
|
60
|
+
|
61
|
+
FakeWeb.register_uri(:post, "https://www.bitstamp.net/api/buy/", body: example_buy_response)
|
62
|
+
|
63
|
+
buy = subject.buy!(BigDecimal('1'), BigDecimal('100'))
|
64
|
+
expect(buy.type).to eq(:buy)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "fails properly" do
|
68
|
+
example_buy_response = <<-JSON
|
69
|
+
{"error"=>{"__all__"=>["Minimum order size is $1"]}}
|
70
|
+
JSON
|
59
71
|
|
60
|
-
|
72
|
+
FakeWeb.register_uri(:post, "https://www.bitstamp.net/api/buy/", body: example_buy_response)
|
61
73
|
|
62
|
-
|
63
|
-
|
74
|
+
expect{ subject.buy!(BigDecimal('1'), BigDecimal('100')) }.to raise_error(Bitstampede::StandardError, "Minimum order size is $1")
|
75
|
+
end
|
64
76
|
end
|
65
77
|
|
66
78
|
it "handles #sell!" do
|
@@ -1,13 +1,26 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
2
|
|
3
3
|
describe Bitstampede::Client do
|
4
|
-
subject { described_class.new }
|
5
|
-
let(:net){
|
6
|
-
let(:mapper){
|
4
|
+
subject(:client) { described_class.new }
|
5
|
+
let(:net){ client.send(:net) }
|
6
|
+
let(:mapper){ client.send(:mapper) }
|
7
7
|
|
8
8
|
before do
|
9
|
-
|
10
|
-
|
9
|
+
client.key = '1'
|
10
|
+
client.secret = '2'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it 'does not require any initial parameters' do
|
15
|
+
expect { described_class.new }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'allows specifying key/secret on initialize' do
|
19
|
+
client = described_class.new('KEY', 'SECRET')
|
20
|
+
|
21
|
+
expect(client.key).to eql('KEY')
|
22
|
+
expect(client.secret).to eql('SECRET')
|
23
|
+
end
|
11
24
|
end
|
12
25
|
|
13
26
|
describe '#balance' do
|
@@ -17,7 +30,7 @@ describe Bitstampede::Client do
|
|
17
30
|
before do
|
18
31
|
net.stub(:post).and_return(api_balance_response)
|
19
32
|
mapper.stub(:map_balance).and_return(balance_object)
|
20
|
-
|
33
|
+
client.balance
|
21
34
|
end
|
22
35
|
|
23
36
|
it 'requests the balance from the API' do
|
@@ -29,7 +42,7 @@ describe Bitstampede::Client do
|
|
29
42
|
end
|
30
43
|
|
31
44
|
it 'returns the mapped object' do
|
32
|
-
expect(
|
45
|
+
expect(client.balance).to eq(balance_object)
|
33
46
|
end
|
34
47
|
end
|
35
48
|
|
@@ -40,7 +53,7 @@ describe Bitstampede::Client do
|
|
40
53
|
before do
|
41
54
|
net.stub(:post).and_return(api_orders_response)
|
42
55
|
mapper.stub(:map_orders).and_return([order_object])
|
43
|
-
|
56
|
+
client.orders
|
44
57
|
end
|
45
58
|
|
46
59
|
it 'requests open orders from the API' do
|
@@ -62,18 +75,18 @@ describe Bitstampede::Client do
|
|
62
75
|
end
|
63
76
|
|
64
77
|
it 'submits a buy order to the API' do
|
65
|
-
|
78
|
+
client.buy!(BigDecimal('100'), BigDecimal('1'))
|
66
79
|
expect(net).to have_received(:post).with('buy', { amount: '100.0', price: '1.0' })
|
67
80
|
end
|
68
81
|
|
69
82
|
it 'maps the API response to an Order object' do
|
70
|
-
|
83
|
+
client.buy!(BigDecimal('100'), BigDecimal('1'))
|
71
84
|
expect(mapper).to have_received(:map_order).with(api_buy_response)
|
72
85
|
end
|
73
86
|
|
74
87
|
it 'wraps exceptions in its own class' do
|
75
88
|
net.stub(:post).and_raise(StandardError)
|
76
|
-
expect{
|
89
|
+
expect{ client.buy!(BigDecimal('100'), BigDecimal('1')) }.to raise_error(Bitstampede::StandardError)
|
77
90
|
end
|
78
91
|
end
|
79
92
|
|
@@ -84,7 +97,7 @@ describe Bitstampede::Client do
|
|
84
97
|
before do
|
85
98
|
net.stub(:post).and_return(api_sell_response)
|
86
99
|
mapper.stub(:map_order).and_return(order_object)
|
87
|
-
|
100
|
+
client.sell!(BigDecimal('100'), BigDecimal('1'))
|
88
101
|
end
|
89
102
|
|
90
103
|
it 'submits a sell order to the API' do
|
@@ -97,7 +110,7 @@ describe Bitstampede::Client do
|
|
97
110
|
|
98
111
|
it 'wraps exceptions in its own class' do
|
99
112
|
net.stub(:post).and_raise(StandardError)
|
100
|
-
expect{
|
113
|
+
expect{ client.sell!(BigDecimal('100'), BigDecimal('1')) }.to raise_error(Bitstampede::StandardError)
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
@@ -107,7 +120,7 @@ describe Bitstampede::Client do
|
|
107
120
|
before do
|
108
121
|
net.stub(:post).and_return(api_cancel_response)
|
109
122
|
mapper.stub(:map_cancel).and_return(true)
|
110
|
-
|
123
|
+
client.cancel(1234)
|
111
124
|
end
|
112
125
|
|
113
126
|
it 'submits a cancel order to the API' do
|
@@ -120,7 +133,7 @@ describe Bitstampede::Client do
|
|
120
133
|
|
121
134
|
it 'wraps exceptions in its own class' do
|
122
135
|
net.stub(:post).and_raise(StandardError)
|
123
|
-
expect{
|
136
|
+
expect{ client.cancel(123) }.to raise_error(Bitstampede::StandardError)
|
124
137
|
end
|
125
138
|
end
|
126
139
|
end
|
@@ -12,37 +12,37 @@ describe Bitstampede::Entities::Balance do
|
|
12
12
|
"fee" => "1.11"
|
13
13
|
}
|
14
14
|
}
|
15
|
-
subject{ described_class.new(balance_hash) }
|
15
|
+
subject(:balance) { described_class.new(balance_hash) }
|
16
16
|
|
17
17
|
it "has a usd_balance" do
|
18
|
-
expect(
|
18
|
+
expect(balance.usd_balance).to eq(BigDecimal('111.12'))
|
19
19
|
end
|
20
20
|
|
21
21
|
it "has a btc_balance" do
|
22
|
-
expect(
|
22
|
+
expect(balance.btc_balance).to eq(BigDecimal('211.23'))
|
23
23
|
end
|
24
24
|
|
25
25
|
it "has a usd_reserved" do
|
26
|
-
expect(
|
26
|
+
expect(balance.usd_reserved).to eq(BigDecimal('1.20'))
|
27
27
|
end
|
28
28
|
|
29
29
|
it "has a btc_reserved" do
|
30
|
-
expect(
|
30
|
+
expect(balance.btc_reserved).to eq(BigDecimal('2.30'))
|
31
31
|
end
|
32
32
|
|
33
33
|
it "has a usd_available" do
|
34
|
-
expect(
|
34
|
+
expect(balance.usd_available).to eq(BigDecimal('5.50'))
|
35
35
|
end
|
36
36
|
|
37
37
|
it "has a btc_available" do
|
38
|
-
expect(
|
38
|
+
expect(balance.btc_available).to eq(BigDecimal('6.60'))
|
39
39
|
end
|
40
40
|
|
41
41
|
it "has a fee" do
|
42
|
-
expect(
|
42
|
+
expect(balance.fee).to eq(BigDecimal('1.11'))
|
43
43
|
end
|
44
44
|
|
45
45
|
it "can be inspected" do
|
46
|
-
expect {
|
46
|
+
expect { balance.inspect }.to_not raise_error
|
47
47
|
end
|
48
48
|
end
|
@@ -1,33 +1,51 @@
|
|
1
1
|
require_relative '../../../spec_helper'
|
2
2
|
|
3
3
|
describe Bitstampede::Entities::Order do
|
4
|
-
let(:order_hash){
|
5
|
-
{
|
6
|
-
"id" => "1",
|
7
|
-
"datetime" => 1234567,
|
8
|
-
"type" => 0,
|
9
|
-
"price" => "1.23",
|
10
|
-
"amount" => "10"
|
11
|
-
}
|
12
|
-
}
|
13
4
|
subject{ described_class.new(order_hash) }
|
14
5
|
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
context "a successful order" do
|
7
|
+
let(:order_hash){
|
8
|
+
{
|
9
|
+
"id" => "1",
|
10
|
+
"datetime" => 1234567,
|
11
|
+
"type" => 0,
|
12
|
+
"price" => "1.23",
|
13
|
+
"amount" => "10"
|
14
|
+
}
|
15
|
+
}
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
expect(subject.type).to eq(:buy)
|
17
|
+
it "has an id" do
|
18
|
+
expect(subject.id).to eq(1)
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
describe "type" do
|
22
|
+
it "maps 0 to :buy" do
|
23
|
+
expect(subject.type).to eq(:buy)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "maps 1 to :sell" do
|
27
|
+
order = described_class.new(order_hash.merge({"type" => 1}))
|
28
|
+
expect(order.type).to eq(:sell)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises InvalidTypeError for other values" do
|
32
|
+
expect { described_class.new(order_hash.merge({"type" => 2})) }.to raise_error(Bitstampede::Entities::Order::InvalidTypeError)
|
33
|
+
end
|
27
34
|
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "an unsuccessful order" do
|
38
|
+
let(:order_hash){
|
39
|
+
# Don't get mad at me, not my fault bitstamp errors look like this
|
40
|
+
{
|
41
|
+
"error" => {
|
42
|
+
"__all__" => ["Minimum order size is $1"]
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
28
46
|
|
29
|
-
it "raises
|
30
|
-
expect
|
47
|
+
it "raises an appropriate error" do
|
48
|
+
expect{ subject }.to raise_error(Bitstampede::StandardError, "Minimum order size is $1")
|
31
49
|
end
|
32
50
|
end
|
33
51
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
2
|
|
3
3
|
describe Bitstampede::Mapper do
|
4
|
-
subject { described_class.new }
|
4
|
+
subject(:mapper) { described_class.new }
|
5
5
|
let(:json_object){ '{"foo": "bar"}' }
|
6
6
|
let(:json_array){ '[{"foo": "bar"}]' }
|
7
7
|
|
@@ -13,12 +13,12 @@ describe Bitstampede::Mapper do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "maps a balance API response into a Balance entity" do
|
16
|
-
|
16
|
+
mapper.map_balance(json_object)
|
17
17
|
expect(Entities::Balance).to have_received(:new).with(json_parse(json_object))
|
18
18
|
end
|
19
19
|
|
20
20
|
it "returns the mapped Balance entity" do
|
21
|
-
expect(
|
21
|
+
expect(mapper.map_balance(json_object)).to eq(balance)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -30,15 +30,15 @@ describe Bitstampede::Mapper do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "maps an open_orders API response into an array of Order entities" do
|
33
|
-
|
33
|
+
mapper.map_orders(json_array)
|
34
34
|
expect(Entities::Order).to have_received(:new).with(json_parse(json_array)[0])
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe '#map_cancel' do
|
39
39
|
it "maps a cancel API response to a boolean" do
|
40
|
-
expect(
|
41
|
-
expect(
|
40
|
+
expect(mapper.map_cancel('"true"')).to eq(true)
|
41
|
+
expect(mapper.map_cancel('"false"')).to eq(false)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
2
2
|
|
3
3
|
describe Bitstampede::Net do
|
4
4
|
let(:client){ double }
|
5
|
-
subject { described_class.new(client) }
|
5
|
+
subject(:net) { described_class.new(client) }
|
6
6
|
|
7
7
|
before do
|
8
8
|
client.stub(:secret).and_return(1)
|
@@ -10,15 +10,15 @@ describe Bitstampede::Net do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'gets instantiated with a client' do
|
13
|
-
expect(
|
13
|
+
expect(net.client).to eq(client)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'defers to its client for secret' do
|
17
|
-
expect(
|
17
|
+
expect(net.secret).to eq(1)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'defers to its client for key' do
|
21
|
-
expect(
|
21
|
+
expect(net.key).to eq(2)
|
22
22
|
end
|
23
23
|
|
24
24
|
describe '#post' do
|
@@ -36,7 +36,7 @@ describe Bitstampede::Net do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "queries the appropriate endpoint and returns its body as a string" do
|
39
|
-
expect(json_parse(
|
39
|
+
expect(json_parse(net.post('balance'))).to eq(json_parse(example_balance))
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitstampede
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -191,7 +191,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
191
191
|
version: '0'
|
192
192
|
segments:
|
193
193
|
- 0
|
194
|
-
hash:
|
194
|
+
hash: -2456329211082367398
|
195
195
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
196
196
|
none: false
|
197
197
|
requirements:
|
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
200
|
version: '0'
|
201
201
|
segments:
|
202
202
|
- 0
|
203
|
-
hash:
|
203
|
+
hash: -2456329211082367398
|
204
204
|
requirements: []
|
205
205
|
rubyforge_project:
|
206
206
|
rubygems_version: 1.8.25
|