ื”ื™ื ื˜ืขืจื’ืจื•ื ื˜ ื˜ืึทืกืงืก ืื•ื™ืฃ Faust, ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–

ื”ื™ื ื˜ืขืจื’ืจื•ื ื˜ ื˜ืึทืกืงืก ืื•ื™ืฃ Faust, ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–

ื˜ื™ืฉ ืคื•ืŸ ืื™ื ื”ืึทืœื˜

  1. ื˜ื™ื™ืœ ืื™ืš: ื”ืงื“ืžื”

  2. ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–

ื•ื•ืืก ื˜ื•ืขืŸ ืžื™ืจ ื“ื?

ืึทื–ื•ื™, ืึทื–ื•ื™, ื“ืขืจ ืฆื•ื•ื™ื™ื˜ืขืจ ื˜ื™ื™ืœ. ื•ื•ื™ ื’ืขืฉืจื™ื‘ืŸ ืคืจื™ืขืจ, ืื™ืŸ ืขืก ืžื™ืจ ื•ื•ืขืœืŸ ื˜ืึธืŸ ื“ื™ ืคืืœื’ืขื ื“ืข:

  1. ืœืึธืžื™ืจ ืฉืจื™ื™ึทื‘ืŸ ืึท ืงืœื™ื™ืŸ ืงืœื™ืขื ื˜ ืคึฟืึทืจ ืึทืœืคืึทื•ื•ืึทื ื˜ื™ื“ื–ืฉ ืื•ื™ืฃ aiohttp ืžื™ื˜ ืจื™ืงื•ื•ืขืก ืคึฟืึทืจ ื“ื™ ืขื ื“ืคึผื•ื™ื ื˜ืก ื•ื•ืึธืก ืžื™ืจ ื“ืึทืจืคึฟืŸ.

  2. ืœืึธืžื™ืจ ืฉืึทืคึฟืŸ ืึทืŸ ืึทื’ืขื ื˜ ื•ื•ืึธืก ื•ื•ืขื˜ ืงืœื™ื™ึทื‘ืŸ ื“ืึทื˜ืŸ ื•ื•ืขื’ืŸ ืกื™ืงื™ื•ืจืึทื˜ื™ื– ืื•ืŸ ืžืขื˜ืึท ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ืื•ื™ืฃ ื–ื™ื™.

ืึธื‘ืขืจ, ื“ืึธืก ืื™ื– ื•ื•ืึธืก ืžื™ืจ ื•ื•ืขืœืŸ ื˜ืึธืŸ ืคึฟืึทืจ ื“ื™ ืคึผืจื•ื™ืขืงื˜ ื–ื™ืš, ืื•ืŸ ืื™ืŸ ื˜ืขืจืžื™ื ืขืŸ ืคื•ืŸ ืคืึทืกื˜ ืคืึธืจืฉื•ื ื’, ืžื™ืจ ื•ื•ืขืœืŸ ืœืขืจื ืขืŸ ื•ื•ื™ ืฆื• ืฉืจื™ื™ึทื‘ืŸ ืึทื’ืขื ืฅ ื•ื•ืึธืก ืคึผืจืึทืกืขืกื˜ ืกื˜ืจื™ืžื™ื ื’ ื’ืขืฉืขืขื ื™ืฉืŸ ืคื•ืŸ ืงืึทืคืงืึท, ื•ื•ื™ ืื•ื™ืš ื•ื•ื™ ืฆื• ืฉืจื™ื™ึทื‘ืŸ ืงืึทืžืึทื ื“ื– (ื’ื™ื˜ ืจืึทืคึผืขืจ), ืื™ืŸ ืื•ื ื“ื–ืขืจ ืคืึทืœ - ืคึฟืึทืจ ืžืึทื ื•ืึทืœ ืฉื˜ื•ืคึผืŸ ืึทืจื˜ื™ืงืœืขืŸ ืฆื• ื“ืขืจ ื˜ืขืžืข ื•ื•ืึธืก ื“ืขืจ ืึทื’ืขื ื˜ ืื™ื– ืžืึธื ื™ื˜ืึธืจื™ื ื’.

ื˜ืจืึทื™ื ื™ื ื’

AlphaVantage Client

ืขืจืฉื˜ืขืจ, ืœืึธื–ืŸ ืื•ื ื“ื– ืฉืจื™ื™ึทื‘ืŸ ืึท ืงืœื™ื™ืŸ ืึทื™ืึธื”ื˜ื˜ืคึผ ืงืœื™ืขื ื˜ ืคึฟืึทืจ ืจื™ืงื•ื•ืขืก ืฆื• ืึทืœืคืึทื•ื•ืึทื ื˜ื™ื“ื–ืฉ.

alphavantage.py

ืกืคึผืึธื™ืœืขืจ

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]) -> 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
    ) -> 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") -> 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) -> Dict[str, str]:
        return await self._construct_query("OVERVIEW", symbol=symbol)

    @logger.catch
    async def get_historical_data(self, symbol: str) -> 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) -> 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
    ) -> Dict[str, Any]:
        return await self._construct_query(
            indicator, symbol=symbol, **indicator_options
        )

ืื™ืŸ ืคืึทืงื˜, ืึทืœืฅ ืื™ื– ืงืœืึธืจ ืคื•ืŸ ืื™ื:

  1. ื“ื™ AlphaVantage API ืื™ื– ื’ืึทื ืฅ ืคึผืฉื•ื˜ ืื•ืŸ ื‘ื™ื•ื˜ืึทืคืœื™ ื“ื™ื–ื™ื™ื ื“, ืึทื–ื•ื™ ืื™ืš ื‘ืึทืฉืœืึธืกืŸ ืฆื• ืžืึทื›ืŸ ืึทืœืข ืจื™ืงื•ื•ืขืก ื“ื•ืจืš ื“ืขื ืื•ืคึฟืŸ construct_query ื•ื•ื• ืื™ืŸ ืงืขืจ ืขืก ืื™ื– ืึท ื”ื˜ื˜ืคึผ ืจื•ืคืŸ.

  2. ืื™ืš ื‘ืจืขื ื’ ืืœืข ืคืขืœื“ืขืจ ืฆื• snake_case ืคึฟืึทืจ ื˜ืจื™ื™ืกื˜.

  3. ื ื•, ื“ื™ logger.catch ื‘ืึทืคึผื•ืฆื•ื ื’ ืคึฟืึทืจ ืฉื™ื™ืŸ ืื•ืŸ ื™ื ืคืึธืจืžืึทื˜ื™ื•ื• ื˜ืจื™ื™ืกื‘ืึทืง ืจืขื–ื•ืœื˜ืึทื˜.

