package handler import ( "fmt" "net/http" "strconv" "time" "github.com/gin-gonic/gin" "github.com/genex/trading-service/internal/domain/entity" "github.com/genex/trading-service/internal/matching" ) type TradeHandler struct { engine *matching.Engine } func NewTradeHandler(engine *matching.Engine) *TradeHandler { return &TradeHandler{engine: engine} } type PlaceOrderReq struct { CouponID string `json:"couponId" binding:"required"` Side string `json:"side" binding:"required,oneof=buy sell"` Type string `json:"type" binding:"required,oneof=limit market"` Price float64 `json:"price"` Quantity int `json:"quantity" binding:"required,min=1"` } func (h *TradeHandler) PlaceOrder(c *gin.Context) { var req PlaceOrderReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": -1, "message": err.Error()}) return } userID := c.GetString("userId") order := &entity.Order{ ID: generateID(), UserID: userID, CouponID: req.CouponID, Side: entity.OrderSide(req.Side), Type: entity.OrderType(req.Type), Price: req.Price, Quantity: req.Quantity, RemainingQty: req.Quantity, Status: entity.OrderPending, } result := h.engine.PlaceOrder(order) c.JSON(http.StatusOK, gin.H{"code": 0, "data": gin.H{ "order": result.UpdatedOrder, "trades": result.Trades, }}) } func (h *TradeHandler) CancelOrder(c *gin.Context) { couponID := c.Query("couponId") orderID := c.Param("id") side := entity.OrderSide(c.Query("side")) success := h.engine.CancelOrder(couponID, orderID, side) if !success { c.JSON(http.StatusNotFound, gin.H{"code": -1, "message": "Order not found"}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "data": nil}) } func (h *TradeHandler) GetOrderBook(c *gin.Context) { couponID := c.Param("couponId") depth, _ := strconv.Atoi(c.DefaultQuery("depth", "20")) bids, asks := h.engine.GetOrderBookSnapshot(couponID, depth) c.JSON(http.StatusOK, gin.H{"code": 0, "data": gin.H{ "couponId": couponID, "bids": bids, "asks": asks, }}) } func generateID() string { return fmt.Sprintf("ord-%d", time.Now().UnixNano()) }