Path: blob/master/ invest-robot-contest_invest-bot-main/blog/blogger.py
5925 views
import asyncio1import logging2from decimal import Decimal34from tinkoff.invest import OrderState56from configuration.settings import BlogSettings, StrategySettings7from invest_api.utils import moneyvalue_to_decimal8from trade_system.signal import SignalType9from trade_system.strategies.base_strategy import IStrategy10from trading.trade_results import TradeOrder1112__all__ = ("Blogger")1314logger = logging.getLogger(__name__)151617class Blogger:18"""19Class formats and sends messages to telegram chat.20"""21def __init__(22self,23blog_settings: BlogSettings,24trade_strategies: list[StrategySettings],25messages_queue: asyncio.Queue26) -> None:27self.__blog_status = blog_settings.blog_status28self.__trade_strategies: dict[str, StrategySettings] = {x.figi: x for x in trade_strategies}29self.__messages_queue = messages_queue3031def __send_text_message(self, text: str) -> None:32try:33logger.debug(f"Put message to telegram messages queue: {text}")3435self.__messages_queue.put_nowait(text)36except Exception as ex:37logger.error(f"Error put message to telegram messages queue: {repr(ex)}")3839def start_trading_message(40self,41today_trade_strategy: dict[str, IStrategy],42rub_before_trade_day: Decimal43) -> None:44"""45The method sends message about depo size, list of stocks for today trading and greetings also.46"""47if self.__blog_status:48self.__send_text_message("Greetings! We are starting.")49self.__send_text_message(f"Depo size: {rub_before_trade_day:.2f} rub")50self.__send_text_message("Stocks list:")51for figi_key, strategy_value in today_trade_strategy.items():52self.__send_text_message(53f"Ticker: {strategy_value.settings.ticker}. "54f"Short trade status: {strategy_value.settings.short_enabled_flag}"55)5657def finish_trading_message(self) -> None:58"""59The method sends information that trading is stopping.60"""61if self.__blog_status:62self.__send_text_message("We are closing trading day.")6364def close_position_message(self, trade_order: TradeOrder) -> None:65"""66The method sends information about closed position.67"""68if self.__blog_status and trade_order:69signal_type = Blogger.__signal_type_to_message_test(trade_order.signal.signal_type)70self.__send_text_message(71f"{self.__trade_strategies[trade_order.signal.figi].ticker} position {signal_type} has been closed."72)7374def open_position_message(self, trade_order: TradeOrder) -> None:75"""76The method sends information about opened position.77"""78if self.__blog_status and trade_order:79signal_type = Blogger.__signal_type_to_message_test(trade_order.signal.signal_type)80self.__send_text_message(81f"{self.__trade_strategies[trade_order.signal.figi].ticker} position {signal_type} has been opened. "82f"Take profit level: {trade_order.signal.take_profit_level:.2f}. "83f"Stop loss level: {trade_order.signal.stop_loss_level:.2f}."84)8586def trading_depo_summary_message(87self,88rub_before_trade_day: Decimal,89current_rub_on_depo: Decimal90) -> None:91"""92The method sends information about trading day summary.93"""94if self.__blog_status:95self.__send_text_message(96f"Start depo: {rub_before_trade_day:.2f} close depo:{current_rub_on_depo:.2f}."97)9899today_profit = current_rub_on_depo - rub_before_trade_day100today_percent_profit = (today_profit / rub_before_trade_day) * 100101self.__send_text_message(f"Today leverage: {today_profit:.2f} rub ({today_percent_profit:.2f} %)")102103def fail_message(self):104"""105The method sends information about emergency situation in bot.106"""107if self.__blog_status:108self.__send_text_message(109f"Something went wrong. We are trying to close all positions. "110f"If we fail, please try to do it himself."111)112113def summary_message(self):114"""115The method sends just summary title.116"""117if self.__blog_status:118self.__send_text_message(f"Trading day summary:")119120def final_message(self):121"""122The method sends just goodbye title.123"""124if self.__blog_status:125self.__send_text_message(f"Trading has been completed. See you on next trade day!")126127def summary_open_signal_message(self, trade_order: TradeOrder, open_order_state: OrderState):128"""129The method sends summary information about only open positions (not closed)130"""131if self.__blog_status:132signal_type = Blogger.__signal_type_to_message_test(trade_order.signal.signal_type)133summary_commission = moneyvalue_to_decimal(open_order_state.executed_commission) + \134moneyvalue_to_decimal(open_order_state.service_commission)135self.__send_text_message(136f"Open {signal_type} position for {self.__trade_strategies[trade_order.signal.figi].ticker}. "137f"Lots executed: {open_order_state.lots_executed}. "138f"Average price: "139f"{moneyvalue_to_decimal(open_order_state.average_position_price):.2f}. "140f"Total order price: "141f"{moneyvalue_to_decimal(open_order_state.total_order_amount):.2f}. "142f"Total commissions: "143f"{summary_commission:.2f}. "144f"You have to close position manually."145)146147def summary_closed_signal_message(self,148trade_order: TradeOrder,149open_order_state: OrderState,150close_order_state: OrderState151) -> None:152"""153The method sends summary information about closed positions154"""155if self.__blog_status:156signal_type = Blogger.__signal_type_to_message_test(trade_order.signal.signal_type)157summary_commission = moneyvalue_to_decimal(open_order_state.executed_commission) + \158moneyvalue_to_decimal(open_order_state.service_commission) + \159moneyvalue_to_decimal(close_order_state.executed_commission) + \160moneyvalue_to_decimal(close_order_state.service_commission)161self.__send_text_message(162f"Close {signal_type} position for {self.__trade_strategies[trade_order.signal.figi].ticker}. "163f"Lots executed: {close_order_state.lots_executed}. "164f"Average open price: "165f"{moneyvalue_to_decimal(open_order_state.average_position_price):.2f}. "166f"Average close price: "167f"{moneyvalue_to_decimal(close_order_state.average_position_price):.2f}. "168f"Summary: "169f"{moneyvalue_to_decimal(close_order_state.total_order_amount) - moneyvalue_to_decimal(open_order_state.total_order_amount):.2f}. "170f"Total commissions: "171f"{summary_commission:.2f}."172)173174@staticmethod175def __signal_type_to_message_test(signal_type: SignalType) -> str:176return "long" if signal_type == SignalType.LONG else "short"177178179