ืคึผืก ื“ื• ื–ืืœืกื˜ ื ื™ืฉื˜ ืคืึทืจื’ืขืกืŸ ืฆื• ืœื™ื™ื’ืŸ ื“ื™ ืึทืœืคืึทื•ื•ืึทื ื˜ืึทื’ืข ืกื™ืžืขืŸ ืœืึธื•ืงืึทืœื™ ืฆื• config.yml, ืึธื“ืขืจ ืึทืจื•ื™ืกืคื™ืจืŸ ื“ื™ ืกื•ื•ื™ื•ื•ืข ื‘ื™ื™ึทื˜ืขื•ื•ื“ื™ืง HORTON_SERVICE_APIKEY. ืžื™ืจ ื‘ืึทืงื•ืžืขืŸ ืึท ืกื™ืžืŸ ื“ืึธ.

CRUD ืงืœืึทืก

ืžื™ืจ ื•ื•ืขืœืŸ ื”ืึธื‘ืŸ ืึท ืกื™ืงื™ื•ืจืึทื˜ื™ื– ื–ืึทืžืœื•ื ื’ ืฆื• ืงืจืึธื ืžืขื˜ืึท ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื•ื•ืขื’ืŸ ืกื™ืงื™ื•ืจืึทื˜ื™ื–.

ื“ืึทื˜ืึทื‘ื™ื™ืก/ืกืขืงื•ืจื™ื˜ื™.ืคึผื™

ืื™ืŸ ืžื™ื™ืŸ ืžื™ื™ื ื•ื ื’, ืขืก ืื™ื– ื ื™ื˜ ื“ืึทืจืคึฟืŸ ืฆื• ื“ืขืจืงืœืขืจืŸ ืขืคึผืขืก ื“ืึธ, ืื•ืŸ ื“ื™ ื‘ืึทื–ืข ืงืœืึทืก ื–ื™ืš ืื™ื– ื’ืึทื ืฅ ืคึผืฉื•ื˜.

ื‘ืึทืงื•ืžืขืŸ_ืึทืคึผ ()

ืœืึธืžื™ืจ ืœื™ื™ื’ืŸ ืึท ืคึฟื•ื ืงืฆื™ืข ืคึฟืึทืจ ืงืจื™ื™ื™ื˜ื™ื ื’ ืึท ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ื›ื™ื™ืคืขืฅ ืื™ืŸ app.py

ืกืคึผืึธื™ืœืขืจ

import faust

from horton.config import KAFKA_BROKERS


def get_app():
    return faust.App("horton", broker=KAFKA_BROKERS)

ืื™ืฆื˜ ืžื™ืจ ื•ื•ืขืœืŸ ื”ืึธื‘ืŸ ื“ื™ ืกื™ืžืคึผืœืึทืกื˜ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืฉืึทืคื•ื ื’, ืึท ื‘ื™ืกืœ ืฉืคึผืขื˜ืขืจ ืžื™ืจ ื•ื•ืขืœืŸ ื™ืงืกืคึผืึทื ื“ ืขืก, ืึธื‘ืขืจ, ืื™ืŸ ืฆื• ื”ืึทืœื˜ืŸ ืื™ืจ ื•ื•ืืจื˜ืŸ, ื“ืึธ ืจืขืคืขืจืขื ืฆืŸ ืฆื• ืึทืคึผ-ืงืœืึทืก. ืื™ืš ืื•ื™ืš ืจืขืงืึธืžืขื ื“ื™ืจืŸ ืื™ืจ ืฆื• ื ืขืžืขืŸ ืึท ืงื•ืง ืื™ืŸ ื“ื™ ืกืขื˜ื˜ื™ื ื’ืก ืงืœืึทืก, ื•ื•ื™ื™ึทืœ ืขืก ืื™ื– ืคืึทืจืึทื ื˜ื•ื•ืึธืจื˜ืœืขืš ืคึฟืึทืจ ืจื•ื‘ึฟ ืกืขื˜ื˜ื™ื ื’ืก.

ื”ื•ื™ืคึผื˜ ื˜ื™ื™ืœ

ืึทื’ืขื ื˜ ืคึฟืึทืจ ืงืึทืœืขืงื˜ื™ื ื’ ืื•ืŸ ืžื™ื™ื ื˜ื™ื™ื ื™ื ื’ ืึท ืจืฉื™ืžื” ืคื•ืŸ ืกื™ืงื™ื•ืจืึทื˜ื™ื–

app = get_app()

collect_securities_topic = app.topic("collect_securities", internal=True)

@app.agent(collect_securities_topic)
async def collect_securities(stream: StreamT[None]) -> AsyncIterable[bool]:
	pass

