moex_iss 1.0.1 → 1.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 931ab0fc8f2e2b3a7f04baa97c08b7078040dd278e461d3743b4128661a33dc1
4
- data.tar.gz: 555072f46a7e8298f0424fcb199c9a9000a4eed80981c148e8b748e94fbeda42
3
+ metadata.gz: 71d87cc339f313c78295e2d5d3569aade22989f93ecef8cf27fcfde8cb151562
4
+ data.tar.gz: '0181b5dc0b1e9e01b93a685ce68bee1a84767c354b35ac27d3b50f48eeff2b5c'
5
5
  SHA512:
6
- metadata.gz: 6d1e0e7e037c4e3a9ebf7ce0ca08f52f89795ba9c09fa96c14d5b8c13aa532cad30179abd8d2f4230fff0b5347d457226dd165ca46c268eefbc0d2aff49e2096
7
- data.tar.gz: 0e87922f366dbcaba06a5ceb04598ad86405ce29903193adfe604e00f5daa434756533804846c5973da2629ea02c10e305d852fad43c87c0097b3e146b43b3ac
6
+ metadata.gz: d5fc0c6b4c6884de71e79c727bb0c5a9923038783736a10f2d0806eef5c765f5cd50dd9f45ce7670cf08dda27279118dee7766d0baca73e1ac1428dcbb9f8165
7
+ data.tar.gz: f6281f2e0f278f577bacdbd179ed3bb7ddd7db31a5ebefc89453de63c5f49235a1658a6e2440cd2cbb387cc3621781d0fdd14866fe7eed2c625d7b98cc8a0568
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
1
  # Change log
2
+ Все важные изменения в этом проекте будут задокументированы в этом файле.
2
3
 
