bitflyer 0.2.0 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7e97040225bbcb8c03f0b30d2cc7e99f961b26b8
4
- data.tar.gz: 635e649a96a37e01cc7c7adb6cdc199cea09cc41
2
+ SHA256:
3
+ metadata.gz: 3b414a7e2a6dd054ca0aff1d217dc8c8e712f8969daa03d91dbf795e33111e94
4
+ data.tar.gz: cb365b45701c9a23bf6d6f7b4818f04e6eeef1e709909802feca8d62779cb7f1
5
5
  SHA512:
6
- metadata.gz: 5c2169cd4ee452ecdef914b95c35d0d01a42f9dc4cf55e2b32dce3f741da641d3684b0aa049e5a5db4b9700c7ab464b1c88b7bcde89e2b39c368570ba4e73e8e
7
- data.tar.gz: c678a6b2ca82f303ec2d7c02c192bde247e144328e2feed5b3d3e9dac813f66ce638664cf38ffbca3f5d75789bdef6559fe459132b2b95a8d36296d6d7b7cda9
6
+ metadata.gz: 66beabfdb8ba7893f44b16c41a6371b6eb0cfd131138055d6d72a02ac90af17ffa450a155c4dac0f19433705228319714111464af07159e56c7f0bd08f456b0e
7
+ data.tar.gz: 56ac4fe5e16694a3c4d2b4049c4fefa9b1fa7a9412133ce9c5596d9ec53dd664ccd5d155af54df3645cfab655f790105b62c18c3e73e562bd44e481f68a687d6
@@ -0,0 +1,54 @@
1
+ version: 2.1
2
+
3
+ update_bundler: &update_bundler
4
+ run:
5
+ name: update bundler
6
+ command: gem update bundler
7
+
8
+ bundle_install: &bundle_install
9
+ run:
10
+ name: bundle install
11
+ command: bundle update --bundler && bundle install --path vendor/bundle --jobs 4
12
+
13
+ restore_bundle_cache: &restore_bundle_cache
14
+ restore_cache:
15
+ key: cache-bundler-{{ checksum "Gemfile.lock" }}
16
+
17
+ jobs:
18
+ build:
19
+ docker:
20
+ - image: circleci/ruby
21
+ steps:
22
+ - checkout
23
+ - *restore_bundle_cache
24
+ - *update_bundler
25
+ - *bundle_install
26
+ - save_cache:
27
+ key: cache-bundler-{{ checksum "Gemfile.lock" }}
28
+ paths:
29
+ - vendor/bundle
30
+ rubocop:
31
+ docker:
32
+ - image: circleci/ruby
33
+ steps:
34
+ - checkout
35
+ - *restore_bundle_cache
36
+ - *update_bundler
37
+ - *bundle_install
38
+ - run: bundle exec rubocop
39
+ rspec:
40
+ docker:
41
+ - image: circleci/ruby
42
+ steps:
43
+ - checkout
44
+ - *restore_bundle_cache
45
+ - *update_bundler
46
+ - *bundle_install
47
+ - run: bundle exec rspec
48
+ workflows:
49
+ version: 2.1
50
+ rspec:
51
+ jobs:
52
+ - build
53
+ - rubocop
54
+ - rspec
@@ -0,0 +1,10 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ NewCops: enable
5
+ Include:
6
+ - 'lib/**/*.rb'
7
+ Style/Documentation:
8
+ Enabled: false
9
+ Metrics/LineLength:
10
+ Max: 120
@@ -0,0 +1,35 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2020-08-08 12:17:16 UTC using RuboCop version 0.89.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ # Configuration parameters: IgnoredMethods.
11
+ Metrics/AbcSize:
12
+ Max: 32
13
+
14
+ # Offense count: 2
15
+ # Configuration parameters: CountComments, CountAsOne.
16
+ Metrics/ClassLength:
17
+ Max: 146
18
+
19
+ # Offense count: 2
20
+ # Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
21
+ Metrics/MethodLength:
22
+ Max: 20
23
+
24
+ # Offense count: 3
25
+ # Configuration parameters: CountKeywordArgs.
26
+ Metrics/ParameterLists:
27
+ Max: 7
28
+
29
+ # Offense count: 1
30
+ # Cop supports --auto-correct.
31
+ # Configuration parameters: EnforcedStyle.
32
+ # SupportedStyles: always, always_true, never
33
+ Style/FrozenStringLiteralComment:
34
+ Exclude:
35
+ - 'bin/console'
@@ -1,99 +1,77 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bitflyer (0.2.0)
5
- faraday (~> 0.14.0)
6
- faraday_middleware (~> 0.12.0)
7
- pubnub (~> 4.0.22)
4
+ bitflyer (1.0.1)
5
+ faraday (>= 0.14, < 1.2)
6
+ faraday_middleware (>= 0.12, < 1.1)
7
+ websocket-client-simple (~> 0.3.0)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- celluloid (0.17.3)
13
- celluloid-essentials
14
- celluloid-extras
15
- celluloid-fsm
16
- celluloid-pool
17
- celluloid-supervision
18
- timers (>= 4.1.1)
19
- celluloid-essentials (0.20.5)
20
- timers (>= 4.1.1)
21
- celluloid-extras (0.20.5)
22
- timers (>= 4.1.1)
23
- celluloid-fsm (0.20.5)
24
- timers (>= 4.1.1)
25
- celluloid-pool (0.20.5)
26
- timers (>= 4.1.1)
27
- celluloid-supervision (0.20.6)
28
- timers (>= 4.1.1)
29
- concurrent-ruby (1.0.5)
30
- diff-lcs (1.3)
31
- dry-configurable (0.7.0)
32
- concurrent-ruby (~> 1.0)
33
- dry-container (0.6.0)
34
- concurrent-ruby (~> 1.0)
35
- dry-configurable (~> 0.1, >= 0.1.3)
36
- dry-core (0.4.2)
37
- concurrent-ruby (~> 1.0)
38
- dry-equalizer (0.2.0)
39
- dry-logic (0.4.2)
40
- dry-container (~> 0.2, >= 0.2.6)
41
- dry-core (~> 0.2)
42
- dry-equalizer (~> 0.2)
43
- dry-types (0.12.2)
44
- concurrent-ruby (~> 1.0)
45
- dry-configurable (~> 0.1)
46
- dry-container (~> 0.3)
47
- dry-core (~> 0.2, >= 0.2.1)
48
- dry-equalizer (~> 0.2)
49
- dry-logic (~> 0.4, >= 0.4.2)
50
- inflecto (~> 0.0.0, >= 0.0.2)
51
- dry-validation (0.11.1)
52
- concurrent-ruby (~> 1.0)
53
- dry-configurable (~> 0.1, >= 0.1.3)
54
- dry-core (~> 0.2, >= 0.2.1)
55
- dry-equalizer (~> 0.2)
56
- dry-logic (~> 0.4, >= 0.4.0)
57
- dry-types (~> 0.12.0)
58
- faraday (0.14.0)
12
+ ast (2.4.1)
13
+ coderay (1.1.3)
14
+ diff-lcs (1.4.4)
15
+ event_emitter (0.2.6)
16
+ faraday (1.1.0)
59
17
  multipart-post (>= 1.2, < 3)
