mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-09 22:10:57 +08:00
feat: Alpaca US stock trader integration (Tasks 8-11)
- trader/alpaca/: Full Trader interface implementation for Alpaca - Paper/Live trading support (market orders, stop/limit) - GetBalance, GetPositions, GetMarketPrice via Alpaca API - Fractional share support (4 decimal places) - Commission-free trading - Agent trade routing: stock symbols (AAPL, TSLA) → Alpaca - isStockSymbol() heuristic to distinguish crypto vs stock - execute_trade tool updated for stock buy/sell semantics - get_market_price works for both crypto and stocks - TraderManager + API: Alpaca registered as exchange type - Factory case in auto_trader.go - Config mapping in trader_manager.go - Temp trader creation in handler_trader.go for balance query - Frontend: PositionsPanel distinguishes stock vs crypto - US flag emoji for stock positions - Dollar prefix for stock PnL/prices - 'Shares' label instead of 'Qty' for stocks - System prompts updated for stock trading capabilities
This commit is contained in:
@@ -63,7 +63,11 @@ export function PositionsPanel() {
|
||||
const isProfit = pnl >= 0
|
||||
const color = isProfit ? '#00e5a0' : '#F6465D'
|
||||
const side = pos.side?.toUpperCase() || (pos.quantity > 0 ? 'LONG' : 'SHORT')
|
||||
const symbol = (pos.symbol || '').replace('USDT', '')
|
||||
const rawSymbol = pos.symbol || ''
|
||||
// Stock symbols are pure letters (1-5 chars), crypto has USDT suffix
|
||||
const isStock = /^[A-Z]{1,5}$/.test(rawSymbol) && !rawSymbol.endsWith('USDT')
|
||||
const symbol = isStock ? rawSymbol : rawSymbol.replace('USDT', '')
|
||||
const currencyPrefix = isStock ? '$' : ''
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -93,6 +97,9 @@ export function PositionsPanel() {
|
||||
>
|
||||
{symbol}
|
||||
</span>
|
||||
{isStock && (
|
||||
<span style={{ fontSize: 10, color: '#8b8ba0' }}>🇺🇸</span>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
fontSize: 10,
|
||||
@@ -106,7 +113,7 @@ export function PositionsPanel() {
|
||||
color: side === 'LONG' ? '#00e5a0' : '#F6465D',
|
||||
}}
|
||||
>
|
||||
{side}
|
||||
{isStock ? (side === 'LONG' ? 'HOLD' : 'SHORT') : side}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -125,7 +132,7 @@ export function PositionsPanel() {
|
||||
<ArrowDownRight size={12} />
|
||||
)}
|
||||
{isProfit ? '+' : ''}
|
||||
{pnl.toFixed(2)}
|
||||
{currencyPrefix}{pnl.toFixed(2)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -136,8 +143,8 @@ export function PositionsPanel() {
|
||||
color: '#5c5c72',
|
||||
}}
|
||||
>
|
||||
<span>Qty: {pos.quantity}</span>
|
||||
<span>Entry: {pos.entry_price.toFixed(2)}</span>
|
||||
<span>{isStock ? 'Shares' : 'Qty'}: {pos.quantity}</span>
|
||||
<span>Entry: {currencyPrefix}{pos.entry_price.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user