tradpas / src /executor.py
tpc-pascal's picture
ci: sync hf to space
b204d57
Raw
History Blame Contribute Delete
3.42 kB
import json
import uuid
from datetime import datetime
from time_utils import now_utc7
from log_utils import setup_logger
from risk_manager import RiskManager
from risk_manager import TradeMode, TradeProposal
logger = setup_logger(__name__)
class TradeExecutor:
def __init__(self, risk_manager: RiskManager):
self.risk = risk_manager
self._pending_confirmations: dict[str, dict] = {}
def prepare_trade(self, pair: str, direction: str, entry: float,
sl: float, tp1: float, tp2: float = None,
confidence: float = 0.5, source: str = "signal") -> dict:
proposal = TradeProposal(
pair=pair, direction=direction, entry=entry,
sl=sl, tp1=tp1, tp2=tp2, confidence=confidence, source=source,
)
result = self.risk.approve_trade(proposal)
if not result["approved"]:
return {"success": False, "reason": result["reason"]}
trade = {
"id": str(uuid.uuid4())[:8],
"pair": pair,
"direction": direction,
"entry": entry,
"sl": sl,
"tp1": tp1,
"tp2": tp2,
"confidence": confidence,
"source": source,
"mode": result["mode"],
"position_size": result["position_size"],
"risk_amount": result["risk_amount"],
"rr_ratio": result["rr_ratio"],
"status": "pending" if result["mode"] == "semi_auto" else "executed",
"opened_at": now_utc7().isoformat(),
"closed_at": None,
"pnl": None,
}
if result["mode"] in ("paper", "auto_controlled"):
self.risk.open_position(trade)
logger.info(f"Trade {trade['id']}: {direction} {pair} @ {entry} ({result['mode']})")
trade["success"] = True
else:
self._pending_confirmations[trade["id"]] = trade
trade["success"] = True
trade["note"] = "Awaiting confirmation"
return trade
def confirm_trade(self, trade_id: str, approved: bool) -> dict:
trade = self._pending_confirmations.pop(trade_id, None)
if not trade:
return {"success": False, "reason": "Trade not found or expired"}
if not approved:
logger.info(f"Trade {trade_id} rejected by user")
return {"success": False, "reason": "Rejected by user"}
trade["status"] = "executed"
self.risk.open_position(trade)
logger.info(f"Trade {trade_id} confirmed and executed")
return {"success": True, "trade": trade}
def close_trade(self, trade_id: str, pnl: float, reason: str = "manual"):
self.risk.close_position(trade_id, pnl)
logger.info(f"Trade {trade_id} closed at PnL {pnl} ({reason})")
def get_pending(self) -> list[dict]:
return list(self._pending_confirmations.values())
def execute_by_mode(self, signal: dict, trade_mode: str) -> dict:
self.risk.set_mode(trade_mode)
return self.prepare_trade(
pair=signal.get("pair", ""),
direction=signal.get("direction", "buy"),
entry=signal.get("entry", 0),
sl=signal.get("sl", 0),
tp1=signal.get("tp1", 0),
tp2=signal.get("tp2"),
confidence=signal.get("confidence", 0.5),
source=signal.get("source", "signal"),
)