Coverage for src/cc_liquid/cli_callbacks.py: 0%

51 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-10-13 20:16 +0000

1"""Rich-based CLI callbacks implementation. 

2 

3This module depends on Rich and rendering helpers and is intentionally 

4separated from the core `callbacks` definitions to avoid UI deps in core. 

5""" 

6 

7from typing import Any 

8 

9from rich.console import Console 

10from rich.prompt import Confirm 

11 

12from .callbacks import CCLiquidCallbacks 

13from .cli_display import display_execution_summary, show_rebalancing_plan 

14 

15 

16class RichCLICallbacks(CCLiquidCallbacks): 

17 """Rich CLI/Terminal UI implementation of `CCLiquidCallbacks`.""" 

18 

19 def __init__(self): 

20 self.console = Console() 

21 

22 def ask_confirmation(self, message: str) -> bool: 

23 return Confirm.ask(f"\n[bold yellow]{message}[/bold yellow]") 

24 

25 def info(self, message: str) -> None: 

26 self.console.print(f"[cyan]{message}[/cyan]") 

27 

28 def warn(self, message: str) -> None: 

29 self.console.print(f"[yellow]{message}[/yellow]") 

30 

31 def error(self, message: str) -> None: 

32 self.console.print(f"[red]{message}[/red]") 

33 

34 def on_config_override(self, overrides: list[str]) -> None: 

35 if overrides: 

36 self.console.print( 

37 f"[yellow]Applied CLI overrides: {', '.join(overrides)}[/yellow]" 

38 ) 

39 

40 def on_trade_start(self, idx: int, total: int, trade: dict[str, Any]) -> None: 

41 side = "BUY" if trade["is_buy"] else "SELL" 

42 side_style = "green" if side == "BUY" else "red" 

43 self.console.print( 

44 f" [{idx}/{total}] {trade['coin']} [{side_style}]{side}[/{side_style}] " 

45 f"{trade['sz']:.4f} @ ${trade['price']:,.4f}...", 

46 end="", 

47 ) 

48 

49 def on_trade_fill( 

50 self, trade: dict[str, Any], fill_data: dict[str, Any], slippage_pct: float 

51 ) -> None: 

52 avg_px = float(fill_data.get("avgPx", trade["price"])) 

53 slippage_style = "green" if slippage_pct <= 0 else "red" 

54 self.console.print( 

55 f" [green]✓[/green] Filled @ ${avg_px:,.4f} " 

56 f"([{slippage_style}]{slippage_pct:+.3f}%[/{slippage_style}])" 

57 ) 

58 

59 def on_trade_fail(self, trade: dict[str, Any], reason: str) -> None: 

60 self.console.print(f" [red]✗ {reason}[/red]") 

61 

62 def on_batch_complete(self, success: list[dict], failed: list[dict]) -> None: 

63 if not success and not failed: 

64 return 

65 total = len(success) + len(failed) 

66 self.console.print( 

67 f"\n[bold]Batch Complete:[/bold] " 

68 f"[green]{len(success)}/{total} succeeded[/green]" 

69 f"{f' [red]{len(failed)} failed[/red]' if failed else ''}" 

70 ) 

71 

72 def show_trade_plan( 

73 self, 

74 target_positions: dict, 

75 trades: list, 

76 account_value: float, 

77 leverage: float, 

78 ) -> None: 

79 show_rebalancing_plan( 

80 self.console, target_positions, trades, account_value, leverage 

81 ) 

82 

83 def show_execution_summary( 

84 self, 

85 successful_trades: list[dict], 

86 all_trades: list[dict], 

87 target_positions: dict, 

88 account_value: float, 

89 ) -> None: 

90 display_execution_summary( 

91 self.console, successful_trades, all_trades, target_positions, account_value 

92 ) 

93 

94 def on_order_submitted(self, order) -> None: 

95 strategy = order.strategy.upper().replace("_", " ") 

96 self.console.print( 

97 f"[cyan]Order submitted:[/cyan] {order.coin} {order.side} " 

98 f"({strategy}, ID: {order.order_id[:12]}...)" 

99 ) 

100 

101 def on_order_update(self, order, fill_pct: float) -> None: 

102 self.console.print( 

103 f" {order.coin}: {fill_pct:.0f}% filled " 

104 f"({order.filled_size:.2f}/{order.size:.2f})" 

105 ) 

106 

107 def show_open_orders(self, orders: list) -> None: 

108 from .cli_display import create_open_orders_panel 

109 panel = create_open_orders_panel(orders) 

110 self.console.print(panel) 

111 

112 def show_order_history(self, history, days: int) -> None: 

113 from .cli_display import create_order_history_panel 

114 panel = create_order_history_panel(history, days) 

115 self.console.print(panel)