mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 00:07:01 +08:00
feat: add OI ranking data support and fix trader config update issues
- Add OI ranking data fetching and formatting for AI prompts - Fix trader update not saving strategy_id, ai_model_id, initial_balance - Fix AI API key not set for non-qwen/deepseek providers - Add strategy_id to trader config API response - Remove old trader from memory before reloading on update - Clean up unused useTraderActions.ts
This commit is contained in:
@@ -65,6 +65,10 @@ type DebateSession struct {
|
||||
FinalDecisions []*DebateDecision `json:"final_decisions,omitempty"` // Multi-coin decisions
|
||||
AutoExecute bool `json:"auto_execute"`
|
||||
TraderID string `json:"trader_id,omitempty"` // Trader to use for auto-execute
|
||||
// OI Ranking data options
|
||||
EnableOIRanking bool `json:"enable_oi_ranking"` // Whether to include OI ranking data
|
||||
OIRankingLimit int `json:"oi_ranking_limit"` // Number of OI ranking entries (default 10)
|
||||
OIDuration string `json:"oi_duration"` // Duration for OI data (1h, 4h, 24h, etc.)
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -239,6 +243,9 @@ func (s *DebateStore) InitSchema() error {
|
||||
`ALTER TABLE debate_sessions ADD COLUMN interval_minutes INTEGER DEFAULT 5`,
|
||||
`ALTER TABLE debate_sessions ADD COLUMN prompt_variant TEXT DEFAULT 'balanced'`,
|
||||
`ALTER TABLE debate_sessions ADD COLUMN trader_id TEXT`,
|
||||
`ALTER TABLE debate_sessions ADD COLUMN enable_oi_ranking BOOLEAN DEFAULT 0`,
|
||||
`ALTER TABLE debate_sessions ADD COLUMN oi_ranking_limit INTEGER DEFAULT 10`,
|
||||
`ALTER TABLE debate_sessions ADD COLUMN oi_duration TEXT DEFAULT '1h'`,
|
||||
`ALTER TABLE debate_votes ADD COLUMN leverage INTEGER DEFAULT 5`,
|
||||
`ALTER TABLE debate_votes ADD COLUMN position_pct REAL DEFAULT 0.2`,
|
||||
`ALTER TABLE debate_votes ADD COLUMN stop_loss_pct REAL DEFAULT 0.03`,
|
||||
@@ -266,15 +273,22 @@ func (s *DebateStore) CreateSession(session *DebateSession) error {
|
||||
if session.PromptVariant == "" {
|
||||
session.PromptVariant = "balanced"
|
||||
}
|
||||
if session.OIRankingLimit == 0 {
|
||||
session.OIRankingLimit = 10
|
||||
}
|
||||
if session.OIDuration == "" {
|
||||
session.OIDuration = "1h"
|
||||
}
|
||||
session.CreatedAt = time.Now()
|
||||
session.UpdatedAt = time.Now()
|
||||
|
||||
_, err := s.db.Exec(`
|
||||
INSERT INTO debate_sessions (id, user_id, name, strategy_id, status, symbol, max_rounds, current_round, interval_minutes, prompt_variant, auto_execute, trader_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
INSERT INTO debate_sessions (id, user_id, name, strategy_id, status, symbol, max_rounds, current_round, interval_minutes, prompt_variant, auto_execute, trader_id, enable_oi_ranking, oi_ranking_limit, oi_duration, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
session.ID, session.UserID, session.Name, session.StrategyID, session.Status,
|
||||
session.Symbol, session.MaxRounds, session.CurrentRound, session.IntervalMinutes, session.PromptVariant,
|
||||
session.AutoExecute, session.TraderID, session.CreatedAt, session.UpdatedAt,
|
||||
session.AutoExecute, session.TraderID, session.EnableOIRanking, session.OIRankingLimit, session.OIDuration,
|
||||
session.CreatedAt, session.UpdatedAt,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -286,17 +300,22 @@ func (s *DebateStore) GetSession(id string) (*DebateSession, error) {
|
||||
var traderID sql.NullString
|
||||
var intervalMinutes sql.NullInt64
|
||||
var promptVariant sql.NullString
|
||||
var enableOIRanking sql.NullBool
|
||||
var oiRankingLimit sql.NullInt64
|
||||
var oiDuration sql.NullString
|
||||
|
||||
// Try new schema first
|
||||
err := s.db.QueryRow(`
|
||||
SELECT id, user_id, name, strategy_id, status, symbol, max_rounds, current_round,
|
||||
interval_minutes, prompt_variant, final_decision, auto_execute, trader_id, created_at, updated_at
|
||||
interval_minutes, prompt_variant, final_decision, auto_execute, trader_id,
|
||||
enable_oi_ranking, oi_ranking_limit, oi_duration, created_at, updated_at
|
||||
FROM debate_sessions WHERE id = ?`, id,
|
||||
).Scan(
|
||||
&session.ID, &session.UserID, &session.Name, &session.StrategyID,
|
||||
&session.Status, &session.Symbol, &session.MaxRounds, &session.CurrentRound,
|
||||
&intervalMinutes, &promptVariant,
|
||||
&finalDecisionJSON, &session.AutoExecute, &traderID, &session.CreatedAt, &session.UpdatedAt,
|
||||
&finalDecisionJSON, &session.AutoExecute, &traderID,
|
||||
&enableOIRanking, &oiRankingLimit, &oiDuration, &session.CreatedAt, &session.UpdatedAt,
|
||||
)
|
||||
|
||||
// Fallback to basic schema if new columns don't exist
|
||||
@@ -316,6 +335,8 @@ func (s *DebateStore) GetSession(id string) (*DebateSession, error) {
|
||||
// Set defaults for new fields
|
||||
session.IntervalMinutes = 5
|
||||
session.PromptVariant = "balanced"
|
||||
session.OIRankingLimit = 10
|
||||
session.OIDuration = "1h"
|
||||
} else {
|
||||
// Set defaults for nullable fields
|
||||
session.IntervalMinutes = 5
|
||||
@@ -329,6 +350,17 @@ func (s *DebateStore) GetSession(id string) (*DebateSession, error) {
|
||||
if traderID.Valid {
|
||||
session.TraderID = traderID.String
|
||||
}
|
||||
if enableOIRanking.Valid {
|
||||
session.EnableOIRanking = enableOIRanking.Bool
|
||||
}
|
||||
session.OIRankingLimit = 10
|
||||
if oiRankingLimit.Valid {
|
||||
session.OIRankingLimit = int(oiRankingLimit.Int64)
|
||||
}
|
||||
session.OIDuration = "1h"
|
||||
if oiDuration.Valid {
|
||||
session.OIDuration = oiDuration.String
|
||||
}
|
||||
}
|
||||
|
||||
if finalDecisionJSON.Valid && finalDecisionJSON.String != "" {
|
||||
|
||||
@@ -98,6 +98,11 @@ type IndicatorConfig struct {
|
||||
QuantDataAPIURL string `json:"quant_data_api_url,omitempty"` // quantitative data API address
|
||||
EnableQuantOI bool `json:"enable_quant_oi"` // whether to show OI data
|
||||
EnableQuantNetflow bool `json:"enable_quant_netflow"` // whether to show Netflow data
|
||||
// OI ranking data (market-wide open interest increase/decrease rankings)
|
||||
EnableOIRanking bool `json:"enable_oi_ranking"` // whether to enable OI ranking data
|
||||
OIRankingAPIURL string `json:"oi_ranking_api_url,omitempty"` // OI ranking API base URL
|
||||
OIRankingDuration string `json:"oi_ranking_duration,omitempty"` // duration: 1h, 4h, 24h
|
||||
OIRankingLimit int `json:"oi_ranking_limit,omitempty"` // number of entries (default 10)
|
||||
}
|
||||
|
||||
// KlineConfig K-line configuration
|
||||
@@ -246,6 +251,11 @@ func GetDefaultStrategyConfig(lang string) StrategyConfig {
|
||||
QuantDataAPIURL: "http://nofxaios.com:30006/api/coin/{symbol}?include=netflow,oi,price&auth=cm_568c67eae410d912c54c",
|
||||
EnableQuantOI: true,
|
||||
EnableQuantNetflow: true,
|
||||
// OI ranking data - market-wide OI increase/decrease rankings
|
||||
EnableOIRanking: true,
|
||||
OIRankingAPIURL: "http://nofxaios.com:30006",
|
||||
OIRankingDuration: "1h",
|
||||
OIRankingLimit: 10,
|
||||
},
|
||||
RiskControl: RiskControlConfig{
|
||||
MaxPositions: 3, // Max 3 coins simultaneously (CODE ENFORCED)
|
||||
|
||||
@@ -2,6 +2,7 @@ package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -262,14 +263,25 @@ func (s *TraderStore) UpdateShowInCompetition(userID, id string, showInCompetiti
|
||||
|
||||
// Update updates trader configuration
|
||||
func (s *TraderStore) Update(trader *Trader) error {
|
||||
fmt.Printf("📝 TraderStore.Update: ID=%s, Name=%s, AIModelID=%s, StrategyID=%s\n",
|
||||
trader.ID, trader.Name, trader.AIModelID, trader.StrategyID)
|
||||
_, err := s.db.Exec(`
|
||||
UPDATE traders SET
|
||||
name = ?, ai_model_id = ?, exchange_id = ?, strategy_id = ?,
|
||||
scan_interval_minutes = ?, is_cross_margin = ?, show_in_competition = ?,
|
||||
name = ?,
|
||||
ai_model_id = ?,
|
||||
exchange_id = ?,
|
||||
strategy_id = ?,
|
||||
initial_balance = CASE WHEN ? > 0 THEN ? ELSE initial_balance END,
|
||||
scan_interval_minutes = CASE WHEN ? > 0 THEN ? ELSE scan_interval_minutes END,
|
||||
is_cross_margin = ?,
|
||||
show_in_competition = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND user_id = ?
|
||||
`, trader.Name, trader.AIModelID, trader.ExchangeID, trader.StrategyID,
|
||||
trader.ScanIntervalMinutes, trader.IsCrossMargin, trader.ShowInCompetition, trader.ID, trader.UserID)
|
||||
trader.InitialBalance, trader.InitialBalance,
|
||||
trader.ScanIntervalMinutes, trader.ScanIntervalMinutes,
|
||||
trader.IsCrossMargin, trader.ShowInCompetition,
|
||||
trader.ID, trader.UserID)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user