bitflyer 0.2.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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