ืึทื–ื•ื™, ืขืจืฉื˜ืขืจ ืžื™ืจ ื‘ืึทืงื•ืžืขืŸ ื“ื™ ืคืึทืกื˜ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ื›ื™ื™ืคืขืฅ - ื“ืึธืก ืื™ื– ื’ืึทื ืฅ ืคึผืฉื•ื˜. ื•ื•ื™ื™ึทื˜ืขืจ, ืžื™ืจ ื“ืขืจืงืœืขืจืŸ ื‘ืคื™ืจื•ืฉ ืึท ื˜ืขืžืข ืคึฟืึทืจ ืื•ื ื“ื–ืขืจ ืึทื’ืขื ื˜ ... ื“ืึธ ืขืก ืื™ื– ื•ื•ืขืจื˜ ื“ืขืจืžืึธื ืขืŸ ื•ื•ืึธืก ืขืก ืื™ื–, ื•ื•ืึธืก ืื™ื– ื“ื™ ื™ื ืขืจืœืขืš ืคึผืึทืจืึทืžืขื˜ืขืจ ืื•ืŸ ื•ื•ื™ ื“ืึธืก ืงืขื ืขืŸ ื–ื™ื™ืŸ ืขืจื™ื™ื ื“ื–ืฉื“ ืึทื ื“ืขืจืฉ.

  1. ื˜ืขืžืขืก ืื™ืŸ ืงืึทืคืงืึท, ืื•ื™ื‘ ืžื™ืจ ื•ื•ื™ืœืŸ ืฆื• ื•ื•ื™ืกืŸ ื“ื™ ืคึผื™ื ื˜ืœืขืš ื“ืขืคึฟื™ื ื™ืฆื™ืข, ืขืก ืื™ื– ื‘ืขืกืขืจ ืฆื• ืœื™ื™ืขื ืขืŸ ืึทื•ื•ืขืง. ื“ืึธืงื•ืžืขื ื˜, ืึธื“ืขืจ ืื™ืจ ืงืขื ืขืŸ ืœื™ื™ืขื ืขืŸ ืงืึธืžืคึผืขื ื“ื™ื•ื ืื•ื™ืฃ Habrรฉ ืื™ืŸ ืจื•ืกื™ืฉ, ื•ื•ื• ืึทืœืฅ ืื™ื– ืื•ื™ืš ืฉืคื™ื’ืœื˜ ื’ืึทื ืฅ ืึทืงื™ืขืจืึทื˜ืœื™ :)

  2. ืคึผืึทืจืึทืžืขื˜ืขืจ ื™ื ืขืจืœืขืš, ื“ื™ืกืงืจื™ื™ื‘ื“ ื’ืึทื ืฅ ื’ื•ื˜ ืื™ืŸ ื“ื™ ืคืึทื•ืกื˜ ื“ืึธืง, ืึทืœืึทื•ื– ืื•ื ื“ื– ืฆื• ืงืึทื ืคื™ื’ื™ืขืจ ื“ื™ ื˜ืขืžืข ื’ืœื™ื™ืš ืื™ืŸ ื“ื™ ืงืึธื“, ื“ืึธืš, ื“ืึธืก ืžื™ื˜ืœ ื“ื™ ืคึผืึทืจืึทืžืขื˜ืขืจืก ืฆื•ื’ืขืฉื˜ืขืœื˜ ื“ื•ืจืš ื“ื™ ืคืึทื•ืกื˜ ื“ืขื•ื•ืขืœืึธืคึผืขืจืก, ืœืžืฉืœ: ืจื™ื˜ืขื ืฉืึทืŸ, ืจื™ื˜ืขื ืฉืึทืŸ ืคึผืึธืœื™ื˜ื™ืง (ื“ื•ืจืš ืคืขืœื™ืงื™ื™ึทื˜ ื•ื™ืกืžืขืงืŸ, ืึธื‘ืขืจ ืื™ืจ ืงืขื ืขืŸ ืฉื˜ืขืœืŸ ืกืึธืœื™ื“), ื ื•ืžืขืจ ืคื•ืŸ ืคึผืึทืจื˜ื™ืฉืึทื ื– ืคึผืขืจ ื˜ืขืžืข (ืกืงืึธืจื–ืฆื• ื˜ืึธืŸ, ืœืžืฉืœ, ื•ื•ื™ื™ื ื™ืงืขืจ ื•ื•ื™ ื’ืœืื‘ืืœืข ื‘ืึทื˜ื™ื™ึทื˜ ืคืึทืกื˜ ืึทืคึผืœืึทืงื™ื™ืฉืึทื ื–).

  3. ืื™ืŸ ืึทืœื’ืขืžื™ื™ืŸ, ื“ืขืจ ืึทื’ืขื ื˜ ืงืขื ืขืŸ ืžืึทื›ืŸ ืึท ื’ืขืจืื˜ืŸ ื˜ืขืžืข ืžื™ื˜ ื’ืœืื‘ืืœืข ื•ื•ืึทืœื•ืขืก, ืึธื‘ืขืจ ืื™ืš ื•ื•ื™ ืฆื• ื“ืขืจืงืœืขืจืŸ ืึทืœืฅ ื‘ืคื™ืจื•ืฉ. ืื™ืŸ ืึทื“ื™ืฉืึทืŸ, ืขื˜ืœืขื›ืข ืคึผืึทืจืึทืžืขื˜ืขืจืก (ืœืžืฉืœ, ื“ื™ ื ื•ืžืขืจ ืคื•ืŸ ืคึผืึทืจื˜ื™ืฉืึทื ื– ืึธื“ืขืจ ืจื™ื˜ืขื ืฉืึทืŸ ืคึผืึธืœื™ื˜ื™ืง) ืคื•ืŸ ื“ื™ ื˜ืขืžืข ืื™ืŸ ื“ื™ ืึทื’ืขื ื˜ ืึทื“ื•ื•ืขืจื˜ื™ื™ื–ืžืึทื ื˜ ืงืขื ืขืŸ ื ื™ื˜ ื–ื™ื™ืŸ ืงืึทื ืคื™ื’ื™ืขืจื“.

    ื“ืึธ ืก ื•ื•ืึธืก ืขืก ืงืขืŸ ืงื•ืงืŸ ื•ื•ื™ ืึธืŸ ืžืึทื ื™ื•ืึทืœื™ ื“ื™ืคื™ื™ื ื™ื ื’ ื“ื™ ื˜ืขืžืข:

app = get_app()

@app.agent()
async def collect_securities(stream: StreamT[None]) -> AsyncIterable[bool]:
	pass

ื ื•, ืื™ืฆื˜ ืœืึธื–ืŸ ืื•ื ื“ื– ื‘ืึทืฉืจื™ื™ึทื‘ืŸ ื•ื•ืึธืก ืื•ื ื“ื–ืขืจ ืึทื’ืขื ื˜ ื•ื•ืขื˜ ื˜ืึธืŸ :)

app = get_app()

collect_securities_topic = app.topic("collect_securities", internal=True)

@app.agent(collect_securities_topic)
async def collect_securities(stream: StreamT[None]) -> 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

