bitstamper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +5 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +66 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +39 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +32 -0
  13. data/bin/setup +8 -0
  14. data/bin/websocket +55 -0
  15. data/bitstamper.gemspec +35 -0
  16. data/credentials.yml.example +9 -0
  17. data/lib/.DS_Store +0 -0
  18. data/lib/bitstamper/configuration.rb +41 -0
  19. data/lib/bitstamper/constants.rb +34 -0
  20. data/lib/bitstamper/errors.rb +11 -0
  21. data/lib/bitstamper/extensions/hash.rb +27 -0
  22. data/lib/bitstamper/models/balance.rb +56 -0
  23. data/lib/bitstamper/models/base.rb +11 -0
  24. data/lib/bitstamper/models/deposit.rb +26 -0
  25. data/lib/bitstamper/models/live_trade.rb +41 -0
  26. data/lib/bitstamper/models/order.rb +48 -0
  27. data/lib/bitstamper/models/order_book.rb +28 -0
  28. data/lib/bitstamper/models/ticker.rb +33 -0
  29. data/lib/bitstamper/models/trading_pair.rb +35 -0
  30. data/lib/bitstamper/models/transaction.rb +37 -0
  31. data/lib/bitstamper/models/user_transaction.rb +55 -0
  32. data/lib/bitstamper/models/withdrawal.rb +53 -0
  33. data/lib/bitstamper/rest/client.rb +102 -0
  34. data/lib/bitstamper/rest/errors.rb +39 -0
  35. data/lib/bitstamper/rest/private/balances.rb +18 -0
  36. data/lib/bitstamper/rest/private/deposits.rb +51 -0
  37. data/lib/bitstamper/rest/private/orders.rb +103 -0
  38. data/lib/bitstamper/rest/private/transactions.rb +19 -0
  39. data/lib/bitstamper/rest/private/withdrawals.rb +53 -0
  40. data/lib/bitstamper/rest/public/currencies.rb +14 -0
  41. data/lib/bitstamper/rest/public/order_book.rb +14 -0
  42. data/lib/bitstamper/rest/public/ticker.rb +30 -0
  43. data/lib/bitstamper/rest/public/trading_pairs.rb +14 -0
  44. data/lib/bitstamper/rest/public/transactions.rb +18 -0
  45. data/lib/bitstamper/utilities.rb +61 -0
  46. data/lib/bitstamper/version.rb +3 -0
  47. data/lib/bitstamper/websocket/client.rb +127 -0
  48. data/lib/bitstamper.rb +72 -0
  49. metadata +231 -0
