106 lines
3.6 KiB
Python
106 lines
3.6 KiB
Python
from pathlib import Path
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://user:pass@localhost:5432/ai_ict_test")
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from scripts.run_execution import build_account_risk_state_from_env
|
|
from src.services.execution import ExecutionService
|
|
from src.services.market_state import MarketStateService, get_market_truth_supervisor
|
|
|
|
|
|
def build_execution_mode_from_env(env=None) -> str:
|
|
env = os.environ if env is None else env
|
|
return str(env.get("EXECUTION_MODE") or "semi_auto").strip() or "semi_auto"
|
|
|
|
|
|
def main(env=None) -> int:
|
|
env = os.environ if env is None else env
|
|
output_json = _get_bool(env, "EXECUTION_TICKET_OUTPUT_JSON", False)
|
|
signal_id = _get_int(env, "EXECUTION_SIGNAL_ID", 1)
|
|
execution_mode = build_execution_mode_from_env(env=env)
|
|
account_equity = _get_float(env, "EXECUTION_ACCOUNT_EQUITY", 10000.0)
|
|
risk_pct = _get_float(env, "EXECUTION_RISK_PCT", 0.01)
|
|
confirm_ticket = _get_bool(env, "EXECUTION_CONFIRM_TICKET", False)
|
|
confirmed_by = str(env.get("EXECUTION_CONFIRMED_BY") or "local_operator")
|
|
service = ExecutionService(
|
|
market_state_service=MarketStateService(market_truth_supervisor=get_market_truth_supervisor())
|
|
)
|
|
account_state = build_account_risk_state_from_env(env=env)
|
|
try:
|
|
ticket = service.create_execution_ticket(
|
|
signal_id=signal_id,
|
|
execution_mode=execution_mode,
|
|
account_equity=account_equity,
|
|
risk_pct=risk_pct,
|
|
account_state=account_state,
|
|
)
|
|
confirmed = None
|
|
if ticket is not None and confirm_ticket:
|
|
confirmed = service.confirm_execution_ticket(
|
|
ticket.ticket_id,
|
|
confirmed_by=confirmed_by,
|
|
account_equity=account_equity,
|
|
risk_pct=risk_pct,
|
|
account_state=account_state,
|
|
)
|
|
except SQLAlchemyError as exc:
|
|
payload = {
|
|
"passed": False,
|
|
"signal_id": signal_id,
|
|
"execution_mode": execution_mode,
|
|
"error_type": exc.__class__.__name__,
|
|
"error": str(exc),
|
|
}
|
|
if output_json:
|
|
print(json.dumps(payload, default=str, ensure_ascii=False, sort_keys=True))
|
|
else:
|
|
print(f"Database unavailable for execution ticket sample: {exc.__class__.__name__}")
|
|
return 2
|
|
payload = {
|
|
"passed": True,
|
|
"signal_id": signal_id,
|
|
"execution_mode": execution_mode,
|
|
"ticket": ticket.to_dict() if ticket is not None else None,
|
|
"confirmed": confirmed.to_dict() if confirmed is not None else None,
|
|
}
|
|
if output_json:
|
|
print(json.dumps(payload, default=str, ensure_ascii=False, sort_keys=True))
|
|
else:
|
|
print(
|
|
f"Ticket status: {(ticket.status if ticket else 'missing')}; "
|
|
f"confirmed status: {(confirmed.status if confirmed else 'not_confirmed')}"
|
|
)
|
|
return 0
|
|
|
|
|
|
def _get_float(env, key: str, default: float) -> float:
|
|
value = env.get(key)
|
|
if value is None or value == "":
|
|
return default
|
|
return float(value)
|
|
|
|
|
|
def _get_int(env, key: str, default: int) -> int:
|
|
value = env.get(key)
|
|
if value is None or value == "":
|
|
return default
|
|
return int(value)
|
|
|
|
|
|
def _get_bool(env, key: str, default: bool) -> bool:
|
|
value = env.get(key)
|
|
if value is None or value == "":
|
|
return default
|
|
return str(value).strip().lower() in {"1", "true", "yes", "on"}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|