moex_iss 1.0.1 → 1.1.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: e2a3f9ad4ce42c5fe38d5b16bf09ec3d937654cf12225360c2c24f4a16b0322a
4
+ data.tar.gz: fa3d5358f2ce99cf174c31a1eb27da86f2ba827d632bcd1214e19cd356080431
5
5
  SHA512:
6
- metadata.gz: 6d1e0e7e037c4e3a9ebf7ce0ca08f52f89795ba9c09fa96c14d5b8c13aa532cad30179abd8d2f4230fff0b5347d457226dd165ca46c268eefbc0d2aff49e2096
7
- data.tar.gz: 0e87922f366dbcaba06a5ceb04598ad86405ce29903193adfe604e00f5daa434756533804846c5973da2629ea02c10e305d852fad43c87c0097b3e146b43b3ac
6
+ metadata.gz: 5a9374940f414e6309bbb3fa1249c1406fb34932deeeb33d50a99c762faffede6a063dd891fa4fac96ec479da194c4dff5c8af5b7c81335cfe29243d40a268e9
7
+ data.tar.gz: feee8548808c648d93726e2a79ac4240f15bd9afd4f469f7123cc743a714e8d12a56ea7d2147d4e42c9b9328fc492d07bb0ac0e048ca390ca3ac7cdb39984f47
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
1
  # Change log
2
+ Все важные изменения в этом проекте будут задокументированы в этом файле.
2
3
 
3
- ## master
4
+ Формат основан на ведении журнала изменений, и этот проект придерживается семантического управления версиями.
5
+ ## [1.1.0] - 2023-12-30
6
+ ### Добавлено
7
+ - Возможность работы с историческими данными акции
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
 
@@ -39,23 +39,41 @@ client = MoexIss.client
39
39
 
40
40
  ### Акции
41
41
 
42
- Для получения одной акций:
42
+ Для получения последних актульных данных:
43
+ - Все акции
44
+ ```ruby
45
+ client.stocks # => MoexIss::Market::Stocks
46
+ ```
47
+ Получаем класс, по которому можно итерироваться а так же вызывать искомую ценную бумагу по ее `isin`
48
+ ```ruby
49
+ stocks.sber # => MoexIss::Market::Stock
50
+ ```
51
+ - Одна Акция
43
52
  ```ruby
44
53
  client.stock(:sber) # => MoexIss::Market::Stock
45
54
  ```
46
- Для получения всех акций:
55
+ + Для получения данные об исторических данных:
47
56
  ```ruby
48
- client.stocks # => MoexIss::Market::Stocks
57
+ client.stock(:sber, from: '2023-12-01', till: '2023-12-05') # => MoexIss::Market::History::Stocks
49
58
  ```
50
- Получаем класс, по которому можно итерироваться а так же вызывать искомую ценную бумагу по ее `isin`
59
+ Есть возможность работы с коллекцией через дату:
51
60
  ```ruby
52
- stocks.sber
61
+ stocks = client.stock(:sber, from: '2023-12-01', till: '2023-12-05') # => MoexIss::Market::History::Stocks
62
+ stocks['2023-12-03'] # => MoexIss::Market::History::Stock
53
63
  ```
54
- Экземпляр класса `MoexIss::Market::Stocks` отвечает на методы:
64
+ Максимальное количесво дней: _100_
65
+
66
+ Аргументы `from` и `till` можно использовать по одиночке
67
+
68
+
69
+ Все экземпляры классов отвечает на метод `response`, который содержит полный ответ от MOEX ISS, из которого можно получать доп.параметры,
70
+ так же у кажого класса свой набор спецефических методов для удобства работы с данными.
55
71
  ```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]
72
+ # Пример
73
+ client.stock(:sber).market_price # => 271.37
74
+ client.stock(:sber).prev_date # => 2023-12-2
75
+ ...
57
76
  ```
58
- где `response` содержит полный ответ от MOEX ISS, из которого можно получать доп.параметры
59
77
 
60
78
 
61
79
  ## Лицензия
@@ -21,7 +21,9 @@ module MoexIss
21
21
  MoexIss::Market::Stocks.new(handle_response(raw_response))
22
22
  end
23
23
 
24
- def stock(isin)
24
+ def stock(isin, from: nil, till: nil)
25
+ return historical_data_of_the_stock(isin, from, till) if from || till
26
+
25
27
  endpoint = "#{STOCKS_ENDPOINT}/#{isin}.json"
26
28
  params = STANDARD_PARAMS
27
29
 
@@ -29,5 +31,25 @@ module MoexIss
29
31
 
30
32
  MoexIss::Market::Stock.new(handle_response(raw_response))
31
33
  end
34
+
35
+ private
36
+
37
+ def historical_data_of_the_stock(isin, from, till)
38
+ validate_date(from, till) if from || till
39
+
40
+ endpoint = "history/#{STOCKS_ENDPOINT}/#{isin}.json"
41
+ params = STANDARD_PARAMS.merge({from: from, till: till})
42
+
43
+ raw_response = get(endpoint, params)
44
+
45
+ MoexIss::Market::History::Stocks.new(handle_response(raw_response))
46
+ end
47
+
48
+ def validate_date(*dates)
49
+ error = Error::InvalidDateError
50
+ message = "Невалидная дата"
51
+
52
+ dates.compact.each { |date| date.match?(/^\d{4}-\d{2}-\d{2}$/) ? nil : fail(error, message) }
53
+ end
32
54
  end
33
55
  end
@@ -36,7 +36,3 @@ module MoexIss
36
36
  end
37
37
 
38
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,7 @@ module MoexIss
4
4
  module Hendler
5
5
  def handle_response(response)
6
6
  return standard_hendler(response) if standard_schema?(response)
7
+ return history_hendler(response) if history_schema?(response)
7
8
 
8
9
  fail MoexIss::Error::ResponseSchemaError, "Неизвестная схема ответа"
9
10
  end
@@ -17,10 +18,18 @@ module MoexIss
17
18
  response[1]["marketdata"].is_a?(Array)
18
19
  end
19
20
 
21
+ def history_schema?(response)
22
+ response.is_a?(Array) && response[1]&.has_key?("history")
23
+ end
24
+
20
25
  def standard_hendler(response)
21
26
  response[1]["securities"].map.with_index do |x, i|
22
27
  {"securities" => x, "marketdata" => response[1]["marketdata"][i]}
23
28
  end
24
29
  end
30
+
31
+ def history_hendler(response)
32
+ response[1]
33
+ end
25
34
  end
26
35
  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,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MoexIss
4
+ module Market
5
+ module History
6
+ class Stocks < MoexIss::Market::Stocks
7
+ def create_instances_stock
8
+ @response["history"].each do |data|
9
+ @stocks_map[data["TRADEDATE"]] = History::Stock.new({"history" => data})
10
+ end
11
+ end
12
+
13
+ def [](key)
14
+ @stocks_map[key]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ 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
@@ -5,28 +5,34 @@ module MoexIss
5
5
  class Stocks
6
6
  include Enumerable
7
7
 
8
- attr_reader :stocks_response
8
+ attr_reader :response
9
9
 
10
- def initialize(stocks_response)
11
- @stocks_response = stocks_response
10
+ def initialize(response)
11
+ @response = response
12
12
  @stocks_map = {}
13
13
 
14
14
  create_instances_stock
15
15
  end
16
16
 
17
17
  def create_instances_stock
18
- @stocks_response.each do |stock_response|
19
- sicid = stock_response["securities"]["SECID"].downcase.to_sym
18
+ @response.each do |data|
19
+ method = data["securities"]["SECID"].downcase.to_sym
20
20
 
21
- @stocks_map[sicid] = Stock.new(stock_response)
22
-
23
- self.class.send(:define_method, sicid) { @stocks_map[sicid] }
21
+ setup_method(method, data)
24
22
  end
25
23
  end
26
24
 
27
25
  def each
28
26
  @stocks_map.values.each { |stock| yield stock }
29
27
  end
28
+
29
+ private
30
+
31
+ def setup_method(method, data)
32
+ @stocks_map[method] = Stock.new(data)
33
+
34
+ self.class.send(:define_method, method) { @stocks_map[method] }
35
+ end
30
36
  end
31
37
  end
32
38
  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.1.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.1.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: 2023-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -96,6 +96,8 @@ 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/history/stock.rb
100
+ - lib/moex_iss/market/history/stocks.rb
99
101
  - lib/moex_iss/market/stock.rb
100
102
  - lib/moex_iss/market/stocks.rb
101
103
  - lib/moex_iss/request.rb