87 lines
2.6 KiB
Python
Executable File
87 lines
2.6 KiB
Python
Executable File
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
|