import logging from datetime import datetime from pathlib import Path from typing import Dict import json logger = logging.getLogger(__name__) class ObsidianLogger: """Logs trades directly to Obsidian vault file.""" def __init__(self, vault_path: str, trade_log_file: str): self.vault_path = Path(vault_path) self.trade_log_file = trade_log_file self.log_path = self.vault_path / self.trade_log_file def log_trade(self, trade_data: Dict) -> bool: """ Log trade to Obsidian markdown file. Args: trade_data: Trade details (timestamp, order_id, pair, side, quantity, price, stop_loss) Returns: True if logged successfully """ try: # Ensure directory exists self.log_path.parent.mkdir(parents=True, exist_ok=True) # Format trade entry timestamp = trade_data.get('timestamp', datetime.utcnow()) entry = self._format_trade_entry(trade_data) # Append to log file with open(self.log_path, 'a', encoding='utf-8') as f: f.write(entry) logger.info(f"Trade logged to Obsidian: {trade_data.get('order_id')}") return True except Exception as e: logger.error(f"Obsidian log error: {e}") return False def _format_trade_entry(self, trade: Dict) -> str: """Format trade as markdown entry""" timestamp = trade.get('timestamp', datetime.utcnow()) entry = f""" ## {timestamp.isoformat()} | {trade['pair']} | {trade['side']} - **Order ID:** {trade['order_id']} - **Quantity:** {trade['quantity']} BTC - **Price:** ${trade['price']} - **Stop Loss:** ${trade['stop_loss']} - **Type:** DCA Bot Trade --- """ return entry def log_stop_loss_hit(self, position: Dict, current_price: float) -> bool: """Log stop loss event""" try: entry = f""" ### ⚠️ STOP LOSS HIT | {position['symbol']} - **Order ID:** {position['order_id']} - **Entry Price:** ${position['entry_price']} - **Stop Loss:** ${position['stop_loss_price']} - **Current Price:** ${current_price} - **Loss %:** {((current_price - position['entry_price']) / position['entry_price'] * 100):.2f}% - **Closed:** {datetime.utcnow().isoformat()} --- """ with open(self.log_path, 'a', encoding='utf-8') as f: f.write(entry) return True except Exception as e: logger.error(f"Stop loss log error: {e}") return False