""" 核心交易操作相关的API端点 (买入、卖出、撤单)。 """ from flask import Blueprint, request, jsonify, abort from core.app_state import get_trader, get_real_trader_manager, is_real_mode, logger from base_trader import BaseTrader from trade_constants import ORDER_TYPE_LIMIT, ORDER_DIRECTION_BUY, ORDER_DIRECTION_SELL trading_bp = Blueprint('trading_routes', __name__, url_prefix='/yu') @trading_bp.route("/buy", methods=["POST"]) def buy(): """处理买入请求。""" logger.info("Received buy request") data = request.get_json() if not data: logger.error("Buy request with no JSON data") abort(400, description="Request body must be JSON.") code = data.get("code") price_str = data.get("price") amount_str = data.get("amount") strategy_name = data.get("strategy_name", "default_strategy") order_type = data.get("order_type", ORDER_TYPE_LIMIT) try: if not all([code, price_str, amount_str]): logger.warning(f"Buy request missing parameters: code={code}, price={price_str}, amount={amount_str}") raise ValueError("Missing required parameters: code, price, amount") price = float(price_str) amount = int(float(amount_str)) if order_type == ORDER_TYPE_LIMIT and (price <= 0 or amount <= 0): logger.warning(f"Buy request with invalid price/amount: price={price}, amount={amount}") raise ValueError("For limit orders, price and amount must be positive") trader = get_trader() if not trader: logger.error("Trader instance not available for buy request.") return jsonify({"success": False, "error": "Trader not available"}), 503 if is_real_mode(): if not BaseTrader.is_trading_time(): logger.warning(f"Buy attempt outside trading hours: {code}, {price}, {amount}") return jsonify({"success": False, "error": "交易失败: 非交易时间不能实盘交易"}), 400 if not trader.is_available(): logger.error(f"Trader not available for real mode buy: {trader.connection_error_message}") return jsonify({"success": False, "error": trader.connection_error_message or "交易系统连接失败"}), 503 rtm = get_real_trader_manager() if not rtm: logger.error("RealTraderManager not available for buy request.") return jsonify({"success": False, "error": "RealTraderManager not available"}), 503 logger.info(f"Using RealTraderManager for buy: {code}, {price}, {amount}, {strategy_name}") result = rtm.place_order(strategy_name, code, ORDER_DIRECTION_BUY, amount, price, order_type) else: result = trader.buy(code, price, amount, strategy_name) if result.get("success"): logger.info(f"买入下单成功: {result}") return jsonify({"success": True, "order_id": result.get("order_id")}), 200 else: logger.error(f"买入下单失败: {result}") return jsonify({"success": False, "error": result.get("error", "Unknown error placing buy order")}), 400 except ValueError as e: logger.error(f"Invalid buy request parameters: {str(e)}") abort(400, description=str(e)) except Exception as e: logger.error(f"Error processing buy request: {str(e)}", exc_info=True) abort(500, description="Internal server error during buy request") @trading_bp.route("/sell", methods=["POST"]) def sell(): """处理卖出请求。""" logger.info("Received sell request") data = request.get_json() if not data: logger.error("Sell request with no JSON data") abort(400, description="Request body must be JSON.") code = data.get("code") price_str = data.get("price") amount_str = data.get("amount") strategy_name = data.get("strategy_name", "default_strategy") order_type = data.get("order_type", ORDER_TYPE_LIMIT) try: if not all([code, price_str, amount_str]): logger.warning(f"Sell request missing parameters: code={code}, price={price_str}, amount={amount_str}") raise ValueError("Missing required parameters: code, price, amount") price = float(price_str) amount = int(float(amount_str)) if order_type == ORDER_TYPE_LIMIT and (price <= 0 or amount <= 0): logger.warning(f"Sell request with invalid price/amount: price={price}, amount={amount}") raise ValueError("For limit orders, price and amount must be positive") trader = get_trader() if not trader: logger.error("Trader instance not available for sell request.") return jsonify({"success": False, "error": "Trader not available"}), 503 if is_real_mode(): if not BaseTrader.is_trading_time(): logger.warning(f"Sell attempt outside trading hours: {code}, {price}, {amount}") return jsonify({"success": False, "error": "交易失败: 非交易时间不能实盘交易"}), 400 if not trader.is_available(): logger.error(f"Trader not available for real mode sell: {trader.connection_error_message}") return jsonify({"success": False, "error": trader.connection_error_message or "交易系统连接失败"}), 503 rtm = get_real_trader_manager() if not rtm: logger.error("RealTraderManager not available for sell request.") return jsonify({"success": False, "error": "RealTraderManager not available"}), 503 logger.info(f"Using RealTraderManager for sell: {code}, {price}, {amount}, {strategy_name}") result = rtm.place_order(strategy_name, code, ORDER_DIRECTION_SELL, amount, price, order_type) else: result = trader.sell(code, price, amount, strategy_name) if result.get("success"): logger.info(f"卖出下单成功: {result}") return jsonify({"success": True, "order_id": result.get("order_id")}), 200 else: logger.error(f"卖出下单失败: {result}") return jsonify({"success": False, "error": result.get("error", "Unknown error placing sell order")}), 400 except ValueError as e: logger.error(f"Invalid sell request parameters: {str(e)}") abort(400, description=str(e)) except Exception as e: logger.error(f"Error processing sell request: {str(e)}", exc_info=True) abort(500, description="Internal server error during sell request") @trading_bp.route("/cancel/", methods=["DELETE"]) def cancel(order_id: str): """根据订单ID处理撤单请求。""" logger.info(f"Received cancel request for order {order_id}") try: trader = get_trader() if not trader: logger.error("Trader instance not available for cancel request.") return jsonify({"success": False, "error": "Trader not available"}), 503 if is_real_mode() and not trader.is_available(): logger.error(f"Trader not available for real mode cancel: {trader.connection_error_message}") return jsonify({"success": False, "error": trader.connection_error_message or "交易系统连接失败"}), 503 result = trader.cancel(order_id) logger.info(f"撤单结果: {result}") # 假设 cancel 操作总是返回一个字典,即使失败也包含状态 if isinstance(result, dict) and result.get("success") is False: return jsonify(result), 400 # Propagate error from trader if structured return jsonify(result), 200 except Exception as e: logger.error(f"Error processing cancel request for order {order_id}: {str(e)}", exc_info=True) abort(500, description=f"Internal server error during cancel request for order {order_id}")