flashboy 0.1.0 → 0.2.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 +4 -4
- data/lib/flashboy.rb +12 -0
- data/lib/flashboy/bitfinex.rb +19 -2
- data/lib/flashboy/cex.rb +20 -2
- data/lib/flashboy/client.rb +13 -0
- data/lib/flashboy/exchange.rb +27 -3
- data/lib/flashboy/gdax.rb +19 -2
- data/lib/flashboy/gemini.rb +17 -0
- data/lib/flashboy/kraken.rb +24 -2
- data/lib/flashboy/order_book.rb +5 -4
- data/lib/flashboy/poloniex.rb +21 -0
- data/lib/flashboy/quoine.rb +24 -1
- data/lib/flashboy/trade.rb +31 -0
- data/lib/flashboy/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ed0ad1eabe895752f900b3db82b730d66a64c92
|
4
|
+
data.tar.gz: 205d2358756acc3908552d6fccc65c73996f2a16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef5a71afb4db214c7fb945e1d5ea7d4ab0ccef8ed9aca91a7680a2a479a772d9229c24c8ae9dbb5a8ef5051624e056c2288cadc6663c71b0d71c841c97f5d77a
|
7
|
+
data.tar.gz: 5279f96044882995075099a7d1c61a2d44782f7ee0b9711ab647934a4b7df0f1a1f9365cf812c13792c556564d89024eaa92e93b60758bfdf94b63b4735b63ab
|
data/lib/flashboy.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'flashboy/version'
|
2
2
|
require 'faraday'
|
3
3
|
require 'json'
|
4
|
+
require 'logger'
|
4
5
|
|
5
6
|
require 'ext/hash'
|
6
7
|
|
@@ -12,6 +13,7 @@ module Flashboy
|
|
12
13
|
autoload :Order, 'flashboy/order'
|
13
14
|
autoload :OrderBook, 'flashboy/order_book'
|
14
15
|
autoload :Quote, 'flashboy/quote'
|
16
|
+
autoload :Trade, 'flashboy/trade'
|
15
17
|
|
16
18
|
autoload :Bitfinex, 'flashboy/bitfinex'
|
17
19
|
autoload :Bittrex, 'flashboy/bittrex'
|
@@ -22,12 +24,22 @@ module Flashboy
|
|
22
24
|
autoload :Poloniex, 'flashboy/poloniex'
|
23
25
|
autoload :Quoine, 'flashboy/quoine'
|
24
26
|
|
27
|
+
def self.logger
|
28
|
+
@logger ||= Logger.new(STDOUT)
|
29
|
+
end
|
30
|
+
|
25
31
|
def self.quote(pair)
|
26
32
|
exchanges.map do |exchange|
|
27
33
|
exchange.new.quote(pair)
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
37
|
+
def self.order_book(pair)
|
38
|
+
exchanges.map do |exchange|
|
39
|
+
exchange.new.order_book(pair)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
31
43
|
def self.exchanges
|
32
44
|
[Bitfinex, Bittrex, Cex, Gdax, Gemini, Kraken, Poloniex, Quoine]
|
33
45
|
end
|
data/lib/flashboy/bitfinex.rb
CHANGED
@@ -5,6 +5,11 @@ module Flashboy
|
|
5
5
|
host 'https://api.bitfinex.com'
|
6
6
|
quote_path { |pair| "v1/pubticker/#{pair}.json" } #ethbtc
|
7
7
|
order_book_path { |pair| "v1/book/#{pair}.json" }
|
8
|
+
trades_path { |pair, params| "v1/trades/#{pair}?timestamp=#{params[:start]}" }
|
9
|
+
|
10
|
+
def self.parse_cursor(params)
|
11
|
+
{ start: params[:start] }
|
12
|
+
end
|
8
13
|
|
9
14
|
private
|
10
15
|
|
@@ -13,6 +18,18 @@ module Flashboy
|
|
13
18
|
"#{currency}#{base}".upcase
|
14
19
|
end
|
15
20
|
|
21
|
+
def parse_trades(trades, exchange, pair)
|
22
|
+
[*trades].map do |trade|
|
23
|
+
{
|
24
|
+
global_id: "#{exchange.key}-#{trade[:tid]}",
|
25
|
+
type: trade[:type],
|
26
|
+
price: trade[:price],
|
27
|
+
amount: trade[:amount],
|
28
|
+
executed_at: trade[:timestamp]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
def parse_quote(quote, pair)
|
17
34
|
{
|
18
35
|
bid: quote[:bid],
|
@@ -25,8 +42,8 @@ module Flashboy
|
|
25
42
|
|
26
43
|
def parse_order_book(order, pair)
|
27
44
|
{
|
28
|
-
bids: order[:bids].map{|order| { price: order[:price], amount: order[:amount] } },
|
29
|
-
asks: order[:asks].map{|order| { price: order[:price], amount: order[:amount] } }
|
45
|
+
bids: (order[:bids] || []).map{|order| { price: order[:price], amount: order[:amount] } },
|
46
|
+
asks: (order[:asks] || []).map{|order| { price: order[:price], amount: order[:amount] } }
|
30
47
|
}
|
31
48
|
end
|
32
49
|
end
|
data/lib/flashboy/cex.rb
CHANGED
@@ -5,6 +5,11 @@ module Flashboy
|
|
5
5
|
host 'https://cex.io/api'
|
6
6
|
quote_path { |pair| "ticker/#{pair}" } #ETH/BTC
|
7
7
|
order_book_path { |pair| "order_book/#{pair}/?depth=10" }
|
8
|
+
trades_path { |pair, params| "trade_history/#{pair}/?since=#{params[:since]}" }
|
9
|
+
|
10
|
+
def self.parse_cursor(params)
|
11
|
+
{ since: params[:since] }
|
12
|
+
end
|
8
13
|
|
9
14
|
private
|
10
15
|
|
@@ -13,6 +18,19 @@ module Flashboy
|
|
13
18
|
"#{currency}/#{base}".upcase
|
14
19
|
end
|
15
20
|
|
21
|
+
def parse_trades(trades, exchange, _pair)
|
22
|
+
[*trades].map do |trade|
|
23
|
+
{
|
24
|
+
global_id: "#{exchange.key}-#{trade[:tid]}",
|
25
|
+
type: trade[:type],
|
26
|
+
price: trade[:price],
|
27
|
+
amount: trade[:amount],
|
28
|
+
executed_at: trade[:date]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
16
34
|
def parse_quote(quote, pair)
|
17
35
|
{
|
18
36
|
bid: quote[:bid],
|
@@ -25,8 +43,8 @@ module Flashboy
|
|
25
43
|
|
26
44
|
def parse_order_book(order, pair)
|
27
45
|
{
|
28
|
-
bids: order[:bids].map{|(p, a)| { price: p, amount: a } },
|
29
|
-
asks: order[:asks].map{|(p, a)| { price: p, amount: a } }
|
46
|
+
bids: (order[:bids] || []).map{|(p, a)| { price: p, amount: a } },
|
47
|
+
asks: (order[:asks] || []).map{|(p, a)| { price: p, amount: a } }
|
30
48
|
}
|
31
49
|
end
|
32
50
|
end
|
data/lib/flashboy/client.rb
CHANGED
@@ -44,6 +44,19 @@ module Flashboy
|
|
44
44
|
self.class.quote_path(pair)
|
45
45
|
end
|
46
46
|
|
47
|
+
def self.trades_path(pair = nil, params = {}, &path)
|
48
|
+
if !block_given?
|
49
|
+
raise RuntimeError, "You must define the trades_path on your exchange" if @trades_path.nil?
|
50
|
+
return @trades_path.call(pair, params)
|
51
|
+
end
|
52
|
+
|
53
|
+
@trades_path = path
|
54
|
+
end
|
55
|
+
|
56
|
+
def trades_path(pair, params = {})
|
57
|
+
self.class.trades_path(pair, params)
|
58
|
+
end
|
59
|
+
|
47
60
|
def self.order_book_path(pair = nil, &path)
|
48
61
|
return @order_book_path.call(pair) unless block_given?
|
49
62
|
@order_book_path = path
|
data/lib/flashboy/exchange.rb
CHANGED
@@ -9,6 +9,24 @@ module Flashboy
|
|
9
9
|
)
|
10
10
|
end
|
11
11
|
|
12
|
+
def trades(pair, options = {})
|
13
|
+
start, finish, cursor = nil
|
14
|
+
if options[:start] || options[:finish]
|
15
|
+
finish = options[:finish] || Time.now.to_i
|
16
|
+
start = options[:start] || finish - (60 * 60)
|
17
|
+
elsif options[:since]
|
18
|
+
cursor = options[:since] || 0
|
19
|
+
end
|
20
|
+
|
21
|
+
id = formatted_pair(pair)
|
22
|
+
url = trades_path(id, {start: start, finish: finish, since: cursor})
|
23
|
+
# puts url
|
24
|
+
data = request url
|
25
|
+
parse_trades(data, self, id).map do |trade|
|
26
|
+
Trade.new(trade.merge(pair: pair, exchange: name))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
12
30
|
def order_book(pair)
|
13
31
|
id = formatted_pair(pair)
|
14
32
|
data = request order_book_path(id)
|
@@ -29,9 +47,15 @@ module Flashboy
|
|
29
47
|
end
|
30
48
|
|
31
49
|
def request(path)
|
32
|
-
|
33
|
-
|
34
|
-
|
50
|
+
begin
|
51
|
+
response = connection.get(path).body
|
52
|
+
data = JSON.parse(response)
|
53
|
+
rescue JSON::ParserError => e
|
54
|
+
Flashboy.logger.warn "Failed to parse response from #{host}/#{path}"
|
55
|
+
data = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
data.is_a?(Hash) ? data.recursively_symbolize_keys! : data.map(&:recursively_symbolize_keys!)
|
35
59
|
end
|
36
60
|
|
37
61
|
def connection
|
data/lib/flashboy/gdax.rb
CHANGED
@@ -5,6 +5,11 @@ module Flashboy
|
|
5
5
|
host 'https://api.gdax.com'
|
6
6
|
quote_path { |pair| "products/#{pair}/ticker" } #ETH-BTC
|
7
7
|
order_book_path { |pair| "products/#{pair}/book" }
|
8
|
+
trades_path { |pair, params| "products/#{pair}/trades?#{params[:since] ? ('before=' + params[:since].to_s) : ''}" }
|
9
|
+
|
10
|
+
def self.parse_cursor(params)
|
11
|
+
{ since: params[:since] }
|
12
|
+
end
|
8
13
|
|
9
14
|
private
|
10
15
|
|
@@ -13,6 +18,18 @@ module Flashboy
|
|
13
18
|
"#{currency}-#{base}".upcase
|
14
19
|
end
|
15
20
|
|
21
|
+
def parse_trades(trades, exchange, _pair)
|
22
|
+
[*trades].map do |trade|
|
23
|
+
{
|
24
|
+
global_id: "#{exchange.key}-#{trade[:trade_id]}",
|
25
|
+
type: trade[:side],
|
26
|
+
price: trade[:price],
|
27
|
+
amount: trade[:size],
|
28
|
+
executed_at: trade[:time]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
def parse_quote(quote, pair)
|
17
34
|
{
|
18
35
|
bid: quote[:bid],
|
@@ -25,8 +42,8 @@ module Flashboy
|
|
25
42
|
|
26
43
|
def parse_order_book(order, pair)
|
27
44
|
{
|
28
|
-
bids: order[:bids].map{|order| { price: order[:price], amount: order[:amount] } },
|
29
|
-
asks: order[:asks].map{|order| { price: order[:price], amount: order[:amount] } }
|
45
|
+
bids: (order[:bids] || []).map{|order| { price: order[:price], amount: order[:amount] } },
|
46
|
+
asks: (order[:asks] || []).map{|order| { price: order[:price], amount: order[:amount] } }
|
30
47
|
}
|
31
48
|
end
|
32
49
|
end
|
data/lib/flashboy/gemini.rb
CHANGED
@@ -5,6 +5,11 @@ module Flashboy
|
|
5
5
|
host 'https://api.gemini.com/v1'
|
6
6
|
quote_path { |pair| "pubticker/#{pair}" } #ethbtc
|
7
7
|
order_book_path { |pair| "book/#{pair}?depth=10" }
|
8
|
+
trades_path { |pair, params| "trades/#{pair}#{params[:start] ? ('?since=' + params[:start].to_s) : ''}" }
|
9
|
+
|
10
|
+
def self.parse_cursor(params)
|
11
|
+
{ start: params[:start] }
|
12
|
+
end
|
8
13
|
|
9
14
|
private
|
10
15
|
|
@@ -13,6 +18,18 @@ module Flashboy
|
|
13
18
|
"#{currency}#{base}".downcase
|
14
19
|
end
|
15
20
|
|
21
|
+
def parse_trades(trades, exchange, pair)
|
22
|
+
[*trades].map do |trade|
|
23
|
+
{
|
24
|
+
global_id: "#{exchange.key}-#{trade[:tid]}",
|
25
|
+
type: trade[:type],
|
26
|
+
price: trade[:price],
|
27
|
+
amount: trade[:amount],
|
28
|
+
executed_at: trade[:timestamp].to_i
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
def parse_quote(quote, pair)
|
17
34
|
{
|
18
35
|
bid: quote[:bid],
|
data/lib/flashboy/kraken.rb
CHANGED
@@ -1,18 +1,40 @@
|
|
1
1
|
module Flashboy
|
2
2
|
class Kraken < Exchange
|
3
3
|
name 'Kraken'
|
4
|
-
docs '
|
4
|
+
docs 'https://www.kraken.com/help/api'
|
5
5
|
host 'https://api.kraken.com'
|
6
6
|
quote_path { |pair| "0/public/Ticker?pair=#{pair}" } #ETHXBT
|
7
7
|
order_book_path { |pair| "0/public/Depth?pair=#{pair}" }
|
8
|
+
trades_path { |pair, params| "0/public/Trades?pair=#{pair}#{params[:since] ? ('&since=' + params[:since].to_s) : ''}" }
|
9
|
+
|
10
|
+
def self.parse_cursor(params)
|
11
|
+
{ since: params[:since] }
|
12
|
+
end
|
8
13
|
|
9
14
|
private
|
10
15
|
|
11
16
|
def formatted_pair(pair)
|
12
|
-
currency, base = super(pair).map { |curr| curr == 'BTC' ? 'XBT' : curr }
|
17
|
+
currency, base = super(pair).map { |curr| curr.upcase == 'BTC' ? 'XBT' : curr }
|
13
18
|
"#{currency}#{base}".upcase
|
14
19
|
end
|
15
20
|
|
21
|
+
def parse_trades(trades, exchange, pair)
|
22
|
+
last_id = trades[:result][:last]
|
23
|
+
pair_id = trades[:result].keys.first
|
24
|
+
trades = trades[:result][pair_id]
|
25
|
+
|
26
|
+
[*trades].map do |trade|
|
27
|
+
price, amount, time, type = trade
|
28
|
+
{
|
29
|
+
global_id: "#{exchange.key}-#{time}-#{last_id}",
|
30
|
+
type: type == 'b' ? 'buy' : 'sell',
|
31
|
+
price: price,
|
32
|
+
amount: amount,
|
33
|
+
executed_at: time
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
16
38
|
def parse_quote(quote, pair)
|
17
39
|
data = quote[:result].values.first
|
18
40
|
{
|
data/lib/flashboy/order_book.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Flashboy
|
2
2
|
class OrderBook
|
3
|
-
attr_reader :bids, :asks, :
|
3
|
+
attr_reader :pair, :bids, :asks, :exchange
|
4
4
|
|
5
5
|
def initialize(data)
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
6
|
+
@pair = data[:pair]
|
7
|
+
@exchange = data[:exchange]
|
8
|
+
@bids = (data[:bids] || []).map { |bid| Bid.new(bid) }
|
9
|
+
@asks = (data[:asks] || []).map { |ask| Ask.new(ask) }
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
data/lib/flashboy/poloniex.rb
CHANGED
@@ -5,6 +5,15 @@ module Flashboy
|
|
5
5
|
host 'https://poloniex.com'
|
6
6
|
quote_path { |pair| "public?command=returnTicker" } #BTC_ETH
|
7
7
|
order_book_path { |pair| "book/#{pair}?depth=10" }
|
8
|
+
trades_path do |pair, params|
|
9
|
+
url = "public?command=returnTradeHistory¤cyPair=#{pair}"
|
10
|
+
url += "&start=#{params[:start]}" unless params[:start].nil?
|
11
|
+
url
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse_cursor(params)
|
15
|
+
{ start: params[:start] }
|
16
|
+
end
|
8
17
|
|
9
18
|
private
|
10
19
|
|
@@ -13,6 +22,18 @@ module Flashboy
|
|
13
22
|
"#{base}_#{currency}".upcase
|
14
23
|
end
|
15
24
|
|
25
|
+
def parse_trades(trades, exchange, _pair)
|
26
|
+
[*trades].map do |trade|
|
27
|
+
{
|
28
|
+
global_id: "#{exchange.key}-#{trade[:globalTradeID]}",
|
29
|
+
type: trade[:type],
|
30
|
+
price: trade[:rate],
|
31
|
+
amount: trade[:amount],
|
32
|
+
executed_at: trade[:date]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
16
37
|
def parse_quote(quote, pair)
|
17
38
|
data = quote[pair.to_sym]
|
18
39
|
{
|
data/lib/flashboy/quoine.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
module Flashboy
|
2
2
|
class Quoine < Exchange
|
3
3
|
name 'Quoine'
|
4
|
-
docs 'https://developers.quoine.com
|
4
|
+
docs 'https://developers.quoine.com'
|
5
5
|
host 'https://api.quoine.com'
|
6
6
|
quote_path { |pair| "products/code/CASH/#{pair}" } #ETHBTC
|
7
7
|
order_book_path { |pair| "products/#{pair}/price_levels" }
|
8
|
+
trades_path do |pair, params|
|
9
|
+
url = "executions?currency_pair_code=#{pair}"
|
10
|
+
url += "×tamp=#{params[:start]}" if params[:start]
|
11
|
+
url
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse_cursor(params)
|
15
|
+
{ start: params[:start] }
|
16
|
+
end
|
8
17
|
|
9
18
|
private
|
10
19
|
|
@@ -13,6 +22,20 @@ module Flashboy
|
|
13
22
|
"#{currency}#{base}".upcase
|
14
23
|
end
|
15
24
|
|
25
|
+
def parse_trades(trades, exchange, pair)
|
26
|
+
trades = trades.is_a?(Hash) ? trades[:models] : trades
|
27
|
+
[*trades].map do |trade|
|
28
|
+
trade.recursively_symbolize_keys!
|
29
|
+
{
|
30
|
+
global_id: "#{exchange.key}-#{trade[:id]}",
|
31
|
+
type: trade[:taker_side],
|
32
|
+
price: trade[:price],
|
33
|
+
amount: trade[:quantity],
|
34
|
+
executed_at: trade[:created_at]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
16
39
|
def parse_quote(quote, pair)
|
17
40
|
{
|
18
41
|
bid: quote[:market_bid],
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Flashboy
|
2
|
+
class Trade
|
3
|
+
attr_reader :global_id, :type, :exchange, :pair, :price, :amount, :executed_at
|
4
|
+
|
5
|
+
def initialize(attrs)
|
6
|
+
@global_id = attrs[:global_id]
|
7
|
+
@type = attrs[:type]
|
8
|
+
@exchange = attrs[:exchange]
|
9
|
+
@pair = attrs[:pair]
|
10
|
+
@price = attrs[:price].to_s.to_f
|
11
|
+
@amount = attrs[:amount].to_s.to_f
|
12
|
+
@executed_at = attrs[:executed_at]
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
global_id.split('-').last
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_json(_opts)
|
20
|
+
{
|
21
|
+
global_id: global_id,
|
22
|
+
type: type,
|
23
|
+
exchange: exchange,
|
24
|
+
pair: pair,
|
25
|
+
price: price,
|
26
|
+
amount: amount,
|
27
|
+
executed_at: executed_at
|
28
|
+
}.to_json
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/flashboy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flashboy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Werner
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/flashboy/poloniex.rb
|
102
102
|
- lib/flashboy/quoine.rb
|
103
103
|
- lib/flashboy/quote.rb
|
104
|
+
- lib/flashboy/trade.rb
|
104
105
|
- lib/flashboy/version.rb
|
105
106
|
homepage: https://github.com/mwerner/flashboy
|
106
107
|
licenses:
|