ืึทื–ื•ื™, ืื™ืŸ ื“ื™ ืึธื ื”ื™ื™ื‘ ืคื•ืŸ ื“ืขื ืึทื’ืขื ื˜, ืžื™ืจ ืขืคึฟืขื ืขืŸ ืึทืŸ aiohttp ืกืขืกื™ืข ืคึฟืึทืจ ืจื™ืงื•ื•ืขืก ื“ื•ืจืš ืื•ื ื“ื–ืขืจ ืงืœื™ืขื ื˜. ืื–ื•ื™, ื•ื•ืขืŸ ืื™ืจ ืึธื ื”ื™ื™ื‘ืŸ ืึท ืึทืจื‘ืขื˜ืขืจ, ื•ื•ืขืŸ ืื•ื ื“ื–ืขืจ ืึทื’ืขื ื˜ ืื™ื– ืœืึธื ื˜ืฉื˜, ืึท ืกืขืกื™ืข ื•ื•ืขื˜ ื’ืœื™ื™ืš ืขืคึฟืขื ืขืŸ - ืื™ื™ื ืขืจ, ืคึฟืึทืจ ื“ื™ ื’ืื ืฆืข ืฆื™ื™ื˜ ื•ื•ืึธืก ื“ืขืจ ืึทืจื‘ืขื˜ืขืจ ืื™ื– ืคืœื™ืกื ื“ื™ืง (ืึธื“ืขืจ ืขื˜ืœืขื›ืข, ืื•ื™ื‘ ืื™ืจ ื˜ื•ื™ืฉืŸ ื“ืขื ืคึผืึทืจืึทืžืขื˜ืขืจ ืงืึธื ืงื•ืจืจืขื ืกื™ ืคื•ืŸ ืึทืŸ ืึทื’ืขื ื˜ ืžื™ื˜ ืึท ืคืขืœื™ืงื™ื™ึทื˜ ืึทืคึผืึทืจืึทื˜).

ื•ื•ื™ื™ึทื˜ืขืจ, ืžื™ืจ ื ืึธื›ื’ื™ื™ืŸ ื“ื™ ื˜ื™ื™ึทืš (ืžื™ืจ ืฉื˜ืขืœืŸ ื“ืขื ืึธื ื–ืึธื’ ืื™ืŸ _, ื–ื™ื ื˜ ืžื™ืจ, ืื™ืŸ ื“ืขื ืึทื’ืขื ื˜, ื˜ืึธืŸ ื ื™ื˜ ื–ืึธืจื’ืŸ ื•ื•ืขื’ืŸ ื“ื™ ืื™ื ื”ืึทืœื˜) ืคื•ืŸ ืึทืจื˜ื™ืงืœืขืŸ ืคื•ืŸ ืื•ื ื“ื–ืขืจ ื˜ืขืžืข, ืื•ื™ื‘ ื–ื™ื™ ืขืงืกื™ืกื˜ื™ืจืŸ ืื™ืŸ ื“ืขื ืงืจืึทื ื˜ ืคืึธื˜ืึธ, ืึทื ื“ืขืจืฉ ืื•ื ื“ื–ืขืจ ืฆื™ืงืœ ื•ื•ืขื˜ ื•ื•ืึทืจื˜ืŸ ืคึฟืึทืจ ื–ื™ื™ืขืจ ืึธื ืงื•ืžืขืŸ. ื ื•, ืื™ืŸ ืื•ื ื“ื–ืขืจ ืฉืœื™ื™ืฃ, ืžื™ืจ ืงืœืึธืฅ ื“ื™ ืงืึทื‘ืึธืœืข ืคื•ืŸ โ€‹โ€‹ื“ืขื ืึธื ื–ืึธื’, ื‘ืึทืงื•ืžืขืŸ ืึท ืจืฉื™ืžื” ืคื•ืŸ ืึทืงื˜ื™ื•ื• (ื’ืขื˜_ืกืขืงื•ืจื™ื˜ื™ืขืก ืงืขืจื˜ ื‘ืœื•ื™ื– ืึทืงื˜ื™ื•ื• ื“ื•ืจืš ืคืขืœื™ืงื™ื™ึทื˜, ื–ืขืŸ ืงืœื™ืขื ื˜ ืงืึธื“) ืกื™ืงื™ื•ืจืึทื˜ื™ื– ืื•ืŸ ืจืึทื˜ืขื•ื•ืขืŸ ืขืก ืฆื• ื“ื™ ื“ืึทื˜ืึทื‘ื™ื™ืก, ืงืึธื ื˜ืจืึธืœื™ืจืŸ ืื•ื™ื‘ ืขืก ืื™ื– ืึท ื–ื™ื›ืขืจื”ื™ื™ื˜ ืžื™ื˜ ื“ืขืจ ื–ืขืœื‘ื™ืงืขืจ ื˜ื™ืงืขืจ ืื•ืŸ ื•ื•ืขืงืกืœ ืื™ืŸ ื“ื™ ื“ืึทื˜ืึทื‘ื™ื™ืก , ืื•ื™ื‘ ืขืก ืื™ื–, ืขืก (ื“ื™ ืคึผืึทืคึผื™ืจ) ื•ื•ืขื˜ ืคืฉื•ื˜ ื–ื™ื™ืŸ ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงื˜.

ื–ืืœ ืก ืงืึทื˜ืขืจ ืื•ื ื“ื–ืขืจ ืฉืึทืคื•ื ื’!

> docker-compose up -d
... ะ—ะฐะฟัƒัะบ ะบะพะฝั‚ะตะนะฝะตั€ะพะฒ ...
> faust -A horton.agents worker --without-web -l info

ืคึผืก ืคึฟืขื™ึดืงื™ื™ื˜ืŸ ื•ื•ืขื‘ ืงืึธืžืคึผืึธื ืขื ื˜ ืื™ืš ื•ื•ืขืœ ื ื™ืฉื˜ ื‘ืึทื˜ืจืึทื›ื˜ืŸ ืคืึทื•ืกื˜ ืื™ืŸ ื“ื™ ืึทืจื˜ื™ืงืœืขืŸ, ืึทื–ื•ื™ ืžื™ืจ ืฉื˜ืขืœืŸ ื“ื™ ืฆื•ื ืขืžืขืŸ ืคืึธืŸ.

ืื™ืŸ ืื•ื ื“ื–ืขืจ ืงืึทื˜ืขืจ ื‘ืึทืคึฟืขืœ, ืžื™ืจ ื“ืขืจืฆื™ื™ืœื˜ ืคืึทื•ืกื˜ ื•ื•ื• ืฆื• ืงื•ืงืŸ ืคึฟืึทืจ ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ื›ื™ื™ืคืขืฅ ืื•ืŸ ื•ื•ืึธืก ืฆื• ื˜ืึธืŸ ืžื™ื˜ ืื™ื (ืงืึทื˜ืขืจ ืึท ืึทืจื‘ืขื˜ืขืจ) ืžื™ื˜ ื“ื™ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ืงืœืึธืฅ ืจืขื–ื•ืœื˜ืึทื˜ ืžื“ืจื’ื”. ืžื™ืจ ื‘ืึทืงื•ืžืขืŸ ื“ื™ ืคืืœื’ืขื ื“ืข ืจืขื–ื•ืœื˜ืึทื˜:

