xtb 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +4 -0
- data/README.md +13 -8
- data/lib/xtb/config.rb +27 -6
- data/lib/xtb/error.rb +88 -0
- data/lib/xtb/error_factory.rb +101 -0
- data/lib/xtb/http/all_symbols.rb +1 -1
- data/lib/xtb/http/calendar.rb +1 -1
- data/lib/xtb/http/chart_last_request.rb +3 -1
- data/lib/xtb/http/chart_range_request.rb +3 -1
- data/lib/xtb/http/client.rb +49 -19
- data/lib/xtb/http/command.rb +27 -19
- data/lib/xtb/http/commission_def.rb +3 -1
- data/lib/xtb/http/current_user_data.rb +1 -1
- data/lib/xtb/http/login.rb +33 -0
- data/lib/xtb/http/logout.rb +12 -0
- data/lib/xtb/http/margin_level.rb +1 -1
- data/lib/xtb/http/margin_trade.rb +3 -1
- data/lib/xtb/http/news.rb +3 -1
- data/lib/xtb/http/ping.rb +12 -0
- data/lib/xtb/http/profit_calculation.rb +3 -1
- data/lib/xtb/http/server_time.rb +1 -1
- data/lib/xtb/http/step_rules.rb +1 -1
- data/lib/xtb/http/symbol.rb +3 -1
- data/lib/xtb/http/tick_prices.rb +3 -1
- data/lib/xtb/http/trade_records.rb +3 -1
- data/lib/xtb/http/trade_transaction.rb +5 -3
- data/lib/xtb/http/trades.rb +3 -1
- data/lib/xtb/http/trades_history.rb +3 -1
- data/lib/xtb/http/trading_hours.rb +6 -4
- data/lib/xtb/http/version.rb +1 -1
- data/lib/xtb/http.rb +5 -1
- data/lib/xtb/request_queue.rb +14 -15
- data/lib/xtb/version.rb +1 -1
- data/lib/xtb/web_socket/client.rb +1 -0
- data/lib/xtb/web_socket.rb +1 -1
- data/lib/xtb.rb +2 -1
- metadata +80 -9
- data/lib/xtb/errors.rb +0 -8
- data/lib/xtb/http/response.rb +0 -63
- data/lib/xtb/http/ssl_client.rb +0 -43
- data/sig/xtb.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d9a9468ded9f433834ca0a96a2fafa64f18b39ae8dd11fb71a6ad4b93522477
|
4
|
+
data.tar.gz: '091e39d9c4fc4e36a738f8c2e2bc6d177e13a8cee71cea3d641788f69fecaf4a'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b367e84969900e94217dfa3c982989cd02ce5e41c8bbd5928118e2f8409a2a7de433d55b441ce8da1800e0bd97c2dccfdd1bbd064b6e3fdf3ae8fc527bacb379
|
7
|
+
data.tar.gz: 8c30d8723954a1aa85e871d2884457b3675929a384999869e6f2f5a5046c85fc74dd02880bd23eeea24b2d1d0d407a39b5e81ee6713f68df6d143b38621f013d
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -6,33 +6,38 @@ This gem allows you to connect to the XTB broker and execute trades, get account
|
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
10
|
-
|
11
9
|
Install the gem and add to the application's Gemfile by executing:
|
12
10
|
|
13
|
-
$ bundle add
|
11
|
+
$ bundle add xtb
|
14
12
|
|
15
13
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
14
|
|
17
|
-
$ gem install
|
15
|
+
$ gem install xtb
|
18
16
|
|
19
17
|
## Usage
|
20
18
|
|
21
19
|
### Configuration
|
22
20
|
|
23
|
-
Before you can connect to the XTB API, you need to configure the connection.
|
24
|
-
You can do this by creating a configuration object and passing it to the client.
|
21
|
+
Before you can connect to the XTB API, you need to configure the connection.
|
25
22
|
|
26
|
-
```
|
27
|
-
|
23
|
+
```shell
|
24
|
+
XTB__USER_ID=your_user_id
|
25
|
+
XTB__PASSWORD=your_password
|
28
26
|
```
|
29
27
|
|
30
28
|
### Connect to the XTB API
|
31
29
|
|
32
30
|
```ruby
|
31
|
+
require 'xtb'
|
33
32
|
|
33
|
+
# You're ready to use the API
|
34
|
+
Xtb::Http::CurrentUserData.call
|
34
35
|
```
|
36
|
+
Note that there is no need to log in first or log out afterwards. The gem handles the connection for you.
|
37
|
+
|
38
|
+
### Subscribing to the XTB API streaming commands
|
35
39
|
|
40
|
+
🚧 The streaming API is not yet supported.
|
36
41
|
|
37
42
|
## Development
|
38
43
|
|
data/lib/xtb/config.rb
CHANGED
@@ -3,25 +3,34 @@
|
|
3
3
|
module Xtb
|
4
4
|
# Configuration mapping for XTB API.
|
5
5
|
class Config
|
6
|
+
DEFAULT_HTTP_HOST = 'xapi.xtb.com'
|
7
|
+
DEFAULT_HTTP_PORT = 5124
|
8
|
+
DEFAULT_WEB_SOCKET_HOST = 'ws.xtb.com'
|
9
|
+
DEFAULT_WEB_SOCKET_PORT = 5125
|
10
|
+
DEFAULT_WEB_SOCKET_PATH = 'demo'
|
11
|
+
DEFAULT_CONNECTION_POOL_SIZE = 5
|
12
|
+
MAX_CONNECTION_POOL_SIZE = 50
|
13
|
+
MIN_REQUEST_INTERVAL = 200 # in milliseconds
|
14
|
+
|
6
15
|
class << self
|
7
16
|
def https_host
|
8
|
-
ENV.fetch('XTB__HTTPS_HOST',
|
17
|
+
ENV.fetch('XTB__HTTPS_HOST', DEFAULT_HTTP_HOST)
|
9
18
|
end
|
10
19
|
|
11
20
|
def https_port
|
12
|
-
ENV.fetch('XTB__HTTPS_PORT',
|
21
|
+
ENV.fetch('XTB__HTTPS_PORT', DEFAULT_HTTP_PORT).to_i
|
13
22
|
end
|
14
23
|
|
15
24
|
def wss_host
|
16
|
-
ENV.fetch('XTB__WSS_HOST',
|
25
|
+
ENV.fetch('XTB__WSS_HOST', DEFAULT_WEB_SOCKET_HOST)
|
17
26
|
end
|
18
27
|
|
19
28
|
def wss_path
|
20
|
-
ENV.fetch('XTB__WSS_PATH',
|
29
|
+
ENV.fetch('XTB__WSS_PATH', DEFAULT_WEB_SOCKET_PATH)
|
21
30
|
end
|
22
31
|
|
23
32
|
def wss_port
|
24
|
-
ENV.fetch('XTB__WSS_PORT',
|
33
|
+
ENV.fetch('XTB__WSS_PORT', DEFAULT_WEB_SOCKET_PORT).to_i
|
25
34
|
end
|
26
35
|
|
27
36
|
def user_id
|
@@ -32,8 +41,20 @@ module Xtb
|
|
32
41
|
ENV.fetch('XTB__PASSWORD') { raise 'XTB__PASSWORD is required' }
|
33
42
|
end
|
34
43
|
|
44
|
+
def connection_pool_size
|
45
|
+
size = ENV.fetch('XTB__CONNECTION_POOL_SIZE', DEFAULT_CONNECTION_POOL_SIZE).to_i
|
46
|
+
raise "Max connection pool size is #{MAX_CONNECTION_POOL_SIZE}" if size > MAX_CONNECTION_POOL_SIZE
|
47
|
+
|
48
|
+
size
|
49
|
+
end
|
50
|
+
|
35
51
|
def min_request_interval
|
36
|
-
ENV.fetch('XTB__MIN_REQUEST_INTERVAL',
|
52
|
+
requests_interval = ENV.fetch('XTB__MIN_REQUEST_INTERVAL', MIN_REQUEST_INTERVAL).to_i
|
53
|
+
if requests_interval < MIN_REQUEST_INTERVAL
|
54
|
+
raise "Minimum request interval must be greater than or equal to #{MIN_REQUEST_INTERVAL}"
|
55
|
+
end
|
56
|
+
|
57
|
+
requests_interval
|
37
58
|
end
|
38
59
|
end
|
39
60
|
end
|
data/lib/xtb/error.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xtb
|
4
|
+
# http://developers.xstore.pro/documentation/#error-messages
|
5
|
+
class Error < StandardError; end
|
6
|
+
|
7
|
+
class InvalidPriceError < Error; end
|
8
|
+
|
9
|
+
class InvalidStopLossOrTakeProfitError < Error; end
|
10
|
+
|
11
|
+
class InvalidVolumeError < Error; end
|
12
|
+
|
13
|
+
class LoginDisabledError < Error; end
|
14
|
+
|
15
|
+
class InvalidLoginOrPasswordError < Error; end
|
16
|
+
|
17
|
+
class MarketClosedError < Error; end
|
18
|
+
|
19
|
+
class MismatchedParametersError < Error; end
|
20
|
+
|
21
|
+
class ModificationDeniedError < Error; end
|
22
|
+
|
23
|
+
class NotEnoughMoneyError < Error; end
|
24
|
+
|
25
|
+
class OffQuotesError < Error; end
|
26
|
+
|
27
|
+
class OppositePositionsProhibitedError < Error; end
|
28
|
+
|
29
|
+
class ShortPositionsProhibitedError < Error; end
|
30
|
+
|
31
|
+
class PriceChangedError < Error; end
|
32
|
+
|
33
|
+
class RequestTooFrequentError < Error; end
|
34
|
+
|
35
|
+
class TooManyTradeRequestsError < Error; end
|
36
|
+
|
37
|
+
class TradingOnInstrumentDisabledError < Error; end
|
38
|
+
|
39
|
+
class TradingTimeoutError < Error; end
|
40
|
+
|
41
|
+
class OtherError < Error; end
|
42
|
+
|
43
|
+
class SymbolDoesNotExistForAccountError < Error; end
|
44
|
+
|
45
|
+
class AccountCannotTradeOnSymbolError < Error; end
|
46
|
+
|
47
|
+
class PendingOrderCannotBeClosedError < Error; end
|
48
|
+
|
49
|
+
class CannotCloseOrderError < Error; end
|
50
|
+
|
51
|
+
class NoSuchTransactionError < Error; end
|
52
|
+
|
53
|
+
class UnknownInstrumentSymbolError < Error; end
|
54
|
+
|
55
|
+
class UnknownTransactionTypeError < Error; end
|
56
|
+
|
57
|
+
class NotLoggedInError < Error; end
|
58
|
+
|
59
|
+
class MethodDoesNotExistError < Error; end
|
60
|
+
|
61
|
+
class IncorrectPeriodError < Error; end
|
62
|
+
|
63
|
+
class MissingDataError < Error; end
|
64
|
+
|
65
|
+
class IncorrectCommandFormatError < Error; end
|
66
|
+
|
67
|
+
class SymbolDoesNotExistError < Error; end
|
68
|
+
|
69
|
+
class InvalidTokenError < Error; end
|
70
|
+
|
71
|
+
class AlreadyLoggedInError < Error; end
|
72
|
+
|
73
|
+
class SessionTimedOutError < Error; end
|
74
|
+
|
75
|
+
class InvalidParametersError < Error; end
|
76
|
+
|
77
|
+
class InternalError < Error; end
|
78
|
+
|
79
|
+
class NoAccessError < Error; end
|
80
|
+
|
81
|
+
class ConnectionLimitError < Error; end
|
82
|
+
|
83
|
+
class DataLimitExceededError < Error; end
|
84
|
+
|
85
|
+
class BlacklistedError < Error; end
|
86
|
+
|
87
|
+
class CommandNotAllowedError < Error; end
|
88
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xtb
|
4
|
+
# Factory for creating error objects based on error codes.
|
5
|
+
class ErrorFactory
|
6
|
+
ERROR_CODES = {
|
7
|
+
'BE001': { klass: 'InvalidPriceError', description: 'Invalid price' },
|
8
|
+
'BE002': { klass: 'InvalidStopLossOrTakeProfitError', description: 'Invalid StopLoss or TakeProfit' },
|
9
|
+
'BE003': { klass: 'InvalidVolumeError', description: 'Invalid volume' },
|
10
|
+
'BE004': { klass: 'LoginDisabledError', description: 'Login disabled' },
|
11
|
+
'BE005': { klass: 'InvalidLoginOrPasswordError', description: 'Invalid login or password' },
|
12
|
+
'BE006': { klass: 'MarketClosedError', description: 'Market for instrument is closed' },
|
13
|
+
'BE007': { klass: 'MismatchedParametersError', description: 'Mismatched parameters' },
|
14
|
+
'BE008': { klass: 'ModificationDeniedError', description: 'Modification is denied' },
|
15
|
+
'BE009': { klass: 'NotEnoughMoneyError', description: 'Not enough money on account to perform trade' },
|
16
|
+
'BE010': { klass: 'OffQuotesError', description: 'Off quotes' },
|
17
|
+
'BE011': { klass: 'OppositePositionsProhibitedError', description: 'Opposite positions prohibited' },
|
18
|
+
'BE012': { klass: 'ShortPositionsProhibitedError', description: 'Short positions prohibited' },
|
19
|
+
'BE013': { klass: 'PriceChangedError', description: 'Price has changed' },
|
20
|
+
'BE014': { klass: 'RequestTooFrequentError', description: 'Request too frequent' },
|
21
|
+
'BE016': { klass: 'TooManyTradeRequestsError', description: 'Too many trade requests' },
|
22
|
+
'BE018': { klass: 'TradingOnInstrumentDisabledError', description: 'Trading on instrument disabled' },
|
23
|
+
'BE019': { klass: 'TradingTimeoutError', description: 'Trading timeout' },
|
24
|
+
'BE020': { klass: 'OtherError', description: 'Other error' },
|
25
|
+
'BE094': { klass: 'SymbolDoesNotExistForAccountError', description: 'Symbol does not exist for given account' },
|
26
|
+
'BE095': { klass: 'AccountCannotTradeOnSymbolError', description: 'Account cannot trade on given symbol' },
|
27
|
+
'BE096': { klass: 'PendingOrderCannotBeClosedError',
|
28
|
+
description: 'Pending order cannot be closed. Pending order must be deleted' },
|
29
|
+
'BE097': { klass: 'CannotCloseOrderError', description: 'Cannot close already closed order' },
|
30
|
+
'BE098': { klass: 'NoSuchTransactionError', description: 'No such transaction' },
|
31
|
+
'BE101': { klass: 'UnknownInstrumentSymbolError', description: 'Unknown instrument symbol' },
|
32
|
+
'BE102': { klass: 'UnknownTransactionTypeError', description: 'Unknown transaction type' },
|
33
|
+
'BE103': { klass: 'NotLoggedInError', description: 'User is not logged' },
|
34
|
+
'BE104': { klass: 'MethodDoesNotExistError', description: 'Method does not exist' },
|
35
|
+
'BE105': { klass: 'IncorrectPeriodError', description: 'Incorrect period given' },
|
36
|
+
'BE106': { klass: 'MissingDataError', description: 'Missing data' },
|
37
|
+
'BE110': { klass: 'IncorrectCommandFormatError', description: 'Incorrect command format' },
|
38
|
+
'BE115': { klass: 'SymbolDoesNotExistError', description: 'Symbol does not exist' },
|
39
|
+
'BE116': { klass: 'SymbolDoesNotExistError', description: 'Symbol does not exist' },
|
40
|
+
'BE117': { klass: 'InvalidTokenError', description: 'Invalid token' },
|
41
|
+
'BE118': { klass: 'AlreadyLoggedInError', description: 'User already logged' },
|
42
|
+
'BE200': { klass: 'SessionTimedOutError', description: 'Session timed out' },
|
43
|
+
'EX000': { klass: 'InvalidParametersError', description: 'Invalid parameters' },
|
44
|
+
'EX001': { klass: 'InternalError', description: 'Internal error, in case of such error, please contact support' },
|
45
|
+
'EX003': { klass: 'InternalError', description: 'Internal error, request timed out' },
|
46
|
+
'EX004': { klass: 'InvalidVolumeError',
|
47
|
+
description: 'Login credentials are incorrect or this login is not allowed to use an application \
|
48
|
+
with this appId' },
|
49
|
+
'EX005': { klass: 'InvalidVolumeError', description: 'Internal error' },
|
50
|
+
'EX006': { klass: 'NoAccessError', description: 'No access' },
|
51
|
+
'EX007': { klass: 'InvalidVolumeError',
|
52
|
+
description: 'Invalid login or password. This login/password is disabled for 10 minutes' },
|
53
|
+
'EX008': { klass: 'ConnectionLimitError', description: 'You have reached the connection limit' },
|
54
|
+
'EX009': { klass: 'DataLimitExceededError', description: 'Data limit potentially exceeded' },
|
55
|
+
'EX010': { klass: 'BlacklistedError', description: 'Your login is on the black list' },
|
56
|
+
'EX011': { klass: 'CommandNotAllowedError', description: 'You are not allowed to execute this command' }
|
57
|
+
}.freeze
|
58
|
+
|
59
|
+
ERROR_CODE_DUPLICATES = {
|
60
|
+
'BE016': ['BE017'],
|
61
|
+
'BE020': ('BE021'..'BE037').to_a + ['BE099'],
|
62
|
+
'BE115': ['BE116'],
|
63
|
+
'EX001': %w[BE000 EX002]
|
64
|
+
}.freeze
|
65
|
+
|
66
|
+
# Create an error object based on the error code. The API specifies multiple error codes can be
|
67
|
+
# matched to the same error, so a list of duplicates is provided, plus a mapping for codes
|
68
|
+
# matching 'SExxx' to 'EX001'.
|
69
|
+
# @param error_code [String]
|
70
|
+
# @param error_description [String] (optional)
|
71
|
+
# @return [Xtb::Error]
|
72
|
+
def self.create(error_code, error_description = '')
|
73
|
+
error_code = error_code.to_sym
|
74
|
+
mapped_code = ERROR_CODES.keys.include?(error_code) ? error_code : error_code_for_duplicate(error_code)
|
75
|
+
error = ERROR_CODES.fetch(mapped_code, nil)
|
76
|
+
return default_error(error_code, error_description) if error.nil?
|
77
|
+
|
78
|
+
error_description = error_description.empty? ? error[:description] : error_description
|
79
|
+
message = "(#{error_code}) #{error_description}"
|
80
|
+
Xtb.const_get(error[:klass]).new(message)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.default_error(error_code, error_description)
|
84
|
+
Xtb::Error.new("(#{error_code}) #{error_description}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.error_code_for_duplicate(error_code_duplicate)
|
88
|
+
code = nil
|
89
|
+
|
90
|
+
if error_code_duplicate.start_with?('SE')
|
91
|
+
code = :EX001
|
92
|
+
else
|
93
|
+
ERROR_CODE_DUPLICATES.each do |error_code, duplicates|
|
94
|
+
code = error_code if duplicates.include?(error_code_duplicate)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
code
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/xtb/http/all_symbols.rb
CHANGED
data/lib/xtb/http/calendar.rb
CHANGED
@@ -14,10 +14,12 @@ module Xtb
|
|
14
14
|
@period = period
|
15
15
|
@start = start
|
16
16
|
@symbol = symbol
|
17
|
+
|
18
|
+
super()
|
17
19
|
end
|
18
20
|
|
19
21
|
def call
|
20
|
-
digits, rate_infos = super.values_at(:digits, :rate_infos)
|
22
|
+
digits, rate_infos = super.return_data.values_at(:digits, :rate_infos)
|
21
23
|
rate_infos = rate_infos.map { |record| RateInfoRecord.new(**record) }
|
22
24
|
ChartLastRequestResponse.new(digits:, rate_infos:)
|
23
25
|
end
|
@@ -18,10 +18,12 @@ module Xtb
|
|
18
18
|
@start_time = start_time
|
19
19
|
@symbol = symbol
|
20
20
|
@ticks = ticks
|
21
|
+
|
22
|
+
super()
|
21
23
|
end
|
22
24
|
|
23
25
|
def call
|
24
|
-
digits, rate_infos = super.values_at(:digits, :rate_infos)
|
26
|
+
digits, rate_infos = super.return_data.values_at(:digits, :rate_infos)
|
25
27
|
rate_infos = rate_infos.map { |record| RateInfoRecord.new(**record) }
|
26
28
|
ChartLastRequestResponse.new(digits:, rate_infos:)
|
27
29
|
end
|
data/lib/xtb/http/client.rb
CHANGED
@@ -1,39 +1,69 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require 'connection_pool'
|
4
|
+
|
5
|
+
require_relative '../error'
|
6
|
+
require_relative '../config'
|
5
7
|
require_relative '../request_queue'
|
6
8
|
|
7
9
|
module Xtb
|
8
10
|
module Http
|
11
|
+
# Client for XTB API.
|
9
12
|
class Client
|
10
13
|
include RequestQueue
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
def initialize
|
16
|
+
@ssl_socket = new_ssl_socket
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sends a request to the broker server. It utilizes a connection pool to manage connections.
|
20
|
+
def self.post
|
21
|
+
connection_pool.with do |connection|
|
14
22
|
with_request_queue do
|
15
|
-
|
23
|
+
yield connection
|
16
24
|
end
|
17
|
-
# rescue NotLoggedInError => e
|
18
|
-
# return if command == :logout
|
19
|
-
#
|
20
|
-
# Rails.logger.debug(e)
|
21
|
-
#
|
22
|
-
# BrokerClients::Xtb::Login.call
|
23
|
-
# retry
|
24
|
-
# rescue AlreadyLoggedInError => _e
|
25
|
-
# # noop
|
26
25
|
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def request(payload)
|
29
|
+
ssl_socket.puts(payload)
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
def stream_session_id
|
34
|
+
@stream_session_id ||= BrokerClients::Xtb::Login.call.stream_session_id
|
35
|
+
end
|
27
36
|
|
28
|
-
|
29
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :ssl_socket
|
40
|
+
|
41
|
+
def self.connection_pool
|
42
|
+
@connection_pool ||= ConnectionPool.new(size: Config.connection_pool_size, timeout: 30) do
|
43
|
+
connection = new
|
44
|
+
Xtb::Http::Login.call(connection:)
|
45
|
+
|
46
|
+
connection
|
30
47
|
end
|
48
|
+
end
|
31
49
|
|
32
|
-
|
50
|
+
def response
|
51
|
+
buffer = []
|
33
52
|
|
34
|
-
|
35
|
-
|
53
|
+
while (line = ssl_socket.gets)
|
54
|
+
break if line.strip.empty?
|
55
|
+
|
56
|
+
buffer << line
|
36
57
|
end
|
58
|
+
|
59
|
+
buffer.join.strip
|
60
|
+
end
|
61
|
+
|
62
|
+
def new_ssl_socket
|
63
|
+
OpenSSL::SSL::SSLSocket.open(Config.https_host, Config.https_port).tap do |socket|
|
64
|
+
socket.hostname = Config.https_host
|
65
|
+
socket.sync_close = true
|
66
|
+
end.connect
|
37
67
|
end
|
38
68
|
end
|
39
69
|
end
|
data/lib/xtb/http/command.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'active_support/inflector'
|
5
|
-
require_relative '../
|
5
|
+
require_relative '../error'
|
6
|
+
require_relative '../error_factory'
|
6
7
|
|
7
8
|
module Xtb
|
8
9
|
module Http
|
@@ -35,14 +36,20 @@ module Xtb
|
|
35
36
|
@response = parse
|
36
37
|
end
|
37
38
|
|
38
|
-
def
|
39
|
+
def status
|
39
40
|
response[:status]
|
40
41
|
end
|
41
42
|
|
43
|
+
alias_method :success?, :status
|
44
|
+
|
42
45
|
def return_data
|
43
46
|
response[:return_data]
|
44
47
|
end
|
45
48
|
|
49
|
+
def stream_session_id
|
50
|
+
response[:stream_session_id]
|
51
|
+
end
|
52
|
+
|
46
53
|
def error_code
|
47
54
|
response[:error_code]
|
48
55
|
end
|
@@ -73,41 +80,42 @@ module Xtb
|
|
73
80
|
end
|
74
81
|
end
|
75
82
|
|
76
|
-
def initialize(**args)
|
83
|
+
def initialize(**args)
|
84
|
+
@args = args
|
85
|
+
@request_data = Request.new(command:, arguments:).to_json
|
86
|
+
end
|
77
87
|
|
78
88
|
def self.call(**args)
|
79
89
|
new(**args).call
|
80
90
|
end
|
81
91
|
|
82
92
|
def call
|
83
|
-
|
84
|
-
|
93
|
+
raw_response = if args[:connection]
|
94
|
+
args.fetch(:connection).request(request_data)
|
95
|
+
else
|
96
|
+
Xtb::Http::Client.post do |connection|
|
97
|
+
connection.request(request_data)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
85
101
|
response = Response.new(command:, raw_response:)
|
86
|
-
raise_error(response.error_code, response.error_description) unless response.success?
|
87
102
|
|
88
|
-
response.
|
103
|
+
raise ErrorFactory.create(response.error_code, response.error_description) unless response.success?
|
104
|
+
|
105
|
+
response
|
89
106
|
end
|
90
107
|
|
91
108
|
private
|
92
109
|
|
110
|
+
attr_reader :args, :request_data
|
111
|
+
|
93
112
|
def command
|
94
|
-
raise NotImplementedError
|
113
|
+
raise NotImplementedError('You must implement the command method')
|
95
114
|
end
|
96
115
|
|
97
116
|
def arguments
|
98
117
|
nil
|
99
118
|
end
|
100
|
-
|
101
|
-
def raise_error(error_code, error_description)
|
102
|
-
case error_code
|
103
|
-
when 'BE103'
|
104
|
-
raise NotLoggedInError, "(#{error_code}) #{error_description}"
|
105
|
-
when 'BE118'
|
106
|
-
raise AlreadyLoggedInError, "(#{error_code}) #{error_description}"
|
107
|
-
else
|
108
|
-
raise "(#{error_code}) #{error_description}"
|
109
|
-
end
|
110
|
-
end
|
111
119
|
end
|
112
120
|
end
|
113
121
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xtb
|
4
|
+
module Http
|
5
|
+
# http://developers.xstore.pro/documentation/2.5.0#login
|
6
|
+
class Login < Command
|
7
|
+
LoginResponse = Data.define(:stream_session_id)
|
8
|
+
|
9
|
+
def call
|
10
|
+
LoginResponse.new(super.stream_session_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def command = :login
|
16
|
+
|
17
|
+
def arguments
|
18
|
+
{
|
19
|
+
user_id:,
|
20
|
+
password:
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def user_id
|
25
|
+
Xtb::Config.user_id
|
26
|
+
end
|
27
|
+
|
28
|
+
def password
|
29
|
+
Xtb::Config.password
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/xtb/http/news.rb
CHANGED
@@ -11,10 +11,12 @@ module Xtb
|
|
11
11
|
def initialize(end_time, start_time)
|
12
12
|
@end_time = end_time
|
13
13
|
@start_time = start_time
|
14
|
+
|
15
|
+
super()
|
14
16
|
end
|
15
17
|
|
16
18
|
def call
|
17
|
-
super.map { |record| NewsTopicRecord.new(**record) }
|
19
|
+
super.return_data.map { |record| NewsTopicRecord.new(**record) }
|
18
20
|
end
|
19
21
|
|
20
22
|
private
|
data/lib/xtb/http/server_time.rb
CHANGED
data/lib/xtb/http/step_rules.rb
CHANGED
data/lib/xtb/http/symbol.rb
CHANGED
data/lib/xtb/http/tick_prices.rb
CHANGED
@@ -11,10 +11,12 @@ module Xtb
|
|
11
11
|
@level = level
|
12
12
|
@symbols = symbols
|
13
13
|
@timestamp = timestamp
|
14
|
+
|
15
|
+
super()
|
14
16
|
end
|
15
17
|
|
16
18
|
def call
|
17
|
-
super[:quotations].map { |record| TickRecord.new(**record) }
|
19
|
+
super.return_data[:quotations].map { |record| TickRecord.new(**record) }
|
18
20
|
end
|
19
21
|
|
20
22
|
private
|
@@ -7,10 +7,12 @@ module Xtb
|
|
7
7
|
# @param orders [Array<Integer>] list of order ids
|
8
8
|
def initialize(orders)
|
9
9
|
@orders = orders
|
10
|
+
|
11
|
+
super()
|
10
12
|
end
|
11
13
|
|
12
14
|
def call
|
13
|
-
super.map { |record| Xtb::TradeRecord.new(**record) }
|
15
|
+
super.return_data.map { |record| Xtb::TradeRecord.new(**record) }
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
@@ -6,7 +6,7 @@ module Xtb
|
|
6
6
|
class TradeTransaction < Command
|
7
7
|
TradeTransactionResponse = Data.define(:order)
|
8
8
|
|
9
|
-
# @param cmd [Symbol]
|
9
|
+
# @param cmd [Symbol] One of :buy, :sell, :buy_limit, :sell_limit, :buy_stop, :sell_stop, :balance, or :credit
|
10
10
|
# @param custom_comment [String]
|
11
11
|
# @param expiration [Integer]
|
12
12
|
# @param offset [Integer]
|
@@ -15,7 +15,7 @@ module Xtb
|
|
15
15
|
# @param stop_loss [Float]
|
16
16
|
# @param symbol [String]
|
17
17
|
# @param take_profit [Float]
|
18
|
-
# @param type [Symbol]
|
18
|
+
# @param type [Symbol] One of :open, :pending, :close, :modify, or :delete
|
19
19
|
# @param volume [Float]
|
20
20
|
def initialize(cmd:, custom_comment:, expiration:, offset:, order:, price:, stop_loss:, symbol:, take_profit:,
|
21
21
|
type:, volume:)
|
@@ -30,10 +30,12 @@ module Xtb
|
|
30
30
|
@take_profit = take_profit
|
31
31
|
@type = type
|
32
32
|
@volume = volume
|
33
|
+
|
34
|
+
super()
|
33
35
|
end
|
34
36
|
|
35
37
|
def call
|
36
|
-
TradeTransactionResponse.new(**super)
|
38
|
+
TradeTransactionResponse.new(**super.return_data)
|
37
39
|
end
|
38
40
|
|
39
41
|
private
|
data/lib/xtb/http/trades.rb
CHANGED
@@ -7,10 +7,12 @@ module Xtb
|
|
7
7
|
# @param opened_only [Boolean]
|
8
8
|
def initialize(opened_only)
|
9
9
|
@opened_only = opened_only
|
10
|
+
|
11
|
+
super()
|
10
12
|
end
|
11
13
|
|
12
14
|
def call
|
13
|
-
super.map { |record| Xtb::TradeRecord.new(**record) }
|
15
|
+
super.return_data.map { |record| Xtb::TradeRecord.new(**record) }
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
@@ -9,10 +9,12 @@ module Xtb
|
|
9
9
|
def initialize(end_time, start_time)
|
10
10
|
@end_time = end_time
|
11
11
|
@start_time = start_time
|
12
|
+
|
13
|
+
super()
|
12
14
|
end
|
13
15
|
|
14
16
|
def call
|
15
|
-
super.map { |record| Xtb::TradeRecord.new(**record) }
|
17
|
+
super.return_data.map { |record| Xtb::TradeRecord.new(**record) }
|
16
18
|
end
|
17
19
|
|
18
20
|
private
|
@@ -4,10 +4,10 @@ module Xtb
|
|
4
4
|
module Http
|
5
5
|
# http://developers.xstore.pro/documentation/2.5.0#getTradingHours
|
6
6
|
class TradingHours < Command
|
7
|
-
|
8
|
-
|
9
|
-
TimesRecord = Data.define(:day, :from_t, :to_t)
|
7
|
+
# Represents both quotes and trading times records.
|
8
|
+
TimesRecord = Data.define(:day, :from_t, :to_t)
|
10
9
|
|
10
|
+
TradingHoursRecord = Data.define(:quotes, :symbol, :trading) do
|
11
11
|
def initialize(symbol:, quotes: TimesRecord.new, trading: TimesRecord.new)
|
12
12
|
super(quotes:, symbol:, trading:)
|
13
13
|
end
|
@@ -16,10 +16,12 @@ module Xtb
|
|
16
16
|
# @param symbols [Array<String|Symbol>]
|
17
17
|
def initialize(symbols)
|
18
18
|
@symbols = symbols
|
19
|
+
|
20
|
+
super()
|
19
21
|
end
|
20
22
|
|
21
23
|
def call
|
22
|
-
super.map { |record| TradingHoursRecord.new(**record) }
|
24
|
+
super.return_data.map { |record| TradingHoursRecord.new(**record) }
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
data/lib/xtb/http/version.rb
CHANGED
data/lib/xtb/http.rb
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'http/client'
|
4
|
+
require_relative 'http/command'
|
4
5
|
|
5
6
|
# commands
|
6
|
-
require_relative 'http/command'
|
7
7
|
require_relative 'http/all_symbols'
|
8
8
|
require_relative 'http/calendar'
|
9
9
|
require_relative 'http/chart_last_request'
|
10
10
|
require_relative 'http/chart_range_request'
|
11
11
|
require_relative 'http/commission_def'
|
12
12
|
require_relative 'http/current_user_data'
|
13
|
+
require_relative 'http/login'
|
14
|
+
require_relative 'http/logout'
|
13
15
|
require_relative 'http/margin_level'
|
14
16
|
require_relative 'http/margin_trade'
|
15
17
|
require_relative 'http/news'
|
18
|
+
require_relative 'http/ping'
|
16
19
|
require_relative 'http/profit_calculation'
|
17
20
|
require_relative 'http/server_time'
|
18
21
|
require_relative 'http/step_rules'
|
19
22
|
require_relative 'http/symbol'
|
20
23
|
require_relative 'http/tick_prices'
|
21
24
|
require_relative 'http/trade_records'
|
25
|
+
require_relative 'http/trade_transaction'
|
22
26
|
require_relative 'http/trades'
|
23
27
|
require_relative 'http/trades_history'
|
24
28
|
require_relative 'http/trading_hours'
|
data/lib/xtb/request_queue.rb
CHANGED
@@ -10,29 +10,28 @@ module Xtb
|
|
10
10
|
base.extend(ClassMethods)
|
11
11
|
end
|
12
12
|
|
13
|
-
module ClassMethods
|
14
|
-
|
15
|
-
|
16
|
-
def with_request_queue(&block)
|
17
|
-
queue << block
|
18
|
-
queue << wait_proc
|
19
|
-
|
20
|
-
result = queue.pop.call
|
21
|
-
queue.pop.call
|
13
|
+
module ClassMethods # :nodoc:
|
14
|
+
def with_request_queue
|
15
|
+
sleep(time_to_next_request / 1000) unless @last_request_time.nil?
|
22
16
|
|
23
|
-
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
@last_request_time = Time.now
|
24
20
|
end
|
25
21
|
|
26
|
-
|
27
|
-
|
22
|
+
private
|
23
|
+
|
24
|
+
def time_to_next_request
|
25
|
+
[0, min_request_interval - time_since_last_request].max.to_f
|
28
26
|
end
|
29
27
|
|
30
|
-
|
31
|
-
|
28
|
+
# @return [Integer] time elapsed since the last request in milliseconds
|
29
|
+
def time_since_last_request
|
30
|
+
(1000 * (@last_request_time - Time.now)).to_i.abs
|
32
31
|
end
|
33
32
|
|
34
33
|
def min_request_interval
|
35
|
-
Config.min_request_interval
|
34
|
+
@min_request_interval ||= Config.min_request_interval
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
data/lib/xtb/version.rb
CHANGED
data/lib/xtb/web_socket.rb
CHANGED
data/lib/xtb.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'xtb/version'
|
4
|
+
require_relative 'xtb/error'
|
4
5
|
require_relative 'xtb/http'
|
5
6
|
require_relative 'xtb/web_socket'
|
6
7
|
require_relative 'xtb/config'
|
@@ -14,7 +15,7 @@ module Xtb
|
|
14
15
|
m30: 30,
|
15
16
|
h1: 60,
|
16
17
|
h4: 240,
|
17
|
-
d1:
|
18
|
+
d1: 1_440,
|
18
19
|
w1: 10_080,
|
19
20
|
mn1: 43_200
|
20
21
|
}.freeze
|
metadata
CHANGED
@@ -1,15 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xtb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Jacek Maciag
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
12
|
-
dependencies:
|
11
|
+
date: 2024-11-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: connection_pool
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: openssl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.21'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.21'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
13
83
|
description: 'The XTB API (xAPI) client for Ruby provides a simple and easy to use
|
14
84
|
interface to interact with XTB API.
|
15
85
|
|
@@ -28,7 +98,8 @@ files:
|
|
28
98
|
- Rakefile
|
29
99
|
- lib/xtb.rb
|
30
100
|
- lib/xtb/config.rb
|
31
|
-
- lib/xtb/
|
101
|
+
- lib/xtb/error.rb
|
102
|
+
- lib/xtb/error_factory.rb
|
32
103
|
- lib/xtb/http.rb
|
33
104
|
- lib/xtb/http/all_symbols.rb
|
34
105
|
- lib/xtb/http/calendar.rb
|
@@ -38,13 +109,14 @@ files:
|
|
38
109
|
- lib/xtb/http/command.rb
|
39
110
|
- lib/xtb/http/commission_def.rb
|
40
111
|
- lib/xtb/http/current_user_data.rb
|
112
|
+
- lib/xtb/http/login.rb
|
113
|
+
- lib/xtb/http/logout.rb
|
41
114
|
- lib/xtb/http/margin_level.rb
|
42
115
|
- lib/xtb/http/margin_trade.rb
|
43
116
|
- lib/xtb/http/news.rb
|
117
|
+
- lib/xtb/http/ping.rb
|
44
118
|
- lib/xtb/http/profit_calculation.rb
|
45
|
-
- lib/xtb/http/response.rb
|
46
119
|
- lib/xtb/http/server_time.rb
|
47
|
-
- lib/xtb/http/ssl_client.rb
|
48
120
|
- lib/xtb/http/step_rules.rb
|
49
121
|
- lib/xtb/http/symbol.rb
|
50
122
|
- lib/xtb/http/tick_prices.rb
|
@@ -58,7 +130,6 @@ files:
|
|
58
130
|
- lib/xtb/version.rb
|
59
131
|
- lib/xtb/web_socket.rb
|
60
132
|
- lib/xtb/web_socket/client.rb
|
61
|
-
- sig/xtb.rbs
|
62
133
|
homepage: https://github.com/jacekmaciag/xtb
|
63
134
|
licenses:
|
64
135
|
- MIT
|
@@ -66,7 +137,7 @@ metadata:
|
|
66
137
|
allowed_push_host: https://rubygems.org
|
67
138
|
homepage_uri: https://github.com/jacekmaciag/xtb
|
68
139
|
source_code_uri: https://github.com/jacekmaciag/xtb
|
69
|
-
changelog_uri: https://github.com/jacekmaciag/xtb/blob/
|
140
|
+
changelog_uri: https://github.com/jacekmaciag/xtb/blob/master/CHANGELOG.md
|
70
141
|
post_install_message:
|
71
142
|
rdoc_options: []
|
72
143
|
require_paths:
|
data/lib/xtb/errors.rb
DELETED
data/lib/xtb/http/response.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Xtb
|
4
|
-
module Http
|
5
|
-
class Response
|
6
|
-
def initialize(raw_response, command)
|
7
|
-
@response = parse_json(raw_response)
|
8
|
-
@command = command
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.parse(raw_response, command)
|
12
|
-
new(raw_response, command).parse
|
13
|
-
end
|
14
|
-
|
15
|
-
def parse
|
16
|
-
return data if success?
|
17
|
-
|
18
|
-
raise_error
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
attr_reader :response, :command
|
24
|
-
|
25
|
-
def parse_json(raw_response)
|
26
|
-
JSON.parse(raw_response).deep_transform_keys { |key| key.underscore.to_sym }
|
27
|
-
end
|
28
|
-
|
29
|
-
def success?
|
30
|
-
response[:status]
|
31
|
-
end
|
32
|
-
|
33
|
-
def data
|
34
|
-
return response if command == :login
|
35
|
-
|
36
|
-
response[:return_data]
|
37
|
-
end
|
38
|
-
|
39
|
-
def error_code
|
40
|
-
response[:error_code]
|
41
|
-
end
|
42
|
-
|
43
|
-
def error_description
|
44
|
-
response[:error_descr]
|
45
|
-
end
|
46
|
-
|
47
|
-
def error_string
|
48
|
-
"(#{error_code}) #{error_description}"
|
49
|
-
end
|
50
|
-
|
51
|
-
def raise_error
|
52
|
-
case error_code
|
53
|
-
when 'BE103'
|
54
|
-
raise NotLoggedInError, error_string
|
55
|
-
when 'BE118'
|
56
|
-
raise AlreadyLoggedInError, error_string
|
57
|
-
else
|
58
|
-
raise BrokerError, error_string
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/xtb/http/ssl_client.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'openssl'
|
4
|
-
require_relative '../config'
|
5
|
-
|
6
|
-
module Xtb
|
7
|
-
module Http
|
8
|
-
class SslClient
|
9
|
-
class << self
|
10
|
-
def request(payload)
|
11
|
-
ssl_socket.connect
|
12
|
-
ssl_socket.puts(payload)
|
13
|
-
next_line
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def next_line
|
19
|
-
line = ssl_socket.gets.chomp
|
20
|
-
return line unless line.empty?
|
21
|
-
|
22
|
-
next_line
|
23
|
-
end
|
24
|
-
|
25
|
-
def ssl_context
|
26
|
-
@ssl_context ||= OpenSSL::SSL::SSLContext.new
|
27
|
-
end
|
28
|
-
|
29
|
-
def ssl_socket
|
30
|
-
@ssl_socket ||= OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context) do |socket|
|
31
|
-
socket.hostname = Config.https_host
|
32
|
-
socket.sync_close = true
|
33
|
-
socket
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def tcp_socket
|
38
|
-
TCPSocket.new(Config.https_host, Config.https_port)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/sig/xtb.rbs
DELETED