fcoin_ruby_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +12 -0
  3. data/.github/pull_request_template.md +12 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +12 -0
  7. data/.rubocop_todo.yml +431 -0
  8. data/.travis.yml +26 -0
  9. data/CHANGELOG.md +2 -0
  10. data/Gemfile +6 -0
  11. data/Gemfile.lock +176 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +204 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +14 -0
  16. data/bin/fcoin +95 -0
  17. data/bin/setup +8 -0
  18. data/examples/cli/realtime_api.md +78 -0
  19. data/examples/cli/rest_api.md +149 -0
  20. data/examples/cli/setting.md +39 -0
  21. data/examples/realtime_api.rb +43 -0
  22. data/examples/rest_api.rb +47 -0
  23. data/fcoin_ruby_client.gemspec +39 -0
  24. data/lib/fcoin/api.rb +47 -0
  25. data/lib/fcoin/authorization.rb +83 -0
  26. data/lib/fcoin/cli/endpoint/accounts_task.rb +33 -0
  27. data/lib/fcoin/cli/endpoint/market_task.rb +98 -0
  28. data/lib/fcoin/cli/endpoint/orders_task.rb +196 -0
  29. data/lib/fcoin/cli/endpoint/public_task.rb +59 -0
  30. data/lib/fcoin/cli/realtime/endpoint_task.rb +107 -0
  31. data/lib/fcoin/cli.rb +77 -0
  32. data/lib/fcoin/client.rb +7 -0
  33. data/lib/fcoin/config/custom_settings.yml +171 -0
  34. data/lib/fcoin/config/settings.yml +10 -0
  35. data/lib/fcoin/configuration.rb +95 -0
  36. data/lib/fcoin/connection.rb +33 -0
  37. data/lib/fcoin/endpoint/accounts.rb +23 -0
  38. data/lib/fcoin/endpoint/market.rb +91 -0
  39. data/lib/fcoin/endpoint/orders.rb +171 -0
  40. data/lib/fcoin/endpoint/public.rb +51 -0
  41. data/lib/fcoin/endpoint/utility.rb +14 -0
  42. data/lib/fcoin/endpoint.rb +13 -0
  43. data/lib/fcoin/error.rb +4 -0
  44. data/lib/fcoin/faraday/fcoin_formatter.rb +17 -0
  45. data/lib/fcoin/formatter/base_formatter.rb +8 -0
  46. data/lib/fcoin/formatter/depth_formatter.rb +33 -0
  47. data/lib/fcoin/formatter/ticker_formatter.rb +34 -0
  48. data/lib/fcoin/formatter.rb +38 -0
  49. data/lib/fcoin/generators/locale.rb +18 -0
  50. data/lib/fcoin/generators/templates/locale/locales/en.yml +176 -0
  51. data/lib/fcoin/generators/templates/locale/locales/ja.yml +176 -0
  52. data/lib/fcoin/generators/templates/locale/locales/zh_CN.yml +176 -0
  53. data/lib/fcoin/generators/templates/validation/my_settings.yml +171 -0
  54. data/lib/fcoin/generators/validation.rb +18 -0
  55. data/lib/fcoin/realtime/api.rb +38 -0
  56. data/lib/fcoin/realtime/client.rb +9 -0
  57. data/lib/fcoin/realtime/endpoint.rb +160 -0
  58. data/lib/fcoin/realtime/formatter/base_formatter.rb +10 -0
  59. data/lib/fcoin/realtime/formatter/depth_formatter.rb +37 -0
  60. data/lib/fcoin/realtime/formatter/ticker_formatter.rb +36 -0
  61. data/lib/fcoin/realtime/formatter.rb +40 -0
  62. data/lib/fcoin/realtime/wss.rb +113 -0
  63. data/lib/fcoin/request.rb +73 -0
  64. data/lib/fcoin/validator/market_validator.rb +60 -0
  65. data/lib/fcoin/validator/orders/base_validator.rb +96 -0
  66. data/lib/fcoin/validator/orders/create_order_limit_validator.rb +54 -0
  67. data/lib/fcoin/validator/orders/create_order_market_validator.rb +95 -0
  68. data/lib/fcoin/validator/orders/order_list_validator.rb +33 -0
  69. data/lib/fcoin/validator/orders_validator.rb +69 -0
  70. data/lib/fcoin/validator/validator_utility.rb +24 -0
  71. data/lib/fcoin/validator.rb +58 -0
  72. data/lib/fcoin/version.rb +3 -0
  73. data/lib/fcoin.rb +11 -0
  74. metadata +353 -0
