moexapi 1.6.42__tar.gz → 1.6.43__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.6.42 → moexapi-1.6.43}/PKG-INFO +1 -1
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/bonds.py +48 -1
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi.egg-info/PKG-INFO +1 -1
- {moexapi-1.6.42 → moexapi-1.6.43}/pyproject.toml +1 -1
- {moexapi-1.6.42 → moexapi-1.6.43}/LICENSE +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/README.md +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/__init__.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/candles.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/changeover.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/dividends.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/exchange.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/history.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/markets.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/splits.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/tickers.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi/utils.py +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi.egg-info/SOURCES.txt +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi.egg-info/dependency_links.txt +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi.egg-info/requires.txt +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/moexapi.egg-info/top_level.txt +0 -0
- {moexapi-1.6.42 → moexapi-1.6.43}/setup.cfg +0 -0
|
@@ -7,6 +7,9 @@ from . import tickers
|
|
|
7
7
|
from . import utils
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
logger = utils.initialize_logging(__file__)
|
|
11
|
+
|
|
12
|
+
|
|
10
13
|
def _max(first, second):
|
|
11
14
|
if first is not None and second is not None:
|
|
12
15
|
return max(first, second)
|
|
@@ -120,13 +123,57 @@ class Bond:
|
|
|
120
123
|
self.amortization = [item for item in self.amortization if item.date != start_date]
|
|
121
124
|
self.coupons = [item for item in self.coupons if item.date != start_date]
|
|
122
125
|
self.offers = [item for item in self.offers if item.date != start_date]
|
|
126
|
+
original_values = [item.value for item in self.amortization]
|
|
127
|
+
amortization_sum = sum(original_values)
|
|
128
|
+
if abs(amortization_sum - self.initial_face_value) > 1e-9:
|
|
129
|
+
values = [value / amortization_sum * self.initial_face_value for value in original_values]
|
|
130
|
+
rounded_values = [round(value + 1e-9, 2) for value in values]
|
|
131
|
+
for original_value, rounded_value in zip(original_values, rounded_values):
|
|
132
|
+
if abs(original_value - rounded_value) > 1e-9:
|
|
133
|
+
logger.error(f"Original value {original_value} is not equal to rounded value {rounded_value}")
|
|
134
|
+
raise ValueError(f"Amortization sum {amortization_sum} is greater than initial face value {self.initial_face_value}")
|
|
135
|
+
for amortization_item, value in zip(self.amortization, values):
|
|
136
|
+
amortization_item.value = value
|
|
123
137
|
except Exception as e:
|
|
124
|
-
|
|
138
|
+
logger.error(f"{ticker.secid} ({ticker.shortname}): {e}")
|
|
139
|
+
raise e
|
|
125
140
|
|
|
126
141
|
@property
|
|
127
142
|
def expiration_date(self) -> datetime.date:
|
|
128
143
|
return max(item.date for item in self.amortization + self.coupons + self.offers)
|
|
129
144
|
|
|
145
|
+
def __repr__(self) -> str:
|
|
146
|
+
lines = [
|
|
147
|
+
f"Bond({self.secid})",
|
|
148
|
+
f" name: {self.name}",
|
|
149
|
+
f" shortname: {self.shortname}",
|
|
150
|
+
f" issue_date: {self.issue_date}",
|
|
151
|
+
f" mat_date: {self.mat_date}",
|
|
152
|
+
f" initial_face_value: {self.initial_face_value}",
|
|
153
|
+
f" face_value: {self.face_value}",
|
|
154
|
+
f" start_date_moex: {self.start_date_moex}",
|
|
155
|
+
f" early_repayment: {self.early_repayment}",
|
|
156
|
+
f" days_to_redemption: {self.days_to_redemption}",
|
|
157
|
+
f" issue_size: {self.issue_size:,}",
|
|
158
|
+
f" is_qualified_investors:{' ' if not self.is_qualified_investors else ''}{self.is_qualified_investors}",
|
|
159
|
+
f" coupon_frequency: {self.coupon_frequency}",
|
|
160
|
+
f" evening_session: {self.evening_session}",
|
|
161
|
+
f" coupon_percent: {self.coupon_percent}",
|
|
162
|
+
]
|
|
163
|
+
if self.amortization:
|
|
164
|
+
lines.append(f" amortization ({len(self.amortization)}):")
|
|
165
|
+
for a in self.amortization:
|
|
166
|
+
lines.append(f" {a.date} value={a.value} face={a.initialfacevalue}")
|
|
167
|
+
if self.coupons:
|
|
168
|
+
lines.append(f" coupons ({len(self.coupons)}):")
|
|
169
|
+
for c in self.coupons:
|
|
170
|
+
lines.append(f" {c.date} value={c.value}")
|
|
171
|
+
if self.offers:
|
|
172
|
+
lines.append(f" offers ({len(self.offers)}):")
|
|
173
|
+
for o in self.offers:
|
|
174
|
+
lines.append(f" {o.date} value={o.value}")
|
|
175
|
+
return "\n".join(lines)
|
|
176
|
+
|
|
130
177
|
def next_offer(self, date_from: T.Optional[datetime.date] = None) -> T.Optional[Offer]:
|
|
131
178
|
date_from = date_from or datetime.date.today()
|
|
132
179
|
result = [offer for offer in self.offers if offer.date >= date_from]
|
|
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
|
|
File without changes
|