diff --git a/api/pub.proto b/api/pub.proto index 702af13..dddf725 100644 --- a/api/pub.proto +++ b/api/pub.proto @@ -181,3 +181,28 @@ message InputRange { int32 type = 2; // 0.fixed, 1.range, 2.enum, 3.simple group string value = 3; // range => [10,20,1](min,max,step); enum => [1,2,3,4,5]; simple group => [["2025-10-01","2025-12-31"],["2025-01-01","2025-12-31"]] } + +// 回测订单 +message BacktestTradeOrder { + int64 backtest_id = 1; + int64 trade_id = 2; + int32 trade_type = 3; + string inst_id = 4; + Side side = 5; + double qty = 6; + double price = 7; + double fee = 8; + int32 leverage = 9; + int64 ctime = 10; + int32 status = 11; + double peak_px = 12; + string close_cause = 13; + double equity = 14; + string hold_time = 15; + double profit = 16; + double last_px = 17; + double entry_px = 18; + double entry_fee = 19; + int64 entry_time = 20; + repeated int64 trades = 21; +} diff --git a/api/trading.proto b/api/trading.proto index 2749409..8c643b5 100644 --- a/api/trading.proto +++ b/api/trading.proto @@ -22,14 +22,8 @@ service TradingService { // 交易计划参数调试回测 rpc BacktestRace(ReqBacktestRace) returns (RspBacktestRace); - // 交易计划回测记录 + // 交易计划回测记录(进行中) rpc BacktestLog(ReqBacktestLog) returns (RspBacktestLog); - - // 交易计划回测交易单详情 - rpc BacktestLogTrades(ReqBacktestLogTrades) returns (RspBacktestLogTrades); - - // 交易计划回测结果统计信息 - rpc BacktestLogStats(ReqBacktestLogStats) returns (RspBacktestLogStats); } message ReqIndicatorPlots { @@ -87,38 +81,7 @@ message ReqBacktestLog { message RspBacktestLog { repeated BacktestLog logs = 1; } - -message BacktestTradeOrder { - int64 backtest_id = 1; - int64 trade_id = 2; - int32 trade_type = 3; - string inst_id = 4; - Side side = 5; - double qty = 6; - double price = 7; - double fee = 8; - int32 leverage = 9; - int64 ctime = 10; - int32 status = 11; - double peak_px = 12; - string close_cause = 13; - double equity = 14; - string hold_time = 15; - double profit = 16; - double last_px = 17; - double entry_px = 18; - double entry_fee = 19; - int64 entry_time = 20; - repeated int64 trades = 21; -} -message ReqBacktestLogTrades { - Paging paging = 1; - int64 backtest_id = 2; -} -message RspBacktestLogTrades { - repeated BacktestTradeOrder trades = 1; -} - + message ReqBacktestRace { int64 plan_id = 1; // 交易计划 repeated InputRange series_input_range = 5; // 运行参数 @@ -131,19 +94,19 @@ message RspBacktestRace { } -// 回测统计信息(line charts) -message ReqBacktestLogStats { - int64 plan_id = 1; - int64 backtest_id = 2; -} -message RspBacktestLogStats { - repeated int64 times = 1; // k线时间 - repeated double equitys = 2; // 平仓后账户净值 - repeated BacktestLogBuySellPoint buy_sell = 9; // 买卖点数据统计 charts data -} -// {time: 1763890200000, value: 86400, text: 'BUY:86400', direction: 'up'} -message BacktestLogBuySellPoint { - double value = 2; // k线收盘价 - Side side = 3; // 买卖方向 - string text = 4; // 买卖点描述 -} +// // 回测统计信息(line charts) +// message ReqBacktestLogStats { +// int64 plan_id = 1; +// int64 backtest_id = 2; +// } +// message RspBacktestLogStats { +// repeated int64 times = 1; // k线时间 +// repeated double equitys = 2; // 平仓后账户净值 +// repeated BacktestLogBuySellPoint buy_sell = 9; // 买卖点数据统计 charts data +// } +// // {time: 1763890200000, value: 86400, text: 'BUY:86400', direction: 'up'} +// message BacktestLogBuySellPoint { +// double value = 2; // k线收盘价 +// Side side = 3; // 买卖方向 +// string text = 4; // 买卖点描述 +// } diff --git a/internal/sig/args/backtest_args.go b/internal/sig/args/backtest_args.go new file mode 100644 index 0000000..3892815 --- /dev/null +++ b/internal/sig/args/backtest_args.go @@ -0,0 +1,5 @@ +package args + +type ListBacktestLogTradesReq struct { + BacktestId int64 `json:"backtestId"` +} diff --git a/internal/sig/repoitory/backtest_repository.go b/internal/sig/repoitory/backtest_repository.go index 63061d2..f44147f 100644 --- a/internal/sig/repoitory/backtest_repository.go +++ b/internal/sig/repoitory/backtest_repository.go @@ -1,17 +1,58 @@ package repository -import "sig-pub/pkg/storage/persist" +import ( + "fmt" + "sig-pub/pkg/data" + "sig-pub/pkg/storage/persist" + "sig-pub/pkg/trade" +) type BacktestRepository struct { - rdb *persist.DB + db *persist.DB } -func NewBacktestRepository(rdb *persist.DB) *BacktestRepository { +func NewBacktestRepository(db *persist.DB) *BacktestRepository { return &BacktestRepository{ - rdb: rdb, + db: db, } } -func (r *BacktestRepository) ListLog() { +// ListBacktestLogs 用户交易计划回测记录查询 +func (p *BacktestRepository) ListBacktestLogs(userId int64, page data.Page) (backtestLogs []*trade.BacktestTradingPlan, err error) { + err = p.db.Select(&backtestLogs, ` + select * from t_backtest_trading_plan where user_id = ? + order by id desc + offset ? limit ? + `, userId, page.Offset, page.Limit) + return +} + +// BacktestLogTrades 交易计划回测交易单详情 +func (p *BacktestRepository) BacktestLogTrades(userId, backtestId int64, page data.Page) (total int, tradeOrders []*trade.TradeOrder, err error) { + sqlFrom := ` + from t_backtest_trading_order + where backtest_id = (select id from t_backtest_trading_plan where id = ? and user_id = ?) + ` + err = p.db.Select(&total, fmt.Sprintf(` + select count(*) %s + `, sqlFrom), backtestId, userId) + if err != nil || total == 0 { + return + } + err = p.db.Select(&tradeOrders, fmt.Sprintf(` + select * %s + order by trade_id asc + offset ? limit ? + `, sqlFrom), backtestId, userId, page.Offset, page.Limit) + return +} +// BacktestLogStats 交易计划回测结果统计信息 +func (p *BacktestRepository) BacktestLogStats(userId, backtestId int64) (stats *trade.BacktestTradingPlan, err error) { + stats = &trade.BacktestTradingPlan{} + err = p.db.Select(stats, ` + select * from t_backtest_trading_plan_stats + where backtest_id = (select id from t_backtest_trading_plan where id = ? and user_id = ?) + `, backtestId, userId) + return } diff --git a/internal/sig/repoitory/market_repository.go b/internal/sig/repoitory/market_repository.go new file mode 100644 index 0000000..a3eebab --- /dev/null +++ b/internal/sig/repoitory/market_repository.go @@ -0,0 +1,17 @@ +package repository + +import "sig-pub/pkg/storage/persist" + +type MarketRepository struct { + db *persist.DB +} + +func NewMarketRepository(db *persist.DB) *MarketRepository { + return &MarketRepository{ + db: db, + } +} + +func (r *MarketRepository) List() { + +} diff --git a/internal/sig/service/backtest_service.go b/internal/sig/service/backtest_service.go index 6f09a25..f3ae76b 100644 --- a/internal/sig/service/backtest_service.go +++ b/internal/sig/service/backtest_service.go @@ -2,7 +2,9 @@ package service import ( "net/http" + "sig-pub/internal/sig/args" repository "sig-pub/internal/sig/repoitory" + "sig-pub/pkg/data" "sig-pub/pkg/resp" "github.com/gin-gonic/gin" @@ -19,12 +21,40 @@ func NewBacktestService(repo *repository.BacktestRepository) *BacktestService { } func (svc *BacktestService) Route(group *gin.RouterGroup) { - group.GET("hello", svc.listBacktestLog) + group.GET("listBacktestLog", svc.ListBacktestLog) // 回测记录 + group.POST("listBacktestLogTrades", svc.ListBacktestLogTrades) // 回测记录订单详情 } -func (svc *BacktestService) listBacktestLog(ctx *gin.Context) { - name := ctx.Query("name") - ctx.JSON(http.StatusOK, resp.H{ - "text": "ojbk: " + name, - }) +func (svc *BacktestService) ListBacktestLog(ctx *gin.Context) { + page := data.PageArgs(ctx) + + logs, err := svc.repo.ListBacktestLogs(10001, page) + if err != nil { + ctx.JSON(http.StatusInternalServerError, resp.Error(err.Error())) + return + } + ctx.JSON(http.StatusOK, resp.Success(resp.H{ + "total": len(logs), + "logs": logs, + })) +} + +func (svc *BacktestService) ListBacktestLogTrades(ctx *gin.Context) { + page := data.PageArgs(ctx) + arg := new(args.ListBacktestLogTradesReq) + if err := ctx.ShouldBindJSON(arg); err != nil { + ctx.JSON(http.StatusBadRequest, resp.Fail(err.Error())) + return + } + + total, trades, err := svc.repo.BacktestLogTrades(10001, arg.BacktestId, page) + if err != nil { + ctx.JSON(http.StatusInternalServerError, resp.Error(err.Error())) + return + } + + ctx.JSON(http.StatusOK, resp.Success(resp.H{ + "total": total, + "trades": trades, + })) } diff --git a/internal/sig/service/market_service.go b/internal/sig/service/market_service.go new file mode 100644 index 0000000..701e16d --- /dev/null +++ b/internal/sig/service/market_service.go @@ -0,0 +1,21 @@ +package service + +import ( + repository "sig-pub/internal/sig/repoitory" + + "github.com/gin-gonic/gin" +) + +type MarketService struct { + repo *repository.MarketRepository +} + +func NewMarketService(repo *repository.MarketRepository) *MarketService { + return &MarketService{ + repo: repo, + } +} + +func (svc *MarketService) Route(group *gin.RouterGroup) { + +} diff --git a/internal/sig/sig_server.go b/internal/sig/sig_server.go index 8e7fcde..fd5d900 100644 --- a/internal/sig/sig_server.go +++ b/internal/sig/sig_server.go @@ -12,13 +12,13 @@ import ( ) type SigServer struct { - rdb *persist.DB + db *persist.DB engine *gin.Engine } -func NewSigServer(rdb *persist.DB) *SigServer { +func NewSigServer(db *persist.DB) *SigServer { return &SigServer{ - rdb: rdb, + db: db, } } @@ -43,7 +43,7 @@ func (s *SigServer) initGinServer() { }) routerGroup := s.engine.Group("/api/sig") - service.Init(routerGroup, s.rdb) + service.Init(routerGroup, s.db) } func (s *SigServer) Run(addr string) (err error) { diff --git a/internal/sig/trade_instance/trade_instance_api.go b/internal/sig/trade_instance/trade_instance_api.go deleted file mode 100644 index 32e25ec..0000000 --- a/internal/sig/trade_instance/trade_instance_api.go +++ /dev/null @@ -1,63 +0,0 @@ -package inst - -import ( - "net/http" - "sig-pub/internal/market" - "sig-pub/pkg/data/args" - "sig-pub/pkg/resp" - - "github.com/gin-gonic/gin" -) - -type TradeInstanceApi struct { - service *market.TradeInstanceService // todo grpc call -} - -func NewTradeInstanceApi() *TradeInstanceApi { - return &TradeInstanceApi{} -} - -func (a *TradeInstanceApi) InitRoute(r *gin.RouterGroup) { - instGroup := r.Group("/inst") - { - instGroup.GET("/one/:inst_id", a.getInst) - instGroup.GET("/listAll", a.listAllInst) - instGroup.POST("/list", a.listInst) - } -} - -// getInst 获取指定交易产品 -func (a *TradeInstanceApi) getInst(c *gin.Context) { - instId := c.Param("inst_id") - inst, err := a.service.GetInstance(instId) - if err != nil { - c.JSON(http.StatusOK, resp.Error(err.Error())) - return - } - c.JSON(http.StatusOK, resp.Success(inst)) -} - -// listAllInst 获取所有交易产品 -func (a *TradeInstanceApi) listAllInst(c *gin.Context) { - // list, err := a.service.ListAllInstance() - // if err != nil { - // c.JSON(http.StatusOK, resp.Error(err.Error())) - // return - // } - // c.JSON(http.StatusOK, resp.Success(list)) -} - -// listInst 交易产品分页查询 -func (a *TradeInstanceApi) listInst(c *gin.Context) { - pageArg := args.ParsePageArgs(c) - - total, list, err := a.service.PageInstance(pageArg.Page, pageArg.Size, "") - if err != nil { - c.JSON(http.StatusOK, resp.Error(err.Error())) - return - } - c.JSON(http.StatusOK, resp.Success(resp.H{ - "total": total, - "data": list, - })) -} diff --git a/internal/trading/backtest/trading_plan_backtester.go b/internal/trading/backtest/trading_plan_backtester.go index f7b21e1..e9412eb 100644 --- a/internal/trading/backtest/trading_plan_backtester.go +++ b/internal/trading/backtest/trading_plan_backtester.go @@ -94,8 +94,8 @@ func (b *TradingPlanBacktester) Init(cash float64, plan entity.TradePlan, sr *pb } // 核心引擎,模拟交易、持仓跟踪、费用计算 -func (b *TradingPlanBacktester) Backtest(ctx context.Context) (test *BacktestTradingPlan, err error) { - test = &BacktestTradingPlan{ +func (b *TradingPlanBacktester) Backtest(ctx context.Context) (test *trade.BacktestTradingPlan, err error) { + test = &trade.BacktestTradingPlan{ Id: time.Now().Unix(), UserId: 10001, PlanId: b.plan.Id, diff --git a/internal/trading/backtest/types.go b/internal/trading/backtest/types.go index e041ee5..6f3e8ed 100644 --- a/internal/trading/backtest/types.go +++ b/internal/trading/backtest/types.go @@ -1,7 +1,6 @@ package backtest import ( - "sig-pub/api/pb" "sig-pub/pkg/trade" ) @@ -80,34 +79,3 @@ type EquitySnapshot struct { Ts int64 Equity float64 } - -// BacktestTradingPlan 交易计划回测结果 -type BacktestTradingPlan struct { - Id int64 `json:"id" gorm:"column:id;primaryKey"` // 测试id - UserId int64 `json:"userId" gorm:"column:user_id"` // 用户id - PlanId int64 `json:"planId" gorm:"column:plan_id"` // 交易计划id - InstId string `json:"instId" gorm:"column:inst_id"` // 交易产品id - Exchange pb.ExchangeType `json:"exchange" gorm:"column:exchange"` // 交易所 - Interval string `json:"interval" gorm:"column:interval"` // 交易周期 - SeriesBefore int64 `json:"seriesBefore" gorm:"column:series_before"` // 回测周期开始时间 - SeriesAfter int64 `json:"seriesAfter" gorm:"column:series_after"` // 回测周期结束时间 - Ctime int64 `json:"ctime" gorm:"column:ctime"` // 创建时间(测试时间) - Etime int64 `json:"etime" gorm:"column:etime"` // 测试结束时间 - Cash float64 `json:"cash" gorm:"column:cash"` // 起始金额 - EndCash float64 `json:"endCash" gorm:"column:end_cash"` // 结束金额 - Profit float64 `json:"profit" gorm:"column:profit"` // 利润 - Singals int `json:"singals" gorm:"column:singals"` // 交易信号数 - TotalTrades int `json:"totalTrades" gorm:"column:total_trades"` // 总单数 - WinningTrades int `json:"winningTrades" gorm:"column:winning_trades"` // 盈利单数 - LosingTrades int `json:"losingTrades" gorm:"column:losing_trades"` // 亏损单数 - Fee float64 `json:"fee" gorm:"column:fee"` // 总手续费 - MaxDrawdown float64 `json:"maxDrawdown" gorm:"column:max_drawdown"` // 最大回撤 - SharpeRatio float64 `json:"sharpeRatio" gorm:"column:sharpe_ratio"` // 夏普比率 - Trades []*trade.TradeOrder `json:"-" gorm:"-"` // 回测交易单 -} - -func (BacktestTradingPlan) TableName() string { - return "t_backtest_trading_plan" -} - -// 参数迭代 diff --git a/internal/trading/trading_data_persist.go b/internal/trading/trading_data_persist.go index 5d07fb2..b799547 100644 --- a/internal/trading/trading_data_persist.go +++ b/internal/trading/trading_data_persist.go @@ -2,7 +2,6 @@ package trading import ( "context" - "sig-pub/internal/trading/backtest" "sig-pub/pkg/data" "sig-pub/pkg/data/entity" "sig-pub/pkg/storage/ck" @@ -49,7 +48,7 @@ func (p *TradingDataPersist) GetTradePlanById(planId int64) (plan *entity.TradeP } // SaveBacktestTradingPlan 保存交易计划回测结果 -func (p *TradingDataPersist) SaveBacktestTradingPlan(ctx context.Context, backtestTradingPlan *backtest.BacktestTradingPlan) (err error) { +func (p *TradingDataPersist) SaveBacktestTradingPlan(ctx context.Context, backtestTradingPlan *trade.BacktestTradingPlan) (err error) { datas := make([]any, 0, len(backtestTradingPlan.Trades)+1) datas = append(datas, backtestTradingPlan) for _, trade := range backtestTradingPlan.Trades { @@ -61,7 +60,7 @@ func (p *TradingDataPersist) SaveBacktestTradingPlan(ctx context.Context, backte } // ListBacktestLogs 用户交易计划回测记录查询 -func (p *TradingDataPersist) ListBacktestLogs(userId int64) (backtestLogs []*backtest.BacktestTradingPlan, err error) { +func (p *TradingDataPersist) ListBacktestLogs(userId int64) (backtestLogs []*trade.BacktestTradingPlan, err error) { err = p.db.Select(&backtestLogs, ` select * from t_backtest_trading_plan where user_id = ? order by id desc `, userId) diff --git a/internal/trading/trading_grpc_server.go b/internal/trading/trading_grpc_server.go index 41b8580..652bc85 100644 --- a/internal/trading/trading_grpc_server.go +++ b/internal/trading/trading_grpc_server.go @@ -132,13 +132,3 @@ func (svr *TradingGrpcServer) BacktestRace(ctx context.Context, req *pb.ReqBackt }) return } - -func (svr *TradingGrpcServer) BacktestLogTrades(ctx context.Context, req *pb.ReqBacktestLogTrades) (rsp *pb.RspBacktestLogTrades, err error) { - - return -} - -func (svr *TradingGrpcServer) BacktestLogStats(ctx context.Context, req *pb.ReqBacktestLogStats) (rsp *pb.RspBacktestLogStats, err error) { - - return -} diff --git a/internal/trading/trading_service.go b/internal/trading/trading_service.go index fa7ff0d..01d70ea 100644 --- a/internal/trading/trading_service.go +++ b/internal/trading/trading_service.go @@ -12,6 +12,7 @@ import ( "sig-pub/pkg/indicator" "sig-pub/pkg/publish" "sig-pub/pkg/strategy" + "sig-pub/pkg/trade" "sig-pub/pkg/types" "sig-pub/pkg/utils/collect" "sig-pub/pkg/utils/lang" @@ -362,7 +363,7 @@ func (svc *TradingService) Backtest(ctx context.Context, planId, stime, etime in } // BacktestLog 回测记录查询 -func (svc *TradingService) BacktestLog(ctx context.Context, userId int64) (backtestLogs []*backtest.BacktestTradingPlan, err error) { +func (svc *TradingService) BacktestLog(ctx context.Context, userId int64) (backtestLogs []*trade.BacktestTradingPlan, err error) { // todo userid from ctx backtestLogs, err = svc.tradingDataPersist.ListBacktestLogs(userId) return @@ -449,7 +450,7 @@ func (svc *TradingService) BacktestRace(ctx context.Context, req *pb.ReqBacktest } } } - var results []*backtest.BacktestTradingPlan + var results []*trade.BacktestTradingPlan for _, backtester := range backtesters { r, e := backtester.Backtest(ctx) if e != nil { diff --git a/pkg/data/common.go b/pkg/data/common.go index 537571e..be5a3b9 100644 --- a/pkg/data/common.go +++ b/pkg/data/common.go @@ -1,6 +1,11 @@ package data -import "errors" +import ( + "errors" + "strconv" + + "github.com/gin-gonic/gin" +) // 状态枚举 type Status int32 @@ -30,3 +35,33 @@ func PageCalc(page, size int) (offset, limit int) { offset = (page - 1) * size return offset, size } + +type Page struct { + Page, PageSize int + SortBy string + Asc bool + Offset, Limit int +} + +func PageArgs(ctx *gin.Context) Page { + page, _ := strconv.Atoi(ctx.Query("page")) + pageSize, _ := strconv.Atoi(ctx.Query("pageSize")) + sortBy := ctx.Query("sortBy") + asc, _ := strconv.Atoi(ctx.Query("asc")) + + if page <= 0 { + page = 1 + } + if pageSize <= 0 || pageSize > 1000 { + pageSize = 20 + } + offset, limit := PageCalc(page, pageSize) + return Page{ + Page: page, + PageSize: pageSize, + SortBy: sortBy, + Asc: asc == 1, + Offset: offset, + Limit: limit, + } +} diff --git a/pkg/trade/types.go b/pkg/trade/types.go index 525914b..dbac545 100644 --- a/pkg/trade/types.go +++ b/pkg/trade/types.go @@ -1,6 +1,7 @@ package trade import ( + "sig-pub/api/pb" "sig-pub/pkg/data" "sig-pub/pkg/types" @@ -54,20 +55,49 @@ type Position struct { LastPx float64 // 最后更新价格 } +// BacktestTradingPlan 交易计划回测结果 +type BacktestTradingPlan struct { + Id int64 `json:"id" gorm:"column:id;primaryKey"` // 测试id + UserId int64 `json:"userId" gorm:"column:user_id"` // 用户id + PlanId int64 `json:"planId" gorm:"column:plan_id"` // 交易计划id + InstId string `json:"instId" gorm:"column:inst_id"` // 交易产品id + Exchange pb.ExchangeType `json:"exchange" gorm:"column:exchange"` // 交易所 + Interval string `json:"interval" gorm:"column:interval"` // 交易周期 + SeriesBefore int64 `json:"seriesBefore" gorm:"column:series_before"` // 回测周期开始时间 + SeriesAfter int64 `json:"seriesAfter" gorm:"column:series_after"` // 回测周期结束时间 + Ctime int64 `json:"ctime" gorm:"column:ctime"` // 创建时间(测试时间) + Etime int64 `json:"etime" gorm:"column:etime"` // 测试结束时间 + Cash float64 `json:"cash" gorm:"column:cash"` // 起始金额 + EndCash float64 `json:"endCash" gorm:"column:end_cash"` // 结束金额 + Profit float64 `json:"profit" gorm:"column:profit"` // 利润 + Singals int `json:"singals" gorm:"column:singals"` // 交易信号数 + TotalTrades int `json:"totalTrades" gorm:"column:total_trades"` // 总单数 + WinningTrades int `json:"winningTrades" gorm:"column:winning_trades"` // 盈利单数 + LosingTrades int `json:"losingTrades" gorm:"column:losing_trades"` // 亏损单数 + Fee float64 `json:"fee" gorm:"column:fee"` // 总手续费 + MaxDrawdown float64 `json:"maxDrawdown" gorm:"column:max_drawdown"` // 最大回撤 + SharpeRatio float64 `json:"sharpeRatio" gorm:"column:sharpe_ratio"` // 夏普比率 + Trades []*TradeOrder `json:"-" gorm:"-"` // 回测交易单 +} + +func (BacktestTradingPlan) TableName() string { + return "t_backtest_trading_plan" +} + // TradeOrder 交易订单 type TradeOrder struct { - BacktestId int64 `jsno:"backtestId" gorm:"column:backtest_id"` // 回测单id - TradeId int64 `jsno:"tradeId" gorm:"column:trade_id"` // 交易单id - TradeType TradeType `jsno:"tradeType" gorm:"column:trade_type"` // 交易类型: 1.开仓 2.平仓 - InstId string `jsno:"instId" gorm:"column:inst_id"` // 交易产品id - Side types.Side `jsno:"side" gorm:"column:side"` // 交易方向 - Qty decimal.Decimal `jsno:"qty" gorm:"column:qty"` // 交易量 - Price float64 `jsno:"price" gorm:"column:price"` // 交易价格 - Fee float64 `jsno:"fee" gorm:"column:fee"` // 手续费 - Leverage int32 `jsno:"leverage" gorm:"column:leverage"` // 杠杆倍数 - Ctime int64 `jsno:"ctime" gorm:"column:ctime"` // 交易时间 - Status data.Status `jsno:"status" gorm:"column:status"` // 1.交易成功 2.交易中 4.交易失败 - PeakPx float64 `jsno:"peakPx" gorm:"column:peak_px"` // 持仓最高价格(空单最低价格) + BacktestId int64 `json:"backtestId" gorm:"column:backtest_id"` // 回测单id + TradeId int64 `json:"tradeId" gorm:"column:trade_id"` // 交易单id + TradeType TradeType `json:"tradeType" gorm:"column:trade_type"` // 交易类型: 1.开仓 2.平仓 + InstId string `json:"instId" gorm:"column:inst_id"` // 交易产品id + Side types.Side `json:"side" gorm:"column:side"` // 交易方向 + Qty decimal.Decimal `json:"qty" gorm:"column:qty"` // 交易量 + Price float64 `json:"price" gorm:"column:price"` // 交易价格 + Fee float64 `json:"fee" gorm:"column:fee"` // 手续费 + Leverage int32 `json:"leverage" gorm:"column:leverage"` // 杠杆倍数 + Ctime int64 `json:"ctime" gorm:"column:ctime"` // 交易时间 + Status data.Status `json:"status" gorm:"column:status"` // 1.交易成功 2.交易中 4.交易失败 + PeakPx float64 `json:"peakPx" gorm:"column:peak_px"` // 持仓最高价格(空单最低价格) // ----------------- 平仓单信息 CloseCause Cause `json:"closeCause" gorm:"column:close_cause"` // 平仓原因 ["stoploss", "takeprofit", "trailing", "retrace", "signal"](“止损”、“止盈”、“动态跟踪”、“回撤”、“信号”) Equity float64 `json:"equity" gorm:"column:equity"` // 平仓后账户净值