Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 57 additions & 47 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ type CreateTraderRequest struct {
AIModelID string `json:"ai_model_id" binding:"required"`
ExchangeID string `json:"exchange_id" binding:"required"`
InitialBalance float64 `json:"initial_balance"`
ScanIntervalMinutes int `json:"scan_interval_minutes"`
BTCETHLeverage int `json:"btc_eth_leverage"`
AltcoinLeverage int `json:"altcoin_leverage"`
TradingSymbols string `json:"trading_symbols"`
Expand Down Expand Up @@ -332,6 +333,12 @@ func (s *Server) handleCreateTrader(c *gin.Context) {
systemPromptTemplate = req.SystemPromptTemplate
}

// 设置扫描间隔默认值
scanIntervalMinutes := req.ScanIntervalMinutes
if scanIntervalMinutes <= 0 {
scanIntervalMinutes = 3 // 默认3分钟
}

// 创建交易员配置(数据库实体)
trader := &config.TraderRecord{
ID: traderID,
Expand All @@ -349,7 +356,7 @@ func (s *Server) handleCreateTrader(c *gin.Context) {
OverrideBasePrompt: req.OverrideBasePrompt,
SystemPromptTemplate: systemPromptTemplate,
IsCrossMargin: isCrossMargin,
ScanIntervalMinutes: 3, // 默认3分钟
ScanIntervalMinutes: scanIntervalMinutes,
IsRunning: false,
}

Expand Down Expand Up @@ -379,16 +386,17 @@ func (s *Server) handleCreateTrader(c *gin.Context) {

// UpdateTraderRequest 更新交易员请求
type UpdateTraderRequest struct {
Name string `json:"name" binding:"required"`
AIModelID string `json:"ai_model_id" binding:"required"`
ExchangeID string `json:"exchange_id" binding:"required"`
InitialBalance float64 `json:"initial_balance"`
BTCETHLeverage int `json:"btc_eth_leverage"`
AltcoinLeverage int `json:"altcoin_leverage"`
TradingSymbols string `json:"trading_symbols"`
CustomPrompt string `json:"custom_prompt"`
OverrideBasePrompt bool `json:"override_base_prompt"`
IsCrossMargin *bool `json:"is_cross_margin"`
Name string `json:"name" binding:"required"`
AIModelID string `json:"ai_model_id" binding:"required"`
ExchangeID string `json:"exchange_id" binding:"required"`
InitialBalance float64 `json:"initial_balance"`
ScanIntervalMinutes int `json:"scan_interval_minutes"`
BTCETHLeverage int `json:"btc_eth_leverage"`
AltcoinLeverage int `json:"altcoin_leverage"`
TradingSymbols string `json:"trading_symbols"`
CustomPrompt string `json:"custom_prompt"`
OverrideBasePrompt bool `json:"override_base_prompt"`
IsCrossMargin *bool `json:"is_cross_margin"`
}

// handleUpdateTrader 更新交易员配置
Expand Down Expand Up @@ -437,23 +445,30 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
if altcoinLeverage <= 0 {
altcoinLeverage = existingTrader.AltcoinLeverage // 保持原值
}


// 设置扫描间隔,允许更新
scanIntervalMinutes := req.ScanIntervalMinutes
if scanIntervalMinutes <= 0 {
scanIntervalMinutes = existingTrader.ScanIntervalMinutes // 保持原值
}

// 更新交易员配置
trader := &config.TraderRecord{
ID: traderID,
UserID: userID,
Name: req.Name,
AIModelID: req.AIModelID,
ExchangeID: req.ExchangeID,
InitialBalance: req.InitialBalance,
BTCETHLeverage: btcEthLeverage,
AltcoinLeverage: altcoinLeverage,
TradingSymbols: req.TradingSymbols,
CustomPrompt: req.CustomPrompt,
OverrideBasePrompt: req.OverrideBasePrompt,
IsCrossMargin: isCrossMargin,
ScanIntervalMinutes: existingTrader.ScanIntervalMinutes, // 保持原值
IsRunning: existingTrader.IsRunning, // 保持原值
ID: traderID,
UserID: userID,
Name: req.Name,
AIModelID: req.AIModelID,
ExchangeID: req.ExchangeID,
InitialBalance: req.InitialBalance,
BTCETHLeverage: btcEthLeverage,
AltcoinLeverage: altcoinLeverage,
TradingSymbols: req.TradingSymbols,
CustomPrompt: req.CustomPrompt,
OverrideBasePrompt: req.OverrideBasePrompt,
SystemPromptTemplate: existingTrader.SystemPromptTemplate, // 保持原值
IsCrossMargin: isCrossMargin,
ScanIntervalMinutes: scanIntervalMinutes,
IsRunning: existingTrader.IsRunning, // 保持原值
}

// 更新数据库
Expand Down Expand Up @@ -801,30 +816,25 @@ func (s *Server) handleGetTraderConfig(c *gin.Context) {
}
}

// AIModelID 应该已经是 provider(如 "deepseek"),直接使用
// 如果是旧数据格式(如 "admin_deepseek"),提取 provider 部分
// 返回完整的模型ID,不做转换,保持与前端模型列表一致
aiModelID := traderConfig.AIModelID
// 兼容旧数据:如果包含下划线,提取最后一部分作为 provider
if strings.Contains(aiModelID, "_") {
parts := strings.Split(aiModelID, "_")
aiModelID = parts[len(parts)-1]
}

result := map[string]interface{}{
"trader_id": traderConfig.ID,
"trader_name": traderConfig.Name,
"ai_model": aiModelID,
"exchange_id": traderConfig.ExchangeID,
"initial_balance": traderConfig.InitialBalance,
"btc_eth_leverage": traderConfig.BTCETHLeverage,
"altcoin_leverage": traderConfig.AltcoinLeverage,
"trading_symbols": traderConfig.TradingSymbols,
"custom_prompt": traderConfig.CustomPrompt,
"override_base_prompt": traderConfig.OverrideBasePrompt,
"is_cross_margin": traderConfig.IsCrossMargin,
"use_coin_pool": traderConfig.UseCoinPool,
"use_oi_top": traderConfig.UseOITop,
"is_running": isRunning,
"trader_id": traderConfig.ID,
"trader_name": traderConfig.Name,
"ai_model": aiModelID,
"exchange_id": traderConfig.ExchangeID,
"initial_balance": traderConfig.InitialBalance,
"scan_interval_minutes": traderConfig.ScanIntervalMinutes,
"btc_eth_leverage": traderConfig.BTCETHLeverage,
"altcoin_leverage": traderConfig.AltcoinLeverage,
"trading_symbols": traderConfig.TradingSymbols,
"custom_prompt": traderConfig.CustomPrompt,
"override_base_prompt": traderConfig.OverrideBasePrompt,
"is_cross_margin": traderConfig.IsCrossMargin,
"use_coin_pool": traderConfig.UseCoinPool,
"use_oi_top": traderConfig.UseOITop,
"is_running": isRunning,
}

c.JSON(http.StatusOK, result)
Expand Down
4 changes: 2 additions & 2 deletions market/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ func (m *WSMonitor) initializeHistoricalData() error {
return
}
if len(klines4h) > 0 {
m.klineDataMap4h.Store(s, klines)
log.Printf("已加载 %s 的历史K线数据-4h: %d 条", s, len(klines))
m.klineDataMap4h.Store(s, klines4h)
log.Printf("已加载 %s 的历史K线数据-4h: %d 条", s, len(klines4h))
}
}(symbol)
}
Expand Down
1 change: 1 addition & 0 deletions web/src/components/AITradersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
ai_model_id: data.ai_model_id,
exchange_id: data.exchange_id,
initial_balance: data.initial_balance,
scan_interval_minutes: data.scan_interval_minutes,
btc_eth_leverage: data.btc_eth_leverage,
altcoin_leverage: data.altcoin_leverage,
trading_symbols: data.trading_symbols,
Expand Down
24 changes: 23 additions & 1 deletion web/src/components/TraderConfigModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface TraderConfigData {
use_coin_pool: boolean;
use_oi_top: boolean;
initial_balance: number;
scan_interval_minutes: number;
}

