Add configurable tick interval (time between trades)

- Seed tick_interval_seconds setting (default 60s)
- Expose tick_interval_seconds via GET/PATCH /api/settings
- startScheduler reads the setting at start time; enforces 5s minimum
- getSchedulerStatus returns intervalSeconds for the UI
- Main page: "Every [__] s" input in idle bar — saves on blur, persists across
  restarts; running state displays "every Ns" next to symbol/action

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Senofy
2026-03-12 03:42:54 -05:00
co-authored by Claude Sonnet 4.6
parent 39d7c5761c
commit 245a15666e
4 changed files with 39 additions and 5 deletions
+33 -2
View File
@@ -256,6 +256,7 @@ interface SchedulerStatus {
action: 'Buy' | 'Sell' | 'Random';
symbol: string;
lastRun: string | null;
intervalSeconds: number;
}
export default function Home() {
@@ -270,10 +271,11 @@ export default function Home() {
const [sortDir, setSortDir] = useState<SortDir>('asc');
// Trade controls
const [scheduler, setScheduler] = useState<SchedulerStatus>({ running: false, action: 'Buy', symbol: 'NQ', lastRun: null });
const [scheduler, setScheduler] = useState<SchedulerStatus>({ running: false, action: 'Buy', symbol: 'NQ', lastRun: null, intervalSeconds: 60 });
const [enabledSymbols, setEnabledSymbols] = useState<string[]>([]);
const [tradeSymbol, setTradeSymbol] = useState('');
const [tradeAction, setTradeAction] = useState<'Buy' | 'Sell' | 'Random'>('Buy');
const [tickInterval, setTickInterval] = useState('60');
const [tradeLoading, setTradeLoading] = useState(false);
const handleSort = (col: SortKey) => {
@@ -314,6 +316,13 @@ export default function Home() {
})
.catch(() => {});
fetch('/api/settings')
.then((r) => r.json())
.then((s: { tick_interval_seconds?: string | null }) => {
if (s.tick_interval_seconds != null) setTickInterval(s.tick_interval_seconds);
})
.catch(() => {});
fetchConfig();
fetchScheduler();
@@ -456,9 +465,10 @@ export default function Home() {
<span className="text-sm font-semibold text-green-700">
{scheduler.symbol} · {scheduler.action}
</span>
<span className="text-xs text-slate-400">every {scheduler.intervalSeconds}s</span>
{scheduler.lastRun && (
<span className="text-xs text-slate-400">
last run {new Date(scheduler.lastRun).toLocaleTimeString()}
· last run {new Date(scheduler.lastRun).toLocaleTimeString()}
</span>
)}
<button
@@ -501,6 +511,27 @@ export default function Home() {
Random
</button>
</div>
<div className="flex items-center gap-1.5 ml-1">
<label className="text-xs text-slate-400 whitespace-nowrap">Every</label>
<input
type="number"
min={5}
max={3600}
value={tickInterval}
onChange={(e) => setTickInterval(e.target.value)}
onBlur={() => {
const secs = Math.max(5, parseInt(tickInterval, 10) || 60);
setTickInterval(String(secs));
fetch('/api/settings', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tick_interval_seconds: secs }),
}).catch(() => {});
}}
className="w-16 rounded-lg border border-slate-200 bg-slate-50 px-2 py-1.5 text-sm text-right font-mono text-slate-800 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<span className="text-xs text-slate-400">s</span>
</div>
</div>
<button
onClick={handleStart}