You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Package handler HTTP Handler实现
package handler
import (
"context"
"fmt"
"market-data-service/api"
"market-data-service/internal/service"
)
// Handler HTTP处理器实现
type Handler struct {
stockService service.StockService
futuresService service.FuturesService
adminService service.AdminService
}
// NewHandler 创建Handler
func NewHandler(
stockService service.StockService,
futuresService service.FuturesService,
adminService service.AdminService,
) *Handler {
return &Handler{
stockService: stockService,
futuresService: futuresService,
adminService: adminService,
}
}
// 确保Handler实现了api.Handler接口
var _ api.Handler = (*Handler)(nil)
// ============================================
// 股票接口实现
// ============================================
// QueryKLines 查询股票K线
func (h *Handler) QueryKLines(ctx context.Context, req *api.KLineQueryRequest) (*api.Response, error) {
// 参数校验
if err := validateKLineRequest(req); err != nil {
return nil, err
}
// 调用Service层
data, err := h.stockService.QueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ListSymbols 查询股票标的列表
func (h *Handler) ListSymbols(ctx context.Context, req *api.SymbolListRequest) (*api.Response, error) {
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 20
}
if req.Size > 100 {
req.Size = 100
}
data, err := h.stockService.ListSymbols(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// BatchQueryKLines 批量查询股票K线
func (h *Handler) BatchQueryKLines(ctx context.Context, req *api.BatchKLineRequest) (*api.Response, error) {
if err := validateBatchKLineRequest(req); err != nil {
return nil, err
}
data, err := h.stockService.BatchQueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ============================================
// 期货接口实现
// ============================================
// QueryKLines 查询期货K线期货Handler
func (h *Handler) QueryKLines(ctx context.Context, req *api.KLineQueryRequest) (*api.Response, error) {
if err := validateKLineRequest(req); err != nil {
return nil, err
}
data, err := h.futuresService.QueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ListSymbols 查询期货标的列表
func (h *Handler) ListSymbols(ctx context.Context, req *api.SymbolListRequest) (*api.Response, error) {
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 20
}
if req.Size > 100 {
req.Size = 100
}
data, err := h.futuresService.ListSymbols(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// BatchQueryKLines 批量查询期货K线
func (h *Handler) BatchQueryKLines(ctx context.Context, req *api.BatchKLineRequest) (*api.Response, error) {
if err := validateBatchKLineRequest(req); err != nil {
return nil, err
}
data, err := h.futuresService.BatchQueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// QueryContinuousKLines 查询主力连续合约K线预留
func (h *Handler) QueryContinuousKLines(ctx context.Context, underlying string, req *api.KLineQueryRequest) (*api.Response, error) {
// TODO: 首期返回空数据或错误提示
return &api.Response{
Code: 0,
Message: "success",
Data: &api.KLineData{
Symbol: underlying + ".MAIN",
Name: underlying + "主力连续",
Freq: req.Freq,
Count: 0,
Items: []api.KLineItem{},
},
}, nil
}
// ============================================
// 管理接口实现
// ============================================
// GetDataSourceStatus 获取数据源状态
func (h *Handler) GetDataSourceStatus(ctx context.Context) (*api.Response, error) {
data, err := h.adminService.GetDataSourceStatus(ctx)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// SwitchDataSource 切换数据源
func (h *Handler) SwitchDataSource(ctx context.Context, req *api.SourceSwitchRequest) (*api.Response, error) {
if err := h.adminService.SwitchDataSource(ctx, req); err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "数据源切换成功",
Data: nil,
}, nil
}
// BackfillData 历史数据补录
func (h *Handler) BackfillData(ctx context.Context, req *api.BackfillRequest) (*api.Response, error) {
// 异步启动补录任务
taskID, err := h.adminService.BackfillData(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "补录任务已启动",
Data: map[string]string{
"task_id": taskID,
},
}, nil
}
// HealthCheck 健康检查
func (h *Handler) HealthCheck(ctx context.Context) (*api.HealthResponse, error) {
// TODO: 检查数据库连接、数据源连通性等
return h.adminService.HealthCheck(ctx)
}
// ============================================
// 新增接口:交易日历和期货合约
// ============================================
// GetTradingDates 获取股票交易日历
func (h *Handler) GetTradingDates(ctx context.Context, req *api.TradingDatesRequest) (*api.Response, error) {
if err := validateTradingDatesRequest(req); err != nil {
return nil, err
}
// 通过请求路径判断是股票还是期货,这里简化处理
// 实际可以通过gin的context或其他方式判断
data, err := h.stockService.GetTradingDates(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// GetContractsByUnderlying 根据品种获取可交易合约
func (h *Handler) GetContractsByUnderlying(ctx context.Context, req *api.FuturesContractsRequest) (*api.Response, error) {
if req.Underlying == "" {
return nil, fmt.Errorf("underlying不能为空")
}
data, err := h.futuresService.GetContractsByUnderlying(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ============================================
// 私有辅助函数
// ============================================
func validateKLineRequest(req *api.KLineQueryRequest) error {
if req.Symbol == "" {
return fmt.Errorf("symbol不能为空")
}
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
if req.Freq == "" {
req.Freq = api.Freq1D
}
return nil
}
func validateBatchKLineRequest(req *api.BatchKLineRequest) error {
if len(req.Symbols) == 0 {
return fmt.Errorf("symbols不能为空")
}
if len(req.Symbols) > 100 {
return fmt.Errorf("单次查询标的数不能超过100")
}
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
if req.Freq == "" {
req.Freq = api.Freq1D
}
return nil
}
func validateTradingDatesRequest(req *api.TradingDatesRequest) error {
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
return nil
}