justcoin 0.1.0
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.
- 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:
|