60
- faraday_middleware (0.12.2)
61
- faraday (>= 0.7.4, < 1.0)
62
- hitimes (1.2.6)
63
- httpclient (2.8.3)
64
- inflecto (0.0.2)
65
- json (2.1.0)
66
- multipart-post (2.0.0)
67
- pubnub (4.0.27)
68
- celluloid (~> 0.17)
69
- dry-validation (~> 0.10)
70
- httpclient (~> 2.8, >= 2.8.3)
71
- json (>= 1.8, < 3)
72
- rake (12.3.0)
73
- rspec (3.7.0)
74
- rspec-core (~> 3.7.0)
75
- rspec-expectations (~> 3.7.0)
76
- rspec-mocks (~> 3.7.0)
77
- rspec-core (3.7.1)
78
- rspec-support (~> 3.7.0)
79
- rspec-expectations (3.7.0)
18
+ ruby2_keywords
19
+ faraday_middleware (1.0.0)
20
+ faraday (~> 1.0)
21
+ method_source (1.0.0)
22
+ multipart-post (2.1.1)
23
+ parallel (1.19.2)
24
+ parser (2.7.2.0)
25
+ ast (~> 2.4.1)
26
+ pry (0.13.1)
27
+ coderay (~> 1.1)
28
+ method_source (~> 1.0)
29
+ rainbow (3.0.0)
30
+ rake (13.0.1)
31
+ regexp_parser (1.8.2)
32
+ rexml (3.2.4)
33
+ rspec (3.10.0)
34
+ rspec-core (~> 3.10.0)
35
+ rspec-expectations (~> 3.10.0)
36
+ rspec-mocks (~> 3.10.0)
37
+ rspec-core (3.10.0)
38
+ rspec-support (~> 3.10.0)
39
+ rspec-expectations (3.10.0)
80
40
  diff-lcs (>= 1.2.0, < 2.0)