@@ -0,0 +1,73 @@
1
+ require_relative 'authorization'
2
+ require_relative 'formatter'
3
+
4
+ # Scope Fcoin::API
5
+ module Fcoin
6
+ module Request
7
+ # Perform an HTTP GET request
8
+ def get(path, auth=true, payload={})
9
+ request(:get, path, auth, payload)
10
+ end
11
+
12
+ # Perform an HTTP POST request
13
+ def post(path, auth=true, payload={})
14
+ request(:post, path, auth, payload)
15
+ end
16
+
17
+ # Perform an HTTP PUT request
18
+ def put(path, auth=true, payload={})
19
+ request(:put, path, auth, payload)
20
+ end
21
+
22
+ # Perform an HTTP DELETE request
23
+ def delete(path, auth=true, payload={})
24
+ request(:delete, path, auth, payload)
25
+ end
26
+
27
+ private
28
+
29
+ # Perform an HTTP request
30
+ def request(http_method, path, auth, payload)
31
+ response = connection.send(http_method) do |request|
32
+ required = {
33
+ http_method: http_method,
34
+ path: path,
35
+ payload: payload,
36
+ endpoint: endpoint,
37
+ api_key: api_key,
38
+ secret_key: secret_key
39
+ }
40
+
41
+ if auth
42
+ auth = Fcoin::Authorization.new(required)
43
+ request.headers.merge!(auth.original_headers)
44
+ end
45
+
46
+ case http_method
47
+ when :get, :delete
48
+ request.url(path, payload)
49
+ when :post, :put
50
+ request.path = path
51
+ request.body = payload unless payload.empty?
52
+ end
53
+ end
54
+
55
+ return formatted(response.body)
56
+ end
57
+
58
+ # change the output format of the body
59
+ #
60
+ # @param body [Hash]
61
+ # @return [Hash or JSON]
62
+ def formatted(body)
63
+ case format_type
64
+ when :json
65
+ body.to_json
66
+ when :hash
67
+ body
68
+ else
69
+ raise "format_type is #{format_type}. format_type must be included in [:json, :hash]."
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,60 @@
1
+ require_relative 'validator_utility'
2
+
3
+ module Fcoin
4
+ class MarketValidator
5
+ include ValidatorUtility
6
+
7
+ # @params params [Hash] Parameter you want to verify including the called method name
8
+ # @option params :level [String or Symbol] Level of depth chart
9
+ # @option params :resolution [String or Symbol] period of Candles Chart
10
+ # @option params :method_name [String or Symbol] invoked method name
11
+ def initialize(params)
12
+ self.level = params[:level]
13
+ self.resolution = params[:resolution]
14
+ self.method_name = params[:method_name]
15
+ end
16
+
17
+ # Validate according to method_name
18
+ def valid?
19
+ case method_name
20
+ when /market_depth|on_depth/
21
+ valid_level?
22
+ when /market_candles|on_candle/
23
+ valid_resolution?
24
+ end
25
+ end
26
+
27
+ # Error message when invalid
28
+ def messages
29
+ return {} if valid?
30
+ results = []
31
+ case method_name
32
+ when /market_depth|on_depth/
33
+ results << includes_error_message(level, :level, valid_levels) unless valid_level?
34
+ when /market_candles|on_candle/
35
+ results << includes_error_message(resolution, :resolution, valid_resolutions) unless valid_resolution?
36
+ end
37
+ results.compact&.each_with_object({}) { |message, data| data.merge!(message) }
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :level, :resolution, :method_name
43
+
44
+ def valid_level?
45
+ level.to_s.in? valid_levels
46
+ end
47
+
48
+ def valid_resolution?
49
+ resolution.to_s.in? valid_resolutions
50
+ end
51
+
52
+ def valid_levels
53
+ ::Settings.fcoin.validation.params.level
54
+ end
55
+
56
+ def valid_resolutions
57
+ ::Settings.fcoin.validation.params.resolution
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,96 @@
1
+ module Fcoin
2
+ module Orders
3
+ class BaseValidator
4
+
5
+ # @param params [Hash] Parameter you want to verify including the called method name
6
+ # @option params :symbol [String or Symbol] Transaction pair
7
+ # @option params :side [String or Symbol] Direction of the transaction
8
+ # @option params :price [Float]
9
+ # @option params :total [Float]
10
+ # @option params :amount [Float]
11
+ # @option params :states [String] Order state
12
+ def initialize(params)
13
+ self.symbol = params[:symbol]
14
+ self.side = params[:side]
15
+ self.price = params[:price]
16
+ self.total = params[:total]
17
+ self.amount = params[:amount]
18
+ self.states = params[:states]
19
+ end
20
+
21
+ # Validate according to method_name
22
+ # @abstract Subclass and override {#valid?} to implement
23
+ def valid?
24
+ raise 'Please be implemented in inheriting.'
25
+ end
26
+
27
+ # Error message when invalid
28
+ # @abstract Subclass and override {#messages} to implement
29
+ def messages
30
+ raise 'Please be implemented in inheriting.'
31
+ end
32
+
33
+ private
34
+
35
+ attr_accessor :symbol, :side, :type, :price, :total, :amount, :states
36
+
37
+ def valid_symbol?
38
+ symbol.present?
39
+ end
40
+
41
+ def valid_side?
42
+ side.to_s.in? valid_sides
43
+ end
44
+
45
+ def valid_type?
46
+ type.to_s.in? valid_types
47
+ end
48
+
49
+ def valid_states?
50
+ states_arr = states.to_s.gsub(' ','')&.split(',')
51
+ states_arr.present? && states_arr.map { |state| state.in? valid_states }.all?
52
+ end
53
+
54
+ def valid_price?
55
+ price.present? && price.between?(min(:price), max(:price))
56
+ end
57
+
58
+ def valid_total?
59
+ total.present? && total.between?(min(:total), max(:total))
60
+ end
61
+
62
+ def valid_amount?
63
+ amount.present? && amount.between?(min(:amount), max(:amount))
64
+ end
65
+
66
+ def min(type)
67
+ valid_symbol_setting_exist? ? valid_symbols[symbol][type].to_h[:min] : 0
68
+ end
69
+
70
+ def max(type)
71
+ valid_symbol_setting_exist? ? valid_symbols[symbol][type].to_h[:max] : 0
72
+ end
73
+
74
+ def valid_symbol_setting_exist?
75
+ valid_symbols[symbol].present?
76
+ end
77
+
78
+ def valid_sides
79
+ ::Settings.fcoin.validation.params.side
80
+ end
81
+
82
+ def valid_types
83
+ ::Settings.fcoin.validation.params.type
84
+ end
85
+
86
+ def valid_states
87
+ ::Settings.fcoin.validation.params.states
88
+ end
89
+
90
+ # @abstract Subclass and override {#valid_symbols} to implement
91
+ def valid_symbols
92
+ raise 'Please be implemented in inheriting.'
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'base_validator'
2
+ require_relative '../validator_utility'
3
+
4
+ module Fcoin
5
+ module Orders
6
+ class CreateOrderLimitValidator < BaseValidator
7
+ include ValidatorUtility
8
+
9
+ # @param params [Hash] Parameter you want to verify including the called method name
10
+ # @option params :symbol [String or Symbol] Transaction pair
11
+ # @option params :side [String or Symbol] Direction of the transaction
12
+ # @option params :price [Float]
13
+ # @option params :amount [Float]
14
+ def initialize(params)
15
+ self.symbol = params[:symbol]
16
+ self.side = params[:side]
17
+ self.price = params[:price]
18
+ self.amount = params[:amount]
19
+ end
20
+
21
+ # Validate according to method_name
22
+ def valid?
23
+ if valid_symbol_setting_exist?
24
+ valid_price? && valid_amount?
25
+ else
26
+ valid_symbol? && valid_side?
27
+ end
28
+ end
29
+
30
+ # Error message when invalid
31
+ def messages
32
+ return {} if valid?
33
+ results = []
34
+
35
+ results << presence_error_message(symbol, :symbol) unless valid_symbol?
36
+ results << includes_error_message(side, :side, valid_sides) unless valid_side?
37
+ if valid_symbol_setting_exist?
38
+ results << between_error_message(price, :price, min(:price), max(:price)) unless valid_price?
39
+ results << between_error_message(amount, :amount, min(:amount), max(:amount)) unless valid_amount?
40
+ end
41
+ results.compact&.each_with_object({}) { |message, data| data.merge!(message) }
42
+ end
43
+
44
+ private
45
+
46
+ def valid_symbols
47
+ return HashWithIndifferentAccess.new unless valid_side?
48
+ ::Settings.fcoin.validation.limit[side].to_h.values.flatten.compact.each_with_object(HashWithIndifferentAccess.new) do |setting, data|
49
+ data[setting.symbol] = setting
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,95 @@
1
+ require_relative 'base_validator'
2
+ require_relative '../validator_utility'
3
+
4
+ module Fcoin
5
+ module Orders
6
+ class CreateOrderMarketValidator < BaseValidator
7
+ include ValidatorUtility
8
+
9
+ # @param params [Hash] Parameter you want to verify including the called method name
10
+ # @option params :symbol [String or Symbol] Transaction pair
11
+ # @option params :side [String or Symbol] Direction of the transaction
12
+ # @option params :total [Float]
13
+ # @option params :amount [Float]
14
+ def initialize(params)
15
+ self.symbol = params[:symbol]
16
+ self.side = params[:side]
17
+ self.total = params[:amount] # this is not a mistake
18
+ self.amount = params[:amount]
19
+ end
20
+
21
+ # Validate according to method_name
22
+ def valid?
23
+ case
24
+ when valid_symbol_setting_exist?
25
+ case
26
+ when sell?
27
+ valid_amount?
28
+ when buy?
29
+ valid_total?
30
+ end
31
+ when invalid_symbol_setting_exist?
32
+ false
33
+ else
34
+ valid_symbol? && valid_side?
35
+ end
36
+ end
37
+
38
+ # Error message when invalid
39
+ def messages
40
+ return {} if valid?
41
+ results = []
42
+ results << presence_error_message(symbol, :symbol) unless valid_symbol?
43
+ results << includes_error_message(side, :side, valid_sides) unless valid_side?
44
+
45
+ case
46
+ when valid_symbol_setting_exist?
47
+ case
48
+ when sell?
49
+ results << between_error_message(amount, :amount, min(:amount), max(:amount)) unless valid_amount?
50
+ when buy?
51
+ results << between_error_message(total, :total, min(:total), max(:total)) unless valid_total?
52
+ end
53
+ when invalid_symbol_setting_exist?
54
+ results << invalid_create_order_market_error_message(symbol, :symbol)
55
+ end
56
+ results.compact&.each_with_object({}) { |message, data| data.merge!(message) }
57
+ end
58
+
59
+ private
60
+
61
+ def sell?
62
+ side.to_s == 'sell'
63
+ end
64
+
65
+ def buy?
66
+ side.to_s == 'buy'
67
+ end
68
+
69
+ def invalid_create_order_market_error_message(value, type)
70
+ message = {}
71
+ adjusted_value = value.present? ? value : 'nil'
72
+ message[type] = "#{type} is #{adjusted_value}. This #{type} board is not adapted on-going order."
73
+ message
74
+ end
75
+
76
+ def invalid_symbol_setting_exist?
77
+ invalid_symbols[symbol].present?
78
+ end
79
+
80
+ def valid_symbols
81
+ return HashWithIndifferentAccess.new unless valid_side?
82
+ ::Settings.fcoin.validation.market.valid[side].to_h.values.flatten.compact.each_with_object(HashWithIndifferentAccess.new) do |setting, data|
83
+ data[setting.symbol] = setting
84
+ end
85
+ end
86
+
87
+ def invalid_symbols
88
+ return HashWithIndifferentAccess.new unless valid_side?
89
+ ::Settings.fcoin.validation.market.invalid[side].to_h.values.flatten.compact.each_with_object(HashWithIndifferentAccess.new) do |setting, data|
90
+ data[setting] = setting
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'base_validator'
2
+ require_relative '../validator_utility'
3
+
4
+ module Fcoin
5
+ module Orders
6
+ class OrderListValidator < BaseValidator
7
+ include ValidatorUtility
8
+
9
+ # @param params [Hash] Parameter you want to verify including the called method name
10
+ # @option params :symbol [String or Symbol] Transaction pair
11
+ # @option params :states [String] Order state
12
+ def initialize(params)
13
+ self.symbol = params[:symbol]
14
+ self.states = params[:states]
15
+ end
16
+
17
+ # Validate according to method_name
18
+ def valid?
19
+ valid_symbol? && valid_states?
20
+ end
21
+
22
+ # Error message when invalid
23
+ def messages
24
+ return {} if valid?
25
+ results = []
26
+
27
+ results << presence_error_message(symbol, :symbol) unless valid_symbol?
28
+ results << includes_error_message(states, :states, valid_states) unless valid_states?
29
+ results.compact&.each_with_object({}) { |message, data| data.merge!(message) }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,69 @@
1
+ require_relative 'orders/create_order_limit_validator'
2
+ require_relative 'orders/create_order_market_validator'
3
+ require_relative 'orders/order_list_validator'
4
+
5
+ module Fcoin
6
+ class OrdersValidator
7
+
8
+ # @param params [Hash] Parameter you want to verify including the called method name
9
+ # @option params :symbol [String or Symbol] Transaction pair
10
+ # @option params :side [String or Symbol] Direction of the transaction
11
+ # @option params :type [String or Symbol] Order type
12
+ # @option params :price [Float]
13
+ # @option params :amount [Float]
14
+ # @option params :states [String] Order state
15
+ # @option params :method_name [String or Symbol] invoked method name
16
+ def initialize(params)
17
+ self.symbol = params[:symbol]
18
+ self.side = params[:side]
19
+ self.type = params[:type]
20
+ self.price = params[:price]
21
+ self.amount = params[:amount]
22
+ self.total = params[:total]
23
+ self.states = params[:states]
24
+ self.method_name = params[:method_name]
25
+ end
26
+
27
+ # Validate according to method_name
28
+ def valid?
29
+ validator.present? ? validator.valid? : false
30
+ end
31
+
32
+ # Error message when invalid
33
+ def messages
34
+ return {} if valid?
35
+ results = []
36
+ results << (validator.present? ? validator.messages : {})
37
+ results.compact&.each_with_object({}) { |message, data| data.merge!(message) }
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :symbol, :side, :type, :price, :total, :amount, :states, :method_name
43
+
44
+ def validator
45
+ case method_name.to_sym
46
+ when :create_order_limit
47
+ create_order_limit_validator
48
+ when :create_order_market
49
+ create_order_market_validator
50
+ when :order_list
51
+ order_list_validator
52
+ else
53
+ nil
54
+ end
55
+ end
56
+
57
+ def create_order_limit_validator
58
+ @create_order_limit_validator ||= Orders::CreateOrderLimitValidator.new(symbol: symbol, side: side, price: price, amount: amount)
59
+ end
60
+
61
+ def create_order_market_validator
62
+ @create_order_market_validator ||= Orders::CreateOrderMarketValidator.new(symbol: symbol, side: side, total: total, amount: amount)
63
+ end
64
+
65
+ def order_list_validator
66
+ @order_list_validator ||= Orders::OrderListValidator.new(symbol: symbol, states: states)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,24 @@
1
+ module Fcoin
2
+ module ValidatorUtility
3
+ def includes_error_message(target, target_type, list)
4
+ message = {}
5
+ target_value = target.present? ? target : 'nil'
6
+ message[target_type] = "#{target_type} is #{target_value}. #{target_type} is not included in the [#{list.join(', ')}]."
7
+ message
8
+ end
9
+
10
+ def between_error_message(target, target_type, min, max)
11
+ message = {}
12
+ target_value = target.present? ? target : 'nil'
13
+ message[target_type] = "#{target_type} is #{target_value}. #{target_type} is not between #{min} and #{max}."
14
+ message
15
+ end
16
+
17
+ def presence_error_message(target, target_type)
18
+ message = {}
19
+ target_value = target.present? ? target : 'nil'
20
+ message[target_type] = "#{target_type} is #{target_value}. #{target_type} can't be blank"
21
+ message
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'validator/market_validator'
2
+ require_relative 'validator/orders_validator'
3
+
4
+ # Scope Fcoin::API
5
+ module Fcoin
6
+ class Validator
7
+ # @param params [Hash] Parameter you want to verify including the called method name
8
+ # @option params :level [String or Symbol] Level of depth chart
9
+ # @option params :resolution [String or Symbol] period of Candles Chart
10
+ # @option params :symbol [String or Symbol] Transaction pair
11
+ # @option params :side [String or Symbol] Direction of the transaction
12
+ # @option params :type [String or Symbol] Order type
13
+ # @option params :price [Float]
14
+ # @option params :amount [Float]
15
+ # @option params :states [String] Order state
16
+ # @option params :method_name [String or Symbol] invoked method name
17
+ def initialize(params)
18
+ self.level = params[:level]
19
+ self.resolution = params[:resolution]
20
+ self.symbol = params[:symbol]
21
+ self.side = params[:side]
22
+ self.type = params[:type]
23
+ self.price = params[:price]
24
+ self.amount = params[:amount]
25
+ self.states = params[:states]
26
+ self.method_name = params[:method_name]
27
+ end
28
+
29
+ # Whether the parameters are valid?
30
+ def valid?
31
+ validator.present? ? validator.valid? : true
32
+ end
33
+
34
+ # Error message when invalid
35
+ def messages
36
+ validator.present? ? validator.messages : {}
37
+ end
38
+
39
+ private
40
+
41
+ def validator
42
+ case method_name
43
+ when /market_depth|on_depth/
44
+ MarketValidator.new(level: level, method_name: method_name)
45
+ when /market_candles|on_candle/
46
+ MarketValidator.new(resolution: resolution, method_name: method_name)
47
+ when /create_order/
48
+ OrdersValidator.new(symbol: symbol, side: side, type: type, price: price, amount: amount, method_name: method_name)
49
+ when /order_list/
50
+ OrdersValidator.new(symbol: symbol, states: states, method_name: method_name)
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ attr_accessor :level, :resolution, :symbol, :side, :type, :price, :amount, :states, :method_name
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module Fcoin
2
+ VERSION = "0.1.0"
3
+ end
data/lib/fcoin.rb ADDED
@@ -0,0 +1,11 @@
1
+ require_relative "fcoin/version"
2
+ require_relative "fcoin/configuration"
3
+ require_relative "fcoin/client"
4
+ require_relative "fcoin/realtime/client"
5
+ require_relative "fcoin/cli"
6
+ require_relative "fcoin/generators/validation"
7
+ require_relative "fcoin/generators/locale"
8
+
9
+ module Fcoin
10
+ extend Configuration
11
+ end