moexapi 1.7.15__tar.gz → 1.7.17__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moexapi
3
- Version: 1.7.15
3
+ Version: 1.7.17
4
4
  Summary: Python API for MOEX ISS
5
5
  Author-email: Aliaksei Rak <kventinel@gmail.com>
6
6
  License: MIT License
@@ -22,7 +22,8 @@ class Candle:
22
22
  open -- open price of the day
23
23
  close -- close price of the day
24
24
  volume -- number of shares/bonds/currencies sold on the day
25
- value -- sum of all transactions in RUB for the day
25
+ value -- sum of all transactions in currency for the day
26
+ currency -- currency of transaction value
26
27
  """
27
28
  start: datetime.datetime
28
29
  end: datetime.datetime
@@ -32,9 +33,11 @@ class Candle:
32
33
  close: float
33
34
  volume: T.Optional[int]
34
35
  value: T.Optional[float]
36
+ currency: T.Optional[str] = None
35
37
 
36
38
  @classmethod
37
39
  def merge(cls, first: 'Candle', second: 'Candle'):
40
+ assert first.currency == second.currency, "Can't merge candles in different currencies"
38
41
  if second.start < first.start:
39
42
  start = second.start
40
43
  open = second.open
@@ -56,6 +59,7 @@ class Candle:
56
59
  close=close,
57
60
  volume=first.volume + second.volume,
58
61
  value=first.value + second.value,
62
+ currency=first.currency,
59
63
  )
60
64
 
61
65
  def mult(self, mult: float) -> None:
@@ -67,7 +71,10 @@ class Candle:
67
71
  self.volume /= mult
68
72
 
69
73
 
70
- def _merge_candles(first: list[Candle], second: list[Candle]) -> list[Candle]:
74
+ def _merge_candles(
75
+ first: list[Candle], second: list[Candle], preferred_currency: T.Optional[str] = None,
76
+ ) -> list[Candle]:
77
+ preferred_currency = tickers._sur_to_rub(preferred_currency)
71
78
  i = 0
72
79
  j = 0
73
80
  result: list[Candle] = []
@@ -79,7 +86,18 @@ def _merge_candles(first: list[Candle], second: list[Candle]) -> list[Candle]:
79
86
  result.append(second[j])
80
87
  j += 1
81
88
  else:
82
- result.append(Candle.merge(first[i], second[j]))
89
+ if first[i].currency == second[j].currency:
90
+ result.append(Candle.merge(first[i], second[j]))
91
+ elif second[j].currency == preferred_currency:
92
+ result.append(second[j])
93
+ elif first[i].currency == preferred_currency:
94
+ result.append(first[i])
95
+ else:
96
+ raise ValueError(
97
+ f"Can't select candle currency at {first[i].start}: "
98
+ f"{first[i].currency} and {second[j].currency}; "
99
+ f"preferred currency is {preferred_currency}"
100
+ )
83
101
  i += 1
84
102
  j += 1
85
103
  if i < len(first):
@@ -89,12 +107,14 @@ def _merge_candles(first: list[Candle], second: list[Candle]) -> list[Candle]:
89
107
  return result
90
108
 
91
109
 
92
- def _merge_candles_list(candles: list[list[Candle]]) -> list[Candle]:
110
+ def _merge_candles_list(
111
+ candles: list[list[Candle]], preferred_currency: T.Optional[str] = None,
112
+ ) -> list[Candle]:
93
113
  if len(candles) == 0:
94
114
  return []
95
115
  result = candles[0]
96
116
  for idx in range(1, len(candles)):
97
- result = _merge_candles(result, candles[idx])
117
+ result = _merge_candles(result, candles[idx], preferred_currency)
98
118
  return result
99
119
 
100
120
 
@@ -141,6 +161,7 @@ def _parse_candles_one_board(
141
161
  close=close,
142
162
  volume=line.get("volume"),
143
163
  value=line.get("value"),
164
+ currency=tickers._sur_to_rub(ticker.currency),
144
165
  )
145
166
  )
146
167
  if len(candles) == 0:
@@ -159,7 +180,7 @@ def _parse_candles(
159
180
  candles.append(
160
181
  _parse_candles_one_board(ticker, board, start_date=start_date, end_date=end_date, interval=interval)
161
182
  )
162
- return _merge_candles_list(candles)
183
+ return _merge_candles_list(candles, ticker.currency)
163
184
 
164
185
 
165
186
  def get_candles(
@@ -174,7 +195,7 @@ def get_candles(
174
195
  candles = []
175
196
  for t in prev_tickers:
176
197
  candles.append(_parse_candles(t, start_date=start_date, end_date=end_date, interval=interval))
177
- result = _merge_candles_list(candles)
198
+ result = _merge_candles_list(candles, ticker.currency)
178
199
  for split in ticker_splits:
179
200
  for candle in result:
180
201
  if candle.end.date() < split.date:
@@ -38,7 +38,8 @@ class History:
38
38
  mid_price -- weighted average price of the day
39
39
  numtrades -- number of trades for the day
40
40
  volume -- number of shares/bonds/currencies sold on the day
41
- value -- sum of all transactions in RUB for the day
41
+ value -- sum of all transactions in currency for the day
42
+ currency -- currency of transaction value
42
43
  """