81
- rspec-support (~> 3.7.0)
82
- rspec-mocks (3.7.0)
41
+ rspec-support (~> 3.10.0)
42
+ rspec-mocks (3.10.0)
83
43
  diff-lcs (>= 1.2.0, < 2.0)
84
- rspec-support (~> 3.7.0)
85
- rspec-support (3.7.1)
86
- timers (4.1.2)
87
- hitimes
44
+ rspec-support (~> 3.10.0)
45
+ rspec-support (3.10.0)
46
+ rubocop (1.2.0)
47
+ parallel (~> 1.10)
48
+ parser (>= 2.7.1.5)
49
+ rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 1.8)
51
+ rexml
52
+ rubocop-ast (>= 1.0.1)
53
+ ruby-progressbar (~> 1.7)
54
+ unicode-display_width (>= 1.4.0, < 2.0)
55
+ rubocop-ast (1.1.1)
56
+ parser (>= 2.7.1.5)
57
+ ruby-progressbar (1.10.1)
58
+ ruby2_keywords (0.0.2)
59
+ unicode-display_width (1.7.0)
60
+ websocket (1.2.8)
61
+ websocket-client-simple (0.3.0)
62
+ event_emitter
63
+ websocket
88
64
 
89
65
  PLATFORMS
90
66
  ruby
91
67
 
92
68
  DEPENDENCIES
93
69
  bitflyer!
94
- bundler (~> 1.12)
70
+ bundler (~> 2.0)
71
+ pry
95
72
  rake
96
73
  rspec
74
+ rubocop
97
75
 
98
76
  BUNDLED WITH
