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.
- {moexapi-1.7.15 → moexapi-1.7.17}/PKG-INFO +1 -1
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/candles.py +28 -7
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/history.py +22 -3
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi.egg-info/PKG-INFO +1 -1
- {moexapi-1.7.15 → moexapi-1.7.17}/pyproject.toml +1 -1
- {moexapi-1.7.15 → moexapi-1.7.17}/LICENSE +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/README.md +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/__init__.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/bonds.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/changeover.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/dividends.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/exchange.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/markets.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/splits.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/tickers.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi/utils.py +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi.egg-info/SOURCES.txt +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi.egg-info/dependency_links.txt +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi.egg-info/requires.txt +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/moexapi.egg-info/top_level.txt +0 -0
- {moexapi-1.7.15 → moexapi-1.7.17}/setup.cfg +0 -0
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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]
|
|
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)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|