Skip to main content
Glama
emerzon

MetaTrader5 MCP Server

by emerzon
ForecastControls.tsx8.05 kB
import { useEffect, useMemo, useState } from 'react' import { useQuery } from '@tanstack/react-query' import { getMethods, forecastPrice } from '../api/client' import type { ForecastPayload, MethodsMeta } from '../types' import { AdvancedPanel } from './AdvancedPanel' import type { DenoiseSpecUI } from './DenoiseModal' import { loadJSON, saveJSON } from '../lib/storage' const DIMRED_METHODS = new Set<string>([ 'mlf_rf', 'mlf_lightgbm', 'nhits', 'nbeatsx', 'tft', 'patchtst', 'chronos_bolt', 'timesfm', 'lag_llama', 'gt_deepar', 'gt_sfeedforward', 'gt_prophet', 'gt_tft', 'gt_wavenet', 'gt_deepnpts', 'gt_mqf2', 'gt_npts', 'ensemble', ]) export function ForecastControls({ symbol, timeframe, anchor, onResult }: { symbol?: string; timeframe: string; anchor?: number; onResult: (res: ForecastPayload) => void }) { const { data: methods, refetch: refetchMethods } = useQuery({ queryKey: ['methods'], queryFn: getMethods, refetchOnWindowFocus: true }) const defaultMethod = useMemo(() => methods?.methods?.find((m) => m.method === 'theta')?.method || methods?.methods?.[0]?.method || 'theta', [methods]) const [method, setMethod] = useState<string>(defaultMethod) const [horizon, setHorizon] = useState<number>(12) const [ci, setCi] = useState<number>(0.1) const [target, setTarget] = useState<'price' | 'return'>('price') const [lookback, setLookback] = useState<number | ''>('') const [methodParams, setMethodParams] = useState<any>({}) const [denoise, setDenoise] = useState<DenoiseSpecUI | undefined>(undefined) const [dimredMethod, setDimredMethod] = useState<string | undefined>(undefined) const [dimredParams, setDimredParams] = useState<any>(undefined) useEffect(() => { if (defaultMethod) setMethod(defaultMethod) }, [defaultMethod]) const selectedMeta = useMemo(() => methods?.methods?.find((m) => m.method === method), [methods, method]) const canRun = !!symbol && !!selectedMeta?.available const supportsDimred = DIMRED_METHODS.has(method) const advancedSummary = [ denoise?.method ? `denoise:${denoise.method}` : null, supportsDimred && dimredMethod ? `dimred:${dimredMethod}` : null, ] .filter(Boolean) .join(' • ') || 'None' useEffect(() => { if (!symbol || !timeframe) return const key = `fc:${symbol}:${timeframe}` const saved = loadJSON<any>(key) if (!saved) return if (saved.method) setMethod(saved.method) if (typeof saved.horizon === 'number') setHorizon(saved.horizon) if (typeof saved.ci === 'number') setCi(saved.ci) if (saved.target) setTarget(saved.target) if (saved.lookback === '' || typeof saved.lookback === 'number') setLookback(saved.lookback) if (saved.methodParams) setMethodParams(saved.methodParams) setDenoise(saved.denoise) setDimredMethod(saved.dimredMethod) setDimredParams(saved.dimredParams) }, [symbol, timeframe]) useEffect(() => { if (!symbol || !timeframe) return const key = `fc:${symbol}:${timeframe}` const payload = { method, horizon, ci, target, lookback, methodParams, denoise, dimredMethod, dimredParams } saveJSON(key, payload) }, [symbol, timeframe, method, horizon, ci, target, lookback, methodParams, denoise, dimredMethod, dimredParams]) useEffect(() => { if (!supportsDimred) { setDimredMethod(undefined) setDimredParams(undefined) } }, [supportsDimred]) async function run(kind: 'full' | 'partial' | 'backtest') { if (!symbol) return const body = { symbol, timeframe, method, horizon, lookback: lookback === '' ? undefined : Number(lookback), ci_alpha: ci, target, as_of: kind === 'full' ? undefined : anchor ? new Date(anchor * 1000).toISOString().slice(0, 19).replace('T', ' ') : undefined, params: methodParams, denoise, dimred_method: supportsDimred ? dimredMethod : undefined, dimred_params: supportsDimred ? dimredParams : undefined, } const res = await forecastPrice(body) onResult({ ...res, __anchor: kind === 'full' ? undefined : anchor, __kind: kind } as any) } return ( <div className="flex flex-col gap-3"> <div className="flex flex-wrap items-end gap-3"> <label className="flex flex-col"> <span className="label">Method</span> <div className="flex gap-2 items-center"> <select className="select w-48" value={method} onChange={(e) => setMethod(e.target.value)}> {methods?.methods?.map((m) => ( <option key={m.method} value={m.method} disabled={!m.available} title={!m.available ? `Requires: ${m.requires?.join(', ') || 'extra dependencies'}` : ''}> {m.method} {!m.available ? ' (unavailable)' : ''} </option> ))} </select> <button type="button" className="btn" onClick={() => refetchMethods()}> Refresh </button> </div> </label> <label className="flex flex-col"> <span className="label">Horizon</span> <input className="input w-24" type="number" min={1} value={horizon} onChange={(e) => setHorizon(Number(e.target.value))} /> </label> <label className="flex flex-col"> <span className="label">Lookback Bars</span> <input className="input w-28" type="number" min={50} value={lookback} onChange={(e) => { const val = e.target.value setLookback(val === '' ? '' : Number(val)) }} placeholder="auto" /> </label> <label className="flex flex-col"> <span className="label">Target</span> <select className="select w-28" value={target} onChange={(e) => setTarget(e.target.value as any)}> <option value="price">price</option> <option value="return">return</option> </select> </label> <label className="flex flex-col" title="Tail probability for confidence intervals. Example: 0.10 -> 90% interval, 0.05 -> 95%."> <span className="label">CI alpha</span> <input className="input w-24" type="number" step="0.01" min={0} max={0.5} value={ci} onChange={(e) => setCi(Number(e.target.value))} /> </label> <div className="flex gap-2 ml-auto items-end"> {!selectedMeta?.available && ( <div className="text-xs text-amber-400 max-w-[24rem]"> {selectedMeta?.method} is not available. {selectedMeta?.requires?.length ? `Requires: ${selectedMeta?.requires.join(', ')}` : 'Install the required package.'} </div> )} <button className="btn" disabled={!canRun} onClick={() => run('full')}> Full Forecast </button> <button className="btn" disabled={!canRun || !anchor} onClick={() => run('partial')}> Forecast from Anchor </button> </div> </div> <details className="border border-slate-800 rounded-md" open={!!denoise?.method || (!!dimredMethod && supportsDimred)}> <summary className="cursor-pointer select-none px-3 py-2 text-sm font-medium text-slate-200 hover:bg-slate-800 flex justify-between items-center"> <span>Advanced Settings</span> <span className="text-xs text-slate-400">{advancedSummary}</span> </summary> <div className="p-3 space-y-3"> <AdvancedPanel methods={methods as MethodsMeta} method={method} methodParams={methodParams} onMethodParams={setMethodParams} denoise={denoise} onDenoise={setDenoise} dimredMethod={dimredMethod} dimredParams={dimredParams} onDimred={(m, p) => { setDimredMethod(m) setDimredParams(p) }} showDimred={supportsDimred} /> </div> </details> </div> ) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/emerzon/mt-data-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server