43
44
  date: datetime.date
44
45
  low: float
@@ -49,10 +50,12 @@ class History:
49
50
  numtrades: int
50
51
  volume: T.Optional[int]
51
52
  value: T.Optional[float]
53
+ currency: T.Optional[str] = None
52
54
 
53
55
  @classmethod
54
56
  def merge(cls, first: 'History', second: 'History'):
55
57
  assert first.date == second.date
58
+ assert first.currency == second.currency, "Can't merge history in different currencies"
56
59
  return cls(
57
60
  date=first.date,
58
61
  low=min(first.low, second.low),
@@ -63,6 +66,7 @@ class History:
63
66
  numtrades=first.numtrades + second.numtrades,
64
67
  volume=_maybe_sum(first.volume, second.volume),
65
68
  value=_maybe_sum(first.value, second.value),
69
+ currency=first.currency,
66
70
  )
67
71
 
68
72
  def mult(self, mult: float) -> None:
@@ -109,8 +113,12 @@ def _parse_history(
109
113
  start_date: T.Optional[datetime.date] = None,
110
114
  end_date: T.Optional[datetime.date] = None,
111
115
  ) -> list[History]:
116
+ # Bond denomination and board settlement currency can differ. Keep one
117
+ # turnover currency per day, preferring the ticker currency when available.
118
+ preferred_currency = tickers._sur_to_rub(ticker.currency)
112
119
  result: list[History] = []
113
120
  prev_date = start_date
121
+ boards = []
114
122
  while True:
115
123
  start_str = f"from={start_date.isoformat()}" if start_date else ""
116
124
  end_str = f"till={end_date.isoformat()}" if end_date else ""
@@ -118,7 +126,6 @@ def _parse_history(
118
126
  url = f"https://iss.moex.com/iss/history{ticker.market.path}/securities/{ticker.secid}.json{query}"
119
127
  response = utils.json_api_call(url)
120
128
  history = utils.prepare_dict(response, "history")
121
- boards = []
122
129
  for line in history:
123
130
  board = line["BOARDID"]
124
131
  if ticker.boards and board not in ticker.boards:
@@ -134,8 +141,10 @@ def _parse_history(
134
141
  if low == 0.0 or high == 0.0 or open == 0.0 or close == 0.0:
135
142
  continue
136
143
  value = line.get("VALUE")
144
+ currency = tickers._sur_to_rub(line.get("CURRENCYID") or ticker.currency)
137
145
  if ticker.market == markets.Markets.CURRENCY:
138
146
  value = line.get("VOLRUR")
147
+ currency = "RUB"
139
148
  item = History(
140
149
  date=date,
141
150
  low=low,
@@ -146,12 +155,22 @@ def _parse_history(
146
155
  numtrades=line.get("NUMTRADES") or 0,
147
156
  volume=line.get("VOLUME"),
148
157
  value=value,
158
+ currency=currency,
149
159
  )
150
160
  if len(result) > 0 and result[-1].date == date:
151
161
  if board in boards:
152
162
  continue
153
163
  boards.append(board)
154
- result[-1] = History.merge(result[-1], item)
164
+ if result[-1].currency == item.currency:
165
+ result[-1] = History.merge(result[-1], item)
166
+ elif item.currency == preferred_currency:
167
+ result[-1] = item
168
+ elif result[-1].currency != preferred_currency:
169
+ raise ValueError(
170
+ f"Can't select history currency for {ticker.secid} on {date}: "
171
+ f"{result[-1].currency} and {item.currency}; "
172
+ f"preferred currency is {preferred_currency}"
173
+ )
155
174
  else:
156
175
  boards = [board]
157
176
  result.append(item)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moexapi
3
- Version: 1.7.15
3
+ Version: 1.7.17
4
4
  Summary: Python API for MOEX ISS
5
5
  Author-email: Aliaksei Rak <kventinel@gmail.com>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "moexapi"
7
- version = "1.7.15"
7
+ version = "1.7.17"
8
8
  description = "Python API for MOEX ISS"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Aliaksei Rak", email = "kventinel@gmail.com" }]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes