Add activation thresholds: qualified-signal defaults and views
Admin-configurable thresholds (min R:R, default 2.0; min confidence, default 70%) defining what counts as an actionable signal: - Admin Settings: new Activation Thresholds panel (GET/PUT /admin/settings/activation) - GET /trades/activation exposes values to all users with access - Signals/Setups: filters initialize from activation values - Track Record: "Qualified signals only" toggle (default on) via min_rr/min_confidence params on /trades/performance; the confidence breakdown always covers the full population so the thresholds can be validated against outcomes - Dashboard: "Qualified" metric and qualified-first Top Setups - Outcome evaluator unchanged: every setup is still evaluated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useActivation } from '../../hooks/useActivation';
|
||||
import { useTrades } from '../../hooks/useTrades';
|
||||
import { TradeTable, type SortColumn, type SortDirection, computeTradeAnalysis } from '../scanner/TradeTable';
|
||||
import { SkeletonTable } from '../ui/Skeleton';
|
||||
@@ -94,16 +95,22 @@ function sortTrades(
|
||||
|
||||
export function SetupsPanel() {
|
||||
const { data: trades, isLoading, isError, error } = useTrades();
|
||||
const activation = useActivation();
|
||||
const queryClient = useQueryClient();
|
||||
const toast = useToast();
|
||||
|
||||
const [minRR, setMinRR] = useState(0);
|
||||
// null = user hasn't touched the filter; falls back to admin-configured
|
||||
// activation thresholds once loaded
|
||||
const [minRROverride, setMinRROverride] = useState<number | null>(null);
|
||||
const [minConfidenceOverride, setMinConfidenceOverride] = useState<number | null>(null);
|
||||
const [directionFilter, setDirectionFilter] = useState<DirectionFilter>('both');
|
||||
const [minConfidence, setMinConfidence] = useState(0);
|
||||
const [actionFilter, setActionFilter] = useState<ActionFilter>('all');
|
||||
const [sortColumn, setSortColumn] = useState<SortColumn>('rr_ratio');
|
||||
const [sortDirection, setSortDirection] = useState<SortDirection>('desc');
|
||||
|
||||
const minRR = minRROverride ?? activation.data?.min_rr ?? 0;
|
||||
const minConfidence = minConfidenceOverride ?? activation.data?.min_confidence ?? 0;
|
||||
|
||||
const scanMutation = useMutation({
|
||||
mutationFn: () => triggerJob('rr_scanner'),
|
||||
onSuccess: () => {
|
||||
@@ -143,7 +150,7 @@ export function SetupsPanel() {
|
||||
min={0}
|
||||
step={0.1}
|
||||
value={minRR}
|
||||
onChange={(e) => setMinRR(Number(e.target.value) || 0)}
|
||||
onChange={(e) => setMinRROverride(Number(e.target.value) || 0)}
|
||||
className="w-20"
|
||||
/>
|
||||
</div>
|
||||
@@ -167,7 +174,7 @@ export function SetupsPanel() {
|
||||
max={100}
|
||||
step={1}
|
||||
value={minConfidence}
|
||||
onChange={(e) => setMinConfidence(Number(e.target.value) || 0)}
|
||||
onChange={(e) => setMinConfidenceOverride(Number(e.target.value) || 0)}
|
||||
className="w-24"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
Reference in New Issue
Block a user