mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 00:36:56 +08:00
fix: OI Top API response parsing and quant data URL validation
- Fix OITopAPIResponse struct to use Code int (0=success) instead of Success bool
- Add all response fields from actual API (time_range_param, rank_type, limit)
- Add {symbol} placeholder validation warning in FetchQuantData
- Add API-level validation in strategy create/update to warn about missing {symbol}
This commit is contained in:
@@ -8,12 +8,27 @@ import (
|
|||||||
"nofx/market"
|
"nofx/market"
|
||||||
"nofx/mcp"
|
"nofx/mcp"
|
||||||
"nofx/store"
|
"nofx/store"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// validateStrategyConfig validates strategy configuration and returns warnings
|
||||||
|
func validateStrategyConfig(config *store.StrategyConfig) []string {
|
||||||
|
var warnings []string
|
||||||
|
|
||||||
|
// Validate quant data URL if enabled
|
||||||
|
if config.Indicators.EnableQuantData && config.Indicators.QuantDataAPIURL != "" {
|
||||||
|
if !strings.Contains(config.Indicators.QuantDataAPIURL, "{symbol}") {
|
||||||
|
warnings = append(warnings, "Quant data URL does not contain {symbol} placeholder. The same data will be used for all coins, which may not be correct.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return warnings
|
||||||
|
}
|
||||||
|
|
||||||
// handleGetStrategies Get strategy list
|
// handleGetStrategies Get strategy list
|
||||||
func (s *Server) handleGetStrategies(c *gin.Context) {
|
func (s *Server) handleGetStrategies(c *gin.Context) {
|
||||||
userID := c.GetString("user_id")
|
userID := c.GetString("user_id")
|
||||||
@@ -123,10 +138,18 @@ func (s *Server) handleCreateStrategy(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
// Validate configuration and collect warnings
|
||||||
|
warnings := validateStrategyConfig(&req.Config)
|
||||||
|
|
||||||
|
response := gin.H{
|
||||||
"id": strategy.ID,
|
"id": strategy.ID,
|
||||||
"message": "Strategy created successfully",
|
"message": "Strategy created successfully",
|
||||||
})
|
}
|
||||||
|
if len(warnings) > 0 {
|
||||||
|
response["warnings"] = warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleUpdateStrategy Update strategy
|
// handleUpdateStrategy Update strategy
|
||||||
@@ -181,7 +204,15 @@ func (s *Server) handleUpdateStrategy(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Strategy updated successfully"})
|
// Validate configuration and collect warnings
|
||||||
|
warnings := validateStrategyConfig(&req.Config)
|
||||||
|
|
||||||
|
response := gin.H{"message": "Strategy updated successfully"}
|
||||||
|
if len(warnings) > 0 {
|
||||||
|
response["warnings"] = warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDeleteStrategy Delete strategy
|
// handleDeleteStrategy Delete strategy
|
||||||
|
|||||||
@@ -215,8 +215,14 @@ func (e *StrategyEngine) FetchQuantData(symbol string) (*QuantData, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if URL contains {symbol} placeholder
|
||||||
|
apiURL := e.config.Indicators.QuantDataAPIURL
|
||||||
|
if !strings.Contains(apiURL, "{symbol}") {
|
||||||
|
logger.Infof("⚠️ Quant data URL does not contain {symbol} placeholder, data may be incorrect for %s", symbol)
|
||||||
|
}
|
||||||
|
|
||||||
// Replace {symbol} placeholder
|
// Replace {symbol} placeholder
|
||||||
url := strings.Replace(e.config.Indicators.QuantDataAPIURL, "{symbol}", symbol, -1)
|
url := strings.Replace(apiURL, "{symbol}", symbol, -1)
|
||||||
|
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
resp, err := client.Get(url)
|
resp, err := client.Get(url)
|
||||||
|
|||||||
@@ -392,12 +392,15 @@ type OIPosition struct {
|
|||||||
|
|
||||||
// OITopAPIResponse data structure returned by OI Top API
|
// OITopAPIResponse data structure returned by OI Top API
|
||||||
type OITopAPIResponse struct {
|
type OITopAPIResponse struct {
|
||||||
Success bool `json:"success"`
|
Code int `json:"code"` // 0 = success
|
||||||
Data struct {
|
Data struct {
|
||||||
Positions []OIPosition `json:"positions"`
|
Positions []OIPosition `json:"positions"`
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
Exchange string `json:"exchange"`
|
Exchange string `json:"exchange"`
|
||||||
TimeRange string `json:"time_range"`
|
TimeRange string `json:"time_range"`
|
||||||
|
TimeRangeParam string `json:"time_range_param"`
|
||||||
|
RankType string `json:"rank_type"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,16 +497,16 @@ func fetchOITop() ([]OIPosition, error) {
|
|||||||
return nil, fmt.Errorf("OI Top JSON parsing failed: %w", err)
|
return nil, fmt.Errorf("OI Top JSON parsing failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !response.Success {
|
if response.Code != 0 {
|
||||||
return nil, fmt.Errorf("OI Top API returned failure status")
|
return nil, fmt.Errorf("OI Top API returned error code: %d", response.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(response.Data.Positions) == 0 {
|
if len(response.Data.Positions) == 0 {
|
||||||
return nil, fmt.Errorf("OI Top position list is empty")
|
return nil, fmt.Errorf("OI Top position list is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("✓ Successfully fetched %d OI Top coins (time range: %s)",
|
log.Printf("✓ Successfully fetched %d OI Top coins (time range: %s, type: %s)",
|
||||||
len(response.Data.Positions), response.Data.TimeRange)
|
len(response.Data.Positions), response.Data.TimeRange, response.Data.RankType)
|
||||||
return response.Data.Positions, nil
|
return response.Data.Positions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user