import schedule import threading import time from real.xt_trader import XtTrader from flask import Flask, request, abort, jsonify from config import Config from simulation.simulation_trader import SimulationTrader from logger_config import get_logger from real.real_trader_manager import RealTraderManager from trade_constants import * # 获取日志记录器 logger = get_logger("server") # 全局交易实例(采用单例模式) _trader_instance = None # 交易实例(单例) _real_trader_manager_instance = None # 实盘交易管理器实例(单例) def is_real_mode(): return not Config.SIMULATION_MODE # 获取实盘交易管理器实例的辅助函数 def get_real_trader_manager(): global _real_trader_manager_instance if _real_trader_manager_instance is None: _real_trader_manager_instance = ( None if Config.SIMULATION_MODE else RealTraderManager(get_trader()) ) return _real_trader_manager_instance # 获取交易实例 - 根据情况返回模拟或实盘交易实例 def get_trader(): global _trader_instance if _trader_instance is None: _trader_instance = SimulationTrader() if Config.SIMULATION_MODE else XtTrader() return _trader_instance def login(): try: global _trader_instance # 如果已经有实例,先销毁 if _trader_instance is not None and is_real_mode(): _trader_instance.logout() _trader_instance = None # 创建新的XtTrader实例 _trader_instance = SimulationTrader() if Config.SIMULATION_MODE else XtTrader() logger.info("开始登录") _trader_instance.login() result = _trader_instance.get_balance() if result and result["account_id"] is not None: logger.info(f"查询余额成功: {result}") else: logger.error(f"登录失败: {result}") raise Exception(f"登录失败: {result}") except Exception as e: logger.error(f"登录失败: {e}") raise Exception(f"登录失败: {e}") def logout(): global _trader_instance if _trader_instance is not None: _trader_instance.logout() logger.info("登出成功") # 销毁实例 if is_real_mode(): _trader_instance = None logger.info("XtTrader实例已销毁") def setup_scheduler(): # 设置每日任务 schedule.every().day.at(Config.MARKET_OPEN_TIME).do(login) schedule.every().day.at(Config.MARKET_CLOSE_TIME).do(logout) # 启动调度线程 scheduler_thread = threading.Thread(target=_run_scheduler, daemon=True) scheduler_thread.start() logger.info("定时任务调度器已启动") return scheduler_thread def _run_scheduler(): """定时任务执行线程""" while True: try: schedule.run_pending() time.sleep(1) except Exception as e: logger.error(f"调度器执行错误: {str(e)}") # 设置并启动调度器 setup_scheduler() # 程序启动时初始化交易实例 login() # 添加请求频率限制 app = Flask(__name__) @app.route("/yu/healthcheck", methods=["GET"]) def health_check(): return "ok", 200 @app.route("/yu/buy", methods=["POST"]) def buy(): """Buy an item with given parameters.""" logger.info("Received buy request") # Get data from request body data = request.get_json() code = data.get("code") price_str = data.get("price") amount_str = data.get("amount") strategy_name = data.get( "strategy_name", "default_strategy" ) # 新增策略名称参数,默认为空 try: if not all([code, price_str, amount_str]): raise ValueError("Missing required parameters") price = float(price_str) amount = int(amount_str) if price <= 0 or amount <= 0: raise ValueError("Price and amount must be positive") # 检查是否在交易时间内 if not get_trader().is_trading_time(): logger.warning( f"交易失败 - 非交易时间不能交易 - 代码: {code}, 价格: {price}, 数量: {amount}" ) return ( jsonify( {"success": False, "error": f"交易失败: 非交易时间不能实盘交易"} ), 400, ) if is_real_mode(): logger.info( f"使用RealTraderManager执行买入: 代码={code}, 价格={price}, 数量={amount}, 策略={strategy_name}" ) rtm = get_real_trader_manager() result = rtm.place_order( strategy_name, code, ORDER_DIRECTION_BUY, amount, price ) else: result = get_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}), 400 except ValueError as e: logger.error(f"Invalid request parameters: {str(e)}") abort(400, description=str(e)) except Exception as e: logger.error(f"Error processing buy request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/sell", methods=["POST"]) def sell(): """Sell an item with given parameters.""" logger.info("Received sell request") # Get data from request body data = request.get_json() code = data.get("code") price_str = data.get("price") amount_str = data.get("amount") strategy_name = data.get("strategy_name", "") # 新增策略名称参数,默认为空 try: if not all([code, price_str, amount_str]): raise ValueError("Missing required parameters") price = float(price_str) amount = int(amount_str) if price <= 0 or amount <= 0: raise ValueError("Price and amount must be positive") # 检查是否在交易时间内 if not get_trader().is_trading_time(): logger.warning( f"交易失败 - 非交易时间不能交易 - 代码: {code}, 价格: {price}, 数量: {amount}" ) return ( jsonify( {"success": False, "error": f"交易失败: 非交易时间不能实盘交易"} ), 400, ) if is_real_mode(): rtm = get_real_trader_manager() result = rtm.place_order( strategy_name, code, ORDER_DIRECTION_SELL, amount, price ) else: result = get_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}), 400 except ValueError as e: logger.error(f"Invalid request parameters: {str(e)}") abort(400, description=str(e)) except Exception as e: logger.error(f"Error processing sell request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/cancel/", methods=["DELETE"]) def cancel(order_id): logger.info(f"Received cancel request for entrust_no={order_id}") try: result = get_trader().cancel(order_id) return jsonify({"success": True, "data": result}), 200 except Exception as e: logger.error(f"Error processing cancel request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/balance", methods=["GET"]) def get_balance(): """Get the balance of the account.""" logger.info("Received balance request") try: # 直接使用实盘交易实例,不考虑模拟盘 balance = get_trader().get_balance() logger.info(f"实盘交易余额: {balance}") return jsonify({"success": True, "data": balance}), 200 except Exception as e: logger.error(f"Error processing balance request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/positions", methods=["GET"]) def get_positions(): """Get the positions of the account.""" logger.info("Received positions request") try: result = get_trader().get_positions() return jsonify({"success": True, "data": result}), 200 except Exception as e: logger.error(f"Error processing positions request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/todaytrades", methods=["GET"]) def get_today_trades(): """Get the today's trades of the account.""" logger.info("Received today trades request") try: trades = get_trader().get_today_trades() logger.info(f"今日成交: {trades}") return jsonify({"success": True, "data": trades}), 200 except Exception as e: logger.error(f"Error processing today trades request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/todayorders", methods=["GET"]) def get_today_orders(): """Get the today's entrust of the account.""" logger.info("Received today entrust request") try: entrust = get_trader().get_today_orders() logger.info(f"今日委托: {entrust}") return jsonify({"success": True, "data": entrust}), 200 except Exception as e: logger.error(f"Error processing today entrust request: {str(e)}") abort(500, description="Internal server error") @app.route("/yu/clear/", methods=["DELETE"]) def clear_strategy(strategy_name): """清除指定策略的持仓管理数据""" logger.info(f"接收到清除策略持仓请求: {strategy_name}") try: get_trader().clear_position_manager(strategy_name) return jsonify({"success": True, "message": "clear success"}), 200 except Exception as e: logger.error(f"清除策略持仓时出错: {str(e)}") abort(500, description="服务器内部错误") if __name__ == "__main__": logger.info(f"Server starting on {Config.HOST}:{Config.PORT}") app.run(debug=Config.DEBUG, host=Config.HOST, port=Config.PORT)