bitstampede 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|