mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 08:46:58 +08:00
Merge branch 'beta' into nofxos-beta
# Conflicts: # config/database.go # config/database_pg.go # docker-compose.yml # main.go # manager/trader_manager.go # web/src/components/AITradersPage.tsx
This commit is contained in:
@@ -742,6 +742,48 @@ func (d *Database) GetExchanges(userID string) ([]*ExchangeConfig, error) {
|
|||||||
return exchanges, nil
|
return exchanges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetExchangesForAPI 获取交易所配置(专用于API返回,排除敏感字段)
|
||||||
|
func (d *Database) GetExchangesForAPI(userID string) ([]*ExchangeConfig, error) {
|
||||||
|
rows, err := d.db.Query(`
|
||||||
|
SELECT id, user_id, name, type, enabled,
|
||||||
|
CASE
|
||||||
|
WHEN type = 'hyperliquid' THEN ''
|
||||||
|
ELSE COALESCE(api_key, '')
|
||||||
|
END as api_key,
|
||||||
|
'' as secret_key,
|
||||||
|
testnet,
|
||||||
|
COALESCE(hyperliquid_wallet_addr, '') as hyperliquid_wallet_addr,
|
||||||
|
COALESCE(aster_user, '') as aster_user,
|
||||||
|
COALESCE(aster_signer, '') as aster_signer,
|
||||||
|
'' as aster_private_key,
|
||||||
|
created_at, updated_at
|
||||||
|
FROM exchanges WHERE user_id = ? ORDER BY id
|
||||||
|
`, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// 初始化为空切片而不是nil,确保JSON序列化为[]而不是null
|
||||||
|
exchanges := make([]*ExchangeConfig, 0)
|
||||||
|
for rows.Next() {
|
||||||
|
var exchange ExchangeConfig
|
||||||
|
err := rows.Scan(
|
||||||
|
&exchange.ID, &exchange.UserID, &exchange.Name, &exchange.Type,
|
||||||
|
&exchange.Enabled, &exchange.APIKey, &exchange.SecretKey, &exchange.Testnet,
|
||||||
|
&exchange.HyperliquidWalletAddr, &exchange.AsterUser,
|
||||||
|
&exchange.AsterSigner, &exchange.AsterPrivateKey,
|
||||||
|
&exchange.CreatedAt, &exchange.UpdatedAt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
exchanges = append(exchanges, &exchange)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exchanges, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateExchange 更新交易所配置,如果不存在则创建用户特定配置
|
// UpdateExchange 更新交易所配置,如果不存在则创建用户特定配置
|
||||||
func (d *Database) UpdateExchange(userID, id string, enabled bool, apiKey, secretKey string, testnet bool, hyperliquidWalletAddr, asterUser, asterSigner, asterPrivateKey string) error {
|
func (d *Database) UpdateExchange(userID, id string, enabled bool, apiKey, secretKey string, testnet bool, hyperliquidWalletAddr, asterUser, asterSigner, asterPrivateKey string) error {
|
||||||
log.Printf("🔧 UpdateExchange: userID=%s, id=%s, enabled=%v", userID, id, enabled)
|
log.Printf("🔧 UpdateExchange: userID=%s, id=%s, enabled=%v", userID, id, enabled)
|
||||||
|
|||||||
@@ -1092,6 +1092,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
|
|||||||
{showExchangeModal && (
|
{showExchangeModal && (
|
||||||
<ExchangeConfigModal
|
<ExchangeConfigModal
|
||||||
allExchanges={supportedExchanges}
|
allExchanges={supportedExchanges}
|
||||||
|
configuredExchanges={allExchanges}
|
||||||
editingExchangeId={editingExchange}
|
editingExchangeId={editingExchange}
|
||||||
onSave={handleSaveExchangeConfig}
|
onSave={handleSaveExchangeConfig}
|
||||||
onDelete={handleDeleteExchangeConfig}
|
onDelete={handleDeleteExchangeConfig}
|
||||||
@@ -1560,6 +1561,7 @@ function ModelConfigModal({
|
|||||||
// Exchange Configuration Modal Component
|
// Exchange Configuration Modal Component
|
||||||
function ExchangeConfigModal({
|
function ExchangeConfigModal({
|
||||||
allExchanges,
|
allExchanges,
|
||||||
|
configuredExchanges,
|
||||||
editingExchangeId,
|
editingExchangeId,
|
||||||
onSave,
|
onSave,
|
||||||
onDelete,
|
onDelete,
|
||||||
@@ -1567,6 +1569,7 @@ function ExchangeConfigModal({
|
|||||||
language,
|
language,
|
||||||
}: {
|
}: {
|
||||||
allExchanges: Exchange[]
|
allExchanges: Exchange[]
|
||||||
|
configuredExchanges: Exchange[]
|
||||||
editingExchangeId: string | null
|
editingExchangeId: string | null
|
||||||
onSave: (
|
onSave: (
|
||||||
exchangeId: string,
|
exchangeId: string,
|
||||||
@@ -1600,15 +1603,20 @@ function ExchangeConfigModal({
|
|||||||
// 币安配置指南展开状态
|
// 币安配置指南展开状态
|
||||||
const [showBinanceGuide, setShowBinanceGuide] = useState(false)
|
const [showBinanceGuide, setShowBinanceGuide] = useState(false)
|
||||||
|
|
||||||
|
// Hyperliquid 特定字段
|
||||||
|
const [hyperliquidWalletAddr, setHyperliquidWalletAddr] = useState('')
|
||||||
|
|
||||||
// Aster 特定字段
|
// Aster 特定字段
|
||||||
const [asterUser, setAsterUser] = useState('')
|
const [asterUser, setAsterUser] = useState('')
|
||||||
const [asterSigner, setAsterSigner] = useState('')
|
const [asterSigner, setAsterSigner] = useState('')
|
||||||
const [asterPrivateKey, setAsterPrivateKey] = useState('')
|
const [asterPrivateKey, setAsterPrivateKey] = useState('')
|
||||||
|
|
||||||
// 获取当前编辑的交易所信息
|
// 获取当前选择的交易所信息
|
||||||
const selectedExchange = allExchanges?.find(
|
// 编辑模式:从 configuredExchanges 查找(包含用户配置的 apiKey、secretKey 等)
|
||||||
(e) => e.id === selectedExchangeId
|
// 新增模式:从 allExchanges 查找(系统支持的交易所列表)
|
||||||
)
|
const selectedExchange = editingExchangeId
|
||||||
|
? configuredExchanges?.find(e => e.id === selectedExchangeId)
|
||||||
|
: allExchanges?.find(e => e.id === selectedExchangeId);
|
||||||
|
|
||||||
// 如果是编辑现有交易所,初始化表单数据
|
// 如果是编辑现有交易所,初始化表单数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1618,6 +1626,9 @@ function ExchangeConfigModal({
|
|||||||
setPassphrase('') // Don't load existing passphrase for security
|
setPassphrase('') // Don't load existing passphrase for security
|
||||||
setTestnet(selectedExchange.testnet || false)
|
setTestnet(selectedExchange.testnet || false)
|
||||||
|
|
||||||
|
// Hyperliquid 字段
|
||||||
|
setHyperliquidWalletAddr(selectedExchange.hyperliquidWalletAddr || '')
|
||||||
|
|
||||||
// Aster 字段
|
// Aster 字段
|
||||||
setAsterUser(selectedExchange.asterUser || '')
|
setAsterUser(selectedExchange.asterUser || '')
|
||||||
setAsterSigner(selectedExchange.asterSigner || '')
|
setAsterSigner(selectedExchange.asterSigner || '')
|
||||||
@@ -2069,6 +2080,29 @@ function ExchangeConfigModal({
|
|||||||
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||||
{t('hyperliquidPrivateKeyDesc', language)}
|
{t('hyperliquidPrivateKeyDesc', language)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="block text-sm font-semibold mb-2"
|
||||||
|
style={{ color: '#EAECEF' }}
|
||||||
|
>
|
||||||
|
钱包地址
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={hyperliquidWalletAddr}
|
||||||
|
onChange={(e) => setHyperliquidWalletAddr(e.target.value)}
|
||||||
|
placeholder="钱包地址(可选,通常由私钥自动生成)"
|
||||||
|
className="w-full px-3 py-2 rounded"
|
||||||
|
style={{
|
||||||
|
background: '#0B0E11',
|
||||||
|
border: '1px solid #2B3139',
|
||||||
|
color: '#EAECEF',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||||
|
钱包地址通常由私钥自动生成,编辑时可查看或修改
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user