ืกืคึผืึธื™ืœืขืจ

โ”Œฦ’aยตSโ€  v1.10.4โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id          โ”‚ horton                                            โ”‚
โ”‚ transport   โ”‚ [URL('kafka://localhost:9092')]                   โ”‚
โ”‚ store       โ”‚ memory:                                           โ”‚
โ”‚ log         โ”‚ -stderr- (info)                                   โ”‚
โ”‚ pid         โ”‚ 1271262                                           โ”‚
โ”‚ hostname    โ”‚ host-name                                         โ”‚
โ”‚ platform    โ”‚ CPython 3.8.2 (Linux x86_64)                      โ”‚
โ”‚ drivers     โ”‚                                                   โ”‚
โ”‚   transport โ”‚ aiokafka=1.1.6                                    โ”‚
โ”‚   web       โ”‚ aiohttp=3.6.2                                     โ”‚
โ”‚ datadir     โ”‚ /path/to/project/horton-data                      โ”‚
โ”‚ appdir      โ”‚ /path/to/project/horton-data/v1                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
... ะปะพะณะธ, ะปะพะณะธ, ะปะพะณะธ ...

โ”ŒTopic Partition Setโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ topic                      โ”‚ partitions โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ collect_securities         โ”‚ {0-7}      โ”‚
โ”‚ horton-__assignor-__leader โ”‚ {0}        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ 

ืขืก ืœืขื‘ื˜!!!

ื–ืืœ ืก ืงื•ืง ืื™ืŸ ื“ื™ ืฆืขื˜ื™ื™ืœื•ื ื’ ืฉื˜ืขืœืŸ. ื•ื•ื™ ืžื™ืจ ืงืขื ืขืŸ ื–ืขืŸ, ืึท ื˜ืขืžืข ืื™ื– ื’ืขื•ื•ืขืŸ ื‘ืืฉืืคืŸ ืžื™ื˜ ื“ื™ ื ืึธืžืขืŸ ื•ื•ืึธืก ืžื™ืจ ื“ืขื–ื™ื’ื ื™ื™ื˜ื™ื“ ืื™ืŸ ื“ื™ ืงืึธื“, ื“ื™ ืคืขืœื™ืงื™ื™ึทื˜ ื ื•ืžืขืจ ืคื•ืŸ ืคึผืึทืจื˜ื™ืฉืึทื ื– (8, ื’ืขื ื•ืžืขืŸ ืคึฟื•ืŸ topic_partitions - ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ื›ื™ื™ืคืขืฅ ืคึผืึทืจืึทืžืขื˜ืขืจ), ื–ื™ื ื˜ ืžื™ืจ ื”ืึธื‘ืŸ ื ื™ืฉื˜ ืกืคึผืขืฆื™ืคื™ืฆื™ืจืŸ ืึท ื™ื—ื™ื“ ื•ื•ืขืจื˜ ืคึฟืึทืจ ืื•ื ื“ื–ืขืจ ื˜ืขืžืข (ื“ื•ืจืš ืคึผืึทืจื˜ื™ืฉืึทื ื–). ื“ื™ ืœืึธื ื˜ืฉื˜ ืึทื’ืขื ื˜ ืื™ืŸ ื“ืขืจ ืึทืจื‘ืขื˜ืขืจ ืื™ื– ืึทืกื™ื™ื ื“ ืึทืœืข 8 ืคึผืึทืจื˜ื™ืฉืึทื ื–, ื•ื•ื™ื™ึทืœ ืขืก ืื™ื– ื“ืขืจ ื‘ืœื•ื™ื– ืื™ื™ื ืขืจ, ืึธื‘ืขืจ ื“ืึธืก ื•ื•ืขื˜ ื–ื™ื™ืŸ ื“ื™ืกืงืึทืกื˜ ืื™ืŸ ืžืขืจ ื“ืขื˜ืึทืœ ืื™ืŸ ื“ืขื ื˜ื™ื™ืœ ื•ื•ืขื’ืŸ ืงืœืึทืกื˜ืขืจื™ื ื’.

ื ื•, ืื™ืฆื˜ ืžื™ืจ ืงืขื ืขืŸ ื’ื™ื™ืŸ ืฆื• ืืŸ ืื ื“ืขืจ ื•ื•ืึธืงื–ืึทืœ ืคึฟืขื ืฆื˜ืขืจ ืื•ืŸ ืฉื™ืงืŸ ืึท ืœื™ื™ื“ื™ืง ืึธื ื–ืึธื’ ืฆื• ืื•ื ื“ื–ืขืจ ื˜ืขืžืข:

> faust -A horton.agents send @collect_securities
{"topic": "collect_securities", "partition": 6, "topic_partition": ["collect_securities", 6], "offset": 0, "timestamp": ..., "timestamp_type": 0}

ืคึผืก ื ื™ืฆืŸ @ ืžื™ืจ ื•ื•ื™ื™ึทื–ืŸ ืึทื– ืžื™ืจ ืฉื™ืงืŸ ืึท ืึธื ื–ืึธื’ ืฆื• ืึท ื˜ืขืžืข ืžื™ื˜ืŸ ื ืึธืžืขืŸ "collect_securities".

ืื™ืŸ ื“ืขื ืคืึทืœ, ื“ืขืจ ืึธื ื–ืึธื’ ืื™ื– ื’ืขื’ืื ื’ืขืŸ ืฆื• ืฆืขื˜ื™ื™ืœื•ื ื’ 6 - ืื™ืจ ืงืขื ืขืŸ ืงืึธื ื˜ืจืึธืœื™ืจืŸ ื“ืขื ื“ื•ืจืš ื’ื™ื™ืŸ ืฆื• ืงืึทืคื“ืจืึธืคึผ ืื•ื™ืฃ localhost:9000

ื’ื™ื™ืŸ ืฆื• ื“ื™ ื•ื•ืึธืงื–ืึทืœ ืคึฟืขื ืฆื˜ืขืจ ืžื™ื˜ ืื•ื ื“ื–ืขืจ ืึทืจื‘ืขื˜ืขืจ, ืžื™ืจ ื•ื•ืขืœืŸ ื–ืขืŸ ืึท ื’ืœื™ืงืœืขืš ืึธื ื–ืึธื’ ื’ืขืฉื™ืงื˜ ื ื™ืฆืŸ ืœืึธื’ื•ืจื•:

2020-09-23 00:26:37.304 | INFO     | horton.agents:collect_securities:40 - Start collect securities