99
- 1.15.4
77
+ 2.0.2
data/README.md CHANGED
@@ -2,8 +2,9 @@
2
2
  [![Gem Version](https://badge.fury.io/rb/bitflyer.svg)](https://badge.fury.io/rb/bitflyer)
3
3
  [![Circle CI](https://circleci.com/gh/unhappychoice/bitflyer.svg?style=shield)](https://circleci.com/gh/unhappychoice/bitflyer)
4
4
  [![Code Climate](https://codeclimate.com/github/unhappychoice/bitflyer/badges/gpa.svg)](https://codeclimate.com/github/unhappychoice/bitflyer)
5
- [![Dependency Status](https://gemnasium.com/badges/github.com/unhappychoice/bitflyer.svg)](https://gemnasium.com/github.com/unhappychoice/bitflyer)
5
+ [![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/unhappychoice/bitflyer.svg)](https://libraries.io/github/unhappychoice/bitflyer)
6
6
  ![](http://ruby-gem-downloads-badge.herokuapp.com/bitflyer?type=total)
7
+ ![GitHub](https://img.shields.io/github/license/unhappychoice/bitflyer.svg)
7
8
 
8
9
  bitflyer is a wrapper interface of [Bitflyer lightning API](https://lightning.bitflyer.jp/docs)
9
10
 
@@ -19,6 +20,8 @@ See https://lightning.bitflyer.jp/docs for details.
19
20
 
20
21
  ### HTTP API
21
22
 
23
+ See [public.rb](./lib/bitflyer/http/public.rb) / [private.rb](./lib/bitflyer/http/private.rb) for method definition.
24
+
22
25
  #### Example
23
26
 
24
27
  ```ruby
@@ -34,17 +37,7 @@ p private_client.positions # will print your positions
34
37
  Accessor format is like `{event_name}_{product_code}`.
35
38
  You can set lambda to get realtime events.
36
39
 
37
- #### `event_name`
38
- - board_snapshot
39
- - board
40
- - ticker
41
- - executions
42
-
43
- #### `product_code`
44
- - btc_jpy
45
- - fx_btc_jpy
46
- - eth_btc
47
- - bch_btc
40
+ `{event_name}` and `{product_code}` is defined at [client.rb](./lib/bitflyer/realtime/client.rb).
48
41
 
49
42
  #### Example
50
43
 
@@ -17,10 +17,12 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_dependency 'faraday', '~> 0.14.0'
21
- spec.add_dependency 'faraday_middleware', '~> 0.12.0'
22
- spec.add_dependency 'pubnub', '~> 4.0.22'
23
- spec.add_development_dependency 'bundler', '~> 1.12'
20
+ spec.add_dependency 'faraday', '>= 0.14', '< 1.2'
21
+ spec.add_dependency 'faraday_middleware', '>= 0.12', '< 1.1'
22
+ spec.add_dependency 'websocket-client-simple', '~> 0.3.0'
23
+ spec.add_development_dependency 'bundler', '~> 2.0'
24
+ spec.add_development_dependency 'pry'
24
25
  spec.add_development_dependency 'rake'
25
26
  spec.add_development_dependency 'rspec'
27
+ spec.add_development_dependency 'rubocop'
26
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bitflyer/version'
2
4
  require 'bitflyer/http'
3
5
  require 'bitflyer/realtime'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bitflyer'
2
4
  require 'bitflyer/http/public'
3
5
  require 'bitflyer/http/private'
@@ -13,7 +15,7 @@ module Bitflyer
13
15
  def_delegators :@connection, :get, :post
14
16
 
15
17
  def initialize(key, secret)
16
- @connection = Faraday::Connection.new(:url => 'https://api.bitflyer.jp') do |f|
18
+ @connection = Faraday::Connection.new(url: 'https://api.bitflyer.jp') do |f|
17
19
  f.request :json
18
20
  f.response :json
19
21
  f.use Authentication, key, secret
@@ -34,9 +36,9 @@ module Bitflyer
34
36
 
35
37
  timestamp = Time.now.to_i.to_s
36
38
  method = env[:method].to_s.upcase
37
- path = env[:url].path + (env[:url].query ? '?' + env[:url].query : '')
39
+ path = env[:url].path + (env[:url].query ? "?#{env[:url].query}" : '')
38
40
  body = env[:body] || ''
39
- signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, timestamp + method + path + body)
41
+ signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, timestamp + method + path + body)
40
42
  env[:request_headers]['ACCESS-KEY'] = @key if @key
41
43
  env[:request_headers]['ACCESS-TIMESTAMP'] = timestamp
42
44
  env[:request_headers]['ACCESS-SIGN'] = signature
@@ -44,4 +46,4 @@ module Bitflyer
44
46
  end
45
47
  end
46
48
  end
47
- end
49
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bitflyer
2
4
  module HTTP
3
5
  module Private
@@ -40,10 +42,10 @@ module Bitflyer
40
42
 
41
43
  def withdraw(currency_code: 'JPY', bank_account_id: nil, amount: nil, code: nil)
42
44
  body = {
43
- currency_code: currency_code,
44
- bank_account_id: bank_account_id,
45
- amount: amount,
46
- code: code
45
+ currency_code: currency_code,
46
+ bank_account_id: bank_account_id,
47
+ amount: amount,
48
+ code: code
47
49
  }.delete_if { |_, v| v.nil? }
48
50
  @connection.post('/v1/me/withdraw', body).body
49
51
  end
@@ -52,102 +54,124 @@ module Bitflyer
52
54
  @connection.get('/v1/me/getwithdrawals').body
53
55
  end
54
56
 
55
- def send_child_order(product_code: 'BTC_JPY', child_order_type: nil, side: nil, price: nil, size: nil, minute_to_expire: nil, time_in_force: 'GTC')
57
+ def send_child_order(
58
+ product_code: 'BTC_JPY',
59
+ child_order_type: nil,
60
+ side: nil,
61
+ price: nil,
62
+ size: nil,
63
+ minute_to_expire: nil,
64
+ time_in_force: 'GTC'
65
+ )
56
66
  body = {
57
- product_code: product_code,
58
- child_order_type: child_order_type,
59
- side: side,
60
- price: price,
61
- size: size,
62
- minute_to_expire: minute_to_expire,
63
- time_in_force: time_in_force
67
+ product_code: product_code,
68
+ child_order_type: child_order_type,
69
+ side: side,
70
+ price: price,
71
+ size: size,
72
+ minute_to_expire: minute_to_expire,
73
+ time_in_force: time_in_force
64
74
  }.delete_if { |_, v| v.nil? }
65
75
  @connection.post('/v1/me/sendchildorder', body).body
66
76
  end
67
77
 
68
78
  def cancel_child_order(product_code: 'BTC_JPY', child_order_id: nil, child_order_acceptance_id: nil)
69
79
  body = {
70
- product_code: product_code,
71
- child_order_id: child_order_id,
72
- child_order_acceptance_id: child_order_acceptance_id
80
+ product_code: product_code,
81
+ child_order_id: child_order_id,
82
+ child_order_acceptance_id: child_order_acceptance_id
73
83
  }.delete_if { |_, v| v.nil? }
74
84
  @connection.post('/v1/me/cancelchildorder', body).body
75
85
  end
76
86
 
77
87
  def send_parent_order(order_method: nil, minute_to_expire: nil, time_in_force: 'GTC', parameters: {})
78
88
  body = {
79
- order_method: order_method,
80
- minute_to_expire: minute_to_expire,
81
- time_in_force: time_in_force,
82
- parameters: parameters
89
+ order_method: order_method,
90
+ minute_to_expire: minute_to_expire,
91
+ time_in_force: time_in_force,
92
+ parameters: parameters
83
93
  }.delete_if { |_, v| v.nil? }
84
94
  @connection.post('/v1/me/sendparentorder', body).body
85
95
  end
86
96
 
87
97
  def cancel_parent_order(product_code: 'BTC_JPY', parent_order_id: nil, parent_order_acceptance_id: nil)
88
98
  body = {
89
- product_code: product_code,
90
- parent_order_id: parent_order_id,
91
- parent_order_acceptance_id: parent_order_acceptance_id
99
+ product_code: product_code,
100
+ parent_order_id: parent_order_id,
101
+ parent_order_acceptance_id: parent_order_acceptance_id
92
102
  }.delete_if { |_, v| v.nil? }
93
103
  @connection.post('/v1/me/cancelparentorder', body).body
94
104
  end
95
105
 
96
106
  def cancel_all_child_orders(product_code: 'BTC_JPY')
97
- @connection.post('/v1/me/cancelallchildorders', { product_code: product_code }).body
107
+ @connection.post('/v1/me/cancelallchildorders', product_code: product_code).body
98
108
  end
99
109
 
100
- def child_orders(product_code: 'BTC_JPY', count: nil, before: nil, after: nil, child_order_state: nil, parent_order_id: nil)
110
+ def child_orders(
111
+ product_code: 'BTC_JPY',
112
+ count: nil,
113
+ before: nil,
114
+ after: nil,
115
+ child_order_state: nil,
116
+ parent_order_id: nil
117
+ )
101
118
  query = {
102
- product_code: product_code,
103
- count: count,
104
- before: before,
105
- after: after,
106
- child_order_state: child_order_state,
107
- parent_order_id: parent_order_id
119
+ product_code: product_code,
120
+ count: count,
121
+ before: before,
122
+ after: after,
123
+ child_order_state: child_order_state,
124
+ parent_order_id: parent_order_id
108
125
  }.delete_if { |_, v| v.nil? }
109
126
  @connection.get('/v1/me/getchildorders', query).body
110
127
  end
111
128
 
112
129
  def parent_orders(product_code: 'BTC_JPY', count: nil, before: nil, after: nil, parent_order_state: nil)
113
130
  query = {
114
- product_code: product_code,
115
- count: count,
116
- before: before,
117
- after: after,
118
- parent_order_state: parent_order_state
131
+ product_code: product_code,
132
+ count: count,
133
+ before: before,
134
+ after: after,
135
+ parent_order_state: parent_order_state
119
136
  }.delete_if { |_, v| v.nil? }
120
137
  @connection.get('/v1/me/getparentorders', query).body
121
138
  end
122
139
 
123
140
  def parent_order(parent_order_id: nil, parent_order_acceptance_id: nil)
124
141
  query = {
125
- parent_order_id: parent_order_id,
126
- parent_order_acceptance_id: parent_order_acceptance_id
142
+ parent_order_id: parent_order_id,
143
+ parent_order_acceptance_id: parent_order_acceptance_id
127
144
  }.delete_if { |_, v| v.nil? }
128
145
  @connection.get('/v1/me/getparentorder', query).body
129
146
  end
130
147
 
131
- def executions(product_code: 'BTC_JPY', count: nil, before: nil, after: nil, child_order_id: nil, child_order_acceptance_id: nil)
148
+ def executions(
149
+ product_code: 'BTC_JPY',
150
+ count: nil,
151
+ before: nil,
152
+ after: nil,
153
+ child_order_id: nil,
154
+ child_order_acceptance_id: nil
155
+ )
132
156
  query = {
133
- product_code: product_code,
134
- count: count,
135
- before: before,
136
- after: after,
137
- child_order_id: child_order_id,
138
- child_order_acceptance_id: child_order_acceptance_id,
157
+ product_code: product_code,
158
+ count: count,
159
+ before: before,
160
+ after: after,
161
+ child_order_id: child_order_id,
162
+ child_order_acceptance_id: child_order_acceptance_id
139
163
  }.delete_if { |_, v| v.nil? }
140
164
  @connection.get('/v1/me/getexecutions', query).body
141
165
  end
142
166
 
143
167
  def positions(product_code: 'FX_BTC_JPY')
144
- @connection.get('/v1/me/getpositions', { product_code: product_code }).body
168
+ @connection.get('/v1/me/getpositions', product_code: product_code).body
145
169
  end
146
170
 
147
171
  def trading_commission(product_code: 'BTC_JPY')
148
- @connection.get('v1/me/gettradingcommission', { product_code: product_code }).body
172
+ @connection.get('v1/me/gettradingcommission', product_code: product_code).body
149
173
  end
150
174
  end
151
175
  end
152
176
  end
153
- end
177
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bitflyer
2
4
  module HTTP
3
5
  module Public
@@ -14,22 +16,22 @@ module Bitflyer
14
16
  @connection.get('/v1/markets').body
15
17
  end
16
18
 
17
- def board(product_code = 'BTC_JPY')
18
- @connection.get('/v1/board', { product_code: product_code }).body
19
+ def board(product_code: 'BTC_JPY')
20
+ @connection.get('/v1/board', product_code: product_code).body
19
21
  end
20
22
 
21
- def ticker(product_code = 'BTC_JPY')
22
- @connection.get('/v1/ticker', { product_code: product_code }).body
23
+ def ticker(product_code: 'BTC_JPY')
24
+ @connection.get('/v1/ticker', product_code: product_code).body
23
25
  end
24
26
 
25
- def executions(product_code = 'BTC_JPY')
26
- @connection.get('/v1/executions', { product_code: product_code }).body
27
+ def executions(product_code: 'BTC_JPY')
28
+ @connection.get('/v1/executions', product_code: product_code).body
27
29
  end
28
30
 
29
- def chats(from_date = (Time.now - 5 * 24 * 60 * 60))
30
- @connection.get('/v1/getchats', { from_date: from_date }).body
31
+ def chats(from_date: (Time.now - 5 * 24 * 60 * 60))
32
+ @connection.get('/v1/getchats', from_date: from_date).body
31
33
  end
32
34
  end
33
35
  end
34
36
  end
35
- end
37
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bitflyer'
2
4
  require 'bitflyer/realtime/client'
3
5
 
4
6
  module Bitflyer
5
7
  module Realtime
6
8
  end
7
- end
9
+ end
@@ -1,46 +1,27 @@
1
- require 'pubnub'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './websocket'
2
4
 
3
5
  module Bitflyer
4
6
  module Realtime
5
- PUBNUB_SUBSCRIBE_KEY = 'sub-c-52a9ab50-291b-11e5-baaa-0619f8945a4f'.freeze
6
- CHANNEL_NAMES = [
7
- 'lightning_board_snapshot_BTC_JPY',
8
- 'lightning_board_snapshot_FX_BTC_JPY',
9
- 'lightning_board_snapshot_ETH_BTC',
10
- 'lightning_board_snapshot_BCH_BTC',
11
- 'lightning_board_BTC_JPY',
12
- 'lightning_board_FX_BTC_JPY',
13
- 'lightning_board_ETH_BTC',
14
- 'lightning_board_BCH_BTC',
15
- 'lightning_ticker_BTC_JPY',
16
- 'lightning_ticker_FX_BTC_JPY',
17
- 'lightning_ticker_ETH_BTC',
18
- 'lightning_ticker_BCH_BTC',
19
- 'lightning_executions_BTC_JPY',
20
- 'lightning_executions_FX_BTC_JPY',
21
- 'lightning_executions_ETH_BTC',
22
- 'lightning_executions_BCH_BTC'
23
- ].freeze
7
+ EVENT_NAMES = %w[lightning_board_snapshot lightning_board lightning_ticker lightning_executions].freeze
8
+ MARKETS = %w[BTC_JPY FX_BTC_JPY ETH_BTC BCH_BTC BTCJPY_MAT3M BTCJPY_MAT1WK BTCJPY_MAT2WK].freeze
9
+ CHANNEL_NAMES = EVENT_NAMES.product(MARKETS).map { |e, m| "#{e}_#{m}" }
24
10
 
25
- class Client
26
- attr_accessor *Realtime::CHANNEL_NAMES.map { |name| name.gsub('lightning_', '').downcase.to_sym }
11
+ SOCKET_HOST = 'https://io.lightstream.bitflyer.com'
27
12
 
28
- def initialize
29
- @pubnub = Pubnub.new(subscribe_key: Realtime::PUBNUB_SUBSCRIBE_KEY)
13
+ class Client
14
+ attr_accessor :websocket_client, :ping_interval, :ping_timeout, :last_ping_at, :last_pong_at
30
15
 
31
- @callback = Pubnub::SubscribeCallback.new(
32
- message: ->(envelope) {
33
- channel_name = envelope.result[:data][:subscribed_channel].gsub('lightning_', '').downcase.to_sym
34
- message = envelope.result[:data][:message]
35
- send(channel_name).call(message) if send(channel_name)
36
- },
37
- presence: ->(envelope) {},
38
- status: ->(envelope) {}
39
- )
16
+ Realtime::CHANNEL_NAMES.each do |channel_name|
17
+ define_method "#{channel_name.gsub('lightning_', '').downcase.to_sym}=" do |callback|
18
+ @websocket_client.subscribe(channel_name: channel_name.to_sym, &callback)
19
+ end
20
+ end
40
21
 
41
- @pubnub.add_listener(callback: @callback)
42
- @pubnub.subscribe(channels: Realtime::CHANNEL_NAMES)
22
+ def initialize
23
+ @websocket_client = Bitflyer::Realtime::WebSocketClient.new(host: SOCKET_HOST)
43
24
  end
44
25
  end
45
26
  end
46
- end
27
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'websocket-client-simple'
4
+ require 'json'
5
+
6
+ module Bitflyer
7
+ module Realtime
8
+ class WebSocketClient
9
+ attr_accessor :websocket_client, :channel_name, :channel_callbacks, :ping_interval, :ping_timeout,
10
+ :last_ping_at, :last_pong_at, :error
11
+
12
+ def initialize(host:, debug: false)
13
+ @host = host
14
+ @debug = debug
15
+ @error = nil
16
+ @channel_names = []
17
+ @channel_callbacks = {}
18
+ connect
19
+ end
20
+
21
+ def subscribe(channel_name:, &block)
22
+ debug_log "Subscribe #{channel_name}"
23
+ @channel_names = (@channel_names + [channel_name]).uniq
24
+ @channel_callbacks[channel_name] = block
25
+ websocket_client.send "42#{['subscribe', channel_name].to_json}"
26
+ end
27
+
28
+ def connect
29
+ @websocket_client = WebSocket::Client::Simple.connect "#{@host}/socket.io/?transport=websocket"
30
+ this = self
31
+
32
+ Thread.new do
33
+ loop do
34
+ sleep 1
35
+ if @websocket_client&.open?
36
+ send_ping
37
+ wait_pong
38
+ end
39
+ end
40
+ end
41
+
42
+ Thread.new do
43
+ loop do
44
+ sleep 1
45
+ next unless @error
46
+
47
+ reconnect
48
+ end
49
+ end
50
+
51
+ @websocket_client.on(:message) { |payload| this.handle_message(payload: payload) }
52
+ @websocket_client.on(:error) { |error| this.handle_error(error: error) }
53
+ end
54
+
55
+ def send_ping
56
+ return unless @last_ping_at && @ping_interval
57
+ return unless Time.now.to_i - @last_ping_at > @ping_interval / 1000
58
+
59
+ debug_log 'Sent ping'
60
+ @websocket_client.send '2'
61
+ @last_ping_at = Time.now.to_i
62
+ end
63
+
64
+ def wait_pong
65
+ return unless @last_pong_at && @ping_timeout
66
+ return unless Time.now.to_i - @last_pong_at > (@ping_interval + @ping_timeout) / 1000
67
+
68
+ debug_log 'Timed out waiting pong'
69
+ @websocket_client.close
70
+ end
71
+
72
+ def reconnect
73
+ return unless @error
74
+
75
+ debug_log 'Reconnecting...'
76
+
77
+ @error = nil
78
+ @websocket_client.close if @websocket_client.open?
79
+ connect
80
+ @channel_names.each do |channel_name|
81
+ debug_log "42#{{ subscribe: channel_name }.to_json}"
82
+ websocket_client.send "42#{['subscribe', channel_name].to_json}"
83
+ end
84
+ end
85
+
86
+ def handle_error(error:)
87
+ debug_log error
88
+ return unless error.is_a? Errno::ECONNRESET
89
+
90
+ reconnect
91
+ end
92
+
93
+ def handle_message(payload:)
94
+ debug_log payload.data
95
+ return unless payload.data =~ /^\d+/
96
+
97
+ code, body = payload.data.scan(/^(\d+)(.*)$/)[0]
98
+
99
+ case code.to_i
100
+ when 0 then setup_by_response(json: body)
101
+ when 3 then receive_pong
102
+ when 41 then disconnect
103
+ when 42 then emit_message(json: body)
104
+ end
105
+ rescue StandardError => e
106
+ puts e
107
+ puts e.backtrace.join("\n")
108
+ end
109
+
110
+ def setup_by_response(json:)
111
+ body = JSON.parse json
112
+ @ping_interval = body['pingInterval'].to_i || 25_000
113
+ @ping_timeout = body['pingTimeout'].to_i || 60_000
114
+ @last_ping_at = Time.now.to_i
115
+ @last_pong_at = Time.now.to_i
116
+ channel_callbacks.each do |channel_name, _|
117
+ websocket_client.send "42#{['subscribe', channel_name].to_json}"
118
+ end
119
+ end
120
+
121
+ def receive_pong
122
+ debug_log 'Received pong'
123
+ @last_pong_at = Time.now.to_i
124
+ end
125
+
126
+ def disconnect
127
+ debug_log 'Disconnecting from server...'
128
+ @error = true
129
+ end
130
+
131
+ def emit_message(json:)
132
+ channel_name, *messages = JSON.parse json
133
+ return unless channel_name
134
+
135
+ messages.each { |message| @channel_callbacks[channel_name.to_sym]&.call(message) }
136
+ end
137
+
138
+ def debug_log(message)
139
+ return unless @debug
140
+
141
+ p message
142
+ end
143
+ end
144
+ end
145
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bitflyer
2
- VERSION = '0.2.0'
4
+ VERSION = '1.0.1'
3
5
  end
metadata CHANGED
@@ -1,71 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitflyer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Ueki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2020-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0.14'
20
+ - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: 0.14.0
22
+ version: '1.2'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 0.14.0
29
+ version: '0.14'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: faraday_middleware
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: 0.12.0
39
+ version: '0.12'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '1.1'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0.12'
50
+ - - "<"
39
51
  - !ruby/object:Gem::Version
40
- version: 0.12.0
52
+ version: '1.1'
41
53
  - !ruby/object:Gem::Dependency
42
- name: pubnub
54
+ name: websocket-client-simple
43
55
  requirement: !ruby/object:Gem::Requirement
44
56
  requirements:
45
57
  - - "~>"
46
58
  - !ruby/object:Gem::Version
47
- version: 4.0.22
59
+ version: 0.3.0
48
60
  type: :runtime
49
61
  prerelease: false
50
62
  version_requirements: !ruby/object:Gem::Requirement
51
63
  requirements:
52
64
  - - "~>"
53
65
  - !ruby/object:Gem::Version
54
- version: 4.0.22
66
+ version: 0.3.0
55
67
  - !ruby/object:Gem::Dependency
56
68
  name: bundler
57
69
  requirement: !ruby/object:Gem::Requirement
58
70
  requirements:
59
71
  - - "~>"
60
72
  - !ruby/object:Gem::Version
61
- version: '1.12'
73
+ version: '2.0'
62
74
  type: :development
63
75
  prerelease: false
64
76
  version_requirements: !ruby/object:Gem::Requirement
65
77
  requirements:
66
78
  - - "~>"
67
79
  - !ruby/object:Gem::Version
68
- version: '1.12'
80
+ version: '2.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: pry
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
69
95
  - !ruby/object:Gem::Dependency
70
96
  name: rake
71
97
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +120,20 @@ dependencies:
94
120
  - - ">="
95
121
  - !ruby/object:Gem::Version
96
122
  version: '0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rubocop
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
97
137
  description: Bitflyer API wrapper
98
138
  email:
99
139
  - unhappychoice@gmail.com
@@ -101,6 +141,9 @@ executables: []
101
141
  extensions: []
102
142
  extra_rdoc_files: []
103
143
  files:
144
+ - ".circleci/config.yml"
145
+ - ".rubocop.yml"
146
+ - ".rubocop_todo.yml"
104
147
  - CODE_OF_CONDUCT.md
105
148
  - Gemfile
106
149
  - Gemfile.lock
@@ -114,6 +157,7 @@ files:
114
157
  - lib/bitflyer/http/public.rb
115
158
  - lib/bitflyer/realtime.rb
116
159
  - lib/bitflyer/realtime/client.rb
160
+ - lib/bitflyer/realtime/websocket.rb
117
161
  - lib/bitflyer/version.rb
118
162
  homepage: https://github.com/unhappychoice/bitflyer
119
163
  licenses:
@@ -134,8 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
178
  - !ruby/object:Gem::Version
135
179
  version: '0'
136
180
  requirements: []
137
- rubyforge_project:
138
- rubygems_version: 2.6.11
181
+ rubygems_version: 3.0.3
139
182
  signing_key:
140
183
  specification_version: 4
141
184
  summary: Bitflyer API wrapper