moex_iss 1.0.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
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