ืžื™ืจ ืงืขื ืขืŸ ืื•ื™ืš ืงื•ืงืŸ ืื™ืŸ ืžืึธื ื’ืึธ (ื ื™ืฆืŸ Robo3T ืึธื“ืขืจ Studio3T) ืื•ืŸ ื–ืขืŸ ืึทื– ื“ื™ ืกื™ืงื™ื•ืจืึทื˜ื™ื– ื–ืขื ืขืŸ ืื™ืŸ ื“ื™ ื“ืึทื˜ืึทื‘ื™ื™ืก:

ืื™ืš ื‘ื™ืŸ ื ื™ืฉื˜ ืึท ื‘ื™ืœื™ืึทื ืขืจ, ืื•ืŸ ื“ืขืจื™ื‘ืขืจ ืžื™ืจ ื–ืขื ืขืŸ ืฆื•ืคืจื™ื“ืŸ ืžื™ื˜ ื“ืขืจ ืขืจืฉื˜ืขืจ ื•ื•ื™ื•ื™ื ื’ ืึธืคึผืฆื™ืข.

ื”ื™ื ื˜ืขืจื’ืจื•ื ื˜ ื˜ืึทืกืงืก ืื•ื™ืฃ Faust, ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–ื”ื™ื ื˜ืขืจื’ืจื•ื ื˜ ื˜ืึทืกืงืก ืื•ื™ืฃ Faust, ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–

ื’ืœื™ืง ืื•ืŸ ืคืจื™ื™ื“ - ื“ืขืจ ืขืจืฉื˜ืขืจ ืึทื’ืขื ื˜ ืื™ื– ื’ืจื™ื™ื˜ :)

ืึทื’ืขื ื˜ ื’ืจื™ื™ื˜, ืœืึทื ื’ ืœืขื‘ืŸ ื“ืขืจ ื ื™ื™ึท ืึทื’ืขื ื˜!

ื™ืึธ, ืจื‘ื•ืชื™, ืžื™ืจ ื”ืึธื‘ืŸ ื‘ืœื•ื™ื– ื‘ืื“ืขืงื˜ 1/3 ืคื•ืŸ ื“ืขื ื•ื•ืขื’ ืฆื•ื’ืขื’ืจื™ื™ื˜ ื“ื•ืจืš ื“ืขื ืึทืจื˜ื™ืงืœ, ืึธื‘ืขืจ ื˜ืึธืŸ ื ื™ื˜ ื–ื™ื™ืŸ ื“ื™ืกืงืขืจื™ื“ื–ืฉื“, ื•ื•ื™ื™ึทืœ ืื™ืฆื˜ ืขืก ื•ื•ืขื˜ ื–ื™ื™ืŸ ื’ืจื™ื ื’ืขืจ.

ืื™ืฆื˜ ืžื™ืจ ื“ืึทืจืคึฟืŸ ืึทืŸ ืึทื’ืขื ื˜ ื•ื•ืึธืก ืงืึทืœืขืงืฅ ืžืขื˜ืึท ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ืื•ืŸ ืœื™ื™ื’ื˜ ืขืก ืื™ืŸ ืึท ื–ืึทืžืœื•ื ื’ ื“ืึธืงื•ืžืขื ื˜:

collect_security_overview_topic = app.topic("collect_security_overview", internal=True)


@app.agent(collect_security_overview_topic)
async def collect_security_overview(
    stream: StreamT[?],
) -> AsyncIterable[bool]:
    async with aiohttp.ClientSession() as session:
        async for event in stream:
            ...

ื–ื™ื ื˜ ื“ืขืจ ืึทื’ืขื ื˜ ื•ื•ืขื˜ ืคึผืจืึธืฆืขืก ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื•ื•ืขื’ืŸ ืึท ืกืคึผืขืฆื™ืคื™ืฉ ื–ื™ื›ืขืจื”ื™ื™ื˜, ืžื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืึธื ื•ื•ื™ื™ึทื–ืŸ ื“ื™ ื˜ื™ืงืขืจ (ืกื™ืžื‘ืึธืœ) ืคื•ืŸ ื“ืขื ื–ื™ื›ืขืจื”ื™ื™ื˜ ืื™ืŸ ื“ืขื ืึธื ื–ืึธื’. ืคึฟืึทืจ ื“ืขื ืฆื•ื•ืขืง ืื™ืŸ ืคืึทื•ืกื˜ ืขืก ื–ืขื ืขืŸ ืจืขืงืึธืจื“ืก - ืงืœืืกืŸ ื•ื•ืึธืก ื“ืขืจืงืœืขืจืŸ ื“ื™ ืึธื ื–ืึธื’ ืกื›ืขืžืข ืื™ืŸ ื“ื™ ืึทื’ืขื ื˜ ื˜ืขืžืข.

ืื™ืŸ ื“ืขื ืคืึทืœ, ืœืึธื–ืŸ ืื•ื ื“ื– ื’ื™ื™ืŸ ืฆื• records.py ืื•ืŸ ื‘ืึทืฉืจื™ื™ึทื‘ืŸ ื•ื•ื™ ื“ืขืจ ืึธื ื–ืึธื’ ืคึฟืึทืจ ื“ืขื ื˜ืขืžืข ื–ืึธืœ ืงื•ืงืŸ ื•ื•ื™:

import faust


class CollectSecurityOverview(faust.Record):
    symbol: str
    exchange: str

ื•ื•ื™ ืื™ืจ ืงืขืŸ ื”ืึธื‘ืŸ ื’ืขืกื˜, Faust ื ื™ืฆื˜ ื“ื™ ืคึผื™ื˜ื”ืึธืŸ ื˜ื™ืคึผ ืึทื ืึธื˜ืึทืฆื™ืข ืฆื• ื‘ืึทืฉืจื™ื™ึทื‘ืŸ ื“ื™ ืึธื ื–ืึธื’ ืกื›ืขืžืข, ื•ื•ืึธืก ืื™ื– ื•ื•ืึธืก ื“ื™ ืžื™ื ื™ืžื•ื ื•ื•ืขืจืกื™ืข ื’ืขืฉื˜ื™ืฆื˜ ื“ื•ืจืš ื“ื™ ื‘ื™ื‘ืœื™ืึธื˜ืขืง ืื™ื– 3.6.

