69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package entity
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/genex/trading-service/internal/domain/vo"
|
|
)
|
|
|
|
const (
|
|
// TakerFeeRate is the fee rate charged to the taker (0.5%).
|
|
TakerFeeRate = 0.005
|
|
// MakerFeeRate is the fee rate charged to the maker (0.1%).
|
|
MakerFeeRate = 0.001
|
|
)
|
|
|
|
// Trade represents an executed trade between a buyer and seller.
|
|
type Trade struct {
|
|
ID string `json:"id"`
|
|
CouponID string `json:"couponId"`
|
|
BuyOrderID string `json:"buyOrderId"`
|
|
SellOrderID string `json:"sellOrderId"`
|
|
BuyerID string `json:"buyerId"`
|
|
SellerID string `json:"sellerId"`
|
|
Price vo.Price `json:"price"`
|
|
Quantity int `json:"quantity"`
|
|
BuyerFee float64 `json:"buyerFee"`
|
|
SellerFee float64 `json:"sellerFee"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
}
|
|
|
|
// NewTrade creates a new Trade from matched orders.
|
|
func NewTrade(id string, buyOrder, sellOrder *Order, price vo.Price, matchQty int) (*Trade, error) {
|
|
if id == "" {
|
|
return nil, fmt.Errorf("trade ID cannot be empty")
|
|
}
|
|
if matchQty <= 0 {
|
|
return nil, fmt.Errorf("trade quantity must be positive")
|
|
}
|
|
|
|
notional := price.Multiply(matchQty)
|
|
takerFee := notional * TakerFeeRate
|
|
makerFee := notional * MakerFeeRate
|
|
|
|
return &Trade{
|
|
ID: id,
|
|
CouponID: buyOrder.CouponID,
|
|
BuyOrderID: buyOrder.ID,
|
|
SellOrderID: sellOrder.ID,
|
|
BuyerID: buyOrder.UserID,
|
|
SellerID: sellOrder.UserID,
|
|
Price: price,
|
|
Quantity: matchQty,
|
|
BuyerFee: takerFee,
|
|
SellerFee: makerFee,
|
|
CreatedAt: time.Now(),
|
|
}, nil
|
|
}
|
|
|
|
// Notional returns the total value of the trade (price * quantity).
|
|
func (t *Trade) Notional() float64 {
|
|
return t.Price.Multiply(t.Quantity)
|
|
}
|
|
|
|
// TotalFees returns the sum of buyer and seller fees.
|
|
func (t *Trade) TotalFees() float64 {
|
|
return t.BuyerFee + t.SellerFee
|
|
}
|