moex_iss 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff742bbab0ebea3db2a2a57e0e8b76285f910ae84e27723217334ee5c86f2797
4
+ data.tar.gz: eb0ee71a6ecb99c00abc9e2eff15eaba516a9345161852250e958d92af396922
5
+ SHA512:
6
+ metadata.gz: 9044394d7813c40661d5c7bf0ba690ce80972ad20d80425927d5e290aa1419ba68dcb1148592077f827aa97e16d72981948e5e0b5b5240eb27e8c89821a3a9ef
7
+ data.tar.gz: ef3537013d7b14c0b3ba6afb88a7ba25013833782ac97d56b4224cd2d459225485e1aaf74dfa944704aed6840d16d263da7b99477d683ce37b764c9d1e8b8c2a
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Change log
2
+
3
+ ## master
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2023 Vyacheslav Konovalov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ [![Gem Version](https://badge.fury.io/rb/moex_iss.svg)](https://rubygems.org/gems/moex_iss)
2
+ [![Build](https://github.com/K0Hb/moex_iss/workflows/Build/badge.svg)](https://github.com/palkan/moex_iss/actions)
3
+ [![JRuby Build](https://github.com/K0Hb/moex_iss/workflows/JRuby%20Build/badge.svg)](https://github.com/K0Hb/moex_iss/actions)
4
+
5
+ # Moex Iss
6
+
7
+ Реализация части запросов к [MOEX Informational & Statistical Server](https://www.moex.com/a2193).
8
+
9
+ Реализовано несколько функций-запросов информации о торгуемых ценных бумаг, результаты которых напрямую конвертируются в Ruby класс.
10
+
11
+ Класс ценной бумаги имеет методы для получения наиболее часто использумеых показателей ценной бумаги а так же метод для получения полного ответа полученного от MOEX ISS.
12
+
13
+ ## Установка
14
+
15
+ ```ruby
16
+ # Gemfile
17
+ gem "moex_iss"
18
+ ```
19
+ А затем выполнить:
20
+
21
+ $ bundle install
22
+
23
+ Или установите его самостоятельно как:
24
+
25
+ $ gem install moex_api
26
+
27
+ ### Поддерживаемые Ruby версии
28
+
29
+ - Ruby (MRI) >= 2.7.0
30
+ - JRuby >= 9.3.0
31
+
32
+ ## Использование
33
+
34
+ ### Создаем клиент
35
+
36
+ ```ruby
37
+ client = MoexIss.client
38
+ ```
39
+
40
+ ### Акции
41
+
42
+ Для получения одной акций:
43
+ ```ruby
44
+ client.stock(:sber) # => MoexIss::Market::Stock
45
+ ```
46
+ Для получения всех акций:
47
+ ```ruby
48
+ client.stocks # => MoexIss::Market::Stocks
49
+ ```
50
+ Получаем класс, по которому можно итерироваться а так же вызывать искомую ценную бумагу по ее `isin`
51
+ ```ruby
52
+ stocks.sber
53
+ ```
54
+ Экземпляр класса `MoexIss::Market::Stocks` отвечает на методы:
55
+ ```ruby
56
+ %i[bid market_price_today market_price secid short_name lat_name board_id board_name isin prev_price prev_date response market_data]
57
+ ```
58
+ где `response` содержит полный ответ от MOEX ISS, из которого можно получать доп.параметры
59
+
60
+
61
+ ## Лицензия
62
+
63
+ Исходный код распространяется под лицензией [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ class Client
5
+ include MoexIss::Request
6
+ include MoexIss::Hendler
7
+
8
+ STOCKS_ENDPOINT = "engines/stock/markets/shares/boards/tqbr/securities"
9
+ STANDARD_PARAMS = {
10
+ "iss.json" => "extended",
11
+ "iss.only" => "securities,marketdata",
12
+ "iss.meta" => "off"
13
+ }
14
+
15
+ def stocks
16
+ endpoint = "#{STOCKS_ENDPOINT}.json"
17
+ params = STANDARD_PARAMS
18
+
19
+ raw_response = get(endpoint, params)
20
+
21
+ MoexIss::Market::Stocks.new(handle_response(raw_response))
22
+ end
23
+
24
+ def stock(isin)
25
+ endpoint = "#{STOCKS_ENDPOINT}/#{isin}.json"
26
+ params = STANDARD_PARAMS
27
+
28
+ raw_response = get(endpoint, params)
29
+
30
+ MoexIss::Market::Stock.new(handle_response(raw_response))
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Connection
5
+ BASE_URL = "https://iss.moex.com/iss"
6
+
7
+ module DoNotEncoder
8
+ def self.encode(params)
9
+ params.map { |k, v| "#{k}=#{v}" }.join("&")
10
+ end
11
+ end
12
+
13
+ def connection
14
+ Faraday.new(options) do |con|
15
+ con.adapter Faraday.default_adapter
16
+ con.request :url_encoded
17
+ con.options.params_encoder = DoNotEncoder
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def options
24
+ headers = {
25
+ accept: "application/json",
26
+ content_type: "application/x-www-from-urlencoded",
27
+ user_agent: "moex_iss gem"
28
+ }
29
+
30
+ {
31
+ headers: headers,
32
+ url: BASE_URL
33
+ }
34
+ end
35
+ end
36
+ end
37
+
38
+ # CURENCY https://iss.moex.com/iss/statistics/engines/currency/markets/selt/rates.json?iss.meta=off&iss.json=extended&iss.only=wap_rates
39
+
40
+ # STOCKS ALL https://iss.moex.com/iss/engines/stock/markets/shares/boards/tqbr/securities.json?iss.meta=off&iss.json=extended&iss.only=securities,marketdata&marketdata.columns=BID,OPEN,CLOSEPRICE,LOW,HIGH,LAST,VALUE,MARKETPRICETODAY,MARKETPRICE,TIME&securities.columns=SECID,SHORTNAME,LATNAME,BOARDID,BOARDNAME,ISIN,PREVPRICE
41
+
42
+ # STOCK ONE https://iss.moex.com/iss/engines/stock/markets/shares/boards/tqbr/securities/sber.json?iss.meta=off&iss.json=extended&iss.only=securities,marketdata&marketdata.columns=BID,OPEN,CLOSEPRICE,LOW,HIGH,LAST,VALUE,MARKETPRICETODAY,MARKETPRICE,TIME&securities.columns=SECID,SHORTNAME,LATNAME,BOARDID,BOARDNAME,ISIN,PREVPRICE
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ class Error < StandardError
5
+ ResponseSchemaError = Class.new(self)
6
+ ResponseParseError = Class.new(self)
7
+
8
+ ClientError = Class.new(self)
9
+ ServerError = Class.new(self)
10
+
11
+ BadRequest = Class.new(ClientError)
12
+ Unauthorized = Class.new(ClientError)
13
+ NotAcceptable = Class.new(ClientError)
14
+ NotFound = Class.new(ClientError)
15
+ Conflict = Class.new(ClientError)
16
+ TooManyRequests = Class.new(ClientError)
17
+ Forbidden = Class.new(ClientError)
18
+ Locked = Class.new(ClientError)
19
+ MethodNotAllowed = Class.new(ClientError)
20
+
21
+ NotImplemented = Class.new(ServerError)
22
+ BadGateway = Class.new(ServerError)
23
+ ServiceUnavailable = Class.new(ServerError)
24
+ GatewayTimeout = Class.new(ServerError)
25
+
26
+ ERRORS = {
27
+ 400 => MoexIss::Error::BadRequest,
28
+ 401 => MoexIss::Error::Unauthorized,
29
+ 403 => MoexIss::Error::Forbidden,
30
+ 404 => MoexIss::Error::NotFound,
31
+ 405 => MoexIss::Error::MethodNotAllowed,
32
+ 406 => MoexIss::Error::NotAcceptable,
33
+ 409 => MoexIss::Error::Conflict,
34
+ 423 => MoexIss::Error::Locked,
35
+ 429 => MoexIss::Error::TooManyRequests,
36
+ 500 => MoexIss::Error::ServerError,
37
+ 502 => MoexIss::Error::BadGateway,
38
+ 503 => MoexIss::Error::ServiceUnavailable,
39
+ 504 => MoexIss::Error::GatewayTimeout
40
+ }.freeze
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Hendler
5
+ def handle_response(response)
6
+ return standard_hendler(response) if standard_schema?(response)
7
+
8
+ fail MoexIss::Error::ResponseSchemaError, "Неизвестная схема ответа"
9
+ end
10
+
11
+ private
12
+
13
+ def standard_schema?(response)
14
+ response.is_a?(Array) &&
15
+ response[1]&.keys == %w[securities marketdata] &&
16
+ response[1]["securities"].is_a?(Array) &&
17
+ response[1]["marketdata"].is_a?(Array)
18
+ end
19
+
20
+ def standard_hendler(response)
21
+ response[1]["securities"].map.with_index do |x, i|
22
+ {"securities" => x, "marketdata" => response[1]["marketdata"][i]}
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ class Stock
6
+ METHODS = {
7
+ "BID" => :bid, "MARKETPRICETODAY" => :market_price_today,
8
+ "MARKETPRICE" => :market_price, "SECID" => :secid,
9
+ "SHORTNAME" => :short_name, "LATNAME" => :lat_name,
10
+ "BOARDID" => :board_id, "BOARDNAME" => :board_name,
11
+ "ISIN" => :isin, "PREVPRICE" => :prev_price,
12
+ "PREVDATE" => :prev_date
13
+ }.freeze
14
+
15
+ MARKET_DATA = %w[CLOSEPRICE OPEN LOW HIGH LAST VALUE SYSTIME]
16
+
17
+ attr_reader(:response, :market_data, *METHODS.values)
18
+
19
+ def initialize(response)
20
+ @response = response.is_a?(Array) ? response.first : response
21
+
22
+ @response["securities"].merge(@response["marketdata"]).each do |key, value|
23
+ next unless METHODS.has_key?(key)
24
+
25
+ instance_variable_set("@#{METHODS[key]}", value)
26
+ end
27
+
28
+ @market_data = @response["marketdata"].slice(*MARKET_DATA)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ class Stocks
6
+ include Enumerable
7
+
8
+ attr_reader :stocks_response
9
+
10
+ def initialize(stocks_response)
11
+ @stocks_response = stocks_response
12
+ @stocks_map = {}
13
+
14
+ create_instances_stock
15
+ end
16
+
17
+ def create_instances_stock
18
+ @stocks_response.each do |stock_response|
19
+ sicid = stock_response["securities"]["SECID"].downcase.to_sym
20
+
21
+ @stocks_map[sicid] = Stock.new(stock_response)
22
+
23
+ self.class.send(:define_method, sicid) { @stocks_map[sicid] }
24
+ end
25
+ end
26
+
27
+ def each
28
+ @stocks_map.values.each { |stock| yield stock }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Request
5
+ include MoexIss::Connection
6
+
7
+ def get(path, params = {})
8
+ respond_with(connection.get(path, params))
9
+ end
10
+
11
+ private
12
+
13
+ def respond_with(raw_response)
14
+ return if raw_response.body.empty?
15
+
16
+ respond_with_error(raw_response.status, raw_response.body) if !raw_response.success?
17
+
18
+ JSON.parse(raw_response.body)
19
+ rescue JSON::ParserError
20
+ raise MoexIss::Error::ResponseParseError, "Ошибка парсинга json из ответа"
21
+ end
22
+
23
+ def respond_with_error(code, body)
24
+ raise(MoexIss::Error, body) unless MoexIss::Error::ERRORS.key?(code)
25
+
26
+ raise MoexIss::Error::ERRORS[code], body
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss # :nodoc:
4
+ VERSION = "1.0.0"
5
+ end
data/lib/moex_iss.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+ require "zeitwerk"
6
+
7
+ loader = Zeitwerk::Loader.for_gem
8
+ loader.setup
9
+
10
+ module MoexIss
11
+ def self.client
12
+ MoexIss::Client.new
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moex_iss
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Vyacheslav Konovalov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-12-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.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.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 2.8.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.8.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: zeitwerk
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.6.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.6.1
83
+ description:
84
+ email:
85
+ - goplit2010.konovalov@yandex.ru
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files:
89
+ - README.md
90
+ files:
91
+ - CHANGELOG.md
92
+ - LICENSE.txt
93
+ - README.md
94
+ - lib/moex_iss.rb
95
+ - lib/moex_iss/client.rb
96
+ - lib/moex_iss/connection.rb
97
+ - lib/moex_iss/error.rb
98
+ - lib/moex_iss/hendler.rb
99
+ - lib/moex_iss/market/stock.rb
100
+ - lib/moex_iss/market/stocks.rb
101
+ - lib/moex_iss/request.rb
102
+ - lib/moex_iss/version.rb
103
+ homepage: https://github.com/K0Hb/moex_iss
104
+ licenses:
105
+ - MIT
106
+ metadata:
107
+ bug_tracker_uri: https://github.com/K0Hb/moex_iss/issues
108
+ changelog_uri: https://github.com/K0Hb/moex_iss/blob/master/CHANGELOG.md
109
+ documentation_uri: https://github.com/K0Hb/moex_iss
110
+ homepage_uri: https://github.com/K0Hb/moex_iss
111
+ source_code_uri: https://github.com/K0Hb/moex_iss
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '2.7'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.5.3
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Client for MOEX ISS API
131
+ test_files: []