ืœืึธืžื™ืจ ืฆื•ืจื™ืงืงื•ืžืขืŸ ืฆื• ื“ื™ ืึทื’ืขื ื˜, ืฉื˜ืขืœืŸ ื“ื™ ื˜ื™ื™ืคึผืก ืื•ืŸ ืœื™ื™ื’ืŸ ืขืก:

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],
) -> 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

ื•ื•ื™ ืื™ืจ ืงืขื ืขืŸ ื–ืขืŸ, ืžื™ืจ ืคืึธืจืŸ ืึท ื ื™ื™ึทืข ืคึผืึทืจืึทืžืขื˜ืขืจ ืžื™ื˜ ืึท ืกื›ืขืžืข ืฆื• ื“ืขืจ ื˜ืขืžืข ื™ื ื™ื˜ื™ืึทืœื™ื–ืึทื˜ื™ืึธืŸ ืื•ืคึฟืŸ - value_type. ื•ื•ื™ื™ึทื˜ืขืจ, ืึทืœืฅ ื’ื™ื™ื˜ ื“ืขืจ ื–ืขืœื‘ื™ืงืขืจ ืกื›ืขืžืข, ืึทื–ื•ื™ ืื™ืš ื˜ืึธืŸ ื ื™ื˜ ื–ืขืŸ ืงื™ื™ืŸ ืคื•ื ื˜ ืื™ืŸ ื•ื•ื•ื™ื ืขืŸ ืื•ื™ืฃ ืขืคึผืขืก ืึทื ื“ืขืจืฉ.

ื ื•, ื“ื™ ืœืขืฆื˜ ืคืึทืจื‘ื™ื ื“ืŸ ืื™ื– ืฆื• ืœื™ื™ื’ืŸ ืึท ืจื•ืฃ ืฆื• ื“ื™ ืžืขื˜ืึท ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื–ืึทืžืœื•ื ื’ ืึทื’ืขื ื˜ ืฆื• collect_securitites:

....
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"])
    )
....

ืžื™ืจ ื ื•ืฆืŸ ื“ื™ ืคืจื™ืขืจ ืžื•ื“ื™ืข ืกื›ืขืžืข ืคึฟืึทืจ ื“ืขื ืึธื ื–ืึธื’. ืื™ืŸ ื“ืขื ืคืึทืœ, ืื™ืš ื’ืขื•ื•ื™ื™ื ื˜ ื“ื™ .ืงืึทืกื˜ ืื•ืคึฟืŸ ื–ื™ื ื˜ ืžื™ืจ ื˜ืึธืŸ ื ื™ื˜ ื“ืึทืจืคึฟืŸ ืฆื• ื•ื•ืึทืจื˜ืŸ ืคึฟืึทืจ ื“ื™ ืจืขื–ื•ืœื˜ืึทื˜ ืคื•ืŸ ื“ื™ ืึทื’ืขื ื˜, ืึธื‘ืขืจ ืขืก ืื™ื– ื•ื•ืขืจื˜ ื“ืขืจืžืึธื ืขืŸ ืึทื– ื•ื•ืขื’ืŸ ืฉื™ืงืŸ ืึท ืึธื ื–ืึธื’ ืฆื• ื“ื™ ื˜ืขืžืข:

  1. ื•ื•ืึทืจืคืŸ - ื˜ื•ื˜ ื ื™ืฉื˜ ืคืึทืจืฉืคึผืึทืจืŸ ื•ื•ื™ื™ึทืœ ืขืก ื˜ื•ื˜ ื ื™ืฉื˜ ื“ืขืจื•ื•ืึทืจื˜ืŸ ืึท ืจืขื–ื•ืœื˜ืึทื˜. ืื™ืจ ืงืขื ืขืŸ ื ื™ืฉื˜ ืฉื™ืงืŸ ื“ื™ ืจืขื–ื•ืœื˜ืึทื˜ ืฆื• ืืŸ ืื ื“ืขืจ ื˜ืขืžืข ื•ื•ื™ ืึท ืึธื ื–ืึธื’.

  2. ืฉื™ืงืŸ - ื˜ื•ื˜ ื ื™ืฉื˜ ืคืึทืจืฉืคึผืึทืจืŸ ื•ื•ื™ื™ึทืœ ืขืก ื˜ื•ื˜ ื ื™ืฉื˜ ื“ืขืจื•ื•ืึทืจื˜ืŸ ืึท ืจืขื–ื•ืœื˜ืึทื˜. ืื™ืจ ืงืขื ืขืŸ ืกืคึผืขืฆื™ืคื™ืฆื™ืจืŸ ืึทืŸ ืึทื’ืขื ื˜ ืื™ืŸ ื“ืขืจ ื˜ืขืžืข ืฆื• ื•ื•ืึธืก ื“ืขืจ ืจืขื–ื•ืœื˜ืึทื˜ ื•ื•ืขื˜ ื’ื™ื™ืŸ.

  3. ืคืจืขื’ืŸ - ื•ื•ื™ื™ืฅ ืคึฟืึทืจ ืึท ืจืขื–ื•ืœื˜ืึทื˜. ืื™ืจ ืงืขื ืขืŸ ืกืคึผืขืฆื™ืคื™ืฆื™ืจืŸ ืึทืŸ ืึทื’ืขื ื˜ ืื™ืŸ ื“ืขืจ ื˜ืขืžืข ืฆื• ื•ื•ืึธืก ื“ืขืจ ืจืขื–ื•ืœื˜ืึทื˜ ื•ื•ืขื˜ ื’ื™ื™ืŸ.

ืึทื–ื•ื™, ื“ืึธืก ืื™ื– ืึทืœืข ืžื™ื˜ ืื’ืขื ื˜ืŸ ืคึฟืึทืจ ื”ื™ื™ึทื ื˜!

ื“ืขืจ ื—ืœื•ื ืžืึทื ืฉืึทืคึฟื˜

ื“ื™ ืœืขืฆื˜ืข ื–ืึทืš ืื™ืš ืฆื•ื’ืขื–ืื’ื˜ ืฆื• ืฉืจื™ื™ึทื‘ืŸ ืื™ืŸ ื“ืขื ื˜ื™ื™ืœ ืื™ื– ืงืึทืžืึทื ื“ื–. ื•ื•ื™ ื“ืขืจืžืื ื˜ ืคืจื™ืขืจ, ืงืึทืžืึทื ื“ื– ืื™ืŸ ืคืึทื•ืกื˜ ื–ืขื ืขืŸ ืึท ืจืึทืคึผืขืจ ืึทืจื•ื ื’ื™ื˜. ืื™ืŸ ืคืึทืงื˜, Faust ืคืฉื•ื˜ ืึทื˜ืึทื˜ืฉื™ื– ืื•ื ื“ื–ืขืจ ืžื ื”ื’ ื‘ืึทืคึฟืขืœ ืฆื• ื–ื™ื™ืŸ ืฆื•ื‘ื™ื ื“ ื•ื•ืขืŸ ืกืคึผืขืฆื™ืคื™ืฆื™ืจืŸ ื“ื™ -A ืฉืœื™ืกืœ

