mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-13 15:57:01 +08:00
Merge pull request #338 from xqliu/feat/add-scan-interval-config-v2
feat: 添加 AI 扫描决策间隔配置支持
This commit is contained in:
@@ -210,6 +210,7 @@ type CreateTraderRequest struct {
|
|||||||
AIModelID string `json:"ai_model_id" binding:"required"`
|
AIModelID string `json:"ai_model_id" binding:"required"`
|
||||||
ExchangeID string `json:"exchange_id" binding:"required"`
|
ExchangeID string `json:"exchange_id" binding:"required"`
|
||||||
InitialBalance float64 `json:"initial_balance"`
|
InitialBalance float64 `json:"initial_balance"`
|
||||||
|
ScanIntervalMinutes int `json:"scan_interval_minutes"`
|
||||||
BTCETHLeverage int `json:"btc_eth_leverage"`
|
BTCETHLeverage int `json:"btc_eth_leverage"`
|
||||||
AltcoinLeverage int `json:"altcoin_leverage"`
|
AltcoinLeverage int `json:"altcoin_leverage"`
|
||||||
TradingSymbols string `json:"trading_symbols"`
|
TradingSymbols string `json:"trading_symbols"`
|
||||||
@@ -332,6 +333,12 @@ func (s *Server) handleCreateTrader(c *gin.Context) {
|
|||||||
systemPromptTemplate = req.SystemPromptTemplate
|
systemPromptTemplate = req.SystemPromptTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置扫描间隔默认值
|
||||||
|
scanIntervalMinutes := req.ScanIntervalMinutes
|
||||||
|
if scanIntervalMinutes <= 0 {
|
||||||
|
scanIntervalMinutes = 3 // 默认3分钟
|
||||||
|
}
|
||||||
|
|
||||||
// 创建交易员配置(数据库实体)
|
// 创建交易员配置(数据库实体)
|
||||||
trader := &config.TraderRecord{
|
trader := &config.TraderRecord{
|
||||||
ID: traderID,
|
ID: traderID,
|
||||||
@@ -349,7 +356,7 @@ func (s *Server) handleCreateTrader(c *gin.Context) {
|
|||||||
OverrideBasePrompt: req.OverrideBasePrompt,
|
OverrideBasePrompt: req.OverrideBasePrompt,
|
||||||
SystemPromptTemplate: systemPromptTemplate,
|
SystemPromptTemplate: systemPromptTemplate,
|
||||||
IsCrossMargin: isCrossMargin,
|
IsCrossMargin: isCrossMargin,
|
||||||
ScanIntervalMinutes: 3, // 默认3分钟
|
ScanIntervalMinutes: scanIntervalMinutes,
|
||||||
IsRunning: false,
|
IsRunning: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,16 +386,17 @@ func (s *Server) handleCreateTrader(c *gin.Context) {
|
|||||||
|
|
||||||
// UpdateTraderRequest 更新交易员请求
|
// UpdateTraderRequest 更新交易员请求
|
||||||
type UpdateTraderRequest struct {
|
type UpdateTraderRequest struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
AIModelID string `json:"ai_model_id" binding:"required"`
|
AIModelID string `json:"ai_model_id" binding:"required"`
|
||||||
ExchangeID string `json:"exchange_id" binding:"required"`
|
ExchangeID string `json:"exchange_id" binding:"required"`
|
||||||
InitialBalance float64 `json:"initial_balance"`
|
InitialBalance float64 `json:"initial_balance"`
|
||||||
BTCETHLeverage int `json:"btc_eth_leverage"`
|
ScanIntervalMinutes int `json:"scan_interval_minutes"`
|
||||||
AltcoinLeverage int `json:"altcoin_leverage"`
|
BTCETHLeverage int `json:"btc_eth_leverage"`
|
||||||
TradingSymbols string `json:"trading_symbols"`
|
AltcoinLeverage int `json:"altcoin_leverage"`
|
||||||
CustomPrompt string `json:"custom_prompt"`
|
TradingSymbols string `json:"trading_symbols"`
|
||||||
OverrideBasePrompt bool `json:"override_base_prompt"`
|
CustomPrompt string `json:"custom_prompt"`
|
||||||
IsCrossMargin *bool `json:"is_cross_margin"`
|
OverrideBasePrompt bool `json:"override_base_prompt"`
|
||||||
|
IsCrossMargin *bool `json:"is_cross_margin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleUpdateTrader 更新交易员配置
|
// handleUpdateTrader 更新交易员配置
|
||||||
@@ -437,23 +445,30 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
|
|||||||
if altcoinLeverage <= 0 {
|
if altcoinLeverage <= 0 {
|
||||||
altcoinLeverage = existingTrader.AltcoinLeverage // 保持原值
|
altcoinLeverage = existingTrader.AltcoinLeverage // 保持原值
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置扫描间隔,允许更新
|
||||||
|
scanIntervalMinutes := req.ScanIntervalMinutes
|
||||||
|
if scanIntervalMinutes <= 0 {
|
||||||
|
scanIntervalMinutes = existingTrader.ScanIntervalMinutes // 保持原值
|
||||||
|
}
|
||||||
|
|
||||||
// 更新交易员配置
|
// 更新交易员配置
|
||||||
trader := &config.TraderRecord{
|
trader := &config.TraderRecord{
|
||||||
ID: traderID,
|
ID: traderID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
AIModelID: req.AIModelID,
|
AIModelID: req.AIModelID,
|
||||||
ExchangeID: req.ExchangeID,
|
ExchangeID: req.ExchangeID,
|
||||||
InitialBalance: req.InitialBalance,
|
InitialBalance: req.InitialBalance,
|
||||||
BTCETHLeverage: btcEthLeverage,
|
BTCETHLeverage: btcEthLeverage,
|
||||||
AltcoinLeverage: altcoinLeverage,
|
AltcoinLeverage: altcoinLeverage,
|
||||||
TradingSymbols: req.TradingSymbols,
|
TradingSymbols: req.TradingSymbols,
|
||||||
CustomPrompt: req.CustomPrompt,
|
CustomPrompt: req.CustomPrompt,
|
||||||
OverrideBasePrompt: req.OverrideBasePrompt,
|
OverrideBasePrompt: req.OverrideBasePrompt,
|
||||||
IsCrossMargin: isCrossMargin,
|
SystemPromptTemplate: existingTrader.SystemPromptTemplate, // 保持原值
|
||||||
ScanIntervalMinutes: existingTrader.ScanIntervalMinutes, // 保持原值
|
IsCrossMargin: isCrossMargin,
|
||||||
IsRunning: existingTrader.IsRunning, // 保持原值
|
ScanIntervalMinutes: scanIntervalMinutes,
|
||||||
|
IsRunning: existingTrader.IsRunning, // 保持原值
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新数据库
|
// 更新数据库
|
||||||
@@ -805,20 +820,21 @@ func (s *Server) handleGetTraderConfig(c *gin.Context) {
|
|||||||
aiModelID := traderConfig.AIModelID
|
aiModelID := traderConfig.AIModelID
|
||||||
|
|
||||||
result := map[string]interface{}{
|
result := map[string]interface{}{
|
||||||
"trader_id": traderConfig.ID,
|
"trader_id": traderConfig.ID,
|
||||||
"trader_name": traderConfig.Name,
|
"trader_name": traderConfig.Name,
|
||||||
"ai_model": aiModelID,
|
"ai_model": aiModelID,
|
||||||
"exchange_id": traderConfig.ExchangeID,
|
"exchange_id": traderConfig.ExchangeID,
|
||||||
"initial_balance": traderConfig.InitialBalance,
|
"initial_balance": traderConfig.InitialBalance,
|
||||||
"btc_eth_leverage": traderConfig.BTCETHLeverage,
|
"scan_interval_minutes": traderConfig.ScanIntervalMinutes,
|
||||||
"altcoin_leverage": traderConfig.AltcoinLeverage,
|
"btc_eth_leverage": traderConfig.BTCETHLeverage,
|
||||||
"trading_symbols": traderConfig.TradingSymbols,
|
"altcoin_leverage": traderConfig.AltcoinLeverage,
|
||||||
"custom_prompt": traderConfig.CustomPrompt,
|
"trading_symbols": traderConfig.TradingSymbols,
|
||||||
"override_base_prompt": traderConfig.OverrideBasePrompt,
|
"custom_prompt": traderConfig.CustomPrompt,
|
||||||
"is_cross_margin": traderConfig.IsCrossMargin,
|
"override_base_prompt": traderConfig.OverrideBasePrompt,
|
||||||
"use_coin_pool": traderConfig.UseCoinPool,
|
"is_cross_margin": traderConfig.IsCrossMargin,
|
||||||
"use_oi_top": traderConfig.UseOITop,
|
"use_coin_pool": traderConfig.UseCoinPool,
|
||||||
"is_running": isRunning,
|
"use_oi_top": traderConfig.UseOITop,
|
||||||
|
"is_running": isRunning,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, result)
|
c.JSON(http.StatusOK, result)
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
|
|||||||
ai_model_id: data.ai_model_id,
|
ai_model_id: data.ai_model_id,
|
||||||
exchange_id: data.exchange_id,
|
exchange_id: data.exchange_id,
|
||||||
initial_balance: data.initial_balance,
|
initial_balance: data.initial_balance,
|
||||||
|
scan_interval_minutes: data.scan_interval_minutes,
|
||||||
btc_eth_leverage: data.btc_eth_leverage,
|
btc_eth_leverage: data.btc_eth_leverage,
|
||||||
altcoin_leverage: data.altcoin_leverage,
|
altcoin_leverage: data.altcoin_leverage,
|
||||||
trading_symbols: data.trading_symbols,
|
trading_symbols: data.trading_symbols,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ interface TraderConfigData {
|
|||||||
use_coin_pool: boolean;
|
use_coin_pool: boolean;
|
||||||
use_oi_top: boolean;
|
use_oi_top: boolean;
|
||||||
initial_balance: number;
|
initial_balance: number;
|
||||||
|
scan_interval_minutes: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TraderConfigModalProps {
|
interface TraderConfigModalProps {
|
||||||
@@ -57,6 +58,7 @@ export function TraderConfigModal({
|
|||||||
use_coin_pool: false,
|
use_coin_pool: false,
|
||||||
use_oi_top: false,
|
use_oi_top: false,
|
||||||
initial_balance: 1000,
|
initial_balance: 1000,
|
||||||
|
scan_interval_minutes: 3,
|
||||||
});
|
});
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [availableCoins, setAvailableCoins] = useState<string[]>([]);
|
const [availableCoins, setAvailableCoins] = useState<string[]>([]);
|
||||||
@@ -87,6 +89,7 @@ export function TraderConfigModal({
|
|||||||
use_coin_pool: false,
|
use_coin_pool: false,
|
||||||
use_oi_top: false,
|
use_oi_top: false,
|
||||||
initial_balance: 1000,
|
initial_balance: 1000,
|
||||||
|
scan_interval_minutes: 3,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 确保旧数据也有默认的 system_prompt_template
|
// 确保旧数据也有默认的 system_prompt_template
|
||||||
@@ -181,6 +184,7 @@ export function TraderConfigModal({
|
|||||||
use_coin_pool: formData.use_coin_pool,
|
use_coin_pool: formData.use_coin_pool,
|
||||||
use_oi_top: formData.use_oi_top,
|
use_oi_top: formData.use_oi_top,
|
||||||
initial_balance: formData.initial_balance,
|
initial_balance: formData.initial_balance,
|
||||||
|
scan_interval_minutes: formData.scan_interval_minutes,
|
||||||
};
|
};
|
||||||
await onSave(saveData);
|
await onSave(saveData);
|
||||||
onClose();
|
onClose();
|
||||||
@@ -319,7 +323,25 @@ export function TraderConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
</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 className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm text-[#EAECEF] block mb-2">BTC/ETH 杠杆</label>
|
<label className="text-sm text-[#EAECEF] block mb-2">BTC/ETH 杠杆</label>
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import AnimatedSection from './AnimatedSection'
|
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 (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
className='p-6 rounded-xl'
|
className='p-6 rounded-xl'
|
||||||
@@ -18,7 +27,7 @@ function TestimonialCard({ quote, author, delay }: any) {
|
|||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<div className='w-8 h-8 rounded-full' style={{ background: 'var(--binance-yellow)' }} />
|
<div className='w-8 h-8 rounded-full' style={{ background: 'var(--binance-yellow)' }} />
|
||||||
<span className='text-sm font-semibold' style={{ color: 'var(--text-secondary)' }}>
|
<span className='text-sm font-semibold' style={{ color: 'var(--text-secondary)' }}>
|
||||||
{author}
|
{authorName}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export interface CreateTraderRequest {
|
|||||||
ai_model_id: string;
|
ai_model_id: string;
|
||||||
exchange_id: string;
|
exchange_id: string;
|
||||||
initial_balance: number;
|
initial_balance: number;
|
||||||
|
scan_interval_minutes?: number;
|
||||||
btc_eth_leverage?: number;
|
btc_eth_leverage?: number;
|
||||||
altcoin_leverage?: number;
|
altcoin_leverage?: number;
|
||||||
trading_symbols?: string;
|
trading_symbols?: string;
|
||||||
@@ -198,5 +199,6 @@ export interface TraderConfigData {
|
|||||||
use_coin_pool: boolean;
|
use_coin_pool: boolean;
|
||||||
use_oi_top: boolean;
|
use_oi_top: boolean;
|
||||||
initial_balance: number;
|
initial_balance: number;
|
||||||
|
scan_interval_minutes: number;
|
||||||
is_running: boolean;
|
is_running: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user