feat: improve AI decision input format and chart UX

Backend changes:
- Add symbol headers to market data sections for clarity
- Add symbol labels to quantitative data output
- Skip position coins in candidate list to avoid duplicate data

Frontend changes:
- Add B/S toggle button to show/hide order markers
- Remove bottom legend (B BUY S SELL)
- Fix chart position reset on data refresh
- Separate marker toggle logic from data loading
This commit is contained in:
tinkle-community
2025-12-26 02:43:34 +08:00
parent 4ff9d21783
commit 6a2abfa96d
2 changed files with 68 additions and 35 deletions
+14 -2
View File
@@ -983,10 +983,20 @@ func (e *StrategyEngine) BuildUserPrompt(ctx *Context) string {
sb.WriteString("Current Positions: None\n\n")
}
// Candidate coins
// Candidate coins (exclude coins already in positions to avoid duplicate data)
positionSymbols := make(map[string]bool)
for _, pos := range ctx.Positions {
positionSymbols[pos.Symbol] = true
}
sb.WriteString(fmt.Sprintf("## Candidate Coins (%d coins)\n\n", len(ctx.MarketDataMap)))
displayedCount := 0
for _, coin := range ctx.CandidateCoins {
// Skip if this coin is already a position (data already shown in positions section)
if positionSymbols[coin.Symbol] {
continue
}
marketData, hasData := ctx.MarketDataMap[coin.Symbol]
if !hasData {
continue
@@ -1081,6 +1091,8 @@ func (e *StrategyEngine) formatMarketData(data *market.Data) string {
var sb strings.Builder
indicators := e.config.Indicators
// 明确标注币种
sb.WriteString(fmt.Sprintf("=== %s Market Data ===\n\n", data.Symbol))
sb.WriteString(fmt.Sprintf("current_price = %.4f", data.CurrentPrice))
if indicators.EnableEMA {
@@ -1252,7 +1264,7 @@ func (e *StrategyEngine) formatQuantData(data *QuantData) string {
}
var sb strings.Builder
sb.WriteString("📊 Quantitative Data:\n")
sb.WriteString(fmt.Sprintf("📊 %s Quantitative Data:\n", data.Symbol))
if len(data.PriceChange) > 0 {
sb.WriteString("Price Change: ")
+54 -33
View File
@@ -76,10 +76,13 @@ export function AdvancedChart({
const volumeSeriesRef = useRef<ISeriesApi<'Histogram'> | null>(null)
const indicatorSeriesRef = useRef<Map<string, ISeriesApi<any>>>(new Map())
const seriesMarkersRef = useRef<any>(null) // Markers primitive for v5
const currentMarkersDataRef = useRef<any[]>([]) // 存储当前的标记数据
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [showIndicatorPanel, setShowIndicatorPanel] = useState(false)
const [showOrderMarkers, setShowOrderMarkers] = useState(true) // 订单标记显示开关,默认显示
const isInitialLoadRef = useRef(true) // 跟踪是否为初始加载
// 指标配置
const [indicators, setIndicators] = useState<IndicatorConfig[]>([
@@ -360,6 +363,9 @@ export function AdvancedChart({
// 加载数据和指标
useEffect(() => {
// 当 symbol 或 interval 改变时,重置初始加载标志(以便自动适配新数据)
isInitialLoadRef.current = true
const loadData = async () => {
if (!candlestickSeriesRef.current) return
@@ -436,15 +442,20 @@ export function AdvancedChart({
console.log('[AdvancedChart] Markers data:', JSON.stringify(markers, null, 2))
try {
// 存储标记数据供后续切换使用
currentMarkersDataRef.current = markers
// 使用 v5 API: createSeriesMarkers
const markersToShow = showOrderMarkers ? markers : []
if (seriesMarkersRef.current) {
// 如果已经存在,更新标记
seriesMarkersRef.current.setMarkers(markers)
seriesMarkersRef.current.setMarkers(markersToShow)
} else {
// 首次创建标记
seriesMarkersRef.current = createSeriesMarkers(candlestickSeriesRef.current, markers)
seriesMarkersRef.current = createSeriesMarkers(candlestickSeriesRef.current, markersToShow)
}
console.log('[AdvancedChart] ✅ Markers set successfully!')
console.log('[AdvancedChart] ✅ Markers updated! Count:', markersToShow.length, 'Visible:', showOrderMarkers)
} catch (err) {
console.error('[AdvancedChart] ❌ Failed to set markers:', err)
}
@@ -465,8 +476,11 @@ export function AdvancedChart({
})
}
// 自动适配视图
chartRef.current?.timeScale().fitContent()
// 只在初始加载时自动适配视图,避免刷新时抖动
if (isInitialLoadRef.current) {
chartRef.current?.timeScale().fitContent()
isInitialLoadRef.current = false
}
setLoading(false)
} catch (err: any) {
console.error('[AdvancedChart] Error loading data:', err)
@@ -482,6 +496,19 @@ export function AdvancedChart({
return () => clearInterval(refreshInterval)
}, [symbol, interval, traderID, indicators])
// 单独处理订单标记的显示/隐藏,避免重新加载数据
useEffect(() => {
if (!seriesMarkersRef.current) return
try {
const markersToShow = showOrderMarkers ? currentMarkersDataRef.current : []
seriesMarkersRef.current.setMarkers(markersToShow)
console.log('[AdvancedChart] 🔄 Toggled markers visibility:', showOrderMarkers, 'Count:', markersToShow.length)
} catch (err) {
console.error('[AdvancedChart] ❌ Failed to toggle markers:', err)
}
}, [showOrderMarkers])
// 更新指标
const updateIndicators = (klineData: Kline[]) => {
if (!chartRef.current) return
@@ -599,6 +626,20 @@ export function AdvancedChart({
<Settings className="w-3.5 h-3.5" />
<span>{language === 'zh' ? '指标' : 'Indicators'}</span>
</button>
{/* 订单标记开关 */}
<button
onClick={() => setShowOrderMarkers(!showOrderMarkers)}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-all"
style={{
background: showOrderMarkers ? 'rgba(240, 185, 11, 0.15)' : 'rgba(255, 255, 255, 0.05)',
color: showOrderMarkers ? '#F0B90B' : '#848E9C',
border: `1px solid ${showOrderMarkers ? 'rgba(240, 185, 11, 0.3)' : '#2B3139'}`,
}}
title={language === 'zh' ? '切换订单标记显示' : 'Toggle Order Markers'}
>
<span className="font-bold text-[11px]">B/S</span>
</button>
</div>
</div>
@@ -704,9 +745,8 @@ export function AdvancedChart({
<div
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bottom: '20%',
right: '5%',
pointerEvents: 'none',
userSelect: 'none',
zIndex: 1,
@@ -714,13 +754,12 @@ export function AdvancedChart({
>
<div
style={{
fontSize: '120px',
fontWeight: '900',
color: 'rgba(240, 185, 11, 0.15)',
letterSpacing: '12px',
fontFamily: 'Arial Black, sans-serif',
textShadow: '0 0 80px rgba(240, 185, 11, 0.25)',
opacity: 0.6,
fontSize: '56px',
fontWeight: '700',
color: 'rgba(240, 185, 11, 0.12)',
letterSpacing: '4px',
fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, sans-serif',
textShadow: '0 2px 30px rgba(240, 185, 11, 0.2)',
}}
>
NOFX
@@ -741,24 +780,6 @@ export function AdvancedChart({
</div>
)}
{/* 图例说明 - 简化版 */}
<div
className="flex items-center gap-4 px-4 py-2.5 text-xs"
style={{ borderTop: '1px solid #2B3139', background: '#0F1215' }}
>
<div className="flex items-center gap-2">
<div className="w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-bold" style={{ background: '#0ECB81', color: '#0B0E11' }}>
B
</div>
<span style={{ color: '#EAECEF' }}>{language === 'zh' ? '买入 (BUY)' : 'BUY'}</span>
</div>
<div className="flex items-center gap-2">
<div className="w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-bold" style={{ background: '#F6465D', color: '#0B0E11' }}>
S
</div>
<span style={{ color: '#EAECEF' }}>{language === 'zh' ? '卖出 (SELL)' : 'SELL'}</span>
</div>
</div>
</div>
)
}