justcoin 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/justcoin.gemspec +29 -0
- data/lib/justcoin.rb +134 -0
- data/lib/justcoin/body_extractor.rb +10 -0
- data/lib/justcoin/decimal_converter.rb +41 -0
- data/lib/justcoin/version.rb +3 -0
- data/spec/fixtures/balances.json +18 -0
- data/spec/fixtures/cancel_order.json +14 -0
- data/spec/fixtures/create_order.json +11 -0
- data/spec/fixtures/market_depth.json +17 -0
- data/spec/fixtures/markets.json +18 -0
- data/spec/fixtures/order.json +18 -0
- data/spec/fixtures/orders.json +18 -0
- data/spec/justcoin_spec.rb +171 -0
- data/spec/spec_helper.rb +56 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dce2808b59479b8c626696ccf4e2fadd96c7531d
|
4
|
+
data.tar.gz: f7332649f19c6110d501a5b1f30cdc106d900a41
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ef93767a6f8883450a4d0c84c0451ea992d638b6580e806f21079f7b7f76d340ca2eeb72571364a20905642a07c8c7e189a2c83ec26eed062978443701eb133a
|
7
|
+
data.tar.gz: 3c756192a10d3dddf5fd4b3b34934bdfeedd9e157da7ae2fe3489cdec501dbdb2bfd8cad552c9cf7a4fa7b0048f3491602cf7be896aec0577e237608aa4aeafb
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Laszlo Bacsi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Justcoin
|
2
|
+
|
3
|
+
An API client for [Justcoin](https://justcoin.com/?r=VLM7U).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'justcoin'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install justcoin
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
* [Documentation](http://rubydoc.info/github/lackac/justcoin)
|
22
|
+
|
23
|
+
### Example
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
client = Justcoin.new(ENV['JUSTCOIN_KEY'])
|
27
|
+
|
28
|
+
# fetch current BTC balance
|
29
|
+
btc = client.balances.detect {|b| b.currency == "BTC"}
|
30
|
+
|
31
|
+
# fetch market stats for BTCSTR
|
32
|
+
btcstr = client.markets.detect {|m| m.id == "BTCSTR"}
|
33
|
+
|
34
|
+
# sell half of available BTC for STR in a limit order
|
35
|
+
client.place_order(:btcstr, :ask, btcstr.ask-0.001, btc.available/2)
|
36
|
+
```
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
|
40
|
+
1. Fork it
|
41
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
42
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
43
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
44
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/justcoin.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'justcoin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "justcoin"
|
8
|
+
spec.version = Justcoin::VERSION
|
9
|
+
spec.authors = ["Laszlo Bacsi"]
|
10
|
+
spec.email = ["lackac@lackac.hu"]
|
11
|
+
spec.description = %q{Justcoin API client}
|
12
|
+
spec.summary = %q{Justcoin API client}
|
13
|
+
spec.homepage = "https://github.com/lackac/justcoin"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "faraday"
|
22
|
+
spec.add_dependency "faraday_middleware"
|
23
|
+
spec.add_dependency "hashie"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "webmock"
|
29
|
+
end
|
data/lib/justcoin.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday_middleware"
|
3
|
+
|
4
|
+
require "justcoin/version"
|
5
|
+
require "justcoin/body_extractor"
|
6
|
+
require "justcoin/decimal_converter"
|
7
|
+
|
8
|
+
class Justcoin
|
9
|
+
|
10
|
+
DEFAULT_URL = "https://justcoin.com/api/v1".freeze
|
11
|
+
|
12
|
+
attr_reader :key, :options, :client
|
13
|
+
|
14
|
+
# Creates a new Justcoin client.
|
15
|
+
#
|
16
|
+
# @param key the API key, get it from
|
17
|
+
# https://justcoin.com/client/#settings/apikeys
|
18
|
+
# @param options the client can receive the following options
|
19
|
+
# * `:log` [true/false] – whether to log requests and responses
|
20
|
+
# * `:logger` [Logger] – a custom logger instance, implies `log: true`
|
21
|
+
# * `:raw` [true/false] – whether to return the raw Faraday::Response object instead of a parsed value
|
22
|
+
# * any other options are passed on to the Faraday client
|
23
|
+
def initialize(key, options={})
|
24
|
+
@key = key
|
25
|
+
|
26
|
+
options[:url] ||= DEFAULT_URL
|
27
|
+
options[:params] ||= {}
|
28
|
+
options[:params][:key] ||= key
|
29
|
+
options[:headers] ||= {}
|
30
|
+
options[:headers][:user_agent] ||= "Justcoin ruby client v#{Justcoin::VERSION}"
|
31
|
+
@options = options
|
32
|
+
|
33
|
+
@client = build_client
|
34
|
+
end
|
35
|
+
|
36
|
+
# List balances
|
37
|
+
#
|
38
|
+
# @return [Array] an array of current balances
|
39
|
+
def balances
|
40
|
+
client.get "balances"
|
41
|
+
end
|
42
|
+
|
43
|
+
# List markets
|
44
|
+
#
|
45
|
+
# @return [Array] an array of markets with current statistics
|
46
|
+
def markets
|
47
|
+
client.get "markets"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Retrieve market depth
|
51
|
+
#
|
52
|
+
# @param [String/Symbol] id the id of the market (e.g. `:btcstr`)
|
53
|
+
# @return [Hashie::Mash] `bids` and `asks` as arrays of `[price, volume]` pairs
|
54
|
+
def market_depth(id)
|
55
|
+
client.get "markets/#{id.upcase}/depth"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Retrieve active user orders
|
59
|
+
#
|
60
|
+
# @return [Array] an array of the user's active orders
|
61
|
+
def orders
|
62
|
+
client.get "orders"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Retrieve a specific user order
|
66
|
+
#
|
67
|
+
# Works for all kinds of orders: active, cancelled, or historical.
|
68
|
+
#
|
69
|
+
# @param id the id of the order
|
70
|
+
# @return [Hashie::Mash] information about the order including matches
|
71
|
+
def order(id)
|
72
|
+
client.get "orders/#{id}"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create an order
|
76
|
+
#
|
77
|
+
# @param [String/Symbol] market the id of the market (e.g. `:btcstr`)
|
78
|
+
# @param type the order type; can be `:bid` (buy base currency) or `:ask` (sell base currency)
|
79
|
+
# @param [Numeric/String/nil] price the order price; if set to `nil`,
|
80
|
+
# the order is placed as a market order
|
81
|
+
# @param [Numeric/String] amount the amount of base currency
|
82
|
+
# (identified by the first three letters of the market id) to buy/sell
|
83
|
+
# @return [Hashie::Mash] includes the order id if the order is successfully created
|
84
|
+
def create_order(market, type, price, amount)
|
85
|
+
type = type.downcase.to_sym
|
86
|
+
raise ArgumentError, "type must be either :bid or :ask" unless [:bid, :ask].include?(type)
|
87
|
+
|
88
|
+
params = {
|
89
|
+
market: market.upcase,
|
90
|
+
type: type,
|
91
|
+
price: price,
|
92
|
+
amount: amount
|
93
|
+
}
|
94
|
+
|
95
|
+
client.post "orders", params
|
96
|
+
end
|
97
|
+
alias_method :place_order, :create_order
|
98
|
+
|
99
|
+
# Cancel the remainder of the specified order
|
100
|
+
#
|
101
|
+
# @param id the id of the order
|
102
|
+
# @return true if cancelling the order was successful
|
103
|
+
def cancel_order(id)
|
104
|
+
client.delete("orders/#{id}") == ""
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def client_options
|
110
|
+
options.select { |k,v| Faraday::ConnectionOptions.members.include?(k) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def build_client
|
114
|
+
Faraday.new(client_options) do |f|
|
115
|
+
unless options[:raw]
|
116
|
+
# This extracts the body and discards all other data from the
|
117
|
+
# Faraday::Response object. It should be placed here in the middle
|
118
|
+
# of the stack so that it runs as the last one.
|
119
|
+
f.use Justcoin::BodyExtractor
|
120
|
+
f.use Justcoin::DecimalConverter
|
121
|
+
end
|
122
|
+
|
123
|
+
f.request :json
|
124
|
+
f.response :mashify
|
125
|
+
f.response :dates
|
126
|
+
f.response :json, content_type: /\bjson$/
|
127
|
+
f.response :logger, options[:logger] if options[:logger] || options[:log]
|
128
|
+
f.response :raise_error
|
129
|
+
|
130
|
+
f.adapter Faraday.default_adapter
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
|
3
|
+
class Justcoin
|
4
|
+
class DecimalConverter < Faraday::Middleware
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
convert_decimals(env.body) if env.body
|
8
|
+
response = @app.call(env)
|
9
|
+
parse_response response.env[:body]
|
10
|
+
response
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def convert_decimals(body)
|
16
|
+
%i(price amount).each do |key|
|
17
|
+
case body[key]
|
18
|
+
when BigDecimal
|
19
|
+
body[key] = body[key].to_s("F")
|
20
|
+
when Numeric
|
21
|
+
body[key] = Float(body[key]).to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_response(value)
|
27
|
+
case value
|
28
|
+
when Array
|
29
|
+
value.map! {|v| parse_response(v)}
|
30
|
+
when Hash, Hashie::Mash
|
31
|
+
value.each do |k, v|
|
32
|
+
value[k] = parse_response(v)
|
33
|
+
end
|
34
|
+
when /^\s*\d*\.\d+/
|
35
|
+
value = BigDecimal.new(value)
|
36
|
+
end
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Accept-Ranges: bytes
|
3
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
4
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
5
|
+
Access-Control-Allow-Origin: *
|
6
|
+
Age: 0
|
7
|
+
cache-control: max-age=0
|
8
|
+
Content-Type: application/json; charset=utf-8
|
9
|
+
Date: Sun, 17 Aug 2014 23:12:03 GMT
|
10
|
+
ETag: W/"247-4257643789"
|
11
|
+
Strict-Transport-Security: max-age=31536000
|
12
|
+
X-Cache: MISS
|
13
|
+
X-Frame-Options: DENY
|
14
|
+
X-XSS-Protection: 1; mode=block
|
15
|
+
Content-Length: 583
|
16
|
+
Connection: keep-alive
|
17
|
+
|
18
|
+
[{"currency":"USD","balance":"0.00000","hold":"0.00000","available":"0.00000"},{"currency":"STR","balance":"5000.00000000","hold":"0.00000000","available":"5000.00000000"},{"currency":"BTC","balance":"0.00000840","hold":"0.00000000","available":"0.00000840"},{"currency":"EUR","balance":"0.00000","hold":"0.00000","available":"0.00000"},{"currency":"NOK","balance":"0.00000","hold":"0.00000","available":"0.00000"},{"currency":"LTC","balance":"0.00000000","hold":"0.00000000","available":"0.00000000"},{"currency":"XRP","balance":"0.114568","hold":"0.000000","available":"0.114568"}]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 204 No Content
|
2
|
+
Accept-Ranges: bytes
|
3
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
4
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
5
|
+
Access-Control-Allow-Origin: *
|
6
|
+
Age: 0
|
7
|
+
cache-control: max-age=0
|
8
|
+
Date: Wed, 20 Aug 2014 20:02:00 GMT
|
9
|
+
Strict-Transport-Security: max-age=31536000
|
10
|
+
X-Cache: MISS
|
11
|
+
X-Frame-Options: DENY
|
12
|
+
X-XSS-Protection: 1; mode=block
|
13
|
+
Connection: keep-alive
|
14
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
3
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
4
|
+
Access-Control-Allow-Origin: *
|
5
|
+
Age: 0
|
6
|
+
cache-control: max-age=0
|
7
|
+
Content-Type: application/json; charset=utf-8
|
8
|
+
Date: Tue, 19 Aug 2014 15:07:08 GMT
|
9
|
+
ETag: W/"6d17-2515187714"
|
10
|
+
Strict-Transport-Security: max-age=31536000
|
11
|
+
X-Cache: MISS
|
12
|
+
X-Frame-Options: DENY
|
13
|
+
X-XSS-Protection: 1; mode=block
|
14
|
+
transfer-encoding: chunked
|
15
|
+
Connection: keep-alive
|
16
|
+
|
17
|
+
{"bids":[["226244.000","0.07020"],["225502.260","0.30000"],["225500.000","0.01651"],["225392.260","0.00200"]],"asks":[["226697.000","0.88946"],["226698.000","3.30000"],["226800.000","0.59715"],["226900.000","1.53781"]]}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Accept-Ranges: bytes
|
3
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
4
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
5
|
+
Access-Control-Allow-Origin: *
|
6
|
+
Age: 0
|
7
|
+
cache-control: max-age=0
|
8
|
+
Content-Type: application/json; charset=utf-8
|
9
|
+
Date: Sun, 17 Aug 2014 23:57:18 GMT
|
10
|
+
ETag: W/"31a-1371539062"
|
11
|
+
Strict-Transport-Security: max-age=31536000
|
12
|
+
X-Cache: MISS
|
13
|
+
X-Frame-Options: DENY
|
14
|
+
X-XSS-Protection: 1; mode=block
|
15
|
+
Content-Length: 794
|
16
|
+
Connection: keep-alive
|
17
|
+
|
18
|
+
[{"id":"BTCEUR","last":"376.777","high":"427.000","low":"371.112","bid":"371.760","ask":"385.410","volume":"16.88278","scale":3},{"id":"BTCLTC","last":"110.999","high":"111.000","low":"86.001","bid":"92.001","ask":"110.999","volume":"2.81474","scale":3},{"id":"BTCNOK","last":"3072.001","high":"3275.149","low":"3072.000","bid":"3075.034","ask":"3110.850","volume":"7.82705","scale":3},{"id":"BTCSTR","last":"210987.890","high":"212303.000","low":"201016.000","bid":"209090.100","ask":"210987.890","volume":"75.07222","scale":3},{"id":"BTCUSD","last":"500.714","high":"533.620","low":"488.501","bid":"495.751","ask":"513.999","volume":"3.92299","scale":3},{"id":"BTCXRP","last":"96800.000","high":"102762.000","low":"93100.000","bid":"93700.714","ask":"96800.000","volume":"7.71935","scale":3}]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Accept-Ranges: bytes
|
3
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
4
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
5
|
+
Access-Control-Allow-Origin: *
|
6
|
+
Age: 0
|
7
|
+
cache-control: max-age=0
|
8
|
+
Content-Type: application/json; charset=utf-8
|
9
|
+
Date: Tue, 19 Aug 2014 15:44:40 GMT
|
10
|
+
ETag: W/"183-2393636014"
|
11
|
+
Strict-Transport-Security: max-age=31536000
|
12
|
+
X-Cache: MISS
|
13
|
+
X-Frame-Options: DENY
|
14
|
+
X-XSS-Protection: 1; mode=block
|
15
|
+
Content-Length: 387
|
16
|
+
Connection: keep-alive
|
17
|
+
|
18
|
+
{"id":3901787,"createdAt":"2014-08-13T09:44:14.093Z","market":"BTCSTR","type":"ask","price":"197999.000","original":"0.08030","matched":"0.08030","canceled":"0.00000","remaining":"0.00000","matches":[{"id":186158,"createdAt":"2014-08-13T09:44:53.274Z","price":"197999.000","amount":"0.00522"},{"id":186159,"createdAt":"2014-08-13T09:45:00.747Z","price":"197999.000","amount":"0.07508"}]}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Accept-Ranges: bytes
|
3
|
+
Access-Control-Allow-Headers: Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
|
4
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, DELETE
|
5
|
+
Access-Control-Allow-Origin: *
|
6
|
+
Age: 0
|
7
|
+
cache-control: max-age=0
|
8
|
+
Content-Type: application/json; charset=utf-8
|
9
|
+
Date: Tue, 19 Aug 2014 15:30:30 GMT
|
10
|
+
ETag: W/"17b-2033545919"
|
11
|
+
Strict-Transport-Security: max-age=31536000
|
12
|
+
X-Cache: MISS
|
13
|
+
X-Frame-Options: DENY
|
14
|
+
X-XSS-Protection: 1; mode=block
|
15
|
+
Content-Length: 379
|
16
|
+
Connection: keep-alive
|
17
|
+
|
18
|
+
[{"id":4054198,"market":"BTCSTR","type":"ask","price":"229494.000","amount":"0.00436","remaining":"0.00436","matched":"0.00000","cancelled":"0.00000","createdAt":"2014-08-19T10:18:55.582Z"},{"id":4054182,"market":"BTCSTR","type":"bid","price":"216777.000","amount":"0.00459","remaining":"0.00459","matched":"0.00000","cancelled":"0.00000","createdAt":"2014-08-19T10:17:55.622Z"}]
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Justcoin do
|
4
|
+
|
5
|
+
let(:justcoin) { Justcoin.new("somekey") }
|
6
|
+
|
7
|
+
it "should have a version number" do
|
8
|
+
expect(Justcoin::VERSION).to_not be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it "builds a client" do
|
13
|
+
expect(justcoin.client).to respond_to(:get)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#balances' do
|
18
|
+
before do
|
19
|
+
stub_get('/balances').with(query: {key: "somekey"}).to_return(fixture("balances.json"))
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the current balances in a hash of currencies" do
|
23
|
+
response = justcoin.balances
|
24
|
+
str = response.detect {|x| x.currency == "STR"}
|
25
|
+
expect(str.balance).to eq(bd("5000.0"))
|
26
|
+
expect(response.map(&:to_hash)).to eq([
|
27
|
+
{'currency' => "USD", 'balance' => bd("0.0"), 'hold' => bd("0.0"), 'available' => bd("0.0")},
|
28
|
+
{'currency' => "STR", 'balance' => bd("5000.0"), 'hold' => bd("0.0"), 'available' => bd("5000.0")},
|
29
|
+
{'currency' => "BTC", 'balance' => bd("0.0000084"), 'hold' => bd("0.0"), 'available' => bd("0.0000084")},
|
30
|
+
{'currency' => "EUR", 'balance' => bd("0.0"), 'hold' => bd("0.0"), 'available' => bd("0.0")},
|
31
|
+
{'currency' => "NOK", 'balance' => bd("0.0"), 'hold' => bd("0.0"), 'available' => bd("0.0")},
|
32
|
+
{'currency' => "LTC", 'balance' => bd("0.0"), 'hold' => bd("0.0"), 'available' => bd("0.0")},
|
33
|
+
{'currency' => "XRP", 'balance' => bd("0.114568"), 'hold' => bd("0.0"), 'available' => bd("0.114568")}
|
34
|
+
])
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with raw: true" do
|
38
|
+
let(:justcoin) { Justcoin.new("somekey", raw: true) }
|
39
|
+
|
40
|
+
it "returns the raw Faraday::Response object" do
|
41
|
+
response = justcoin.balances
|
42
|
+
expect(response).to be_a(Faraday::Response)
|
43
|
+
expect(response).to be_success
|
44
|
+
expect(response.status).to eq(200)
|
45
|
+
expect(response.body.first).to be_a(Hashie::Mash)
|
46
|
+
expect(response.body.map(&:to_hash)).to eq([
|
47
|
+
{"currency"=>"USD", "balance"=>"0.00000", "hold"=>"0.00000", "available"=>"0.00000"},
|
48
|
+
{"currency"=>"STR", "balance"=>"5000.00000000", "hold"=>"0.00000000", "available"=>"5000.00000000"},
|
49
|
+
{"currency"=>"BTC", "balance"=>"0.00000840", "hold"=>"0.00000000", "available"=>"0.00000840"},
|
50
|
+
{"currency"=>"EUR", "balance"=>"0.00000", "hold"=>"0.00000", "available"=>"0.00000"},
|
51
|
+
{"currency"=>"NOK", "balance"=>"0.00000", "hold"=>"0.00000", "available"=>"0.00000"},
|
52
|
+
{"currency"=>"LTC", "balance"=>"0.00000000", "hold"=>"0.00000000", "available"=>"0.00000000"},
|
53
|
+
{"currency"=>"XRP", "balance"=>"0.114568", "hold"=>"0.000000", "available"=>"0.114568"}
|
54
|
+
])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#markets' do
|
60
|
+
before do
|
61
|
+
stub_get('/markets').with(query: {key: "somekey"}).to_return(fixture("markets.json"))
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns the current market statistics" do
|
65
|
+
response = justcoin.markets
|
66
|
+
expect(response.first.high).to eq(bd("427.0"))
|
67
|
+
expect(response.map(&:to_hash)).to eq([
|
68
|
+
{'id' => "BTCEUR", 'last' => bd("376.777"), 'high' => bd("427.0"), 'low' => bd("371.112"), 'bid' => bd("371.76"), 'ask' => bd("385.41"), 'volume' => bd("16.88278"), 'scale' => 3},
|
69
|
+
{'id' => "BTCLTC", 'last' => bd("110.999"), 'high' => bd("111.0"), 'low' => bd("86.001"), 'bid' => bd("92.001"), 'ask' => bd("110.999"), 'volume' => bd("2.81474"), 'scale' => 3},
|
70
|
+
{'id' => "BTCNOK", 'last' => bd("3072.001"), 'high' => bd("3275.149"), 'low' => bd("3072.0"), 'bid' => bd("3075.034"), 'ask' => bd("3110.85"), 'volume' => bd("7.82705"), 'scale' => 3},
|
71
|
+
{'id' => "BTCSTR", 'last' => bd("210987.89"), 'high' => bd("212303.0"), 'low' => bd("201016.0"), 'bid' => bd("209090.1"), 'ask' => bd("210987.89"), 'volume' => bd("75.07222"), 'scale' => 3},
|
72
|
+
{'id' => "BTCUSD", 'last' => bd("500.714"), 'high' => bd("533.62"), 'low' => bd("488.501"), 'bid' => bd("495.751"), 'ask' => bd("513.999"), 'volume' => bd("3.92299"), 'scale' => 3},
|
73
|
+
{'id' => "BTCXRP", 'last' => bd("96800.0"), 'high' => bd("102762.0"), 'low' => bd("93100.0"), 'bid' => bd("93700.714"), 'ask' => bd("96800.0"), 'volume' => bd("7.71935"), 'scale' => 3}
|
74
|
+
])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#market_depth' do
|
79
|
+
before do
|
80
|
+
stub_get('/markets/BTCSTR/depth').with(query: {key: "somekey"}).to_return(fixture("market_depth.json"))
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns the current orders for the given market as arrays of bids and asks" do
|
84
|
+
response = justcoin.market_depth(:btcstr)
|
85
|
+
expect(response.bids).to eq([
|
86
|
+
[bd("226244.0"), bd("0.0702")],
|
87
|
+
[bd("225502.26"), bd("0.3")],
|
88
|
+
[bd("225500.0"), bd("0.01651")],
|
89
|
+
[bd("225392.26"), bd("0.002")]
|
90
|
+
])
|
91
|
+
expect(response.asks).to eq([
|
92
|
+
[bd("226697.0"), bd("0.88946")],
|
93
|
+
[bd("226698.0"), bd("3.3")],
|
94
|
+
[bd("226800.0"), bd("0.59715")],
|
95
|
+
[bd("226900.0"), bd("1.53781")]
|
96
|
+
])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#orders' do
|
101
|
+
before do
|
102
|
+
stub_get('/orders').with(query: {key: "somekey"}).to_return(fixture("orders.json"))
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns the user's active orders" do
|
106
|
+
response = justcoin.orders
|
107
|
+
expect(response.map(&:to_hash)).to eq([
|
108
|
+
{'id' => 4054198, 'market' => "BTCSTR", 'type' => "ask", 'price' => bd("229494.0"), 'amount' => bd("0.00436"), 'remaining' => bd("0.00436"), 'matched' => bd("0.0"), 'cancelled' => bd("0.0"), 'createdAt' => t("2014-08-19T10:18:55.582Z")},
|
109
|
+
{'id' => 4054182, 'market' => "BTCSTR", 'type' => "bid", 'price' => bd("216777.0"), 'amount' => bd("0.00459"), 'remaining' => bd("0.00459"), 'matched' => bd("0.0"), 'cancelled' => bd("0.0"), 'createdAt' => t("2014-08-19T10:17:55.622Z")}
|
110
|
+
])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#order' do
|
115
|
+
before do
|
116
|
+
stub_get('/orders/3901787').with(query: {key: "somekey"}).to_return(fixture("order.json"))
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns information about a specific order" do
|
120
|
+
response = justcoin.order(3901787)
|
121
|
+
expect(response.to_hash).to eq({
|
122
|
+
'id' => 3901787,
|
123
|
+
'createdAt' => t("2014-08-13T09:44:14.093Z"),
|
124
|
+
'market' => "BTCSTR",
|
125
|
+
'type' => "ask",
|
126
|
+
'price' => bd("197999.0"),
|
127
|
+
'original' => bd("0.0803"),
|
128
|
+
'matched' => bd("0.0803"),
|
129
|
+
'canceled' => bd("0.0"),
|
130
|
+
'remaining' => bd("0.0"),
|
131
|
+
'matches' => [
|
132
|
+
{'id' => 186158, 'createdAt' => t("2014-08-13T09:44:53.274Z"), 'price' => bd("197999.0"), 'amount' => bd("0.00522")},
|
133
|
+
{'id' => 186159, 'createdAt' => t("2014-08-13T09:45:00.747Z"), 'price' => bd("197999.0"), 'amount' => bd("0.07508")}
|
134
|
+
]
|
135
|
+
})
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#create_order' do
|
140
|
+
it "accepts only :bid or :ask for the type argument" do
|
141
|
+
expect(-> { justcoin.create_order(:btcstr, :foo, 0, 0) }).to raise_error(ArgumentError)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "converts amount and price to string and returns the id of the created order" do
|
145
|
+
request = stub_post('/orders').with(
|
146
|
+
query: {key: "somekey"},
|
147
|
+
body: {
|
148
|
+
market: "BTCSTR",
|
149
|
+
type: "bid",
|
150
|
+
price: "202020.0",
|
151
|
+
amount: "0.002462689"
|
152
|
+
}
|
153
|
+
).to_return(fixture("create_order.json"))
|
154
|
+
response = justcoin.create_order(:btcstr, :bid, 202020, bd("0.002462689"))
|
155
|
+
expect(request).to have_been_requested
|
156
|
+
expect(response.id).to eq(4089635)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#cancel_order' do
|
161
|
+
before do
|
162
|
+
stub_delete('/orders/4094455').with(query: {key: "somekey"}).to_return(fixture("cancel_order.json"))
|
163
|
+
end
|
164
|
+
|
165
|
+
it "returns true if cancelling was successful" do
|
166
|
+
response = justcoin.cancel_order(4094455)
|
167
|
+
expect(response).to be(true)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'justcoin'
|
3
|
+
|
4
|
+
require 'webmock/rspec'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include WebMock::API
|
8
|
+
end
|
9
|
+
|
10
|
+
def a_delete(path)
|
11
|
+
a_request(:delete, Justcoin::DEFAULT_URL + path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def a_get(path)
|
15
|
+
a_request(:get, Justcoin::DEFAULT_URL + path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def a_post(path)
|
19
|
+
a_request(:post, Justcoin::DEFAULT_URL + path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def a_put(path)
|
23
|
+
a_request(:put, Justcoin::DEFAULT_URL + path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_delete(path)
|
27
|
+
stub_request(:delete, Justcoin::DEFAULT_URL + path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def stub_get(path)
|
31
|
+
stub_request(:get, Justcoin::DEFAULT_URL + path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def stub_post(path)
|
35
|
+
stub_request(:post, Justcoin::DEFAULT_URL + path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def stub_put(path)
|
39
|
+
stub_request(:put, Justcoin::DEFAULT_URL + path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def fixture_path
|
43
|
+
File.expand_path('../fixtures', __FILE__)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fixture(file)
|
47
|
+
File.new(fixture_path + '/' + file)
|
48
|
+
end
|
49
|
+
|
50
|
+
def bd(number)
|
51
|
+
BigDecimal.new(number)
|
52
|
+
end
|
53
|
+
|
54
|
+
def t(time_string)
|
55
|
+
Time.parse(time_string)
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: justcoin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Laszlo Bacsi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday_middleware
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hashie
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Justcoin API client
|
112
|
+
email:
|
113
|
+
- lackac@lackac.hu
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- .travis.yml
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- justcoin.gemspec
|
126
|
+
- lib/justcoin.rb
|
127
|
+
- lib/justcoin/body_extractor.rb
|
128
|
+
- lib/justcoin/decimal_converter.rb
|
129
|
+
- lib/justcoin/version.rb
|
130
|
+
- spec/fixtures/balances.json
|
131
|
+
- spec/fixtures/cancel_order.json
|
132
|
+
- spec/fixtures/create_order.json
|
133
|
+
- spec/fixtures/market_depth.json
|
134
|
+
- spec/fixtures/markets.json
|
135
|
+
- spec/fixtures/order.json
|
136
|
+
- spec/fixtures/orders.json
|
137
|
+
- spec/justcoin_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
homepage: https://github.com/lackac/justcoin
|
140
|
+
licenses:
|
141
|
+
- MIT
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - '>='
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.1.10
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: Justcoin API client
|
163
|
+
test_files:
|
164
|
+
- spec/fixtures/balances.json
|
165
|
+
- spec/fixtures/cancel_order.json
|
166
|
+
- spec/fixtures/create_order.json
|
167
|
+
- spec/fixtures/market_depth.json
|
168
|
+
- spec/fixtures/markets.json
|
169
|
+
- spec/fixtures/order.json
|
170
|
+
- spec/fixtures/orders.json
|
171
|
+
- spec/justcoin_spec.rb
|
172
|
+
- spec/spec_helper.rb
|
173
|
+
has_rdoc:
|