{"id":310351,"date":"2020-09-23T03:00:10","date_gmt":"2020-09-23T03:00:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=310351"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=310351","title":{"rendered":"\u0424\u043e\u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430 Faust, \u0427\u0430\u0441\u0442\u044c II: \u0410\u0433\u0435\u043d\u0442\u044b \u0438 \u041a\u043e\u043c\u0430\u043d\u0434\u044b"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/520274\/\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/is\/mh\/8k\/ismh8kk9mjw7weuaopnqw07kp4m.jpeg\" width=\"1200\" height=\"751\"><figcaption><\/figcaption><\/figure>\n<h3>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/h3>\n<ol>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/519882\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c I: \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c II: \u0410\u0433\u0435\u043d\u0442\u044b \u0438 \u041a\u043e\u043c\u0430\u043d\u0434\u044b<\/p>\n<\/li>\n<\/ol>\n<h3>\u0427\u0442\u043e \u043c\u044b \u0442\u0443\u0442 \u0434\u0435\u043b\u0430\u0435\u043c?<\/h3>\n<p>\u0418\u0442\u0430\u043a-\u0438\u0442\u0430\u043a, \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c. \u041a\u0430\u043a \u0438 \u043f\u0438\u0441\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u0435\u0435, \u0432 \u043d\u0435\u0439 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u0438\u043a \u0434\u043b\u044f alphavantage \u043d\u0430 aiohttp \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0434\u0435\u043b\u0430\u0435\u043c \u0430\u0433\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433\u0430\u0445 \u0438 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u043d\u0438\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u043e, \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0430 \u0432 \u043f\u043b\u0430\u043d\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f faust \u043c\u044b \u0443\u0437\u043d\u0430\u0435\u043c, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u0442\u0440\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437 kafka, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b (\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430 click), \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0438 &#8212; \u0434\u043b\u044f \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043f\u0443\u0448\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u0438\u043a, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043b\u0435\u0434\u0438\u0442 \u0430\u0433\u0435\u043d\u0442.<\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<h4>\u041a\u043b\u0438\u0435\u043d\u0442 AlphaVantage<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 aiohttp \u043a\u043b\u0438\u0435\u043d\u0442\u0438\u043a \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430 alphavantage.<\/p>\n<p><a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/3b50581b3639ce7d6fe0d53edbf4ac0976f3fd67\/horton\/alphavantage.py\" rel=\"noopener noreferrer nofollow\">alphavantage.py<\/a><\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import urllib.parse as urlparse from io import StringIO from typing import Any, Dict, List, Union  import aiohttp import pandas as pd import stringcase from loguru import logger  from horton.config import API_ENDPOINT   class AlphaVantageClient:     def __init__(         self,         session: aiohttp.ClientSession,         api_key: str,         api_endpoint: str = API_ENDPOINT,     ):         self._query_params = {\"datatype\": \"json\", \"apikey\": api_key}         self._api_endpoint = api_endpoint         self._session = session      @logger.catch     def _format_fields(self, data: Dict[str, Any]) -&gt; Dict[str, Any]:         formatted_data = {}          for field, item in data.items():             formatted_data[stringcase.snakecase(field)] = item          return formatted_data      @logger.catch     async def _construct_query(         self, function: str, to_json: bool = True, **kwargs     ) -&gt; Union[Dict[str, Any], str]:         path = \"query\/\"          async with self._session.get(             urlparse.urljoin(self._api_endpoint, path),             params={\"function\": function, **kwargs, **self._query_params},         ) as response:             data = (await response.json()) if to_json else (await response.text())              if to_json:                 data = self._format_fields(data)          return data      @logger.catch     async def get_securities(self, state: str = \"active\") -&gt; List[Dict[str, str]]:         data = await self._construct_query(\"LISTING_STATUS\", state=state, to_json=False)          data = pd.read_csv(StringIO(data))          securities = data.to_dict(\"records\")          for index, security in enumerate(securities):             security = self._format_fields(security)             security[\"_type\"] = \"physical\"              securities[index] = security          return securities      @logger.catch     async def get_security_overview(self, symbol: str) -&gt; Dict[str, str]:         return await self._construct_query(\"OVERVIEW\", symbol=symbol)      @logger.catch     async def get_historical_data(self, symbol: str) -&gt; Dict[str, Any]:         return await self._construct_query(             \"TIME_SERIES_DAILY_ADJUSTED\", symbol=symbol, outputsize=\"full\"         )      @logger.catch     async def get_last_price_data(self, symbol: str) -&gt; Dict[str, Any]:         return await self._construct_query(\"GLOBAL_QUOTE\", symbol=symbol)      @logger.catch     async def get_indicator_data(         self, symbol: str, indicator: str, **indicator_options     ) -&gt; Dict[str, Any]:         return await self._construct_query(             indicator, symbol=symbol, **indicator_options         ) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e \u043d\u0435\u043c\u0443 \u0432\u0441\u0451 \u044f\u0441\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>API AlphaVantage \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u043e \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>construct_query<\/code> \u0433\u0434\u0435 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438\u0434\u0451\u0442 http \u0432\u044b\u0437\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u044f \u043f\u0440\u0438\u0432\u043e\u0436\u0443 \u043a <code>snake_case<\/code> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443 \u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0446\u0438\u044f logger.catch \u0434\u043b\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0442\u0440\u0435\u0439\u0441\u0431\u0435\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>P.S. \u041d\u0435\u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d alphavantage \u0432 config.yml, \u043b\u0438\u0431\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u044b <code>HORTON_SERVICE_APIKEY<\/code>.  \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d <a href=\"https:\/\/www.alphavantage.co\/support\/#api-key\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<h4>CRUD-\u043a\u043b\u0430\u0441\u0441<\/h4>\n<p>\u0423 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f securities \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433\u0430\u0445.<\/p>\n<p><a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/363d601030da16733940bf2532a2d9e493e05401\/horton\/database\/cruds\/security.py\" rel=\"noopener noreferrer nofollow\">database\/security.py<\/a><\/p>\n<p>\u0422\u0443\u0442 \u043f\u043e-\u043c\u043e\u0435\u043c\u0443 \u043d\u0438\u0447\u0435\u0433\u043e \u043f\u043e\u044f\u0441\u043d\u044f\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442.<\/p>\n<h4>get_app()<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 <a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/3126e66dafa2c20edf4f657119fc2a7f4833cc6c\/horton\/app.py\" rel=\"noopener noreferrer nofollow\">app.py<\/a><\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import faust  from horton.config import KAFKA_BROKERS   def get_app():     return faust.App(\"horton\", broker=KAFKA_BROKERS) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043a\u0430 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043c, \u043e\u0434\u043d\u0430\u043a\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0430\u0441 \u0436\u0434\u0430\u0442\u044c, \u0432\u043e\u0442 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.app.html#faust-app\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u0444\u0435\u0440\u0435\u043d\u0441\u044b<\/a> \u043d\u0430 App-\u043a\u043b\u0430\u0441\u0441. \u041d\u0430 \u043a\u043b\u0430\u0441\u0441 settings \u0442\u043e\u0436\u0435 \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.<\/p>\n<\/p>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c<\/h3>\n<h4>\u0410\u0433\u0435\u043d\u0442 \u0441\u0431\u043e\u0440\u0430 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433<\/h4>\n<pre><code class=\"python\">app = get_app()  collect_securities_topic = app.topic(\"collect_securities\", internal=True)  @app.agent(collect_securities_topic) async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]: \tpass<\/code><\/pre>\n<p>\u0422\u0430\u043a, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 faust-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f &#8212; \u044d\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0414\u0430\u043b\u0435\u0435, \u043c\u044b \u044f\u0432\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043f\u0438\u043a \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&#8230; \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0435, \u0447\u0442\u043e \u0437\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 internal \u0438 \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443.<\/p>\n<ol>\n<li>\n<p>\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 kafka, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u0442\u043e\u0447\u043d\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435, \u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/kafka.apache.org\/documentation\/#intro_concepts_and_terms\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0444. \u0434\u043e\u043a\u0443<\/a>, \u043b\u0438\u0431\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/post\/354486\/\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442<\/a> \u043d\u0430 \u0445\u0430\u0431\u0440\u0435 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c, \u0433\u0434\u0435 \u0442\u0430\u043a \u0436\u0435 \u0432\u0441\u0451 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u043e\u0442\u0440\u0430\u0436\u0435\u043d\u043e \ud83d\ude42<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.html?highlight=internal#faust.TopicT.internal\" rel=\"noopener noreferrer nofollow\">\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 internal<\/a>, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u0434\u043e\u043a\u0435 faust, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043f\u0438\u043a \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u043e\u0434\u0435, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u0432\u0438\u0434\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 faust, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: retention, retention policy (\u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e delete, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.html?highlight=internal#faust.TopicT.compacting\" rel=\"noopener noreferrer nofollow\">compact<\/a>), \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u043d\u0430 \u0442\u043e\u043f\u0438\u043a (<a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.topics.html?highlight=partitions#faust.topics.Topic.partitions\" rel=\"noopener noreferrer nofollow\">partitions<\/a>, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u0447\u0435\u043c <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.app.html?highlight=partitions#faust.app.App.Settings.topic_partitions\" rel=\"noopener noreferrer nofollow\">\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <\/a>\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f faust). <\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u0430\u0433\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0442\u043e\u043f\u0438\u043a \u0441 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u043e\u0434\u043d\u0430\u043a\u043e, \u044f \u043b\u044e\u0431\u043b\u044e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0432\u0441\u0451 \u044f\u0432\u043d\u043e. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u0438\u043b\u0438 retention policy)  \u0442\u043e\u043f\u0438\u043a\u0430 \u0432 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0438 \u0430\u0433\u0435\u043d\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0431\u0435\u0437 \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u0438\u043a\u0430:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">app = get_app()  @app.agent() async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]: \tpass<\/code><\/pre>\n<\/p>\n<p>\u041d\u0443 \u0430 \u0442\u0435\u043f\u0435\u0440\u044c, \u043e\u043f\u0438\u0448\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u0433\u0435\u043d\u0442 \ud83d\ude42<\/p>\n<pre><code class=\"python\">app = get_app()  collect_securities_topic = app.topic(\"collect_securities\", internal=True)  @app.agent(collect_securities_topic) async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]:     async with aiohttp.ClientSession() as session:         async for _ in stream:             logger.info(\"Start collect securities\")              client = AlphaVantageClient(session, API_KEY)              securities = await client.get_securities()              for security in securities:                 await SecurityCRUD.update_one(                     {\"symbol\": security[\"symbol\"], \"exchange\": security[\"exchange\"]}, security, upsert=True                 )              yield True <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u043c\u044b \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c aiohttp \u0441\u0435\u0441\u0441\u0438\u044e \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043b\u0438\u0435\u043d\u0442. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432\u043e\u0440\u043a\u0435\u0440\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043d\u0430\u0448 \u0430\u0433\u0435\u043d\u0442, \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u0441\u0435\u0441\u0441\u0438\u044f &#8212; \u043e\u0434\u043d\u0430, \u043d\u0430 \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u043e\u0440\u043a\u0435\u0440\u0430 (\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e, \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/settings.html?highlight=concurrency#advanced-agent-settings\" rel=\"noopener noreferrer nofollow\">concurrency<\/a> \u0443 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0439 \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0438).<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043c\u044b \u0438\u0434\u0451\u043c \u043f\u043e \u0441\u0442\u0440\u0438\u043c\u0443 (\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u044b \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0432 <code>_<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0430\u0433\u0435\u043d\u0442\u0435, \u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435) \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u0434\u0432\u0438\u0433\u0435 (offset), \u0438\u043d\u0430\u0447\u0435, \u043d\u0430\u0448 \u0446\u0438\u043a\u043b \u0431\u0443\u0434\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0442\u044c \u0438\u0445 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f. \u041d\u0443 \u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0446\u0438\u043a\u043b\u0430, \u043c\u044b \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 (get_securities \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044f \u0442\u043e\u043b\u044c\u043a\u043e active, \u0441\u043c. \u043a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430) \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u0432 \u0431\u0430\u0437\u0443, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0431\u0443\u043c\u0430\u0433\u0430 \u0441 \u0442\u0430\u043a\u0438\u043c \u0442\u0438\u043a\u0435\u0440\u043e\u043c \u0438 \u0431\u0438\u0440\u0436\u0435\u0439 \u0432 \u0411\u0414, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c, \u0442\u043e \u043e\u043d\u0430 (\u0431\u0443\u043c\u0430\u0433\u0430) \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0441\u044f.<\/p>\n<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448\u0435 \u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0435!<\/p>\n<pre><code>&gt; docker-compose up -d ... \u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 ... &gt; faust -A horton.agents worker --without-web -l info<\/code><\/pre>\n<p>P.S. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/tasks.html#web-views\" rel=\"noopener noreferrer nofollow\">\u0432\u0435\u0431-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/a> faust \u044f \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043d\u0435 \u0431\u0443\u0434\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u043b\u0430\u0433.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 faust&#8217;\u0443, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043d\u0438\u043c (\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440) \u0441 \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u043e\u0432 info. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u044b\u0432\u043e\u0434:<\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>\u250c\u0192a\u00b5S\u2020 v1.10.4\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 id          \u2502 horton                                            \u2502 \u2502 transport   \u2502 [URL('kafka:\/\/localhost:9092')]                   \u2502 \u2502 store       \u2502 memory:                                           \u2502 \u2502 log         \u2502 -stderr- (info)                                   \u2502 \u2502 pid         \u2502 1271262                                           \u2502 \u2502 hostname    \u2502 host-name                                         \u2502 \u2502 platform    \u2502 CPython 3.8.2 (Linux x86_64)                      \u2502 \u2502 drivers     \u2502                                                   \u2502 \u2502   transport \u2502 aiokafka=1.1.6                                    \u2502 \u2502   web       \u2502 aiohttp=3.6.2                                     \u2502 \u2502 datadir     \u2502 \/path\/to\/project\/horton-data                      \u2502 \u2502 appdir      \u2502 \/path\/to\/project\/horton-data\/v1                   \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 ... \u043b\u043e\u0433\u0438, \u043b\u043e\u0433\u0438, \u043b\u043e\u0433\u0438 ...  \u250cTopic Partition Set\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 topic                      \u2502 partitions \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 collect_securities         \u2502 {0-7}      \u2502 \u2502 horton-__assignor-__leader \u2502 {0}        \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><s>\u041e\u043d\u043e \u0436\u0438\u0432\u043e\u0435!!!<\/s><\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 partition set. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0442\u043e\u043f\u0438\u043a \u0441 \u0438\u043c\u0435\u043d\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u043b\u0438 \u0432 \u043a\u043e\u0434\u0435, \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 (8, \u0432\u0437\u044f\u0442\u043e\u0435 \u0438\u0437 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/settings.html?highlight=topic_partitions#std:setting-topic_partitions\" rel=\"noopener noreferrer nofollow\">topic_partitions<\/a> &#8212; \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f), \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430 \u043c\u044b \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 (\u0447\u0435\u0440\u0435\u0437 partitions) \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438. \u0417\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u0430\u0433\u0435\u043d\u0442\u0443 \u0432 \u0432\u043e\u0440\u043a\u0435\u0440\u0435 \u043e\u0442\u0432\u0435\u0434\u0435\u043d\u044b \u0432\u0441\u0435 8 \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0446\u0438\u0439, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439, \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u043d\u0433.<\/p>\n<p>\u0427\u0442\u043e \u0436\u0435, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0439\u0442\u0438 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u043e\u043a\u043d\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0448 \u0442\u043e\u043f\u0438\u043a:<\/p>\n<pre><code>&gt; faust -A horton.agents send @collect_securities {\"topic\": \"collect_securities\", \"partition\": 6, \"topic_partition\": [\"collect_securities\", 6], \"offset\": 0, \"timestamp\": ..., \"timestamp_type\": 0}<\/code><\/pre>\n<p>P.S. \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>@<\/code> \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u043f\u0438\u043a \u0441 \u0438\u043c\u0435\u043d\u0435\u043c &#171;collect_securities&#187;.<\/p>\n<\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443\u0448\u043b\u043e \u0432 6 \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u044e &#8212; \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0437\u0430\u0439\u0434\u044f \u0432 kafdrop \u043d\u0430 <code>localhost:9000<\/code><\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u044f \u0432 \u043e\u043a\u043d\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u0441 \u043d\u0430\u0448\u0438\u043c \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u043c, \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0440\u0430\u0434\u043e\u0441\u0442\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u043b\u0430\u043d\u043d\u043e\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e loguru:<\/p>\n<pre><code>2020-09-23 00:26:37.304 | INFO     | horton.agents:collect_securities:40 - Start collect securities<\/code><\/pre>\n<p>\u0422\u0430\u043a \u0436\u0435, \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u0432 mongo (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Robo3T \u0438\u043b\u0438 Studio3T) \u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u0447\u0442\u043e \u0446\u0435\u043d\u043d\u044b\u0435 \u0431\u0443\u043c\u0430\u0433\u0438 \u0432 \u0431\u0430\u0437\u0435:<\/p>\n<p><em>\u042f \u043d\u0435 \u043c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u0435\u0440, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443, \u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0443\u0435\u043c\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.<\/em><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/48b\/5ad\/c11\/48b5adc118587bb7a99ac3c299ef8bef\" width=\"885\" height=\"382\"><figcaption><\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0b7\/efa\/5ec\/0b7efa5ec51937472240628289c28908\" width=\"862\" height=\"214\"><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0447\u0430\u0441\u0442\u044c\u0435 \u0438 \u0440\u0430\u0434\u043e\u0441\u0442\u044c &#8212; \u043f\u0435\u0440\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0433\u043e\u0442\u043e\u0432 \ud83d\ude42<\/p>\n<\/p>\n<h4>\u0410\u0433\u0435\u043d\u0442 \u0433\u043e\u0442\u043e\u0432, \u0434\u0430 \u0437\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442!<\/h4>\n<p>\u0414\u0430, \u0433\u043e\u0441\u043f\u043e\u0434\u0430, \u043d\u0430\u043c\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e 1\/3 \u043f\u0443\u0442\u0438, \u0443\u0433\u043e\u0442\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0451\u0439, \u043d\u043e \u043d\u0435 \u0443\u043d\u044b\u0432\u0430\u0439\u0442\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0435\u0439\u0447\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0443\u0436\u0435 \u043b\u0435\u0433\u0447\u0435.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0430\u0433\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0435\u0451 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"python\">collect_security_overview_topic = app.topic(\"collect_security_overview\", internal=True)   @app.agent(collect_security_overview_topic) async def collect_security_overview(     stream: StreamT[?], ) -&gt; AsyncIterable[bool]:     async with aiohttp.ClientSession() as session:         async for event in stream:             ...<\/code><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u0430\u0433\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 security, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0438\u043a\u0435\u0440 (symbol) \u044d\u0442\u043e\u0439 \u0431\u0443\u043c\u0430\u0433\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 faust \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/models.html?highlight=Records#model-types\" rel=\"noopener noreferrer nofollow\">Records<\/a> &#8212; \u043a\u043b\u0430\u0441\u0441\u044b, \u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0441\u0445\u0435\u043c\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u0438\u043a\u0435 \u0430\u0433\u0435\u043d\u0442\u0430.<\/p>\n<\/p>\n<p>\u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u0432 <a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/3126e66dafa2c20edf4f657119fc2a7f4833cc6c\/horton\/records.py\" rel=\"noopener noreferrer nofollow\"><em>records.py<\/em><\/a><em> <\/em>\u0438 \u043e\u043f\u0438\u0448\u0435\u043c, \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443 \u044d\u0442\u043e\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430:<\/p>\n<pre><code class=\"python\">import faust   class CollectSecurityOverview(faust.Record):     symbol: str     exchange: str <\/code><\/pre>\n<\/p>\n<p>\u041a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u043c\u043e\u0433\u043b\u0438 \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f, faust \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0445\u0435\u043c\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u0442\u0438\u043f\u043e\u0432 \u0432 python, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 &#8212; <a href=\"https:\/\/github.com\/robinhood\/faust\/blob\/cf0ea8ce38d7808bd81378f21e6fc6072123d82e\/setup.py#L209\" rel=\"noopener noreferrer nofollow\">3.6<\/a>.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u0430\u0433\u0435\u043d\u0442\u0443, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0442\u0438\u043f\u044b \u0438 \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"python\">collect_security_overview_topic = app.topic(     \"collect_security_overview\", internal=True, value_type=CollectSecurityOverview )   @app.agent(collect_security_overview_topic) async def collect_security_overview(     stream: StreamT[CollectSecurityOverview], ) -&gt; AsyncIterable[bool]:     async with aiohttp.ClientSession() as session:         async for event in stream:             logger.info(                 \"Start collect security [{symbol}] overview\", symbol=event.symbol             )              client = AlphaVantageClient(session, API_KEY)              security_overview = await client.get_security_overview(event.symbol)              await SecurityCRUD.update_one({\"symbol\": event.symbol, \"exchange\": event.exchange}, security_overview)              yield True <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435, \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 \u043c\u0435\u0442\u043e\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u043e\u043f\u0438\u043a\u0430 \u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0441\u043e \u0441\u0445\u0435\u043c\u043e\u0439 &#8212; value_type. \u0414\u0430\u043b\u0435\u0435, \u0432\u0441\u0451 \u043f\u043e \u0442\u043e\u0439 \u0436\u0435 \u0441\u0430\u043c\u043e\u0439 \u0441\u0445\u0435\u043c\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0447\u0451\u043c \u0442\u043e \u0435\u0449\u0451 &#8212; \u0441\u043c\u044b\u0441\u043b\u0430 \u043d\u0435 \u0432\u0438\u0436\u0443.<\/p>\n<\/p>\n<p>\u041d\u0443 \u0447\u0442\u043e \u0436\u0435, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0442\u0440\u0438\u0445 &#8212; \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 collect_securitites \u0432\u044b\u0437\u043e\u0432 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441\u0431\u043e\u0440\u0430 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"python\">.... for security in securities:     await SecurityCRUD.update_one({             \"symbol\": security[\"symbol\"],             \"exchange\": security[\"exchange\"]         },         security,         upsert = True,     )      await collect_security_overview.cast(         CollectSecurityOverview(symbol = security[\"symbol\"], exchange = security[\"exchange\"])     ) ....<\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u0441\u0445\u0435\u043c\u0443 \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434 .cast, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0436\u0438\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0442 \u0430\u0433\u0435\u043d\u0442\u0430, \u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/agents.html?highlight=.cast#cast-or-ask\" rel=\"noopener noreferrer nofollow\">\u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432<\/a> \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u043f\u0438\u043a:<\/p>\n<ol>\n<li>\n<p>cast &#8212; \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430. \u041d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u043e\u043f\u0438\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>send &#8212; \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430. \u041c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0433\u0435\u043d\u0442\u0430 \u0432 \u0442\u043e\u043f\u0438\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u0439\u0434\u0451\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.<\/p>\n<\/li>\n<li>\n<p>ask &#8212; \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430. \u041c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0433\u0435\u043d\u0442\u0430 \u0432 \u0442\u043e\u043f\u0438\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u0439\u0434\u0451\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.<\/p>\n<\/li>\n<\/ol>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0430 \u044d\u0442\u043e\u043c \u0441 \u0430\u0433\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0432\u0441\u0451!<\/p>\n<\/p>\n<h4>\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u043c\u0435\u0447\u0442\u044b<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u0447\u0442\u043e \u044f \u043e\u0431\u0435\u0449\u0430\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 &#8212; \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u041a\u0430\u043a \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u0435\u0435, \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 faust  &#8212; \u044d\u0442\u043e \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 click. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 faust \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043d\u0430\u0448\u0443 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 \u043f\u0440\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0438 \u043a\u043b\u044e\u0447\u0430 -A<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0432 <a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/b27b5160d3fd47cf53899b74b6ed222a0fdbfe45\/horton\/agents.py\" rel=\"noopener noreferrer nofollow\">agents.py<\/a> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u043c <em>app.command<\/em>, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u043c\u0435\u0442\u043e\u0434 <em>cast<\/em> \u0443 <em>collect_securitites<\/em>:<\/p>\n<pre><code class=\"python\">@app.command() async def start_collect_securities():     \"\"\"Collect securities and overview.\"\"\"      await collect_securities.cast() <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u044b\u0437\u043e\u0432\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043e\u043c\u0430\u043d\u0434, \u0432 \u043d\u0451\u043c \u0431\u0443\u0434\u0435\u0442 \u0438 \u043d\u0430\u0448\u0430 \u043d\u043e\u0432\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430:<\/p>\n<pre><code>&gt; faust -A horton.agents --help  .... Commands:   agents                    List agents.   clean-versions            Delete old version directories.   completion                Output shell completion to be evaluated by the...   livecheck                 Manage LiveCheck instances.   model                     Show model detail.   models                    List all available models as a tabulated list.   reset                     Delete local table state.   send                      Send message to agent\/topic.   start-collect-securities  Collect securities and overview.   tables                    List available tables.   worker                    Start worker instance for given app. <\/code><\/pre>\n<p>\u0415\u044e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u043a\u0430\u043a \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c faust \u0432\u043e\u0440\u043a\u0435\u0440 \u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0441\u0431\u043e\u0440 \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433:<\/p>\n<pre><code>&gt; faust -A horton.agents start-collect-securities<\/code><\/pre>\n<h3>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435?<\/h3>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b, \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c sink \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043a\u0441\u0442\u0440\u0435\u043c\u0443\u043c \u0432 \u0446\u0435\u043d\u0430\u0445 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u043e\u0440\u0433\u043e\u0432 \u0437\u0430 \u0433\u043e\u0434 \u0438 cron-\u0437\u0430\u043f\u0443\u0441\u043a \u0430\u0433\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p>\u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0432\u0441\u0451! \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435 \ud83d\ude42<\/p>\n<p><a href=\"https:\/\/github.com\/Egnod\/horton\/tree\/b27b5160d3fd47cf53899b74b6ed222a0fdbfe45\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u0434 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d0b\/290\/1bc\/d0b2901bcb6af16d5e14310329b596bf\" width=\"800\" height=\"439\"><figcaption><\/figcaption><\/figure>\n<p>P.S. \u041f\u043e\u0434 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043c\u0435\u043d\u044f \u0441\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u043f\u0440\u043e faust \u0438 confluent kafka (<a href=\"https:\/\/stackoverflow.com\/a\/39709900\" rel=\"noopener noreferrer nofollow\">\u043a\u0430\u043a\u0438\u0435 \u0435\u0441\u0442\u044c \u0443 confluent \u0444\u0438\u0447\u0438<\/a>). \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e confluent \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0435\u0435, \u043d\u043e \u0434\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e faust \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043b\u044f confluent &#8212; \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437<a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/settings.html?highlight=confluent#available-transports\" rel=\"noopener noreferrer nofollow\"> \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0432 \u0434\u043e\u043a\u0435<\/a>.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/520274\/\"> https:\/\/habr.com\/ru\/post\/520274\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/520274\/\">\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<h3>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/h3>\n<ol>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/post\/519882\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c I: \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c II: \u0410\u0433\u0435\u043d\u0442\u044b \u0438 \u041a\u043e\u043c\u0430\u043d\u0434\u044b<\/p>\n<\/li>\n<\/ol>\n<h3>\u0427\u0442\u043e \u043c\u044b \u0442\u0443\u0442 \u0434\u0435\u043b\u0430\u0435\u043c?<\/h3>\n<p>\u0418\u0442\u0430\u043a-\u0438\u0442\u0430\u043a, \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c. \u041a\u0430\u043a \u0438 \u043f\u0438\u0441\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u0435\u0435, \u0432 \u043d\u0435\u0439 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u0438\u043a \u0434\u043b\u044f alphavantage \u043d\u0430 aiohttp \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0434\u0435\u043b\u0430\u0435\u043c \u0430\u0433\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433\u0430\u0445 \u0438 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u043d\u0438\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u043e, \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0430 \u0432 \u043f\u043b\u0430\u043d\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f faust \u043c\u044b \u0443\u0437\u043d\u0430\u0435\u043c, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u0442\u0440\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437 kafka, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b (\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430 click), \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0438 &#8212; \u0434\u043b\u044f \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043f\u0443\u0448\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043f\u0438\u043a, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043b\u0435\u0434\u0438\u0442 \u0430\u0433\u0435\u043d\u0442.<\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<h4>\u041a\u043b\u0438\u0435\u043d\u0442 AlphaVantage<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 aiohttp \u043a\u043b\u0438\u0435\u043d\u0442\u0438\u043a \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430 alphavantage.<\/p>\n<p><a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/3b50581b3639ce7d6fe0d53edbf4ac0976f3fd67\/horton\/alphavantage.py\" rel=\"noopener noreferrer nofollow\">alphavantage.py<\/a><\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import urllib.parse as urlparse from io import StringIO from typing import Any, Dict, List, Union  import aiohttp import pandas as pd import stringcase from loguru import logger  from horton.config import API_ENDPOINT   class AlphaVantageClient:     def __init__(         self,         session: aiohttp.ClientSession,         api_key: str,         api_endpoint: str = API_ENDPOINT,     ):         self._query_params = {\"datatype\": \"json\", \"apikey\": api_key}         self._api_endpoint = api_endpoint         self._session = session      @logger.catch     def _format_fields(self, data: Dict[str, Any]) -&gt; Dict[str, Any]:         formatted_data = {}          for field, item in data.items():             formatted_data[stringcase.snakecase(field)] = item          return formatted_data      @logger.catch     async def _construct_query(         self, function: str, to_json: bool = True, **kwargs     ) -&gt; Union[Dict[str, Any], str]:         path = \"query\/\"          async with self._session.get(             urlparse.urljoin(self._api_endpoint, path),             params={\"function\": function, **kwargs, **self._query_params},         ) as response:             data = (await response.json()) if to_json else (await response.text())              if to_json:                 data = self._format_fields(data)          return data      @logger.catch     async def get_securities(self, state: str = \"active\") -&gt; List[Dict[str, str]]:         data = await self._construct_query(\"LISTING_STATUS\", state=state, to_json=False)          data = pd.read_csv(StringIO(data))          securities = data.to_dict(\"records\")          for index, security in enumerate(securities):             security = self._format_fields(security)             security[\"_type\"] = \"physical\"              securities[index] = security          return securities      @logger.catch     async def get_security_overview(self, symbol: str) -&gt; Dict[str, str]:         return await self._construct_query(\"OVERVIEW\", symbol=symbol)      @logger.catch     async def get_historical_data(self, symbol: str) -&gt; Dict[str, Any]:         return await self._construct_query(             \"TIME_SERIES_DAILY_ADJUSTED\", symbol=symbol, outputsize=\"full\"         )      @logger.catch     async def get_last_price_data(self, symbol: str) -&gt; Dict[str, Any]:         return await self._construct_query(\"GLOBAL_QUOTE\", symbol=symbol)      @logger.catch     async def get_indicator_data(         self, symbol: str, indicator: str, **indicator_options     ) -&gt; Dict[str, Any]:         return await self._construct_query(             indicator, symbol=symbol, **indicator_options         ) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e \u043d\u0435\u043c\u0443 \u0432\u0441\u0451 \u044f\u0441\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>API AlphaVantage \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u043e \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>construct_query<\/code> \u0433\u0434\u0435 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438\u0434\u0451\u0442 http \u0432\u044b\u0437\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u044f \u043f\u0440\u0438\u0432\u043e\u0436\u0443 \u043a <code>snake_case<\/code> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443 \u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0446\u0438\u044f logger.catch \u0434\u043b\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0442\u0440\u0435\u0439\u0441\u0431\u0435\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>P.S. \u041d\u0435\u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d alphavantage \u0432 config.yml, \u043b\u0438\u0431\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u044b <code>HORTON_SERVICE_APIKEY<\/code>.  \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d <a href=\"https:\/\/www.alphavantage.co\/support\/#api-key\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<h4>CRUD-\u043a\u043b\u0430\u0441\u0441<\/h4>\n<p>\u0423 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f securities \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433\u0430\u0445.<\/p>\n<p><a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/363d601030da16733940bf2532a2d9e493e05401\/horton\/database\/cruds\/security.py\" rel=\"noopener noreferrer nofollow\">database\/security.py<\/a><\/p>\n<p>\u0422\u0443\u0442 \u043f\u043e-\u043c\u043e\u0435\u043c\u0443 \u043d\u0438\u0447\u0435\u0433\u043e \u043f\u043e\u044f\u0441\u043d\u044f\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442.<\/p>\n<h4>get_app()<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 <a href=\"https:\/\/github.com\/Egnod\/horton\/blob\/3126e66dafa2c20edf4f657119fc2a7f4833cc6c\/horton\/app.py\" rel=\"noopener noreferrer nofollow\">app.py<\/a><\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import faust  from horton.config import KAFKA_BROKERS   def get_app():     return faust.App(\"horton\", broker=KAFKA_BROKERS) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043a\u0430 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043c, \u043e\u0434\u043d\u0430\u043a\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0430\u0441 \u0436\u0434\u0430\u0442\u044c, \u0432\u043e\u0442 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.app.html#faust-app\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u0444\u0435\u0440\u0435\u043d\u0441\u044b<\/a> \u043d\u0430 App-\u043a\u043b\u0430\u0441\u0441. \u041d\u0430 \u043a\u043b\u0430\u0441\u0441 settings \u0442\u043e\u0436\u0435 \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.<\/p>\n<\/p>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c<\/h3>\n<h4>\u0410\u0433\u0435\u043d\u0442 \u0441\u0431\u043e\u0440\u0430 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433<\/h4>\n<pre><code class=\"python\">app = get_app()  collect_securities_topic = app.topic(\"collect_securities\", internal=True)  @app.agent(collect_securities_topic) async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]: \tpass<\/code><\/pre>\n<p>\u0422\u0430\u043a, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 faust-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f &#8212; \u044d\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0414\u0430\u043b\u0435\u0435, \u043c\u044b \u044f\u0432\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043f\u0438\u043a \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&#8230; \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0435, \u0447\u0442\u043e \u0437\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 internal \u0438 \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443.<\/p>\n<ol>\n<li>\n<p>\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 kafka, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u0442\u043e\u0447\u043d\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435, \u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/kafka.apache.org\/documentation\/#intro_concepts_and_terms\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0444. \u0434\u043e\u043a\u0443<\/a>, \u043b\u0438\u0431\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/post\/354486\/\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442<\/a> \u043d\u0430 \u0445\u0430\u0431\u0440\u0435 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c, \u0433\u0434\u0435 \u0442\u0430\u043a \u0436\u0435 \u0432\u0441\u0451 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u043e\u0442\u0440\u0430\u0436\u0435\u043d\u043e \ud83d\ude42<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.html?highlight=internal#faust.TopicT.internal\" rel=\"noopener noreferrer nofollow\">\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 internal<\/a>, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u0434\u043e\u043a\u0435 faust, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043f\u0438\u043a \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u043e\u0434\u0435, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432\u0432\u0438\u0434\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 faust, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: retention, retention policy (\u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e delete, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.html?highlight=internal#faust.TopicT.compacting\" rel=\"noopener noreferrer nofollow\">compact<\/a>), \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u043d\u0430 \u0442\u043e\u043f\u0438\u043a (<a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.topics.html?highlight=partitions#faust.topics.Topic.partitions\" rel=\"noopener noreferrer nofollow\">partitions<\/a>, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u0447\u0435\u043c <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/reference\/faust.app.html?highlight=partitions#faust.app.App.Settings.topic_partitions\" rel=\"noopener noreferrer nofollow\">\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <\/a>\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f faust). <\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u0430\u0433\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0442\u043e\u043f\u0438\u043a \u0441 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u043e\u0434\u043d\u0430\u043a\u043e, \u044f \u043b\u044e\u0431\u043b\u044e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0432\u0441\u0451 \u044f\u0432\u043d\u043e. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u0438\u043b\u0438 retention policy)  \u0442\u043e\u043f\u0438\u043a\u0430 \u0432 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0438 \u0430\u0433\u0435\u043d\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0431\u0435\u0437 \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u0438\u043a\u0430:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">app = get_app()  @app.agent() async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]: \tpass<\/code><\/pre>\n<\/p>\n<p>\u041d\u0443 \u0430 \u0442\u0435\u043f\u0435\u0440\u044c, \u043e\u043f\u0438\u0448\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u0433\u0435\u043d\u0442 \ud83d\ude42<\/p>\n<pre><code class=\"python\">app = get_app()  collect_securities_topic = app.topic(\"collect_securities\", internal=True)  @app.agent(collect_securities_topic) async def collect_securities(stream: StreamT[None]) -&gt; AsyncIterable[bool]:     async with aiohttp.ClientSession() as session:         async for _ in stream:             logger.info(\"Start collect securities\")              client = AlphaVantageClient(session, API_KEY)              securities = await client.get_securities()              for security in securities:                 await SecurityCRUD.update_one(                     {\"symbol\": security[\"symbol\"], \"exchange\": security[\"exchange\"]}, security, upsert=True                 )              yield True <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u043c\u044b \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c aiohttp \u0441\u0435\u0441\u0441\u0438\u044e \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043b\u0438\u0435\u043d\u0442. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432\u043e\u0440\u043a\u0435\u0440\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043d\u0430\u0448 \u0430\u0433\u0435\u043d\u0442, \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u0441\u0435\u0441\u0441\u0438\u044f &#8212; \u043e\u0434\u043d\u0430, \u043d\u0430 \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u043e\u0440\u043a\u0435\u0440\u0430 (\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e, \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/settings.html?highlight=concurrency#advanced-agent-settings\" rel=\"noopener noreferrer nofollow\">concurrency<\/a> \u0443 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0439 \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0438).<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043c\u044b \u0438\u0434\u0451\u043c \u043f\u043e \u0441\u0442\u0440\u0438\u043c\u0443 (\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u044b \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0432 <code>_<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0430\u0433\u0435\u043d\u0442\u0435, \u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435) \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u0434\u0432\u0438\u0433\u0435 (offset), \u0438\u043d\u0430\u0447\u0435, \u043d\u0430\u0448 \u0446\u0438\u043a\u043b \u0431\u0443\u0434\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0442\u044c \u0438\u0445 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f. \u041d\u0443 \u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0446\u0438\u043a\u043b\u0430, \u043c\u044b \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 (get_securities \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044f \u0442\u043e\u043b\u044c\u043a\u043e active, \u0441\u043c. \u043a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430) \u0446\u0435\u043d\u043d\u044b\u0445 \u0431\u0443\u043c\u0430\u0433 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u0432 \u0431\u0430\u0437\u0443, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0431\u0443\u043c\u0430\u0433\u0430 \u0441 \u0442\u0430\u043a\u0438\u043c \u0442\u0438\u043a\u0435\u0440\u043e\u043c \u0438 \u0431\u0438\u0440\u0436\u0435\u0439 \u0432 \u0411\u0414, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c, \u0442\u043e \u043e\u043d\u0430 (\u0431\u0443\u043c\u0430\u0433\u0430) \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0441\u044f.<\/p>\n<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448\u0435 \u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0435!<\/p>\n<pre><code>&gt; docker-compose up -d ... \u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 ... &gt; faust -A horton.agents worker --without-web -l info<\/code><\/pre>\n<p>P.S. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/tasks.html#web-views\" rel=\"noopener noreferrer nofollow\">\u0432\u0435\u0431-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/a> faust \u044f \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043d\u0435 \u0431\u0443\u0434\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u043b\u0430\u0433.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 faust&#8217;\u0443, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043d\u0438\u043c (\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440) \u0441 \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u043e\u0432 info. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u044b\u0432\u043e\u0434:<\/p>\n<details class=\"spoiler\">\n<summary>Spoiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>\u250c\u0192a\u00b5S\u2020 v1.10.4\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 id          \u2502 horton                                            \u2502 \u2502 transport   \u2502 [URL('kafka:\/\/localhost:9092')]                   \u2502 \u2502 store       \u2502 memory:                                           \u2502 \u2502 log         \u2502 -stderr- (info)                                   \u2502 \u2502 pid         \u2502 1271262                                           \u2502 \u2502 hostname    \u2502 host-name                                         \u2502 \u2502 platform    \u2502 CPython 3.8.2 (Linux x86_64)                      \u2502 \u2502 drivers     \u2502                                                   \u2502 \u2502   transport \u2502 aiokafka=1.1.6                                    \u2502 \u2502   web       \u2502 aiohttp=3.6.2                                     \u2502 \u2502 datadir     \u2502 \/path\/to\/project\/horton-data                      \u2502 \u2502 appdir      \u2502 \/path\/to\/project\/horton-data\/v1                   \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 ... \u043b\u043e\u0433\u0438, \u043b\u043e\u0433\u0438, \u043b\u043e\u0433\u0438 ...  \u250cTopic Partition Set\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 topic                      \u2502 partitions \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 collect_securities         \u2502 {0-7}      \u2502 \u2502 horton-__assignor-__leader \u2502 {0}        \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><s>\u041e\u043d\u043e \u0436\u0438\u0432\u043e\u0435!!!<\/s><\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 partition set. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0442\u043e\u043f\u0438\u043a \u0441 \u0438\u043c\u0435\u043d\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u043b\u0438 \u0432 \u043a\u043e\u0434\u0435, \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0439 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 (8, \u0432\u0437\u044f\u0442\u043e\u0435 \u0438\u0437 <a href=\"https:\/\/faust.readthedocs.io\/en\/latest\/userguide\/settings.html?highlight=topic_partitions#std:setting-topic_partitions\" rel=\"noopener noreferrer nofollow\">topic_partitions<\/a> &#8212; \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f), \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430 \u043c\u044b \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 (\u0447\u0435\u0440\u0435\u0437 partitions) \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438. \u0417\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u0430\u0433\u0435\u043d\u0442\u0443 \u0432 \u0432\u043e\u0440\u043a\u0435\u0440\u0435 \u043e\u0442\u0432\u0435\u0434\u0435\u043d\u044b \u0432\u0441\u0435 8 \u043f\u0430\u0440\u0442\u0438\u0446\u0438\u0446\u0438\u0439, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439, \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u043d\u0433.<\/p>\n<p>\u0427\u0442\u043e \u0436\u0435, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0439\u0442\u0438 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u043e\u043a\u043d\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0448 \u0442\u043e\u043f\u0438\u043a:<\/p>\n<pre><code>&gt; faust -A horton.agents send @collect_securities {\"topic\": \"collect_securities\", \"partition\": 6, \"topic_partition\": [\"collect_securities\", 6], \"offset\": 0, \"timestamp\": ..., \"timestamp_type\": 0}<\/code><\/pre>\n<p>P.S. \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>@<\/code> \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u043f\u0438\u043a \u0441 \u0438\u043c\u0435\u043d\u0435\u043c &#171;collect_securities&#187;.<\/p>\n<\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443\u0448\u043b\u043e \u0432 6<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-310351","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/310351","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=310351"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/310351\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=310351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=310351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=310351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}