Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions backend/app/llm/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@

logger = logging.getLogger(__name__)

MODEL = "openrouter/openai/gpt-oss-120b"
EXTRA_BODY = {"provider": {"order": ["cerebras"]}}
MODEL = "claude-sonnet-4-6"

SYSTEM_PROMPT = """You are FinAlly, an AI trading assistant for a simulated trading workstation.

Expand Down Expand Up @@ -240,8 +239,6 @@ async def chat_with_llm(user_message: str, price_cache: PriceCache) -> dict:
model=MODEL,
messages=messages,
response_format=LlmResponse,
reasoning_effort="low",
extra_body=EXTRA_BODY,
)
content = response.choices[0].message.content
llm_response = LlmResponse.model_validate_json(content)
Expand Down
5 changes: 5 additions & 0 deletions backend/app/routes/watchlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ class AddTickerRequest(BaseModel):
async def list_watchlist(request: Request):
"""Current watchlist tickers with latest prices from PriceCache."""
cache = request.app.state.price_cache
source = request.app.state.market_source
watchlist = await get_watchlist()

items = []
for entry in watchlist:
ticker = entry["ticker"]
update = cache.get(ticker)
# Auto-recover tickers not currently tracked (e.g., added in a previous session)
if update is None:
await source.add_ticker(ticker)
update = cache.get(ticker)
items.append({
"ticker": ticker,
"price": update.price if update else None,
Expand Down
29 changes: 10 additions & 19 deletions frontend/components/PriceChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function PriceChart({ ticker, getHistory }: PriceChartProps) {
if (!containerRef.current) return;

const chart = createChart(containerRef.current, {
autoSize: true,
layout: {
background: { color: "#161b22" },
textColor: "#8b949e",
Expand Down Expand Up @@ -52,16 +53,7 @@ export default function PriceChart({ ticker, getHistory }: PriceChartProps) {
chartRef.current = chart;
seriesRef.current = series;

const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
chart.applyOptions({ width, height });
}
});
ro.observe(containerRef.current);

return () => {
ro.disconnect();
chart.remove();
chartRef.current = null;
seriesRef.current = null;
Expand Down Expand Up @@ -101,22 +93,21 @@ export default function PriceChart({ ticker, getHistory }: PriceChartProps) {
});
});

if (!ticker) {
return (
<div className="flex items-center justify-center h-full text-text-muted text-sm">
Select a ticker from the watchlist
</div>
);
}

return (
<div className="flex flex-col h-full">
<div className="px-3 py-2 border-b border-border">
<h2 className="text-xs font-bold text-text-secondary uppercase tracking-wider">
{ticker} -- Price Chart
{ticker ? `${ticker} -- Price Chart` : "Price Chart"}
</h2>
</div>
<div ref={containerRef} className="flex-1 min-h-0" />
<div className="flex-1 min-h-0 relative">
<div ref={containerRef} style={{ position: "absolute", inset: 0 }} />
{!ticker && (
<div className="absolute inset-0 flex items-center justify-center text-text-muted text-sm">
Select a ticker from the watchlist
</div>
)}
</div>
</div>
);
}
7 changes: 6 additions & 1 deletion frontend/components/Watchlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function Watchlist({
const [addInput, setAddInput] = useState("");
const prevPricesRef = useRef<Record<string, number>>({});
const rowRefs = useRef<Record<string, HTMLTableRowElement | null>>({});
const listRef = useRef<HTMLDivElement>(null);

// Apply flash CSS classes directly to DOM elements
useEffect(() => {
Expand All @@ -51,6 +52,10 @@ export default function Watchlist({
await addToWatchlist(ticker);
setAddInput("");
onRefresh();
// Scroll to bottom to reveal the newly added ticker
setTimeout(() => {
if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;
}, 100);
}, [addInput, onRefresh]);

const handleRemove = useCallback(
Expand Down Expand Up @@ -86,7 +91,7 @@ export default function Watchlist({
</div>
</div>

<div className="flex-1 overflow-y-auto">
<div ref={listRef} className="flex-1 overflow-y-auto">
<table className="w-full text-xs">
<thead>
<tr className="text-text-muted border-b border-border">
Expand Down