fix(web): source simple trigger market price

This commit is contained in:
root 2026-05-06 00:05:28 +00:00
parent 00c117321d
commit b7044a1eae

View File

@ -140,6 +140,8 @@ export function SimpleView() {
const normalizedSymbol = draft.symbol.trim().toUpperCase(); const normalizedSymbol = draft.symbol.trim().toUpperCase();
const livePrice = normalizedSymbol ? Number(botState.symbols?.[normalizedSymbol]?.price || 0) : 0; const livePrice = normalizedSymbol ? Number(botState.symbols?.[normalizedSymbol]?.price || 0) : 0;
const computedTriggerPrice = computeSimpleTriggerPrice(draft); const computedTriggerPrice = computeSimpleTriggerPrice(draft);
const resolvedMarketPrice = parsePositiveNumber(draft.currentMarketPrice);
const marketPriceSource = livePrice > 0 ? 'live' : (resolvedMarketPrice !== null ? 'recent_close' : null);
const triggerOptions = draft.side === 'buy' const triggerOptions = draft.side === 'buy'
? [ ? [
@ -176,11 +178,23 @@ export function SimpleView() {
}, [draft.side, draft.triggerMode]); }, [draft.side, draft.triggerMode]);
useEffect(() => { useEffect(() => {
if (draft.triggerMode !== 'drop_percent' || !livePrice || draft.currentMarketPrice.trim()) { if (draft.triggerMode !== 'drop_percent' || !livePrice) {
return; return;
} }
setDraft(prev => ({ ...prev, currentMarketPrice: livePrice.toFixed(4) })); setDraft(prev => (
}, [draft.triggerMode, draft.currentMarketPrice, livePrice]); prev.currentMarketPrice === livePrice.toFixed(4)
? prev
: { ...prev, currentMarketPrice: livePrice.toFixed(4) }
));
}, [draft.triggerMode, livePrice]);
useEffect(() => {
if (draft.triggerMode !== 'drop_percent' || !normalizedSymbol || livePrice > 0 || draft.currentMarketPrice.trim() || loadingPrice) {
return;
}
void handleLoadMarketPrice();
}, [draft.triggerMode, normalizedSymbol, livePrice]);
const rulePreview = useMemo(() => { const rulePreview = useMemo(() => {
if (!normalizedSymbol || computedTriggerPrice === null) return null; if (!normalizedSymbol || computedTriggerPrice === null) return null;
@ -207,7 +221,7 @@ export function SimpleView() {
throw new Error(`No recent market price found for ${normalizedSymbol}`); throw new Error(`No recent market price found for ${normalizedSymbol}`);
} }
updateDraft('currentMarketPrice', latestClose.toFixed(4)); updateDraft('currentMarketPrice', latestClose.toFixed(4));
setMessage(`Loaded current market price for ${normalizedSymbol}`); setMessage(`Loaded market price for ${normalizedSymbol}`);
} catch (err: any) { } catch (err: any) {
setError(err?.message ?? 'Failed to load current market price'); setError(err?.message ?? 'Failed to load current market price');
} finally { } finally {
@ -387,15 +401,22 @@ export function SimpleView() {
<div style={{ display: 'flex', gap: 8 }}> <div style={{ display: 'flex', gap: 8 }}>
<input <input
value={draft.currentMarketPrice} value={draft.currentMarketPrice}
onChange={e => updateDraft('currentMarketPrice', e.target.value)} readOnly
placeholder="e.g. 212.42" placeholder={normalizedSymbol ? 'Loading market price…' : 'Enter symbol first'}
inputMode="decimal" style={{
style={{ flex: 1, border: '1px solid #D1D5DB', borderRadius: 10, padding: '10px 12px', fontSize: 14 }} flex: 1,
border: '1px solid #D1D5DB',
borderRadius: 10,
padding: '10px 12px',
fontSize: 14,
background: '#F9FAFB',
color: draft.currentMarketPrice ? '#111827' : '#6B7280',
}}
/> />
<button <button
type="button" type="button"
onClick={handleLoadMarketPrice} onClick={handleLoadMarketPrice}
disabled={loadingPrice} disabled={loadingPrice || !normalizedSymbol}
style={{ style={{
border: '1px solid #D1D5DB', border: '1px solid #D1D5DB',
borderRadius: 10, borderRadius: 10,
@ -403,15 +424,17 @@ export function SimpleView() {
padding: '0 12px', padding: '0 12px',
fontSize: 12, fontSize: 12,
fontWeight: 800, fontWeight: 800,
color: '#374151', color: loadingPrice || !normalizedSymbol ? '#9CA3AF' : '#374151',
cursor: loadingPrice ? 'wait' : 'pointer', cursor: loadingPrice ? 'wait' : (!normalizedSymbol ? 'not-allowed' : 'pointer'),
}} }}
> >
<RefreshCw size={14} style={{ animation: loadingPrice ? 'spin 1s linear infinite' : 'none' }} /> <RefreshCw size={14} style={{ animation: loadingPrice ? 'spin 1s linear infinite' : 'none' }} />
</button> </button>
</div> </div>
{livePrice > 0 && ( {marketPriceSource && (
<small style={{ color: '#6B7280' }}>Live feed price in app state: {livePrice.toFixed(4)}</small> <small style={{ color: '#6B7280' }}>
Source: {marketPriceSource === 'live' ? 'live market feed' : 'recent market close'}
</small>
)} )}
</label> </label>
<label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}> <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>