simulation.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. """
  2. 智能股票分析助手 — 模拟交易API路由
  3. 提供模拟持仓查询、资金查询、委托下单、撤单等接口。
  4. """
  5. from typing import Optional
  6. from fastapi import APIRouter, Query
  7. from pydantic import BaseModel, Field
  8. from app.services import simulation_service
  9. from app.utils.response import success_response, error_response
  10. router = APIRouter(prefix="/simulation", tags=["模拟交易"])
  11. class PlaceOrderRequest(BaseModel):
  12. """下单请求"""
  13. trade_type: str = Field(..., description="交易类型: buy(买入) / sell(卖出)", pattern="^(buy|sell)$")
  14. stock_code: str = Field(..., description="6位股票代码", min_length=6, max_length=6)
  15. quantity: int = Field(..., description="委托数量(100的整数倍)", gt=0)
  16. price: Optional[float] = Field(default=None, description="委托价格(不填则为市价委托)")
  17. class CancelOrderRequest(BaseModel):
  18. """撤单请求"""
  19. order_id: str = Field(..., description="委托编号", min_length=1)
  20. stock_code: str = Field(default="", description="股票代码(可选)")
  21. @router.get("/portfolio")
  22. async def get_portfolio():
  23. """查询模拟持仓
  24. 返回当前模拟账户下所有持仓股票及其盈亏信息。
  25. """
  26. result = simulation_service.get_positions()
  27. if not result["success"]:
  28. return error_response(code=500, message=result.get("error", "查询持仓失败"))
  29. return success_response(
  30. data={
  31. "positions": result["positions"],
  32. "total": result["total"],
  33. },
  34. message=f"共 {result['total']} 只持仓股票",
  35. )
  36. @router.get("/funds")
  37. async def get_funds():
  38. """查询模拟账户资金
  39. 返回总资产、可用资金、冻结资金、持仓市值、累计盈亏等信息。
  40. """
  41. result = simulation_service.get_balance()
  42. if not result["success"]:
  43. return error_response(code=500, message=result.get("error", "查询资金失败"))
  44. return success_response(
  45. data=result["balance"],
  46. message="资金查询成功",
  47. )
  48. @router.get("/orders")
  49. async def get_orders():
  50. """查询委托记录
  51. 返回历史委托订单列表(包含已成交、未成交、已撤销等状态)。
  52. """
  53. result = simulation_service.get_orders()
  54. if not result["success"]:
  55. return error_response(code=500, message=result.get("error", "查询委托失败"))
  56. return success_response(
  57. data={
  58. "orders": result["orders"],
  59. "total": result["total"],
  60. },
  61. message=f"共 {result['total']} 条委托记录",
  62. )
  63. @router.post("/order")
  64. async def place_order(body: PlaceOrderRequest):
  65. """模拟下单(买入/卖出)
  66. 提交模拟交易委托,支持限价委托和市价委托。
  67. - **trade_type**: buy=买入, sell=卖出
  68. - **stock_code**: 6位股票代码,如 600519
  69. - **quantity**: 委托数量,必须为100的整数倍
  70. - **price**: 委托价格(不填=市价委托)
  71. """
  72. result = simulation_service.place_order(
  73. trade_type=body.trade_type,
  74. stock_code=body.stock_code,
  75. quantity=body.quantity,
  76. price=body.price,
  77. )
  78. if not result["success"]:
  79. return error_response(code=500, message=result.get("error", "下单失败"))
  80. return success_response(
  81. data={
  82. "order_id": result["order_id"],
  83. "trade_type": body.trade_type,
  84. "stock_code": body.stock_code,
  85. "quantity": body.quantity,
  86. "price": body.price,
  87. },
  88. message=result["message"],
  89. )
  90. @router.delete("/order/{order_id}")
  91. async def cancel_order(
  92. order_id: str,
  93. stock_code: str = Query(default="", description="股票代码(可选)"),
  94. ):
  95. """撤销指定委托
  96. 根据委托编号撤销未成交的委托订单。
  97. - **order_id**: 委托编号(如 260854300000078983)
  98. - **stock_code**: 股票代码(可选)
  99. """
  100. result = simulation_service.cancel_order(order_id, stock_code)
  101. if not result["success"]:
  102. return error_response(code=500, message=result.get("error", "撤单失败"))
  103. return success_response(data={"order_id": order_id}, message=result["message"])
  104. @router.post("/cancel-all")
  105. async def cancel_all_orders():
  106. """一键撤单
  107. 撤销当前账户下所有未成交的委托订单。
  108. """
  109. result = simulation_service.cancel_all_orders()
  110. if not result["success"]:
  111. return error_response(code=500, message=result.get("error", "一键撤单失败"))
  112. return success_response(data={}, message=result["message"])