feat: add debate arena and fix multiple issues

- Add AI debate arena for multi-AI trading decisions
- Fix debate consensus calculation and display
- Fix vote parsing to support both <decision> and <final_vote> tags
- Fix JSON field name compatibility (stop_loss/stop_loss_pct)
- Fix symbol validation to prevent AI hallucinating invalid symbols
- Fix Bybit position side display (was uppercase, now lowercase for consistency)
- Fix NOFX logo navigation to home page
- Add detailed logging for debugging trade execution
This commit is contained in:
tinkle-community
2025-12-12 11:24:32 +08:00
parent e5703ffab6
commit f5ae22d85c
14 changed files with 4133 additions and 32 deletions

View File

@@ -22,6 +22,12 @@ import type {
BacktestRunMetadata,
Strategy,
StrategyConfig,
DebateSession,
DebateSessionWithDetails,
CreateDebateRequest,
DebateMessage,
DebateVote,
DebatePersonalityInfo,
} from '../types'
import { CryptoService } from './crypto'
import { httpClient } from './httpClient'
@@ -67,7 +73,7 @@ export const api = {
async getTraders(): Promise<TraderInfo[]> {
const result = await httpClient.get<TraderInfo[]>(`${API_BASE}/my-traders`)
if (!result.success) throw new Error('获取trader列表失败')
return result.data!
return Array.isArray(result.data) ? result.data : []
},
// 获取公开的交易员列表(无需认证)
@@ -155,7 +161,7 @@ export const api = {
async getModelConfigs(): Promise<AIModel[]> {
const result = await httpClient.get<AIModel[]>(`${API_BASE}/models`)
if (!result.success) throw new Error('获取模型配置失败')
return result.data!
return Array.isArray(result.data) ? result.data : []
},
// 获取系统支持的AI模型列表无需认证
@@ -623,9 +629,10 @@ export const api = {
// Strategy APIs
async getStrategies(): Promise<Strategy[]> {
const result = await httpClient.get<Strategy[]>(`${API_BASE}/strategies`)
const result = await httpClient.get<{ strategies: Strategy[] }>(`${API_BASE}/strategies`)
if (!result.success) throw new Error('获取策略列表失败')
return result.data!
const strategies = result.data?.strategies
return Array.isArray(strategies) ? strategies : []
},
async getStrategy(strategyId: string): Promise<Strategy> {
@@ -685,4 +692,71 @@ export const api = {
if (!result.success) throw new Error('复制策略失败')
return result.data!
},
// Debate Arena APIs
async getDebates(): Promise<DebateSession[]> {
const result = await httpClient.get<DebateSession[]>(`${API_BASE}/debates`)
if (!result.success) throw new Error('获取辩论列表失败')
return Array.isArray(result.data) ? result.data : []
},
async getDebate(debateId: string): Promise<DebateSessionWithDetails> {
const result = await httpClient.get<DebateSessionWithDetails>(`${API_BASE}/debates/${debateId}`)
if (!result.success) throw new Error('获取辩论详情失败')
return result.data!
},
async createDebate(request: CreateDebateRequest): Promise<DebateSessionWithDetails> {
const result = await httpClient.post<DebateSessionWithDetails>(`${API_BASE}/debates`, request)
if (!result.success) throw new Error('创建辩论失败')
return result.data!
},
async startDebate(debateId: string): Promise<void> {
const result = await httpClient.post(`${API_BASE}/debates/${debateId}/start`)
if (!result.success) throw new Error('启动辩论失败')
},
async cancelDebate(debateId: string): Promise<void> {
const result = await httpClient.post(`${API_BASE}/debates/${debateId}/cancel`)
if (!result.success) throw new Error('取消辩论失败')
},
async executeDebate(debateId: string, traderId: string): Promise<DebateSessionWithDetails> {
const result = await httpClient.post<{ message: string; session: DebateSessionWithDetails }>(
`${API_BASE}/debates/${debateId}/execute`,
{ trader_id: traderId }
)
if (!result.success) throw new Error('执行交易失败')
return result.data!.session
},
async deleteDebate(debateId: string): Promise<void> {
const result = await httpClient.delete(`${API_BASE}/debates/${debateId}`)
if (!result.success) throw new Error('删除辩论失败')
},
async getDebateMessages(debateId: string): Promise<DebateMessage[]> {
const result = await httpClient.get<DebateMessage[]>(`${API_BASE}/debates/${debateId}/messages`)
if (!result.success) throw new Error('获取辩论消息失败')
return result.data!
},
async getDebateVotes(debateId: string): Promise<DebateVote[]> {
const result = await httpClient.get<DebateVote[]>(`${API_BASE}/debates/${debateId}/votes`)
if (!result.success) throw new Error('获取辩论投票失败')
return result.data!
},
async getDebatePersonalities(): Promise<DebatePersonalityInfo[]> {
const result = await httpClient.get<DebatePersonalityInfo[]>(`${API_BASE}/debates/personalities`)
if (!result.success) throw new Error('获取AI性格列表失败')
return result.data!
},
// SSE stream for live debate updates
createDebateStream(debateId: string): EventSource {
const token = localStorage.getItem('auth_token')
return new EventSource(`${API_BASE}/debates/${debateId}/stream?token=${token}`)
},
}