UI: surface buying/selling suggestion and execution plan in portfolio and stock detail (show last saved suggestion)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { useLoaderData, useNavigate, useLocation } from "react-router";
|
|||||||
import TradingViewChart from "../components/TradingViewChart";
|
import TradingViewChart from "../components/TradingViewChart";
|
||||||
import Navbar from "../components/Navbar";
|
import Navbar from "../components/Navbar";
|
||||||
import JobHistory from "../components/JobHistory";
|
import JobHistory from "../components/JobHistory";
|
||||||
|
import { useMemo } from "react";
|
||||||
import type { TradingDecision, AnalystReport, DebateRound } from "../types/agents";
|
import type { TradingDecision, AnalystReport, DebateRound } from "../types/agents";
|
||||||
|
|
||||||
export const meta = () => [{ title: "Stock Detail - AITrader" }];
|
export const meta = () => [{ title: "Stock Detail - AITrader" }];
|
||||||
@@ -103,6 +104,15 @@ export default function StockDetail() {
|
|||||||
// Cache key for this ticker
|
// Cache key for this ticker
|
||||||
const cacheKey = `tradinggraph-${ticker}`;
|
const cacheKey = `tradinggraph-${ticker}`;
|
||||||
|
|
||||||
|
// Parsed last execution plan if present on stockRecord
|
||||||
|
const lastExecutionPlan = useMemo(() => {
|
||||||
|
try {
|
||||||
|
return stockRecord?.lastExecutionPlan ? JSON.parse(stockRecord.lastExecutionPlan) : null;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, [stockRecord]);
|
||||||
|
|
||||||
// Load cached results on mount
|
// Load cached results on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const cached = sessionStorage.getItem(cacheKey);
|
const cached = sessionStorage.getItem(cacheKey);
|
||||||
@@ -299,6 +309,23 @@ export default function StockDetail() {
|
|||||||
|
|
||||||
{/* Job history */}
|
{/* Job history */}
|
||||||
<JobHistory ticker={ticker} />
|
<JobHistory ticker={ticker} />
|
||||||
|
|
||||||
|
{/* Last persisted decision (if no live decision) */}
|
||||||
|
{!decision && stockRecord?.lastDecision && (
|
||||||
|
<div className="mt-3 bg-white rounded-lg p-3 border border-gray-200 text-gray-900">
|
||||||
|
<h4 className="text-sm font-medium">Last Saved Suggestion</h4>
|
||||||
|
<div className="mt-2 text-sm">
|
||||||
|
<div>Action: <strong className={stockRecord.lastDecision === 'buy' ? 'text-green-600' : stockRecord.lastDecision === 'sell' ? 'text-red-600' : 'text-gray-800'}>{stockRecord.lastDecision?.toUpperCase()}</strong></div>
|
||||||
|
{lastExecutionPlan && (
|
||||||
|
<div className="mt-2 text-sm text-gray-700">
|
||||||
|
{lastExecutionPlan.amount != null && (<div>Amount: <strong>{lastExecutionPlan.amount}</strong></div>)}
|
||||||
|
{lastExecutionPlan.takeProfit != null && (<div>Take profit: <strong>${lastExecutionPlan.takeProfit}</strong></div>)}
|
||||||
|
{lastExecutionPlan.riskManagement?.maxLossPercent != null && (<div>Risk: <strong>{lastExecutionPlan.riskManagement.maxLossPercent}%</strong></div>)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 bg-white rounded-xl shadow-lg p-6 border border-gray-200">
|
<div className="mt-6 bg-white rounded-xl shadow-lg p-6 border border-gray-200">
|
||||||
|
|||||||
@@ -352,8 +352,14 @@ export default function Analyze() {
|
|||||||
{stock.analysis.action.toUpperCase()}
|
{stock.analysis.action.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
<div className="text-xs text-gray-500">
|
<div className="text-xs text-gray-500">
|
||||||
Confidence: {(stock.analysis.confidence * 100).toFixed(0)}%
|
{stock.analysis.confidence ? `Confidence: ${(stock.analysis.confidence * 100).toFixed(0)}%` : "Saved suggestion"}
|
||||||
</div>
|
</div>
|
||||||
|
{stock.analysis.executionPlan && (
|
||||||
|
<div className="text-xs text-gray-700 mt-1">
|
||||||
|
{stock.analysis.executionPlan.amount != null && (<div>Amount: <strong>{stock.analysis.executionPlan.amount}</strong></div>)}
|
||||||
|
{stock.analysis.executionPlan.takeProfit != null && (<div>Take profit: <strong>${stock.analysis.executionPlan.takeProfit}</strong></div>)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : stock.loading ? (
|
) : stock.loading ? (
|
||||||
<span className="text-blue-600">Analyzing...</span>
|
<span className="text-blue-600">Analyzing...</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user