package sdk import ( "context" "encoding/json" "fmt" ) // Position 对应 HoldingHandler 封装后的持仓。 type Position struct { StockCode string `json:"StockCode"` StockName string `json:"StockName"` Direction any `json:"Direction"` Volume int `json:"Volume"` OpenPrice float64 `json:"OpenPrice"` FloatProfit float64 `json:"FloatProfit"` MarketValue float64 `json:"MarketValue"` StockHolder string `json:"StockHolder"` FrozenVolume int `json:"FrozenVolume"` CanUseVolume int `json:"CanUseVolume"` OnRoadVolume int `json:"OnRoadVolume"` YesterdayVolume int `json:"YesterdayVolume"` LastPrice float64 `json:"LastPrice"` ProfitRate float64 `json:"ProfitRate"` FutureTradeType any `json:"FutureTradeType"` ExpireDate string `json:"ExpireDate"` } type Assets struct { Total float64 `json:"total"` Available float64 `json:"available"` } func (c *Client) Positions(ctx context.Context) ([]string, []Position, error) { return c.decodePositions(ctx, "/api/v2/positions") } func (c *Client) Holding(ctx context.Context) ([]string, []Position, error) { return c.decodePositions(ctx, "/api/holding") } func (c *Client) decodePositions(ctx context.Context, path string) ([]string, []Position, error) { raw := map[string]json.RawMessage{} if err := c.post(ctx, path, map[string]any{"account": c.accountType}, &raw); err != nil { return nil, nil, err } codes := make([]string, 0, len(raw)) out := make([]Position, 0, len(raw)) for code, blob := range raw { var p Position if err := json.Unmarshal(blob, &p); err != nil { return nil, nil, fmt.Errorf("position %s: %w", code, err) } if p.StockCode == "" { p.StockCode = code } codes = append(codes, code) out = append(out, p) } return codes, out, nil } func (c *Client) Assets(ctx context.Context) (*Assets, error) { var out Assets if err := c.post(ctx, "/api/v2/assets", map[string]any{"account": c.accountType}, &out); err != nil { return nil, err } return &out, nil } func (c *Client) TotalMoney(ctx context.Context) (float64, error) { var out struct { TotalMoney float64 `json:"total_money"` } if err := c.post(ctx, "/api/money/total", map[string]any{"account": c.accountType}, &out); err != nil { return 0, err } return out.TotalMoney, nil } func (c *Client) AvailableMoney(ctx context.Context) (float64, error) { var out struct { AvailableMoney float64 `json:"available_money"` } if err := c.post(ctx, "/api/money/available", map[string]any{"account": c.accountType}, &out); err != nil { return 0, err } return out.AvailableMoney, nil } type OrderRefResult struct { Status string `json:"status"` Action string `json:"action"` Stock string `json:"stock"` OpType int `json:"opType"` OrderRef string `json:"order_ref"` } func (c *Client) Buy(ctx context.Context, stock string, price float64, volume int, prType int) (*OrderRefResult, error) { body := map[string]any{"stock": stock, "price": price, "volume": volume} if prType != 0 { body["prType"] = prType } var out OrderRefResult if err := c.post(ctx, "/api/order/buy", body, &out); err != nil { return nil, err } return &out, nil } func (c *Client) Sell(ctx context.Context, stock string, price float64, volume int, prType int) (*OrderRefResult, error) { body := map[string]any{"stock": stock, "price": price, "volume": volume} if prType != 0 { body["prType"] = prType } var out OrderRefResult if err := c.post(ctx, "/api/order/sell", body, &out); err != nil { return nil, err } return &out, nil } type OrderStatus struct { OrderSysID string `json:"order_sys_id"` Status int `json:"status"` VolumeLeft int `json:"volume_left"` VolumeTraded int `json:"volume_traded"` } func (c *Client) OrderStatusList(ctx context.Context) ([]OrderStatus, error) { var out struct { Orders []OrderStatus `json:"orders"` } if err := c.post(ctx, "/api/order/status", map[string]any{"account": c.accountType}, &out); err != nil { return nil, err } return out.Orders, nil } type CanceledOrder struct { OrderSysID string `json:"order_sys_id"` Stock string `json:"stock"` VolumeLeft int `json:"volume_left"` } type CancelAllResult struct { Status string `json:"status"` Message string `json:"message"` CanceledOrders []CanceledOrder `json:"canceled_orders"` CanceledSysIDs []string `json:"canceled_sys_ids"` } func (c *Client) CancelAll(ctx context.Context) (*CancelAllResult, error) { var out CancelAllResult if err := c.post(ctx, "/api/order/cancel_all", map[string]any{"account": c.accountType}, &out); err != nil { return nil, err } return &out, nil } // CancelByRule 按「代码.市场 + (剩余+已成)」匹配撤单。HTTP 没有按委托号撤单。 func (c *Client) CancelByRule(ctx context.Context, stock string, volume int) (*CancelAllResult, error) { var out CancelAllResult body := map[string]any{"stock": stock, "volume": volume, "account": c.accountType} if err := c.post(ctx, "/api/order/cancel_order", body, &out); err != nil { return nil, err } return &out, nil } func (c *Client) Deals(ctx context.Context) ([]map[string]string, error) { var out struct { Deals []map[string]string `json:"deals"` } if err := c.post(ctx, "/api/order/deal", map[string]any{"account": c.accountType}, &out); err != nil { return nil, err } return out.Deals, nil }