ื ืึธืš ื“ื™ ืžื•ื“ื™ืข ืื’ืขื ื˜ืŸ ืื™ืŸ agents.py ืœื™ื™ื’ืŸ ืึท ืคึฟื•ื ืงืฆื™ืข ืžื™ื˜ ืึท ื“ืขืงืขืจื™ื™ื˜ืขืจ app.commandืจื•ืคืŸ ื“ืขื ืื•ืคึฟืŸ ื’ื•ืก ัƒ collect_securitites:

@app.command()
async def start_collect_securities():
    """Collect securities and overview."""

    await collect_securities.cast()

ืื–ื•ื™, ืื•ื™ื‘ ืžื™ืจ ืจื•ืคืŸ ื“ื™ ืจืฉื™ืžื” ืคื•ืŸ ืงืึทืžืึทื ื“ื–, ืื•ื ื“ื–ืขืจ ื ื™ื™ึทืข ื‘ืึทืคึฟืขืœ ื•ื•ืขื˜ ื–ื™ื™ืŸ ืื™ืŸ ืขืก:

> 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.

ืžื™ืจ ืงืขื ืขืŸ ื ื•ืฆืŸ ืขืก ื•ื•ื™ ื•ื•ืขืจ ืขืก ื™ื– ืึทื ื“ืขืจืฉ, ืึทื–ื•ื™ ืœืึธื–ืŸ ืื•ื ื“ื– ืจื™ืกื˜ืึทืจื˜ ื“ื™ ืคืึทื•ืกื˜ ืึทืจื‘ืขื˜ืขืจ ืื•ืŸ ืึธื ื”ื™ื™ื‘ืŸ ืึท ืคื•ืœ-ืคืœืขื“ื–ืฉื“ ื–ืึทืžืœื•ื ื’ ืคื•ืŸ ืกื™ืงื™ื•ืจืึทื˜ื™ื–:

> faust -A horton.agents start-collect-securities

ื•ื•ืึธืก ื•ื•ืขื˜ ืคึผืึทืกื™ืจืŸ ื•ื•ื™ื™ึทื˜ืขืจ?

ืื™ืŸ ื“ืขืจ ื•ื•ื™ื™ึทื˜ืขืจ ื˜ื™ื™ืœ, ื ื™ืฆืŸ ื“ื™ ืจื•ืขืŸ ืื’ืขื ื˜ืŸ ื•ื•ื™ ืึท ื‘ื™ื™ืฉืคึผื™ืœ, ืžื™ืจ ื•ื•ืขืœืŸ ื‘ืึทื˜ืจืึทื›ื˜ืŸ ื“ื™ ื–ื™ื ืงืขืŸ ืžืขืงืึทื ื™ื–ืึทื ืคึฟืึทืจ ื–ื•ื›ืŸ ืคึฟืึทืจ ืขืงืกื˜ืจืขืžืขืก ืื™ืŸ ื“ื™ ืงืœืึธื•ื–ื™ื ื’ ืคึผืจื™ื™ื– ืคื•ืŸ ื˜ืจื™ื™ื“ื™ื ื’ ืคึฟืึทืจ ื“ื™ ื™ืึธืจ ืื•ืŸ ื“ื™ ืงืึทื˜ืขืจ ืคื•ืŸ ืึทื’ืขื ืฅ.

ืึทื– ืก ืึทืœืข ืคึฟืึทืจ ื”ื™ื™ึทื ื˜! ื“ืึทื ืงืขืŸ ืคึฟืึทืจ ืœื™ื™ืขื ืขืŸ :)

ืงืึธื“ ืคึฟืึทืจ ื“ืขื ื˜ื™ื™ืœ

ื”ื™ื ื˜ืขืจื’ืจื•ื ื˜ ื˜ืึทืกืงืก ืื•ื™ืฃ Faust, ื˜ื™ื™ืœ ื•ื•: ืึทื’ืขื ืฅ ืื•ืŸ ื˜ื™ืžื–

ืคึผืก ืื•ื ื˜ืขืจ ื“ื™ ืœืขืฆื˜ืข ื˜ื™ื™ืœ ืื™ืš ืื™ื– ื’ืขื•ื•ืขืŸ ื’ืขืคืจืขื’ื˜ ื•ื•ืขื’ืŸ ืคืึทื•ืกื˜ ืื•ืŸ ืงืึทื ืคืœื•ืึทื ื˜ ืงืึทืคืงืึท (ื•ื•ืึธืก ืคึฟืขื™ึดืงื™ื™ื˜ืŸ ื”ืื˜ ืงืึธื ืคืœื•ืขื ื˜?). ืขืก ืžื™ื™ื ื˜ ืึทื– ืงืึทื ืคืœื•ืึทื ื˜ ืื™ื– ืžืขืจ ืคืึทื ื’ืงืฉืึทื ืึทืœ ืื™ืŸ ืคื™ืœืข ื•ื•ืขื’ืŸ, ืึธื‘ืขืจ ื“ืขืจ ืคืึทืงื˜ ืื™ื– ืึทื– ืคืึทื•ืกื˜ ื˜ื•ื˜ ื ื™ืฉื˜ ื”ืึธื‘ืŸ ืคื•ืœ ืงืœื™ืขื ื˜ ืฉื˜ื™ืฆืŸ ืคึฟืึทืจ ืงืึทื ืคืœื•ืึทื ื˜ - ื“ืึธืก ื’ื™ื™ื˜ ืคึฟื•ืŸ ื“ื™ืกืงืจื™ืคึผืฉืึทื ื– ืคื•ืŸ ืงืœื™ืขื ื˜ ืจื™ืกื˜ืจื™ืงืฉืึทื ื– ืื™ืŸ ื“ื™ ื“ืึธืง.

ืžืงื•ืจ: www.habr.com

ืœื™ื™ื’ืŸ ืึท ื‘ืึทืžืขืจืงื•ื ื’