Source code for tradeexecutor.cli.approval
"""Approve new trades in the console."""
from typing import List
import textwrap
from prompt_toolkit import print_formatted_text, HTML
from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog
from tradeexecutor.state.state import State
from tradeexecutor.state.portfolio import Portfolio
from tradeexecutor.state.position import TradingPosition
from tradeexecutor.state.trade import TradeExecution
from tradeexecutor.strategy.approval import ApprovalModel
[docs]class CLIApprovalModel(ApprovalModel):
"""Confirm trades in the CLI before they go through.
The terminal execution of the bot stops until the user confirms the trades.
If no one is there to press a key then nothing happens.
"""
[docs] def render_portfolio(self, portfolio: Portfolio) -> HTML:
"""Render the current portfolio holdings using ANSI formatting.
https://python-prompt-toolkit.readthedocs.io/en/master/pages/printing_text.html
:return: promp_toolkit HTML for displaying the portfolio
"""
equity = portfolio.get_total_equity()
cash = portfolio.get_cash()
text = textwrap.dedent(f"""
Total equity <ansigreen>${equity:,.2f}</ansigreen>
Current cash <ansigreen>${cash:,.2f}</ansigreen>""")
text += '\n'
positions: List[TradingPosition] = list(portfolio.get_executed_positions())
if positions:
for tp in positions:
text += f"<b>{tp.get_name()}</b>: <ansigreen>${tp.get_value():,.2f}</ansigreen> at quantity of <ansigreen>{tp.get_quantity()} {tp.get_quantity_unit_name()}</ansigreen>\n"
else:
text += f"<ansired>No open positions</ansired>"
return HTML(text)
[docs] def confirm_trades(self, state: State, trades: List[TradeExecution]) -> List[TradeExecution]:
"""Create a checkbox list to approve trades using prompt_toolkit.
See https://python-prompt-toolkit.readthedocs.io/en/master/pages/dialogs.html#checkbox-list-dialog
:param state: The current trade execution state
:param trades: New trades to be executed
:return: What trades went through human approval
"""
# Show the user what we got
text = self.render_portfolio(state.portfolio)
new_trades = [
(t.trade_id, t.get_human_description())
for t in trades
]
# Did not detect any new trades
if len(new_trades) == 0:
message_dialog(
title='No new trades to execute',
text=text).run()
return []
approvals_dialog = checkboxlist_dialog(
title="New trades to execute",
text=text,
values=new_trades,
)
approvals = approvals_dialog.run()
return [t for t in trades if t.trade_id in approvals]