3
- ## master
4
+ Формат основан на ведении журнала изменений, и этот проект придерживается семантического управления версиями.
5
+ ## [1.1.0] - 2023-12-30
6
+ ### Добавлено
7
+ - Возможность работы с историческими данными акции
8
+ ## [1.11.0] - 2024-01-03
9
+ ### Добавлено
10
+ - Возможность получать данные об актуальных курсах валют ЦБ РФ
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Gem Version](https://badge.fury.io/rb/moex_iss.svg)](https://rubygems.org/gems/moex_iss)
1
+ [![Gem Version](https://badge.fury.io/rb/moex_iss.svg)](https://badge.fury.io/rb/moex_iss)
2
2
  [![Build](https://github.com/K0Hb/moex_iss/workflows/Build/badge.svg)](https://github.com/palkan/moex_iss/actions)
3
3
  [![JRuby Build](https://github.com/K0Hb/moex_iss/workflows/JRuby%20Build/badge.svg)](https://github.com/K0Hb/moex_iss/actions)
4
4
 
@@ -37,25 +37,54 @@ gem "moex_iss"
37
37
  client = MoexIss.client
38
38
  ```
39
39
 
40
+ ### Валюты
41
+ Для получения последних актульных данных о курсах валют:
42
+ ```ruby
43
+ currencies = client.currencies # => MoexIss::Market::Currencies
44
+
45
+ cny_rub = currencues.cny_rub # => MoexIss::Market::Currency
46
+ cny_urb.price = 12.5762
47
+ ...
48
+ ```
49
+
40
50
  ### Акции
41
51
 
42
- Для получения одной акций:
52
+ Для получения последних актульных данных:
53
+ - Все акции
54
+ ```ruby
55
+ client.stocks # => MoexIss::Market::Stocks
56
+ ```
57
+ Получаем класс, по которому можно итерироваться а так же вызывать искомую ценную бумагу по ее `isin`
58
+ ```ruby
59
+ stocks.sber # => MoexIss::Market::Stock
60
+ ```
61
+ - Одна Акция
43
62
  ```ruby
44
63
  client.stock(:sber) # => MoexIss::Market::Stock
45
64
  ```
46
- Для получения всех акций:
65
+ + Для получения данные об исторических данных:
47
66
  ```ruby
48
- client.stocks # => MoexIss::Market::Stocks
67
+ client.stock(:sber, from: '2023-12-01', till: '2023-12-05') # => MoexIss::Market::History::Stocks
49
68
  ```
50
- Получаем класс, по которому можно итерироваться а так же вызывать искомую ценную бумагу по ее `isin`
69
+ Есть возможность работы с коллекцией через дату:
51
70
  ```ruby
52
- stocks.sber
71
+ stocks = client.stock(:sber, from: '2023-12-01', till: '2023-12-05') # => MoexIss::Market::History::Stocks
72
+ stocks['2023-12-03'] # => MoexIss::Market::History::Stock
53
73
  ```
54
- Экземпляр класса `MoexIss::Market::Stocks` отвечает на методы:
74
+ Максимальное количесво дней: _100_
75
+
76
+ Аргументы `from` и `till` можно использовать по одиночке
77
+
78
+ ### Обратите внимание
79
+
80
+ Все экземпляры классов отвечает на метод `response`, который содержит полный ответ от MOEX ISS, из которого можно получать доп.параметры,
81
+ так же у каждого класса свой набор специфических методов для удобства работы с данными.
55
82
  ```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]
83
+ # Пример
84
+ client.stock(:sber).market_price # => 271.37
85
+ client.stock(:sber).prev_date # => 2023-12-2
86
+ ...
57
87
  ```
58
- где `response` содержит полный ответ от MOEX ISS, из которого можно получать доп.параметры
59
88
 
60
89
 
61
90
  ## Лицензия
@@ -6,28 +6,62 @@ module MoexIss
6
6
  include MoexIss::Hendler
7
7
 
8
8
  STOCKS_ENDPOINT = "engines/stock/markets/shares/boards/tqbr/securities"
9
+ CURRENCIES_ENDPOINT = "statistics/engines/currency/markets/selt/rates"
9
10
  STANDARD_PARAMS = {
10
11
  "iss.json" => "extended",
11
- "iss.only" => "securities,marketdata",
12
12
  "iss.meta" => "off"
13
13
  }
14
14
 
15
15
  def stocks
16
16
  endpoint = "#{STOCKS_ENDPOINT}.json"
17
17
  params = STANDARD_PARAMS
18
+ params["iss.only"] = "securities,marketdata"
18
19
 
19
20
  raw_response = get(endpoint, params)
20
21
 
21
22
  MoexIss::Market::Stocks.new(handle_response(raw_response))
22
23
  end
23
24
 
24
- def stock(isin)
25
+ def stock(isin, from: nil, till: nil)
26
+ return historical_data_of_the_stock(isin, from, till) if from || till
27
+
25
28
  endpoint = "#{STOCKS_ENDPOINT}/#{isin}.json"
26
29
  params = STANDARD_PARAMS
30
+ params["iss.only"] = "securities,marketdata"
27
31
 
28
32
  raw_response = get(endpoint, params)
29
33
 
30
34
  MoexIss::Market::Stock.new(handle_response(raw_response))
31
35
  end
36
+
37
+ def currencies
38
+ endpoint = "#{CURRENCIES_ENDPOINT}.json"
39
+ params = STANDARD_PARAMS
40
+ params["iss.only"] = "wap_rates"
41
+
42
+ raw_response = get(endpoint, params)
43
+
44
+ MoexIss::Market::Currencies.new(handle_response(raw_response))
45
+ end
46
+
47
+ private
48
+
49
+ def historical_data_of_the_stock(isin, from, till)
50
+ validate_date(from, till) if from || till
51
+
52
+ endpoint = "history/#{STOCKS_ENDPOINT}/#{isin}.json"
53
+ params = STANDARD_PARAMS.merge({from: from, till: till})
54
+
55
+ raw_response = get(endpoint, params)
56
+
57
+ MoexIss::Market::History::Stocks.new(handle_response(raw_response))
58
+ end
59
+
60
+ def validate_date(*dates)
61
+ error = Error::InvalidDateError
62
+ message = "Невалидная дата"
63
+
64
+ dates.compact.each { |date| date.match?(/^\d{4}-\d{2}-\d{2}$/) ? nil : fail(error, message) }
65
+ end
32
66
  end
33
67
  end
@@ -34,9 +34,3 @@ module MoexIss
34
34
  end
35
35
  end
36
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
@@ -4,6 +4,7 @@ module MoexIss
4
4
  class Error < StandardError
5
5
  ResponseSchemaError = Class.new(self)
6
6
  ResponseParseError = Class.new(self)
7
+ InvalidDateError = Class.new(self)
7
8
 
8
9
  ClientError = Class.new(self)
9
10
  ServerError = Class.new(self)
@@ -4,6 +4,8 @@ module MoexIss
4
4
  module Hendler
5
5
  def handle_response(response)
6
6
  return standard_hendler(response) if standard_schema?(response)
7
+ return response[1] if history_schema?(response)
8
+ return response[1] if currencies_schema?(response)
7
9
 
8
10
  fail MoexIss::Error::ResponseSchemaError, "Неизвестная схема ответа"
9
11
  end
@@ -17,6 +19,14 @@ module MoexIss
17
19
  response[1]["marketdata"].is_a?(Array)
18
20
  end
19
21
 
22
+ def history_schema?(response)
23
+ response.is_a?(Array) && response[1]&.has_key?("history")
24
+ end
25
+
26
+ def currencies_schema?(response)
27
+ response.is_a?(Array) && response[1]&.has_key?("wap_rates")
28
+ end
29
+
20
30
  def standard_hendler(response)
21
31
  response[1]["securities"].map.with_index do |x, i|
22
32
  {"securities" => x, "marketdata" => response[1]["marketdata"][i]}
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ class Collection
6
+ include Enumerable
7
+
8
+ attr_reader :response
9
+
10
+ def initialize(response, instance_class: Security)
11
+ @response = response
12
+ @instance_class = instance_class
13
+ @stocks_map = {}
14
+
15
+ create_instances
16
+ end
17
+
18
+ def create_instances
19
+ @response.each do |data|
20
+ method = method_name(data)
21
+
22
+ setup_method(method, data)
23
+ end
24
+ end
25
+
26
+ def each
27
+ @stocks_map.values.each { |stock| yield stock }
28
+ end
29
+
30
+ private
31
+
32
+ def method_name(data)
33
+ :some_name
34
+ end
35
+
36
+ def setup_method(method, data)
37
+ @stocks_map[method] = @instance_class.new(data)
38
+
39
+ self.class.send(:define_method, method) { @stocks_map[method] }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ class Currencies < Collection
6
+ def initialize(response, instance_class: MoexIss::Market::Currency)
7
+ super
8
+ end
9
+
10
+ def create_instances
11
+ @response["wap_rates"].each do |data|
12
+ method = method_name(data)
13
+
14
+ setup_method(method, data)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def method_name(data)
21
+ data["shortname"]
22
+ .split("_")
23
+ .first.downcase
24
+ .insert(3, "_")
25
+ .to_sym
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ class Currency
6
+ METHODS = {
7
+ "tradedate" => :trade_date, "tradetime" => :trade_time,
8
+ "secid" => :secid, "shortname" => :short_name,
9
+ "price" => :price, "lasttoprevprice" => :last_top_rev_price,
10
+ "nominal" => :nominal, "decimals" => :decimals
11
+ }.freeze
12
+
13
+ attr_reader(:response, *METHODS.values)
14
+
15
+ def initialize(response)
16
+ @response = response
17
+
18
+ setup_instance_varibales(@response)
19
+ end
20
+
21
+ private
22
+
23
+ def setup_instance_varibales(data)
24
+ return if data.nil?
25
+
26
+ data.each do |key, value|
27
+ next unless METHODS.has_key?(key)
28
+
29
+ instance_variable_set("@#{METHODS[key]}", value)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ module History
6
+ class Stock
7
+ METHODS = {
8
+ "TRADEDATE" => :trade_date, "SHORTNAME" => :short_name, "SECID" => :secid, "VALUE" => :value,
9
+ "OPEN" => :open, "LOW" => :low, "HIGH" => :high, "LEGALCLOSEPRICE" => :legal_close_price,
10
+ "VOLUME" => :volume
11
+ }.freeze
12
+
13
+ attr_reader(:response, *METHODS.values)
14
+
15
+ def initialize(response)
16
+ @response = response
17
+
18
+ setup_instance_varibales(@response["history"])
19
+ end
20
+
21
+ private
22
+
23
+ def setup_instance_varibales(data)
24
+ return if data.nil?
25
+
26
+ data.each do |key, value|
27
+ next unless METHODS.has_key?(key)
28
+
29
+ instance_variable_set("@#{METHODS[key]}", value)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ module History
6
+ class Stocks < MoexIss::Market::Collection
7
+ def initialize(response, instance_class: MoexIss::Market::History::Stock)
8
+ super
9
+ end
10
+
11
+ def create_instances
12
+ @response["history"].each do |data|
13
+ @stocks_map[data["TRADEDATE"]] = History::Stock.new({"history" => data})
14
+ end
15
+ end
16
+
17
+ def [](key)
18
+ @stocks_map[key]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -19,13 +19,23 @@ module MoexIss
19
19
  def initialize(response)
20
20
  @response = response.is_a?(Array) ? response.first : response
21
21
 
22
- @response["securities"].merge(@response["marketdata"]).each do |key, value|
22
+ setup_instance_varibales(@response["securities"])
23
+ setup_instance_varibales(@response["marketdata"])
24
+ setup_instance_varibales(@response["history"])
25
+
26
+ @market_data = @response["marketdata"]&.slice(*MARKET_DATA)
27
+ end
28
+
29
+ private
30
+
31
+ def setup_instance_varibales(data)
32
+ return if data.nil?
33
+
34
+ data.each do |key, value|
23
35
  next unless METHODS.has_key?(key)
24
36
 
25
37
  instance_variable_set("@#{METHODS[key]}", value)
26
38
  end
27
-
28
- @market_data = @response["marketdata"].slice(*MARKET_DATA)
29
39
  end
30
40
  end
31
41
  end
@@ -2,30 +2,23 @@
2
2
 
3
3
  module MoexIss
4
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
5
+ class Stocks < Collection
6
+ def initialize(response, instance_class: MoexIss::Market::Stock)
7
+ super
15
8
  end
16
9
 
17
10
  def create_instances_stock
18
- @stocks_response.each do |stock_response|
19
- sicid = stock_response["securities"]["SECID"].downcase.to_sym
11
+ @response.each do |data|
12
+ method = method_name(data)
20
13
 
21
- @stocks_map[sicid] = Stock.new(stock_response)
22
-
23
- self.class.send(:define_method, sicid) { @stocks_map[sicid] }
14
+ setup_method(method, data)
24
15
  end
25
16
  end
26
17
 
27
- def each
28
- @stocks_map.values.each { |stock| yield stock }
18
+ private
19
+
20
+ def method_name(data)
21
+ data["securities"]["SECID"].downcase.to_sym
29
22
  end
30
23
  end
31
24
  end
@@ -21,9 +21,9 @@ module MoexIss
21
21
  end
22
22
 
23
23
  def respond_with_error(code, body)
24
- raise(MoexIss::Error, body) unless MoexIss::Error::ERRORS.key?(code)
24
+ fail(MoexIss::Error, body) unless MoexIss::Error::ERRORS.key?(code)
25
25
 
26
- raise MoexIss::Error::ERRORS[code], body
26
+ fail MoexIss::Error::ERRORS[code], body
27
27
  end
28
28
  end
29
29
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MoexIss # :nodoc:
4
- VERSION = "1.0.1"
4
+ VERSION = "1.11.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moex_iss
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vyacheslav Konovalov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-28 00:00:00.000000000 Z
11
+ date: 2024-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -96,6 +96,11 @@ files:
96
96
  - lib/moex_iss/connection.rb
97
97
  - lib/moex_iss/error.rb
98
98
  - lib/moex_iss/hendler.rb
99
+ - lib/moex_iss/market/collection.rb
100
+ - lib/moex_iss/market/currencies.rb
101
+ - lib/moex_iss/market/currency.rb
102
+ - lib/moex_iss/market/history/stock.rb
103
+ - lib/moex_iss/market/history/stocks.rb
99
104
  - lib/moex_iss/market/stock.rb
100
105
  - lib/moex_iss/market/stocks.rb
101
106
  - lib/moex_iss/request.rb
@@ -124,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
129
  - !ruby/object:Gem::Version
125
130
  version: '0'
126
131
  requirements: []
127
- rubygems_version: 3.5.3
132
+ rubygems_version: 3.1.6
128
133
  signing_key:
129
134
  specification_version: 4
130
135
  summary: Client for MOEX ISS API