interface TraderConfigModalProps {
Expand Down Expand Up @@ -57,6 +58,7 @@ export function TraderConfigModal({
use_coin_pool: false,
use_oi_top: false,
initial_balance: 1000,
scan_interval_minutes: 3,
});
const [isSaving, setIsSaving] = useState(false);
const [availableCoins, setAvailableCoins] = useState<string[]>([]);
Expand Down Expand Up @@ -87,6 +89,7 @@ export function TraderConfigModal({
use_coin_pool: false,
use_oi_top: false,
initial_balance: 1000,
scan_interval_minutes: 3,
});
}
// 确保旧数据也有默认的 system_prompt_template
Expand Down Expand Up @@ -181,6 +184,7 @@ export function TraderConfigModal({
use_coin_pool: formData.use_coin_pool,
use_oi_top: formData.use_oi_top,
initial_balance: formData.initial_balance,
scan_interval_minutes: formData.scan_interval_minutes,
};
await onSave(saveData);
onClose();
Expand Down Expand Up @@ -319,7 +323,25 @@ export function TraderConfigModal({
</div>
</div>

{/* 第二行:杠杆设置 */}
{/* 第二行:AI 扫描决策间隔 */}
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm text-[#EAECEF] block mb-2">AI 扫描决策间隔 (分钟)</label>
<input
type="number"
value={formData.scan_interval_minutes}
onChange={(e) => handleInputChange('scan_interval_minutes', Number(e.target.value))}
className="w-full px-3 py-2 bg-[#0B0E11] border border-[#2B3139] rounded text-[#EAECEF] focus:border-[#F0B90B] focus:outline-none"
min="1"
max="60"
step="1"
/>
<p className="text-xs text-gray-500 mt-1">建议: 3-10分钟</p>
</div>
<div></div>
</div>

{/* 第三行:杠杆设置 */}
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm text-[#EAECEF] block mb-2">BTC/ETH 杠杆</label>
Expand Down
13 changes: 11 additions & 2 deletions web/src/components/landing/CommunitySection.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { motion } from 'framer-motion'
import AnimatedSection from './AnimatedSection'

function TestimonialCard({ quote, author, delay }: any) {
interface CardProps {
quote: string;
authorName: string;
handle: string;
avatarUrl: string;
tweetUrl: string;
delay: number;
}

function TestimonialCard({ quote, authorName, delay }: CardProps) {
return (
<motion.div
className='p-6 rounded-xl'
Expand All @@ -18,7 +27,7 @@ function TestimonialCard({ quote, author, delay }: any) {
<div className='flex items-center gap-2'>
<div className='w-8 h-8 rounded-full' style={{ background: 'var(--binance-yellow)' }} />
<span className='text-sm font-semibold' style={{ color: 'var(--text-secondary)' }}>
{author}
{authorName}
</span>
</div>
</motion.div>
Expand Down
2 changes: 2 additions & 0 deletions web/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export interface CreateTraderRequest {
ai_model_id: string;
exchange_id: string;
initial_balance: number;
scan_interval_minutes?: number;
btc_eth_leverage?: number;
altcoin_leverage?: number;
trading_symbols?: string;
Expand Down Expand Up @@ -198,5 +199,6 @@ export interface TraderConfigData {
use_coin_pool: boolean;
use_oi_top: boolean;
initial_balance: number;
scan_interval_minutes: number;
is_running: boolean;
}
Loading