Merge pull request #416 from zhouyongyou/fix/bug-fixes-collection-v2

fix: 修復 6 個 bug(替代 #271)
This commit is contained in:
Icyoung
2025-11-05 15:57:36 +08:00
committed by GitHub
8 changed files with 65 additions and 53 deletions

View File

@@ -859,19 +859,12 @@ func (s *Server) handleTraderList(c *gin.Context) {
} }
} }
// AIModelID 应该已经是 provider(如 "deepseek"直接使用 // 返回完整的 AIModelID如 "admin_deepseek"不要截断
// 如果是旧数据格式(如 "admin_deepseek"),提取 provider 部分 // 前端需要完整 ID 来验证模型是否存在(与 handleGetTraderConfig 保持一致)
aiModelID := trader.AIModelID
// 兼容旧数据:如果包含下划线,提取最后一部分作为 provider
if strings.Contains(aiModelID, "_") {
parts := strings.Split(aiModelID, "_")
aiModelID = parts[len(parts)-1]
}
result = append(result, map[string]interface{}{ result = append(result, map[string]interface{}{
"trader_id": trader.ID, "trader_id": trader.ID,
"trader_name": trader.Name, "trader_name": trader.Name,
"ai_model": aiModelID, "ai_model": trader.AIModelID, // 使用完整 ID
"exchange_id": trader.ExchangeID, "exchange_id": trader.ExchangeID,
"is_running": isRunning, "is_running": isRunning,
"initial_balance": trader.InitialBalance, "initial_balance": trader.InitialBalance,
@@ -1801,4 +1794,3 @@ func (s *Server) handleGetPublicTraderConfig(c *gin.Context) {
c.JSON(http.StatusOK, result) c.JSON(http.StatusOK, result)
} }

View File

@@ -258,17 +258,17 @@ func (d *Database) initDefaultData() error {
// 初始化系统配置 - 创建所有字段设置默认值后续由config.json同步更新 // 初始化系统配置 - 创建所有字段设置默认值后续由config.json同步更新
systemConfigs := map[string]string{ systemConfigs := map[string]string{
"admin_mode": "true", // 默认开启管理员模式,便于首次使用 "admin_mode": "true", // 默认开启管理员模式,便于首次使用
"beta_mode": "false", // 默认关闭内测模式 "beta_mode": "false", // 默认关闭内测模式
"api_server_port": "8080", // 默认API端口 "api_server_port": "8080", // 默认API端口
"use_default_coins": "true", // 默认使用内置币种列表 "use_default_coins": "true", // 默认使用内置币种列表
"default_coins": `["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT","DOGEUSDT","ADAUSDT","HYPEUSDT"]`, // 默认币种列表JSON格式 "default_coins": `["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT","DOGEUSDT","ADAUSDT","HYPEUSDT"]`, // 默认币种列表JSON格式
"max_daily_loss": "10.0", // 最大日损失百分比 "max_daily_loss": "10.0", // 最大日损失百分比
"max_drawdown": "20.0", // 最大回撤百分比 "max_drawdown": "20.0", // 最大回撤百分比
"stop_trading_minutes": "60", // 停止交易时间(分钟) "stop_trading_minutes": "60", // 停止交易时间(分钟)
"btc_eth_leverage": "5", // BTC/ETH杠杆倍数 "btc_eth_leverage": "5", // BTC/ETH杠杆倍数
"altcoin_leverage": "5", // 山寨币杠杆倍数 "altcoin_leverage": "5", // 山寨币杠杆倍数
"jwt_secret": "", // JWT密钥默认为空由config.json或系统生成 "jwt_secret": "", // JWT密钥默认为空由config.json或系统生成
} }
for key, value := range systemConfigs { for key, value := range systemConfigs {

2
go.mod
View File

@@ -10,7 +10,7 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.0 github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.22
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/sonirico/go-hyperliquid v0.17.0 github.com/sonirico/go-hyperliquid v0.17.0

4
go.sum
View File

@@ -120,8 +120,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=

View File

@@ -295,6 +295,8 @@ func isRetryableError(err error) bool {
"connection refused", "connection refused",
"temporary failure", "temporary failure",
"no such host", "no such host",
"stream error", // HTTP/2 stream 错误
"INTERNAL_ERROR", // 服务端内部错误
} }
for _, retryable := range retryableErrors { for _, retryable := range retryableErrors {
if strings.Contains(errStr, retryable) { if strings.Contains(errStr, retryable) {

View File

@@ -165,6 +165,16 @@ start() {
# 读取环境变量 # 读取环境变量
read_env_vars read_env_vars
# 确保必要的文件和目录存在(修复 Docker volume 挂载问题)
if [ ! -f "config.db" ]; then
print_info "创建数据库文件..."
touch config.db
fi
if [ ! -d "decision_logs" ]; then
print_info "创建日志目录..."
mkdir -p decision_logs
fi
# Auto-build frontend if missing or forced # Auto-build frontend if missing or forced
# if [ ! -d "web/dist" ] || [ "$1" == "--build" ]; then # if [ ! -d "web/dist" ] || [ "$1" == "--build" ]; then
# build_frontend # build_frontend

View File

@@ -196,7 +196,8 @@ func NewAutoTrader(config AutoTraderConfig) (*AutoTrader, error) {
// 设置默认系统提示词模板 // 设置默认系统提示词模板
systemPromptTemplate := config.SystemPromptTemplate systemPromptTemplate := config.SystemPromptTemplate
if systemPromptTemplate == "" { if systemPromptTemplate == "" {
systemPromptTemplate = "default" // 默认使用 default 模板 // feature/partial-close-dynamic-tpsl 分支默认使用 adaptive支持动态止盈止损
systemPromptTemplate = "adaptive"
} }
return &AutoTrader{ return &AutoTrader{
@@ -482,6 +483,12 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
if quantity < 0 { if quantity < 0 {
quantity = -quantity // 空仓数量为负,转为正数 quantity = -quantity // 空仓数量为负,转为正数
} }
// 跳过已平仓的持仓quantity = 0防止"幽灵持仓"传递给AI
if quantity == 0 {
continue
}
unrealizedPnl := pos["unRealizedProfit"].(float64) unrealizedPnl := pos["unRealizedProfit"].(float64)
liquidationPrice := pos["liquidationPrice"].(float64) liquidationPrice := pos["liquidationPrice"].(float64)

View File

@@ -112,9 +112,10 @@ export function EquityChart({ traderId }: EquityChartProps) {
? validHistory.slice(-MAX_DISPLAY_POINTS) ? validHistory.slice(-MAX_DISPLAY_POINTS)
: validHistory : validHistory
// 计算初始余额(使用第一个有效数据点,如果无数据则从account获取,最后才用默认值 // 计算初始余额(优先从 account 获取配置的初始余额,备选从历史数据反推
const initialBalance = const initialBalance = account?.initial_balance // 从交易员配置读取真实初始余额
validHistory[0]?.total_equity || account?.total_equity || 100 // 默认值改为100与常见配置一致 || (validHistory[0] ? validHistory[0].total_equity - validHistory[0].pnl : undefined) // 备选:淨值 - 盈亏
|| 1000; // 默认值(与创建交易员时的默认配置一致)
// 转换数据格式 // 转换数据格式
const chartData = displayHistory.map((point) => { const chartData = displayHistory.map((point) => {