@@ -0,0 +1,14 @@
1
+ module Bitstamper
2
+ module Rest
3
+ module Public
4
+ module Currencies
5
+
6
+ def eur_usd_rate
7
+ response = get("/eur_usd")
8
+ {buy: response&.fetch("buy", nil)&.to_f, sell: response&.fetch("sell", nil)&.to_f}
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Bitstamper
2
+ module Rest
3
+ module Public
4
+ module OrderBook
5
+
6
+ def order_book(currency_pair = "btcusd")
7
+ response = get(path_with_currency_pair("/v2/order_book", currency_pair))
8
+ ::Bitstamper::Models::OrderBook.new(response) if response
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Bitstamper
2
+ module Rest
3
+ module Public
4
+ module Ticker
5
+
6
+ def daily_ticker(currency_pair: "btcusd")
7
+ ticker(currency_pair: currency_pair, interval: :daily)
8
+ end
9
+
10
+ def hourly_ticker(currency_pair: "btcusd")
11
+ ticker(currency_pair: currency_pair, interval: :hourly)
12
+ end
13
+
14
+ def ticker(currency_pair: "btcusd", interval: :daily)
15
+ path = case interval.to_sym
16
+ when :daily
17
+ !currency_pair.to_s.empty? ? "/v2/ticker/#{::Bitstamper::Utilities.fix_currency_pair(currency_pair)}" : "/ticker"
18
+ when :hourly
19
+ !currency_pair.to_s.empty? ? "/v2/ticker_hour/#{::Bitstamper::Utilities.fix_currency_pair(currency_pair)}" : "/ticker_hour"
20
+ end
21
+
22
+ response = get(path)
23
+
24
+ ::Bitstamper::Models::Ticker.new(response.merge("currency_pair" => currency_pair)) if response
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ module Bitstamper
2
+ module Rest
3
+ module Public
4
+ module TradingPairs
5
+
6
+ def trading_pairs
7
+ response = get("/v2/trading-pairs-info")
8
+ ::Bitstamper::Models::TradingPair.parse(response) if response
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module Bitstamper
2
+ module Rest
3
+ module Public
4
+ module Transactions
5
+
6
+ def transactions(currency_pair = "btcusd", time: :hour)
7
+ response = get(path_with_currency_pair("/v2/transactions", currency_pair), params: {time: time})
8
+ Bitstamper::Models::Transaction.parse(response) if response
9
+ end
10
+
11
+ def find_transaction(transaction_id)
12
+ transactions.select { |transaction| transaction.id == transaction_id }&.first
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,61 @@
1
+ module Bitstamper
2
+ class Utilities
3
+
4
+ class << self
5
+ def fix_currency_pair(currency_pair)
6
+ currency_pair&.to_s&.strip&.downcase
7
+ end
8
+
9
+ def convert_value(value, type)
10
+ return case type
11
+ when :string
12
+ value.to_s
13
+ when :integer
14
+ value.to_i
15
+ when :float
16
+ value.to_f
17
+ when :boolean
18
+ value.to_s.downcase.eql?("true")
19
+ when :datetime
20
+ DateTime.parse(value)
21
+ when :time
22
+ epoch_to_time(value)
23
+ when :hash
24
+ value.symbolize_keys
25
+ else
26
+ value
27
+ end
28
+ end
29
+
30
+ def epoch_to_time(epoch)
31
+ ::Time.at(epoch.to_i).utc
32
+ end
33
+
34
+ def numeric?(string)
35
+ !!Kernel.Float(string)
36
+ rescue TypeError, ArgumentError
37
+ false
38
+ end
39
+
40
+ def parse_objects!(string, klass)
41
+ # If Bitstamp returned nothing (which it does if the results yield empty) 'cast' it to an array
42
+ string = "[]" if string == ""
43
+
44
+ objects = JSON.parse(string)
45
+ objects.collect do |t_json|
46
+ parse_object!(t_json, klass)
47
+ end
48
+ end
49
+
50
+ def parse_object!(object, klass)
51
+ object = JSON.parse(object) if object.is_a? String
52
+ if object["status"] == "error"
53
+ raise ArgumentError.new(object["reason"])
54
+ end
55
+
56
+ klass.new(object)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Bitstamper
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,127 @@
1
+ module Bitstamper
2
+ module Websocket
3
+ class Client
4
+ attr_accessor :socket, :application_key, :enable_logging
5
+ attr_accessor :channels, :subscriptions, :callbacks
6
+
7
+ def initialize(application_key: ::Bitstamper.configuration.pusher_app_key, enable_logging: false)
8
+ self.socket = nil
9
+
10
+ self.application_key = application_key
11
+ self.enable_logging = enable_logging
12
+
13
+ self.channels = {
14
+ live_trades: [],
15
+ order_book: [],
16
+ diff_order_book: [],
17
+ live_orders: []
18
+ }
19
+
20
+ self.subscriptions = []
21
+
22
+ self.callbacks = {
23
+ live_trades: -> (channel, event, data) { received(channel, event, data) },
24
+ order_book: -> (channel, event, data) { received(channel, event, data) },
25
+ diff_order_book: -> (channel, event, data) { received(channel, event, data) },
26
+
27
+ live_orders: {
28
+ order_created: -> (channel, event, data) { received(channel, event, data) },
29
+ order_changed: -> (channel, event, data) { received(channel, event, data) },
30
+ order_deleted: -> (channel, event, data) { received(channel, event, data) }
31
+ }
32
+ }
33
+
34
+ disable_pusher_logging if !self.enable_logging
35
+ generate_channels
36
+ end
37
+
38
+ def disable_pusher_logging
39
+ PusherClient.logger = Logger.new(nil)
40
+ end
41
+
42
+ def generate_channels
43
+ ::Bitstamper.configuration.products.each do |product|
44
+ self.channels[:live_trades] << {name: "live_trades_#{product}", product: product, events: ["trade"]}
45
+ self.channels[:order_book] << {name: "order_book_#{product}", product: product, events: ["data"]}
46
+ self.channels[:diff_order_book] << {name: "diff_order_book_#{product}", product: product, events: ["data"]}
47
+ self.channels[:live_orders] << {name: "live_orders_#{product}", product: product, events: ["order_created", "order_changed", "order_deleted"]}
48
+ end
49
+ end
50
+
51
+ def start!(async: true)
52
+ self.socket = PusherClient::Socket.new(self.application_key)
53
+ self.socket.connect(async)
54
+ end
55
+
56
+ def stop!
57
+ self.socket.disconnect
58
+ end
59
+
60
+ def subscribe!(type, product: nil)
61
+ chnls = self.channels.fetch(type, [])
62
+ chnls = chnls&.select { |channel| channel[:product].to_s == product.to_s } if !product.to_s.empty? && product.to_s != "all"
63
+
64
+ chnls.each do |channel|
65
+ if !self.subscriptions.include?(channel[:name])
66
+ self.socket.subscribe(channel[:name])
67
+ self.subscriptions << channel[:name]
68
+
69
+ channel[:events].each do |event|
70
+ self.socket[channel[:name]].bind(event) do |data|
71
+ ws_received(channel, event, data)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def loop!
79
+ loop do
80
+ sleep(1)
81
+ end
82
+ end
83
+
84
+ # Implement your own callback to customize how data is processed
85
+ def received(channel, event, data)
86
+ parsed = case channel[:name]
87
+ when /^live_trades/i
88
+ ::Bitstamper::Models::LiveTrade.new(data.symbolize_keys.merge(product: channel[:product]))
89
+ when /^order_book/i
90
+ ::Bitstamper::Models::OrderBook.new(data)
91
+ when /^diff_order_book/i
92
+ ::Bitstamper::Models::OrderBook.new(data)
93
+ when /^live_orders/i
94
+ ::Bitstamper::Models::Order.new(data.merge(event: event))
95
+ end
96
+
97
+ pp parsed
98
+ end
99
+
100
+ private
101
+ def ws_received(channel, event, data)
102
+ data = parse(data)
103
+
104
+ case channel[:name]
105
+ when /^live_trades/i
106
+ self.callbacks[:live_trades].call(channel, event, data)
107
+ when /^order_book/i
108
+ self.callbacks[:order_book].call(channel, event, data)
109
+ when /^diff_order_book/i
110
+ self.callbacks[:diff_order_book].call(channel, event, data)
111
+ when /^live_orders/i
112
+ self.callbacks[:live_orders][:order_created].call(channel, event, data) if event == "order_created"
113
+ self.callbacks[:live_orders][:order_changed].call(channel, event, data) if event == "order_changed"
114
+ self.callbacks[:live_orders][:order_deleted].call(channel, event, data) if event == "order_deleted"
115
+ end
116
+ end
117
+
118
+ def parse(data)
119
+ return data if data.is_a? Hash
120
+ return JSON.parse(data)
121
+ rescue => err
122
+ return data
123
+ end
124
+
125
+ end
126
+ end
127
+ end
data/lib/bitstamper.rb ADDED
@@ -0,0 +1,72 @@
1
+ # Rest API
2
+ require "faraday"
3
+ require "faraday_middleware"
4
+ require "hmac-sha2"
5
+
6
+ # Websockets
7
+ require "pusher-client"
8
+
9
+ # Shared
10
+ require "json"
11
+ require "date"
12
+
13
+ # Library
14
+ require "bitstamper/version"
15
+
16
+ require "bitstamper/configuration"
17
+ require "bitstamper/errors"
18
+ require "bitstamper/constants"
19
+ require "bitstamper/utilities"
20
+
21
+ require "bitstamper/models/base"
22
+ require "bitstamper/models/balance"
23
+ require "bitstamper/models/order"
24
+ require "bitstamper/models/order_book"
25
+ require "bitstamper/models/ticker"
26
+ require "bitstamper/models/user_transaction"
27
+ require "bitstamper/models/transaction"
28
+ require "bitstamper/models/trading_pair"
29
+ require "bitstamper/models/deposit"
30
+ require "bitstamper/models/withdrawal"
31
+ require "bitstamper/models/live_trade"
32
+
33
+ require "bitstamper/rest/public/ticker"
34
+ require "bitstamper/rest/public/order_book"
35
+ require "bitstamper/rest/public/transactions"
36
+ require "bitstamper/rest/public/trading_pairs"
37
+ require "bitstamper/rest/public/currencies"
38
+
39
+ require "bitstamper/rest/private/balances"
40
+ require "bitstamper/rest/private/deposits"
41
+ require "bitstamper/rest/private/withdrawals"
42
+ require "bitstamper/rest/private/orders"
43
+ require "bitstamper/rest/private/transactions"
44
+
45
+ require "bitstamper/rest/errors"
46
+ require "bitstamper/rest/client"
47
+
48
+ require "bitstamper/websocket/client"
49
+
50
+ if !Hash.instance_methods(false).include?(:symbolize_keys)
51
+ require "bitstamper/extensions/hash"
52
+ end
53
+
54
+ module Bitstamper
55
+
56
+ class << self
57
+ attr_writer :configuration
58
+ end
59
+
60
+ def self.configuration
61
+ @configuration ||= ::Bitstamper::Configuration.new
62
+ end
63
+
64
+ def self.reset
65
+ @configuration = ::Bitstamper::Configuration.new
66
+ end
67
+
68
+ def self.configure
69
+ yield(configuration)
70
+ end
71
+
72
+ end
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitstamper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - SebastianJ
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-01-28 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.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0.13'
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.12.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.12.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-hmac
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.4.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.4.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: pusher-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.16'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.16'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rdoc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '6.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '6.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: vcr
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '4.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '4.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: webmock
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.1'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.1'
153
+ description: Rest + Websocket client for interacting with Bitstamp's API'
154
+ email:
155
+ - sebastian.johnsson@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".DS_Store"
161
+ - ".gitignore"
162
+ - ".rspec"
163
+ - ".travis.yml"
164
+ - CODE_OF_CONDUCT.md
165
+ - Gemfile
166
+ - Gemfile.lock
167
+ - LICENSE.txt
168
+ - README.md
169
+ - Rakefile
170
+ - bin/console
171
+ - bin/setup
172
+ - bin/websocket
173
+ - bitstamper.gemspec
174
+ - credentials.yml.example
175
+ - lib/.DS_Store
176
+ - lib/bitstamper.rb
177
+ - lib/bitstamper/configuration.rb
178
+ - lib/bitstamper/constants.rb
179
+ - lib/bitstamper/errors.rb
180
+ - lib/bitstamper/extensions/hash.rb
181
+ - lib/bitstamper/models/balance.rb
182
+ - lib/bitstamper/models/base.rb
183
+ - lib/bitstamper/models/deposit.rb
184
+ - lib/bitstamper/models/live_trade.rb
185
+ - lib/bitstamper/models/order.rb
186
+ - lib/bitstamper/models/order_book.rb
187
+ - lib/bitstamper/models/ticker.rb
188
+ - lib/bitstamper/models/trading_pair.rb
189
+ - lib/bitstamper/models/transaction.rb
190
+ - lib/bitstamper/models/user_transaction.rb
191
+ - lib/bitstamper/models/withdrawal.rb
192
+ - lib/bitstamper/rest/client.rb
193
+ - lib/bitstamper/rest/errors.rb
194
+ - lib/bitstamper/rest/private/balances.rb
195
+ - lib/bitstamper/rest/private/deposits.rb
196
+ - lib/bitstamper/rest/private/orders.rb
197
+ - lib/bitstamper/rest/private/transactions.rb
198
+ - lib/bitstamper/rest/private/withdrawals.rb
199
+ - lib/bitstamper/rest/public/currencies.rb
200
+ - lib/bitstamper/rest/public/order_book.rb
201
+ - lib/bitstamper/rest/public/ticker.rb
202
+ - lib/bitstamper/rest/public/trading_pairs.rb
203
+ - lib/bitstamper/rest/public/transactions.rb
204
+ - lib/bitstamper/utilities.rb
205
+ - lib/bitstamper/version.rb
206
+ - lib/bitstamper/websocket/client.rb
207
+ homepage: https://github.com/SebastianJ/Bitstamper
208
+ licenses:
209
+ - MIT
210
+ metadata: {}
211
+ post_install_message:
212
+ rdoc_options: []
213
+ require_paths:
214
+ - lib
215
+ required_ruby_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ">="
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ requirements: []
226
+ rubyforge_project:
227
+ rubygems_version: 2.7.4
228
+ signing_key:
229
+ specification_version: 4
230
+ summary: Ruby client for Bitstamp's API'
231
+ test_files: []