xtb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getServerTime
6
+ class ServerTime < Command
7
+ ServerTimeResponse = Data.define(:time, :time_string)
8
+
9
+ def call
10
+ ServerTimeResponse.new(**super)
11
+ end
12
+
13
+ private
14
+
15
+ def command = :getServerTime
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,43 @@
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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getStepRules
6
+ class StepRules < Command
7
+ StepRecord = Data.define(:from_value, :step)
8
+
9
+ def call
10
+ super.map { |record| StepRecord.new(**record) }
11
+ end
12
+
13
+ private
14
+
15
+ def command = :getStepRules
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getSymbol
6
+ class Symbol < Command
7
+ # @param symbol [String|Symbol]
8
+ def initialize(symbol)
9
+ @symbol = symbol
10
+ end
11
+
12
+ def call
13
+ Xtb::SymbolRecord.new(**super)
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :symbol
19
+
20
+ def command = :getSymbol
21
+
22
+ def arguments
23
+ {
24
+ symbol:
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getTickPrices
6
+ class TickPrices < Command
7
+ TickRecord = Data.define(:ask, :ask_volume, :bid, :bid_volume, :high, :level, :low, :spread_raw, :spread_table,
8
+ :symbol, :timestamp)
9
+
10
+ def initialize(level, symbols, timestamp)
11
+ @level = level
12
+ @symbols = symbols
13
+ @timestamp = timestamp
14
+ end
15
+
16
+ def call
17
+ super[:quotations].map { |record| TickRecord.new(**record) }
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :level, :symbols, :timestamp
23
+
24
+ def command = :getTickPrices
25
+
26
+ def arguments
27
+ {
28
+ level:,
29
+ symbols:,
30
+ timestamp:
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getTradeRecords
6
+ class TradeRecords < Command
7
+ # @param orders [Array<Integer>] list of order ids
8
+ def initialize(orders)
9
+ @orders = orders
10
+ end
11
+
12
+ def call
13
+ super.map { |record| Xtb::TradeRecord.new(**record) }
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :orders
19
+
20
+ def command = :getTradeRecords
21
+
22
+ def arguments
23
+ {
24
+ orders:
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#tradeTransaction
6
+ class TradeTransaction < Command
7
+ TradeTransactionResponse = Data.define(:order)
8
+
9
+ # @param cmd [Symbol]
10
+ # @param custom_comment [String]
11
+ # @param expiration [Integer]
12
+ # @param offset [Integer]
13
+ # @param order [Integer]
14
+ # @param price [Float]
15
+ # @param stop_loss [Float]
16
+ # @param symbol [String]
17
+ # @param take_profit [Float]
18
+ # @param type [Symbol]
19
+ # @param volume [Float]
20
+ def initialize(cmd:, custom_comment:, expiration:, offset:, order:, price:, stop_loss:, symbol:, take_profit:,
21
+ type:, volume:)
22
+ @cmd = cmd
23
+ @custom_comment = custom_comment
24
+ @expiration = expiration
25
+ @offset = offset
26
+ @order = order
27
+ @price = price
28
+ @stop_loss = stop_loss
29
+ @symbol = symbol
30
+ @take_profit = take_profit
31
+ @type = type
32
+ @volume = volume
33
+ end
34
+
35
+ def call
36
+ TradeTransactionResponse.new(**super)
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :cmd, :custom_comment, :expiration, :offset, :order, :price, :stop_loss, :symbol, :take_profit,
42
+ :type, :volume
43
+
44
+ def command = :tradeTransaction
45
+
46
+ def arguments
47
+ {
48
+ trade_trans_info: {
49
+ cmd: Xtb::OPERATIONS[cmd],
50
+ custom_comment:,
51
+ expiration:,
52
+ offset:,
53
+ order:,
54
+ price:,
55
+ sl: stop_loss,
56
+ symbol:,
57
+ tp: take_profit,
58
+ type: Xtb::TRADE_TRANSACTION_TYPES[type],
59
+ volume:
60
+ }
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getTrades
6
+ class Trades < Command
7
+ # @param opened_only [Boolean]
8
+ def initialize(opened_only)
9
+ @opened_only = opened_only
10
+ end
11
+
12
+ def call
13
+ super.map { |record| Xtb::TradeRecord.new(**record) }
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :opened_only
19
+
20
+ def command = :getTrades
21
+
22
+ def arguments
23
+ {
24
+ opened_only:
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getTrades
6
+ class TradesHistory < Command
7
+ # @param end_time [Time]
8
+ # @param start_time [Time]
9
+ def initialize(end_time, start_time)
10
+ @end_time = end_time
11
+ @start_time = start_time
12
+ end
13
+
14
+ def call
15
+ super.map { |record| Xtb::TradeRecord.new(**record) }
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :end_time, :start_time
21
+
22
+ def command = :getTradesHistory
23
+
24
+ def arguments
25
+ {
26
+ end: end_time,
27
+ start: start_time
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getTradingHours
6
+ class TradingHours < Command
7
+ TradingHoursRecord = Data.define(:quotes, :symbol, :trading) do
8
+ # Represents both quotes and trading times records.
9
+ TimesRecord = Data.define(:day, :from_t, :to_t)
10
+
11
+ def initialize(symbol:, quotes: TimesRecord.new, trading: TimesRecord.new)
12
+ super(quotes:, symbol:, trading:)
13
+ end
14
+ end
15
+
16
+ # @param symbols [Array<String|Symbol>]
17
+ def initialize(symbols)
18
+ @symbols = symbols
19
+ end
20
+
21
+ def call
22
+ super.map { |record| TradingHoursRecord.new(**record) }
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :symbols
28
+
29
+ def command = :getTradingHours
30
+
31
+ def arguments
32
+ {
33
+ symbols:
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module Http
5
+ # http://developers.xstore.pro/documentation/2.5.0#getVersion
6
+ class Version < Command
7
+ VersionResponse = Data.define(:version)
8
+
9
+ def call
10
+ VersionResponse.new(**super)
11
+ end
12
+
13
+ private
14
+
15
+ def command = :getVersion
16
+ end
17
+ end
18
+ end
data/lib/xtb/http.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'http/client'
4
+
5
+ # commands
6
+ require_relative 'http/command'
7
+ require_relative 'http/all_symbols'
8
+ require_relative 'http/calendar'
9
+ require_relative 'http/chart_last_request'
10
+ require_relative 'http/chart_range_request'
11
+ require_relative 'http/commission_def'
12
+ require_relative 'http/current_user_data'
13
+ require_relative 'http/margin_level'
14
+ require_relative 'http/margin_trade'
15
+ require_relative 'http/news'
16
+ require_relative 'http/profit_calculation'
17
+ require_relative 'http/server_time'
18
+ require_relative 'http/step_rules'
19
+ require_relative 'http/symbol'
20
+ require_relative 'http/tick_prices'
21
+ require_relative 'http/trade_records'
22
+ require_relative 'http/trades'
23
+ require_relative 'http/trades_history'
24
+ require_relative 'http/trading_hours'
25
+ require_relative 'http/version'
26
+
27
+ module Xtb
28
+ module Http # :nodoc:
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require_relative 'config'
5
+
6
+ module Xtb
7
+ # Module provides a mechanism to limit the number of requests to the broker server.
8
+ module RequestQueue
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ private
15
+
16
+ def with_request_queue(&block)
17
+ queue << block
18
+ queue << wait_proc
19
+
20
+ result = queue.pop.call
21
+ queue.pop.call
22
+
23
+ result
24
+ end
25
+
26
+ def queue
27
+ @queue ||= Queue.new
28
+ end
29
+
30
+ def wait_proc
31
+ proc { sleep(min_request_interval) }
32
+ end
33
+
34
+ def min_request_interval
35
+ Config.min_request_interval
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module WebSocket
5
+ class Client
6
+ include RequestQueue
7
+
8
+ def initialize() end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xtb
4
+ module WebSocket
5
+ end
6
+ end
data/lib/xtb.rb ADDED
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'xtb/version'
4
+ require_relative 'xtb/http'
5
+ require_relative 'xtb/web_socket'
6
+ require_relative 'xtb/config'
7
+
8
+ module Xtb
9
+ # Periods in minutes.
10
+ PERIODS = {
11
+ m1: 1,
12
+ m5: 5,
13
+ m15: 15,
14
+ m30: 30,
15
+ h1: 60,
16
+ h4: 240,
17
+ d1: 1440,
18
+ w1: 10_080,
19
+ mn1: 43_200
20
+ }.freeze
21
+
22
+ # Operations with XTB broker codes.
23
+ OPERATIONS = {
24
+ buy: 0,
25
+ sell: 1,
26
+ buy_limit: 2,
27
+ sell_limit: 3,
28
+ buy_stop: 4,
29
+ sell_stop: 5,
30
+ balance: 6,
31
+ credit: 7
32
+ }.freeze
33
+
34
+ # Trade transaction type with XTB broker codes.
35
+ TRADE_TRANSACTION_TYPES = {
36
+ open: 0,
37
+ pending: 1,
38
+ close: 2,
39
+ modify: 3,
40
+ delete: 4
41
+ }.freeze
42
+
43
+ SymbolRecord = Data.define(:ask, :bid, :category_name, :contract_size, :currency, :currency_pair, :currency_profit,
44
+ :description, :exemode, :expiration, :group_name, :high, :initial_margin,
45
+ :instant_max_volume, :leverage, :long_only, :lot_max, :lot_min, :lot_step, :low,
46
+ :margin_hedged, :margin_hedged_strong, :margin_maintenance, :margin_mode, :percentage,
47
+ :pips_precision, :precision, :profit_mode, :quote_id, :quote_id_cross, :short_selling,
48
+ :spread_raw, :spread_table, :starting, :step_rule_id, :stops_level, :swap_rollover3days,
49
+ :swap_enable, :swap_long, :swap_short, :swap_type, :symbol, :tick_size, :tick_value,
50
+ :time, :time_string, :trailing_enabled, :type)
51
+
52
+ TradeRecord = Data.define(:close_price, :close_time, :close_time_string, :closed, :cmd, :comment, :commission,
53
+ :custom_comment, :digits, :expiration, :expiration_string, :margin_rate, :offset,
54
+ :open_price, :open_time, :open_time_string, :order, :order2, :position, :profit, :sl,
55
+ :storage, :symbol, :timestamp, :tp, :volume)
56
+ end
data/sig/xtb.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Xtb
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xtb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jacekmaciag
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'The XTB API (xAPI) client for Ruby provides a simple and easy to use
14
+ interface to interact with XTB API.
15
+
16
+ '
17
+ email:
18
+ - jacek.maciag@gmail.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - ".rspec"
24
+ - ".rubocop.yml"
25
+ - CHANGELOG.md
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - lib/xtb.rb
30
+ - lib/xtb/config.rb
31
+ - lib/xtb/errors.rb
32
+ - lib/xtb/http.rb
33
+ - lib/xtb/http/all_symbols.rb
34
+ - lib/xtb/http/calendar.rb
35
+ - lib/xtb/http/chart_last_request.rb
36
+ - lib/xtb/http/chart_range_request.rb
37
+ - lib/xtb/http/client.rb
38
+ - lib/xtb/http/command.rb
39
+ - lib/xtb/http/commission_def.rb
40
+ - lib/xtb/http/current_user_data.rb
41
+ - lib/xtb/http/margin_level.rb
42
+ - lib/xtb/http/margin_trade.rb
43
+ - lib/xtb/http/news.rb
44
+ - lib/xtb/http/profit_calculation.rb
45
+ - lib/xtb/http/response.rb
46
+ - lib/xtb/http/server_time.rb
47
+ - lib/xtb/http/ssl_client.rb
48
+ - lib/xtb/http/step_rules.rb
49
+ - lib/xtb/http/symbol.rb
50
+ - lib/xtb/http/tick_prices.rb
51
+ - lib/xtb/http/trade_records.rb
52
+ - lib/xtb/http/trade_transaction.rb
53
+ - lib/xtb/http/trades.rb
54
+ - lib/xtb/http/trades_history.rb
55
+ - lib/xtb/http/trading_hours.rb
56
+ - lib/xtb/http/version.rb
57
+ - lib/xtb/request_queue.rb
58
+ - lib/xtb/version.rb
59
+ - lib/xtb/web_socket.rb
60
+ - lib/xtb/web_socket/client.rb
61
+ - sig/xtb.rbs
62
+ homepage: https://github.com/jacekmaciag/xtb
63
+ licenses:
64
+ - MIT
65
+ metadata:
66
+ allowed_push_host: https://rubygems.org
67
+ homepage_uri: https://github.com/jacekmaciag/xtb
68
+ source_code_uri: https://github.com/jacekmaciag/xtb
69
+ changelog_uri: https://github.com/jacekmaciag/xtb/blob/main/CHANGELOG.md
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 3.1.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.5.11
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: XTB API client for Ruby.
89
+ test_files: []